From 58285f7b127cb93b314e22344bac678b9ba4298f Mon Sep 17 00:00:00 2001 From: Cameron Hart Date: Mon, 20 Jun 2022 22:25:02 +1200 Subject: [PATCH] Generate glam source code offline instead of with macros (#294) Replaces macro codegen with code generated offline by a code generator tool. The intention is to improve source code readability for users. * Move implementation from core module to codegen templates. All scalar, sse2 and wasm32 code is inside the codegen templates now, the core module is removed. * Making const creation functions, deprecating const macros. * Bump minimum Rust version to 1.58.1 and the 2021 edition Needed for const pointer dereferences and assert in a const eval context. --- .github/workflows/ci.yml | 2 +- .github/workflows/coverage.yml | 2 +- .tarpaulin.toml | 4 +- CHANGELOG.md | 20 + Cargo.toml | 11 +- README.md | 10 +- benches/transform.rs | 132 -- build_all_msrv.sh | 8 +- build_and_test_features.sh | 6 +- clippy.toml | 2 +- codegen/Cargo.toml | 16 + codegen/LICENSE-APACHE | 201 +++ codegen/LICENSE-MIT | 23 + codegen/README.md | 137 ++ codegen/src/main.rs | 620 ++++++++ codegen/templates/affine.rs | 815 ++++++++++ codegen/templates/macros.rs | 7 + codegen/templates/mat.rs | 2282 +++++++++++++++++++++++++++ codegen/templates/quat.rs | 1142 ++++++++++++++ codegen/templates/swizzle_impl.rs | 98 ++ codegen/templates/swizzle_traits.rs | 75 + codegen/templates/vec.rs | 2242 ++++++++++++++++++++++++++ codegen/templates/vec_mask.rs | 369 +++++ src/affine2.rs | 519 ------ src/affine3.rs | 631 -------- src/align16.rs | 27 + src/bool.rs | 68 + src/bool/bvec2.rs | 155 ++ src/bool/bvec3.rs | 170 ++ src/bool/bvec4.rs | 176 +++ src/bool/sse2.rs | 2 + src/bool/sse2/bvec3a.rs | 182 +++ src/bool/sse2/bvec4a.rs | 194 +++ src/bool/wasm32.rs | 2 + src/bool/wasm32/bvec3a.rs | 174 ++ src/bool/wasm32/bvec4a.rs | 181 +++ src/core.rs | 18 - src/core/scalar.rs | 4 - src/core/scalar/mask.rs | 452 ------ src/core/scalar/matrix.rs | 285 ---- src/core/scalar/quaternion.rs | 98 -- src/core/scalar/vector.rs | 1465 ----------------- src/core/sse2.rs | 4 - src/core/sse2/matrix.rs | 558 ------- src/core/sse2/quaternion.rs | 147 -- src/core/sse2/vector.rs | 871 ---------- src/core/storage.rs | 128 -- src/core/traits.rs | 5 - src/core/traits/matrix.rs | 985 ------------ src/core/traits/projection.rs | 164 -- src/core/traits/quaternion.rs | 140 -- src/core/traits/scalar.rs | 434 ----- src/core/traits/vector.rs | 864 ---------- src/core/wasm32.rs | 4 - src/core/wasm32/float.rs | 113 -- src/core/wasm32/matrix.rs | 532 ------- src/core/wasm32/quaternion.rs | 130 -- src/core/wasm32/vector.rs | 812 ---------- src/deref.rs | 50 + src/euler.rs | 114 +- src/f32.rs | 140 ++ src/f32/affine2.rs | 435 +++++ src/f32/affine3a.rs | 566 +++++++ src/f32/mat3.rs | 705 +++++++++ src/f32/scalar.rs | 6 + src/f32/scalar/mat2.rs | 431 +++++ src/f32/scalar/mat3a.rs | 693 ++++++++ src/f32/scalar/mat4.rs | 1226 ++++++++++++++ src/f32/scalar/quat.rs | 854 ++++++++++ src/f32/scalar/vec2.rs | 953 +++++++++++ src/f32/scalar/vec3a.rs | 1136 +++++++++++++ src/f32/scalar/vec4.rs | 1150 ++++++++++++++ src/f32/sse2.rs | 6 + src/f32/sse2/mat2.rs | 479 ++++++ src/f32/sse2/mat3a.rs | 703 +++++++++ src/f32/sse2/mat4.rs | 1327 ++++++++++++++++ src/f32/sse2/quat.rs | 911 +++++++++++ src/f32/sse2/vec3a.rs | 1098 +++++++++++++ src/f32/sse2/vec4.rs | 1029 ++++++++++++ src/f32/vec2.rs | 1010 ++++++++++++ src/f32/vec3.rs | 1120 +++++++++++++ src/f32/wasm32.rs | 6 + src/f32/wasm32/mat2.rs | 454 ++++++ src/f32/wasm32/mat3a.rs | 698 ++++++++ src/f32/wasm32/mat4.rs | 1318 ++++++++++++++++ src/f32/wasm32/quat.rs | 901 +++++++++++ src/f32/wasm32/vec3a.rs | 1066 +++++++++++++ src/f32/wasm32/vec4.rs | 1004 ++++++++++++ src/f64.rs | 89 ++ src/f64/daffine2.rs | 406 +++++ src/f64/daffine3.rs | 555 +++++++ src/f64/dmat2.rs | 427 +++++ src/f64/dmat3.rs | 684 ++++++++ src/f64/dmat4.rs | 1208 ++++++++++++++ src/f64/dquat.rs | 836 ++++++++++ src/f64/dvec2.rs | 1010 ++++++++++++ src/f64/dvec3.rs | 1115 +++++++++++++ src/f64/dvec4.rs | 1128 +++++++++++++ src/float_ex.rs | 50 + src/i32.rs | 37 + src/i32/ivec2.rs | 931 +++++++++++ src/i32/ivec3.rs | 1004 ++++++++++++ src/i32/ivec4.rs | 1093 +++++++++++++ src/lib.rs | 80 +- src/macros.rs | 259 +-- src/mat.rs | 114 -- src/mat2.rs | 398 ----- src/mat3.rs | 596 ------- src/mat4.rs | 890 ----------- src/quat.rs | 818 ---------- src/{core/sse2/float.rs => sse2.rs} | 166 +- src/swizzles/dvec2_impl_scalar.rs | 168 +- src/swizzles/dvec3_impl_scalar.rs | 540 +++++-- src/swizzles/dvec4_impl_scalar.rs | 1988 +++++++++++++++-------- src/swizzles/ivec2_impl_scalar.rs | 168 +- src/swizzles/ivec3_impl_scalar.rs | 540 +++++-- src/swizzles/ivec4_impl_scalar.rs | 1988 +++++++++++++++-------- src/swizzles/uvec2_impl_scalar.rs | 168 +- src/swizzles/uvec3_impl_scalar.rs | 540 +++++-- src/swizzles/uvec4_impl_scalar.rs | 1988 +++++++++++++++-------- src/swizzles/vec2_impl_scalar.rs | 168 +- src/swizzles/vec3_impl_scalar.rs | 540 +++++-- src/swizzles/vec3a_impl_scalar.rs | 540 +++++-- src/swizzles/vec3a_impl_sse2.rs | 596 ++++--- src/swizzles/vec3a_impl_wasm32.rs | 434 +++-- src/swizzles/vec4_impl_scalar.rs | 1988 +++++++++++++++-------- src/swizzles/vec4_impl_sse2.rs | 1990 +++++++++++++++-------- src/swizzles/vec4_impl_wasm32.rs | 1990 +++++++++++++++-------- src/swizzles/vec_traits.rs | 736 +++++++-- src/transform.rs | 432 ----- src/u32.rs | 37 + src/u32/uvec2.rs | 864 ++++++++++ src/u32/uvec3.rs | 965 +++++++++++ src/u32/uvec4.rs | 1051 ++++++++++++ src/vec.rs | 1029 ------------ src/vec2.rs | 334 ---- src/vec3.rs | 454 ------ src/vec4.rs | 434 ----- src/vec_mask.rs | 460 ------ src/wasm32.rs | 43 + swizzlegen/.gitignore | 1 - swizzlegen/Cargo.toml | 9 - swizzlegen/src/main.rs | 948 ----------- tests/affine2.rs | 67 +- tests/affine3.rs | 92 +- tests/euler.rs | 37 - tests/mat2.rs | 35 +- tests/mat3.rs | 40 +- tests/mat4.rs | 45 +- tests/quat.rs | 17 +- tests/support.rs | 4 +- tests/transform.rs | 129 -- tests/vec2.rs | 76 +- tests/vec3.rs | 114 +- tests/vec4.rs | 153 +- 155 files changed, 56813 insertions(+), 22528 deletions(-) delete mode 100644 benches/transform.rs create mode 100644 codegen/Cargo.toml create mode 100644 codegen/LICENSE-APACHE create mode 100644 codegen/LICENSE-MIT create mode 100644 codegen/README.md create mode 100644 codegen/src/main.rs create mode 100644 codegen/templates/affine.rs create mode 100644 codegen/templates/macros.rs create mode 100644 codegen/templates/mat.rs create mode 100644 codegen/templates/quat.rs create mode 100644 codegen/templates/swizzle_impl.rs create mode 100644 codegen/templates/swizzle_traits.rs create mode 100644 codegen/templates/vec.rs create mode 100644 codegen/templates/vec_mask.rs delete mode 100644 src/affine2.rs delete mode 100644 src/affine3.rs create mode 100644 src/align16.rs create mode 100644 src/bool.rs create mode 100644 src/bool/bvec2.rs create mode 100644 src/bool/bvec3.rs create mode 100644 src/bool/bvec4.rs create mode 100644 src/bool/sse2.rs create mode 100644 src/bool/sse2/bvec3a.rs create mode 100644 src/bool/sse2/bvec4a.rs create mode 100644 src/bool/wasm32.rs create mode 100644 src/bool/wasm32/bvec3a.rs create mode 100644 src/bool/wasm32/bvec4a.rs delete mode 100644 src/core.rs delete mode 100644 src/core/scalar.rs delete mode 100644 src/core/scalar/mask.rs delete mode 100644 src/core/scalar/matrix.rs delete mode 100644 src/core/scalar/quaternion.rs delete mode 100644 src/core/scalar/vector.rs delete mode 100644 src/core/sse2.rs delete mode 100644 src/core/sse2/matrix.rs delete mode 100644 src/core/sse2/quaternion.rs delete mode 100644 src/core/sse2/vector.rs delete mode 100644 src/core/storage.rs delete mode 100644 src/core/traits.rs delete mode 100644 src/core/traits/matrix.rs delete mode 100644 src/core/traits/projection.rs delete mode 100644 src/core/traits/quaternion.rs delete mode 100644 src/core/traits/scalar.rs delete mode 100644 src/core/traits/vector.rs delete mode 100644 src/core/wasm32.rs delete mode 100644 src/core/wasm32/float.rs delete mode 100644 src/core/wasm32/matrix.rs delete mode 100644 src/core/wasm32/quaternion.rs delete mode 100644 src/core/wasm32/vector.rs create mode 100644 src/deref.rs create mode 100644 src/f32.rs create mode 100644 src/f32/affine2.rs create mode 100644 src/f32/affine3a.rs create mode 100644 src/f32/mat3.rs create mode 100644 src/f32/scalar.rs create mode 100644 src/f32/scalar/mat2.rs create mode 100644 src/f32/scalar/mat3a.rs create mode 100644 src/f32/scalar/mat4.rs create mode 100644 src/f32/scalar/quat.rs create mode 100644 src/f32/scalar/vec2.rs create mode 100644 src/f32/scalar/vec3a.rs create mode 100644 src/f32/scalar/vec4.rs create mode 100644 src/f32/sse2.rs create mode 100644 src/f32/sse2/mat2.rs create mode 100644 src/f32/sse2/mat3a.rs create mode 100644 src/f32/sse2/mat4.rs create mode 100644 src/f32/sse2/quat.rs create mode 100644 src/f32/sse2/vec3a.rs create mode 100644 src/f32/sse2/vec4.rs create mode 100644 src/f32/vec2.rs create mode 100644 src/f32/vec3.rs create mode 100644 src/f32/wasm32.rs create mode 100644 src/f32/wasm32/mat2.rs create mode 100644 src/f32/wasm32/mat3a.rs create mode 100644 src/f32/wasm32/mat4.rs create mode 100644 src/f32/wasm32/quat.rs create mode 100644 src/f32/wasm32/vec3a.rs create mode 100644 src/f32/wasm32/vec4.rs create mode 100644 src/f64.rs create mode 100644 src/f64/daffine2.rs create mode 100644 src/f64/daffine3.rs create mode 100644 src/f64/dmat2.rs create mode 100644 src/f64/dmat3.rs create mode 100644 src/f64/dmat4.rs create mode 100644 src/f64/dquat.rs create mode 100644 src/f64/dvec2.rs create mode 100644 src/f64/dvec3.rs create mode 100644 src/f64/dvec4.rs create mode 100644 src/float_ex.rs create mode 100644 src/i32.rs create mode 100644 src/i32/ivec2.rs create mode 100644 src/i32/ivec3.rs create mode 100644 src/i32/ivec4.rs delete mode 100644 src/mat.rs delete mode 100644 src/mat2.rs delete mode 100644 src/mat3.rs delete mode 100644 src/mat4.rs delete mode 100644 src/quat.rs rename src/{core/sse2/float.rs => sse2.rs} (66%) delete mode 100644 src/transform.rs create mode 100644 src/u32.rs create mode 100644 src/u32/uvec2.rs create mode 100644 src/u32/uvec3.rs create mode 100644 src/u32/uvec4.rs delete mode 100644 src/vec.rs delete mode 100644 src/vec2.rs delete mode 100644 src/vec3.rs delete mode 100644 src/vec4.rs delete mode 100644 src/vec_mask.rs create mode 100644 src/wasm32.rs delete mode 100644 swizzlegen/.gitignore delete mode 100644 swizzlegen/Cargo.toml delete mode 100644 swizzlegen/src/main.rs delete mode 100644 tests/transform.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9ce0c54a..d45b3e09 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,7 +27,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] - toolchain: [1.52.1, stable, beta, nightly] + toolchain: [1.58.1, stable, beta, nightly] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 504edd3b..542a30a7 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -13,7 +13,7 @@ jobs: # run: cargo install cargo-tarpaulin - name: Generate code coverage - run: cargo tarpaulin -v --timeout 120 --out Lcov --output-dir ./coverage + run: cargo tarpaulin --timeout 120 --out Lcov --output-dir ./coverage - name: Upload to coveralls.io uses: coverallsapp/github-action@master diff --git a/.tarpaulin.toml b/.tarpaulin.toml index 9fe5954b..cc8629e4 100644 --- a/.tarpaulin.toml +++ b/.tarpaulin.toml @@ -1,7 +1,7 @@ [sse2_math] features = "approx bytemuck mint rand rkyv serde debug-glam-assert" -exclude-files = ["src/transform.rs", "src/core/wasm32/*", "src/swizzles/vec3a_impl_wasm32.rs", "src/swizzles/vec4_impl_wasm32.rs", "benches/*", "tests/support/mod.rs"] +exclude-files = ["codegen/*", "src/wasm32.rs", "src/bool/wasm32/*", "src/f32/wasm32/*", "src/swizzles/vec3a_impl_wasm32.rs", "src/swizzles/vec4_impl_wasm32.rs", "benches/*", "tests/support.rs"] [scalar_math] features = "scalar-math approx bytemuck mint rand rkyv serde debug-glam-assert" -exclude-files = ["src/transform.rs", "src/core/wasm32/*", "src/swizzles/vec3a_impl_wasm32.rs", "src/swizzles/vec4_impl_wasm32.rs", "benches/*", "tests/support/mod.rs"] +exclude-files = ["codegen/*", "src/wasm32.rs", "src/bool/wasm32/*", "src/f32/wasm32/*", "src/swizzles/vec3a_impl_wasm32.rs", "src/swizzles/vec4_impl_wasm32.rs", "benches/*", "tests/support.rs"] diff --git a/CHANGELOG.md b/CHANGELOG.md index e0323ac6..eebc7e17 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,26 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog], and this project adheres to [Semantic Versioning]. +## [Unreleased] + +### Breaking changes + +* Minimum Supported Version of Rust bumped to 1.58.1 to allow const pointer + dereferences in constant evaluation. + +* The `abs_diff_eq` method on `Mat2` and `DMat2` now takes `other` by value + instead of reference. This is consistent with the other matrix types. + +### Changed + +* Source code is now largely generated. This largely removes the usage of macros + internally to improve readability. There should be no change in API or + behavior. + +### Removed + +* Deleted deprecated `TransformRT` and `TransformSRT` types. + ## [0.20.5] - 2022-04-12 ### Fixed diff --git a/Cargo.toml b/Cargo.toml index cab98dec..ccb835cf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "glam" version = "0.20.5" # remember to update html_root_url -edition = "2018" +edition = "2021" authors = ["Cameron Hart "] description = "A simple and fast 3D math library for games and graphics" repository = "https://github.com/bitshifter/glam-rs" @@ -9,6 +9,7 @@ readme = "README.md" license = "MIT OR Apache-2.0" keywords = ["gamedev", "math", "matrix", "vector", "quaternion"] categories = ["game-engines", "no-std"] +rust-version = "1.58.1" [badges] maintenance = { status = "actively-developed" } @@ -27,9 +28,6 @@ glam-assert = [] # this is primarily for testing the fallback implementation scalar-math = [] -# deprecated and will move to a separate crate -transform-types = [] - # libm is required when building no_std libm = ["num-traits/libm"] @@ -95,11 +93,6 @@ harness = false name = "quat" harness = false -[[bench]] -name = "transform" -harness = false -required-features = ["transform-types"] - [[bench]] name = "vec2" harness = false diff --git a/README.md b/README.md index ebee2426..a7bb6ca3 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Build Status]][github-ci] [![Coverage Status]][coveralls.io] [![Latest Version]][crates.io] [![docs]][docs.rs] -[![Minimum Supported Rust Version]][Rust 1.52] +[![Minimum Supported Rust Version]][Rust 1.58.1] A simple and fast 3D math library for games and graphics. @@ -128,9 +128,7 @@ glam = { version = "0.20.4", default-features = false } ### Minimum Supported Rust Version (MSRV) -The minimum supported version of Rust for `glam` is `1.52.1`. - -`wasm32` SIMD intrinsics require Rust `1.54.0`. +The minimum supported version of Rust for `glam` is `1.58.1`. ## Conventions @@ -249,5 +247,5 @@ See [ATTRIBUTION.md] for details. [crates.io]: https://crates.io/crates/glam/ [docs]: https://docs.rs/glam/badge.svg [docs.rs]: https://docs.rs/glam/ -[Minimum Supported Rust Version]: https://img.shields.io/badge/Rust-1.52.1-blue?color=fc8d62&logo=rust -[Rust 1.52]: https://github.com/rust-lang/rust/blob/master/RELEASES.md#version-1521-2021-05-10 +[Minimum Supported Rust Version]: https://img.shields.io/badge/Rust-1.58.1-blue?color=fc8d62&logo=rust +[Rust 1.58.1]: https://github.com/rust-lang/rust/blob/master/RELEASES.md#version-1581-2022-01-19 diff --git a/benches/transform.rs b/benches/transform.rs deleted file mode 100644 index 25103974..00000000 --- a/benches/transform.rs +++ /dev/null @@ -1,132 +0,0 @@ -#![allow(deprecated)] - -#[path = "support/macros.rs"] -#[macro_use] -mod macros; -mod support; - -use criterion::{criterion_group, criterion_main, Criterion}; -use glam::{TransformRT, TransformSRT}; -use std::ops::Mul; -use support::*; - -fn random_transformsrt(rng: &mut PCG32) -> TransformSRT { - TransformSRT::from_scale_rotation_translation( - random_nonzero_vec3(rng), - random_quat(rng), - random_vec3(rng), - ) -} - -fn random_transformrt(rng: &mut PCG32) -> TransformRT { - TransformRT::from_rotation_translation(random_quat(rng), random_vec3(rng)) -} - -bench_unop!( - transformrt_inverse, - "transform_rt inverse", - op => inverse, - from => random_transformrt -); - -bench_unop!( - transformsrt_inverse, - "transform_srt inverse", - op => inverse, - from => random_transformsrt -); - -bench_binop!( - transformrt_transform_point3, - "transform_rt transform point3", - op => transform_point3, - from1 => random_transformrt, - from2 => random_vec3 -); - -bench_binop!( - transformrt_transform_point3a, - "transform_rt transform point3a", - op => transform_point3a, - from1 => random_transformrt, - from2 => random_vec3a -); - -bench_binop!( - transformrt_transform_vector3, - "transform_rt transform vector3", - op => transform_vector3, - from1 => random_transformrt, - from2 => random_vec3 -); - -bench_binop!( - transformrt_transform_vector3a, - "transform_rt transform vector3a", - op => transform_vector3a, - from1 => random_transformrt, - from2 => random_vec3a -); - -bench_binop!( - transformsrt_transform_point3, - "transform_srt transform point3", - op => transform_point3, - from1 => random_transformsrt, - from2 => random_vec3 -); - -bench_binop!( - transformsrt_transform_point3a, - "transform_srt transform point3a", - op => transform_point3a, - from1 => random_transformsrt, - from2 => random_vec3a -); - -bench_binop!( - transformsrt_transform_vector3, - "transform_srt transform vector3", - op => transform_vector3, - from1 => random_transformsrt, - from2 => random_vec3 -); - -bench_binop!( - transformsrt_transform_vector3a, - "transform_srt transform vector3a", - op => transform_vector3a, - from1 => random_transformsrt, - from2 => random_vec3a -); -bench_binop!( - transformsrt_mul_transformsrt, - "transform_srt mul transform_srt", - op => mul, - from => random_transformsrt -); - -bench_binop!( - transformrt_mul_transformrt, - "transform_rt mul transform_rt", - op => mul, - from => random_transformrt -); - -criterion_group!( - benches, - transformrt_inverse, - transformrt_mul_transformrt, - transformrt_transform_point3, - transformrt_transform_point3a, - transformrt_transform_vector3, - transformrt_transform_vector3a, - transformsrt_inverse, - transformsrt_mul_transformsrt, - transformsrt_transform_point3, - transformsrt_transform_point3a, - transformsrt_transform_vector3, - transformsrt_transform_vector3a, -); - -criterion_main!(benches); diff --git a/build_all_msrv.sh b/build_all_msrv.sh index eea26728..402cf761 100755 --- a/build_all_msrv.sh +++ b/build_all_msrv.sh @@ -2,8 +2,8 @@ set -e -CARGO='rustup run 1.52.1 cargo' -$CARGO test --features "bytemuck mint rand serde debug-glam-assert transform-types" && \ -$CARGO test --features "scalar-math bytemuck mint rand serde debug-glam-assert transform-types" && \ -$CARGO test --no-default-features --features "libm scalar-math bytemuck mint rand serde debug-glam-assert transform-types" && \ +CARGO='rustup run 1.58.1 cargo' +$CARGO test --features "bytemuck mint rand serde debug-glam-assert" && \ +$CARGO test --features "scalar-math bytemuck mint rand serde debug-glam-assert" && \ +$CARGO test --no-default-features --features "libm scalar-math bytemuck mint rand serde debug-glam-assert" && \ $CARGO bench --no-run diff --git a/build_and_test_features.sh b/build_and_test_features.sh index 8ceb4b4c..7946f26a 100755 --- a/build_and_test_features.sh +++ b/build_and_test_features.sh @@ -6,13 +6,13 @@ set -e FEATURE_SETS=( # std "std" - "std approx bytemuck mint rand serde debug-glam-assert transform-types" - "std scalar-math approx bytemuck mint rand serde debug-glam-assert transform-types" + "std approx bytemuck mint rand serde debug-glam-assert" + "std scalar-math approx bytemuck mint rand serde debug-glam-assert" "std cuda" "std scalar-math cuda" # no_std "libm" - "libm scalar-math approx bytemuck mint rand serde debug-glam-assert transform-types" + "libm scalar-math approx bytemuck mint rand serde debug-glam-assert" ) rustc --version diff --git a/clippy.toml b/clippy.toml index 829dd1c5..ddbdbc1f 100644 --- a/clippy.toml +++ b/clippy.toml @@ -1 +1 @@ -msrv = "1.51" +msrv = "1.58" diff --git a/codegen/Cargo.toml b/codegen/Cargo.toml new file mode 100644 index 00000000..08fa86a6 --- /dev/null +++ b/codegen/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "codegen" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +anyhow = { version = "1", default-features = false } +clap = { version = "3", default-features = false, features = ["cargo", "std"] } +git2 = { version = "0.14", default-features = false } +globset = { version = "0.4", default-features = false } +rustfmt-wrapper = { version = "0.1" } +serde = { version = "1.0", default-features = false, features = ["std"] } +serde_json = { version = "1.0", default-features = false, features = ["std"] } +tera = { version = "1", default-features = false } diff --git a/codegen/LICENSE-APACHE b/codegen/LICENSE-APACHE new file mode 100644 index 00000000..301f1f0e --- /dev/null +++ b/codegen/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright 2020 Cameron Hart + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/codegen/LICENSE-MIT b/codegen/LICENSE-MIT new file mode 100644 index 00000000..31aa7938 --- /dev/null +++ b/codegen/LICENSE-MIT @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/codegen/README.md b/codegen/README.md new file mode 100644 index 00000000..61a9c277 --- /dev/null +++ b/codegen/README.md @@ -0,0 +1,137 @@ +# glam code generation + +A tool to generate `glam`'s source code. + +## Overview + +`glam` is not a generic library, in part because some types are backed by SIMD +when it is available and also to avoid code complexity. However to support a +number of different number types combined with a number of different SIMD +architectures there is a lot of duplicate code and comments. Previously macros +were used to avoid a lot of the duplication. The down side of this was macros +were also quite complex and `glam` users often needed to navigate the macros +when viewing source or debugging. Contributors also had to find their way around +the macros to fix bugs or add features to `glam`. + +This tool replaces the majority of macros in `glam` by instead generating all of +the different containers and SIMD implementations offline. These generated files +are committed to the `glam` repo and this is what is compiled, read and debugged +by `glam` users. + +## Tera templates + +Source files are generated using [`Tera`] templates. These kinds of templates +are typically used to generate static web pages, but here we are using them to +generate Rust source. The main advantages are a lot of the template looks like +Rust code. The templates are fairly declarative and easier to follow than the +macros (in my opinion). I try to stick to basic features of the [templating +language] to keep things simple. + +[`Tera`]: https://tera.netlify.app/ +[templating language]: https://tera.netlify.app/docs/ + +### Control variables + +There `codegen` program maps a template to an output file. There are a small +number of variables that are usually set before the template is rendered to +control output: + +* `scalar_t` - the container's scalar type, e.g. `f32`, `f64`, `i32`, `u32` +* `dim` - the container's dimension, e.g. `2`, `3` or `4` +* `is_scalar` - generate regular Rust code using arithmetic operators +* `is_sse2` - generate code using `sse2` intrinsics +* `is_wasm32` - generate code using `wasm32` `simd128` intrinsics + +The templates for swizzles and vector masks behave slightly differently but +otherwise this is the common setup. + +### Template files + +The following templates are used: + +* `affine.rs` - generates 2D and 3D affine transformation types +* `mat.rs` - generates all matrix types +* `quat.rs` - generates all quaternion types +* `vec.rs` - generates all vector types +* `vec_mask.rs` - generates all vector mask types +* `swizzle_traits.rs` - generates swizzle traits +* `swizzle_impl.rs` - generates impls of swizzle traits for all vector types + +### Output module structure + +Not all types have sse2 or wasm32 implementations, if a type does have these the +scalar and SIMD types will be in their respective modules. For example the `f32` +`Vec3` type has no SIMD implementation, but `Vec4` does, the generated source +files are structured like so: + +* `src/f32/vec3.rs` +* `src/f32/scalar/vec4.rs` +* `src/f32/sse2/vec4.rs` +* `src/f32/wasm32/vec4.rs` + +The appropriate implementation module will be included when `glam` is compiled. + +### Template prelude + +Each template starts with setting up a number of common variables based on the +inputs from the `codegen` program. Commonly used variables are: + +* `self_t` - the name of the type being generated +* `inner_t` - the inner storage type used by this type (e.g. `__m128` or + `core::storage::XYZ`) +* `deref_t` - the type used by the `Deref` and `DerefMut` implementation - not + always the same as `inner_t` +* `col_t` - the column type - used by matrix and affine transform templates +* `quat_t` - the `scalar_t` quaternion type name +* `affine2_t` - the `scalar_t` 2D affine transform type name +* `affine3_t` - the `scalar_t` 3D affine transform type name +* `vec2_t` - the `scalar_t` 2D vector type name +* `vec3_t` - the `scalar_t` 3D vector type name +* `vec4_t` - the `scalar_t` 4D vector type name +* `mat2_t` - the `scalar_t` 2D matrix type name +* `mat3_t` - the `scalar_t` 3D matrix type name +* `mat4_t` - the `scalar_t` 4D matrix type name + +## Running `codegen` + +`codegen` will generate all files by default or if a glob pattern is specified, +only output files that match the glob. + +The following steps will be performed for each output file: + +* Check `git` status to see if the output is already modified. This is to avoid + overriding changes by accident. The `-f` flag can be used to force override. +* Render the `Tera` template in memory +* Rust format the template output +* Write the formatted output to the output file path + +### Template errors + +The `Tera` error output leaves a little to be desired. If the template fails to +render with no error it is usually because a variable that doesn't exist is +being referenced somewhere in the template. + +### Rust format errors + +If the Rust format step fails it is usually because the template generated +invalid Rust. The `-n` flag can be used to skip the Rust format step so that the +file may be compiled which typically shows what the problem is. + +### Workflow + +When working on a template it is often easiest to generate one or two output +files using a glob pattern to check that template changes are working as +expected. When finished editing generate everything (most files should not +change unexpectedly) and run the test suite using `build_and_test_features.sh` +and `build_and_test_wasm32_chrome.sh`. + +## License + +Licensed under either of + +* Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) + or [http://www.apache.org/licenses/LICENSE-2.0]) +* MIT license ([LICENSE-MIT](LICENSE-MIT) + or [http://opensource.org/licenses/MIT]) + +at your option. diff --git a/codegen/src/main.rs b/codegen/src/main.rs new file mode 100644 index 00000000..a3f1b580 --- /dev/null +++ b/codegen/src/main.rs @@ -0,0 +1,620 @@ +use anyhow::bail; +use clap::{arg, command}; +use rustfmt_wrapper::rustfmt; +use serde::ser::Serialize; +use std::collections::HashMap; +use std::fs::File; +use std::io::Write; +use std::path::Path; + +const GLAM_ROOT: &str = ".."; + +fn is_modified(repo: &git2::Repository, output_path: &str) -> anyhow::Result { + match repo.status_file(Path::new(output_path)) { + Ok(status) => { + return Ok(status.is_wt_modified()); + // if status.is_wt_modified() { + // bail!("{} is already modified, revert or stash your changes.", output_path); + // } + } + Err(e) => { + if e.code() == git2::ErrorCode::NotFound { + return Ok(false); + } else { + bail!("git file status failed for {}: {}", output_path, e); + } + } + } +} + +fn generate_file( + tera: &tera::Tera, + context: &tera::Context, + template_path: &str, +) -> anyhow::Result { + let buffer = match tera.render(template_path, &context) { + Ok(output) => output, + Err(e) => { + bail!("tera error encountered: {}", e); + } + }; + + Ok(buffer) +} + +struct ContextBuilder(tera::Context); + +impl ContextBuilder { + pub fn new() -> Self { + Self(tera::Context::new()) + } + + fn new_tvecn_swizzle_impl(dim: u32, prefix: &str) -> Self { + ContextBuilder::new() + .with_template("swizzle_impl.rs") + .target_scalar() + .with_key_val("vec2_t", &format!("{}Vec2", prefix)) + .with_key_val("vec3_t", &format!("{}Vec3", prefix)) + .with_key_val("vec4_t", &format!("{}Vec4", prefix)) + .with_self_t(&format!("{}Vec{}", prefix, dim)) + .with_dimension(dim) + } + + pub fn new_vec2_swizzle_impl() -> Self { + Self::new_tvecn_swizzle_impl(2, "") + } + + pub fn new_vec3_swizzle_impl() -> Self { + Self::new_tvecn_swizzle_impl(3, "") + } + + pub fn new_vec3a_swizzle_impl() -> Self { + Self::new_tvecn_swizzle_impl(3, "") + .with_key_val("vec3_t", "Vec3A") + .with_self_t("Vec3A") + } + + pub fn new_vec4_swizzle_impl() -> Self { + Self::new_tvecn_swizzle_impl(4, "") + } + + pub fn new_dvec2_swizzle_impl() -> Self { + Self::new_tvecn_swizzle_impl(2, "D") + } + + pub fn new_dvec3_swizzle_impl() -> Self { + Self::new_tvecn_swizzle_impl(3, "D") + } + + pub fn new_dvec4_swizzle_impl() -> Self { + Self::new_tvecn_swizzle_impl(4, "D") + } + + pub fn new_ivec2_swizzle_impl() -> Self { + Self::new_tvecn_swizzle_impl(2, "I") + } + + pub fn new_ivec3_swizzle_impl() -> Self { + Self::new_tvecn_swizzle_impl(3, "I") + } + + pub fn new_ivec4_swizzle_impl() -> Self { + Self::new_tvecn_swizzle_impl(4, "I") + } + + pub fn new_uvec2_swizzle_impl() -> Self { + Self::new_tvecn_swizzle_impl(2, "U") + } + + pub fn new_uvec3_swizzle_impl() -> Self { + Self::new_tvecn_swizzle_impl(3, "U") + } + + pub fn new_uvec4_swizzle_impl() -> Self { + Self::new_tvecn_swizzle_impl(4, "U") + } + + fn new_taffinen(dim: u32, scalar_t: &str) -> Self { + ContextBuilder::new() + .with_template("affine.rs") + .target_scalar() + .with_scalar_t(scalar_t) + .with_dimension(dim) + .with_is_align(false) + } + + pub fn new_affine2() -> Self { + Self::new_taffinen(2, "f32") + } + + pub fn new_affine3a() -> Self { + Self::new_taffinen(3, "f32").with_is_align(true) + } + + pub fn new_daffine2() -> Self { + Self::new_taffinen(2, "f64") + } + + pub fn new_daffine3() -> Self { + Self::new_taffinen(3, "f64") + } + + pub fn new_bvecn(dim: u32) -> Self { + ContextBuilder::new() + .with_template("vec_mask.rs") + .target_scalar() + .with_dimension(dim) + } + + pub fn new_bvec2() -> Self { + Self::new_bvecn(2) + } + + pub fn new_bvec3() -> Self { + Self::new_bvecn(3) + } + + pub fn new_bvec4() -> Self { + Self::new_bvecn(4) + } + + pub fn new_vecn(dim: u32) -> Self { + ContextBuilder::new() + .with_template("vec.rs") + .target_scalar() + .with_dimension(dim) + .with_is_align(false) + } + + pub fn new_vec2() -> Self { + Self::new_vecn(2).with_scalar_t("f32") + } + + pub fn new_vec3() -> Self { + Self::new_vecn(3).with_scalar_t("f32") + } + + pub fn new_vec3a() -> Self { + Self::new_vecn(3).with_scalar_t("f32").with_is_align(true) + } + + pub fn new_vec4() -> Self { + Self::new_vecn(4).with_scalar_t("f32") + } + + pub fn new_dvec2() -> Self { + Self::new_vecn(2).with_scalar_t("f64") + } + + pub fn new_dvec3() -> Self { + Self::new_vecn(3).with_scalar_t("f64") + } + + pub fn new_dvec4() -> Self { + Self::new_vecn(4).with_scalar_t("f64") + } + + pub fn new_ivec2() -> Self { + Self::new_vecn(2).with_scalar_t("i32") + } + + pub fn new_ivec3() -> Self { + Self::new_vecn(3).with_scalar_t("i32") + } + + pub fn new_ivec4() -> Self { + Self::new_vecn(4).with_scalar_t("i32") + } + + pub fn new_uvec2() -> Self { + Self::new_vecn(2).with_scalar_t("u32") + } + + pub fn new_uvec3() -> Self { + Self::new_vecn(3).with_scalar_t("u32") + } + + pub fn new_uvec4() -> Self { + Self::new_vecn(4).with_scalar_t("u32") + } + + pub fn new_quat() -> Self { + ContextBuilder::new() + .with_template("quat.rs") + .target_scalar() + .with_scalar_t("f32") + } + + pub fn new_dquat() -> Self { + Self::new_quat().with_scalar_t("f64") + } + + fn new_tmatn(dim: u32, scalar_t: &str) -> Self { + ContextBuilder::new() + .with_template("mat.rs") + .target_scalar() + .with_scalar_t(scalar_t) + .with_dimension(dim) + } + + pub fn new_mat2() -> Self { + Self::new_tmatn(2, "f32") + } + + pub fn new_dmat2() -> Self { + Self::new_tmatn(2, "f64") + } + + pub fn new_mat3() -> Self { + Self::new_tmatn(3, "f32") + } + + pub fn new_mat3a() -> Self { + Self::new_tmatn(3, "f32").with_is_align(true) + } + + pub fn new_dmat3() -> Self { + Self::new_tmatn(3, "f64") + } + + pub fn new_mat4() -> Self { + Self::new_tmatn(4, "f32") + } + + pub fn new_dmat4() -> Self { + Self::new_tmatn(4, "f64") + } + + pub fn with_template(mut self, template_path: &str) -> Self { + self.0.insert("template_path", template_path); + self + } + + pub fn with_scalar_t(mut self, scalar_t: &str) -> Self { + self.0.insert("scalar_t", scalar_t); + self + } + + pub fn target_sse2(mut self) -> Self { + self.0.insert("is_sse2", &true); + self.0.insert("is_wasm32", &false); + self.0.insert("is_scalar", &false); + self + } + + pub fn target_wasm32(mut self) -> Self { + self.0.insert("is_sse2", &false); + self.0.insert("is_wasm32", &true); + self.0.insert("is_scalar", &false); + self + } + + pub fn target_scalar(mut self) -> Self { + self.0.insert("is_sse2", &false); + self.0.insert("is_wasm32", &false); + self.0.insert("is_scalar", &true); + self + } + + fn with_self_t(mut self, self_t: &str) -> Self { + self.0.insert("self_t", self_t); + self + } + + fn with_dimension(mut self, dim: u32) -> Self { + self.0.insert("dim", &dim); + self + } + + fn with_is_align(mut self, is_align: bool) -> Self { + self.0.insert("is_align", &is_align); + self + } + + fn with_key_val>(mut self, key: S, val: &T) -> Self { + self.0.insert(key, val); + self + } + + pub fn build(self) -> tera::Context { + self.0 + } +} + +fn build_output_pairs() -> HashMap<&'static str, tera::Context> { + HashMap::from([ + ( + "src/swizzles/vec_traits.rs", + ContextBuilder::new() + .with_template("swizzle_traits.rs") + .build(), + ), + ( + "src/swizzles/vec2_impl_scalar.rs", + ContextBuilder::new_vec2_swizzle_impl().build(), + ), + ( + "src/swizzles/vec3_impl_scalar.rs", + ContextBuilder::new_vec3_swizzle_impl().build(), + ), + ( + "src/swizzles/vec3a_impl_scalar.rs", + ContextBuilder::new_vec3a_swizzle_impl().build(), + ), + ( + "src/swizzles/vec3a_impl_sse2.rs", + ContextBuilder::new_vec3a_swizzle_impl() + .target_sse2() + .build(), + ), + ( + "src/swizzles/vec3a_impl_wasm32.rs", + ContextBuilder::new_vec3a_swizzle_impl() + .target_wasm32() + .build(), + ), + ( + "src/swizzles/vec4_impl_scalar.rs", + ContextBuilder::new_vec4_swizzle_impl().build(), + ), + ( + "src/swizzles/vec4_impl_sse2.rs", + ContextBuilder::new_vec4_swizzle_impl() + .target_sse2() + .build(), + ), + ( + "src/swizzles/vec4_impl_wasm32.rs", + ContextBuilder::new_vec4_swizzle_impl() + .target_wasm32() + .build(), + ), + ( + "src/swizzles/dvec2_impl_scalar.rs", + ContextBuilder::new_dvec2_swizzle_impl().build(), + ), + ( + "src/swizzles/dvec3_impl_scalar.rs", + ContextBuilder::new_dvec3_swizzle_impl().build(), + ), + ( + "src/swizzles/dvec4_impl_scalar.rs", + ContextBuilder::new_dvec4_swizzle_impl().build(), + ), + ( + "src/swizzles/ivec2_impl_scalar.rs", + ContextBuilder::new_ivec2_swizzle_impl().build(), + ), + ( + "src/swizzles/ivec3_impl_scalar.rs", + ContextBuilder::new_ivec3_swizzle_impl().build(), + ), + ( + "src/swizzles/ivec4_impl_scalar.rs", + ContextBuilder::new_ivec4_swizzle_impl().build(), + ), + ( + "src/swizzles/uvec2_impl_scalar.rs", + ContextBuilder::new_uvec2_swizzle_impl().build(), + ), + ( + "src/swizzles/uvec3_impl_scalar.rs", + ContextBuilder::new_uvec3_swizzle_impl().build(), + ), + ( + "src/swizzles/uvec4_impl_scalar.rs", + ContextBuilder::new_uvec4_swizzle_impl().build(), + ), + ("src/f32/affine2.rs", ContextBuilder::new_affine2().build()), + ( + "src/f32/affine3a.rs", + ContextBuilder::new_affine3a().build(), + ), + ( + "src/f64/daffine2.rs", + ContextBuilder::new_daffine2().build(), + ), + ( + "src/f64/daffine3.rs", + ContextBuilder::new_daffine3().build(), + ), + ("src/bool/bvec2.rs", ContextBuilder::new_bvec2().build()), + ("src/bool/bvec3.rs", ContextBuilder::new_bvec3().build()), + ("src/bool/bvec4.rs", ContextBuilder::new_bvec4().build()), + ( + "src/bool/sse2/bvec3a.rs", + ContextBuilder::new_bvec3().target_sse2().build(), + ), + ( + "src/bool/wasm32/bvec3a.rs", + ContextBuilder::new_bvec3().target_wasm32().build(), + ), + ( + "src/bool/sse2/bvec4a.rs", + ContextBuilder::new_bvec4().target_sse2().build(), + ), + ( + "src/bool/wasm32/bvec4a.rs", + ContextBuilder::new_bvec4().target_wasm32().build(), + ), + ("src/f32/vec2.rs", ContextBuilder::new_vec2().build()), + ("src/f32/vec3.rs", ContextBuilder::new_vec3().build()), + ( + "src/f32/scalar/vec3a.rs", + ContextBuilder::new_vec3a().build(), + ), + ( + "src/f32/sse2/vec3a.rs", + ContextBuilder::new_vec3a().target_sse2().build(), + ), + ( + "src/f32/wasm32/vec3a.rs", + ContextBuilder::new_vec3a().target_wasm32().build(), + ), + ("src/f32/scalar/vec4.rs", ContextBuilder::new_vec4().build()), + ( + "src/f32/sse2/vec4.rs", + ContextBuilder::new_vec4().target_sse2().build(), + ), + ( + "src/f32/wasm32/vec4.rs", + ContextBuilder::new_vec4().target_wasm32().build(), + ), + ("src/f64/dvec2.rs", ContextBuilder::new_dvec2().build()), + ("src/f64/dvec3.rs", ContextBuilder::new_dvec3().build()), + ("src/f64/dvec4.rs", ContextBuilder::new_dvec4().build()), + ("src/i32/ivec2.rs", ContextBuilder::new_ivec2().build()), + ("src/i32/ivec3.rs", ContextBuilder::new_ivec3().build()), + ("src/i32/ivec4.rs", ContextBuilder::new_ivec4().build()), + ("src/u32/uvec2.rs", ContextBuilder::new_uvec2().build()), + ("src/u32/uvec3.rs", ContextBuilder::new_uvec3().build()), + ("src/u32/uvec4.rs", ContextBuilder::new_uvec4().build()), + ("src/f32/scalar/quat.rs", ContextBuilder::new_quat().build()), + ( + "src/f32/sse2/quat.rs", + ContextBuilder::new_quat().target_sse2().build(), + ), + ( + "src/f32/wasm32/quat.rs", + ContextBuilder::new_quat().target_wasm32().build(), + ), + ("src/f64/dquat.rs", ContextBuilder::new_dquat().build()), + ("src/f32/scalar/mat2.rs", ContextBuilder::new_mat2().build()), + ( + "src/f32/sse2/mat2.rs", + ContextBuilder::new_mat2().target_sse2().build(), + ), + ( + "src/f32/wasm32/mat2.rs", + ContextBuilder::new_mat2().target_wasm32().build(), + ), + ("src/f64/dmat2.rs", ContextBuilder::new_dmat2().build()), + ("src/f32/mat3.rs", ContextBuilder::new_mat3().build()), + ( + "src/f32/scalar/mat3a.rs", + ContextBuilder::new_mat3a().build(), + ), + ( + "src/f32/sse2/mat3a.rs", + ContextBuilder::new_mat3a().target_sse2().build(), + ), + ( + "src/f32/wasm32/mat3a.rs", + ContextBuilder::new_mat3a().target_wasm32().build(), + ), + ("src/f32/scalar/mat4.rs", ContextBuilder::new_mat4().build()), + ( + "src/f32/sse2/mat4.rs", + ContextBuilder::new_mat4().target_sse2().build(), + ), + ( + "src/f32/wasm32/mat4.rs", + ContextBuilder::new_mat4().target_wasm32().build(), + ), + ("src/f64/dmat3.rs", ContextBuilder::new_dmat3().build()), + ("src/f64/dmat4.rs", ContextBuilder::new_dmat4().build()), + ]) +} + +fn main() -> anyhow::Result<()> { + let matches = command!() + .arg(arg!([GLOB])) + .arg(arg!(-f - -force)) + .arg(arg!(-s - -stdout)) + .arg(arg!(-n - -nofmt)) + .get_matches(); + + let force = matches.is_present("force"); + let stdout = matches.is_present("stdout"); + let fmt_output = !matches.is_present("nofmt"); + let output_path_glob = matches.value_of("GLOB"); + + if stdout && output_path_glob.is_none() { + bail!("specify a single file to output to stdout."); + } + + let glob = if let Some(output_path_glob) = output_path_glob { + match globset::Glob::new(output_path_glob) { + Ok(glob) => Some(glob.compile_matcher()), + Err(e) => bail!("failed to compile glob: {}", e), + } + } else { + None + }; + let tera = match tera::Tera::new("templates/**/*.rs") { + Ok(t) => t, + Err(e) => bail!("Parsing error(s): {}", e), + }; + + let repo = match git2::Repository::open(GLAM_ROOT) { + Ok(repo) => repo, + Err(e) => bail!("failed to open git repo: {}", e), + }; + let workdir = repo.workdir().unwrap(); + + let output_pairs = build_output_pairs(); + + let mut output_paths = vec![]; + if let Some(glob) = glob { + for k in output_pairs.keys() { + if glob.is_match(k) { + output_paths.push(k) + } + } + if output_paths.is_empty() { + bail!("no matching output paths found for '{}'.", glob.glob()); + }; + } else { + for k in output_pairs.keys() { + output_paths.push(k) + } + }; + + output_paths.sort(); + + for output_path in output_paths { + println!("generating {}", output_path); + let context = output_pairs.get(output_path).unwrap(); + let template_path = context.get("template_path").unwrap().as_str().unwrap(); + + if !(force || stdout) && is_modified(&repo, output_path)? { + bail!( + "{} is already modified, use `-f` to force overwrite or revert local changes.", + output_path + ); + } + + let mut output_str = generate_file(&tera, &context, template_path)?; + + if fmt_output { + match rustfmt(&output_str) { + Ok(output) => output_str = output, + Err(e) => { + bail!("rustfmt error encountered: {}", e); + } + } + } + + if stdout { + print!("{}", output_str); + continue; + } + + let full_output_path = workdir.join(output_path); + let mut output_file = match File::create(&full_output_path) { + Ok(file) => file, + Err(e) => { + bail!("failed to create {}: {}", full_output_path.display(), e); + } + }; + + match write!(output_file, "{}", output_str) { + Err(e) => { + bail!("failed to write output: {}", e); + } + Ok(()) => (), + } + } + + Ok(()) +} diff --git a/codegen/templates/affine.rs b/codegen/templates/affine.rs new file mode 100644 index 00000000..a7204354 --- /dev/null +++ b/codegen/templates/affine.rs @@ -0,0 +1,815 @@ +// Generated from {{template_path}} template. Edit the template, not the generated file. + +{% if scalar_t == "f32" %} + {% if dim == 3 %} + {% set self_t = "Affine3A" %} + {% set col_t = "Vec3A" %} + {% set mat_t = "Mat3A" %} + {% else %} + {% set self_t = "Affine" ~ dim %} + {% set col_t = "Vec" ~ dim %} + {% set mat_t = "Mat" ~ dim %} + {% endif %} + {% set quat_t = "Quat" %} + {% set vec2_t = "Vec2" %} + {% set vec3_t = "Vec3" %} + {% set mat3_t = "Mat3" %} + {% set mat4_t = "Mat4" %} +{% elif scalar_t == "f64" %} + {% set self_t = "DAffine" ~ dim %} + {% set col_t = "DVec" ~ dim %} + {% set mat_t = "DMat" ~ dim %} + {% set quat_t = "DQuat" %} + {% set vec2_t = "DVec2" %} + {% set vec3_t = "DVec3" %} + {% set mat3_t = "DMat3" %} + {% set mat4_t = "DMat4" %} +{% endif %} + +{% if dim == 2 %} + {% set size = 6 %} +{% elif dim == 3 %} + {% set size = 12 %} +{% endif %} + +{% set components = ["x", "y", "z", "w"] | slice(end = dim + 1) %} +{% set axes = ["x_axis", "y_axis", "z_axis", "w_axis"] | slice(end = dim + 1) %} + +use crate::{ +{% if self_t == "Affine2" %} + Mat3A, Vec3A, +{% elif self_t == "Affine3A" %} + Vec3, Mat3, +{% endif %} +{% if dim == 2 %} + {{ mat_t }}, {{ col_t }}, {{ mat3_t }}, +{% elif dim == 3 %} + {{ mat_t }}, {{ col_t}}, {{ mat4_t }}, {{ quat_t }}, +{% endif %} +}; +use core::ops::{Add, Deref, DerefMut, Mul, Sub}; + +/// A {{ dim }}D affine transform, which can represent translation, rotation, scaling and shear. +#[derive(Copy, Clone)] +#[repr(C)] +pub struct {{ self_t }} { + pub matrix{{ dim }}: {{ mat_t }}, + pub translation: {{ col_t }}, +} + +impl {{ self_t }} { + /// The degenerate zero transform. + /// + /// This transforms any finite vector and point to zero. + /// The zero transform is non-invertible. + pub const ZERO: Self = Self { + matrix{{ dim }}: {{ mat_t }}::ZERO, + translation: {{ col_t }}::ZERO, + }; + + /// The identity transform. + /// + /// Multiplying a vector with this returns the same vector. + pub const IDENTITY: Self = Self { + matrix{{ dim }}: {{ mat_t }}::IDENTITY, + translation: {{ col_t }}::ZERO, + }; + + /// All NAN:s. + pub const NAN: Self = Self { + matrix{{ dim }}: {{ mat_t }}::NAN, + translation: {{ col_t }}::NAN, + }; + + /// Creates an affine transform from three column vectors. + #[inline(always)] + pub const fn from_cols( + {% for axis in axes %} + {{ axis }}: {{ col_t }}, + {% endfor %} + ) -> Self { + Self { + matrix{{ dim }}: {{ mat_t }}::from_cols( + {% for axis in axes | slice(end = dim) %} + {{ axis }}, + {% endfor %} + ), + translation: {{ axes[dim] }}, + } + } + + /// Creates an affine transform from a `[{{ scalar_t }}; {{ size }}]` array stored in column major order. + /// If your data is stored in row major you will need to `transpose` the returned + /// matrix. + #[inline] + pub fn from_cols_array(m: &[{{ scalar_t }}; {{ size }}]) -> Self { + Self { + matrix{{ dim }}: {{ mat_t }}::from_cols_slice(&m[0..{{ dim * dim }}]), + translation: {{ col_t }}::from_slice(&m[{{ dim * dim }}..{{ size }}]), + } + } + + /// Creates a `[{{ scalar_t }}; {{ size }}]` array storing data in column major order. + /// If you require data in row major order `transpose` the matrix first. + #[inline] + pub fn to_cols_array(&self) -> [{{ scalar_t }}; {{ size }}] { + {% for i in range(end = dim) %} + let {{ components[i] }} = &self.matrix{{ dim }}.{{ axes[i] }}; + {%- endfor %} + let {{ components[dim] }} = &self.translation; + [ + {% for i in range(end = dim + 1) %} + {% for j in range(end = dim) %} + {{ components[i] }}.{{ components[j] }}, + {% endfor %} + {% endfor %} + ] + } + + /// Creates an affine transform from a `[[{{ scalar_t }}; {{ dim }}]; {{ dim + 1 }}]` + /// {{ dim }}D array stored in column major order. + /// If your data is in row major order you will need to `transpose` the returned + /// matrix. + #[inline] + pub fn from_cols_array_2d(m: &[[{{ scalar_t }}; {{ dim }}]; {{ dim + 1 }}]) -> Self { + Self { + matrix{{ dim }}: {{ mat_t }}::from_cols( + {% for i in range(end = dim) %} + m[{{ i }}].into(), + {% endfor %} + ), + translation: m[{{ dim }}].into(), + } + } + + /// Creates a `[[{{ scalar_t }}; {{ dim }}]; {{ dim + 1 }}]` {{ dim }}D array storing data in + /// column major order. + /// If you require data in row major order `transpose` the matrix first. + #[inline] + pub fn to_cols_array_2d(&self) -> [[{{ scalar_t }}; {{ dim }}]; {{ dim + 1 }}] { + [ + {% for i in range(end = dim) %} + self.matrix{{ dim }}.{{ axes[i] }}.into(), + {% endfor %} + self.translation.into(), + ] + } + + /// Creates an affine transform from the first {{ size }} values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than {{ size }} elements long. + #[inline] + pub fn from_cols_slice(slice: &[{{ scalar_t }}]) -> Self { + Self { + matrix{{ dim }}: {{ mat_t }}::from_cols_slice(&slice[0..{{ dim * dim }}]), + translation: {{ col_t }}::from_slice(&slice[{{ dim * dim }}..{{ size }}]), + } + } + + /// Writes the columns of `self` to the first {{ size }} elements in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than {{ size }} elements long. + #[inline] + pub fn write_cols_to_slice(self, slice: &mut [{{ scalar_t }}]) { + self.matrix{{ dim }}.write_cols_to_slice(&mut slice[0..{{ dim * dim }}]); + self.translation.write_to_slice(&mut slice[{{ dim * dim }}..{{ size }}]); + } + +{% if dim == 2 %} + /// Creates an affine transform that changes scale. + /// Note that if any scale is zero the transform will be non-invertible. + #[inline] + pub fn from_scale(scale: {{ vec2_t }}) -> Self { + Self { + matrix{{ dim }}: {{ mat_t }}::from_diagonal(scale), + translation: {{ col_t }}::ZERO, + } + } + + /// Creates an affine transform from the given rotation `angle`. + #[inline] + pub fn from_angle(angle: {{ scalar_t }}) -> Self { + Self { + matrix2: {{ mat_t }}::from_angle(angle), + translation: {{ col_t }}::ZERO, + } + } + + /// Creates an affine transformation from the given 2D `translation`. + #[inline] + pub fn from_translation(translation: {{ vec2_t }}) -> Self { + Self { + matrix2: {{ mat_t }}::IDENTITY, + translation, + } + } + + /// Creates an affine transform from a 2x2 matrix (expressing scale, shear and rotation) + #[inline] + pub fn from_mat2(matrix2: {{ mat_t }}) -> Self { + Self { + matrix2, + translation: {{ col_t }}::ZERO, + } + } + + /// Creates an affine transform from a 2x2 matrix (expressing scale, shear and rotation) and a + /// translation vector. + /// + /// Equivalent to + /// `{{ self_t }}::from_translation(translation) * {{ self_t }}::from_mat{{ dim }}(mat{{ dim }})` + #[inline] + pub fn from_mat2_translation(matrix2: {{ mat_t }}, translation: {{ vec2_t }}) -> Self { + Self { + matrix2, + translation, + } + } + + /// Creates an affine transform from the given 2D `scale`, rotation `angle` (in radians) and + /// `translation`. + /// + /// Equivalent to `{{ self_t }}::from_translation(translation) * + /// {{ self_t }}::from_angle(angle) * {{ self_t }}::from_scale(scale)` + #[inline] + pub fn from_scale_angle_translation( + scale: {{ vec2_t }}, + angle: {{ scalar_t }}, + translation: {{ vec2_t }}, + ) -> Self { + let rotation = {{ mat_t }}::from_angle(angle); + Self { + matrix2: {{ mat_t }}::from_cols( + rotation.x_axis * scale.x, + rotation.y_axis * scale.y, + ), + translation, + } + } + + /// Creates an affine transform from the given 2D rotation `angle` (in radians) and + /// `translation`. + /// + /// Equivalent to `{{ self_t }}::from_translation(translation) * {{ self_t }}::from_angle(angle)` + #[inline] + pub fn from_angle_translation(angle: {{ scalar_t }}, translation: {{ vec2_t }}) -> Self { + Self { + matrix2: {{ mat_t }}::from_angle(angle), + translation, + } + } + + /// The given `{{ mat3_t }}` must be an affine transform, + #[inline] + pub fn from_mat3(m: {{ mat3_t }}) -> Self { + use crate::swizzles::Vec3Swizzles; + Self { + matrix2: {{ mat_t }}::from_cols(m.x_axis.xy(), m.y_axis.xy()), + translation: m.z_axis.xy(), + } + } + + /// Transforms the given 2D point, applying shear, scale, rotation and translation. + #[inline] + pub fn transform_point2(&self, rhs: {{ vec2_t }}) -> {{ vec2_t }} { + self.matrix2 * rhs + self.translation + } + + /// Transforms the given 2D vector, applying shear, scale and rotation (but NOT + /// translation). + /// + /// To also apply translation, use [`Self::transform_point2`] instead. + #[inline] + pub fn transform_vector2(&self, rhs: {{ vec2_t }}) -> {{ vec2_t }} { + self.matrix2 * rhs + } + +{% elif dim == 3 %} + /// Creates an affine transform that changes scale. + /// Note that if any scale is zero the transform will be non-invertible. + #[inline] + pub fn from_scale(scale: {{ vec3_t }}) -> Self { + Self { + matrix3: {{ mat_t }}::from_diagonal(scale), + translation: {{ col_t }}::ZERO, + } + } + /// Creates an affine transform from the given `rotation` quaternion. + #[inline] + pub fn from_quat(rotation: {{ quat_t }}) -> Self { + Self { + matrix3: {{ mat_t }}::from_quat(rotation), + translation: {{ col_t }}::ZERO, + } + } + + /// Creates an affine transform containing a 3D rotation around a normalized + /// rotation `axis` of `angle` (in radians). + #[inline] + pub fn from_axis_angle(axis: {{ vec3_t }}, angle: {{ scalar_t }}) -> Self { + Self { + matrix3: {{ mat_t }}::from_axis_angle(axis, angle), + translation: {{ col_t }}::ZERO, + } + } + + /// Creates an affine transform containing a 3D rotation around the x axis of + /// `angle` (in radians). + #[inline] + pub fn from_rotation_x(angle: {{ scalar_t }}) -> Self { + Self { + matrix3: {{ mat_t }}::from_rotation_x(angle), + translation: {{ col_t }}::ZERO, + } + } + + /// Creates an affine transform containing a 3D rotation around the y axis of + /// `angle` (in radians). + #[inline] + pub fn from_rotation_y(angle: {{ scalar_t }}) -> Self { + Self { + matrix3: {{ mat_t }}::from_rotation_y(angle), + translation: {{ col_t }}::ZERO, + } + } + + /// Creates an affine transform containing a 3D rotation around the z axis of + /// `angle` (in radians). + #[inline] + pub fn from_rotation_z(angle: {{ scalar_t }}) -> Self { + Self { + matrix3: {{ mat_t }}::from_rotation_z(angle), + translation: {{ col_t }}::ZERO, + } + } + + /// Creates an affine transformation from the given 3D `translation`. + #[inline] + pub fn from_translation(translation: {{ vec3_t }}) -> Self { + #[allow(clippy::useless_conversion)] + Self { + matrix3: {{ mat_t }}::IDENTITY, + translation: translation.into(), + } + } + + /// Creates an affine transform from a 3x3 matrix (expressing scale, shear and + /// rotation) + #[inline] + pub fn from_mat3(mat3: {{ mat3_t }}) -> Self { + #[allow(clippy::useless_conversion)] + Self { + matrix3: mat3.into(), + translation: {{ col_t }}::ZERO, + } + } + + /// Creates an affine transform from a 3x3 matrix (expressing scale, shear and rotation) + /// and a translation vector. + /// + /// Equivalent to `{{ self_t }}::from_translation(translation) * {{ self_t }}::from_mat3(mat3)` + #[inline] + pub fn from_mat3_translation(mat3: {{ mat3_t }}, translation: {{ vec3_t }}) -> Self { + #[allow(clippy::useless_conversion)] + Self { + matrix3: mat3.into(), + translation: translation.into(), + } + } + + /// Creates an affine transform from the given 3D `scale`, `rotation` and + /// `translation`. + /// + /// Equivalent to `{{ self_t }}::from_translation(translation) * + /// {{ self_t }}::from_quat(rotation) * {{ self_t }}::from_scale(scale)` + #[inline] + pub fn from_scale_rotation_translation( + scale: {{ vec3_t }}, + rotation: {{ quat_t }}, + translation: {{ vec3_t }}, + ) -> Self { + let rotation = {{ mat_t }}::from_quat(rotation); + #[allow(clippy::useless_conversion)] + Self { + matrix3: {{ mat_t }}::from_cols( + rotation.x_axis * scale.x, + rotation.y_axis * scale.y, + rotation.z_axis * scale.z, + ), + translation: translation.into(), + } + } + + /// Creates an affine transform from the given 3D `rotation` and `translation`. + /// + /// Equivalent to `{{ self_t }}::from_translation(translation) * {{ self_t }}::from_quat(rotation)` + #[inline] + pub fn from_rotation_translation(rotation: {{ quat_t }}, translation: {{ vec3_t }}) -> Self { + #[allow(clippy::useless_conversion)] + Self { + matrix3: {{ mat_t }}::from_quat(rotation), + translation: translation.into(), + } + } + + /// The given `{{ mat4_t }}` must be an affine transform, + /// i.e. contain no perspective transform. + #[inline] + pub fn from_mat4(m: {{ mat4_t }}) -> Self { + Self { + matrix3: {{ mat_t }}::from_cols( + {{ col_t }}::from_vec4(m.x_axis), + {{ col_t }}::from_vec4(m.y_axis), + {{ col_t }}::from_vec4(m.z_axis), + ), + translation: {{ col_t }}::from_vec4(m.w_axis), + } + } + + /// Extracts `scale`, `rotation` and `translation` from `self`. + /// + /// The transform is expected to be non-degenerate and without shearing, or the output + /// will be invalid. + /// + /// # Panics + /// + /// Will panic if the determinant `self.matrix3` is zero or if the resulting scale + /// vector contains any zero elements when `glam_assert` is enabled. + #[inline] + pub fn to_scale_rotation_translation(&self) -> ({{ vec3_t }}, {{ quat_t }}, {{ vec3_t }}) { + #[cfg(not(feature = "std"))] + use num_traits::Float; + + // TODO: migrate to core module + let det = self.matrix3.determinant(); + glam_assert!(det != 0.0); + + let scale = {{ vec3_t }}::new( + self.matrix3.x_axis.length() * det.signum(), + self.matrix3.y_axis.length(), + self.matrix3.z_axis.length(), + ); + + glam_assert!(scale.cmpne({{ vec3_t }}::ZERO).all()); + + let inv_scale = scale.recip(); + + #[allow(clippy::useless_conversion)] + let rotation = {{ quat_t }}::from_mat3(&{{ mat3_t }}::from_cols( + (self.matrix3.x_axis * inv_scale.x).into(), + (self.matrix3.y_axis * inv_scale.y).into(), + (self.matrix3.z_axis * inv_scale.z).into(), + )); + + #[allow(clippy::useless_conversion)] + (scale, rotation, self.translation.into()) + } + + #[inline] + fn look_to_lh(eye: {{ vec3_t }}, dir: {{ vec3_t }}, up: {{ vec3_t }}) -> Self { + let f = dir.normalize(); + let s = up.cross(f).normalize(); + let u = f.cross(s); + Self { + matrix3: {{ mat_t }}::from_cols( + {{ col_t }}::new(s.x, u.x, f.x), + {{ col_t }}::new(s.y, u.y, f.y), + {{ col_t }}::new(s.z, u.z, f.z), + ), + translation: {{ col_t }}::new(-s.dot(eye), -u.dot(eye), -f.dot(eye)), + } + } + + /// Creates a left-handed view transform using a camera position, an up direction, and + /// a focal point. + /// + /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=forward`. + /// + /// # Panics + /// + /// Will panic if `up` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn look_at_lh(eye: {{ vec3_t }}, center: {{ vec3_t }}, up: {{ vec3_t }}) -> Self { + glam_assert!(up.is_normalized()); + Self::look_to_lh(eye, center - eye, up) + } + + /// Creates a right-handed view transform using a camera position, an up direction, and + /// a focal point. + /// + /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=back`. + /// + /// # Panics + /// + /// Will panic if `up` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn look_at_rh(eye: {{ vec3_t }}, center: {{ vec3_t }}, up: {{ vec3_t }}) -> Self { + glam_assert!(up.is_normalized()); + Self::look_to_lh(eye, eye - center, up) + } + + /// Transforms the given 3D points, applying shear, scale, rotation and translation. + #[inline] + pub fn transform_point3(&self, rhs: {{ vec3_t }}) -> {{ vec3_t }} { + #[allow(clippy::useless_conversion)] + ((self.matrix3.x_axis * rhs.x) + + (self.matrix3.y_axis * rhs.y) + + (self.matrix3.z_axis * rhs.z) + + self.translation) + .into() + } + + /// Transforms the given 3D vector, applying shear, scale and rotation (but NOT + /// translation). + /// + /// To also apply translation, use [`Self::transform_point3`] instead. + #[inline] + pub fn transform_vector3(&self, rhs: {{ vec3_t }}) -> {{ vec3_t }} { + #[allow(clippy::useless_conversion)] + ((self.matrix3.x_axis * rhs.x) + + (self.matrix3.y_axis * rhs.y) + + (self.matrix3.z_axis * rhs.z)) + .into() + } +{% endif %} + +{% if self_t == "Affine3A" %} + /// Transforms the given `Vec3A`, applying shear, scale, rotation and translation. + #[inline] + pub fn transform_point3a(&self, rhs: Vec3A) -> Vec3A { + self.matrix3 * rhs + self.translation + } + + /// Transforms the given `Vec3A`, applying shear, scale and rotation (but NOT + /// translation). + /// + /// To also apply translation, use [`Self::transform_point3`] instead. + #[inline] + pub fn transform_vector3a(&self, rhs: Vec3A) -> Vec3A { + self.matrix3 * rhs + } +{% endif %} + + /// Returns `true` if, and only if, all elements are finite. + /// + /// If any element is either `NaN`, positive or negative infinity, this will return + /// `false`. + #[inline] + pub fn is_finite(&self) -> bool { + self.matrix{{ dim }}.is_finite() && self.translation.is_finite() + } + + /// Returns `true` if any elements are `NaN`. + #[inline] + pub fn is_nan(&self) -> bool { + self.matrix{{ dim }}.is_nan() || self.translation.is_nan() + } + + /// Returns true if the absolute difference of all elements between `self` and `rhs` + /// is less than or equal to `max_abs_diff`. + /// + /// This can be used to compare if two 3x4 matrices contain similar elements. It works + /// best when comparing with a known value. The `max_abs_diff` that should be used used + /// depends on the values being compared against. + /// + /// For more see + /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/). + #[inline] + pub fn abs_diff_eq(&self, rhs: Self, max_abs_diff: {{ scalar_t }}) -> bool { + self.matrix{{ dim }}.abs_diff_eq(rhs.matrix{{ dim }}, max_abs_diff) + && self + .translation + .abs_diff_eq(rhs.translation, max_abs_diff) + } + + /// Return the inverse of this transform. + /// + /// Note that if the transform is not invertible the result will be invalid. + #[must_use] + #[inline] + pub fn inverse(&self) -> Self { + let matrix{{ dim }} = self.matrix{{ dim }}.inverse(); + // transform negative translation by the matrix inverse: + let translation = -(matrix{{ dim }} * self.translation); + + Self { + matrix{{ dim }}, + translation, + } + } +} + +impl Default for {{ self_t }} { + #[inline(always)] + fn default() -> Self { + Self::IDENTITY + } +} + +impl Deref for {{ self_t }} { + type Target = crate::deref::Columns{{ dim + 1 }}<{{ col_t }}>; + #[inline(always)] + fn deref(&self) -> &Self::Target { + unsafe { &*(self as *const Self as *const Self::Target) } + } +} + +impl DerefMut for {{ self_t }} { + #[inline(always)] + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { &mut *(self as *mut Self as *mut Self::Target) } + } +} + +impl PartialEq for {{ self_t }} { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.matrix{{ dim }}.eq(&rhs.matrix{{ dim }}) && self.translation.eq(&rhs.translation) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl core::fmt::Debug for {{ self_t }} { + fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + fmt.debug_struct(stringify!({{ self_t }})) + .field("matrix{{ dim }}", &self.matrix{{ dim }}) + .field("translation", &self.translation) + .finish() + } +} + +#[cfg(not(target_arch = "spirv"))] +impl core::fmt::Display for {{ self_t }} { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + {% if dim == 2 %} + write!(f, "[{}, {}, {}]", self.matrix2.x_axis, self.matrix2.y_axis, self.translation) + {% elif dim == 3 %} + write!( + f, + "[{}, {}, {}, {}]", + self.matrix3.x_axis, self.matrix3.y_axis, self.matrix3.z_axis, self.translation + ) + {% endif %} + } +} + +impl<'a> core::iter::Product<&'a Self> for {{ self_t }} { + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::IDENTITY, |a, &b| a * b) + } +} + +impl Mul for {{ self_t }} { + type Output = {{ self_t }}; + + #[inline] + fn mul(self, rhs: {{ self_t }}) -> Self::Output { + Self { + matrix{{ dim }}: self.matrix{{ dim }} * rhs.matrix{{ dim }}, + translation: self.matrix{{ dim }} * rhs.translation + self.translation, + } + } +} + +impl Mul<{{ self_t }}> for {{ scalar_t }} { + type Output = {{ self_t }}; + #[inline] + fn mul(self, rhs: {{ self_t }}) -> Self::Output { + {{ self_t }} { + matrix{{ dim }}: self * rhs.matrix{{ dim }}, + translation: self * rhs.translation, + } + } +} + +impl Mul<{{ scalar_t }}> for {{ self_t }} { + type Output = Self; + #[inline] + fn mul(self, rhs: {{ scalar_t }}) -> Self::Output { + Self { + matrix{{ dim }}: self.matrix{{ dim }} * rhs, + translation: self.translation * rhs, + } + } +} + +impl Add<{{ self_t }}> for {{ self_t }} { + type Output = Self; + #[inline] + fn add(self, rhs: Self) -> Self::Output { + Self { + matrix{{ dim }}: self.matrix{{ dim }} + rhs.matrix{{ dim }}, + translation: self.translation + rhs.translation, + } + } +} + +impl Sub<{{ self_t }}> for {{ self_t }} { + type Output = Self; + #[inline] + fn sub(self, rhs: Self) -> Self::Output { + Self { + matrix{{ dim }}: self.matrix{{ dim }} - rhs.matrix{{ dim }}, + translation: self.translation - rhs.translation, + } + } +} + +{% if dim == 2 %} +impl From<{{ self_t }}> for {{ mat3_t }} { + #[inline] + fn from(m: {{ self_t }}) -> {{ mat3_t }} { + Self::from_cols( + m.matrix2.x_axis.extend(0.0), + m.matrix2.y_axis.extend(0.0), + m.translation.extend(1.0), + ) + } +} + +impl Mul<{{ mat3_t }}> for {{ self_t }} { + type Output = {{ mat3_t }}; + + #[inline] + fn mul(self, rhs: {{ mat3_t }}) -> Self::Output { + {{ mat3_t }}::from(self) * rhs + } +} + +impl Mul<{{ self_t }}> for {{ mat3_t }} { + type Output = {{ mat3_t }}; + + #[inline] + fn mul(self, rhs: {{ self_t }}) -> Self::Output { + self * {{ mat3_t }}::from(rhs) + } +} +{% elif dim == 3 %} +impl From<{{ self_t }}> for {{ mat4_t }} { + #[inline] + fn from(m: {{ self_t }}) -> {{ mat4_t }} { + {{ mat4_t }}::from_cols( + m.matrix3.x_axis.extend(0.0), + m.matrix3.y_axis.extend(0.0), + m.matrix3.z_axis.extend(0.0), + m.translation.extend(1.0), + ) + } +} + +impl Mul<{{ mat4_t }}> for {{ self_t }} { + type Output = {{ mat4_t }}; + + #[inline] + fn mul(self, rhs: {{ mat4_t }}) -> Self::Output { + {{ mat4_t }}::from(self) * rhs + } +} + +impl Mul<{{ self_t }}> for {{ mat4_t }} { + type Output = {{ mat4_t }}; + + #[inline] + fn mul(self, rhs: {{ self_t }}) -> Self::Output { + self * {{ mat4_t }}::from(rhs) + } +} +{% endif %} + +{% if self_t == "Affine2" %} +impl From for Mat3A { + #[inline] + fn from(m: Affine2) -> Mat3A { + Self::from_cols( + Vec3A::from((m.matrix2.x_axis, 0.0)), + Vec3A::from((m.matrix2.y_axis, 0.0)), + Vec3A::from((m.translation, 1.0)), + ) + } +} + +impl Mul for Affine2 { + type Output = Mat3A; + + #[inline] + fn mul(self, rhs: Mat3A) -> Self::Output { + Mat3A::from(self) * rhs + } +} + +impl Mul for Mat3A { + type Output = Mat3A; + + #[inline] + fn mul(self, rhs: Affine2) -> Self::Output { + self * Mat3A::from(rhs) + } +} +{% endif %} diff --git a/codegen/templates/macros.rs b/codegen/templates/macros.rs new file mode 100644 index 00000000..a6de0473 --- /dev/null +++ b/codegen/templates/macros.rs @@ -0,0 +1,7 @@ +{% macro make_tuple_t(t, n) %} + ( + {%- for i in range(end=n) -%} + {{ t }}, + {%- endfor -%} + ) +{% endmacro make_tuple_t %} diff --git a/codegen/templates/mat.rs b/codegen/templates/mat.rs new file mode 100644 index 00000000..3ee20182 --- /dev/null +++ b/codegen/templates/mat.rs @@ -0,0 +1,2282 @@ +// Generated from {{template_path}} template. Edit the template, not the generated file. + +{% if scalar_t == "f32" %} + {% set vecn_t = "Vec" ~ dim %} + {% if dim == 3 and is_align %} + {% set self_t = "Mat3A" %} + {% set col_t = "Vec3A" %} + {% else %} + {% set self_t = "Mat" ~ dim %} + {% set col_t = vecn_t %} + {% endif %} + {% set quat_t = "Quat" %} + {% set affine2_t = "Affine2" %} + {% set affine3_t = "Affine3A" %} + {% set vec2_t = "Vec2" %} + {% set vec3_t = "Vec3" %} + {% set vec3a_t = "Vec3A" %} + {% set vec4_t = "Vec4" %} + {% set mat2_t = "Mat2" %} + {% set mat3_t = "Mat3" %} + {% set mat3a_t = "Mat3A" %} + {% set mat4_t = "Mat4" %} +{% elif scalar_t == "f64" %} + {% set vecn_t = "DVec" ~ dim %} + {% set self_t = "DMat" ~ dim %} + {% set col_t = vecn_t %} + {% set quat_t = "DQuat" %} + {% set affine2_t = "DAffine2" %} + {% set affine3_t = "DAffine3" %} + {% set vec2_t = "DVec2" %} + {% set vec3_t = "DVec3" %} + {% set vec4_t = "DVec4" %} + {% set mat2_t = "DMat2" %} + {% set mat3_t = "DMat3" %} + {% set mat4_t = "DMat4" %} +{% endif %} + +{% if self_t == "Mat2" %} + {% if not is_scalar %} + {% set is_simd = true %} + {% if is_sse2 %} + {% set simd_t = "__m128" %} + {% elif is_wasm32 %} + {% set simd_t = "v128" %} + {% endif %} + {% endif %} +{% endif %} + +{% set size = dim * dim %} +{% set nxn = dim ~ "x" ~ dim %} + +{% set components = ["x", "y", "z", "w"] | slice(end = dim) %} +{% set axes = ["x_axis", "y_axis", "z_axis", "w_axis"] | slice(end = dim) %} + +use crate::{ +{% if scalar_t == "f32" %} + DMat{{ dim }}, +{% elif scalar_t == "f64" %} + Mat{{ dim }}, +{% endif %} +{% if dim == 2 %} + {{ mat3_t }}, {{ vec2_t }}, +{% elif dim == 3 %} + EulerRot, + {{ mat2_t }}, {{ mat4_t }}, {{ quat_t }}, {{ vec2_t }}, {{ col_t }}, + {% if is_align %} + {{ mat3_t }}, {{ vec3_t }}, + {% elif scalar_t == "f32" %} + {{ mat3a_t }}, {{ vec3a_t }}, + {% endif %} +{% elif dim == 4 %} + EulerRot, + {{ mat3_t }}, {{ quat_t }}, {{ vec3_t }}, {{ col_t }}, + {% if scalar_t == "f32" %} + {{ vec3a_t }}, + {% endif %} +{% endif %} + swizzles::*, +}; +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::iter::{Product, Sum}; +use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; + +{% if is_sse2 %} +#[cfg(target_arch = "x86")] +use core::arch::x86::*; +#[cfg(target_arch = "x86_64")] +use core::arch::x86_64::*; +{% elif is_wasm32 %} +use core::arch::wasm32::*; +{% endif %} + +#[cfg(not(feature = "std"))] +use num_traits::Float; + + +{% if self_t == "Mat2" and is_sse2 %} +union UnionCast { + a: [f32; 4], + v: {{ self_t }} +} +{% endif %} + +/// Creates a {{ nxn }} matrix from column vectors. +#[inline(always)] +pub const fn {{ self_t | lower }}( + {% for axis in axes %} + {{ axis }}: {{ col_t }}, + {% endfor %} +) -> {{ self_t }} { + {{ self_t }}::from_cols({{ axes | join(sep=",") }}) +} + +/// A {{ nxn }} column major matrix. +{%- if dim == 3 %} +/// +/// This 3x3 matrix type features convenience methods for creating and using linear and +/// affine transformations. If you are primarily dealing with 2D affine transformations the +/// [`{{ affine2_t }}`](crate::{{ affine2_t }}) type is much faster and more space efficient than +/// using a 3x3 matrix. +/// +/// Linear transformations including 3D rotation and scale can be created using methods +/// such as [`Self::from_diagonal()`], [`Self::from_quat()`], [`Self::from_axis_angle()`], +/// [`Self::from_rotation_x()`], [`Self::from_rotation_y()`], or +/// [`Self::from_rotation_z()`]. +/// +/// The resulting matrices can be use to transform 3D vectors using regular vector +/// multiplication. +/// +/// Affine transformations including 2D translation, rotation and scale can be created +/// using methods such as [`Self::from_translation()`], [`Self::from_angle()`], +/// [`Self::from_scale()`] and [`Self::from_scale_angle_translation()`]. +/// +/// The [`Self::transform_point2()`] and [`Self::transform_vector2()`] convenience methods +/// are provided for performing affine transforms on 2D vectors and points. These multiply +/// 2D inputs as 3D vectors with an implicit `z` value of `1` for points and `0` for +/// vectors respectively. These methods assume that `Self` contains a valid affine +/// transform. +{%- elif dim == 4 %} +/// +/// This 4x4 matrix type features convenience methods for creating and using affine transforms and +/// perspective projections. If you are primarily dealing with 3D affine transformations +/// considering using [`{{affine3_t}}`](crate::{{ affine3_t }}) which is faster than a 4x4 matrix +/// for some affine operations. +/// +/// Affine transformations including 3D translation, rotation and scale can be created +/// using methods such as [`Self::from_translation()`], [`Self::from_quat()`], +/// [`Self::from_scale()`] and [`Self::from_scale_rotation_translation()`]. +/// +/// Othographic projections can be created using the methods [`Self::orthographic_lh()`] for +/// left-handed coordinate systems and [`Self::orthographic_rh()`] for right-handed +/// systems. The resulting matrix is also an affine transformation. +/// +/// The [`Self::transform_point3()`] and [`Self::transform_vector3()`] convenience methods +/// are provided for performing affine transformations on 3D vectors and points. These +/// multiply 3D inputs as 4D vectors with an implicit `w` value of `1` for points and `0` +/// for vectors respectively. These methods assume that `Self` contains a valid affine +/// transform. +/// +/// Perspective projections can be created using methods such as +/// [`Self::perspective_lh()`], [`Self::perspective_infinite_lh()`] and +/// [`Self::perspective_infinite_reverse_lh()`] for left-handed co-ordinate systems and +/// [`Self::perspective_rh()`], [`Self::perspective_infinite_rh()`] and +/// [`Self::perspective_infinite_reverse_rh()`] for right-handed co-ordinate systems. +/// +/// The resulting perspective project can be use to transform 3D vectors as points with +/// perspective correction using the [`Self::project_point3()`] convenience method. +{%- endif %} +#[derive(Clone, Copy)] +{%- if self_t == "Mat4" and is_scalar %} +#[cfg_attr( + any( + not(any(feature = "scalar-math", target_arch = "spirv")), + feature = "cuda"), + repr(C, align(16)) +)] +{%- elif self_t == "Mat2" and is_scalar %} +#[cfg_attr(not(any(feature = "scalar-math", target_arch = "spirv")), repr(C, align(16)))] +#[cfg_attr(feature = "cuda", repr(C, align(8)))] +{%- elif self_t == "DMat2" or self_t == "DMat4" %} +#[cfg_attr(feature = "cuda", repr(align(16)))] +{%- endif %} +{%- if self_t == "Mat2" and not is_scalar %} +#[repr(transparent)] +pub struct {{ self_t }}(pub(crate) {{ simd_t }}); +{% else %} +pub struct {{ self_t }} +{ + {% for axis in axes %} + pub {{ axis }}: {{ col_t }}, + {%- endfor %} +} +{% endif %} + +impl {{ self_t }} { + /// A {{ nxn }} matrix with all elements set to `0.0`. + pub const ZERO: Self = Self::from_cols( + {% for axis in axes %} + {{ col_t }}::ZERO, + {%- endfor %} + ); + + /// A {{ nxn }} identity matrix, where all diagonal elements are `1`, and all off-diagonal elements are `0`. + pub const IDENTITY: Self = Self::from_cols( + {% for i in range(end = dim) %} + {{ col_t }}::{{ components[i] | upper }}, + {%- endfor %} + ); + + /// All NAN:s. + pub const NAN: Self = Self::from_cols( + {% for axis in axes %} + {{ col_t }}::NAN, + {%- endfor %} + ); + + #[allow(clippy::too_many_arguments)] + #[inline(always)] + const fn new( + {% for i in range(end = dim) %} + {%- for j in range(end = dim) %} + m{{ i }}{{ j }}: {{ scalar_t }}, + {%- endfor %} + {%- endfor %} + ) -> Self { + {% if self_t == "Mat2" and is_sse2 %} + unsafe { UnionCast { a: [m00, m01, m10, m11] }.v } + {% elif self_t == "Mat2" and is_wasm32 %} + Self(f32x4(m00, m01, m10, m11)) + {% else %} + Self { + {% for i in range(end = dim) %} + {{ axes[i] }}: {{ col_t}}::new( + {% for j in range(end = dim) %} + m{{ i }}{{ j }}, + {% endfor %} + ), + {%- endfor %} + } + {% endif %} + } + + /// Creates a {{ nxn }} matrix from two column vectors. + #[inline(always)] + pub const fn from_cols( + {% for axis in axes %} + {{ axis }}: {{ col_t }}, + {% endfor %} + ) -> Self { + {% if self_t == "Mat2" and is_sse2 %} + unsafe { UnionCast { a: [x_axis.x, x_axis.y, y_axis.x, y_axis.y] }.v } + {% elif self_t == "Mat2" and is_wasm32 %} + Self(f32x4(x_axis.x, x_axis.y, y_axis.x, y_axis.y)) + {% else %} + Self { + {% for axis in axes %} + {{ axis }}, + {%- endfor %} + } + {% endif %} + } + + /// Creates a {{ nxn }} matrix from a `[{{ scalar_t }}; {{ size }}]` array stored in column major order. + /// If your data is stored in row major you will need to `transpose` the returned + /// matrix. + #[inline] + pub const fn from_cols_array(m: &[{{ scalar_t }}; {{ size }}]) -> Self { + Self::new( + {% for i in range(end = size) %} + m[{{ i }}], + {%- endfor %} + ) + } + + /// Creates a `[{{ scalar_t }}; {{ size }}]` array storing data in column major order. + /// If you require data in row major order `transpose` the matrix first. + #[inline] + pub fn to_cols_array(&self) -> [{{ scalar_t }}; {{ size }}] { + [ + {% for axis in axes %} + {% for c in components %} + self.{{ axis }}.{{ c }}, + {%- endfor %} + {%- endfor %} + ] + } + + /// Creates a {{ nxn }} matrix from a `[[{{ scalar_t }}; {{ dim }}]; {{ dim }}]` {{ dim }}D array stored in column major order. + /// If your data is in row major order you will need to `transpose` the returned + /// matrix. + #[inline] + pub const fn from_cols_array_2d(m: &[[{{ scalar_t }}; {{ dim }}]; {{ dim }}]) -> Self { + Self::from_cols( + {% for i in range(end = dim) %} + {{ col_t }}::from_array(m[{{ i }}]), + {%- endfor %} + ) + } + + /// Creates a `[[{{ scalar_t }}; {{ dim }}]; {{ dim }}]` {{ dim }}D array storing data in column major order. + /// If you require data in row major order `transpose` the matrix first. + #[inline] + pub fn to_cols_array_2d(&self) -> [[{{ scalar_t }}; {{ dim }}]; {{ dim }}] { + [ + {% for axis in axes %} + self.{{ axis }}.to_array(), + {%- endfor %} + ] + } + + /// Creates a {{ nxn }} matrix with its diagonal set to `diagonal` and all other entries set to 0. + #[doc(alias = "scale")] + #[inline] + pub fn from_diagonal(diagonal: {{ vecn_t }}) -> Self { + Self::new( + {% for i in range(end = dim) %} + {% for j in range(end = dim) %} + {% if i == j %} + diagonal.{{ components[i] }}, + {% else %} + 0.0, + {% endif %} + {%- endfor %} + {%- endfor %} + ) + } + +{% if dim == 2 %} + /// Creates a {{ nxn }} matrix containing the combining non-uniform `scale` and rotation of + /// `angle` (in radians). + #[inline] + pub fn from_scale_angle(scale: {{ col_t }}, angle: {{ scalar_t }}) -> Self { + let (sin, cos) = angle.sin_cos(); + Self::new(cos * scale.x, sin * scale.x, -sin * scale.y, cos * scale.y) + } + + /// Creates a {{ nxn }} matrix containing a rotation of `angle` (in radians). + #[inline] + pub fn from_angle(angle: {{ scalar_t }}) -> Self { + let (sin, cos) = angle.sin_cos(); + Self::new(cos, sin, -sin, cos) + } + + /// Creates a {{ nxn }} matrix from a 3x3 matrix, discarding the 2nd row and column. + #[inline] + pub fn from_mat3(m: {{ mat3_t }}) -> Self { + Self::from_cols(m.x_axis.xy(), m.y_axis.xy()) + } +{% elif dim == 3 %} + /// Creates a 3x3 matrix from a 4x4 matrix, discarding the 3rd row and column. + pub fn from_mat4(m: {{ mat4_t }}) -> Self { + {% if self_t == "Mat3A" %} + Self::from_cols( + m.x_axis.into(), + m.y_axis.into(), + m.z_axis.into(), + ) + {% else %} + Self::from_cols( + m.x_axis.xyz(), + m.y_axis.xyz(), + m.z_axis.xyz(), + ) + {% endif %} + } + + /// Creates a 3D rotation matrix from the given quaternion. + /// + /// # Panics + /// + /// Will panic if `rotation` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn from_quat(rotation: {{ quat_t }}) -> Self { + glam_assert!(rotation.is_normalized()); + + let x2 = rotation.x + rotation.x; + let y2 = rotation.y + rotation.y; + let z2 = rotation.z + rotation.z; + let xx = rotation.x * x2; + let xy = rotation.x * y2; + let xz = rotation.x * z2; + let yy = rotation.y * y2; + let yz = rotation.y * z2; + let zz = rotation.z * z2; + let wx = rotation.w * x2; + let wy = rotation.w * y2; + let wz = rotation.w * z2; + + Self::from_cols( + {{ col_t }}::new(1.0 - (yy + zz), xy + wz, xz - wy), + {{ col_t }}::new(xy - wz, 1.0 - (xx + zz), yz + wx), + {{ col_t }}::new(xz + wy, yz - wx, 1.0 - (xx + yy)), + ) + } + + /// Creates a 3D rotation matrix from a normalized rotation `axis` and `angle` (in + /// radians). + /// + /// # Panics + /// + /// Will panic if `axis` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn from_axis_angle(axis: {{ vec3_t }}, angle: {{ scalar_t }}) -> Self { + {# TODO: make common with dim == 4 #} + glam_assert!(axis.is_normalized()); + + let (sin, cos) = angle.sin_cos(); + let (xsin, ysin, zsin) = axis.mul(sin).into(); + let (x, y, z) = axis.into(); + let (x2, y2, z2) = axis.mul(axis).into(); + let omc = 1.0 - cos; + let xyomc = x * y * omc; + let xzomc = x * z * omc; + let yzomc = y * z * omc; + Self::from_cols( + {{ col_t }}::new(x2 * omc + cos, xyomc + zsin, xzomc - ysin), + {{ col_t }}::new(xyomc - zsin, y2 * omc + cos, yzomc + xsin), + {{ col_t }}::new(xzomc + ysin, yzomc - xsin, z2 * omc + cos), + ) + } + + #[inline] + /// Creates a 3D rotation matrix from the given euler rotation sequence and the angles (in + /// radians). + pub fn from_euler(order: EulerRot, a: {{ scalar_t }}, b: {{ scalar_t }}, c: {{ scalar_t }}) -> Self { + let quat = {{ quat_t }}::from_euler(order, a, b, c); + Self::from_quat(quat) + } + + /// Creates a 3D rotation matrix from `angle` (in radians) around the x axis. + #[inline] + pub fn from_rotation_x(angle: {{ scalar_t }}) -> Self { + let (sina, cosa) = angle.sin_cos(); + Self::from_cols( + {{ col_t }}::X, + {{ col_t }}::new(0.0, cosa, sina), + {{ col_t }}::new(0.0, -sina, cosa), + ) + } + + /// Creates a 3D rotation matrix from `angle` (in radians) around the y axis. + #[inline] + pub fn from_rotation_y(angle: {{ scalar_t }}) -> Self { + let (sina, cosa) = angle.sin_cos(); + Self::from_cols( + {{ col_t }}::new(cosa, 0.0, -sina), + {{ col_t }}::Y, + {{ col_t }}::new(sina, 0.0, cosa), + ) + } + + /// Creates a 3D rotation matrix from `angle` (in radians) around the z axis. + #[inline] + pub fn from_rotation_z(angle: {{ scalar_t }}) -> Self { + let (sina, cosa) = angle.sin_cos(); + Self::from_cols( + {{ col_t }}::new(cosa, sina, 0.0), + {{ col_t }}::new(-sina, cosa, 0.0), + {{ col_t }}::Z, + ) + } + + /// Creates an affine transformation matrix from the given 2D `translation`. + /// + /// The resulting matrix can be used to transform 2D points and vectors. See + /// [`Self::transform_point2()`] and [`Self::transform_vector2()`]. + #[inline] + pub fn from_translation(translation: {{ vec2_t }}) -> Self { + Self::from_cols( + {{ col_t }}::X, + {{ col_t }}::Y, + {{ col_t }}::new(translation.x, translation.y, 1.0)) + } + + /// Creates an affine transformation matrix from the given 2D rotation `angle` (in + /// radians). + /// + /// The resulting matrix can be used to transform 2D points and vectors. See + /// [`Self::transform_point2()`] and [`Self::transform_vector2()`]. + #[inline] + pub fn from_angle(angle: {{ scalar_t }}) -> Self { + let (sin, cos) = angle.sin_cos(); + Self::from_cols( + {{ col_t }}::new(cos, sin, 0.0), + {{ col_t }}::new(-sin, cos, 0.0), + {{ col_t }}::Z, + ) + } + + /// Creates an affine transformation matrix from the given 2D `scale`, rotation `angle` (in + /// radians) and `translation`. + /// + /// The resulting matrix can be used to transform 2D points and vectors. See + /// [`Self::transform_point2()`] and [`Self::transform_vector2()`]. + #[inline] + pub fn from_scale_angle_translation(scale: {{ vec2_t }}, angle: {{ scalar_t }}, translation: {{ vec2_t }}) -> Self { + let (sin, cos) = angle.sin_cos(); + Self::from_cols( + {{ col_t }}::new(cos * scale.x, sin * scale.x, 0.0), + {{ col_t }}::new(-sin * scale.y, cos * scale.y, 0.0), + {{ col_t }}::new(translation.x, translation.y, 1.0), + ) + } + + /// Creates an affine transformation matrix from the given non-uniform 2D `scale`. + /// + /// The resulting matrix can be used to transform 2D points and vectors. See + /// [`Self::transform_point2()`] and [`Self::transform_vector2()`]. + /// + /// # Panics + /// + /// Will panic if all elements of `scale` are zero when `glam_assert` is enabled. + #[inline] + pub fn from_scale(scale: {{ vec2_t }}) -> Self { + // Do not panic as long as any component is non-zero + glam_assert!(scale.cmpne({{ vec2_t }}::ZERO).any()); + + Self::from_cols( + {{ col_t }}::new(scale.x, 0.0, 0.0), + {{ col_t }}::new(0.0, scale.y, 0.0), + {{ col_t }}::Z, + ) + } + + /// Creates an affine transformation matrix from the given 2x2 matrix. + /// + /// The resulting matrix can be used to transform 2D points and vectors. See + /// [`Self::transform_point2()`] and [`Self::transform_vector2()`]. + #[inline] + pub fn from_mat2(m: {{ mat2_t }}) -> Self { + Self::from_cols((m.x_axis, 0.0).into(), (m.y_axis, 0.0).into(), {{ col_t }}::Z) + } + +{% elif dim == 4 %} + fn quat_to_axes(rotation: {{ quat_t }}) -> ({{ col_t }}, {{ col_t }}, {{ col_t }}) { + glam_assert!(rotation.is_normalized()); + + let (x, y, z, w) = rotation.into(); + let x2 = x + x; + let y2 = y + y; + let z2 = z + z; + let xx = x * x2; + let xy = x * y2; + let xz = x * z2; + let yy = y * y2; + let yz = y * z2; + let zz = z * z2; + let wx = w * x2; + let wy = w * y2; + let wz = w * z2; + + let x_axis = {{ col_t }}::new(1.0 - (yy + zz), xy + wz, xz - wy, 0.0); + let y_axis = {{ col_t }}::new(xy - wz, 1.0 - (xx + zz), yz + wx, 0.0); + let z_axis = {{ col_t }}::new(xz + wy, yz - wx, 1.0 - (xx + yy), 0.0); + (x_axis, y_axis, z_axis) + } + + /// Creates an affine transformation matrix from the given 3D `scale`, `rotation` and + /// `translation`. + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + /// + /// # Panics + /// + /// Will panic if `rotation` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn from_scale_rotation_translation( + scale: {{ vec3_t }}, + rotation: {{ quat_t }}, + translation: {{ vec3_t }}, + ) -> Self { + let (x_axis, y_axis, z_axis) = Self::quat_to_axes(rotation); + Self::from_cols( + x_axis.mul(scale.x), + y_axis.mul(scale.y), + z_axis.mul(scale.z), + {{ col_t }}::from((translation, 1.0)), + ) + } + + /// Creates an affine transformation matrix from the given 3D `translation`. + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + /// + /// # Panics + /// + /// Will panic if `rotation` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn from_rotation_translation(rotation: {{ quat_t }}, translation: {{ vec3_t }}) -> Self { + let (x_axis, y_axis, z_axis) = Self::quat_to_axes(rotation); + Self::from_cols(x_axis, y_axis, z_axis, {{ col_t }}::from((translation, 1.0))) + } + + /// Extracts `scale`, `rotation` and `translation` from `self`. The input matrix is + /// expected to be a 3D affine transformation matrix otherwise the output will be invalid. + /// + /// # Panics + /// + /// Will panic if the determinant of `self` is zero or if the resulting scale vector + /// contains any zero elements when `glam_assert` is enabled. + #[inline] + pub fn to_scale_rotation_translation(&self) -> ({{ vec3_t }}, {{ quat_t }}, {{ vec3_t }}) { + let det = self.determinant(); + glam_assert!(det != 0.0); + + let scale = {{ vec3_t }}::new( + self.x_axis.length() * det.signum(), + self.y_axis.length(), + self.z_axis.length(), + ); + + glam_assert!(scale.cmpne({{ vec3_t }}::ZERO).all()); + + let inv_scale = scale.recip(); + + let rotation = {{ quat_t }}::from_rotation_axes( + self.x_axis.mul(inv_scale.x).xyz(), + self.y_axis.mul(inv_scale.y).xyz(), + self.z_axis.mul(inv_scale.z).xyz(), + ); + + let translation = self.w_axis.xyz(); + + (scale, rotation, translation) + } + + /// Creates an affine transformation matrix from the given `rotation` quaternion. + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + /// + /// # Panics + /// + /// Will panic if `rotation` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn from_quat(rotation: {{ quat_t }}) -> Self { + let (x_axis, y_axis, z_axis) = Self::quat_to_axes(rotation); + Self::from_cols(x_axis, y_axis, z_axis, {{ col_t }}::W) + } + + /// Creates an affine transformation matrix from the given 3x3 linear transformation + /// matrix. + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + #[inline] + pub fn from_mat3(m: {{ mat3_t }}) -> Self { + Self::from_cols( + {{ col_t }}::from((m.x_axis, 0.0)), + {{ col_t }}::from((m.y_axis, 0.0)), + {{ col_t }}::from((m.z_axis, 0.0)), + {{ col_t }}::W, + ) + } + + /// Creates an affine transformation matrix from the given 3D `translation`. + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + #[inline] + pub fn from_translation(translation: {{ vec3_t }}) -> Self { + Self::from_cols( + {{ col_t }}::X, + {{ col_t }}::Y, + {{ col_t }}::Z, + {{ col_t }}::new(translation.x, translation.y, translation.z, 1.0), + ) + } + + /// Creates an affine transformation matrix containing a 3D rotation around a normalized + /// rotation `axis` of `angle` (in radians). + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + /// + /// # Panics + /// + /// Will panic if `axis` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn from_axis_angle(axis: {{ vec3_t }}, angle: {{ scalar_t }}) -> Self { + {# TODO: make common with dim == 3 #} + glam_assert!(axis.is_normalized()); + + let (sin, cos) = angle.sin_cos(); + let axis_sin = axis.mul(sin); + let axis_sq = axis.mul(axis); + let omc = 1.0 - cos; + let xyomc = axis.x * axis.y * omc; + let xzomc = axis.x * axis.z * omc; + let yzomc = axis.y * axis.z * omc; + Self::from_cols( + {{ col_t }}::new( + axis_sq.x * omc + cos, + xyomc + axis_sin.z, + xzomc - axis_sin.y, + 0.0, + ), + {{ col_t }}::new( + xyomc - axis_sin.z, + axis_sq.y * omc + cos, + yzomc + axis_sin.x, + 0.0, + ), + {{ col_t }}::new( + xzomc + axis_sin.y, + yzomc - axis_sin.x, + axis_sq.z * omc + cos, + 0.0, + ), + {{ col_t }}::W, + ) + } + + #[inline] + /// Creates a affine transformation matrix containing a rotation from the given euler + /// rotation sequence and angles (in radians). + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + pub fn from_euler(order: EulerRot, a: {{ scalar_t }}, b: {{ scalar_t }}, c: {{ scalar_t }}) -> Self { + let quat = {{ quat_t }}::from_euler(order, a, b, c); + Self::from_quat(quat) + } + + /// Creates an affine transformation matrix containing a 3D rotation around the x axis of + /// `angle` (in radians). + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + #[inline] + pub fn from_rotation_x(angle: {{ scalar_t }}) -> Self { + let (sina, cosa) = angle.sin_cos(); + Self::from_cols( + {{ col_t }}::X, + {{ col_t }}::new(0.0, cosa, sina, 0.0), + {{ col_t }}::new(0.0, -sina, cosa, 0.0), + {{ col_t }}::W, + ) + } + + /// Creates an affine transformation matrix containing a 3D rotation around the y axis of + /// `angle` (in radians). + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + #[inline] + pub fn from_rotation_y(angle: {{ scalar_t }}) -> Self { + let (sina, cosa) = angle.sin_cos(); + Self::from_cols( + {{ col_t }}::new(cosa, 0.0, -sina, 0.0), + {{ col_t }}::Y, + {{ col_t }}::new(sina, 0.0, cosa, 0.0), + {{ col_t }}::W, + ) + } + + /// Creates an affine transformation matrix containing a 3D rotation around the z axis of + /// `angle` (in radians). + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + #[inline] + pub fn from_rotation_z(angle: {{ scalar_t }}) -> Self { + let (sina, cosa) = angle.sin_cos(); + Self::from_cols( + {{ col_t }}::new(cosa, sina, 0.0, 0.0), + {{ col_t }}::new(-sina, cosa, 0.0, 0.0), + {{ col_t }}::Z, + {{ col_t }}::W, + ) + } + + /// Creates an affine transformation matrix containing the given 3D non-uniform `scale`. + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + /// + /// # Panics + /// + /// Will panic if all elements of `scale` are zero when `glam_assert` is enabled. + #[inline] + pub fn from_scale(scale: {{ vec3_t }}) -> Self { + // Do not panic as long as any component is non-zero + glam_assert!(scale.cmpne({{ vec3_t }}::ZERO).any()); + + Self::from_cols( + {{ col_t }}::new(scale.x, 0.0, 0.0, 0.0), + {{ col_t }}::new(0.0, scale.y, 0.0, 0.0), + {{ col_t }}::new(0.0, 0.0, scale.z, 0.0), + {{ col_t }}::W, + ) + } +{% endif %} + + /// Creates a {{ nxn }} matrix from the first {{ size }} values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than {{ size }} elements long. + #[inline] + pub const fn from_cols_slice(slice: &[{{ scalar_t }}]) -> Self { + Self::new( + {% for i in range(end = size) %} + slice[{{ i }}], + {%- endfor %} + ) + } + + /// Writes the columns of `self` to the first {{ size }} elements in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than {{ size }} elements long. + #[inline] + pub fn write_cols_to_slice(self, slice: &mut [{{ scalar_t }}]) { + {% for i in range(end = dim) %} + {%- for j in range(end = dim) %} + slice[{{ i * dim + j }}] = self.{{ axes[i] }}.{{ components[j] }}; + {%- endfor %} + {%- endfor %} + } + + /// Returns the matrix column for the given `index`. + /// + /// # Panics + /// + /// Panics if `index` is greater than {{ dim - 1 }}. + #[inline] + pub fn col(&self, index: usize) -> {{ col_t }} { + match index { + {% for axis in axes %} + {{ loop.index0 }} => self.{{ axis }}, + {%- endfor %} + _ => panic!("index out of bounds"), + } + } + + /// Returns a mutable reference to the matrix column for the given `index`. + /// + /// # Panics + /// + /// Panics if `index` is greater than {{ dim - 1 }}. + #[inline] + pub fn col_mut(&mut self, index: usize) -> &mut {{ col_t }} { + match index { + {% for axis in axes %} + {{ loop.index0 }} => &mut self.{{ axis }}, + {%- endfor %} + _ => panic!("index out of bounds"), + } + } + + /// Returns the matrix row for the given `index`. + /// + /// # Panics + /// + /// Panics if `index` is greater than {{ dim - 1 }}. + #[inline] + pub fn row(&self, index: usize) -> {{ col_t }} { + match index { + {% for i in range(end=dim) %} + {{ i }} => {{ col_t }}::new( + {% for axis in axes %} + self.{{ axis }}.{{ components[i] }}, + {%- endfor %} + ), + {%- endfor %} + _ => panic!("index out of bounds"), + } + } + + /// Returns `true` if, and only if, all elements are finite. + /// If any element is either `NaN`, positive or negative infinity, this will return `false`. + #[inline] + pub fn is_finite(&self) -> bool { + {% for axis in axes %} + self.{{ axis }}.is_finite() {% if not loop.last %} && {% endif %} + {% endfor %} + } + + /// Returns `true` if any elements are `NaN`. + #[inline] + pub fn is_nan(&self) -> bool { + {% for axis in axes %} + self.{{ axis }}.is_nan() {% if not loop.last %} || {% endif %} + {% endfor %} + } + + /// Returns the transpose of `self`. + #[must_use] + #[inline] + pub fn transpose(&self) -> Self { + {% if self_t == "Mat2" and is_sse2 %} + Self(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_01_10_00) }) + {% elif self_t == "Mat2" and is_wasm32 %} + Self(i32x4_shuffle::<0, 2, 5, 7>(self.0, self.0)) + {% elif self_t == "Mat3A" and is_sse2 %} + unsafe { + let tmp0 = _mm_shuffle_ps(self.x_axis.0, self.y_axis.0, 0b01_00_01_00); + let tmp1 = _mm_shuffle_ps(self.x_axis.0, self.y_axis.0, 0b11_10_11_10); + + Self { + x_axis: Vec3A(_mm_shuffle_ps(tmp0, self.z_axis.0, 0b00_00_10_00)), + y_axis: Vec3A(_mm_shuffle_ps(tmp0, self.z_axis.0, 0b01_01_11_01)), + z_axis: Vec3A(_mm_shuffle_ps(tmp1, self.z_axis.0, 0b10_10_10_00)), + } + } + {% elif self_t == "Mat3A" and is_wasm32 %} + let tmp0 = i32x4_shuffle::<0, 1, 4, 5>(self.x_axis.0, self.y_axis.0); + let tmp1 = i32x4_shuffle::<2, 3, 6, 7>(self.x_axis.0, self.y_axis.0); + + Self { + x_axis: Vec3A(i32x4_shuffle::<0, 2, 4, 4>(tmp0, self.z_axis.0)), + y_axis: Vec3A(i32x4_shuffle::<1, 3, 5, 5>(tmp0, self.z_axis.0)), + z_axis: Vec3A(i32x4_shuffle::<0, 2, 6, 6>(tmp1, self.z_axis.0)), + } + {% elif self_t == "Mat4" and is_sse2 %} + unsafe { + // Based on https://github.com/microsoft/DirectXMath `XMMatrixTranspose` + let tmp0 = _mm_shuffle_ps(self.x_axis.0, self.y_axis.0, 0b01_00_01_00); + let tmp1 = _mm_shuffle_ps(self.x_axis.0, self.y_axis.0, 0b11_10_11_10); + let tmp2 = _mm_shuffle_ps(self.z_axis.0, self.w_axis.0, 0b01_00_01_00); + let tmp3 = _mm_shuffle_ps(self.z_axis.0, self.w_axis.0, 0b11_10_11_10); + + Self { + x_axis: Vec4(_mm_shuffle_ps(tmp0, tmp2, 0b10_00_10_00)), + y_axis: Vec4(_mm_shuffle_ps(tmp0, tmp2, 0b11_01_11_01)), + z_axis: Vec4(_mm_shuffle_ps(tmp1, tmp3, 0b10_00_10_00)), + w_axis: Vec4(_mm_shuffle_ps(tmp1, tmp3, 0b11_01_11_01)), + } + } + {% elif self_t == "Mat4" and is_wasm32 %} + // Based on https://github.com/microsoft/DirectXMath `XMMatrixTranspose` + let tmp0 = i32x4_shuffle::<0, 1, 4, 5>(self.x_axis.0, self.y_axis.0); + let tmp1 = i32x4_shuffle::<2, 3, 6, 7>(self.x_axis.0, self.y_axis.0); + let tmp2 = i32x4_shuffle::<0, 1, 4, 5>(self.z_axis.0, self.w_axis.0); + let tmp3 = i32x4_shuffle::<2, 3, 6, 7>(self.z_axis.0, self.w_axis.0); + + Self { + x_axis: Vec4(i32x4_shuffle::<0, 2, 4, 6>(tmp0, tmp2)), + y_axis: Vec4(i32x4_shuffle::<1, 3, 5, 7>(tmp0, tmp2)), + z_axis: Vec4(i32x4_shuffle::<0, 2, 4, 6>(tmp1, tmp3)), + w_axis: Vec4(i32x4_shuffle::<1, 3, 5, 7>(tmp1, tmp3)), + } + {% else %} + Self { + {% for i in range(end = dim) %} + {{ axes[i] }}: {{ col_t }}::new( + {% for j in range(end = dim) %} + self.{{ axes[j] }}.{{ components[i] }}, + {% endfor %} + ), + {%- endfor %} + } + {% endif %} + } + + /// Returns the determinant of `self`. + {%- if dim < 3 %} + #[inline] + {%- endif %} + pub fn determinant(&self) -> {{ scalar_t }} { + {% if self_t == "Mat2" and is_sse2 %} + unsafe { + let abcd = self.0; + let dcba = _mm_shuffle_ps(abcd, abcd, 0b00_01_10_11); + let prod = _mm_mul_ps(abcd, dcba); + let det = _mm_sub_ps(prod, _mm_shuffle_ps(prod, prod, 0b01_01_01_01)); + _mm_cvtss_f32(det) + } + {% elif self_t == "Mat2" and is_wasm32 %} + let abcd = self.0; + let dcba = i32x4_shuffle::<3, 2, 5, 4>(abcd, abcd); + let prod = f32x4_mul(abcd, dcba); + let det = f32x4_sub(prod, i32x4_shuffle::<1, 1, 5, 5>(prod, prod)); + f32x4_extract_lane::<0>(det) + {% elif self_t == "Mat4" and is_sse2 %} + unsafe { + // Based on https://github.com/g-truc/glm `glm_mat4_determinant_lowp` + let swp2a = _mm_shuffle_ps(self.z_axis.0, self.z_axis.0, 0b00_01_01_10); + let swp3a = _mm_shuffle_ps(self.w_axis.0, self.w_axis.0, 0b11_10_11_11); + let swp2b = _mm_shuffle_ps(self.z_axis.0, self.z_axis.0, 0b11_10_11_11); + let swp3b = _mm_shuffle_ps(self.w_axis.0, self.w_axis.0, 0b00_01_01_10); + let swp2c = _mm_shuffle_ps(self.z_axis.0, self.z_axis.0, 0b00_00_01_10); + let swp3c = _mm_shuffle_ps(self.w_axis.0, self.w_axis.0, 0b01_10_00_00); + + let mula = _mm_mul_ps(swp2a, swp3a); + let mulb = _mm_mul_ps(swp2b, swp3b); + let mulc = _mm_mul_ps(swp2c, swp3c); + let sube = _mm_sub_ps(mula, mulb); + let subf = _mm_sub_ps(_mm_movehl_ps(mulc, mulc), mulc); + + let subfaca = _mm_shuffle_ps(sube, sube, 0b10_01_00_00); + let swpfaca = _mm_shuffle_ps(self.y_axis.0, self.y_axis.0, 0b00_00_00_01); + let mulfaca = _mm_mul_ps(swpfaca, subfaca); + + let subtmpb = _mm_shuffle_ps(sube, subf, 0b00_00_11_01); + let subfacb = _mm_shuffle_ps(subtmpb, subtmpb, 0b11_01_01_00); + let swpfacb = _mm_shuffle_ps(self.y_axis.0, self.y_axis.0, 0b01_01_10_10); + let mulfacb = _mm_mul_ps(swpfacb, subfacb); + + let subres = _mm_sub_ps(mulfaca, mulfacb); + let subtmpc = _mm_shuffle_ps(sube, subf, 0b01_00_10_10); + let subfacc = _mm_shuffle_ps(subtmpc, subtmpc, 0b11_11_10_00); + let swpfacc = _mm_shuffle_ps(self.y_axis.0, self.y_axis.0, 0b10_11_11_11); + let mulfacc = _mm_mul_ps(swpfacc, subfacc); + + let addres = _mm_add_ps(subres, mulfacc); + let detcof = _mm_mul_ps(addres, _mm_setr_ps(1.0, -1.0, 1.0, -1.0)); + + crate::sse2::dot4(self.x_axis.0, detcof) + } + {% elif self_t == "Mat4" and is_wasm32 %} + // Based on https://github.com/g-truc/glm `glm_mat4_determinant` + let swp2a = i32x4_shuffle::<2, 1, 1, 0>(self.z_axis.0, self.z_axis.0); + let swp3a = i32x4_shuffle::<3, 3, 2, 3>(self.w_axis.0, self.w_axis.0); + let swp2b = i32x4_shuffle::<3, 3, 2, 3>(self.z_axis.0, self.z_axis.0); + let swp3b = i32x4_shuffle::<2, 1, 1, 0>(self.w_axis.0, self.w_axis.0); + let swp2c = i32x4_shuffle::<2, 1, 0, 0>(self.z_axis.0, self.z_axis.0); + let swp3c = i32x4_shuffle::<0, 0, 2, 1>(self.w_axis.0, self.w_axis.0); + + let mula = f32x4_mul(swp2a, swp3a); + let mulb = f32x4_mul(swp2b, swp3b); + let mulc = f32x4_mul(swp2c, swp3c); + let sube = f32x4_sub(mula, mulb); + let subf = f32x4_sub(i32x4_shuffle::<6, 7, 2, 3>(mulc, mulc), mulc); + + let subfaca = i32x4_shuffle::<0, 0, 1, 2>(sube, sube); + let swpfaca = i32x4_shuffle::<1, 0, 0, 0>(self.y_axis.0, self.y_axis.0); + let mulfaca = f32x4_mul(swpfaca, subfaca); + + let subtmpb = i32x4_shuffle::<1, 3, 4, 4>(sube, subf); + let subfacb = i32x4_shuffle::<0, 1, 1, 3>(subtmpb, subtmpb); + let swpfacb = i32x4_shuffle::<2, 2, 1, 1>(self.y_axis.0, self.y_axis.0); + let mulfacb = f32x4_mul(swpfacb, subfacb); + + let subres = f32x4_sub(mulfaca, mulfacb); + let subtmpc = i32x4_shuffle::<2, 2, 4, 5>(sube, subf); + let subfacc = i32x4_shuffle::<0, 2, 3, 3>(subtmpc, subtmpc); + let swpfacc = i32x4_shuffle::<3, 3, 3, 2>(self.y_axis.0, self.y_axis.0); + let mulfacc = f32x4_mul(swpfacc, subfacc); + + let addres = f32x4_add(subres, mulfacc); + let detcof = f32x4_mul(addres, f32x4(1.0, -1.0, 1.0, -1.0)); + + crate::wasm32::dot4(self.x_axis.0, detcof) + {% elif dim == 2 %} + self.x_axis.x * self.y_axis.y - self.x_axis.y * self.y_axis.x + {% elif dim == 3 %} + self.z_axis.dot(self.x_axis.cross(self.y_axis)) + {% elif dim == 4 %} + let (m00, m01, m02, m03) = self.x_axis.into(); + let (m10, m11, m12, m13) = self.y_axis.into(); + let (m20, m21, m22, m23) = self.z_axis.into(); + let (m30, m31, m32, m33) = self.w_axis.into(); + + 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) + {% endif %} + } + + /// Returns the inverse of `self`. + /// + /// If the matrix is not invertible the returned matrix will be invalid. + /// + /// # Panics + /// + /// Will panic if the determinant of `self` is zero when `glam_assert` is enabled. + #[must_use] + pub fn inverse(&self) -> Self { + {% if self_t == "Mat2" and is_sse2 %} + unsafe { + const SIGN: __m128 = const_f32x4!([1.0, -1.0, -1.0, 1.0]); + let abcd = self.0; + let dcba = _mm_shuffle_ps(abcd, abcd, 0b00_01_10_11); + let prod = _mm_mul_ps(abcd, dcba); + let sub = _mm_sub_ps(prod, _mm_shuffle_ps(prod, prod, 0b01_01_01_01)); + let det = _mm_shuffle_ps(sub, sub, 0b00_00_00_00); + let tmp = _mm_div_ps(SIGN, det); + glam_assert!(Mat2(tmp).is_finite()); + let dbca = _mm_shuffle_ps(abcd, abcd, 0b00_10_01_11); + Self(_mm_mul_ps(dbca, tmp)) + } + {% elif self_t == "Mat2" and is_wasm32 %} + const SIGN: v128 = const_f32x4!([1.0, -1.0, -1.0, 1.0]); + let abcd = self.0; + let dcba = i32x4_shuffle::<3, 2, 5, 4>(abcd, abcd); + let prod = f32x4_mul(abcd, dcba); + let sub = f32x4_sub(prod, i32x4_shuffle::<1, 1, 5, 5>(prod, prod)); + let det = i32x4_shuffle::<0, 0, 4, 4>(sub, sub); + let tmp = f32x4_div(SIGN, det); + glam_assert!(Mat2(tmp).is_finite()); + let dbca = i32x4_shuffle::<3, 1, 6, 4>(abcd, abcd); + Self(f32x4_mul(dbca, tmp)) + {% elif self_t == "Mat4" and is_sse2 %} + unsafe { + // Based on https://github.com/g-truc/glm `glm_mat4_inverse` + let fac0 = { + let swp0a = _mm_shuffle_ps(self.w_axis.0, self.z_axis.0, 0b11_11_11_11); + let swp0b = _mm_shuffle_ps(self.w_axis.0, self.z_axis.0, 0b10_10_10_10); + + let swp00 = _mm_shuffle_ps(self.z_axis.0, self.y_axis.0, 0b10_10_10_10); + let swp01 = _mm_shuffle_ps(swp0a, swp0a, 0b10_00_00_00); + let swp02 = _mm_shuffle_ps(swp0b, swp0b, 0b10_00_00_00); + let swp03 = _mm_shuffle_ps(self.z_axis.0, self.y_axis.0, 0b11_11_11_11); + + let mul00 = _mm_mul_ps(swp00, swp01); + let mul01 = _mm_mul_ps(swp02, swp03); + _mm_sub_ps(mul00, mul01) + }; + let fac1 = { + let swp0a = _mm_shuffle_ps(self.w_axis.0, self.z_axis.0, 0b11_11_11_11); + let swp0b = _mm_shuffle_ps(self.w_axis.0, self.z_axis.0, 0b01_01_01_01); + + let swp00 = _mm_shuffle_ps(self.z_axis.0, self.y_axis.0, 0b01_01_01_01); + let swp01 = _mm_shuffle_ps(swp0a, swp0a, 0b10_00_00_00); + let swp02 = _mm_shuffle_ps(swp0b, swp0b, 0b10_00_00_00); + let swp03 = _mm_shuffle_ps(self.z_axis.0, self.y_axis.0, 0b11_11_11_11); + + let mul00 = _mm_mul_ps(swp00, swp01); + let mul01 = _mm_mul_ps(swp02, swp03); + _mm_sub_ps(mul00, mul01) + }; + let fac2 = { + let swp0a = _mm_shuffle_ps(self.w_axis.0, self.z_axis.0, 0b10_10_10_10); + let swp0b = _mm_shuffle_ps(self.w_axis.0, self.z_axis.0, 0b01_01_01_01); + + let swp00 = _mm_shuffle_ps(self.z_axis.0, self.y_axis.0, 0b01_01_01_01); + let swp01 = _mm_shuffle_ps(swp0a, swp0a, 0b10_00_00_00); + let swp02 = _mm_shuffle_ps(swp0b, swp0b, 0b10_00_00_00); + let swp03 = _mm_shuffle_ps(self.z_axis.0, self.y_axis.0, 0b10_10_10_10); + + let mul00 = _mm_mul_ps(swp00, swp01); + let mul01 = _mm_mul_ps(swp02, swp03); + _mm_sub_ps(mul00, mul01) + }; + let fac3 = { + let swp0a = _mm_shuffle_ps(self.w_axis.0, self.z_axis.0, 0b11_11_11_11); + let swp0b = _mm_shuffle_ps(self.w_axis.0, self.z_axis.0, 0b00_00_00_00); + + let swp00 = _mm_shuffle_ps(self.z_axis.0, self.y_axis.0, 0b00_00_00_00); + let swp01 = _mm_shuffle_ps(swp0a, swp0a, 0b10_00_00_00); + let swp02 = _mm_shuffle_ps(swp0b, swp0b, 0b10_00_00_00); + let swp03 = _mm_shuffle_ps(self.z_axis.0, self.y_axis.0, 0b11_11_11_11); + + let mul00 = _mm_mul_ps(swp00, swp01); + let mul01 = _mm_mul_ps(swp02, swp03); + _mm_sub_ps(mul00, mul01) + }; + let fac4 = { + let swp0a = _mm_shuffle_ps(self.w_axis.0, self.z_axis.0, 0b10_10_10_10); + let swp0b = _mm_shuffle_ps(self.w_axis.0, self.z_axis.0, 0b00_00_00_00); + + let swp00 = _mm_shuffle_ps(self.z_axis.0, self.y_axis.0, 0b00_00_00_00); + let swp01 = _mm_shuffle_ps(swp0a, swp0a, 0b10_00_00_00); + let swp02 = _mm_shuffle_ps(swp0b, swp0b, 0b10_00_00_00); + let swp03 = _mm_shuffle_ps(self.z_axis.0, self.y_axis.0, 0b10_10_10_10); + + let mul00 = _mm_mul_ps(swp00, swp01); + let mul01 = _mm_mul_ps(swp02, swp03); + _mm_sub_ps(mul00, mul01) + }; + let fac5 = { + let swp0a = _mm_shuffle_ps(self.w_axis.0, self.z_axis.0, 0b01_01_01_01); + let swp0b = _mm_shuffle_ps(self.w_axis.0, self.z_axis.0, 0b00_00_00_00); + + let swp00 = _mm_shuffle_ps(self.z_axis.0, self.y_axis.0, 0b00_00_00_00); + let swp01 = _mm_shuffle_ps(swp0a, swp0a, 0b10_00_00_00); + let swp02 = _mm_shuffle_ps(swp0b, swp0b, 0b10_00_00_00); + let swp03 = _mm_shuffle_ps(self.z_axis.0, self.y_axis.0, 0b01_01_01_01); + + let mul00 = _mm_mul_ps(swp00, swp01); + let mul01 = _mm_mul_ps(swp02, swp03); + _mm_sub_ps(mul00, mul01) + }; + let sign_a = _mm_set_ps(1.0, -1.0, 1.0, -1.0); + let sign_b = _mm_set_ps(-1.0, 1.0, -1.0, 1.0); + + let temp0 = _mm_shuffle_ps(self.y_axis.0, self.x_axis.0, 0b00_00_00_00); + let vec0 = _mm_shuffle_ps(temp0, temp0, 0b10_10_10_00); + + let temp1 = _mm_shuffle_ps(self.y_axis.0, self.x_axis.0, 0b01_01_01_01); + let vec1 = _mm_shuffle_ps(temp1, temp1, 0b10_10_10_00); + + let temp2 = _mm_shuffle_ps(self.y_axis.0, self.x_axis.0, 0b10_10_10_10); + let vec2 = _mm_shuffle_ps(temp2, temp2, 0b10_10_10_00); + + let temp3 = _mm_shuffle_ps(self.y_axis.0, self.x_axis.0, 0b11_11_11_11); + let vec3 = _mm_shuffle_ps(temp3, temp3, 0b10_10_10_00); + + let mul00 = _mm_mul_ps(vec1, fac0); + let mul01 = _mm_mul_ps(vec2, fac1); + let mul02 = _mm_mul_ps(vec3, fac2); + let sub00 = _mm_sub_ps(mul00, mul01); + let add00 = _mm_add_ps(sub00, mul02); + let inv0 = _mm_mul_ps(sign_b, add00); + + let mul03 = _mm_mul_ps(vec0, fac0); + let mul04 = _mm_mul_ps(vec2, fac3); + let mul05 = _mm_mul_ps(vec3, fac4); + let sub01 = _mm_sub_ps(mul03, mul04); + let add01 = _mm_add_ps(sub01, mul05); + let inv1 = _mm_mul_ps(sign_a, add01); + + let mul06 = _mm_mul_ps(vec0, fac1); + let mul07 = _mm_mul_ps(vec1, fac3); + let mul08 = _mm_mul_ps(vec3, fac5); + let sub02 = _mm_sub_ps(mul06, mul07); + let add02 = _mm_add_ps(sub02, mul08); + let inv2 = _mm_mul_ps(sign_b, add02); + + let mul09 = _mm_mul_ps(vec0, fac2); + let mul10 = _mm_mul_ps(vec1, fac4); + let mul11 = _mm_mul_ps(vec2, fac5); + let sub03 = _mm_sub_ps(mul09, mul10); + let add03 = _mm_add_ps(sub03, mul11); + let inv3 = _mm_mul_ps(sign_a, add03); + + let row0 = _mm_shuffle_ps(inv0, inv1, 0b00_00_00_00); + let row1 = _mm_shuffle_ps(inv2, inv3, 0b00_00_00_00); + let row2 = _mm_shuffle_ps(row0, row1, 0b10_00_10_00); + + let dot0 = crate::sse2::dot4(self.x_axis.0, row2); + glam_assert!(dot0 != 0.0); + + let rcp0 = _mm_set1_ps(dot0.recip()); + + Self { + x_axis: Vec4(_mm_mul_ps(inv0, rcp0)), + y_axis: Vec4(_mm_mul_ps(inv1, rcp0)), + z_axis: Vec4(_mm_mul_ps(inv2, rcp0)), + w_axis: Vec4(_mm_mul_ps(inv3, rcp0)), + } + } + {% elif self_t == "Mat4" and is_wasm32 %} + // Based on https://github.com/g-truc/glm `glm_mat4_inverse` + let fac0 = { + let swp0a = i32x4_shuffle::<3, 3, 7, 7>(self.w_axis.0, self.z_axis.0); + let swp0b = i32x4_shuffle::<2, 2, 6, 6>(self.w_axis.0, self.z_axis.0); + + let swp00 = i32x4_shuffle::<2, 2, 6, 6>(self.z_axis.0, self.y_axis.0); + let swp01 = i32x4_shuffle::<0, 0, 4, 6>(swp0a, swp0a); + let swp02 = i32x4_shuffle::<0, 0, 4, 6>(swp0b, swp0b); + let swp03 = i32x4_shuffle::<3, 3, 7, 7>(self.z_axis.0, self.y_axis.0); + + let mul00 = f32x4_mul(swp00, swp01); + let mul01 = f32x4_mul(swp02, swp03); + f32x4_sub(mul00, mul01) + }; + let fac1 = { + let swp0a = i32x4_shuffle::<3, 3, 7, 7>(self.w_axis.0, self.z_axis.0); + let swp0b = i32x4_shuffle::<1, 1, 5, 5>(self.w_axis.0, self.z_axis.0); + + let swp00 = i32x4_shuffle::<1, 1, 5, 5>(self.z_axis.0, self.y_axis.0); + let swp01 = i32x4_shuffle::<0, 0, 4, 6>(swp0a, swp0a); + let swp02 = i32x4_shuffle::<0, 0, 4, 6>(swp0b, swp0b); + let swp03 = i32x4_shuffle::<3, 3, 7, 7>(self.z_axis.0, self.y_axis.0); + + let mul00 = f32x4_mul(swp00, swp01); + let mul01 = f32x4_mul(swp02, swp03); + f32x4_sub(mul00, mul01) + }; + let fac2 = { + let swp0a = i32x4_shuffle::<2, 2, 6, 6>(self.w_axis.0, self.z_axis.0); + let swp0b = i32x4_shuffle::<1, 1, 5, 5>(self.w_axis.0, self.z_axis.0); + + let swp00 = i32x4_shuffle::<1, 1, 5, 5>(self.z_axis.0, self.y_axis.0); + let swp01 = i32x4_shuffle::<0, 0, 4, 6>(swp0a, swp0a); + let swp02 = i32x4_shuffle::<0, 0, 4, 6>(swp0b, swp0b); + let swp03 = i32x4_shuffle::<2, 2, 6, 6>(self.z_axis.0, self.y_axis.0); + + let mul00 = f32x4_mul(swp00, swp01); + let mul01 = f32x4_mul(swp02, swp03); + f32x4_sub(mul00, mul01) + }; + let fac3 = { + let swp0a = i32x4_shuffle::<3, 3, 7, 7>(self.w_axis.0, self.z_axis.0); + let swp0b = i32x4_shuffle::<0, 0, 4, 4>(self.w_axis.0, self.z_axis.0); + + let swp00 = i32x4_shuffle::<0, 0, 4, 4>(self.z_axis.0, self.y_axis.0); + let swp01 = i32x4_shuffle::<0, 0, 4, 6>(swp0a, swp0a); + let swp02 = i32x4_shuffle::<0, 0, 4, 6>(swp0b, swp0b); + let swp03 = i32x4_shuffle::<3, 3, 7, 7>(self.z_axis.0, self.y_axis.0); + + let mul00 = f32x4_mul(swp00, swp01); + let mul01 = f32x4_mul(swp02, swp03); + f32x4_sub(mul00, mul01) + }; + let fac4 = { + let swp0a = i32x4_shuffle::<2, 2, 6, 6>(self.w_axis.0, self.z_axis.0); + let swp0b = i32x4_shuffle::<0, 0, 4, 4>(self.w_axis.0, self.z_axis.0); + + let swp00 = i32x4_shuffle::<0, 0, 4, 4>(self.z_axis.0, self.y_axis.0); + let swp01 = i32x4_shuffle::<0, 0, 4, 6>(swp0a, swp0a); + let swp02 = i32x4_shuffle::<0, 0, 4, 6>(swp0b, swp0b); + let swp03 = i32x4_shuffle::<2, 2, 6, 6>(self.z_axis.0, self.y_axis.0); + + let mul00 = f32x4_mul(swp00, swp01); + let mul01 = f32x4_mul(swp02, swp03); + f32x4_sub(mul00, mul01) + }; + let fac5 = { + let swp0a = i32x4_shuffle::<1, 1, 5, 5>(self.w_axis.0, self.z_axis.0); + let swp0b = i32x4_shuffle::<0, 0, 4, 4>(self.w_axis.0, self.z_axis.0); + + let swp00 = i32x4_shuffle::<0, 0, 4, 4>(self.z_axis.0, self.y_axis.0); + let swp01 = i32x4_shuffle::<0, 0, 4, 6>(swp0a, swp0a); + let swp02 = i32x4_shuffle::<0, 0, 4, 6>(swp0b, swp0b); + let swp03 = i32x4_shuffle::<1, 1, 5, 5>(self.z_axis.0, self.y_axis.0); + + let mul00 = f32x4_mul(swp00, swp01); + let mul01 = f32x4_mul(swp02, swp03); + f32x4_sub(mul00, mul01) + }; + let sign_a = f32x4(-1.0, 1.0, -1.0, 1.0); + let sign_b = f32x4(1.0, -1.0, 1.0, -1.0); + + let temp0 = i32x4_shuffle::<0, 0, 4, 4>(self.y_axis.0, self.x_axis.0); + let vec0 = i32x4_shuffle::<0, 2, 6, 6>(temp0, temp0); + + let temp1 = i32x4_shuffle::<1, 1, 5, 5>(self.y_axis.0, self.x_axis.0); + let vec1 = i32x4_shuffle::<0, 2, 6, 6>(temp1, temp1); + + let temp2 = i32x4_shuffle::<2, 2, 6, 6>(self.y_axis.0, self.x_axis.0); + let vec2 = i32x4_shuffle::<0, 2, 6, 6>(temp2, temp2); + + let temp3 = i32x4_shuffle::<3, 3, 7, 7>(self.y_axis.0, self.x_axis.0); + let vec3 = i32x4_shuffle::<0, 2, 6, 6>(temp3, temp3); + + let mul00 = f32x4_mul(vec1, fac0); + let mul01 = f32x4_mul(vec2, fac1); + let mul02 = f32x4_mul(vec3, fac2); + let sub00 = f32x4_sub(mul00, mul01); + let add00 = f32x4_add(sub00, mul02); + let inv0 = f32x4_mul(sign_b, add00); + + let mul03 = f32x4_mul(vec0, fac0); + let mul04 = f32x4_mul(vec2, fac3); + let mul05 = f32x4_mul(vec3, fac4); + let sub01 = f32x4_sub(mul03, mul04); + let add01 = f32x4_add(sub01, mul05); + let inv1 = f32x4_mul(sign_a, add01); + + let mul06 = f32x4_mul(vec0, fac1); + let mul07 = f32x4_mul(vec1, fac3); + let mul08 = f32x4_mul(vec3, fac5); + let sub02 = f32x4_sub(mul06, mul07); + let add02 = f32x4_add(sub02, mul08); + let inv2 = f32x4_mul(sign_b, add02); + + let mul09 = f32x4_mul(vec0, fac2); + let mul10 = f32x4_mul(vec1, fac4); + let mul11 = f32x4_mul(vec2, fac5); + let sub03 = f32x4_sub(mul09, mul10); + let add03 = f32x4_add(sub03, mul11); + let inv3 = f32x4_mul(sign_a, add03); + + let row0 = i32x4_shuffle::<0, 0, 4, 4>(inv0, inv1); + let row1 = i32x4_shuffle::<0, 0, 4, 4>(inv2, inv3); + let row2 = i32x4_shuffle::<0, 2, 4, 6>(row0, row1); + + let dot0 = crate::wasm32::dot4(self.x_axis.0, row2); + glam_assert!(dot0 != 0.0); + + let rcp0 = f32x4_splat(dot0.recip()); + + Self { + x_axis: Vec4(f32x4_mul(inv0, rcp0)), + y_axis: Vec4(f32x4_mul(inv1, rcp0)), + z_axis: Vec4(f32x4_mul(inv2, rcp0)), + w_axis: Vec4(f32x4_mul(inv3, rcp0)), + } + {% elif dim == 2 %} + let inv_det = { + let det = self.determinant(); + glam_assert!(det != 0.0); + det.recip() + }; + Self::new( + self.y_axis.y * inv_det, + self.x_axis.y * -inv_det, + self.y_axis.x * -inv_det, + self.x_axis.x * inv_det, + ) + {% elif dim == 3 %} + let tmp0 = self.y_axis.cross(self.z_axis); + let tmp1 = self.z_axis.cross(self.x_axis); + let tmp2 = self.x_axis.cross(self.y_axis); + let det = self.z_axis.dot(tmp2); + glam_assert!(det != 0.0); + let inv_det = {{ col_t }}::splat(det.recip()); + Self::from_cols(tmp0.mul(inv_det), tmp1.mul(inv_det), tmp2.mul(inv_det)).transpose() + {% elif dim == 4 %} + let (m00, m01, m02, m03) = self.x_axis.into(); + let (m10, m11, m12, m13) = self.y_axis.into(); + let (m20, m21, m22, m23) = self.z_axis.into(); + let (m30, m31, m32, m33) = self.w_axis.into(); + + let coef00 = m22 * m33 - m32 * m23; + let coef02 = m12 * m33 - m32 * m13; + let coef03 = m12 * m23 - m22 * m13; + + let coef04 = m21 * m33 - m31 * m23; + let coef06 = m11 * m33 - m31 * m13; + let coef07 = m11 * m23 - m21 * m13; + + let coef08 = m21 * m32 - m31 * m22; + let coef10 = m11 * m32 - m31 * m12; + let coef11 = m11 * m22 - m21 * m12; + + let coef12 = m20 * m33 - m30 * m23; + let coef14 = m10 * m33 - m30 * m13; + let coef15 = m10 * m23 - m20 * m13; + + let coef16 = m20 * m32 - m30 * m22; + let coef18 = m10 * m32 - m30 * m12; + let coef19 = m10 * m22 - m20 * m12; + + let coef20 = m20 * m31 - m30 * m21; + let coef22 = m10 * m31 - m30 * m11; + let coef23 = m10 * m21 - m20 * m11; + + let fac0 = {{ col_t }}::new(coef00, coef00, coef02, coef03); + let fac1 = {{ col_t }}::new(coef04, coef04, coef06, coef07); + let fac2 = {{ col_t }}::new(coef08, coef08, coef10, coef11); + let fac3 = {{ col_t }}::new(coef12, coef12, coef14, coef15); + let fac4 = {{ col_t }}::new(coef16, coef16, coef18, coef19); + let fac5 = {{ col_t }}::new(coef20, coef20, coef22, coef23); + + let vec0 = {{ col_t }}::new(m10, m00, m00, m00); + let vec1 = {{ col_t }}::new(m11, m01, m01, m01); + let vec2 = {{ col_t }}::new(m12, m02, m02, m02); + let vec3 = {{ col_t }}::new(m13, m03, m03, m03); + + let inv0 = vec1.mul(fac0).sub(vec2.mul(fac1)).add(vec3.mul(fac2)); + let inv1 = vec0.mul(fac0).sub(vec2.mul(fac3)).add(vec3.mul(fac4)); + let inv2 = vec0.mul(fac1).sub(vec1.mul(fac3)).add(vec3.mul(fac5)); + let inv3 = vec0.mul(fac2).sub(vec1.mul(fac4)).add(vec2.mul(fac5)); + + let sign_a = {{ col_t }}::new(1.0, -1.0, 1.0, -1.0); + let sign_b = {{ col_t }}::new(-1.0, 1.0, -1.0, 1.0); + + let inverse = Self::from_cols( + inv0.mul(sign_a), + inv1.mul(sign_b), + inv2.mul(sign_a), + inv3.mul(sign_b), + ); + + let col0 = {{ col_t }}::new( + inverse.x_axis.x, + inverse.y_axis.x, + inverse.z_axis.x, + inverse.w_axis.x, + ); + + let dot0 = self.x_axis.mul(col0); + let dot1 = dot0.x + dot0.y + dot0.z + dot0.w; + + glam_assert!(dot1 != 0.0); + + let rcp_det = dot1.recip(); + inverse.mul(rcp_det) + {% endif %} + } + +{% if dim == 3 %} + /// Transforms the given 2D vector as a point. + /// + /// This is the equivalent of multiplying `rhs` as a 3D vector where `z` is `1`. + /// + /// This method assumes that `self` contains a valid affine transform. + #[inline] + pub fn transform_point2(&self, rhs: {{ vec2_t }}) -> {{ vec2_t }} { + {{ mat2_t }}::from_cols(self.x_axis.xy(), self.y_axis.xy()) * rhs + self.z_axis.xy() + } + + /// Rotates the given 2D vector. + /// + /// This is the equivalent of multiplying `rhs` as a 3D vector where `z` is `0`. + /// + /// This method assumes that `self` contains a valid affine transform. + #[inline] + pub fn transform_vector2(&self, rhs: {{ vec2_t }}) -> {{ vec2_t }} { + {{ mat2_t }}::from_cols(self.x_axis.xy(), self.y_axis.xy()) * rhs + } + +{% elif dim == 4 %} + #[inline] + fn look_to_lh(eye: {{ vec3_t }}, dir: {{ vec3_t }}, up: {{ vec3_t }}) -> Self { + let f = dir.normalize(); + let s = up.cross(f).normalize(); + let u = f.cross(s); + Self::from_cols( + {{ col_t }}::new(s.x, u.x, f.x, 0.0), + {{ col_t }}::new(s.y, u.y, f.y, 0.0), + {{ col_t }}::new(s.z, u.z, f.z, 0.0), + {{ col_t }}::new(-s.dot(eye), -u.dot(eye), -f.dot(eye), 1.0), + ) + } + + /// Creates a left-handed view matrix using a camera position, an up direction, and a focal + /// point. + /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=forward`. + /// + /// # Panics + /// + /// Will panic if `up` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn look_at_lh(eye: {{ vec3_t }}, center: {{ vec3_t }}, up: {{ vec3_t }}) -> Self { + glam_assert!(up.is_normalized()); + Self::look_to_lh(eye, center.sub(eye), up) + } + + /// Creates a right-handed view matrix using a camera position, an up direction, and a focal + /// point. + /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=back`. + /// + /// # Panics + /// + /// Will panic if `up` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn look_at_rh(eye: {{ vec3_t }}, center: {{ vec3_t }}, up: {{ vec3_t }}) -> Self { + glam_assert!(up.is_normalized()); + Self::look_to_lh(eye, eye.sub(center), up) + } + + /// Creates a right-handed perspective projection matrix with [-1,1] depth range. + /// This is the same as the OpenGL `gluPerspective` function. + /// See + #[inline] + pub fn perspective_rh_gl( + fov_y_radians: {{ scalar_t }}, + aspect_ratio: {{ scalar_t }}, + z_near: {{ scalar_t }}, + z_far: {{ scalar_t }}, + ) -> Self { + let inv_length = 1.0 / (z_near - z_far); + let f = 1.0 / (0.5 * fov_y_radians).tan(); + let a = f / aspect_ratio; + let b = (z_near + z_far) * inv_length; + let c = (2.0 * z_near * z_far) * inv_length; + Self::from_cols( + {{ col_t }}::new(a, 0.0, 0.0, 0.0), + {{ col_t }}::new(0.0, f, 0.0, 0.0), + {{ col_t }}::new(0.0, 0.0, b, -1.0), + {{ col_t }}::new(0.0, 0.0, c, 0.0), + ) + } + + /// Creates a left-handed perspective projection matrix with `[0,1]` depth range. + /// + /// # Panics + /// + /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is + /// enabled. + #[inline] + pub fn perspective_lh(fov_y_radians: {{ scalar_t }}, aspect_ratio: {{ scalar_t }}, z_near: {{ scalar_t }}, z_far: {{ scalar_t }}) -> Self { + glam_assert!(z_near > 0.0 && z_far > 0.0); + let (sin_fov, cos_fov) = (0.5 * fov_y_radians).sin_cos(); + let h = cos_fov / sin_fov; + let w = h / aspect_ratio; + let r = z_far / (z_far - z_near); + Self::from_cols( + {{ col_t }}::new(w, 0.0, 0.0, 0.0), + {{ col_t }}::new(0.0, h, 0.0, 0.0), + {{ col_t }}::new(0.0, 0.0, r, 1.0), + {{ col_t }}::new(0.0, 0.0, -r * z_near, 0.0), + ) + } + + /// Creates a right-handed perspective projection matrix with `[0,1]` depth range. + /// + /// # Panics + /// + /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is + /// enabled. + #[inline] + pub fn perspective_rh(fov_y_radians: {{ scalar_t }}, aspect_ratio: {{ scalar_t }}, z_near: {{ scalar_t }}, z_far: {{ scalar_t }}) -> Self { + glam_assert!(z_near > 0.0 && z_far > 0.0); + let (sin_fov, cos_fov) = (0.5 * fov_y_radians).sin_cos(); + let h = cos_fov / sin_fov; + let w = h / aspect_ratio; + let r = z_far / (z_near - z_far); + Self::from_cols( + {{ col_t }}::new(w, 0.0, 0.0, 0.0), + {{ col_t }}::new(0.0, h, 0.0, 0.0), + {{ col_t }}::new(0.0, 0.0, r, -1.0), + {{ col_t }}::new(0.0, 0.0, r * z_near, 0.0), + ) + } + + /// Creates an infinite left-handed perspective projection matrix with `[0,1]` depth range. + /// + /// # Panics + /// + /// Will panic if `z_near` is less than or equal to zero when `glam_assert` is enabled. + #[inline] + pub fn perspective_infinite_lh(fov_y_radians: {{ scalar_t }}, aspect_ratio: {{ scalar_t }}, z_near: {{ scalar_t }}) -> Self { + glam_assert!(z_near > 0.0); + let (sin_fov, cos_fov) = (0.5 * fov_y_radians).sin_cos(); + let h = cos_fov / sin_fov; + let w = h / aspect_ratio; + Self::from_cols( + {{ col_t }}::new(w, 0.0, 0.0, 0.0), + {{ col_t }}::new(0.0, h, 0.0, 0.0), + {{ col_t }}::new(0.0, 0.0, 1.0, 1.0), + {{ col_t }}::new(0.0, 0.0, -z_near, 0.0), + ) + } + + /// Creates an infinite left-handed perspective projection matrix with `[0,1]` depth range. + /// + /// # Panics + /// + /// Will panic if `z_near` is less than or equal to zero when `glam_assert` is enabled. + #[inline] + pub fn perspective_infinite_reverse_lh( + fov_y_radians: {{ scalar_t }}, + aspect_ratio: {{ scalar_t }}, + z_near: {{ scalar_t }}, + ) -> Self { + glam_assert!(z_near > 0.0); + let (sin_fov, cos_fov) = (0.5 * fov_y_radians).sin_cos(); + let h = cos_fov / sin_fov; + let w = h / aspect_ratio; + Self::from_cols( + {{ col_t }}::new(w, 0.0, 0.0, 0.0), + {{ col_t }}::new(0.0, h, 0.0, 0.0), + {{ col_t }}::new(0.0, 0.0, 0.0, 1.0), + {{ col_t }}::new(0.0, 0.0, z_near, 0.0), + ) + } + + /// Creates an infinite right-handed perspective projection matrix with + /// `[0,1]` depth range. + #[inline] + pub fn perspective_infinite_rh(fov_y_radians: {{ scalar_t }}, aspect_ratio: {{ scalar_t }}, z_near: {{ scalar_t }}) -> Self { + glam_assert!(z_near > 0.0); + let f = 1.0 / (0.5 * fov_y_radians).tan(); + Self::from_cols( + {{ col_t }}::new(f / aspect_ratio, 0.0, 0.0, 0.0), + {{ col_t }}::new(0.0, f, 0.0, 0.0), + {{ col_t }}::new(0.0, 0.0, -1.0, -1.0), + {{ col_t }}::new(0.0, 0.0, -z_near, 0.0), + ) + } + + /// Creates an infinite reverse right-handed perspective projection matrix + /// with `[0,1]` depth range. + #[inline] + pub fn perspective_infinite_reverse_rh( + fov_y_radians: {{ scalar_t }}, + aspect_ratio: {{ scalar_t }}, + z_near: {{ scalar_t }}, + ) -> Self { + glam_assert!(z_near > 0.0); + let f = 1.0 / (0.5 * fov_y_radians).tan(); + Self::from_cols( + {{ col_t }}::new(f / aspect_ratio, 0.0, 0.0, 0.0), + {{ col_t }}::new(0.0, f, 0.0, 0.0), + {{ col_t }}::new(0.0, 0.0, 0.0, -1.0), + {{ col_t }}::new(0.0, 0.0, z_near, 0.0), + ) + } + + /// Creates a right-handed orthographic projection matrix with `[-1,1]` depth + /// range. This is the same as the OpenGL `glOrtho` function in OpenGL. + /// See + /// + #[inline] + pub fn orthographic_rh_gl( + left: {{ scalar_t }}, + right: {{ scalar_t }}, + bottom: {{ scalar_t }}, + top: {{ scalar_t }}, + near: {{ scalar_t }}, + far: {{ scalar_t }}, + ) -> Self { + let a = 2.0 / (right - left); + let b = 2.0 / (top - bottom); + let c = -2.0 / (far - near); + let tx = -(right + left) / (right - left); + let ty = -(top + bottom) / (top - bottom); + let tz = -(far + near) / (far - near); + + Self::from_cols( + {{ col_t }}::new(a, 0.0, 0.0, 0.0), + {{ col_t }}::new(0.0, b, 0.0, 0.0), + {{ col_t }}::new(0.0, 0.0, c, 0.0), + {{ col_t }}::new(tx, ty, tz, 1.0), + ) + } + + /// Creates a left-handed orthographic projection matrix with `[0,1]` depth range. + #[inline] + pub fn orthographic_lh( + left: {{ scalar_t }}, + right: {{ scalar_t }}, + bottom: {{ scalar_t }}, + top: {{ scalar_t }}, + near: {{ scalar_t }}, + far: {{ scalar_t }}, + ) -> Self { + let rcp_width = 1.0 / (right - left); + let rcp_height = 1.0 / (top - bottom); + let r = 1.0 / (far - near); + Self::from_cols( + {{ col_t }}::new(rcp_width + rcp_width, 0.0, 0.0, 0.0), + {{ col_t }}::new(0.0, rcp_height + rcp_height, 0.0, 0.0), + {{ col_t }}::new(0.0, 0.0, r, 0.0), + {{ col_t }}::new( + -(left + right) * rcp_width, + -(top + bottom) * rcp_height, + -r * near, + 1.0, + ), + ) + } + + /// Creates a right-handed orthographic projection matrix with `[0,1]` depth range. + #[inline] + pub fn orthographic_rh( + left: {{ scalar_t }}, + right: {{ scalar_t }}, + bottom: {{ scalar_t }}, + top: {{ scalar_t }}, + near: {{ scalar_t }}, + far: {{ scalar_t }}, + ) -> Self { + let rcp_width = 1.0 / (right - left); + let rcp_height = 1.0 / (top - bottom); + let r = 1.0 / (near - far); + Self::from_cols( + {{ col_t }}::new(rcp_width + rcp_width, 0.0, 0.0, 0.0), + {{ col_t }}::new(0.0, rcp_height + rcp_height, 0.0, 0.0), + {{ col_t }}::new(0.0, 0.0, r, 0.0), + {{ col_t }}::new( + -(left + right) * rcp_width, + -(top + bottom) * rcp_height, + r * near, + 1.0, + ), + ) + } + + /// Transforms the given 3D vector as a point, applying perspective correction. + /// + /// This is the equivalent of multiplying the 3D vector as a 4D vector where `w` is `1.0`. + /// The perspective divide is performed meaning the resulting 3D vector is divided by `w`. + /// + /// This method assumes that `self` contains a projective transform. + #[inline] + pub fn project_point3(&self, rhs: {{ vec3_t }}) -> {{ vec3_t }} { + let mut res = self.x_axis.mul(rhs.x); + res = self.y_axis.mul(rhs.y).add(res); + res = self.z_axis.mul(rhs.z).add(res); + res = self.w_axis.add(res); + res = res.mul(res.wwww().recip()); + res.xyz() + } + + /// Transforms the given 3D vector as a point. + /// + /// This is the equivalent of multiplying the 3D vector as a 4D vector where `w` is + /// `1.0`. + /// + /// This method assumes that `self` contains a valid affine transform. It does not perform + /// a persective divide, if `self` contains a perspective transform, or if you are unsure, + /// the [`Self::project_point3()`] method should be used instead. + /// + /// # Panics + /// + /// Will panic if the 3rd row of `self` is not `(0, 0, 0, 1)` when `glam_assert` is enabled. + #[inline] + pub fn transform_point3(&self, rhs: {{ vec3_t }}) -> {{ vec3_t }} { + glam_assert!(self.row(3) == {{ vec4_t }}::W); + let mut res = self.x_axis.mul(rhs.x); + res = self.y_axis.mul(rhs.y).add(res); + res = self.z_axis.mul(rhs.z).add(res); + res = self.w_axis.add(res); + res.xyz() + } + + /// Transforms the give 3D vector as a direction. + /// + /// This is the equivalent of multiplying the 3D vector as a 4D vector where `w` is + /// `0.0`. + /// + /// This method assumes that `self` contains a valid affine transform. + /// + /// # Panics + /// + /// Will panic if the 3rd row of `self` is not `(0, 0, 0, 1)` when `glam_assert` is enabled. + #[inline] + pub fn transform_vector3(&self, rhs: {{ vec3_t }}) -> {{ vec3_t }} { + glam_assert!(self.row(3) == {{ vec4_t }}::W); + let mut res = self.x_axis.mul(rhs.x); + res = self.y_axis.mul(rhs.y).add(res); + res = self.z_axis.mul(rhs.z).add(res); + res.xyz() + } + +{% endif %} + +{% if self_t == "Mat4" %} + /// Transforms the given `Vec3A` as 3D point. + /// + /// This is the equivalent of multiplying the `Vec3A` as a 4D vector where `w` is `1.0`. + #[inline] + pub fn transform_point3a(&self, rhs: Vec3A) -> Vec3A { + {% if is_scalar %} + self.transform_point3(rhs.into()).into() + {% else %} + let mut res = self.x_axis.mul(rhs.xxxx()); + res = self.y_axis.mul(rhs.yyyy()).add(res); + res = self.z_axis.mul(rhs.zzzz()).add(res); + res = self.w_axis.add(res); + res.into() + {% endif %} + } + + /// Transforms the give `Vec3A` as 3D vector. + /// + /// This is the equivalent of multiplying the `Vec3A` as a 4D vector where `w` is `0.0`. + #[inline] + pub fn transform_vector3a(&self, rhs: Vec3A) -> Vec3A { + {% if is_scalar %} + self.transform_vector3(rhs.into()).into() + {% else %} + let mut res = self.x_axis.mul(rhs.xxxx()); + res = self.y_axis.mul(rhs.yyyy()).add(res); + res = self.z_axis.mul(rhs.zzzz()).add(res); + res.into() + {% endif %} + } +{% endif %} + + /// Transforms a {{ dim }}D vector. + #[inline] + pub fn mul_vec{{ dim }}(&self, rhs: {{ vecn_t }}) -> {{ vecn_t }} { + {% if self_t == "Mat2" and is_sse2 %} + unsafe { + use core::mem::MaybeUninit; + use crate::Align16; + let abcd = self.0; + let xxyy = _mm_set_ps(rhs.y, rhs.y, rhs.x, rhs.x); + let axbxcydy = _mm_mul_ps(abcd, xxyy); + let cydyaxbx = _mm_shuffle_ps(axbxcydy, axbxcydy, 0b01_00_11_10); + let result = _mm_add_ps(axbxcydy, cydyaxbx); + let mut out: MaybeUninit> = MaybeUninit::uninit(); + _mm_store_ps(out.as_mut_ptr().cast(), result); + out.assume_init().0 + } + {% elif self_t == "Mat2" and is_wasm32 %} + use core::mem::MaybeUninit; + let abcd = self.0; + let xxyy = f32x4(rhs.x, rhs.x, rhs.y, rhs.y); + let axbxcydy = f32x4_mul(abcd, xxyy); + let cydyaxbx = i32x4_shuffle::<2, 3, 4, 5>(axbxcydy, axbxcydy); + let result = f32x4_add(axbxcydy, cydyaxbx); + let mut out: MaybeUninit = MaybeUninit::uninit(); + unsafe { + v128_store(out.as_mut_ptr(), result); + *(&out.assume_init() as *const v128 as *const Vec2) + } + {% elif dim == 2 %} + #[allow(clippy::suspicious_operation_groupings)] + {{ col_t }}::new( + (self.x_axis.x * rhs.x) + (self.y_axis.x * rhs.y), + (self.x_axis.y * rhs.x) + (self.y_axis.y * rhs.y), + ) + {% elif self_t == "Mat3A" %} + {# use the Vec3A implementation #} + self.mul_vec3a(rhs.into()).into() + {% elif dim == 3 %} + let mut res = self.x_axis.mul(rhs.x); + res = res.add(self.y_axis.mul(rhs.y)); + res = res.add(self.z_axis.mul(rhs.z)); + res + {% elif dim == 4 %} + {% if is_scalar %} + let mut res = self.x_axis.mul(rhs.x); + res = res.add(self.y_axis.mul(rhs.y)); + res = res.add(self.z_axis.mul(rhs.z)); + res = res.add(self.w_axis.mul(rhs.w)); + res + {% else %} + {# use swizzles if simd #} + let mut res = self.x_axis.mul(rhs.xxxx()); + res = res.add(self.y_axis.mul(rhs.yyyy())); + res = res.add(self.z_axis.mul(rhs.zzzz())); + res = res.add(self.w_axis.mul(rhs.wwww())); + res + {% endif %} + {% endif %} + } + +{% if self_t == "Mat3" %} + /// Transforms a `Vec3A`. + #[inline] + pub fn mul_vec3a(&self, rhs: Vec3A) -> Vec3A { + self.mul_vec3(rhs.into()).into() + } +{% elif self_t == "Mat3A" %} + /// Transforms a `Vec3A`. + #[inline] + pub fn mul_vec3a(&self, rhs: Vec3A) -> Vec3A { + let mut res = self.x_axis.mul(rhs.xxx()); + res = res.add(self.y_axis.mul(rhs.yyy())); + res = res.add(self.z_axis.mul(rhs.zzz())); + res + } +{% endif %} + + /// Multiplies two {{ nxn }} matrices. + #[inline] + pub fn mul_mat{{ dim }}(&self, rhs: &Self) -> Self { + {% if self_t == "Mat2" and is_sse2 %} + unsafe { + let abcd = self.0; + let rhs = rhs.0; + let xxyy0 = _mm_shuffle_ps(rhs, rhs, 0b01_01_00_00); + let xxyy1 = _mm_shuffle_ps(rhs, rhs, 0b11_11_10_10); + let axbxcydy0 = _mm_mul_ps(abcd, xxyy0); + let axbxcydy1 = _mm_mul_ps(abcd, xxyy1); + let cydyaxbx0 = _mm_shuffle_ps(axbxcydy0, axbxcydy0, 0b01_00_11_10); + let cydyaxbx1 = _mm_shuffle_ps(axbxcydy1, axbxcydy1, 0b01_00_11_10); + let result0 = _mm_add_ps(axbxcydy0, cydyaxbx0); + let result1 = _mm_add_ps(axbxcydy1, cydyaxbx1); + Self(_mm_shuffle_ps(result0, result1, 0b01_00_01_00)) + } + {% elif self_t == "Mat2" and is_wasm32 %} + let abcd = self.0; + let rhs = rhs.0; + let xxyy0 = i32x4_shuffle::<0, 0, 5, 5>(rhs, rhs); + let xxyy1 = i32x4_shuffle::<2, 2, 7, 7>(rhs, rhs); + let axbxcydy0 = f32x4_mul(abcd, xxyy0); + let axbxcydy1 = f32x4_mul(abcd, xxyy1); + let cydyaxbx0 = i32x4_shuffle::<2, 3, 4, 5>(axbxcydy0, axbxcydy0); + let cydyaxbx1 = i32x4_shuffle::<2, 3, 4, 5>(axbxcydy1, axbxcydy1); + let result0 = f32x4_add(axbxcydy0, cydyaxbx0); + let result1 = f32x4_add(axbxcydy1, cydyaxbx1); + Self(i32x4_shuffle::<0, 1, 4, 5>(result0, result1)) + {% else %} + Self::from_cols( + {% for axis in axes %} + self.mul(rhs.{{ axis }}), + {%- endfor %} + ) + {% endif %} + } + + /// Adds two {{ nxn }} matrices. + #[inline] + pub fn add_mat{{ dim }}(&self, rhs: &Self) -> Self { + {% if self_t == "Mat2" and is_sse2 %} + Self(unsafe { _mm_add_ps(self.0, rhs.0) }) + {% elif self_t == "Mat2" and is_wasm32 %} + Self(f32x4_add(self.0, rhs.0)) + {% else %} + Self::from_cols( + {% for axis in axes %} + self.{{ axis }}.add(rhs.{{ axis }}), + {%- endfor %} + ) + {% endif %} + } + + /// Subtracts two {{ nxn }} matrices. + #[inline] + pub fn sub_mat{{ dim }}(&self, rhs: &Self) -> Self { + {% if self_t == "Mat2" and is_sse2 %} + Self(unsafe { _mm_sub_ps(self.0, rhs.0) }) + {% elif self_t == "Mat2" and is_wasm32 %} + Self(f32x4_sub(self.0, rhs.0)) + {% else %} + Self::from_cols( + {% for axis in axes %} + self.{{ axis }}.sub(rhs.{{ axis }}), + {%- endfor %} + ) + {% endif %} + } + + /// Multiplies a {{ nxn }} matrix by a scalar. + #[inline] + pub fn mul_scalar(&self, rhs: {{ scalar_t }}) -> Self { + {% if self_t == "Mat2" and is_sse2 %} + Self(unsafe { _mm_mul_ps(self.0, _mm_set_ps1(rhs)) }) + {% elif self_t == "Mat2" and is_wasm32 %} + Self(f32x4_mul(self.0, f32x4_splat(rhs))) + {% else %} + Self::from_cols( + {% for axis in axes %} + self.{{ axis }}.mul(rhs), + {%- endfor %} + ) + {% endif %} + } + + /// Returns true if the absolute difference of all elements between `self` and `rhs` + /// is less than or equal to `max_abs_diff`. + /// + /// This can be used to compare if two matrices contain similar elements. It works best + /// when comparing with a known value. The `max_abs_diff` that should be used used + /// depends on the values being compared against. + /// + /// For more see + /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/). + #[inline] + pub fn abs_diff_eq(&self, rhs: Self, max_abs_diff: {{ scalar_t }}) -> bool { + {% for axis in axes %} + self.{{ axis }}.abs_diff_eq(rhs.{{ axis }}, max_abs_diff) + {% if not loop.last %} && {% endif %} + {% endfor %} + } + + {% if scalar_t == "f32" %} + #[inline] + pub fn as_dmat{{ dim }}(&self) -> DMat{{ dim }} { + DMat{{ dim }}::from_cols( + {% for axis in axes %} + self.{{ axis }}.as_dvec{{ dim }}(), + {% endfor %} + ) + } + {% elif scalar_t == "f64" %} + #[inline] + pub fn as_mat{{ dim }}(&self) -> Mat{{ dim }} { + Mat{{ dim }}::from_cols( + {% for axis in axes %} + self.{{ axis }}.as_vec{{ dim }}(), + {% endfor %} + ) + } + {% endif %} +} + +impl Default for {{ self_t }} { + #[inline] + fn default() -> Self { + Self::IDENTITY + } +} + +impl Add<{{ self_t }}> for {{ self_t }} { + type Output = Self; + #[inline] + fn add(self, rhs: Self) -> Self::Output { + self.add_mat{{ dim }}(&rhs) + } +} + +impl AddAssign<{{ self_t }}> for {{ self_t }} { + #[inline] + fn add_assign(&mut self, rhs: Self) { + *self = self.add_mat{{ dim }}(&rhs); + } +} + +impl Sub<{{ self_t }}> for {{ self_t }} { + type Output = Self; + #[inline] + fn sub(self, rhs: Self) -> Self::Output { + self.sub_mat{{ dim }}(&rhs) + } +} + +impl SubAssign<{{ self_t }}> for {{ self_t }} { + #[inline] + fn sub_assign(&mut self, rhs: Self) { + *self = self.sub_mat{{ dim }}(&rhs); + } +} + +impl Neg for {{ self_t }} { + type Output = Self; + #[inline] + fn neg(self) -> Self::Output { + {% if self_t == "Mat2" and is_sse2 %} + Self(unsafe { _mm_xor_ps(self.0, _mm_set1_ps(-0.0)) }) + {% elif self_t == "Mat2" and is_wasm32 %} + Self(f32x4_neg(self.0)) + {% else %} + Self::from_cols( + {% for axis in axes %} + self.{{ axis }}.neg(), + {%- endfor %} + ) + {% endif %} + } +} + +impl Mul<{{ self_t }}> for {{ self_t }} { + type Output = Self; + #[inline] + fn mul(self, rhs: Self) -> Self::Output { + self.mul_mat{{ dim }}(&rhs) + } +} + +impl MulAssign<{{ self_t }}> for {{ self_t }} { + #[inline] + fn mul_assign(&mut self, rhs: Self) { + *self = self.mul_mat{{ dim }}(&rhs); + } +} + +impl Mul<{{ col_t }}> for {{ self_t }} { + type Output = {{ col_t }}; + #[inline] + fn mul(self, rhs: {{ col_t }}) -> Self::Output { + {% if self_t == "Mat3A" %} + self.mul_vec3a(rhs) + {% else %} + self.mul_vec{{ dim }}(rhs) + {% endif %} + } +} + +impl Mul<{{ self_t }}> for {{ scalar_t }} { + type Output = {{ self_t }}; + #[inline] + fn mul(self, rhs: {{ self_t }}) -> Self::Output { + rhs.mul_scalar(self) + } +} + +impl Mul<{{ scalar_t }}> for {{ self_t }} { + type Output = Self; + #[inline] + fn mul(self, rhs: {{ scalar_t }}) -> Self::Output { + self.mul_scalar(rhs) + } +} + +impl MulAssign<{{ scalar_t }}> for {{ self_t }} { + #[inline] + fn mul_assign(&mut self, rhs: {{ scalar_t }}) { + *self = self.mul_scalar(rhs); + } +} + +{% if self_t == "Mat3" %} +impl Mul for Mat3 { + type Output = Vec3A; + #[inline] + fn mul(self, rhs: Vec3A) -> Vec3A { + self.mul_vec3a(rhs) + } +} + +impl From for Mat3 { + #[inline] + fn from(m: Mat3A) -> Self { + Self { + x_axis: m.x_axis.into(), + y_axis: m.y_axis.into(), + z_axis: m.z_axis.into(), + } + } +} +{% elif self_t == "Mat3A" %} +impl Mul for Mat3A { + type Output = Vec3; + #[inline] + fn mul(self, rhs: Vec3) -> Vec3 { + self.mul_vec3a(rhs.into()).into() + } +} + +impl From for Mat3A { + #[inline] + fn from(m: Mat3) -> Self { + Self { + x_axis: m.x_axis.into(), + y_axis: m.y_axis.into(), + z_axis: m.z_axis.into(), + } + } +} +{% endif %} + +impl<'a> Sum<&'a Self> for {{ self_t }} { + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, |a, &b| Self::add(a, b)) + } +} + +impl<'a> Product<&'a Self> for {{ self_t }} { + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::IDENTITY, |a, &b| Self::mul(a, b)) + } +} + +impl PartialEq for {{ self_t }} { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + {% for axis in axes %} + self.{{ axis }}.eq(&rhs.{{ axis }}) {% if not loop.last %} && {% endif %} + {% endfor %} + } +} + +{% if not is_align %} +#[cfg(not(target_arch = "spirv"))] +impl AsRef<[{{ scalar_t }}; {{ size }}]> for {{ self_t }} { + #[inline] + fn as_ref(&self) -> &[{{ scalar_t }}; {{ size }}] { + unsafe { &*(self as *const Self as *const [{{ scalar_t }}; {{ size }}]) } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsMut<[{{ scalar_t }}; {{ size }}]> for {{ self_t }} { + #[inline] + fn as_mut(&mut self) -> &mut [{{ scalar_t }}; {{ size }}] { + unsafe { &mut *(self as *mut Self as *mut [{{ scalar_t }}; {{ size }}]) } + } +} +{% endif %} + +{% if self_t == "Mat2" and not is_scalar %} +impl core::ops::Deref for Mat2 { + type Target = crate::deref::Columns2; + #[inline] + fn deref(&self) -> &Self::Target { + unsafe { &*(self as *const Self as *const Self::Target) } + } +} + +impl core::ops::DerefMut for Mat2 { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { &mut *(self as *mut Self as *mut Self::Target) } + } +} +{% endif %} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Debug for {{ self_t }} { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct(stringify!({{ self_t }})) + {% for axis in axes %} + .field("{{ axis }}", &self.{{ axis }}) + {% endfor %} + .finish() + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Display for {{ self_t }} { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + {% if dim == 2 %} + write!(f, "[{}, {}]", self.x_axis, self.y_axis) + {% elif dim == 3 %} + write!(f, "[{}, {}, {}]", self.x_axis, self.y_axis, self.z_axis) + {% elif dim == 4 %} + write!(f, "[{}, {}, {}, {}]", self.x_axis, self.y_axis, self.z_axis, self.w_axis) + {% endif %} + } +} + diff --git a/codegen/templates/quat.rs b/codegen/templates/quat.rs new file mode 100644 index 00000000..c0e640d6 --- /dev/null +++ b/codegen/templates/quat.rs @@ -0,0 +1,1142 @@ +// Generated from {{template_path}} template. Edit the template, not the generated file. + +{% if not is_scalar %} + {% set is_simd = true %} + {% if is_sse2 %} + {% set simd_t = "__m128" %} + {% elif is_wasm32 %} + {% set simd_t = "v128" %} + {% endif %} +{% endif %} + +{% if scalar_t == "f32" %} + {% set self_t = "Quat" %} + {% set affine3_t = "Affine3A" %} + {% set vec2_t = "Vec2" %} + {% set vec3_t = "Vec3" %} + {% set vec4_t = "Vec4" %} + {% set mat3_t = "Mat3" %} + {% set mat4_t = "Mat4" %} +{% elif scalar_t == "f64" %} + {% set self_t = "DQuat" %} + {% set affine3_t = "DAffine3" %} + {% set vec2_t = "DVec2" %} + {% set vec3_t = "DVec3" %} + {% set vec4_t = "DVec4" %} + {% set mat3_t = "DMat3" %} + {% set mat4_t = "DMat4" %} +{% endif %} + +use crate::{ + FloatEx, + euler::{EulerFromQuaternion, EulerRot, EulerToQuaternion}, + {% if scalar_t == "f32" %} + DQuat, Mat3, Mat4, Vec2, Vec3, Vec3A, Vec4, + {% elif scalar_t == "f64" %} + DMat3, DMat4, DVec2, DVec3, DVec4, Quat, + {% endif %} +}; + +#[cfg(not(feature = "std"))] +use num_traits::Float; + +{% if is_sse2 %} +#[cfg(target_arch = "x86")] +use core::arch::x86::*; +#[cfg(target_arch = "x86_64")] +use core::arch::x86_64::*; +{% elif is_wasm32 %} +use core::arch::wasm32::*; +{% endif %} + +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::iter::{Product, Sum}; +use core::ops::{Add, Deref, Div, Mul, MulAssign, Neg, Sub}; + +{% if is_sse2 %} +union UnionCast { + a: [f32; 4], + v: {{ self_t }} +} +{% endif %} + +/// Creates a quaternion from `x`, `y`, `z` and `w` values. +/// +/// This should generally not be called manually unless you know what you are doing. Use +/// one of the other constructors instead such as `identity` or `from_axis_angle`. +#[inline] +pub const fn {{ self_t | lower }}(x: {{ scalar_t }}, y: {{ scalar_t }}, z: {{ scalar_t }}, w: {{ scalar_t }}) -> {{ self_t }} { + {{ self_t }}::from_xyzw(x, y, z, w) +} + +/// A quaternion representing an orientation. +/// +/// This quaternion is intended to be of unit length but may denormalize due to +/// floating point "error creep" which can occur when successive quaternion +/// operations are applied. +{%- if is_simd %} +/// +/// This type is 16 byte aligned. +{%- endif %} +#[derive(Clone, Copy)] +{%- if is_scalar %} +{%- if scalar_t == "f32" %} +#[cfg_attr(not(any(feature = "scalar-math", target_arch = "spirv")), repr(C, align(16)))] +{%- endif %} +pub struct {{ self_t }}{ + x: {{ scalar_t }}, + y: {{ scalar_t }}, + z: {{ scalar_t }}, + w: {{ scalar_t }}, +} +{%- else %} +#[repr(transparent)] +pub struct {{ self_t }}(pub(crate) {{ simd_t }}); +{%- endif %} + +impl {{ self_t }} { + /// All zeros. + const ZERO: Self = Self::from_array([0.0; 4]); + + /// The identity quaternion. Corresponds to no rotation. + pub const IDENTITY: Self = Self::from_xyzw(0.0, 0.0, 0.0, 1.0); + + /// All NANs. + pub const NAN: Self = Self::from_array([{{ scalar_t }}::NAN; 4]); + + /// Creates a new rotation quaternion. + /// + /// This should generally not be called manually unless you know what you are doing. + /// Use one of the other constructors instead such as `identity` or `from_axis_angle`. + /// + /// `from_xyzw` is mostly used by unit tests and `serde` deserialization. + /// + /// # Preconditions + /// + /// This function does not check if the input is normalized, it is up to the user to + /// provide normalized input or to normalized the resulting quaternion. + #[inline(always)] + pub const fn from_xyzw(x: {{ scalar_t }}, y: {{ scalar_t }}, z: {{ scalar_t }}, w: {{ scalar_t }}) -> Self { + {% if is_scalar %} + Self { x, y, z, w } + {% elif is_sse2 %} + unsafe { UnionCast { a: [x, y, z, w] }.v } + {% elif is_wasm32 %} + Self(f32x4(x, y, z, w)) + {% endif %} + } + + /// Creates a rotation quaternion from an array. + /// + /// # Preconditions + /// + /// This function does not check if the input is normalized, it is up to the user to + /// provide normalized input or to normalized the resulting quaternion. + #[inline] + pub const fn from_array(a: [{{ scalar_t }}; 4]) -> Self { + Self::from_xyzw(a[0], a[1], a[2], a[3]) + } + + /// Creates a new rotation quaternion from a 4D vector. + /// + /// # Preconditions + /// + /// This function does not check if the input is normalized, it is up to the user to + /// provide normalized input or to normalized the resulting quaternion. + #[inline] + pub fn from_vec4(v: {{ vec4_t }}) -> Self { + {% if is_scalar %} + Self { x: v.x, y: v.y, z: v.z, w: v.w } + {% else %} + Self(v.0) + {% endif %} + } + + /// Creates a rotation quaternion from a slice. + /// + /// # Preconditions + /// + /// This function does not check if the input is normalized, it is up to the user to + /// provide normalized input or to normalized the resulting quaternion. + /// + /// # Panics + /// + /// Panics if `slice` length is less than 4. + #[inline] + pub fn from_slice(slice: &[{{ scalar_t }}]) -> Self { + {% if is_sse2 %} + assert!(slice.len() >= 4); + Self(unsafe { _mm_loadu_ps(slice.as_ptr()) }) + {% else %} + Self::from_xyzw(slice[0], slice[1], slice[2], slice[3]) + {% endif %} + } + + /// Writes the quaternion to an unaligned slice. + /// + /// # Panics + /// + /// Panics if `slice` length is less than 4. + #[inline] + pub fn write_to_slice(self, slice: &mut [{{ scalar_t }}]) { + {% if is_sse2 %} + assert!(slice.len() >= 4); + unsafe { _mm_storeu_ps(slice.as_mut_ptr(), self.0) } + {% else %} + slice[0] = self.x; + slice[1] = self.y; + slice[2] = self.z; + slice[3] = self.w; + {% endif %} + } + + /// Create a quaternion for a normalized rotation `axis` and `angle` (in radians). + /// The axis must be normalized (unit-length). + /// + /// # Panics + /// + /// Will panic if `axis` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn from_axis_angle(axis: {{ vec3_t }}, angle: {{ scalar_t }}) -> Self { + glam_assert!(axis.is_normalized()); + let (s, c) = (angle * 0.5).sin_cos(); + let v = axis * s; + Self::from_xyzw(v.x, v.y, v.z, c) + } + + /// Create a quaternion that rotates `v.length()` radians around `v.normalize()`. + /// + /// `from_scaled_axis(Vec3::ZERO)` results in the identity quaternion. + #[inline] + pub fn from_scaled_axis(v: {{ vec3_t }}) -> Self { + let length = v.length(); + if length == 0.0 { + Self::IDENTITY + } else { + Self::from_axis_angle(v / length, length) + } + } + + /// Creates a quaternion from the `angle` (in radians) around the x axis. + #[inline] + pub fn from_rotation_x(angle: {{ scalar_t }}) -> Self { + let (s, c) = (angle * 0.5).sin_cos(); + Self::from_xyzw(s, 0.0, 0.0, c) + } + + /// Creates a quaternion from the `angle` (in radians) around the y axis. + #[inline] + pub fn from_rotation_y(angle: {{ scalar_t }}) -> Self { + let (s, c) = (angle * 0.5).sin_cos(); + Self::from_xyzw(0.0, s, 0.0, c) + } + + /// Creates a quaternion from the `angle` (in radians) around the z axis. + #[inline] + pub fn from_rotation_z(angle: {{ scalar_t }}) -> Self { + let (s, c) = (angle * 0.5).sin_cos(); + Self::from_xyzw(0.0, 0.0, s, c) + } + + #[inline] + /// Creates a quaternion from the given Euler rotation sequence and the angles (in radians). + pub fn from_euler(euler: EulerRot, a: {{ scalar_t }}, b: {{ scalar_t }}, c: {{ scalar_t }}) -> Self { + euler.new_quat(a, b, c) + } + + /// From the columns of a 3x3 rotation matrix. + #[inline] + pub(crate) fn from_rotation_axes(x_axis: {{ vec3_t }}, y_axis: {{ vec3_t }}, z_axis: {{ vec3_t }}) -> Self { + // Based on https://github.com/microsoft/DirectXMath `XM$quaternionRotationMatrix` + // TODO: sse2 version + let (m00, m01, m02) = x_axis.into(); + let (m10, m11, m12) = y_axis.into(); + let (m20, m21, m22) = z_axis.into(); + if m22 <= 0.0 { + // x^2 + y^2 >= z^2 + w^2 + let dif10 = m11 - m00; + let omm22 = 1.0 - m22; + if dif10 <= 0.0 { + // x^2 >= y^2 + let four_xsq = omm22 - dif10; + let inv4x = 0.5 / four_xsq.sqrt(); + Self::from_xyzw( + four_xsq * inv4x, + (m01 + m10) * inv4x, + (m02 + m20) * inv4x, + (m12 - m21) * inv4x, + ) + } else { + // y^2 >= x^2 + let four_ysq = omm22 + dif10; + let inv4y = 0.5 / four_ysq.sqrt(); + Self::from_xyzw( + (m01 + m10) * inv4y, + four_ysq * inv4y, + (m12 + m21) * inv4y, + (m20 - m02) * inv4y, + ) + } + } else { + // z^2 + w^2 >= x^2 + y^2 + let sum10 = m11 + m00; + let opm22 = 1.0 + m22; + if sum10 <= 0.0 { + // z^2 >= w^2 + let four_zsq = opm22 - sum10; + let inv4z = 0.5 / four_zsq.sqrt(); + Self::from_xyzw( + (m02 + m20) * inv4z, + (m12 + m21) * inv4z, + four_zsq * inv4z, + (m01 - m10) * inv4z, + ) + } else { + // w^2 >= z^2 + let four_wsq = opm22 + sum10; + let inv4w = 0.5 / four_wsq.sqrt(); + Self::from_xyzw( + (m12 - m21) * inv4w, + (m20 - m02) * inv4w, + (m01 - m10) * inv4w, + four_wsq * inv4w, + ) + } + } + } + + /// Creates a quaternion from a 3x3 rotation matrix. + #[inline] + pub fn from_mat3(mat: &{{ mat3_t }}) -> Self { + Self::from_rotation_axes( + mat.x_axis, + mat.y_axis, + mat.z_axis, + ) + } + + /// Creates a quaternion from a 3x3 rotation matrix inside a homogeneous 4x4 matrix. + #[inline] + pub fn from_mat4(mat: &{{ mat4_t }}) -> Self { + Self::from_rotation_axes( + mat.x_axis.truncate(), + mat.y_axis.truncate(), + mat.z_axis.truncate(), + ) + } + + /// Gets the minimal rotation for transforming `from` to `to`. The rotation is in the + /// plane spanned by the two vectors. Will rotate at most 180 degrees. + /// + /// The input vectors must be normalized (unit-length). + /// + /// `from_rotation_arc(from, to) * from ≈ to`. + /// + /// For near-singular cases (from≈to and from≈-to) the current implementation + /// is only accurate to about 0.001 (for `f32`). + /// + /// # Panics + /// + /// Will panic if `from` or `to` are not normalized when `glam_assert` is enabled. + pub fn from_rotation_arc(from: {{ vec3_t }}, to: {{ vec3_t }}) -> Self { + glam_assert!(from.is_normalized()); + glam_assert!(to.is_normalized()); + + const ONE_MINUS_EPS: {{ scalar_t }} = 1.0 - 2.0 * core::{{ scalar_t }}::EPSILON; + let dot = from.dot(to); + if dot > ONE_MINUS_EPS { + // 0° singulary: from ≈ to + Self::IDENTITY + } else if dot < -ONE_MINUS_EPS { + // 180° singulary: from ≈ -to + use core::{{ scalar_t }}::consts::PI; // half a turn = 𝛕/2 = 180° + Self::from_axis_angle(from.any_orthonormal_vector(), PI) + } else { + let c = from.cross(to); + Self::from_xyzw(c.x, c.y, c.z, 1.0 + dot).normalize() + } + } + + /// Gets the minimal rotation for transforming `from` to either `to` or `-to`. This means + /// that the resulting quaternion will rotate `from` so that it is colinear with `to`. + /// + /// The rotation is in the plane spanned by the two vectors. Will rotate at most 90 + /// degrees. + /// + /// The input vectors must be normalized (unit-length). + /// + /// `to.dot(from_rotation_arc_colinear(from, to) * from).abs() ≈ 1`. + /// + /// # Panics + /// + /// Will panic if `from` or `to` are not normalized when `glam_assert` is enabled. + #[inline] + pub fn from_rotation_arc_colinear(from: {{ vec3_t }}, to: {{ vec3_t }}) -> Self { + if from.dot(to) < 0.0 { + Self::from_rotation_arc(from, -to) + } else { + Self::from_rotation_arc(from, to) + } + } + + /// Gets the minimal rotation for transforming `from` to `to`. The resulting rotation is + /// around the z axis. Will rotate at most 180 degrees. + /// + /// The input vectors must be normalized (unit-length). + /// + /// `from_rotation_arc_2d(from, to) * from ≈ to`. + /// + /// For near-singular cases (from≈to and from≈-to) the current implementation + /// is only accurate to about 0.001 (for `f32`). + /// + /// # Panics + /// + /// Will panic if `from` or `to` are not normalized when `glam_assert` is enabled. + pub fn from_rotation_arc_2d(from: {{ vec2_t }}, to: {{ vec2_t }}) -> Self { + glam_assert!(from.is_normalized()); + glam_assert!(to.is_normalized()); + + const ONE_MINUS_EPSILON: {{ scalar_t }} = 1.0 - 2.0 * core::{{ scalar_t }}::EPSILON; + let dot = from.dot(to); + if dot > ONE_MINUS_EPSILON { + // 0° singulary: from ≈ to + Self::IDENTITY + } else if dot < -ONE_MINUS_EPSILON { + // 180° singulary: from ≈ -to + const COS_FRAC_PI_2: {{ scalar_t }} = 0.0; + const SIN_FRAC_PI_2: {{ scalar_t }} = 1.0; + // rotation around z by PI radians + Self::from_xyzw(0.0, 0.0, SIN_FRAC_PI_2, COS_FRAC_PI_2) + } else { + // vector3 cross where z=0 + let z = from.x * to.y - to.x * from.y; + let w = 1.0 + dot; + // calculate length with x=0 and y=0 to normalize + let len_rcp = 1.0 / (z * z + w * w).sqrt(); + Self::from_xyzw(0.0, 0.0, z * len_rcp, w * len_rcp) + } + } + + /// Returns the rotation axis and angle (in radians) of `self`. + #[inline] + pub fn to_axis_angle(self) -> ({{ vec3_t }}, {{ scalar_t }}) { + const EPSILON: {{ scalar_t }} = 1.0e-8; + const EPSILON_SQUARED: {{ scalar_t }} = EPSILON * EPSILON; + let w = self.w; + let angle = w.acos_approx() * 2.0; + let scale_sq = {{ scalar_t }}::max(1.0 - w * w, 0.0); + if scale_sq >= EPSILON_SQUARED { + ({{ vec3_t }}::new(self.x, self.y, self.z) * scale_sq.sqrt().recip(), angle) + } else { + ({{ vec3_t }}::X, angle) + } + } + + /// Returns the rotation axis scaled by the rotation in radians. + #[inline] + pub fn to_scaled_axis(self) -> {{ vec3_t }} { + let (axis, angle) = self.to_axis_angle(); + axis * angle + } + + /// Returns the rotation angles for the given euler rotation sequence. + #[inline] + pub fn to_euler(self, euler: EulerRot) -> ({{ scalar_t }}, {{ scalar_t }}, {{ scalar_t }}) { + euler.convert_quat(self) + } + + /// `[x, y, z, w]` + #[inline] + pub fn to_array(&self) -> [{{ scalar_t }}; 4] { + [self.x, self.y, self.z, self.w] + } + + /// Returns the vector part of the quaternion. + #[inline] + pub fn xyz(self) -> {{ vec3_t }} { + {{ vec3_t }}::new(self.x, self.y, self.z) + } + + /// Returns the quaternion conjugate of `self`. For a unit quaternion the + /// conjugate is also the inverse. + #[must_use] + #[inline] + pub fn conjugate(self) -> Self { + {% if is_scalar %} + Self { x: -self.x, y: -self.y, z: -self.z, w: self.w } + {% elif is_sse2 %} + const SIGN: __m128 = const_f32x4!([-0.0, -0.0, -0.0, 0.0]); + Self(unsafe { _mm_xor_ps(self.0, SIGN) }) + {% elif is_wasm32 %} + const SIGN: v128 = const_f32x4!([-1.0, -1.0, -1.0, 1.0]); + Self(f32x4_mul(self.0, SIGN)) + {% endif %} + } + + /// Returns the inverse of a normalized quaternion. + /// + /// Typically quaternion inverse returns the conjugate of a normalized quaternion. + /// Because `self` is assumed to already be unit length this method *does not* normalize + /// before returning the conjugate. + /// + /// # Panics + /// + /// Will panic if `self` is not normalized when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn inverse(self) -> Self { + glam_assert!(self.is_normalized()); + self.conjugate() + } + + /// Computes the dot product of `self` and `rhs`. The dot product is + /// equal to the cosine of the angle between two quaternion rotations. + #[inline] + pub fn dot(self, rhs: Self) -> {{ scalar_t }} { + {{ vec4_t }}::from(self).dot({{ vec4_t }}::from(rhs)) + } + + /// Computes the length of `self`. + #[doc(alias = "magnitude")] + #[inline] + pub fn length(self) -> {{ scalar_t }} { + {{ vec4_t }}::from(self).length() + } + + /// Computes the squared length of `self`. + /// + /// This is generally faster than `length()` as it avoids a square + /// root operation. + #[doc(alias = "magnitude2")] + #[inline] + pub fn length_squared(self) -> {{ scalar_t }} { + {{ vec4_t }}::from(self).length_squared() + } + + /// Computes `1.0 / length()`. + /// + /// For valid results, `self` must _not_ be of length zero. + #[inline] + pub fn length_recip(self) -> {{ scalar_t }} { + {{ vec4_t }}::from(self).length_recip() + } + + /// Returns `self` normalized to length 1.0. + /// + /// For valid results, `self` must _not_ be of length zero. + /// + /// Panics + /// + /// Will panic if `self` is zero length when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn normalize(self) -> Self { + Self::from_vec4({{ vec4_t }}::from(self).normalize()) + } + + /// Returns `true` if, and only if, all elements are finite. + /// If any element is either `NaN`, positive or negative infinity, this will return `false`. + #[inline] + pub fn is_finite(self) -> bool { + {{ vec4_t }}::from(self).is_finite() + } + + #[inline] + pub fn is_nan(self) -> bool { + {{ vec4_t }}::from(self).is_nan() + } + + /// Returns whether `self` of length `1.0` or not. + /// + /// Uses a precision threshold of `1e-6`. + #[inline] + pub fn is_normalized(self) -> bool { + {{ vec4_t }}::from(self).is_normalized() + } + + #[inline] + pub fn is_near_identity(self) -> bool { + // Based on https://github.com/nfrechette/rtm `rtm::quat_near_identity` + let threshold_angle = 0.002_847_144_6; + // Because of floating point precision, we cannot represent very small rotations. + // The closest f32 to 1.0 that is not 1.0 itself yields: + // 0.99999994.acos() * 2.0 = 0.000690533954 rad + // + // An error threshold of 1.e-6 is used by default. + // (1.0 - 1.e-6).acos() * 2.0 = 0.00284714461 rad + // (1.0 - 1.e-7).acos() * 2.0 = 0.00097656250 rad + // + // We don't really care about the angle value itself, only if it's close to 0. + // This will happen whenever quat.w is close to 1.0. + // If the quat.w is close to -1.0, the angle will be near 2*PI which is close to + // a negative 0 rotation. By forcing quat.w to be positive, we'll end up with + // the shortest path. + let positive_w_angle = self.w.abs().acos_approx() * 2.0; + positive_w_angle < threshold_angle + } + + /// Returns the angle (in radians) for the minimal rotation + /// for transforming this quaternion into another. + /// + /// Both quaternions must be normalized. + /// + /// # Panics + /// + /// Will panic if `self` or `rhs` are not normalized when `glam_assert` is enabled. + #[inline] + pub fn angle_between(self, rhs: Self) -> {{ scalar_t }} { + glam_assert!(self.is_normalized() && rhs.is_normalized()); + self.dot(rhs).abs().acos_approx() * 2.0 + } + + /// Returns true if the absolute difference of all elements between `self` and `rhs` + /// is less than or equal to `max_abs_diff`. + /// + /// This can be used to compare if two quaternions contain similar elements. It works + /// best when comparing with a known value. The `max_abs_diff` that should be used used + /// depends on the values being compared against. + /// + /// For more see + /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/). + #[inline] + pub fn abs_diff_eq(self, rhs: Self, max_abs_diff: {{ scalar_t }}) -> bool { + {{ vec4_t }}::from(self).abs_diff_eq({{ vec4_t }}::from(rhs), max_abs_diff) + } + + /// Performs a linear interpolation between `self` and `rhs` based on + /// the value `s`. + /// + /// When `s` is `0.0`, the result will be equal to `self`. When `s` + /// is `1.0`, the result will be equal to `rhs`. + /// + /// # Panics + /// + /// Will panic if `self` or `end` are not normalized when `glam_assert` is enabled. + #[inline] + #[doc(alias = "mix")] + pub fn lerp(self, end: Self, s: {{ scalar_t }}) -> Self { + glam_assert!(self.is_normalized()); + glam_assert!(end.is_normalized()); + + {% if is_scalar %} + let start = self; + let dot = start.dot(end); + let bias = if dot >= 0.0 { 1.0 } else { -1.0 }; + let interpolated = start.add(end.mul(bias).sub(start).mul(s)); + interpolated.normalize() + {% elif is_sse2 %} + const NEG_ZERO: __m128 = const_f32x4!([-0.0; 4]); + let start = self.0; + let end = end.0; + unsafe { + let dot = crate::sse2::dot4_into_m128(start, end); + // Calculate the bias, if the dot product is positive or zero, there is no bias + // but if it is negative, we want to flip the 'end' rotation XYZW components + let bias = _mm_and_ps(dot, NEG_ZERO); + let interpolated = _mm_add_ps( + _mm_mul_ps(_mm_sub_ps(_mm_xor_ps(end, bias), start), _mm_set_ps1(s)), + start, + ); + {{ self_t }}(interpolated).normalize() + } + {% elif is_wasm32 %} + const NEG_ZERO: v128 = const_f32x4!([-0.0; 4]); + let start = self.0; + let end = end.0; + let dot = crate::wasm32::dot4_into_v128(start, end); + // Calculate the bias, if the dot product is positive or zero, there is no bias + // but if it is negative, we want to flip the 'end' rotation XYZW components + let bias = v128_and(dot, NEG_ZERO); + let interpolated = f32x4_add( + f32x4_mul(f32x4_sub(v128_xor(end, bias), start), f32x4_splat(s)), + start, + ); + {{ self_t }}(interpolated).normalize() + {% endif %} + } + + /// Performs a spherical linear interpolation between `self` and `end` + /// based on the value `s`. + /// + /// When `s` is `0.0`, the result will be equal to `self`. When `s` + /// is `1.0`, the result will be equal to `end`. + /// + /// # Panics + /// + /// Will panic if `self` or `end` are not normalized when `glam_assert` is enabled. + #[inline] + pub fn slerp(self, mut end: Self, s: {{ scalar_t }}) -> Self { + // http://number-none.com/product/Understanding%20Slerp,%20Then%20Not%20Using%20It/ + glam_assert!(self.is_normalized()); + glam_assert!(end.is_normalized()); + + const DOT_THRESHOLD: {{ scalar_t }} = 0.9995; + + // Note that a rotation can be represented by two quaternions: `q` and + // `-q`. The slerp path between `q` and `end` will be different from the + // path between `-q` and `end`. One path will take the long way around and + // one will take the short way. In order to correct for this, the `dot` + // product between `self` and `end` should be positive. If the `dot` + // product is negative, slerp between `self` and `-end`. + let mut dot = self.dot(end); + if dot < 0.0 { + end = -end; + dot = -dot; + } + + if dot > DOT_THRESHOLD { + // assumes lerp returns a normalized quaternion + self.lerp(end, s) + } else { + let theta = dot.acos_approx(); + {% if is_scalar %} + let scale1 = (theta * (1.0 - s)).sin(); + let scale2 = (theta * s).sin(); + let theta_sin = theta.sin(); + + self.mul(scale1) + .add(end.mul(scale2)) + .mul(theta_sin.recip()) + {% elif is_sse2 %} + let x = 1.0 - s; + let y = s; + let z = 1.0; + + unsafe { + let tmp = _mm_mul_ps(_mm_set_ps1(theta), _mm_set_ps(0.0, z, y, x)); + let tmp = crate::sse2::m128_sin(tmp); + + let scale1 = _mm_shuffle_ps(tmp, tmp, 0b00_00_00_00); + let scale2 = _mm_shuffle_ps(tmp, tmp, 0b01_01_01_01); + let theta_sin = _mm_shuffle_ps(tmp, tmp, 0b10_10_10_10); + + Self(_mm_div_ps( + _mm_add_ps(_mm_mul_ps(self.0, scale1), _mm_mul_ps(end.0, scale2)), + theta_sin, + )) + } + {% elif is_wasm32 %} + // TODO: v128_sin is broken + // let x = 1.0 - s; + // let y = s; + // let z = 1.0; + // let w = 0.0; + // let tmp = f32x4_mul(f32x4_splat(theta), f32x4(x, y, z, w)); + // let tmp = v128_sin(tmp); + let x = (theta * (1.0 - s)).sin(); + let y = (theta * s).sin(); + let z = theta.sin(); + let w = 0.0; + let tmp = f32x4(x, y, z, w); + + let scale1 = i32x4_shuffle::<0, 0, 4, 4>(tmp, tmp); + let scale2 = i32x4_shuffle::<1, 1, 5, 5>(tmp, tmp); + let theta_sin = i32x4_shuffle::<2, 2, 6, 6>(tmp, tmp); + + Self(f32x4_div( + f32x4_add(f32x4_mul(self.0, scale1), f32x4_mul(end.0, scale2)), + theta_sin, + )) + {% endif %} + } + } + + /// Multiplies a quaternion and a 3D vector, returning the rotated vector. + /// + /// # Panics + /// + /// Will panic if `self` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn mul_vec3(self, rhs: {{ vec3_t }}) -> {{ vec3_t }} { + glam_assert!(self.is_normalized()); + {% if is_scalar %} + let w = self.w; + let b = {{ vec3_t }}::new(self.x, self.y, self.z); + let b2 = b.dot(b); + rhs + .mul(w * w - b2) + .add(b.mul(rhs.dot(b) * 2.0)) + .add(b.cross(rhs).mul(w * 2.0)) + {% else %} + self.mul_vec3a(rhs.into()).into() + {% endif %} + } + + /// Multiplies two quaternions. If they each represent a rotation, the result will + /// represent the combined rotation. + /// + /// Note that due to floating point rounding the result may not be perfectly normalized. + /// + /// # Panics + /// + /// Will panic if `self` or `rhs` are not normalized when `glam_assert` is enabled. + #[inline] + pub fn mul_quat(self, rhs: Self) -> Self { + glam_assert!(self.is_normalized()); + glam_assert!(rhs.is_normalized()); + + {% if is_scalar %} + let (x0, y0, z0, w0) = self.into(); + let (x1, y1, z1, w1) = rhs.into(); + Self::from_xyzw( + w0 * x1 + x0 * w1 + y0 * z1 - z0 * y1, + w0 * y1 - x0 * z1 + y0 * w1 + z0 * x1, + w0 * z1 + x0 * y1 - y0 * x1 + z0 * w1, + w0 * w1 - x0 * x1 - y0 * y1 - z0 * z1, + ) + {% elif is_sse2 %} + // Based on https://github.com/nfrechette/rtm `rtm::quat_mul` + const CONTROL_WZYX: __m128 = const_f32x4!([1.0, -1.0, 1.0, -1.0]); + const CONTROL_ZWXY: __m128 = const_f32x4!([1.0, 1.0, -1.0, -1.0]); + const CONTROL_YXWZ: __m128 = const_f32x4!([-1.0, 1.0, 1.0, -1.0]); + + let lhs = self.0; + let rhs = rhs.0; + + unsafe { + let r_xxxx = _mm_shuffle_ps(lhs, lhs, 0b00_00_00_00); + let r_yyyy = _mm_shuffle_ps(lhs, lhs, 0b01_01_01_01); + let r_zzzz = _mm_shuffle_ps(lhs, lhs, 0b10_10_10_10); + let r_wwww = _mm_shuffle_ps(lhs, lhs, 0b11_11_11_11); + + let lxrw_lyrw_lzrw_lwrw = _mm_mul_ps(r_wwww, rhs); + let l_wzyx = _mm_shuffle_ps(rhs, rhs, 0b00_01_10_11); + + let lwrx_lzrx_lyrx_lxrx = _mm_mul_ps(r_xxxx, l_wzyx); + let l_zwxy = _mm_shuffle_ps(l_wzyx, l_wzyx, 0b10_11_00_01); + + let lwrx_nlzrx_lyrx_nlxrx = _mm_mul_ps(lwrx_lzrx_lyrx_lxrx, CONTROL_WZYX); + + let lzry_lwry_lxry_lyry = _mm_mul_ps(r_yyyy, l_zwxy); + let l_yxwz = _mm_shuffle_ps(l_zwxy, l_zwxy, 0b00_01_10_11); + + let lzry_lwry_nlxry_nlyry = _mm_mul_ps(lzry_lwry_lxry_lyry, CONTROL_ZWXY); + + let lyrz_lxrz_lwrz_lzrz = _mm_mul_ps(r_zzzz, l_yxwz); + let result0 = _mm_add_ps(lxrw_lyrw_lzrw_lwrw, lwrx_nlzrx_lyrx_nlxrx); + + let nlyrz_lxrz_lwrz_wlzrz = _mm_mul_ps(lyrz_lxrz_lwrz_lzrz, CONTROL_YXWZ); + let result1 = _mm_add_ps(lzry_lwry_nlxry_nlyry, nlyrz_lxrz_lwrz_wlzrz); + + Self(_mm_add_ps(result0, result1)) + } + {% elif is_wasm32 %} + let lhs = self.0; + let rhs = rhs.0; + + const CONTROL_WZYX: v128 = const_f32x4!([1.0, -1.0, 1.0, -1.0]); + const CONTROL_ZWXY: v128 = const_f32x4!([1.0, 1.0, -1.0, -1.0]); + const CONTROL_YXWZ: v128 = const_f32x4!([-1.0, 1.0, 1.0, -1.0]); + + let r_xxxx = i32x4_shuffle::<0, 0, 4, 4>(lhs, lhs); + let r_yyyy = i32x4_shuffle::<1, 1, 5, 5>(lhs, lhs); + let r_zzzz = i32x4_shuffle::<2, 2, 6, 6>(lhs, lhs); + let r_wwww = i32x4_shuffle::<3, 3, 7, 7>(lhs, lhs); + + let lxrw_lyrw_lzrw_lwrw = f32x4_mul(r_wwww, rhs); + let l_wzyx = i32x4_shuffle::<3, 2, 5, 4>(rhs, rhs); + + let lwrx_lzrx_lyrx_lxrx = f32x4_mul(r_xxxx, l_wzyx); + let l_zwxy = i32x4_shuffle::<1, 0, 7, 6>(l_wzyx, l_wzyx); + + let lwrx_nlzrx_lyrx_nlxrx = f32x4_mul(lwrx_lzrx_lyrx_lxrx, CONTROL_WZYX); + + let lzry_lwry_lxry_lyry = f32x4_mul(r_yyyy, l_zwxy); + let l_yxwz = i32x4_shuffle::<3, 2, 5, 4>(l_zwxy, l_zwxy); + + let lzry_lwry_nlxry_nlyry = f32x4_mul(lzry_lwry_lxry_lyry, CONTROL_ZWXY); + + let lyrz_lxrz_lwrz_lzrz = f32x4_mul(r_zzzz, l_yxwz); + let result0 = f32x4_add(lxrw_lyrw_lzrw_lwrw, lwrx_nlzrx_lyrx_nlxrx); + + let nlyrz_lxrz_lwrz_wlzrz = f32x4_mul(lyrz_lxrz_lwrz_lzrz, CONTROL_YXWZ); + let result1 = f32x4_add(lzry_lwry_nlxry_nlyry, nlyrz_lxrz_lwrz_wlzrz); + + Self(f32x4_add(result0, result1)) + {% endif %} + } + + /// Creates a quaternion from a 3x3 rotation matrix inside a 3D affine transform. + #[inline] + pub fn from_affine3(a: &crate::{{ affine3_t }}) -> Self { + #[allow(clippy::useless_conversion)] + Self::from_rotation_axes( + a.matrix3.x_axis.into(), + a.matrix3.y_axis.into(), + a.matrix3.z_axis.into(), + ) + } + +{% if scalar_t == "f32" %} + /// Multiplies a quaternion and a 3D vector, returning the rotated vector. + #[inline] + pub fn mul_vec3a(self, rhs: Vec3A) -> Vec3A { + {% if is_scalar %} + self.mul_vec3(rhs.into()).into() + {% elif is_sse2 %} + unsafe { + const TWO: __m128 = const_f32x4!([2.0; 4]); + let w = _mm_shuffle_ps(self.0, self.0, 0b11_11_11_11); + let b = self.0; + let b2 = crate::sse2::dot3_into_m128(b, b); + Vec3A(_mm_add_ps( + _mm_add_ps( + _mm_mul_ps(rhs.0, _mm_sub_ps(_mm_mul_ps(w, w), b2)), + _mm_mul_ps(b, _mm_mul_ps(crate::sse2::dot3_into_m128(rhs.0, b), TWO)), + ), + _mm_mul_ps(Vec3A(b).cross(rhs).into(), _mm_mul_ps(w, TWO)), + )) + } + {% elif is_wasm32 %} + const TWO: v128 = const_f32x4!([2.0; 4]); + let w = i32x4_shuffle::<3, 3, 7, 7>(self.0, self.0); + let b = self.0; + let b2 = crate::wasm32::dot3_into_v128(b, b); + Vec3A(f32x4_add( + f32x4_add( + f32x4_mul(rhs.0, f32x4_sub(f32x4_mul(w, w), b2)), + f32x4_mul(b, f32x4_mul(crate::wasm32::dot3_into_v128(rhs.0, b), TWO)), + ), + f32x4_mul(Vec3A(b).cross(rhs).into(), f32x4_mul(w, TWO)), + )) + {% endif %} + } + + #[inline] + pub fn as_f64(self) -> DQuat { + DQuat::from_xyzw(self.x as f64, self.y as f64, self.z as f64, self.w as f64) + } + +{% elif scalar_t == "f64" %} + #[inline] + pub fn as_f32(self) -> Quat { + Quat::from_xyzw(self.x as f32, self.y as f32, self.z as f32, self.w as f32) + } +{% endif %} +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Debug for {{ self_t }} { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_tuple(stringify!({{ self_t }})) + .field(&self.x) + .field(&self.y) + .field(&self.z) + .field(&self.w) + .finish() + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Display for {{ self_t }} { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(fmt, "[{}, {}, {}, {}]", self.x, self.y, self.z, self.w) + } +} + +impl Add<{{ self_t }}> for {{ self_t }} { + type Output = Self; + /// Adds two quaternions. + /// + /// The sum is not guaranteed to be normalized. + /// + /// Note that addition is not the same as combining the rotations represented by the + /// two quaternions! That corresponds to multiplication. + #[inline] + fn add(self, rhs: Self) -> Self { + Self::from_vec4({{ vec4_t }}::from(self) + {{ vec4_t }}::from(rhs)) + } +} + +impl Sub<{{ self_t }}> for {{ self_t }} { + type Output = Self; + /// Subtracts the `rhs` quaternion from `self`. + /// + /// The difference is not guaranteed to be normalized. + #[inline] + fn sub(self, rhs: Self) -> Self { + Self::from_vec4({{ vec4_t }}::from(self) - {{ vec4_t }}::from(rhs)) + } +} + +impl Mul<{{ scalar_t }}> for {{ self_t }} { + type Output = Self; + /// Multiplies a quaternion by a scalar value. + /// + /// The product is not guaranteed to be normalized. + #[inline] + fn mul(self, rhs: {{ scalar_t }}) -> Self { + Self::from_vec4({{ vec4_t }}::from(self) * rhs) + } +} + +impl Div<{{ scalar_t }}> for {{ self_t }} { + type Output = Self; + /// Divides a quaternion by a scalar value. + /// The quotient is not guaranteed to be normalized. + #[inline] + fn div(self, rhs: {{ scalar_t }}) -> Self { + Self::from_vec4({{ vec4_t }}::from(self) / rhs) + } +} + +impl Mul<{{ self_t }}> for {{ self_t }} { + type Output = Self; + /// Multiplies two quaternions. If they each represent a rotation, the result will + /// represent the combined rotation. + /// + /// Note that due to floating point rounding the result may not be perfectly + /// normalized. + /// + /// # Panics + /// + /// Will panic if `self` or `rhs` are not normalized when `glam_assert` is enabled. + #[inline] + fn mul(self, rhs: Self) -> Self { + self.mul_quat(rhs) + } +} + +impl MulAssign<{{ self_t }}> for {{ self_t }} { + /// Multiplies two quaternions. If they each represent a rotation, the result will + /// represent the combined rotation. + /// + /// Note that due to floating point rounding the result may not be perfectly + /// normalized. + /// + /// # Panics + /// + /// Will panic if `self` or `rhs` are not normalized when `glam_assert` is enabled. + #[inline] + fn mul_assign(&mut self, rhs: Self) { + *self = self.mul_quat(rhs); + } +} + +impl Mul<{{ vec3_t }}> for {{ self_t }} { + type Output = {{ vec3_t }}; + /// Multiplies a quaternion and a 3D vector, returning the rotated vector. + /// + /// # Panics + /// + /// Will panic if `self` is not normalized when `glam_assert` is enabled. + #[inline] + fn mul(self, rhs: {{ vec3_t }}) -> Self::Output { + self.mul_vec3(rhs) + } +} + +impl Neg for {{ self_t }} { + type Output = Self; + #[inline] + fn neg(self) -> Self { + self * -1.0 + } +} + +impl Default for {{ self_t }} { + #[inline] + fn default() -> Self { + Self::IDENTITY + } +} + +impl PartialEq for {{ self_t }} { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + {{ vec4_t }}::from(*self).eq(&{{ vec4_t }}::from(*rhs)) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsRef<[{{ scalar_t }}; 4]> for {{ self_t }} { + #[inline] + fn as_ref(&self) -> &[{{ scalar_t }}; 4] { + unsafe { &*(self as *const Self as *const [{{ scalar_t }}; 4]) } + } +} + +impl<'a> Sum<&'a Self> for {{ self_t }} { + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, |a, &b| Self::add(a, b)) + } +} + +impl<'a> Product<&'a Self> for {{ self_t }} { + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::IDENTITY, |a, &b| Self::mul(a, b)) + } +} + +{% if scalar_t == "f32" %} +impl Mul for Quat { + type Output = Vec3A; + #[inline] + fn mul(self, rhs: Vec3A) -> Self::Output { + self.mul_vec3a(rhs) + } +} +{% endif %} + +impl From<{{ self_t }}> for {{ vec4_t }} { + #[inline] + fn from(q: {{ self_t }}) -> Self { + {% if is_scalar %} + Self::new(q.x, q.y, q.z, q.w) + {% else %} + Self(q.0) + {% endif %} + } +} + +impl From<{{ self_t }}> for ({{ scalar_t }}, {{ scalar_t }}, {{ scalar_t }}, {{ scalar_t }}) { + #[inline] + fn from(q: {{ self_t }}) -> Self { + {% if is_scalar %} + (q.x, q.y, q.z, q.w) + {% else %} + {{ vec4_t }}::from(q).into() + {% endif %} + } +} + +impl From<{{ self_t }}> for [{{ scalar_t }}; 4] { + #[inline] + fn from(q: {{ self_t }}) -> Self { + {% if is_scalar %} + [q.x, q.y, q.z, q.w] + {% else %} + {{ vec4_t }}::from(q).into() + {% endif %} + } +} + +{% if not is_scalar %} +impl From<{{ self_t }}> for {{ simd_t }} { + // TODO: write test + #[inline] + fn from(q: {{ self_t }}) -> Self { + {% if is_scalar %} + Self { x: q.x, y: q.y, z: q.z, w: q.w } + {% else %} + q.0 + {% endif %} + } +} +{% endif %} + +impl Deref for {{ self_t }} { + type Target = crate::deref::XYZW<{{ scalar_t }}>; + #[inline] + fn deref(&self) -> &Self::Target { + unsafe { &*(self as *const Self).cast() } + } +} + diff --git a/codegen/templates/swizzle_impl.rs b/codegen/templates/swizzle_impl.rs new file mode 100644 index 00000000..3cb85f31 --- /dev/null +++ b/codegen/templates/swizzle_impl.rs @@ -0,0 +1,98 @@ +// Generated from {{template_path}} template. Edit the template, not the generated file. + +#![allow(clippy::useless_conversion)] + +{# component indices #} +{% set indices = [0, 1, 2, 3] %} + +{# vector dimensions #} +{% set dimensions = [2, 3, 4] %} + +{# element names #} +{% set e = ["x", "y", "z", "w"] %} + +{# shuffle bits (sse2) #} +{% set b = ["00", "01", "10", "11"] %} + +{# low index (wasm32) #} +{% set l = ["0", "1", "2", "3"] %} + +{# high index (wasm32) #} +{% set h = ["4", "5", "6", "7"] %} + +use crate::{ + {{vec2_t}}, {{vec3_t}}, {{vec4_t}}, +}; +use super::Vec{{ dim }}Swizzles; + +{% if is_sse2 %} +#[cfg(target_arch = "x86")] +use core::arch::x86::*; +#[cfg(target_arch = "x86_64")] +use core::arch::x86_64::*; +{% elif is_wasm32 %} +use core::arch::wasm32::*; +{% endif %} + +impl Vec{{ dim }}Swizzles for {{ self_t }} { + {% if dim != 2 %} + type Vec2 = {{ vec2_t }}; + {% endif %} + {% if dim != 3 %} + type Vec3 = {{ vec3_t }}; + {% endif %} + {% if dim != 4 %} + type Vec4 = {{ vec4_t }}; + {% endif %} + + {% for i in dimensions %} + {% for j0 in indices | slice(end=dim) %} + {% for j1 in indices | slice(end=dim) %} + {% if i == 2 %} + {% set skip = dim == 2 and j0 == "x" and j1 == "y" %} + {% if not skip %} + #[inline] + fn {{ e[j0] }}{{ e[j1] }}(self) -> {{ vec2_t }} { + {{ vec2_t }} { x: self.{{ e[j0] }}, y: self.{{ e[j1] }} } + } + {% endif %} + {% else %} + {% for j2 in indices | slice(end=dim) %} + {% if i == 3 %} + {% set skip = dim == 3 and j0 == "x" and j1 == "y" and j2 == "z" %} + {% if not skip %} + #[inline] + fn {{ e[j0] }}{{ e[j1] }}{{ e[j2] }}(self) -> {{ vec3_t }} { + {% if vec3_t == "Vec3A" and is_sse2 %} + {{ vec3_t }}((unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_{{ b[j2] }}_{{ b[j1] }}_{{ b[j0] }}) }).into()) + {% elif vec3_t == "Vec3A" and is_wasm32 %} + {{ vec3_t }}(i32x4_shuffle::<{{ l[j0] }}, {{ l[j1] }}, {{ h[j2] }}, {{ h[0] }}>(self.0, self.0).into()) + {% else %} + {{ vec3_t }} { x: self.{{ e[j0] }}, y: self.{{ e[j1] }}, z: self.{{ e[j2] }} } + {% endif %} + } + {% endif %} + {% else %} + {% for j3 in indices | slice(end=dim) %} + {% set skip = dim == 4 and j0 == "x" and j1 == "y" and j2 == "z" and j3 == "w" %} + {% if not skip %} + #[inline] + fn {{ e[j0] }}{{ e[j1] }}{{ e[j2] }}{{ e[j3] }}(self) -> {{ vec4_t }} { + {% if is_sse2 %} + {{ vec4_t }}(unsafe { _mm_shuffle_ps(self.0, self.0, 0b{{ b[j3] }}_{{ b[j2] }}_{{ b[j1] }}_{{ b[j0] }}) }) + {% elif is_wasm32 %} + {{ vec4_t}}(i32x4_shuffle::<{{ l[j0] }}, {{ l[j1] }}, {{ h[j2] }}, {{ h[j3] }}>(self.0, self.0)) + {% else %} + {{ vec4_t }}::new(self.{{ e[j0] }}, self.{{ e[j1] }}, self.{{ e[j2] }}, self.{{ e[j3] }}) + {% endif %} + } + {% endif %} + {% endfor %} + {% endif %} + {% endfor %} + {% endif %} + {% endfor %} + {% endfor %} + {% endfor %} +} + diff --git a/codegen/templates/swizzle_traits.rs b/codegen/templates/swizzle_traits.rs new file mode 100644 index 00000000..bad26435 --- /dev/null +++ b/codegen/templates/swizzle_traits.rs @@ -0,0 +1,75 @@ +// Generated from {{template_path}} template. Edit the template, not the generated file. + +{% set components = ["x", "y", "z", "w"] %} +{% set dimensions = [2, 3, 4] %} +{% for dim in dimensions %} + {% set ret2 = "Self::Vec2" %} + {% set ret3 = "Self::Vec3" %} + {% set ret4 = "Self::Vec4" %} + + {% if dim == 4 %} + {% set ret4 = "Self" %} + {% elif dim == 3 %} + {% set ret3 = "Self" %} + {% elif dim == 2 %} + {% set ret2 = "Self" %} + {% endif %} + + pub trait Vec{{ dim }}Swizzles: Sized + Copy + Clone { + {% if dim != 2 %} + type Vec2; + {% endif %} + {% if dim != 3 %} + type Vec3; + {% endif %} + {% if dim != 4 %} + type Vec4; + {% endif %} + + {% if dim == 4 %} + #[inline] + fn xyzw(self) -> Self { + self + } + {% elif dim == 3 %} + #[inline] + fn xyz(self) -> Self { + self + } + {% elif dim == 2 %} + #[inline] + fn xy(self) -> Self { + self + } + {% endif %} + + {% for i in dimensions %} + {% for e0 in components | slice(end=dim) %} + {% for e1 in components | slice(end=dim) %} + {% if i == 2 %} + {% set skip = dim == 2 and e0 == "x" and e1 == "y" %} + {% if not skip %} + fn {{e0}}{{e1}}(self) -> {{ret2}}; + {% endif %} + {% else %} + {% for e2 in components | slice(end=dim) %} + {% if i == 3 %} + {% set skip = dim == 3 and e0 == "x" and e1 == "y" and e2 == "z" %} + {% if not skip %} + fn {{e0}}{{e1}}{{e2}}(self) -> {{ret3}}; + {% endif %} + {% else %} + {% for e3 in components | slice(end=dim) %} + {% set skip = dim == 4 and e0 == "x" and e1 == "y" and e2 == "z" and e3 == "w" %} + {% if not skip %} + fn {{e0}}{{e1}}{{e2}}{{e3}}(self) -> {{ret4}}; + {% endif %} + {% endfor %} + {% endif %} + {% endfor %} + {% endif %} + {% endfor %} + {% endfor %} + {% endfor %} + } +{% endfor %} diff --git a/codegen/templates/vec.rs b/codegen/templates/vec.rs new file mode 100644 index 00000000..22b509f7 --- /dev/null +++ b/codegen/templates/vec.rs @@ -0,0 +1,2242 @@ +{% import "macros.rs" as macros %} + +// Generated from {{template_path}} template. Edit the template, not the generated file. + +{% if dim == 2 %} + {% set deref_t = "XY::<" ~ scalar_t ~ ">" %} +{% elif dim == 3 %} + {% set deref_t = "XYZ::<" ~ scalar_t ~ ">" %} +{% elif dim == 4 %} + {% set deref_t = "XYZW::<" ~ scalar_t ~ ">" %} +{% endif %} + +{% if is_scalar %} + {% set mask_t = "BVec" ~ dim %} +{% else %} + {% set is_simd = true %} + {% if is_sse2 %} + {% set simd_t = "__m128" %} + {% elif is_wasm32 %} + {% set simd_t = "v128" %} + {% endif %} + {% set mask_t = "BVec" ~ dim ~ "A" %} +{% endif %} + +{% if scalar_t == "f32" or scalar_t == "f64" %} + {% set is_signed = true %} + {% set is_float = true %} + {% if scalar_t == "f32" %} + {% if dim == 3 and is_simd or is_align %} + {% set self_t = "Vec3A" %} + {% else %} + {% set self_t = "Vec" ~ dim %} + {% endif %} + {% set vec2_t = "Vec2" %} + {% set vec3_t = "Vec3" %} + {% set vec3a_t = "Vec3A" %} + {% set vec4_t = "Vec4" %} + {% elif scalar_t == "f64" %} + {% set self_t = "DVec" ~ dim %} + {% set vec2_t = "DVec2" %} + {% set vec3_t = "DVec3" %} + {% set vec4_t = "DVec4" %} + {% endif %} +{% elif scalar_t == "i32" %} + {% set is_signed = true %} + {% set is_float = false %} + {% set self_t = "IVec" ~ dim %} + {% set vec2_t = "IVec2" %} + {% set vec3_t = "IVec3" %} + {% set vec4_t = "IVec4" %} +{% else %} + {% set is_signed = false %} + {% set is_float = false %} + {% set self_t = "UVec" ~ dim %} + {% set vec2_t = "UVec2" %} + {% set vec3_t = "UVec3" %} + {% set vec4_t = "UVec4" %} +{% endif %} + +{% set const_new = "const_" ~ self_t | lower %} + +{% if scalar_t == "f64" or dim == 4 %} + {% set cuda_align = 16 %} +{% elif dim == 2 %} + {% set cuda_align = 8 %} +{% endif %} + +{% set components = ["x", "y", "z", "w"] | slice(end = dim) %} +{% if is_float %} + {% set one = "1.0" %} + {% set zero = "0.0" %} +{% else %} + {% set one = "1" %} + {% set zero = "0" %} +{% endif %} +{% set unit_x = [one, zero, zero, zero] %} +{% set unit_y = [zero, one, zero, zero] %} +{% set unit_z = [zero, zero, one, zero] %} +{% set unit_w = [zero, zero, zero, one] %} +{% set identity = [unit_x, unit_y, unit_z, unit_w] %} + +use crate::{ + {{ mask_t }}, + {% if self_t != vec2_t %} + {{ vec2_t }}, + {% endif %} + {% if self_t != vec3_t %} + {{ vec3_t }}, + {% endif %} + {% if self_t == "Vec3" or self_t == "Vec4" %} + {{ vec3a_t }}, + {% endif %} + {% if dim > 2 and self_t != vec4_t %} + {{ vec4_t }}, + {% endif %} +}; + +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::iter::{Product, Sum}; +use core::{f32, ops::*}; + +{% if is_sse2 %} +#[cfg(target_arch = "x86")] +use core::arch::x86::*; +#[cfg(target_arch = "x86_64")] +use core::arch::x86_64::*; +{% elif is_wasm32 %} +use core::arch::wasm32::*; +{% endif %} + +{% if is_float %} +#[cfg(not(feature = "std"))] +use num_traits::Float; +{% endif %} + +{% if is_simd %} +union UnionCast { + a: [f32; 4], + v: {{ self_t }} +} +{% endif %} + +/// Creates a {{ dim }}-dimensional vector. +#[inline(always)] +pub const fn {{ self_t | lower }}( + {% for c in components %} + {{ c }}: {{ scalar_t }}, + {% endfor %} +) -> {{ self_t }} { + {{ self_t }}::new({{ components | join(sep=",") }}) +} + +{% if self_t == "Vec3A" %} +/// A 3-dimensional vector with SIMD support. +/// +/// This type is 16 byte aligned. A SIMD vector type is used for storage on supported platforms for +/// better performance than the `Vec3` type. +/// +/// It is possible to convert between `Vec3` and `Vec3A` types using `From` trait implementations. +{%- elif self_t == "Vec4" and is_simd %} +/// A 4-dimensional vector with SIMD support. +/// +/// This type uses 16 byte aligned SIMD vector type for storage. +{%- else %} +/// A {{ dim }}-dimensional vector. +{%- endif %} +#[derive(Clone, Copy)] +{%- if self_t == "Vec3A" and is_scalar %} +#[repr(C, align(16))] +{%- elif self_t == "Vec4" and is_scalar %} +#[cfg_attr( + any( + not(any(feature = "scalar-math", target_arch = "spirv")), + feature = "cuda"), + repr(C, align(16)) +)] +{%- elif dim != 3 and is_scalar %} +#[cfg_attr(feature = "cuda", repr(C, align({{ cuda_align }})))] +{%- endif %} +{%- if is_scalar %} +pub struct {{ self_t }} +{ + {% for c in components %} + pub {{ c }}: {{ scalar_t }}, + {%- endfor %} +} +{% else %} +#[repr(transparent)] +pub struct {{ self_t }}(pub(crate) {{ simd_t }}); +{% endif %} + +impl {{ self_t }} { + /// All zeroes. + pub const ZERO: Self = Self::splat({{ zero }}); + + /// All ones. + pub const ONE: Self = Self::splat({{ one }}); + +{% if is_signed %} + /// All negative ones. + pub const NEG_ONE: Self = Self::splat(-{{ one }}); +{% endif %} + +{% if is_float %} + /// All NAN. + pub const NAN: Self = Self::splat({{ scalar_t }}::NAN); +{% endif %} + +{% for i in range(end = dim) %} + {% set C = components[i] | upper %} + /// `[{{ identity[i] | slice(end = dim) | join(sep=", ") }}]`: a unit-length vector pointing along the positive {{ C }} axis. + pub const {{ C }}: Self = Self::from_array({{ identity[i] | slice(end = dim) }}); +{% endfor %} + + /// The unit axes. + pub const AXES: [Self; {{ dim }}] = [ + {% for c in components %} + Self::{{ c | upper }}, + {% endfor %} + ]; + + /// Creates a new vector. + #[inline(always)] + pub const fn new( + {% for c in components %} + {{ c }}: {{ scalar_t }}, + {% endfor %} + ) -> Self { + {% if is_scalar %} + Self { + {% for c in components %} + {{ c }}, + {%- endfor %} + } + {% elif is_sse2 %} + unsafe { + UnionCast { a: [ + {% if dim == 3 %} + x, y, z, z + {% elif dim == 4 %} + x, y, z, w + {% endif %} + ] }.v + } + {% elif is_wasm32 %} + Self(f32x4( + {% if dim == 3 %} + x, y, z, z + {% elif dim == 4 %} + x, y, z, w + {% endif %} + )) + {% endif %} + } + + /// Creates a vector with all elements set to `v`. + #[inline] + pub const fn splat(v: {{ scalar_t }}) -> Self { + {% if is_scalar %} + Self { + {% for c in components %} + {{ c }}: v, + {% endfor %} + } + {% else %} + unsafe { UnionCast { a: [v; 4] }.v } + {% endif %} + } + + /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use + /// for each element of `self`. + /// + /// A true element in the mask uses the corresponding element from `if_true`, and false + /// uses the element from `if_false`. + #[inline] + pub fn select(mask: {{ mask_t }}, if_true: Self, if_false: Self) -> Self { + {% if is_scalar %} + Self { + {% for c in components %} + {{ c }}: if mask.{{ c }} { if_true.{{ c }} } else { if_false.{{ c }} }, + {%- endfor %} + } + {% elif is_sse2 %} + Self(unsafe { _mm_or_ps(_mm_andnot_ps(mask.0, if_false.0), _mm_and_ps(if_true.0, mask.0)) }) + {% elif is_wasm32 %} + Self(v128_bitselect(if_true.0, if_false.0, mask.0)) + {% endif %} + } + + /// Creates a new vector from an array. + #[inline] + pub const fn from_array(a: [{{ scalar_t }}; {{ dim }}]) -> Self { + Self::new( + {% for c in components %} + a[{{ loop.index0 }}], + {%- endfor %} + ) + } + + /// `[{{ components | join(sep=", ") }}]` + #[inline] + pub const fn to_array(&self) -> [{{ scalar_t }}; {{ dim }}] { + {% if is_scalar %} + [ + {% for c in components %} + self.{{ c }}, + {% endfor %} + ] + {% else %} + unsafe { *(self as *const {{ self_t }} as *const [{{ scalar_t }}; {{ dim }}]) } + {% endif %} + } + + /// Creates a vector from the first N values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than N elements long. + #[inline] + pub const fn from_slice(slice: &[{{ scalar_t }}]) -> Self { + Self::new( + {% for c in components %} + slice[{{ loop.index0 }}], + {%- endfor %} + ) + } + + /// Writes the elements of `self` to the first {{ dim }} elements in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than N elements long. + #[inline] + pub fn write_to_slice(self, slice: &mut [{{ scalar_t }}]) { + {% if self_t == "Vec4" and is_sse2 %} + unsafe { + assert!(slice.len() >= 4); + _mm_storeu_ps(slice.as_mut_ptr(), self.0); + } + {% else %} + {% for c in components %} + slice[{{ loop.index0 }}] = self.{{ c }}; + {%- endfor %} + {% endif %} + } + +{% if dim == 2 %} + /// Creates a 3D vector from `self` and the given `z` value. + #[inline] + pub const fn extend(self, z: {{ scalar_t }}) -> {{ vec3_t }} { + {{ vec3_t }}::new(self.x, self.y, z) + } +{% elif dim == 3 %} + /// Internal method for creating a 3D vector from a 4D vector, discarding `w`. + #[allow(dead_code)] + #[inline] + pub(crate) fn from_vec4(v: {{ vec4_t }}) -> Self { + {% if is_scalar %} + Self { x: v.x, y: v.y, z: v.z } + {% else %} + Self(v.0) + {% endif %} + } + + /// Creates a 4D vector from `self` and the given `w` value. + #[inline] + pub fn extend(self, w: {{ scalar_t }}) -> {{ vec4_t }} { + {{ vec4_t }}::new(self.x, self.y, self.z, w) + } + + /// Creates a 2D vector from the `x` and `y` elements of `self`, discarding `z`. + /// + /// Truncation may also be performed by using `self.xy()` or `{{ vec2_t }}::from()`. + #[inline] + pub fn truncate(self) -> {{ vec2_t }} { + use crate::swizzles::Vec3Swizzles; + self.xy() + } +{% elif dim == 4 %} + /// Creates a 2D vector from the `x`, `y` and `z` elements of `self`, discarding `w`. + /// + /// Truncation to `{{ vec3_t }}` may also be performed by using `self.xyz()` or `{{ vec3_t }}::from()`. +{%- if scalar_t == "f32" %} + /// + /// To truncate to `Vec3A` use `Vec3A::from()`. +{%- endif %} + #[inline] + pub fn truncate(self) -> {{ vec3_t }} { + use crate::swizzles::Vec4Swizzles; + self.xyz() + } +{% endif %} + + /// Computes the dot product of `self` and `rhs`. + #[inline] + pub fn dot(self, rhs: Self) -> {{ scalar_t }} { + {% if is_scalar %} + {% for c in components %} + (self.{{ c }} * rhs.{{ c }}) {% if not loop.last %} + {% endif %} + {%- endfor %} + {% elif is_sse2 %} + unsafe { crate::sse2::dot{{ dim }}(self.0, rhs.0) } + {% elif is_wasm32 %} + crate::wasm32::dot{{ dim }}(self.0, rhs.0) + {% endif %} + } + +{% if dim == 3 %} + /// Computes the cross product of `self` and `rhs`. + #[inline] + pub fn cross(self, rhs: Self) -> Self { + {% if is_scalar %} + Self { + x: self.y * rhs.z - rhs.y * self.z, + y: self.z * rhs.x - rhs.z * self.x, + z: self.x * rhs.y - rhs.x * self.y, + } + {% elif is_sse2 %} + unsafe { + // x <- a.y*b.z - a.z*b.y + // y <- a.z*b.x - a.x*b.z + // z <- a.x*b.y - a.y*b.x + // We can save a shuffle by grouping it in this wacky order: + // (self.zxy() * rhs - self * rhs.zxy()).zxy() + let lhszxy = _mm_shuffle_ps(self.0, self.0, 0b01_01_00_10); + let rhszxy = _mm_shuffle_ps(rhs.0, rhs.0, 0b01_01_00_10); + let lhszxy_rhs = _mm_mul_ps(lhszxy, rhs.0); + let rhszxy_lhs = _mm_mul_ps(rhszxy, self.0); + let sub = _mm_sub_ps(lhszxy_rhs, rhszxy_lhs); + Self(_mm_shuffle_ps(sub, sub, 0b01_01_00_10)) + } + {% elif is_wasm32 %} + let lhszxy = i32x4_shuffle::<2, 0, 1, 1>(self.0, self.0); + let rhszxy = i32x4_shuffle::<2, 0, 1, 1>(rhs.0, rhs.0); + let lhszxy_rhs = f32x4_mul(lhszxy, rhs.0); + let rhszxy_lhs = f32x4_mul(rhszxy, self.0); + let sub = f32x4_sub(lhszxy_rhs, rhszxy_lhs); + Self(i32x4_shuffle::<2, 0, 1, 1>(sub, sub)) + {% endif %} + } +{% endif %} + + /// Returns a vector containing the minimum values for each element of `self` and `rhs`. + /// + /// In other words this computes `[self.x.min(rhs.x), self.y.min(rhs.y), ..]`. + #[inline] + pub fn min(self, rhs: Self) -> Self { + {% if is_scalar %} + Self { + {% for c in components %} + {{ c }}: self.{{ c }}.min(rhs.{{ c }}), + {%- endfor %} + } + {% elif is_sse2 %} + Self(unsafe { _mm_min_ps(self.0, rhs.0) }) + {% elif is_wasm32 %} + Self(f32x4_pmin(self.0, rhs.0)) + {% endif %} + } + + /// Returns a vector containing the maximum values for each element of `self` and `rhs`. + /// + /// In other words this computes `[self.x.max(rhs.x), self.y.max(rhs.y), ..]`. + #[inline] + pub fn max(self, rhs: Self) -> Self { + {% if is_scalar %} + Self { + {% for c in components %} + {{ c }}: self.{{ c }}.max(rhs.{{ c }}), + {%- endfor %} + } + {% elif is_sse2 %} + Self(unsafe { _mm_max_ps(self.0, rhs.0) }) + {% elif is_wasm32 %} + Self(f32x4_pmax(self.0, rhs.0)) + {% endif %} + } + + /// Component-wise clamping of values, similar to [`f32::clamp`]. + /// + /// Each element in `min` must be less-or-equal to the corresponding element in `max`. + /// + /// # Panics + /// + /// Will panic if `min` is greater than `max` when `glam_assert` is enabled. + #[inline] + pub fn clamp(self, min: Self, max: Self) -> Self { + glam_assert!(min.cmple(max).all(), "clamp: expected min <= max"); + self.max(min).min(max) + } + + /// Returns the horizontal minimum of `self`. + /// + /// In other words this computes `min(x, y, ..)`. + #[inline] + pub fn min_element(self) -> {{ scalar_t }} { + {% if is_scalar %} + {% if dim == 2 %} + self.x.min(self.y) + {% elif dim == 3 %} + self.x.min(self.y.min(self.z)) + {% elif dim == 4 %} + self.x.min(self.y.min(self.z.min(self.w))) + {% endif %} + {% elif is_sse2 %} + {% if dim == 3 %} + unsafe { + let v = self.0; + let v = _mm_min_ps(v, _mm_shuffle_ps(v, v, 0b01_01_10_10)); + let v = _mm_min_ps(v, _mm_shuffle_ps(v, v, 0b00_00_00_01)); + _mm_cvtss_f32(v) + } + {% elif dim == 4 %} + unsafe { + let v = self.0; + let v = _mm_min_ps(v, _mm_shuffle_ps(v, v, 0b00_00_11_10)); + let v = _mm_min_ps(v, _mm_shuffle_ps(v, v, 0b00_00_00_01)); + _mm_cvtss_f32(v) + } + {% endif %} + {% elif is_wasm32 %} + {% if dim == 3 %} + let v = self.0; + let v = f32x4_pmin(v, i32x4_shuffle::<2, 2, 1, 1>(v, v)); + let v = f32x4_pmin(v, i32x4_shuffle::<1, 0, 0, 0>(v, v)); + f32x4_extract_lane::<0>(v) + {% elif dim == 4 %} + let v = self.0; + let v = f32x4_pmin(v, i32x4_shuffle::<2, 3, 0, 0>(v, v)); + let v = f32x4_pmin(v, i32x4_shuffle::<1, 0, 0, 0>(v, v)); + f32x4_extract_lane::<0>(v) + {% endif %} + {% endif %} + } + + /// Returns the horizontal maximum of `self`. + /// + /// In other words this computes `max(x, y, ..)`. + #[inline] + pub fn max_element(self) -> {{ scalar_t }} { + {% if is_scalar %} + {% if dim == 2 %} + self.x.max(self.y) + {% elif dim == 3 %} + self.x.max(self.y.max(self.z)) + {% elif dim == 4 %} + self.x.max(self.y.max(self.z.max(self.w))) + {% endif %} + {% elif is_sse2 %} + {% if dim == 3 %} + unsafe { + let v = self.0; + let v = _mm_max_ps(v, _mm_shuffle_ps(v, v, 0b00_00_10_10)); + let v = _mm_max_ps(v, _mm_shuffle_ps(v, v, 0b00_00_00_01)); + _mm_cvtss_f32(v) + } + {% elif dim == 4 %} + unsafe { + let v = self.0; + let v = _mm_max_ps(v, _mm_shuffle_ps(v, v, 0b00_00_11_10)); + let v = _mm_max_ps(v, _mm_shuffle_ps(v, v, 0b00_00_00_01)); + _mm_cvtss_f32(v) + } + {% endif %} + {% elif is_wasm32 %} + {% if dim == 3 %} + let v = self.0; + let v = f32x4_pmax(v, i32x4_shuffle::<2, 2, 0, 0>(v, v)); + let v = f32x4_pmax(v, i32x4_shuffle::<1, 0, 0, 0>(v, v)); + f32x4_extract_lane::<0>(v) + {% elif dim == 4 %} + let v = self.0; + let v = f32x4_pmax(v, i32x4_shuffle::<2, 3, 0, 0>(v, v)); + let v = f32x4_pmax(v, i32x4_shuffle::<1, 0, 0, 0>(v, v)); + f32x4_extract_lane::<0>(v) + {% endif %} + {% endif %} + } + + /// Returns a vector mask containing the result of a `==` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words, this computes `[self.x == rhs.x, self.y == rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpeq(self, rhs: Self) -> {{ mask_t }} { + {% if is_scalar %} + {{ mask_t }}::new( + {% for c in components %} + self.{{ c }}.eq(&rhs.{{ c }}), + {%- endfor %} + ) + {% elif is_sse2 %} + {{ mask_t }}(unsafe { _mm_cmpeq_ps(self.0, rhs.0) }) + {% elif is_wasm32 %} + {{ mask_t }}(f32x4_eq(self.0, rhs.0)) + {% endif %} + } + + /// Returns a vector mask containing the result of a `!=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x != rhs.x, self.y != rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpne(self, rhs: Self) -> {{ mask_t }} { + {% if is_scalar %} + {{ mask_t }}::new( + {% for c in components %} + self.{{ c }}.ne(&rhs.{{ c }}), + {%- endfor %} + ) + {% elif is_sse2 %} + {{ mask_t }}(unsafe { _mm_cmpneq_ps(self.0, rhs.0) }) + {% elif is_wasm32 %} + {{ mask_t }}(f32x4_ne(self.0, rhs.0)) + {% endif %} + } + + /// Returns a vector mask containing the result of a `>=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x >= rhs.x, self.y >= rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpge(self, rhs: Self) -> {{ mask_t }} { + {% if is_scalar %} + {{ mask_t }}::new( + {% for c in components %} + self.{{ c }}.ge(&rhs.{{ c }}), + {%- endfor %} + ) + {% elif is_sse2 %} + {{ mask_t }}(unsafe { _mm_cmpge_ps(self.0, rhs.0) }) + {% elif is_wasm32 %} + {{ mask_t }}(f32x4_ge(self.0, rhs.0)) + {% endif %} + } + + /// Returns a vector mask containing the result of a `>` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x > rhs.x, self.y > rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpgt(self, rhs: Self) -> {{ mask_t }} { + {% if is_scalar %} + {{ mask_t }}::new( + {% for c in components %} + self.{{ c }}.gt(&rhs.{{ c }}), + {%- endfor %} + ) + {% elif is_sse2 %} + {{ mask_t }}(unsafe { _mm_cmpgt_ps(self.0, rhs.0) }) + {% elif is_wasm32 %} + {{ mask_t }}(f32x4_gt(self.0, rhs.0)) + {% endif %} + } + + /// Returns a vector mask containing the result of a `<=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x <= rhs.x, self.y <= rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmple(self, rhs: Self) -> {{ mask_t }} { + {% if is_scalar %} + {{ mask_t }}::new( + {% for c in components %} + self.{{ c }}.le(&rhs.{{ c }}), + {%- endfor %} + ) + {% elif is_sse2 %} + {{ mask_t }}(unsafe { _mm_cmple_ps(self.0, rhs.0) }) + {% elif is_wasm32 %} + {{ mask_t }}(f32x4_le(self.0, rhs.0)) + {% endif %} + } + + /// Returns a vector mask containing the result of a `<` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x < rhs.x, self.y < rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmplt(self, rhs: Self) -> {{ mask_t }} { + {% if is_scalar %} + {{ mask_t }}::new( + {% for c in components %} + self.{{ c }}.lt(&rhs.{{ c }}), + {%- endfor %} + ) + {% elif is_sse2 %} + {{ mask_t }}(unsafe { _mm_cmplt_ps(self.0, rhs.0) }) + {% elif is_wasm32 %} + {{ mask_t }}(f32x4_lt(self.0, rhs.0)) + {% endif %} + } + +{% if is_signed %} + /// Returns a vector containing the absolute value of each element of `self`. + #[inline] + pub fn abs(self) -> Self { + {% if is_scalar %} + Self { + {% for c in components %} + {{ c }}: self.{{ c }}.abs(), + {%- endfor %} + } + {% elif is_sse2 %} + Self(unsafe { crate::sse2::m128_abs(self.0) }) + {% elif is_wasm32 %} + Self(f32x4_abs(self.0)) + {% endif %} + } + + /// Returns a vector with elements representing the sign of `self`. + /// + /// - `1.0` if the number is positive, `+0.0` or `INFINITY` + /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` + /// - `NAN` if the number is `NAN` + #[inline] + pub fn signum(self) -> Self { + {% if is_scalar %} + Self { + {% for c in components %} + {{ c }}: self.{{ c }}.signum(), + {%- endfor %} + } + {% else %} + let mask = self.cmpge(Self::ZERO); + let result = Self::select(mask, Self::ONE, Self::NEG_ONE); + let mask = self.is_nan_mask(); + Self::select(mask, self, result) + {% endif %} + } +{% endif %} + +{% if is_float %} + /// Returns `true` if, and only if, all elements are finite. If any element is either + /// `NaN`, positive or negative infinity, this will return `false`. + #[inline] + pub fn is_finite(self) -> bool { + {% for c in components %} + self.{{ c }}.is_finite() {% if not loop.last %} && {% endif %} + {%- endfor %} + } + + /// Returns `true` if any elements are `NaN`. + #[inline] + pub fn is_nan(self) -> bool { + {% if is_scalar %} + {% for c in components %} + self.{{ c }}.is_nan() {% if not loop.last %} || {% endif %} + {%- endfor %} + {% else %} + self.is_nan_mask().any() + {% endif %} + } + + /// Performs `is_nan` on each element of self, returning a vector mask of the results. + /// + /// In other words, this computes `[x.is_nan(), y.is_nan(), z.is_nan(), w.is_nan()]`. + #[inline] + pub fn is_nan_mask(self) -> {{ mask_t }} { + {% if is_scalar %} + {{ mask_t }}::new( + {% for c in components %} + self.{{ c }}.is_nan(), + {%- endfor %} + ) + {% elif is_sse2 %} + {{ mask_t }}(unsafe { _mm_cmpunord_ps(self.0, self.0) }) + {% elif is_wasm32 %} + {{ mask_t }}(f32x4_ne(self.0, self.0)) + {% endif %} + } + + /// Computes the length of `self`. + #[doc(alias = "magnitude")] + #[inline] + pub fn length(self) -> {{ scalar_t }} { + {% if is_scalar %} + self.dot(self).sqrt() + {% elif is_sse2 %} + unsafe { + let dot = crate::sse2::dot{{ dim }}_in_x(self.0, self.0); + _mm_cvtss_f32(_mm_sqrt_ps(dot)) + } + {% elif is_wasm32 %} + let dot = crate::wasm32::dot{{ dim }}_in_x(self.0, self.0); + f32x4_extract_lane::<0>(f32x4_sqrt(dot)) + {% endif %} + } + + /// Computes the squared length of `self`. + /// + /// This is faster than `length()` as it avoids a square root operation. + #[doc(alias = "magnitude2")] + #[inline] + pub fn length_squared(self) -> {{ scalar_t }} { + self.dot(self) + } + + /// Computes `1.0 / length()`. + /// + /// For valid results, `self` must _not_ be of length zero. + #[inline] + pub fn length_recip(self) -> {{ scalar_t }} { + {% if is_scalar %} + self.length().recip() + {% elif is_sse2 %} + unsafe { + let dot = crate::sse2::dot{{ dim }}_in_x(self.0, self.0); + _mm_cvtss_f32(_mm_div_ps(Self::ONE.0, _mm_sqrt_ps(dot))) + } + {% elif is_wasm32 %} + let dot = crate::wasm32::dot{{ dim }}_in_x(self.0, self.0); + f32x4_extract_lane::<0>(f32x4_div(Self::ONE.0, f32x4_sqrt(dot))) + {% endif %} + } + + /// Computes the Euclidean distance between two points in space. + #[inline] + pub fn distance(self, rhs: Self) -> {{ scalar_t }} { + (self - rhs).length() + } + + /// Compute the squared euclidean distance between two points in space. + #[inline] + pub fn distance_squared(self, rhs: Self) -> {{ scalar_t }} { + (self - rhs).length_squared() + } + + /// Returns `self` normalized to length 1.0. + /// + /// For valid results, `self` must _not_ be of length zero, nor very close to zero. + /// + /// See also [`Self::try_normalize`] and [`Self::normalize_or_zero`]. + /// + /// Panics + /// + /// Will panic if `self` is zero length when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn normalize(self) -> Self { + {% if is_scalar %} + #[allow(clippy::let_and_return)] + let normalized = self.mul(self.length_recip()); + glam_assert!(normalized.is_finite()); + normalized + {% elif is_sse2 %} + unsafe { + let length = _mm_sqrt_ps(crate::sse2::dot{{ dim }}_into_m128(self.0, self.0)); + #[allow(clippy::let_and_return)] + let normalized = Self(_mm_div_ps(self.0, length)); + glam_assert!(normalized.is_finite()); + normalized + } + {% elif is_wasm32 %} + let length = f32x4_sqrt(crate::wasm32::dot{{ dim }}_into_v128(self.0, self.0)); + #[allow(clippy::let_and_return)] + let normalized = Self(f32x4_div(self.0, length)); + glam_assert!(normalized.is_finite()); + normalized + {% endif %} + } + + /// Returns `self` normalized to length 1.0 if possible, else returns `None`. + /// + /// In particular, if the input is zero (or very close to zero), or non-finite, + /// the result of this operation will be `None`. + /// + /// See also [`Self::normalize_or_zero`]. + #[must_use] + #[inline] + pub fn try_normalize(self) -> Option { + let rcp = self.length_recip(); + if rcp.is_finite() && rcp > 0.0 { + Some(self * rcp) + } else { + None + } + } + + /// Returns `self` normalized to length 1.0 if possible, else returns zero. + /// + /// In particular, if the input is zero (or very close to zero), or non-finite, + /// the result of this operation will be zero. + /// + /// See also [`Self::try_normalize`]. + #[must_use] + #[inline] + pub fn normalize_or_zero(self) -> Self { + let rcp = self.length_recip(); + if rcp.is_finite() && rcp > 0.0 { + self * rcp + } else { + Self::ZERO + } + } + + /// Returns whether `self` is length `1.0` or not. + /// + /// Uses a precision threshold of `1e-6`. + #[inline] + pub fn is_normalized(self) -> bool { + // TODO: do something with epsilon + (self.length_squared() - 1.0).abs() <= 1e-4 + } + + /// Returns the vector projection of `self` onto `rhs`. + /// + /// `rhs` must be of non-zero length. + /// + /// # Panics + /// + /// Will panic if `rhs` is zero length when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn project_onto(self, rhs: Self) -> Self { + let other_len_sq_rcp = rhs.dot(rhs).recip(); + glam_assert!(other_len_sq_rcp.is_finite()); + rhs * self.dot(rhs) * other_len_sq_rcp + } + + /// Returns the vector rejection of `self` from `rhs`. + /// + /// The vector rejection is the vector perpendicular to the projection of `self` onto + /// `rhs`, in rhs words the result of `self - self.project_onto(rhs)`. + /// + /// `rhs` must be of non-zero length. + /// + /// # Panics + /// + /// Will panic if `rhs` has a length of zero when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn reject_from(self, rhs: Self) -> Self { + self - self.project_onto(rhs) + } + + /// Returns the vector projection of `self` onto `rhs`. + /// + /// `rhs` must be normalized. + /// + /// # Panics + /// + /// Will panic if `rhs` is not normalized when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn project_onto_normalized(self, rhs: Self) -> Self { + glam_assert!(rhs.is_normalized()); + rhs * self.dot(rhs) + } + + /// Returns the vector rejection of `self` from `rhs`. + /// + /// The vector rejection is the vector perpendicular to the projection of `self` onto + /// `rhs`, in rhs words the result of `self - self.project_onto(rhs)`. + /// + /// `rhs` must be normalized. + /// + /// # Panics + /// + /// Will panic if `rhs` is not normalized when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn reject_from_normalized(self, rhs: Self) -> Self { + self - self.project_onto_normalized(rhs) + } + + /// Returns a vector containing the nearest integer to a number for each element of `self`. + /// Round half-way cases away from 0.0. + #[inline] + pub fn round(self) -> Self { + {% if is_scalar %} + Self { + {% for c in components %} + {{ c }}: self.{{ c }}.round(), + {%- endfor %} + } + {% elif is_sse2 %} + Self(unsafe { crate::sse2::m128_round(self.0) }) + {% elif is_wasm32 %} + Self(f32x4_nearest(self.0)) + {% endif %} + } + + /// Returns a vector containing the largest integer less than or equal to a number for each + /// element of `self`. + #[inline] + pub fn floor(self) -> Self { + {% if is_scalar %} + Self { + {% for c in components %} + {{ c }}: self.{{ c }}.floor(), + {%- endfor %} + } + {% elif is_sse2 %} + Self(unsafe { crate::sse2::m128_floor(self.0) }) + {% elif is_wasm32 %} + Self(f32x4_floor(self.0)) + {% endif %} + } + + /// Returns a vector containing the smallest integer greater than or equal to a number for + /// each element of `self`. + #[inline] + pub fn ceil(self) -> Self { + {% if is_scalar %} + Self { + {% for c in components %} + {{ c }}: self.{{ c }}.ceil(), + {%- endfor %} + } + {% elif is_sse2 %} + Self(unsafe { crate::sse2::m128_ceil(self.0) }) + {% elif is_wasm32 %} + Self(f32x4_ceil(self.0)) + {% endif %} + } + + /// Returns a vector containing the fractional part of the vector, e.g. `self - + /// self.floor()`. + /// + /// Note that this is fast but not precise for large numbers. + #[inline] + pub fn fract(self) -> Self { + self - self.floor() + } + + /// Returns a vector containing `e^self` (the exponential function) for each element of + /// `self`. + #[inline] + pub fn exp(self) -> Self { + Self::new( + {% for c in components %} + self.{{ c }}.exp(), + {%- endfor %} + ) + } + + /// Returns a vector containing each element of `self` raised to the power of `n`. + #[inline] + pub fn powf(self, n: {{ scalar_t }}) -> Self { + Self::new( + {% for c in components %} + self.{{ c }}.powf(n), + {%- endfor %} + ) + } + + /// Returns a vector containing the reciprocal `1.0/n` of each element of `self`. + #[inline] + pub fn recip(self) -> Self { + {% if is_scalar %} + Self { + {% for c in components %} + {{ c }}: self.{{ c }}.recip(), + {%- endfor %} + } + {% elif is_sse2 %} + Self(unsafe { _mm_div_ps(Self::ONE.0, self.0) }) + {% elif is_wasm32 %} + Self(f32x4_div(Self::ONE.0, self.0)) + {% endif %} + } + + /// Performs a linear interpolation between `self` and `rhs` based on the value `s`. + /// + /// When `s` is `0.0`, the result will be equal to `self`. When `s` is `1.0`, the result + /// will be equal to `rhs`. When `s` is outside of range `[0, 1]`, the result is linearly + /// extrapolated. + #[doc(alias = "mix")] + #[inline] + pub fn lerp(self, rhs: Self, s: {{ scalar_t }}) -> Self { + self + ((rhs - self) * s) + } + + /// Returns true if the absolute difference of all elements between `self` and `rhs` is + /// less than or equal to `max_abs_diff`. + /// + /// This can be used to compare if two vectors contain similar elements. It works best when + /// comparing with a known value. The `max_abs_diff` that should be used used depends on + /// the values being compared against. + /// + /// For more see + /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/). + #[inline] + pub fn abs_diff_eq(self, rhs: Self, max_abs_diff: {{ scalar_t }}) -> bool { + self.sub(rhs).abs().cmple(Self::splat(max_abs_diff)).all() + } + + /// Returns a vector with a length no less than `min` and no more than `max` + /// + /// # Panics + /// + /// Will panic if `min` is greater than `max` when `glam_assert` is enabled. + #[inline] + pub fn clamp_length(self, min: {{ scalar_t }}, max: {{ scalar_t }}) -> Self { + glam_assert!(min <= max); + let length_sq = self.length_squared(); + if length_sq < min * min { + self * (length_sq.sqrt().recip() * min) + } else if length_sq > max * max { + self * (length_sq.sqrt().recip() * max) + } else { + self + } + } + + /// Returns a vector with a length no more than `max` + pub fn clamp_length_max(self, max: {{ scalar_t }}) -> Self { + let length_sq = self.length_squared(); + if length_sq > max * max { + self * (length_sq.sqrt().recip() * max) + } else { + self + } + } + + /// Returns a vector with a length no less than `min` + pub fn clamp_length_min(self, min: {{ scalar_t }}) -> Self { + let length_sq = self.length_squared(); + if length_sq < min * min { + self * (length_sq.sqrt().recip() * min) + } else { + self + } + } + + /// Fused multiply-add. Computes `(self * a) + b` element-wise with only one rounding + /// error, yielding a more accurate result than an unfused multiply-add. + /// + /// Using `mul_add` *may* be more performant than an unfused multiply-add if the target + /// architecture has a dedicated fma CPU instruction. However, this is not always true, + /// and will be heavily dependant on designing algorithms with specific target hardware in + /// mind. + #[inline] + pub fn mul_add(self, a: Self, b: Self) -> Self { + {% if is_sse2 %} + #[cfg(target_feature = "fma")] + unsafe { _mm_fmadd_ps(self, b, c) } + #[cfg(not(target_feature = "fma"))] + {% endif %} + Self::new( + {% for c in components %} + self.{{ c }}.mul_add(a.{{ c }}, b.{{ c }}), + {%- endfor %} + ) + } + +{% if dim == 2 %} + /// Creates a 2D vector containing `[angle.cos(), angle.sin()]`. This can be used in + /// conjunction with the `rotate` method, e.g. `Vec2::from_angle(PI).rotate(Vec2::Y)` will + /// create the vector [-1, 0] and rotate `Vec2::Y` around it returning `-Vec2::Y`. + #[inline] + pub fn from_angle(angle: {{ scalar_t }}) -> Self { + let (sin, cos) = angle.sin_cos(); + Self { + x: cos, + y: sin, + } + } + + /// Returns the angle (in radians) between `self` and `rhs`. + /// + /// The input vectors do not need to be unit length however they must be non-zero. + #[inline] + pub fn angle_between(self, rhs: Self) -> {{ scalar_t }} { + use crate::FloatEx; + let angle = (self.dot(rhs) / (self.length_squared() * rhs.length_squared()).sqrt()) + .acos_approx(); + + angle * self.perp_dot(rhs).signum() + } +{% elif dim == 3 %} + /// Returns the angle (in radians) between two vectors. + /// + /// The input vectors do not need to be unit length however they must be non-zero. + #[inline] + pub fn angle_between(self, rhs: Self) -> {{ scalar_t }} { + use crate::FloatEx; + self.dot(rhs) + .div(self.length_squared().mul(rhs.length_squared()).sqrt()) + .acos_approx() + } + + /// Returns some vector that is orthogonal to the given one. + /// + /// The input vector must be finite and non-zero. + /// + /// The output vector is not necessarily unit-length. + /// For that use [`Self::any_orthonormal_vector`] instead. + #[inline] + pub fn any_orthogonal_vector(&self) -> Self { + // This can probably be optimized + if self.x.abs() > self.y.abs() { + Self::new(-self.z, 0.0, self.x) // self.cross(Self::Y) + } else { + Self::new(0.0, self.z, -self.y) // self.cross(Self::X) + } + } + + /// Returns any unit-length vector that is orthogonal to the given one. + /// The input vector must be finite and non-zero. + /// + /// # Panics + /// + /// Will panic if `self` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn any_orthonormal_vector(&self) -> Self { + glam_assert!(self.is_normalized()); + // From https://graphics.pixar.com/library/OrthonormalB/paper.pdf + #[cfg(feature = "std")] + let sign = (1.0_{{ scalar_t }}).copysign(self.z); + #[cfg(not(feature = "std"))] + let sign = self.z.signum(); + let a = -1.0 / (sign + self.z); + let b = self.x * self.y * a; + Self::new(b, sign + self.y * self.y * a, -self.y) + } + + /// Given a unit-length vector return two other vectors that together form an orthonormal + /// basis. That is, all three vectors are orthogonal to each other and are normalized. + /// + /// # Panics + /// + /// Will panic if `self` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn any_orthonormal_pair(&self) -> (Self, Self) { + glam_assert!(self.is_normalized()); + // From https://graphics.pixar.com/library/OrthonormalB/paper.pdf + #[cfg(feature = "std")] + let sign = (1.0_{{ scalar_t }}).copysign(self.z); + #[cfg(not(feature = "std"))] + let sign = self.z.signum(); + let a = -1.0 / (sign + self.z); + let b = self.x * self.y * a; + ( + Self::new(1.0 + sign * self.x * self.x * a, sign * b, -sign * self.x), + Self::new(b, sign + self.y * self.y * a, -self.y), + ) + } +{% endif %} +{% endif %} + +{% if is_signed and dim == 2 %} + /// Returns a vector that is equal to `self` rotated by 90 degrees. + #[inline] + pub fn perp(self) -> Self { + Self { + x: -self.y, + y: self.x, + } + } + + /// The perpendicular dot product of `self` and `rhs`. + /// Also known as the wedge product, 2D cross product, and determinant. + #[doc(alias = "wedge")] + #[doc(alias = "cross")] + #[doc(alias = "determinant")] + #[inline] + pub fn perp_dot(self, rhs: Self) -> {{ scalar_t }} { + (self.x * rhs.y) - (self.y * rhs.x) + } + + /// Returns `rhs` rotated by the angle of `self`. If `self` is normalized, + /// then this just rotation. This is what you usually want. Otherwise, + /// it will be like a rotation with a multiplication by `self`'s length. + #[must_use] + #[inline] + pub fn rotate(self, rhs: Self) -> Self { + Self { + x: self.x * rhs.x - self.y * rhs.y, + y: self.y * rhs.x + self.x * rhs.y, + } + } +{% endif %} + +{% if scalar_t != "f32" %} + {% if dim == 2 %} + /// Casts all elements of `self` to `f32`. + #[inline] + pub fn as_vec2(&self) -> crate::Vec2 { + crate::Vec2::new(self.x as f32, self.y as f32) + } + {% elif dim == 3 %} + /// Casts all elements of `self` to `f32`. + #[inline] + pub fn as_vec3(&self) -> crate::Vec3 { + crate::Vec3::new(self.x as f32, self.y as f32, self.z as f32) + } + + /// Casts all elements of `self` to `f32`. + #[inline] + pub fn as_vec3a(&self) -> crate::Vec3A { + crate::Vec3A::new(self.x as f32, self.y as f32, self.z as f32) + } + {% elif dim == 4 %} + /// Casts all elements of `self` to `f32`. + #[inline] + pub fn as_vec4(&self) -> crate::Vec4 { + crate::Vec4::new(self.x as f32, self.y as f32, self.z as f32, self.w as f32) + } + {% endif %} +{% endif %} +{% if scalar_t != "f64" %} + {% if dim == 2 %} + /// Casts all elements of `self` to `f64`. + #[inline] + pub fn as_dvec2(&self) -> crate::DVec2 { + crate::DVec2::new(self.x as f64, self.y as f64) + } + {% elif dim == 3 %} + /// Casts all elements of `self` to `f64`. + #[inline] + pub fn as_dvec3(&self) -> crate::DVec3 { + crate::DVec3::new(self.x as f64, self.y as f64, self.z as f64) + } + {% elif dim == 4 %} + /// Casts all elements of `self` to `f64`. + #[inline] + pub fn as_dvec4(&self) -> crate::DVec4 { + crate::DVec4::new(self.x as f64, self.y as f64, self.z as f64, self.w as f64) + } + {% endif %} +{% endif %} +{% if scalar_t != "i32" %} + {% if dim == 2 %} + /// Casts all elements of `self` to `i32`. + #[inline] + pub fn as_ivec2(&self) -> crate::IVec2 { + crate::IVec2::new(self.x as i32, self.y as i32) + } + {% elif dim == 3 %} + /// Casts all elements of `self` to `i32`. + #[inline] + pub fn as_ivec3(&self) -> crate::IVec3 { + crate::IVec3::new(self.x as i32, self.y as i32, self.z as i32) + } + {% elif dim == 4 %} + /// Casts all elements of `self` to `i32`. + #[inline] + pub fn as_ivec4(&self) -> crate::IVec4 { + crate::IVec4::new(self.x as i32, self.y as i32, self.z as i32, self.w as i32) + } + {% endif %} +{% endif %} +{% if scalar_t != "u32" %} + {% if dim == 2 %} + /// Casts all elements of `self` to `u32`. + #[inline] + pub fn as_uvec2(&self) -> crate::UVec2 { + crate::UVec2::new(self.x as u32, self.y as u32) + } + {% elif dim == 3 %} + /// Casts all elements of `self` to `u32`. + #[inline] + pub fn as_uvec3(&self) -> crate::UVec3 { + crate::UVec3::new(self.x as u32, self.y as u32, self.z as u32) + } + {% elif dim == 4 %} + /// Casts all elements of `self` to `u32`. + #[inline] + pub fn as_uvec4(&self) -> crate::UVec4 { + crate::UVec4::new(self.x as u32, self.y as u32, self.z as u32, self.w as u32) + } + {% endif %} +{% endif %} +} + +impl Default for {{ self_t }} { + #[inline(always)] + fn default() -> Self { + Self::ZERO + } +} + +impl PartialEq for {{ self_t }} { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.cmpeq(*rhs).all() + } +} + +impl Div<{{ self_t }}> for {{ self_t }} { + type Output = Self; + #[inline] + fn div(self, rhs: Self) -> Self { + {% if is_scalar %} + Self { + {% for c in components %} + {{ c }}: self.{{ c }}.div(rhs.{{ c }}), + {%- endfor %} + } + {% elif is_sse2 %} + Self(unsafe { _mm_div_ps(self.0, rhs.0) }) + {% elif is_wasm32 %} + Self(f32x4_div(self.0, rhs.0)) + {% endif %} + } +} + +impl DivAssign<{{ self_t }}> for {{ self_t }} { + #[inline] + fn div_assign(&mut self, rhs: Self) { + {% if is_scalar %} + {% for c in components %} + self.{{ c }}.div_assign(rhs.{{ c }}); + {%- endfor %} + {% elif is_sse2 %} + self.0 = unsafe { _mm_div_ps(self.0, rhs.0) }; + {% elif is_wasm32 %} + self.0 = f32x4_div(self.0, rhs.0); + {% endif %} + } +} + +impl Div<{{ scalar_t }}> for {{ self_t }} { + type Output = Self; + #[inline] + fn div(self, rhs: {{ scalar_t }}) -> Self { + {% if is_scalar %} + Self { + {% for c in components %} + {{ c }}: self.{{ c }}.div(rhs), + {%- endfor %} + } + {% elif is_sse2 %} + Self(unsafe { _mm_div_ps(self.0, _mm_set1_ps(rhs)) }) + {% elif is_wasm32 %} + Self(f32x4_div(self.0, f32x4_splat(rhs))) + {% endif %} + } +} + +impl DivAssign<{{ scalar_t }}> for {{ self_t }} { + #[inline] + fn div_assign(&mut self, rhs: {{ scalar_t }}) { + {% if is_scalar %} + {% for c in components %} + self.{{ c }}.div_assign(rhs); + {%- endfor %} + {% elif is_sse2 %} + self.0 = unsafe { _mm_div_ps(self.0, _mm_set1_ps(rhs)) }; + {% elif is_wasm32 %} + self.0 = f32x4_div(self.0, f32x4_splat(rhs)) + {% endif %} + } +} + +impl Div<{{ self_t }}> for {{ scalar_t }} { + type Output = {{ self_t }}; + #[inline] + fn div(self, rhs: {{ self_t }}) -> {{ self_t }} { + {% if is_scalar %} + {{ self_t }} { + {% for c in components %} + {{ c }}: self.div(rhs.{{ c }}), + {%- endfor %} + } + {% elif is_sse2 %} + {{ self_t }}(unsafe { _mm_div_ps(_mm_set1_ps(self), rhs.0) }) + {% elif is_wasm32 %} + {{ self_t }}(f32x4_div(f32x4_splat(self), rhs.0)) + {% endif %} + } +} + +impl Mul<{{ self_t }}> for {{ self_t }} { + type Output = Self; + #[inline] + fn mul(self, rhs: Self) -> Self { + {% if is_scalar %} + Self { + {% for c in components %} + {{ c }}: self.{{ c }}.mul(rhs.{{ c }}), + {%- endfor %} + } + {% elif is_sse2 %} + Self(unsafe { _mm_mul_ps(self.0, rhs.0) }) + {% elif is_wasm32 %} + Self(f32x4_mul(self.0, rhs.0)) + {% endif %} + } +} + +impl MulAssign<{{ self_t }}> for {{ self_t }} { + #[inline] + fn mul_assign(&mut self, rhs: Self) { + {% if is_scalar %} + {% for c in components %} + self.{{ c }}.mul_assign(rhs.{{ c }}); + {%- endfor %} + {% elif is_sse2 %} + self.0 = unsafe { _mm_mul_ps(self.0, rhs.0) }; + {% elif is_wasm32 %} + self.0 = f32x4_mul(self.0, rhs.0); + {% endif %} + } +} + +impl Mul<{{ scalar_t }}> for {{ self_t }} { + type Output = Self; + #[inline] + fn mul(self, rhs: {{ scalar_t }}) -> Self { + {% if is_scalar %} + Self { + {% for c in components %} + {{ c }}: self.{{ c }}.mul(rhs), + {%- endfor %} + } + {% elif is_sse2 %} + Self(unsafe { _mm_mul_ps(self.0, _mm_set1_ps(rhs)) }) + {% elif is_wasm32 %} + Self(f32x4_mul(self.0, f32x4_splat(rhs))) + {% endif %} + } +} + +impl MulAssign<{{ scalar_t }}> for {{ self_t }} { + #[inline] + fn mul_assign(&mut self, rhs: {{ scalar_t }}) { + {% if is_scalar %} + {% for c in components %} + self.{{ c }}.mul_assign(rhs); + {%- endfor %} + {% elif is_sse2 %} + self.0 = unsafe { _mm_mul_ps(self.0, _mm_set1_ps(rhs)) }; + {% elif is_wasm32 %} + self.0 = f32x4_mul(self.0, f32x4_splat(rhs)) + {% endif %} + } +} + +impl Mul<{{ self_t }}> for {{ scalar_t }} { + type Output = {{ self_t }}; + #[inline] + fn mul(self, rhs: {{ self_t }}) -> {{ self_t }} { + {% if is_scalar %} + {{ self_t }} { + {% for c in components %} + {{ c }}: self.mul(rhs.{{ c }}), + {%- endfor %} + } + {% elif is_sse2 %} + {{ self_t }}(unsafe { _mm_mul_ps(_mm_set1_ps(self), rhs.0) }) + {% elif is_wasm32 %} + {{ self_t }}(f32x4_mul(f32x4_splat(self), rhs.0)) + {% endif %} + } +} + +impl Add<{{ self_t }}> for {{ self_t }} { + type Output = Self; + #[inline] + fn add(self, rhs: Self) -> Self { + {% if is_scalar %} + Self { + {% for c in components %} + {{ c }}: self.{{ c }}.add(rhs.{{ c }}), + {%- endfor %} + } + {% elif is_sse2 %} + Self(unsafe { _mm_add_ps(self.0, rhs.0) }) + {% elif is_wasm32 %} + Self(f32x4_add(self.0, rhs.0)) + {% endif %} + } +} + +impl AddAssign<{{ self_t }}> for {{ self_t }} { + #[inline] + fn add_assign(&mut self, rhs: Self) { + {% if is_scalar %} + {% for c in components %} + self.{{ c }}.add_assign(rhs.{{ c }}); + {%- endfor %} + {% elif is_sse2 %} + self.0 = unsafe { _mm_add_ps(self.0, rhs.0) }; + {% elif is_wasm32 %} + self.0 = f32x4_add(self.0, rhs.0); + {% endif %} + } +} + +impl Add<{{ scalar_t }}> for {{ self_t }} { + type Output = Self; + #[inline] + fn add(self, rhs: {{ scalar_t }}) -> Self { + {% if is_scalar %} + Self { + {% for c in components %} + {{ c }}: self.{{ c }}.add(rhs), + {%- endfor %} + } + {% elif is_sse2 %} + Self(unsafe { _mm_add_ps(self.0, _mm_set1_ps(rhs)) }) + {% elif is_wasm32 %} + Self(f32x4_add(self.0, f32x4_splat(rhs))) + {% endif %} + } +} + +impl AddAssign<{{ scalar_t }}> for {{ self_t }} { + #[inline] + fn add_assign(&mut self, rhs: {{ scalar_t }}) { + {% if is_scalar %} + {% for c in components %} + self.{{ c }}.add_assign(rhs); + {%- endfor %} + {% elif is_sse2 %} + self.0 = unsafe { _mm_add_ps(self.0, _mm_set1_ps(rhs)) }; + {% elif is_wasm32 %} + self.0 = f32x4_add(self.0, f32x4_splat(rhs)) + {% endif %} + } +} + +impl Add<{{ self_t }}> for {{ scalar_t }} { + type Output = {{ self_t }}; + #[inline] + fn add(self, rhs: {{ self_t }}) -> {{ self_t }} { + {% if is_scalar %} + {{ self_t }} { + {% for c in components %} + {{ c }}: self.add(rhs.{{ c }}), + {%- endfor %} + } + {% elif is_sse2 %} + {{ self_t }}(unsafe { _mm_add_ps(_mm_set1_ps(self), rhs.0) }) + {% elif is_wasm32 %} + {{ self_t }}(f32x4_add(f32x4_splat(self), rhs.0)) + {% endif %} + } +} + +impl Sub<{{ self_t }}> for {{ self_t }} { + type Output = Self; + #[inline] + fn sub(self, rhs: Self) -> Self { + {% if is_scalar %} + Self { + {% for c in components %} + {{ c }}: self.{{ c }}.sub(rhs.{{ c }}), + {%- endfor %} + } + {% elif is_sse2 %} + Self(unsafe { _mm_sub_ps(self.0, rhs.0) }) + {% elif is_wasm32 %} + Self(f32x4_sub(self.0, rhs.0)) + {% endif %} + } +} + +impl SubAssign<{{ self_t }}> for {{ self_t }} { + #[inline] + fn sub_assign(&mut self, rhs: {{ self_t }}) { + {% if is_scalar %} + {% for c in components %} + self.{{ c }}.sub_assign(rhs.{{ c }}); + {%- endfor %} + {% elif is_sse2 %} + self.0 = unsafe { _mm_sub_ps(self.0, rhs.0) }; + {% elif is_wasm32 %} + self.0 = f32x4_sub(self.0, rhs.0); + {% endif %} + } +} + +impl Sub<{{ scalar_t }}> for {{ self_t }} { + type Output = Self; + #[inline] + fn sub(self, rhs: {{ scalar_t }}) -> Self { + {% if is_scalar %} + Self { + {% for c in components %} + {{ c }}: self.{{ c }}.sub(rhs), + {%- endfor %} + } + {% elif is_sse2 %} + Self(unsafe { _mm_sub_ps(self.0, _mm_set1_ps(rhs)) }) + {% elif is_wasm32 %} + Self(f32x4_sub(self.0, f32x4_splat(rhs))) + {% endif %} + } +} + +impl SubAssign<{{ scalar_t }}> for {{ self_t }} { + #[inline] + fn sub_assign(&mut self, rhs: {{ scalar_t }}) { + {% if is_scalar %} + {% for c in components %} + self.{{ c }}.sub_assign(rhs); + {%- endfor %} + {% elif is_sse2 %} + self.0 = unsafe { _mm_sub_ps(self.0, _mm_set1_ps(rhs)) }; + {% elif is_wasm32 %} + self.0 = f32x4_sub(self.0, f32x4_splat(rhs)) + {% endif %} + } +} + +impl Sub<{{ self_t }}> for {{ scalar_t }} { + type Output = {{ self_t }}; + #[inline] + fn sub(self, rhs: {{ self_t }}) -> {{ self_t }} { + {% if is_scalar %} + {{ self_t }} { + {% for c in components %} + {{ c }}: self.sub(rhs.{{ c }}), + {%- endfor %} + } + {% elif is_sse2 %} + {{ self_t }}(unsafe { _mm_sub_ps(_mm_set1_ps(self), rhs.0) }) + {% elif is_wasm32 %} + {{ self_t }}(f32x4_sub(f32x4_splat(self), rhs.0)) + {% endif %} + } +} + +impl Rem<{{ self_t }}> for {{ self_t }} { + type Output = Self; + #[inline] + fn rem(self, rhs: Self) -> Self { + {% if is_scalar %} + Self { + {% for c in components %} + {{ c }}: self.{{ c }}.rem(rhs.{{ c }}), + {%- endfor %} + } + {% elif is_sse2 %} + unsafe { + let n = crate::sse2::m128_floor(_mm_div_ps(self.0, rhs.0)); + Self(_mm_sub_ps(self.0, _mm_mul_ps(n, rhs.0))) + } + {% elif is_wasm32 %} + let n = f32x4_floor(f32x4_div(self.0, rhs.0)); + Self(f32x4_sub(self.0, f32x4_mul(n, rhs.0))) + {% endif %} + } +} + +impl RemAssign<{{ self_t }}> for {{ self_t }} { + #[inline] + fn rem_assign(&mut self, rhs: Self) { + {% if is_scalar %} + {% for c in components %} + self.{{ c }}.rem_assign(rhs.{{ c }}); + {%- endfor %} + {% else %} + *self = self.rem(rhs); + {% endif %} + } +} + +impl Rem<{{ scalar_t }}> for {{ self_t }} { + type Output = Self; + #[inline] + fn rem(self, rhs: {{ scalar_t }}) -> Self { + {% if is_scalar %} + Self { + {% for c in components %} + {{ c }}: self.{{ c }}.rem(rhs), + {%- endfor %} + } + {% else %} + self.rem(Self::splat(rhs)) + {% endif %} + } +} + +impl RemAssign<{{ scalar_t }}> for {{ self_t }} { + #[inline] + fn rem_assign(&mut self, rhs: {{ scalar_t }}) { + {% if is_scalar %} + {% for c in components %} + self.{{ c }}.rem_assign(rhs); + {%- endfor %} + {% else %} + *self = self.rem(Self::splat(rhs)); + {% endif %} + } +} + +impl Rem<{{ self_t }}> for {{ scalar_t }} { + type Output = {{ self_t }}; + #[inline] + fn rem(self, rhs: {{ self_t }}) -> {{ self_t }} { + {% if is_scalar %} + {{ self_t }} { + {% for c in components %} + {{ c }}: self.rem(rhs.{{ c }}), + {%- endfor %} + } + {% else %} + {{ self_t }}::splat(self).rem(rhs) + {% endif %} + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsRef<[{{ scalar_t }}; {{ dim }}]> for {{ self_t }} { + #[inline] + fn as_ref(&self) -> &[{{ scalar_t }}; {{ dim }}] { + unsafe { &*(self as *const {{ self_t }} as *const [{{ scalar_t }}; {{ dim }}]) } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsMut<[{{ scalar_t }}; {{ dim }}]> for {{ self_t }} { + #[inline] + fn as_mut(&mut self) -> &mut [{{ scalar_t }}; {{ dim }}] { + unsafe { &mut *(self as *mut {{ self_t }} as *mut [{{ scalar_t }}; {{ dim }}]) } + } +} + +impl<'a> Sum<&'a Self> for {{ self_t }} { + #[inline] + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, |a, &b| Self::add(a, b)) + } +} + +impl<'a> Product<&'a Self> for {{ self_t }} { + #[inline] + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ONE, |a, &b| Self::mul(a, b)) + } +} + +{% if is_signed %} +impl Neg for {{ self_t }} { + type Output = Self; + #[inline] + fn neg(self) -> Self { + {% if is_scalar %} + Self { + {% for c in components %} + {{ c }}: self.{{ c }}.neg(), + {%- endfor %} + } + {% elif is_sse2 %} + Self(unsafe { _mm_sub_ps(Self::ZERO.0, self.0) }) + {% elif is_wasm32 %} + Self(f32x4_neg(self.0)) + {% endif %} + } +} +{% endif %} + +{% if not is_float %} +impl Eq for {{ self_t }} {} + +#[cfg(not(target_arch = "spirv"))] +impl core::hash::Hash for {{ self_t }} { + fn hash(&self, state: &mut H) { + let inner: &[{{ scalar_t }}; {{ dim }}] = self.as_ref(); + inner.hash(state); + } +} + +impl Not for {{ self_t }} { + type Output = Self; + #[inline] + fn not(self) -> Self::Output { + Self { + {% for c in components %} + {{ c }}: self.{{ c }}.not(), + {%- endfor %} + } + } +} + +impl BitAnd for {{ self_t }} { + type Output = Self; + #[inline] + fn bitand(self, rhs: Self) -> Self::Output { + Self { + {% for c in components %} + {{ c }}: self.{{ c }}.bitand(rhs.{{ c }}), + {%- endfor %} + } + } +} + +impl BitOr for {{ self_t }} { + type Output = Self; + #[inline] + fn bitor(self, rhs: Self) -> Self::Output { + Self { + {% for c in components %} + {{ c }}: self.{{ c }}.bitor(rhs.{{ c }}), + {%- endfor %} + } + } +} + +impl BitXor for {{ self_t }} { + type Output = Self; + #[inline] + fn bitxor(self, rhs: Self) -> Self::Output { + Self { + {% for c in components %} + {{ c }}: self.{{ c }}.bitxor(rhs.{{ c }}), + {%- endfor %} + } + } +} + +impl BitAnd<{{ scalar_t }}> for {{ self_t }} { + type Output = Self; + #[inline] + fn bitand(self, rhs: {{ scalar_t }}) -> Self::Output { + Self { + {% for c in components %} + {{ c }}: self.{{ c }}.bitand(rhs), + {%- endfor %} + } + } +} + +impl BitOr<{{ scalar_t }}> for {{ self_t }} { + type Output = Self; + #[inline] + fn bitor(self, rhs: {{ scalar_t }}) -> Self::Output { + Self { + {% for c in components %} + {{ c }}: self.{{ c }}.bitor(rhs), + {%- endfor %} + } + } +} + +impl BitXor<{{ scalar_t }}> for {{ self_t }} { + type Output = Self; + #[inline] + fn bitxor(self, rhs: {{ scalar_t }}) -> Self::Output { + Self { + {% for c in components %} + {{ c }}: self.{{ c }}.bitxor(rhs), + {%- endfor %} + } + } +} + +{% for rhs_t in ["i8", "i16", "i32", "u8", "u16", "u32"] %} + impl Shl<{{ rhs_t }}> for {{ self_t }} { + type Output = Self; + #[inline] + fn shl(self, rhs: {{ rhs_t }}) -> Self::Output { + Self { + {% for c in components %} + {{ c }}: self.{{ c }}.shl(rhs), + {%- endfor %} + } + } + } + + impl Shr<{{ rhs_t }}> for {{ self_t }} { + type Output = Self; + #[inline] + fn shr(self, rhs: {{ rhs_t }}) -> Self::Output { + Self { + {% for c in components %} + {{ c }}: self.{{ c }}.shr(rhs), + {%- endfor %} + } + } + } +{% endfor %} + +{% for rhs_t in ["crate::IVec" ~ dim, "crate::UVec" ~ dim] %} + impl Shl<{{ rhs_t }}> for {{ self_t }} { + type Output = Self; + #[inline] + fn shl(self, rhs: {{ rhs_t }}) -> Self::Output { + Self { + {% for c in components %} + {{ c }}: self.{{ c }}.shl(rhs.{{ c }}), + {%- endfor %} + } + } + } + + impl Shr<{{ rhs_t }}> for {{ self_t }} { + type Output = Self; + #[inline] + fn shr(self, rhs: {{ rhs_t }}) -> Self::Output { + Self { + {% for c in components %} + {{ c }}: self.{{ c }}.shr(rhs.{{ c }}), + {%- endfor %} + } + } + } +{% endfor %} +{% endif %} + +impl Index for {{ self_t }} { + type Output = {{ scalar_t }}; + #[inline] + fn index(&self, index: usize) -> &Self::Output { + match index { + {% for c in components %} + {{ loop.index0 }} => &self.{{ c }}, + {%- endfor %} + _ => panic!("index out of bounds"), + } + } +} + +impl IndexMut for {{ self_t }} { + #[inline] + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + match index { + {% for c in components %} + {{ loop.index0 }} => &mut self.{{ c }}, + {%- endfor %} + _ => panic!("index out of bounds"), + } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Display for {{ self_t }} { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + {% if dim == 2 %} + write!(f, "[{}, {}]", self.x, self.y) + {% elif dim == 3 %} + write!(f, "[{}, {}, {}]", self.x, self.y, self.z) + {% elif dim == 4 %} + write!(f, "[{}, {}, {}, {}]", self.x, self.y, self.z, self.w) + {% endif %} + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Debug for {{ self_t }} { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_tuple(stringify!({{ self_t }})) + {% for c in components %} + .field(&self.{{ c }}) + {% endfor %} + .finish() + } +} + +{% if not is_scalar %} +impl From<{{ self_t }}> for {{ simd_t }} { + #[inline] + fn from(t: {{ self_t }}) -> Self { + t.0 + } +} + +impl From<{{ simd_t }}> for {{ self_t }} { + #[inline] + fn from(t: {{ simd_t }}) -> Self { + Self(t) + } +} +{% endif %} + +impl From<[{{ scalar_t }}; {{ dim }}]> for {{ self_t }} { + #[inline] + fn from(a: [{{ scalar_t }}; {{ dim }}]) -> Self { + {% if self_t == "Vec4" and is_sse2 %} + Self(unsafe { _mm_loadu_ps(a.as_ptr()) }) + {% else %} + Self::new( + {% for c in components %} + a[{{ loop.index0 }}], + {%- endfor %} + ) + {% endif %} + } +} + +impl From<{{ self_t }}> for [{{ scalar_t }}; {{ dim }}] { + #[inline] + fn from(v: {{ self_t }}) -> Self { + {% if is_scalar %} + [ + {% for c in components %} + v.{{ c }}, + {%- endfor %} + ] + {% elif is_sse2 %} + use core::mem::MaybeUninit; + use crate::Align16; + let mut out: MaybeUninit> = MaybeUninit::uninit(); + unsafe { + _mm_store_ps(out.as_mut_ptr().cast(), v.0); + out.assume_init().0 + } + {% elif is_wasm32 %} + // TODO: can probably simplify this? + use core::mem::MaybeUninit; + let mut out: MaybeUninit = MaybeUninit::uninit(); + unsafe { + v128_store(out.as_mut_ptr(), v.0); + *(&out.assume_init() as *const v128 as *const [f32; {{ dim }}]) + } + {% endif %} + } +} + +impl From<{{ macros::make_tuple_t(t=scalar_t, n=dim) }}> for {{ self_t }} { + #[inline] + fn from(t: {{ macros::make_tuple_t(t=scalar_t, n=dim) }}) -> Self { + Self::new( + {% for c in components %} + t.{{ loop.index0 }}, + {%- endfor %} + ) + } +} + +impl From<{{ self_t }}> for {{ macros::make_tuple_t(t=scalar_t, n=dim) }} { + #[inline] + fn from(v: {{ self_t }}) -> Self { + {% if is_scalar %} + ( + {% for c in components %} + v.{{ c }}, + {%- endfor %} + ) + {% elif is_sse2 %} + use core::mem::MaybeUninit; + use crate::Align16; + let mut out: MaybeUninit> = MaybeUninit::uninit(); + unsafe { + _mm_store_ps(out.as_mut_ptr().cast(), v.0); + out.assume_init().0 + } + {% elif is_wasm32 %} + // TODO: can probably simplify this + use core::mem::MaybeUninit; + let mut out: MaybeUninit = MaybeUninit::uninit(); + unsafe { + v128_store(out.as_mut_ptr(), v.0); + *(&out.assume_init() as *const v128 as *const Self) + } + {% endif %} + } +} + +{% if self_t == "Vec3A" %} +impl From for Vec3A { + #[inline] + fn from(v: Vec3) -> Self { + Self::new(v.x, v.y, v.z) + } +} + +impl From for Vec3A { + /// Creates a `Vec3A` from the `x`, `y` and `z` elements of `self` discarding `w`. + /// + /// On architectures where SIMD is supported such as SSE2 on `x86_64` this conversion is a noop. + #[inline] + fn from(v: Vec4) -> Self { + {% if is_scalar %} + Self { + x: v.x, + y: v.y, + z: v.z, + } + {% else %} + Self(v.0) + {% endif %} + } +} +{% elif self_t == "Vec3" %} +impl From for Vec3 { + #[inline] + fn from(v: Vec3A) -> Self { + Self { + x: v.x, + y: v.y, + z: v.z, + } + } +} +{% elif self_t == "Vec4" %} +impl From<(Vec3A, f32)> for Vec4 { + #[inline] + fn from((v, w): (Vec3A, f32)) -> Self { + v.extend(w) + } +} + +impl From<(f32, Vec3A)> for Vec4 { + #[inline] + fn from((x, v): (f32, Vec3A)) -> Self { + Self::new(x, v.x, v.y, v.z) + } +} +{% endif %} + +{% if dim == 3 %} +impl From<({{ vec2_t }}, {{ scalar_t }})> for {{ self_t }} { + #[inline] + fn from((v, z): ({{ vec2_t }}, {{ scalar_t }})) -> Self { + Self::new(v.x, v.y, z) + } +} +{% elif dim == 4 %} +impl From<({{ vec3_t }}, {{ scalar_t }})> for {{ self_t }} { + #[inline] + fn from((v, w): ({{ vec3_t }}, {{ scalar_t }})) -> Self { + Self::new(v.x, v.y, v.z, w) + } +} + +impl From<({{ scalar_t }}, {{ vec3_t }})> for {{ self_t }} { + #[inline] + fn from((x, v): ({{ scalar_t }}, {{ vec3_t }})) -> Self { + Self::new(x, v.x, v.y, v.z) + } +} + +impl From<({{ vec2_t }}, {{ scalar_t }}, {{ scalar_t }})> for {{ self_t }} { + #[inline] + fn from((v, z, w): ({{ vec2_t }}, {{ scalar_t }}, {{ scalar_t }})) -> Self { + Self::new(v.x, v.y, z, w) + } +} + +impl From<({{ vec2_t }}, {{ vec2_t }})> for {{ self_t }} { + #[inline] + fn from((v, u): ({{ vec2_t }}, {{ vec2_t }})) -> Self { + Self::new(v.x, v.y, u.x, u.y) + } +} +{% endif %} + +{% if not is_scalar %} +impl Deref for {{ self_t }} { + type Target = crate::deref::{{ deref_t }}; + #[inline] + fn deref(&self) -> &Self::Target { + unsafe { &*(self as *const Self).cast() } + } +} + +impl DerefMut for {{ self_t }} { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { &mut *(self as *mut Self).cast() } + } +} +{% endif %} diff --git a/codegen/templates/vec_mask.rs b/codegen/templates/vec_mask.rs new file mode 100644 index 00000000..53cea34e --- /dev/null +++ b/codegen/templates/vec_mask.rs @@ -0,0 +1,369 @@ +// Generated from {{template_path}} template. Edit the template, not the generated file. + +{% if is_scalar %} + {% set self_t = "BVec" ~ dim %} + {% set scalar_t = "bool" %} + {% set align = 1 %} +{% else %} + {% set self_t = "BVec" ~ dim ~ "A" %} + {% set scalar_t = "u32" %} + {% set align = 16 %} + {% if is_sse2 %} + {% set simd_t = "__m128" %} + {% elif is_wasm32 %} + {% set simd_t = "v128" %} + {% endif %} +{% endif %} + +{% set components = ["x", "y", "z", "w"] | slice(end = dim) %} + +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::{hash, ops::*}; + +{% if is_sse2 %} +#[cfg(target_arch = "x86")] +use core::arch::x86::*; +#[cfg(target_arch = "x86_64")] +use core::arch::x86_64::*; +{% elif is_wasm32 %} +use core::arch::wasm32::*; +{% endif %} + +{% if is_sse2 %} +union UnionCast { + a: [u32; 4], + v: {{ self_t }} +} +{% endif %} + +{% if is_scalar %} +/// A {{ dim }}-dimensional boolean vector. +{%- else %} +/// A {{ dim }}-dimensional SIMD vector mask. +/// +/// This type is {{ align }} byte aligned and is backed by a SIMD vector. If SIMD is not available +/// `{{ self_t }}` will be a type alias for `BVec{{ dim }}`. +{%- endif %} +#[derive(Clone, Copy)] +{%- if is_scalar %} +pub struct {{ self_t }} +{ +{% for c in components %} + pub {{ c }}: bool, +{%- endfor %} +} +{%- else %} +#[repr(transparent)] +pub struct {{ self_t }}(pub(crate) {{ simd_t }}); +{% endif %} + +const MASK: [u32; 2] = [0, 0xff_ff_ff_ff]; + +const FALSE: {{ self_t }} = {{ self_t }}::new( + {% for c in components %} + false, + {%- endfor %} +); + +impl {{ self_t }} { + + /// Creates a new vector mask. + #[inline(always)] + pub const fn new( + {% for c in components %} + {{ c }}: bool, + {% endfor %} + ) -> Self { + {% if is_scalar %} + Self { + {% for c in components %} + {{ c }}, + {%- endfor %} + } + {% elif is_sse2 %} + unsafe { + UnionCast { a: [ + MASK[x as usize], + MASK[y as usize], + MASK[z as usize], + {% if dim == 3 %} + 0, + {% elif dim == 4 %} + MASK[w as usize], + {% endif %} + ] }.v + } + {% elif is_wasm32 %} + Self(u32x4( + MASK[x as usize], + MASK[y as usize], + MASK[z as usize], + {% if dim == 3 %} + 0, + {% elif dim == 4 %} + MASK[w as usize], + {% endif %} + )) + {% endif %} + } + + /// Returns a bitmask with the lowest two bits set from the elements of `self`. + /// + /// A true element results in a `1` bit and a false element in a `0` bit. Element `x` goes + /// into the first lowest bit, element `y` into the second, etc. + #[inline] + pub fn bitmask(self) -> u32 { + {% if is_scalar %} + {% for c in components %} + {% if loop.first %} + (self.{{ c }} as u32) | + {% else %} + (self.{{ c }} as u32) << {{ loop.index0 }} {% if not loop.last %} | {% endif %} + {% endif %} + {% endfor %} + {% elif is_sse2 %} + {% if dim == 3 %} + unsafe { (_mm_movemask_ps(self.0) as u32) & 0x7 } + {% elif dim == 4 %} + unsafe { _mm_movemask_ps(self.0) as u32 } + {% endif %} + {% elif is_wasm32 %} + {% if dim == 3 %} + (u32x4_bitmask(self.0) & 0x7) as u32 + {% elif dim == 4 %} + u32x4_bitmask(self.0) as u32 + {% endif %} + {% endif %} + } + + /// Returns true if any of the elements are true, false otherwise. + #[inline] + pub fn any(self) -> bool { + {% if is_scalar %} + {% for c in components %} + self.{{ c }} {% if not loop.last %} || {% endif %} + {%- endfor %} + {% elif is_sse2 %} + {% if dim == 3 %} + unsafe { (_mm_movemask_ps(self.0) & 0x7) != 0 } + {% elif dim == 4 %} + unsafe { _mm_movemask_ps(self.0) != 0 } + {% endif %} + {% elif is_wasm32 %} + {% if dim == 3 %} + (u32x4_bitmask(self.0) & 0x7) != 0 + {% elif dim == 4 %} + u32x4_bitmask(self.0) != 0 + {% endif %} + {% endif %} + } + + /// Returns true if all the elements are true, false otherwise. + #[inline] + pub fn all(self) -> bool { + {% if is_scalar %} + {% for c in components %} + self.{{ c }} {% if not loop.last %} && {% endif %} + {%- endfor %} + {% elif is_sse2 %} + {% if dim == 3 %} + unsafe { (_mm_movemask_ps(self.0) & 0x7) == 0x7 } + {% elif dim == 4 %} + unsafe { _mm_movemask_ps(self.0) == 0xf } + {% endif %} + {% elif is_wasm32 %} + {% if dim == 3 %} + (u32x4_bitmask(self.0) & 0x7) == 0x7 + {% elif dim == 4 %} + u32x4_bitmask(self.0) == 0xf + {% endif %} + {% endif %} + } + + #[inline] + fn into_bool_array(self) -> [bool; {{ dim }}] { + {% if is_scalar %} + [ + {% for c in components %} + self.{{ c }}, + {%- endfor %} + ] + {% else %} + {% set bits = [1, 2, 4, 8] | slice(end = dim) %} + let bitmask = self.bitmask(); + [ + {% for b in bits %} + (bitmask & {{ b }}) != 0, + {%- endfor %} + ] + {% endif %} + } + + #[inline] + fn into_u32_array(self) -> [u32; {{ dim }}] { + {% if is_scalar %} + [ + {% for c in components %} + MASK[self.{{ c }} as usize], + {%- endfor %} + ] + {% else %} + let bitmask = self.bitmask(); + [ + {% for c in components %} + {% if loop.first %} + MASK[(bitmask & 1) as usize], + {% else %} + MASK[((bitmask >> {{ loop.index0 }}) & 1) as usize], + {% endif %} + {%- endfor %} + ] + {% endif %} + } +} + + +impl Default for {{ self_t }} { + #[inline] + fn default() -> Self { + FALSE + } +} + +impl PartialEq for {{ self_t }} { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.bitmask().eq(&rhs.bitmask()) + } +} + +impl Eq for {{ self_t }} {} + +impl hash::Hash for {{ self_t }} { + #[inline] + fn hash(&self, state: &mut H) { + self.bitmask().hash(state); + } +} + +impl BitAnd for {{ self_t }} { + type Output = Self; + #[inline] + fn bitand(self, rhs: Self) -> Self { + {% if is_scalar %} + Self { + {% for c in components %} + {{ c }}: self.{{ c }} && rhs.{{ c }}, + {%- endfor %} + } + {% elif is_sse2 %} + Self(unsafe { _mm_and_ps(self.0, rhs.0) }) + {% elif is_wasm32 %} + Self(v128_and(self.0, rhs.0)) + {% endif %} + } +} + +impl BitAndAssign for {{ self_t }} { + #[inline] + fn bitand_assign(&mut self, rhs: Self) { + *self = self.bitand(rhs); + } +} + +impl BitOr for {{ self_t }} { + type Output = Self; + #[inline] + fn bitor(self, rhs: Self) -> Self { + {% if is_scalar %} + Self { + {% for c in components %} + {{ c }}: self.{{ c }} || rhs.{{ c }}, + {%- endfor %} + } + {% elif is_sse2 %} + Self(unsafe { _mm_or_ps(self.0, rhs.0) }) + {% elif is_wasm32 %} + Self(v128_or(self.0, rhs.0)) + {% endif %} + } +} + +impl BitOrAssign for {{ self_t }} { + #[inline] + fn bitor_assign(&mut self, rhs: Self) { + *self = self.bitor(rhs); + } +} + +impl Not for {{ self_t }} { + type Output = Self; + #[inline] + fn not(self) -> Self { + {% if is_scalar %} + Self { + {% for c in components %} + {{ c }}: !self.{{ c }}, + {%- endfor %} + } + {% elif is_sse2 %} + Self(unsafe { + _mm_andnot_ps(self.0, _mm_set_ps1(f32::from_bits(0xff_ff_ff_ff))) + }) + {% elif is_wasm32 %} + Self(v128_not(self.0)) + {% endif %} + } +} + +{% if not is_scalar %} +impl From<{{ self_t }}> for {{ simd_t }} { + #[inline] + fn from(t: {{ self_t }}) -> Self { + t.0 + } +} +{% endif %} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Debug for {{ self_t }} { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let arr = self.into_u32_array(); +{%- if dim == 2 %} + write!(f, "{}({:#x}, {:#x})", stringify!({{ self_t }}), arr[0], arr[1]) +{% elif dim == 3 %} + write!(f, "{}({:#x}, {:#x}, {:#x})", stringify!({{ self_t }}), arr[0], arr[1], arr[2]) +{% elif dim == 4 %} + write!(f, "{}({:#x}, {:#x}, {:#x}, {:#x})", stringify!({{ self_t }}), arr[0], arr[1], arr[2], arr[3]) +{% endif %} + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Display for {{ self_t }} { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let arr = self.into_bool_array(); +{%- if dim == 2 %} + write!(f, "[{}, {}]", arr[0], arr[1]) +{% elif dim == 3 %} + write!(f, "[{}, {}, {}]", arr[0], arr[1], arr[2]) +{% elif dim == 4 %} + write!(f, "[{}, {}, {}, {}]", arr[0], arr[1], arr[2], arr[3]) +{% endif %} + } +} + +impl From<{{ self_t }}> for [bool; {{ dim }}] { + #[inline] + fn from(mask: {{ self_t }}) -> Self { + mask.into_bool_array() + } +} + +impl From<{{ self_t }}> for [u32; {{ dim }}] { + #[inline] + fn from(mask: {{ self_t }}) -> Self { + mask.into_u32_array() + } +} diff --git a/src/affine2.rs b/src/affine2.rs deleted file mode 100644 index f3b9e3b6..00000000 --- a/src/affine2.rs +++ /dev/null @@ -1,519 +0,0 @@ -use crate::core::storage::Columns3; -use crate::{DMat2, DMat3, DVec2, Mat2, Mat3, Mat3A, Vec2, Vec3A}; -use core::ops::{Add, Deref, DerefMut, Mul, Sub}; - -#[cfg(not(feature = "std"))] -use num_traits::Float; - -macro_rules! define_affine2_struct { - ($affine2:ident, $matrix:ident, $column:ident) => { - /// A 2D affine transform, which can represent translation, rotation, scaling and shear. - #[derive(Copy, Clone)] - #[repr(C)] - pub struct $affine2 { - pub matrix2: $matrix, - pub translation: $column, - } - }; -} - -macro_rules! impl_affine2_methods { - ($t:ty, $mat2:ident, $mat3:ident, $vec2:ident, $affine2:ident, $matrix:ident, $column:ident) => { - impl $affine2 { - /// The degenerate zero transform. - /// - /// This transforms any finite vector and point to zero. - /// The zero transform is non-invertible. - pub const ZERO: Self = Self { - matrix2: $matrix::ZERO, - translation: $column::ZERO, - }; - - /// The identity transform. - /// - /// Multiplying a vector with this returns the same vector. - pub const IDENTITY: Self = Self { - matrix2: $matrix::IDENTITY, - translation: $column::ZERO, - }; - - /// All NAN:s. - pub const NAN: Self = Self { - matrix2: $matrix::NAN, - translation: $column::NAN, - }; - - /// Creates an affine transform from three column vectors. - #[inline(always)] - pub fn from_cols(x_axis: $column, y_axis: $column, z_axis: $column) -> Self { - Self { - matrix2: $matrix::from_cols(x_axis, y_axis), - translation: z_axis, - } - } - - /// Creates an affine transform from a `[S; 6]` array stored in column major order. - /// If your data is stored in row major you will need to `transpose` the returned - /// matrix. - #[inline(always)] - pub fn from_cols_array(m: &[$t; 6]) -> Self { - Self { - matrix2: $matrix::from_cols_slice(&m[0..4]), - translation: $column::from_slice(&m[4..6]), - } - } - - /// Creates a `[S; 6]` array storing data in column major order. - /// If you require data in row major order `transpose` the matrix first. - #[inline(always)] - pub fn to_cols_array(&self) -> [$t; 6] { - let x = &self.matrix2.x_axis; - let y = &self.matrix2.y_axis; - let z = &self.translation; - [x.x, x.y, y.x, y.y, z.x, z.y] - } - - /// Creates an affine transform from a `[[S; 2]; 3]` 2D array stored in column major order. - /// If your data is in row major order you will need to `transpose` the returned - /// matrix. - #[inline(always)] - pub fn from_cols_array_2d(m: &[[$t; 2]; 3]) -> Self { - Self { - matrix2: $matrix::from_cols(m[0].into(), m[1].into()), - translation: m[2].into(), - } - } - - /// Creates a `[[S; 2]; 3]` 2D array storing data in column major order. - /// If you require data in row major order `transpose` the matrix first. - #[inline(always)] - pub fn to_cols_array_2d(&self) -> [[$t; 2]; 3] { - [ - self.matrix2.x_axis.into(), - self.matrix2.y_axis.into(), - self.translation.into(), - ] - } - - /// Creates an affine transform from the first 6 values in `slice`. - /// - /// # Panics - /// - /// Panics if `slice` is less than 6 elements long. - #[inline(always)] - pub fn from_cols_slice(slice: &[$t]) -> Self { - Self { - matrix2: $matrix::from_cols_slice(&slice[0..4]), - translation: $column::from_slice(&slice[4..6]), - } - } - - /// Writes the columns of `self` to the first 12 elements in `slice`. - /// - /// # Panics - /// - /// Panics if `slice` is less than 12 elements long. - #[inline(always)] - pub fn write_cols_to_slice(self, slice: &mut [$t]) { - self.matrix2.write_cols_to_slice(&mut slice[0..4]); - self.translation.write_to_slice(&mut slice[4..6]); - } - - /// Creates an affine transform that changes scale. - /// Note that if any scale is zero the transform will be non-invertible. - #[inline(always)] - pub fn from_scale(scale: $vec2) -> Self { - Self { - matrix2: $matrix::from_diagonal(scale), - translation: $column::ZERO, - } - } - - /// Creates an affine transform from the given rotation `angle`. - #[inline(always)] - pub fn from_angle(angle: $t) -> Self { - Self { - matrix2: $matrix::from_angle(angle), - translation: $column::ZERO, - } - } - - /// Creates an affine transformation from the given 2D `translation`. - #[inline(always)] - pub fn from_translation(translation: $vec2) -> Self { - Self { - matrix2: $matrix::IDENTITY, - translation, - } - } - - /// Creates an affine transform from a 2x2 matrix (expressing scale, shear and - /// rotation) - #[inline(always)] - pub fn from_mat2(matrix2: $mat2) -> Self { - Self { - matrix2, - translation: $column::ZERO, - } - } - - /// Creates an affine transform from a 2x2 matrix (expressing scale, shear and rotation) - /// and a translation vector. - /// - /// Equivalent to `Affine2::from_translation(translation) * Affine2::from_mat2(mat2)` - #[inline(always)] - pub fn from_mat2_translation(matrix2: $mat2, translation: $vec2) -> Self { - Self { - matrix2, - translation, - } - } - - /// Creates an affine transform from the given 2D `scale`, rotation `angle` (in - /// radians) and `translation`. - /// - /// Equivalent to `Affine2::from_translation(translation) * - /// Affine2::from_angle(angle) * Affine2::from_scale(scale)` - #[inline] - pub fn from_scale_angle_translation( - scale: $vec2, - angle: $t, - translation: $vec2, - ) -> Self { - let rotation = $matrix::from_angle(angle); - Self { - matrix2: $matrix::from_cols( - rotation.x_axis * scale.x, - rotation.y_axis * scale.y, - ), - translation, - } - } - - /// Creates an affine transform from the given 2D rotation `angle` (in radians) and - /// `translation`. - /// - /// Equivalent to `Affine2::from_translation(translation) * Affine2::from_angle(angle)` - #[inline(always)] - pub fn from_angle_translation(angle: $t, translation: $vec2) -> Self { - Self { - matrix2: $matrix::from_angle(angle), - translation, - } - } - - /// The given `Mat3` must be an affine transform, - #[inline] - pub fn from_mat3(m: $mat3) -> Self { - Self { - matrix2: $matrix::from_cols($vec2(m.x_axis.0.into()), $vec2(m.y_axis.0.into())), - translation: $vec2(m.z_axis.0.into()), - } - } - - /// Transforms the given 2D point, applying shear, scale, rotation and translation. - #[inline(always)] - pub fn transform_point2(&self, other: $vec2) -> $vec2 { - self.matrix2 * other + self.translation - } - - /// Transforms the given 2D vector, applying shear, scale and rotation (but NOT - /// translation). - /// - /// To also apply translation, use [`Self::transform_point2`] instead. - #[inline(always)] - pub fn transform_vector2(&self, other: $vec2) -> $vec2 { - self.matrix2 * other - } - - /// Returns `true` if, and only if, all elements are finite. - /// - /// If any element is either `NaN`, positive or negative infinity, this will return - /// `false`. - #[inline] - pub fn is_finite(&self) -> bool { - self.matrix2.is_finite() && self.translation.is_finite() - } - - /// Returns `true` if any elements are `NaN`. - #[inline] - pub fn is_nan(&self) -> bool { - self.matrix2.is_nan() || self.translation.is_nan() - } - - /// Returns true if the absolute difference of all elements between `self` and `other` - /// is less than or equal to `max_abs_diff`. - /// - /// This can be used to compare if two 3x4 matrices contain similar elements. It works - /// best when comparing with a known value. The `max_abs_diff` that should be used used - /// depends on the values being compared against. - /// - /// For more see - /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/). - #[inline] - pub fn abs_diff_eq(&self, other: Self, max_abs_diff: $t) -> bool { - self.matrix2.abs_diff_eq(&other.matrix2, max_abs_diff) - && self - .translation - .abs_diff_eq(other.translation, max_abs_diff) - } - - /// Return the inverse of this transform. - /// - /// Note that if the transform is not invertible the result will be invalid. - #[must_use] - #[inline] - pub fn inverse(&self) -> Self { - let matrix2 = self.matrix2.inverse(); - // transform negative translation by the 2x2 inverse: - let translation = -(matrix2 * self.translation); - - Self { - matrix2, - translation, - } - } - } - }; -} - -macro_rules! impl_affine2_traits { - ($t:ty, $mat2:ident, $mat3:ident, $vec2:ident, $affine2:ident, $matrix:ident, $column:ident, $deref:ident) => { - impl Default for $affine2 { - #[inline(always)] - fn default() -> Self { - Self::IDENTITY - } - } - - impl Deref for $affine2 { - type Target = $deref; - #[inline(always)] - fn deref(&self) -> &Self::Target { - unsafe { &*(self as *const Self as *const Self::Target) } - } - } - - impl DerefMut for $affine2 { - #[inline(always)] - fn deref_mut(&mut self) -> &mut Self::Target { - unsafe { &mut *(self as *mut Self as *mut Self::Target) } - } - } - - impl PartialEq for $affine2 { - #[inline] - fn eq(&self, other: &Self) -> bool { - self.matrix2.eq(&other.matrix2) && self.translation.eq(&other.translation) - } - } - - #[cfg(not(target_arch = "spirv"))] - impl core::fmt::Debug for $affine2 { - fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - fmt.debug_struct(stringify!($affine2)) - .field("matrix2", &self.matrix2) - .field("translation", &self.translation) - .finish() - } - } - - #[cfg(not(target_arch = "spirv"))] - impl core::fmt::Display for $affine2 { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "[{}, {}, {}]", self.x_axis, self.y_axis, self.z_axis) - } - } - - impl From<$affine2> for $mat3 { - #[inline] - fn from(m: $affine2) -> $mat3 { - Self::from_cols( - m.matrix2.x_axis.extend(0.0), - m.matrix2.y_axis.extend(0.0), - m.translation.extend(1.0), - ) - } - } - - impl Mul for $affine2 { - type Output = $affine2; - - #[inline(always)] - fn mul(self, other: $affine2) -> Self::Output { - Self { - matrix2: self.matrix2 * other.matrix2, - translation: self.matrix2 * other.translation + self.translation, - } - } - } - - impl Mul<$affine2> for $t { - type Output = $affine2; - #[inline(always)] - fn mul(self, other: $affine2) -> Self::Output { - $affine2 { - matrix2: self * other.matrix2, - translation: self * other.translation, - } - } - } - - impl Mul<$t> for $affine2 { - type Output = Self; - #[inline(always)] - fn mul(self, other: $t) -> Self::Output { - Self { - matrix2: self.matrix2 * other, - translation: self.translation * other, - } - } - } - - impl Add<$affine2> for $affine2 { - type Output = Self; - #[inline(always)] - fn add(self, other: Self) -> Self::Output { - Self { - matrix2: self.matrix2 + other.matrix2, - translation: self.translation + other.translation, - } - } - } - - impl Sub<$affine2> for $affine2 { - type Output = Self; - #[inline(always)] - fn sub(self, other: Self) -> Self::Output { - Self { - matrix2: self.matrix2 - other.matrix2, - translation: self.translation - other.translation, - } - } - } - - impl Mul<$mat3> for $affine2 { - type Output = $mat3; - - #[inline(always)] - fn mul(self, other: $mat3) -> Self::Output { - $mat3::from(self) * other - } - } - - impl Mul<$affine2> for $mat3 { - type Output = $mat3; - - #[inline(always)] - fn mul(self, other: $affine2) -> Self::Output { - self * $mat3::from(other) - } - } - - impl<'a> core::iter::Product<&'a Self> for $affine2 { - fn product(iter: I) -> Self - where - I: Iterator, - { - iter.fold(Self::IDENTITY, |a, &b| a * b) - } - } - }; -} - -type TransformF32 = Mat2; -type TranslateF32 = Vec2; -type DerefTargetF32 = Columns3; - -define_affine2_struct!(Affine2, TransformF32, TranslateF32); -impl_affine2_methods!(f32, Mat2, Mat3, Vec2, Affine2, TransformF32, TranslateF32); -impl_affine2_traits!( - f32, - Mat2, - Mat3, - Vec2, - Affine2, - TransformF32, - TranslateF32, - DerefTargetF32 -); - -impl From for Mat3A { - #[inline] - fn from(m: Affine2) -> Mat3A { - Self::from_cols( - Vec3A::from((m.matrix2.x_axis, 0.0)), - Vec3A::from((m.matrix2.y_axis, 0.0)), - Vec3A::from((m.translation, 1.0)), - ) - } -} - -impl Mul for Affine2 { - type Output = Mat3A; - - #[inline(always)] - fn mul(self, other: Mat3A) -> Self::Output { - Mat3A::from(self) * other - } -} - -impl Mul for Mat3A { - type Output = Mat3A; - - #[inline(always)] - fn mul(self, other: Affine2) -> Self::Output { - self * Mat3A::from(other) - } -} - -type TransformF64 = DMat2; -type TranslateF64 = DVec2; -type DerefTargetF64 = Columns3; - -define_affine2_struct!(DAffine2, TransformF64, TranslateF64); -impl_affine2_methods!( - f64, - DMat2, - DMat3, - DVec2, - DAffine2, - TransformF64, - TranslateF64 -); -impl_affine2_traits!( - f64, - DMat2, - DMat3, - DVec2, - DAffine2, - TransformF64, - TranslateF64, - DerefTargetF64 -); - -#[cfg(all( - not(feature = "cuda"), - any(feature = "scalar-math", target_arch = "spirv") -))] -mod const_test_affine2 { - const_assert_eq!( - core::mem::align_of::(), - core::mem::align_of::() - ); - const_assert_eq!(24, core::mem::size_of::()); -} - -#[cfg(not(any(feature = "scalar-math", target_arch = "spirv")))] -mod const_test_affine2 { - const_assert_eq!(16, core::mem::align_of::()); - const_assert_eq!(32, core::mem::size_of::()); -} - -mod const_test_daffine2 { - const_assert_eq!( - core::mem::align_of::(), - core::mem::align_of::() - ); - const_assert_eq!(48, core::mem::size_of::()); -} diff --git a/src/affine3.rs b/src/affine3.rs deleted file mode 100644 index afde9490..00000000 --- a/src/affine3.rs +++ /dev/null @@ -1,631 +0,0 @@ -use crate::core::storage::Columns4; -use crate::{DMat3, DMat4, DQuat, DVec3, Mat3, Mat3A, Mat4, Quat, Vec3, Vec3A}; -use core::ops::{Add, Deref, DerefMut, Mul, Sub}; - -#[cfg(not(feature = "std"))] -use num_traits::Float; - -macro_rules! define_affine3_struct { - ($affine3:ident, $matrix:ident, $column:ident) => { - /// A 3D affine transform, which can represent translation, rotation, scaling and shear. - /// - /// The type is composed of a 3x3 matrix containing a linear transformation (e.g. scale, - /// rotation, shear, reflection) and a 3D vector translation. - #[derive(Copy, Clone)] - #[repr(C)] - pub struct $affine3 { - pub matrix3: $matrix, - pub translation: $column, - } - }; -} - -macro_rules! impl_affine3_methods { - ($t:ty, $mat3:ident, $mat4:ident, $quat:ident, $vec3:ident, $affine3:ident, $matrix:ident, $column:ident) => { - impl $affine3 { - /// The degenerate zero transform. - /// - /// This transforms any finite vector and point to zero. - /// The zero transform is non-invertible. - pub const ZERO: Self = Self { - matrix3: $matrix::ZERO, - translation: $column::ZERO, - }; - - /// The identity transform. - /// - /// Multiplying a vector with this returns the same vector. - pub const IDENTITY: Self = Self { - matrix3: $matrix::IDENTITY, - translation: $column::ZERO, - }; - - /// All NAN. - pub const NAN: Self = Self { - matrix3: $matrix::NAN, - translation: $column::NAN, - }; - - /// Creates an affine transform from four column vectors. - #[inline(always)] - pub fn from_cols( - x_axis: $column, - y_axis: $column, - z_axis: $column, - w_axis: $column, - ) -> Self { - Self { - matrix3: $matrix::from_cols(x_axis, y_axis, z_axis), - translation: w_axis, - } - } - - /// Creates an affine transform from a `[S; 12]` array stored in column major order. - /// If your data is stored in row major you will need to `transpose` the returned - /// matrix. - #[inline(always)] - pub fn from_cols_array(m: &[$t; 12]) -> Self { - Self { - matrix3: $matrix::from_cols_slice(&m[0..9]), - translation: $column::from_slice(&m[9..12]), - } - } - - /// Creates a `[S; 12]` array storing data in column major order. - /// If you require data in row major order `transpose` the matrix first. - #[inline(always)] - pub fn to_cols_array(&self) -> [$t; 12] { - let x = &self.matrix3.x_axis; - let y = &self.matrix3.y_axis; - let z = &self.matrix3.z_axis; - let w = &self.translation; - [x.x, x.y, x.z, y.x, y.y, y.z, z.x, z.y, z.z, w.x, w.y, w.z] - } - - /// Creates an affine transform from a `[[S; 3]; 4]` 2D array stored in column major order. - /// If your data is in row major order you will need to `transpose` the returned - /// matrix. - #[inline(always)] - pub fn from_cols_array_2d(m: &[[$t; 3]; 4]) -> Self { - Self { - matrix3: $matrix::from_cols(m[0].into(), m[1].into(), m[2].into()), - translation: m[3].into(), - } - } - - /// Creates a `[[S; 3]; 4]` 2D array storing data in column major order. - /// If you require data in row major order `transpose` the matrix first. - #[inline(always)] - pub fn to_cols_array_2d(&self) -> [[$t; 3]; 4] { - [ - self.matrix3.x_axis.into(), - self.matrix3.y_axis.into(), - self.matrix3.z_axis.into(), - self.translation.into(), - ] - } - - /// Creates an affine transform from the first 12 values in `slice`. - /// - /// # Panics - /// - /// Panics if `slice` is less than 12 elements long. - #[inline(always)] - pub fn from_cols_slice(slice: &[$t]) -> Self { - Self { - matrix3: $matrix::from_cols_slice(&slice[0..9]), - translation: $column::from_slice(&slice[9..12]), - } - } - - /// Writes the columns of `self` to the first 12 elements in `slice`. - /// - /// # Panics - /// - /// Panics if `slice` is less than 12 elements long. - #[inline(always)] - pub fn write_cols_to_slice(self, slice: &mut [$t]) { - self.matrix3.write_cols_to_slice(&mut slice[0..9]); - self.translation.write_to_slice(&mut slice[9..12]); - } - - /// Creates an affine transform that changes scale. - /// Note that if any scale is zero the transform will be non-invertible. - #[inline(always)] - pub fn from_scale(scale: $vec3) -> Self { - Self { - matrix3: $matrix::from_diagonal(scale), - translation: $column::ZERO, - } - } - - /// Creates an affine transform from the given `rotation` quaternion. - #[inline(always)] - pub fn from_quat(rotation: $quat) -> Self { - Self { - matrix3: $matrix::from_quat(rotation), - translation: $column::ZERO, - } - } - - /// Creates an affine transform containing a 3D rotation around a normalized - /// rotation `axis` of `angle` (in radians). - #[inline(always)] - pub fn from_axis_angle(axis: $vec3, angle: $t) -> Self { - Self { - matrix3: $matrix::from_axis_angle(axis, angle), - translation: $column::ZERO, - } - } - - /// Creates an affine transform containing a 3D rotation around the x axis of - /// `angle` (in radians). - #[inline(always)] - pub fn from_rotation_x(angle: $t) -> Self { - Self { - matrix3: $matrix::from_rotation_x(angle), - translation: $column::ZERO, - } - } - - /// Creates an affine transform containing a 3D rotation around the y axis of - /// `angle` (in radians). - #[inline] - pub fn from_rotation_y(angle: $t) -> Self { - Self { - matrix3: $matrix::from_rotation_y(angle), - translation: $column::ZERO, - } - } - - /// Creates an affine transform containing a 3D rotation around the z axis of - /// `angle` (in radians). - #[inline] - pub fn from_rotation_z(angle: $t) -> Self { - Self { - matrix3: $matrix::from_rotation_z(angle), - translation: $column::ZERO, - } - } - - /// Creates an affine transformation from the given 3D `translation`. - #[inline(always)] - pub fn from_translation(translation: $vec3) -> Self { - Self { - matrix3: $matrix::IDENTITY, - translation: translation.into(), - } - } - - /// Creates an affine transform from a 3x3 matrix (expressing scale, shear and - /// rotation) - #[inline(always)] - pub fn from_mat3(mat3: $mat3) -> Self { - Self { - matrix3: mat3.into(), - translation: $column::ZERO, - } - } - - /// Creates an affine transform from a 3x3 matrix (expressing scale, shear and rotation) - /// and a translation vector. - /// - /// Equivalent to `Affine3::from_translation(translation) * Affine3::from_mat3(mat3)` - #[inline(always)] - pub fn from_mat3_translation(mat3: $mat3, translation: $vec3) -> Self { - Self { - matrix3: mat3.into(), - translation: translation.into(), - } - } - - /// Creates an affine transform from the given 3D `scale`, `rotation` and - /// `translation`. - /// - /// Equivalent to `Affine3::from_translation(translation) * - /// Affine3::from_quat(rotation) * Affine3::from_scale(scale)` - #[inline(always)] - pub fn from_scale_rotation_translation( - scale: $vec3, - rotation: $quat, - translation: $vec3, - ) -> Self { - let rotation = $matrix::from_quat(rotation); - Self { - matrix3: $matrix::from_cols( - rotation.x_axis * scale.x, - rotation.y_axis * scale.y, - rotation.z_axis * scale.z, - ), - translation: translation.into(), - } - } - - /// Creates an affine transform from the given 3D `rotation` and `translation`. - /// - /// Equivalent to `Affine3::from_translation(translation) * Affine3::from_quat(rotation)` - #[inline(always)] - pub fn from_rotation_translation(rotation: $quat, translation: $vec3) -> Self { - Self { - matrix3: $matrix::from_quat(rotation.into()), - translation: translation.into(), - } - } - - /// The given `Mat4` must be an affine transform, - /// i.e. contain no perspective transform. - #[inline] - pub fn from_mat4(m: $mat4) -> Self { - Self { - matrix3: $matrix::from_cols( - $column(m.x_axis.0.into()), - $column(m.y_axis.0.into()), - $column(m.z_axis.0.into()), - ), - translation: $column(m.w_axis.0.into()), - } - } - - /// Extracts `scale`, `rotation` and `translation` from `self`. - /// - /// The transform is expected to be non-degenerate and without shearing, or the output - /// will be invalid. - /// - /// # Panics - /// - /// Will panic if the determinant `self.matrix3` is zero or if the resulting scale - /// vector contains any zero elements when `glam_assert` is enabled. - #[inline(always)] - pub fn to_scale_rotation_translation(&self) -> ($vec3, $quat, $vec3) { - // TODO: migrate to core module - let det = self.matrix3.determinant(); - glam_assert!(det != 0.0); - - let scale = $vec3::new( - self.matrix3.x_axis.length() * det.signum(), - self.matrix3.y_axis.length(), - self.matrix3.z_axis.length(), - ); - - glam_assert!(scale.cmpne($vec3::ZERO).all()); - - let inv_scale = scale.recip(); - - let rotation = $quat::from_mat3(&$mat3::from_cols( - (self.matrix3.x_axis * inv_scale.x).into(), - (self.matrix3.y_axis * inv_scale.y).into(), - (self.matrix3.z_axis * inv_scale.z).into(), - )); - - (scale, rotation, self.translation.into()) - } - - #[inline] - fn look_to_lh(eye: $vec3, dir: $vec3, up: $vec3) -> Self { - let f = dir.normalize(); - let s = up.cross(f).normalize(); - let u = f.cross(s); - Self { - matrix3: $matrix::from_cols( - $vec3::new(s.x, u.x, f.x).into(), - $vec3::new(s.y, u.y, f.y).into(), - $vec3::new(s.z, u.z, f.z).into(), - ), - translation: $column::new(-s.dot(eye), -u.dot(eye), -f.dot(eye)), - } - } - - /// Creates a left-handed view transform using a camera position, an up direction, and - /// a focal point. - /// - /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=forward`. - /// - /// # Panics - /// - /// Will panic if `up` is not normalized when `glam_assert` is enabled. - #[inline] - pub fn look_at_lh(eye: $vec3, center: $vec3, up: $vec3) -> Self { - glam_assert!(up.is_normalized()); - Self::look_to_lh(eye, center - eye, up) - } - - /// Creates a right-handed view transform using a camera position, an up direction, and - /// a focal point. - /// - /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=back`. - /// - /// # Panics - /// - /// Will panic if `up` is not normalized when `glam_assert` is enabled. - #[inline] - pub fn look_at_rh(eye: $vec3, center: $vec3, up: $vec3) -> Self { - glam_assert!(up.is_normalized()); - Self::look_to_lh(eye, eye - center, up) - } - - /// Transforms the given 3D points, applying shear, scale, rotation and translation. - #[inline(always)] - pub fn transform_point3(&self, other: $vec3) -> $vec3 { - ((self.matrix3.x_axis * other.x) - + (self.matrix3.y_axis * other.y) - + (self.matrix3.z_axis * other.z) - + self.translation) - .into() - } - - /// Transforms the given 3D vector, applying shear, scale and rotation (but NOT - /// translation). - /// - /// To also apply translation, use [`Self::transform_point3`] instead. - #[inline(always)] - pub fn transform_vector3(&self, other: $vec3) -> $vec3 { - ((self.matrix3.x_axis * other.x) - + (self.matrix3.y_axis * other.y) - + (self.matrix3.z_axis * other.z)) - .into() - } - - /// Returns `true` if, and only if, all elements are finite. - /// - /// If any element is either `NaN`, positive or negative infinity, this will return - /// `false`. - #[inline] - pub fn is_finite(&self) -> bool { - self.matrix3.is_finite() && self.translation.is_finite() - } - - /// Returns `true` if any elements are `NaN`. - #[inline] - pub fn is_nan(&self) -> bool { - self.matrix3.is_nan() || self.translation.is_nan() - } - - /// Returns true if the absolute difference of all elements between `self` and `other` - /// is less than or equal to `max_abs_diff`. - /// - /// This can be used to compare if two 3x4 matrices contain similar elements. It works - /// best when comparing with a known value. The `max_abs_diff` that should be used used - /// depends on the values being compared against. - /// - /// For more see - /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/). - #[inline] - pub fn abs_diff_eq(&self, other: Self, max_abs_diff: $t) -> bool { - self.matrix3.abs_diff_eq(other.matrix3, max_abs_diff) - && self - .translation - .abs_diff_eq(other.translation, max_abs_diff) - } - - /// Return the inverse of this transform. - /// - /// Note that if the transform is not invertible the result will be invalid. - #[must_use] - #[inline] - pub fn inverse(&self) -> Self { - let matrix3 = self.matrix3.inverse(); - // transform negative translation by the 3x3 inverse: - let translation = -(matrix3 * self.translation); - - Self { - matrix3, - translation, - } - } - } - }; -} - -macro_rules! impl_affine3_traits { - ($t:ty, $mat3:ident, $mat4:ident, $vec3:ident, $vec4:ident, $affine3:ident, $matrix:ident, $column:ident, $deref:ident) => { - impl Default for $affine3 { - #[inline(always)] - fn default() -> Self { - Self::IDENTITY - } - } - - impl Deref for $affine3 { - type Target = $deref; - #[inline(always)] - fn deref(&self) -> &Self::Target { - unsafe { &*(self as *const Self as *const Self::Target) } - } - } - - impl DerefMut for $affine3 { - #[inline(always)] - fn deref_mut(&mut self) -> &mut Self::Target { - unsafe { &mut *(self as *mut Self as *mut Self::Target) } - } - } - - impl PartialEq for $affine3 { - #[inline] - fn eq(&self, other: &Self) -> bool { - self.matrix3.eq(&other.matrix3) && self.translation.eq(&other.translation) - } - } - - #[cfg(not(target_arch = "spirv"))] - impl core::fmt::Debug for $affine3 { - fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - fmt.debug_struct(stringify!($affine3)) - .field("matrix3", &self.matrix3) - .field("translation", &self.translation) - .finish() - } - } - - #[cfg(not(target_arch = "spirv"))] - impl core::fmt::Display for $affine3 { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!( - f, - "[{}, {}, {}, {}]", - self.x_axis, self.y_axis, self.z_axis, self.w_axis - ) - } - } - - impl From<$affine3> for $mat4 { - #[inline] - fn from(m: $affine3) -> $mat4 { - $mat4::from_cols( - m.matrix3.x_axis.extend(0.0), - m.matrix3.y_axis.extend(0.0), - m.matrix3.z_axis.extend(0.0), - m.translation.extend(1.0), - ) - } - } - - impl Mul for $affine3 { - type Output = $affine3; - - #[inline(always)] - fn mul(self, other: $affine3) -> Self::Output { - Self { - matrix3: self.matrix3 * other.matrix3, - translation: self.matrix3 * other.translation + self.translation, - } - } - } - - impl Mul<$affine3> for $t { - type Output = $affine3; - #[inline(always)] - fn mul(self, other: $affine3) -> Self::Output { - $affine3 { - matrix3: self * other.matrix3, - translation: self * other.translation, - } - } - } - - impl Mul<$t> for $affine3 { - type Output = Self; - #[inline(always)] - fn mul(self, other: $t) -> Self::Output { - Self { - matrix3: self.matrix3 * other, - translation: self.translation * other, - } - } - } - - impl Add<$affine3> for $affine3 { - type Output = Self; - #[inline(always)] - fn add(self, other: Self) -> Self::Output { - Self { - matrix3: self.matrix3 + other.matrix3, - translation: self.translation + other.translation, - } - } - } - - impl Sub<$affine3> for $affine3 { - type Output = Self; - #[inline(always)] - fn sub(self, other: Self) -> Self::Output { - Self { - matrix3: self.matrix3 - other.matrix3, - translation: self.translation - other.translation, - } - } - } - - impl Mul<$mat4> for $affine3 { - type Output = $mat4; - - #[inline(always)] - fn mul(self, rhs: $mat4) -> Self::Output { - $mat4::from(self) * rhs - } - } - - impl Mul<$affine3> for $mat4 { - type Output = $mat4; - - #[inline(always)] - fn mul(self, rhs: $affine3) -> Self::Output { - self * $mat4::from(rhs) - } - } - - impl<'a> core::iter::Product<&'a Self> for $affine3 { - fn product(iter: I) -> Self - where - I: Iterator, - { - iter.fold(Self::IDENTITY, |a, &b| a * b) - } - } - }; -} - -type DerefTargetF32 = Columns4; - -define_affine3_struct!(Affine3A, Mat3A, Vec3A); -impl_affine3_methods!(f32, Mat3, Mat4, Quat, Vec3, Affine3A, Mat3A, Vec3A); -impl_affine3_traits!( - f32, - Mat3, - Mat4, - Vec3, - Vec4, - Affine3A, - Mat3A, - Vec3A, - DerefTargetF32 -); - -impl Affine3A { - /// Transforms the given `Vec3A`, applying shear, scale, rotation and translation. - #[inline(always)] - pub fn transform_point3a(&self, other: Vec3A) -> Vec3A { - self.matrix3 * other + self.translation - } - - /// Transforms the given `Vec3A`, applying shear, scale and rotation (but NOT - /// translation). - /// - /// To also apply translation, use [`Self::transform_point3`] instead. - #[inline(always)] - pub fn transform_vector3a(&self, other: Vec3A) -> Vec3A { - self.matrix3 * other - } -} - -type DerefTargetF64 = Columns4; - -define_affine3_struct!(DAffine3, DMat3, DVec3); -impl_affine3_methods!(f64, DMat3, DMat4, DQuat, DVec3, DAffine3, DMat3, DVec3); -impl_affine3_traits!( - f64, - DMat3, - DMat4, - DVec3, - DVec4, - DAffine3, - DMat3, - DVec3, - DerefTargetF64 -); - -mod const_test_affine3a { - const_assert_eq!( - core::mem::align_of::(), - core::mem::align_of::() - ); - const_assert_eq!(64, core::mem::size_of::()); -} - -mod const_test_daffine3 { - const_assert_eq!( - core::mem::align_of::(), - core::mem::align_of::() - ); - const_assert_eq!(96, core::mem::size_of::()); -} diff --git a/src/align16.rs b/src/align16.rs new file mode 100644 index 00000000..4e0e725f --- /dev/null +++ b/src/align16.rs @@ -0,0 +1,27 @@ +#[derive(Clone, Copy, Default, PartialEq, PartialOrd)] +#[repr(C, align(16))] +pub(crate) struct Align16(pub T); + +impl Align16 { + #[allow(dead_code)] + pub fn as_ptr(&self) -> *const T { + &self.0 + } + + #[allow(dead_code)] + pub fn as_mut_ptr(&mut self) -> *mut T { + &mut self.0 + } +} + +#[test] +fn test_align16() { + use core::{mem, ptr}; + let mut a = Align16::(1.0); + assert_eq!(mem::align_of_val(&a), 16); + unsafe { + assert_eq!(ptr::read(a.as_ptr()).to_bits(), f32::to_bits(1.0)); + ptr::write(a.as_mut_ptr(), -1.0); + } + assert_eq!(a.0.to_bits(), f32::to_bits(-1.0)); +} diff --git a/src/bool.rs b/src/bool.rs new file mode 100644 index 00000000..86493466 --- /dev/null +++ b/src/bool.rs @@ -0,0 +1,68 @@ +mod bvec2; +mod bvec3; +mod bvec4; + +#[cfg(all(target_feature = "sse2", not(feature = "scalar-math")))] +mod sse2; + +#[cfg(all(target_feature = "simd128", not(feature = "scalar-math")))] +mod wasm32; + +pub use bvec2::BVec2; +pub use bvec3::BVec3; +pub use bvec4::BVec4; + +#[cfg(all(target_feature = "sse2", not(feature = "scalar-math")))] +pub use sse2::bvec3a::BVec3A; +#[cfg(all(target_feature = "sse2", not(feature = "scalar-math")))] +pub use sse2::bvec4a::BVec4A; + +#[cfg(all(target_feature = "simd128", not(feature = "scalar-math")))] +pub use wasm32::bvec3a::BVec3A; +#[cfg(all(target_feature = "simd128", not(feature = "scalar-math")))] +pub use wasm32::bvec4a::BVec4A; + +#[cfg(any( + not(any(target_feature = "sse2", target_feature = "simd128")), + feature = "scalar-math" +))] +pub type BVec3A = BVec3; + +#[cfg(any( + not(any(target_feature = "sse2", target_feature = "simd128")), + feature = "scalar-math" +))] +pub type BVec4A = BVec4; + +mod const_test_bvec2 { + const_assert_eq!(1, core::mem::align_of::()); + const_assert_eq!(2, core::mem::size_of::()); +} + +mod const_test_bvec3 { + const_assert_eq!(1, core::mem::align_of::()); + const_assert_eq!(3, core::mem::size_of::()); +} + +mod const_test_bvec4 { + const_assert_eq!(1, core::mem::align_of::()); + const_assert_eq!(4, core::mem::size_of::()); +} + +#[cfg(all( + any(target_feature = "sse2", target_feature = "simd128"), + not(feature = "scalar-math") +))] +mod const_test_bvec3a { + const_assert_eq!(16, core::mem::align_of::()); + const_assert_eq!(16, core::mem::size_of::()); +} + +#[cfg(all( + any(target_feature = "sse2", target_feature = "simd128"), + not(feature = "scalar-math") +))] +mod const_test_bvec4a { + const_assert_eq!(16, core::mem::align_of::()); + const_assert_eq!(16, core::mem::size_of::()); +} diff --git a/src/bool/bvec2.rs b/src/bool/bvec2.rs new file mode 100644 index 00000000..8d009bc5 --- /dev/null +++ b/src/bool/bvec2.rs @@ -0,0 +1,155 @@ +// Generated from vec_mask.rs template. Edit the template, not the generated file. + +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::{hash, ops::*}; + +/// A 2-dimensional boolean vector. +#[derive(Clone, Copy)] +pub struct BVec2 { + pub x: bool, + pub y: bool, +} + +const MASK: [u32; 2] = [0, 0xff_ff_ff_ff]; + +const FALSE: BVec2 = BVec2::new(false, false); + +impl BVec2 { + /// Creates a new vector mask. + #[inline(always)] + pub const fn new(x: bool, y: bool) -> Self { + Self { x, y } + } + + /// Returns a bitmask with the lowest two bits set from the elements of `self`. + /// + /// A true element results in a `1` bit and a false element in a `0` bit. Element `x` goes + /// into the first lowest bit, element `y` into the second, etc. + #[inline] + pub fn bitmask(self) -> u32 { + (self.x as u32) | (self.y as u32) << 1 + } + + /// Returns true if any of the elements are true, false otherwise. + #[inline] + pub fn any(self) -> bool { + self.x || self.y + } + + /// Returns true if all the elements are true, false otherwise. + #[inline] + pub fn all(self) -> bool { + self.x && self.y + } + + #[inline] + fn into_bool_array(self) -> [bool; 2] { + [self.x, self.y] + } + + #[inline] + fn into_u32_array(self) -> [u32; 2] { + [MASK[self.x as usize], MASK[self.y as usize]] + } +} + +impl Default for BVec2 { + #[inline] + fn default() -> Self { + FALSE + } +} + +impl PartialEq for BVec2 { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.bitmask().eq(&rhs.bitmask()) + } +} + +impl Eq for BVec2 {} + +impl hash::Hash for BVec2 { + #[inline] + fn hash(&self, state: &mut H) { + self.bitmask().hash(state); + } +} + +impl BitAnd for BVec2 { + type Output = Self; + #[inline] + fn bitand(self, rhs: Self) -> Self { + Self { + x: self.x && rhs.x, + y: self.y && rhs.y, + } + } +} + +impl BitAndAssign for BVec2 { + #[inline] + fn bitand_assign(&mut self, rhs: Self) { + *self = self.bitand(rhs); + } +} + +impl BitOr for BVec2 { + type Output = Self; + #[inline] + fn bitor(self, rhs: Self) -> Self { + Self { + x: self.x || rhs.x, + y: self.y || rhs.y, + } + } +} + +impl BitOrAssign for BVec2 { + #[inline] + fn bitor_assign(&mut self, rhs: Self) { + *self = self.bitor(rhs); + } +} + +impl Not for BVec2 { + type Output = Self; + #[inline] + fn not(self) -> Self { + Self { + x: !self.x, + y: !self.y, + } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Debug for BVec2 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let arr = self.into_u32_array(); + write!(f, "{}({:#x}, {:#x})", stringify!(BVec2), arr[0], arr[1]) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Display for BVec2 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let arr = self.into_bool_array(); + write!(f, "[{}, {}]", arr[0], arr[1]) + } +} + +impl From for [bool; 2] { + #[inline] + fn from(mask: BVec2) -> Self { + mask.into_bool_array() + } +} + +impl From for [u32; 2] { + #[inline] + fn from(mask: BVec2) -> Self { + mask.into_u32_array() + } +} diff --git a/src/bool/bvec3.rs b/src/bool/bvec3.rs new file mode 100644 index 00000000..117bd19f --- /dev/null +++ b/src/bool/bvec3.rs @@ -0,0 +1,170 @@ +// Generated from vec_mask.rs template. Edit the template, not the generated file. + +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::{hash, ops::*}; + +/// A 3-dimensional boolean vector. +#[derive(Clone, Copy)] +pub struct BVec3 { + pub x: bool, + pub y: bool, + pub z: bool, +} + +const MASK: [u32; 2] = [0, 0xff_ff_ff_ff]; + +const FALSE: BVec3 = BVec3::new(false, false, false); + +impl BVec3 { + /// Creates a new vector mask. + #[inline(always)] + pub const fn new(x: bool, y: bool, z: bool) -> Self { + Self { x, y, z } + } + + /// Returns a bitmask with the lowest two bits set from the elements of `self`. + /// + /// A true element results in a `1` bit and a false element in a `0` bit. Element `x` goes + /// into the first lowest bit, element `y` into the second, etc. + #[inline] + pub fn bitmask(self) -> u32 { + (self.x as u32) | (self.y as u32) << 1 | (self.z as u32) << 2 + } + + /// Returns true if any of the elements are true, false otherwise. + #[inline] + pub fn any(self) -> bool { + self.x || self.y || self.z + } + + /// Returns true if all the elements are true, false otherwise. + #[inline] + pub fn all(self) -> bool { + self.x && self.y && self.z + } + + #[inline] + fn into_bool_array(self) -> [bool; 3] { + [self.x, self.y, self.z] + } + + #[inline] + fn into_u32_array(self) -> [u32; 3] { + [ + MASK[self.x as usize], + MASK[self.y as usize], + MASK[self.z as usize], + ] + } +} + +impl Default for BVec3 { + #[inline] + fn default() -> Self { + FALSE + } +} + +impl PartialEq for BVec3 { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.bitmask().eq(&rhs.bitmask()) + } +} + +impl Eq for BVec3 {} + +impl hash::Hash for BVec3 { + #[inline] + fn hash(&self, state: &mut H) { + self.bitmask().hash(state); + } +} + +impl BitAnd for BVec3 { + type Output = Self; + #[inline] + fn bitand(self, rhs: Self) -> Self { + Self { + x: self.x && rhs.x, + y: self.y && rhs.y, + z: self.z && rhs.z, + } + } +} + +impl BitAndAssign for BVec3 { + #[inline] + fn bitand_assign(&mut self, rhs: Self) { + *self = self.bitand(rhs); + } +} + +impl BitOr for BVec3 { + type Output = Self; + #[inline] + fn bitor(self, rhs: Self) -> Self { + Self { + x: self.x || rhs.x, + y: self.y || rhs.y, + z: self.z || rhs.z, + } + } +} + +impl BitOrAssign for BVec3 { + #[inline] + fn bitor_assign(&mut self, rhs: Self) { + *self = self.bitor(rhs); + } +} + +impl Not for BVec3 { + type Output = Self; + #[inline] + fn not(self) -> Self { + Self { + x: !self.x, + y: !self.y, + z: !self.z, + } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Debug for BVec3 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let arr = self.into_u32_array(); + write!( + f, + "{}({:#x}, {:#x}, {:#x})", + stringify!(BVec3), + arr[0], + arr[1], + arr[2] + ) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Display for BVec3 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let arr = self.into_bool_array(); + write!(f, "[{}, {}, {}]", arr[0], arr[1], arr[2]) + } +} + +impl From for [bool; 3] { + #[inline] + fn from(mask: BVec3) -> Self { + mask.into_bool_array() + } +} + +impl From for [u32; 3] { + #[inline] + fn from(mask: BVec3) -> Self { + mask.into_u32_array() + } +} diff --git a/src/bool/bvec4.rs b/src/bool/bvec4.rs new file mode 100644 index 00000000..2aea9f49 --- /dev/null +++ b/src/bool/bvec4.rs @@ -0,0 +1,176 @@ +// Generated from vec_mask.rs template. Edit the template, not the generated file. + +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::{hash, ops::*}; + +/// A 4-dimensional boolean vector. +#[derive(Clone, Copy)] +pub struct BVec4 { + pub x: bool, + pub y: bool, + pub z: bool, + pub w: bool, +} + +const MASK: [u32; 2] = [0, 0xff_ff_ff_ff]; + +const FALSE: BVec4 = BVec4::new(false, false, false, false); + +impl BVec4 { + /// Creates a new vector mask. + #[inline(always)] + pub const fn new(x: bool, y: bool, z: bool, w: bool) -> Self { + Self { x, y, z, w } + } + + /// Returns a bitmask with the lowest two bits set from the elements of `self`. + /// + /// A true element results in a `1` bit and a false element in a `0` bit. Element `x` goes + /// into the first lowest bit, element `y` into the second, etc. + #[inline] + pub fn bitmask(self) -> u32 { + (self.x as u32) | (self.y as u32) << 1 | (self.z as u32) << 2 | (self.w as u32) << 3 + } + + /// Returns true if any of the elements are true, false otherwise. + #[inline] + pub fn any(self) -> bool { + self.x || self.y || self.z || self.w + } + + /// Returns true if all the elements are true, false otherwise. + #[inline] + pub fn all(self) -> bool { + self.x && self.y && self.z && self.w + } + + #[inline] + fn into_bool_array(self) -> [bool; 4] { + [self.x, self.y, self.z, self.w] + } + + #[inline] + fn into_u32_array(self) -> [u32; 4] { + [ + MASK[self.x as usize], + MASK[self.y as usize], + MASK[self.z as usize], + MASK[self.w as usize], + ] + } +} + +impl Default for BVec4 { + #[inline] + fn default() -> Self { + FALSE + } +} + +impl PartialEq for BVec4 { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.bitmask().eq(&rhs.bitmask()) + } +} + +impl Eq for BVec4 {} + +impl hash::Hash for BVec4 { + #[inline] + fn hash(&self, state: &mut H) { + self.bitmask().hash(state); + } +} + +impl BitAnd for BVec4 { + type Output = Self; + #[inline] + fn bitand(self, rhs: Self) -> Self { + Self { + x: self.x && rhs.x, + y: self.y && rhs.y, + z: self.z && rhs.z, + w: self.w && rhs.w, + } + } +} + +impl BitAndAssign for BVec4 { + #[inline] + fn bitand_assign(&mut self, rhs: Self) { + *self = self.bitand(rhs); + } +} + +impl BitOr for BVec4 { + type Output = Self; + #[inline] + fn bitor(self, rhs: Self) -> Self { + Self { + x: self.x || rhs.x, + y: self.y || rhs.y, + z: self.z || rhs.z, + w: self.w || rhs.w, + } + } +} + +impl BitOrAssign for BVec4 { + #[inline] + fn bitor_assign(&mut self, rhs: Self) { + *self = self.bitor(rhs); + } +} + +impl Not for BVec4 { + type Output = Self; + #[inline] + fn not(self) -> Self { + Self { + x: !self.x, + y: !self.y, + z: !self.z, + w: !self.w, + } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Debug for BVec4 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let arr = self.into_u32_array(); + write!( + f, + "{}({:#x}, {:#x}, {:#x}, {:#x})", + stringify!(BVec4), + arr[0], + arr[1], + arr[2], + arr[3] + ) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Display for BVec4 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let arr = self.into_bool_array(); + write!(f, "[{}, {}, {}, {}]", arr[0], arr[1], arr[2], arr[3]) + } +} + +impl From for [bool; 4] { + #[inline] + fn from(mask: BVec4) -> Self { + mask.into_bool_array() + } +} + +impl From for [u32; 4] { + #[inline] + fn from(mask: BVec4) -> Self { + mask.into_u32_array() + } +} diff --git a/src/bool/sse2.rs b/src/bool/sse2.rs new file mode 100644 index 00000000..9a9a3297 --- /dev/null +++ b/src/bool/sse2.rs @@ -0,0 +1,2 @@ +pub mod bvec3a; +pub mod bvec4a; diff --git a/src/bool/sse2/bvec3a.rs b/src/bool/sse2/bvec3a.rs new file mode 100644 index 00000000..2f956e7b --- /dev/null +++ b/src/bool/sse2/bvec3a.rs @@ -0,0 +1,182 @@ +// Generated from vec_mask.rs template. Edit the template, not the generated file. + +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::{hash, ops::*}; + +#[cfg(target_arch = "x86")] +use core::arch::x86::*; +#[cfg(target_arch = "x86_64")] +use core::arch::x86_64::*; + +union UnionCast { + a: [u32; 4], + v: BVec3A, +} + +/// A 3-dimensional SIMD vector mask. +/// +/// This type is 16 byte aligned and is backed by a SIMD vector. If SIMD is not available +/// `BVec3A` will be a type alias for `BVec3`. +#[derive(Clone, Copy)] +#[repr(transparent)] +pub struct BVec3A(pub(crate) __m128); + +const MASK: [u32; 2] = [0, 0xff_ff_ff_ff]; + +const FALSE: BVec3A = BVec3A::new(false, false, false); + +impl BVec3A { + /// Creates a new vector mask. + #[inline(always)] + pub const fn new(x: bool, y: bool, z: bool) -> Self { + unsafe { + UnionCast { + a: [MASK[x as usize], MASK[y as usize], MASK[z as usize], 0], + } + .v + } + } + + /// Returns a bitmask with the lowest two bits set from the elements of `self`. + /// + /// A true element results in a `1` bit and a false element in a `0` bit. Element `x` goes + /// into the first lowest bit, element `y` into the second, etc. + #[inline] + pub fn bitmask(self) -> u32 { + unsafe { (_mm_movemask_ps(self.0) as u32) & 0x7 } + } + + /// Returns true if any of the elements are true, false otherwise. + #[inline] + pub fn any(self) -> bool { + unsafe { (_mm_movemask_ps(self.0) & 0x7) != 0 } + } + + /// Returns true if all the elements are true, false otherwise. + #[inline] + pub fn all(self) -> bool { + unsafe { (_mm_movemask_ps(self.0) & 0x7) == 0x7 } + } + + #[inline] + fn into_bool_array(self) -> [bool; 3] { + let bitmask = self.bitmask(); + [(bitmask & 1) != 0, (bitmask & 2) != 0, (bitmask & 4) != 0] + } + + #[inline] + fn into_u32_array(self) -> [u32; 3] { + let bitmask = self.bitmask(); + [ + MASK[(bitmask & 1) as usize], + MASK[((bitmask >> 1) & 1) as usize], + MASK[((bitmask >> 2) & 1) as usize], + ] + } +} + +impl Default for BVec3A { + #[inline] + fn default() -> Self { + FALSE + } +} + +impl PartialEq for BVec3A { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.bitmask().eq(&rhs.bitmask()) + } +} + +impl Eq for BVec3A {} + +impl hash::Hash for BVec3A { + #[inline] + fn hash(&self, state: &mut H) { + self.bitmask().hash(state); + } +} + +impl BitAnd for BVec3A { + type Output = Self; + #[inline] + fn bitand(self, rhs: Self) -> Self { + Self(unsafe { _mm_and_ps(self.0, rhs.0) }) + } +} + +impl BitAndAssign for BVec3A { + #[inline] + fn bitand_assign(&mut self, rhs: Self) { + *self = self.bitand(rhs); + } +} + +impl BitOr for BVec3A { + type Output = Self; + #[inline] + fn bitor(self, rhs: Self) -> Self { + Self(unsafe { _mm_or_ps(self.0, rhs.0) }) + } +} + +impl BitOrAssign for BVec3A { + #[inline] + fn bitor_assign(&mut self, rhs: Self) { + *self = self.bitor(rhs); + } +} + +impl Not for BVec3A { + type Output = Self; + #[inline] + fn not(self) -> Self { + Self(unsafe { _mm_andnot_ps(self.0, _mm_set_ps1(f32::from_bits(0xff_ff_ff_ff))) }) + } +} + +impl From for __m128 { + #[inline] + fn from(t: BVec3A) -> Self { + t.0 + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Debug for BVec3A { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let arr = self.into_u32_array(); + write!( + f, + "{}({:#x}, {:#x}, {:#x})", + stringify!(BVec3A), + arr[0], + arr[1], + arr[2] + ) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Display for BVec3A { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let arr = self.into_bool_array(); + write!(f, "[{}, {}, {}]", arr[0], arr[1], arr[2]) + } +} + +impl From for [bool; 3] { + #[inline] + fn from(mask: BVec3A) -> Self { + mask.into_bool_array() + } +} + +impl From for [u32; 3] { + #[inline] + fn from(mask: BVec3A) -> Self { + mask.into_u32_array() + } +} diff --git a/src/bool/sse2/bvec4a.rs b/src/bool/sse2/bvec4a.rs new file mode 100644 index 00000000..3ad7d9c9 --- /dev/null +++ b/src/bool/sse2/bvec4a.rs @@ -0,0 +1,194 @@ +// Generated from vec_mask.rs template. Edit the template, not the generated file. + +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::{hash, ops::*}; + +#[cfg(target_arch = "x86")] +use core::arch::x86::*; +#[cfg(target_arch = "x86_64")] +use core::arch::x86_64::*; + +union UnionCast { + a: [u32; 4], + v: BVec4A, +} + +/// A 4-dimensional SIMD vector mask. +/// +/// This type is 16 byte aligned and is backed by a SIMD vector. If SIMD is not available +/// `BVec4A` will be a type alias for `BVec4`. +#[derive(Clone, Copy)] +#[repr(transparent)] +pub struct BVec4A(pub(crate) __m128); + +const MASK: [u32; 2] = [0, 0xff_ff_ff_ff]; + +const FALSE: BVec4A = BVec4A::new(false, false, false, false); + +impl BVec4A { + /// Creates a new vector mask. + #[inline(always)] + pub const fn new(x: bool, y: bool, z: bool, w: bool) -> Self { + unsafe { + UnionCast { + a: [ + MASK[x as usize], + MASK[y as usize], + MASK[z as usize], + MASK[w as usize], + ], + } + .v + } + } + + /// Returns a bitmask with the lowest two bits set from the elements of `self`. + /// + /// A true element results in a `1` bit and a false element in a `0` bit. Element `x` goes + /// into the first lowest bit, element `y` into the second, etc. + #[inline] + pub fn bitmask(self) -> u32 { + unsafe { _mm_movemask_ps(self.0) as u32 } + } + + /// Returns true if any of the elements are true, false otherwise. + #[inline] + pub fn any(self) -> bool { + unsafe { _mm_movemask_ps(self.0) != 0 } + } + + /// Returns true if all the elements are true, false otherwise. + #[inline] + pub fn all(self) -> bool { + unsafe { _mm_movemask_ps(self.0) == 0xf } + } + + #[inline] + fn into_bool_array(self) -> [bool; 4] { + let bitmask = self.bitmask(); + [ + (bitmask & 1) != 0, + (bitmask & 2) != 0, + (bitmask & 4) != 0, + (bitmask & 8) != 0, + ] + } + + #[inline] + fn into_u32_array(self) -> [u32; 4] { + let bitmask = self.bitmask(); + [ + MASK[(bitmask & 1) as usize], + MASK[((bitmask >> 1) & 1) as usize], + MASK[((bitmask >> 2) & 1) as usize], + MASK[((bitmask >> 3) & 1) as usize], + ] + } +} + +impl Default for BVec4A { + #[inline] + fn default() -> Self { + FALSE + } +} + +impl PartialEq for BVec4A { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.bitmask().eq(&rhs.bitmask()) + } +} + +impl Eq for BVec4A {} + +impl hash::Hash for BVec4A { + #[inline] + fn hash(&self, state: &mut H) { + self.bitmask().hash(state); + } +} + +impl BitAnd for BVec4A { + type Output = Self; + #[inline] + fn bitand(self, rhs: Self) -> Self { + Self(unsafe { _mm_and_ps(self.0, rhs.0) }) + } +} + +impl BitAndAssign for BVec4A { + #[inline] + fn bitand_assign(&mut self, rhs: Self) { + *self = self.bitand(rhs); + } +} + +impl BitOr for BVec4A { + type Output = Self; + #[inline] + fn bitor(self, rhs: Self) -> Self { + Self(unsafe { _mm_or_ps(self.0, rhs.0) }) + } +} + +impl BitOrAssign for BVec4A { + #[inline] + fn bitor_assign(&mut self, rhs: Self) { + *self = self.bitor(rhs); + } +} + +impl Not for BVec4A { + type Output = Self; + #[inline] + fn not(self) -> Self { + Self(unsafe { _mm_andnot_ps(self.0, _mm_set_ps1(f32::from_bits(0xff_ff_ff_ff))) }) + } +} + +impl From for __m128 { + #[inline] + fn from(t: BVec4A) -> Self { + t.0 + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Debug for BVec4A { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let arr = self.into_u32_array(); + write!( + f, + "{}({:#x}, {:#x}, {:#x}, {:#x})", + stringify!(BVec4A), + arr[0], + arr[1], + arr[2], + arr[3] + ) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Display for BVec4A { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let arr = self.into_bool_array(); + write!(f, "[{}, {}, {}, {}]", arr[0], arr[1], arr[2], arr[3]) + } +} + +impl From for [bool; 4] { + #[inline] + fn from(mask: BVec4A) -> Self { + mask.into_bool_array() + } +} + +impl From for [u32; 4] { + #[inline] + fn from(mask: BVec4A) -> Self { + mask.into_u32_array() + } +} diff --git a/src/bool/wasm32.rs b/src/bool/wasm32.rs new file mode 100644 index 00000000..9a9a3297 --- /dev/null +++ b/src/bool/wasm32.rs @@ -0,0 +1,2 @@ +pub mod bvec3a; +pub mod bvec4a; diff --git a/src/bool/wasm32/bvec3a.rs b/src/bool/wasm32/bvec3a.rs new file mode 100644 index 00000000..0e5c6808 --- /dev/null +++ b/src/bool/wasm32/bvec3a.rs @@ -0,0 +1,174 @@ +// Generated from vec_mask.rs template. Edit the template, not the generated file. + +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::{hash, ops::*}; + +use core::arch::wasm32::*; + +/// A 3-dimensional SIMD vector mask. +/// +/// This type is 16 byte aligned and is backed by a SIMD vector. If SIMD is not available +/// `BVec3A` will be a type alias for `BVec3`. +#[derive(Clone, Copy)] +#[repr(transparent)] +pub struct BVec3A(pub(crate) v128); + +const MASK: [u32; 2] = [0, 0xff_ff_ff_ff]; + +const FALSE: BVec3A = BVec3A::new(false, false, false); + +impl BVec3A { + /// Creates a new vector mask. + #[inline(always)] + pub const fn new(x: bool, y: bool, z: bool) -> Self { + Self(u32x4( + MASK[x as usize], + MASK[y as usize], + MASK[z as usize], + 0, + )) + } + + /// Returns a bitmask with the lowest two bits set from the elements of `self`. + /// + /// A true element results in a `1` bit and a false element in a `0` bit. Element `x` goes + /// into the first lowest bit, element `y` into the second, etc. + #[inline] + pub fn bitmask(self) -> u32 { + (u32x4_bitmask(self.0) & 0x7) as u32 + } + + /// Returns true if any of the elements are true, false otherwise. + #[inline] + pub fn any(self) -> bool { + (u32x4_bitmask(self.0) & 0x7) != 0 + } + + /// Returns true if all the elements are true, false otherwise. + #[inline] + pub fn all(self) -> bool { + (u32x4_bitmask(self.0) & 0x7) == 0x7 + } + + #[inline] + fn into_bool_array(self) -> [bool; 3] { + let bitmask = self.bitmask(); + [(bitmask & 1) != 0, (bitmask & 2) != 0, (bitmask & 4) != 0] + } + + #[inline] + fn into_u32_array(self) -> [u32; 3] { + let bitmask = self.bitmask(); + [ + MASK[(bitmask & 1) as usize], + MASK[((bitmask >> 1) & 1) as usize], + MASK[((bitmask >> 2) & 1) as usize], + ] + } +} + +impl Default for BVec3A { + #[inline] + fn default() -> Self { + FALSE + } +} + +impl PartialEq for BVec3A { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.bitmask().eq(&rhs.bitmask()) + } +} + +impl Eq for BVec3A {} + +impl hash::Hash for BVec3A { + #[inline] + fn hash(&self, state: &mut H) { + self.bitmask().hash(state); + } +} + +impl BitAnd for BVec3A { + type Output = Self; + #[inline] + fn bitand(self, rhs: Self) -> Self { + Self(v128_and(self.0, rhs.0)) + } +} + +impl BitAndAssign for BVec3A { + #[inline] + fn bitand_assign(&mut self, rhs: Self) { + *self = self.bitand(rhs); + } +} + +impl BitOr for BVec3A { + type Output = Self; + #[inline] + fn bitor(self, rhs: Self) -> Self { + Self(v128_or(self.0, rhs.0)) + } +} + +impl BitOrAssign for BVec3A { + #[inline] + fn bitor_assign(&mut self, rhs: Self) { + *self = self.bitor(rhs); + } +} + +impl Not for BVec3A { + type Output = Self; + #[inline] + fn not(self) -> Self { + Self(v128_not(self.0)) + } +} + +impl From for v128 { + #[inline] + fn from(t: BVec3A) -> Self { + t.0 + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Debug for BVec3A { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let arr = self.into_u32_array(); + write!( + f, + "{}({:#x}, {:#x}, {:#x})", + stringify!(BVec3A), + arr[0], + arr[1], + arr[2] + ) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Display for BVec3A { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let arr = self.into_bool_array(); + write!(f, "[{}, {}, {}]", arr[0], arr[1], arr[2]) + } +} + +impl From for [bool; 3] { + #[inline] + fn from(mask: BVec3A) -> Self { + mask.into_bool_array() + } +} + +impl From for [u32; 3] { + #[inline] + fn from(mask: BVec3A) -> Self { + mask.into_u32_array() + } +} diff --git a/src/bool/wasm32/bvec4a.rs b/src/bool/wasm32/bvec4a.rs new file mode 100644 index 00000000..6c71dd74 --- /dev/null +++ b/src/bool/wasm32/bvec4a.rs @@ -0,0 +1,181 @@ +// Generated from vec_mask.rs template. Edit the template, not the generated file. + +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::{hash, ops::*}; + +use core::arch::wasm32::*; + +/// A 4-dimensional SIMD vector mask. +/// +/// This type is 16 byte aligned and is backed by a SIMD vector. If SIMD is not available +/// `BVec4A` will be a type alias for `BVec4`. +#[derive(Clone, Copy)] +#[repr(transparent)] +pub struct BVec4A(pub(crate) v128); + +const MASK: [u32; 2] = [0, 0xff_ff_ff_ff]; + +const FALSE: BVec4A = BVec4A::new(false, false, false, false); + +impl BVec4A { + /// Creates a new vector mask. + #[inline(always)] + pub const fn new(x: bool, y: bool, z: bool, w: bool) -> Self { + Self(u32x4( + MASK[x as usize], + MASK[y as usize], + MASK[z as usize], + MASK[w as usize], + )) + } + + /// Returns a bitmask with the lowest two bits set from the elements of `self`. + /// + /// A true element results in a `1` bit and a false element in a `0` bit. Element `x` goes + /// into the first lowest bit, element `y` into the second, etc. + #[inline] + pub fn bitmask(self) -> u32 { + u32x4_bitmask(self.0) as u32 + } + + /// Returns true if any of the elements are true, false otherwise. + #[inline] + pub fn any(self) -> bool { + u32x4_bitmask(self.0) != 0 + } + + /// Returns true if all the elements are true, false otherwise. + #[inline] + pub fn all(self) -> bool { + u32x4_bitmask(self.0) == 0xf + } + + #[inline] + fn into_bool_array(self) -> [bool; 4] { + let bitmask = self.bitmask(); + [ + (bitmask & 1) != 0, + (bitmask & 2) != 0, + (bitmask & 4) != 0, + (bitmask & 8) != 0, + ] + } + + #[inline] + fn into_u32_array(self) -> [u32; 4] { + let bitmask = self.bitmask(); + [ + MASK[(bitmask & 1) as usize], + MASK[((bitmask >> 1) & 1) as usize], + MASK[((bitmask >> 2) & 1) as usize], + MASK[((bitmask >> 3) & 1) as usize], + ] + } +} + +impl Default for BVec4A { + #[inline] + fn default() -> Self { + FALSE + } +} + +impl PartialEq for BVec4A { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.bitmask().eq(&rhs.bitmask()) + } +} + +impl Eq for BVec4A {} + +impl hash::Hash for BVec4A { + #[inline] + fn hash(&self, state: &mut H) { + self.bitmask().hash(state); + } +} + +impl BitAnd for BVec4A { + type Output = Self; + #[inline] + fn bitand(self, rhs: Self) -> Self { + Self(v128_and(self.0, rhs.0)) + } +} + +impl BitAndAssign for BVec4A { + #[inline] + fn bitand_assign(&mut self, rhs: Self) { + *self = self.bitand(rhs); + } +} + +impl BitOr for BVec4A { + type Output = Self; + #[inline] + fn bitor(self, rhs: Self) -> Self { + Self(v128_or(self.0, rhs.0)) + } +} + +impl BitOrAssign for BVec4A { + #[inline] + fn bitor_assign(&mut self, rhs: Self) { + *self = self.bitor(rhs); + } +} + +impl Not for BVec4A { + type Output = Self; + #[inline] + fn not(self) -> Self { + Self(v128_not(self.0)) + } +} + +impl From for v128 { + #[inline] + fn from(t: BVec4A) -> Self { + t.0 + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Debug for BVec4A { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let arr = self.into_u32_array(); + write!( + f, + "{}({:#x}, {:#x}, {:#x}, {:#x})", + stringify!(BVec4A), + arr[0], + arr[1], + arr[2], + arr[3] + ) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Display for BVec4A { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let arr = self.into_bool_array(); + write!(f, "[{}, {}, {}, {}]", arr[0], arr[1], arr[2], arr[3]) + } +} + +impl From for [bool; 4] { + #[inline] + fn from(mask: BVec4A) -> Self { + mask.into_bool_array() + } +} + +impl From for [u32; 4] { + #[inline] + fn from(mask: BVec4A) -> Self { + mask.into_u32_array() + } +} diff --git a/src/core.rs b/src/core.rs deleted file mode 100644 index 8eba6e40..00000000 --- a/src/core.rs +++ /dev/null @@ -1,18 +0,0 @@ -// the core module provides traits for implementing vector, quaternion and matrix operations, -// storage structs for scalar vector, quaternion and matrix data and implementations of the traits -// for those structs and for supported SIMD types such as SSE2's `__m128`. -// -// The higher level glam library types have an inner type which either uses one of these storage -// structs, or `__m128` and the actual implementation is provided by the core module. -// -// This architecture allows the public API to not require generics or traits, while still -// supporting a number of Rust primitive types and SIMD architectures such as SSE2. -// -pub mod storage; -pub mod traits; - -mod scalar; -#[cfg(all(target_feature = "sse2", not(feature = "scalar-math")))] -mod sse2; -#[cfg(all(target_feature = "simd128", not(feature = "scalar-math")))] -mod wasm32; diff --git a/src/core/scalar.rs b/src/core/scalar.rs deleted file mode 100644 index 88050c07..00000000 --- a/src/core/scalar.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub mod mask; -pub mod matrix; -pub mod quaternion; -pub mod vector; diff --git a/src/core/scalar/mask.rs b/src/core/scalar/mask.rs deleted file mode 100644 index 77458263..00000000 --- a/src/core/scalar/mask.rs +++ /dev/null @@ -1,452 +0,0 @@ -use crate::core::{ - storage::{XY, XYZ, XYZW}, - traits::{scalar::*, vector::*}, -}; - -impl MaskConst for u32 { - const MASK: [u32; 2] = [0, 0xff_ff_ff_ff]; -} - -impl MaskConst for u64 { - const MASK: [u64; 2] = [0, 0xff_ff_ff_ff_ff_ff_ff_ff]; -} - -// u32 (currently unused) - -/* -impl MaskVectorConst for XY { - const FALSE: Self = Self { x: 0, y: 0 }; -} - -impl MaskVectorConst for XYZ { - const FALSE: Self = Self { x: 0, y: 0, z: 0 }; -} - -impl MaskVectorConst for XYZW { - const FALSE: Self = Self { - x: 0, - y: 0, - z: 0, - w: 0, - }; -} - -impl MaskVector for XY { - #[inline] - fn bitand(self, other: Self) -> Self { - Self { - x: self.x & other.x, - y: self.y & other.y, - } - } - - #[inline] - fn bitor(self, other: Self) -> Self { - Self { - x: self.x | other.x, - y: self.y | other.y, - } - } - - #[inline] - fn not(self) -> Self { - Self { - x: !self.x, - y: !self.y, - } - } -} - -impl MaskVector for XYZ { - #[inline] - fn bitand(self, other: Self) -> Self { - Self { - x: self.x & other.x, - y: self.y & other.y, - z: self.z & other.z, - } - } - - #[inline] - fn bitor(self, other: Self) -> Self { - Self { - x: self.x | other.x, - y: self.y | other.y, - z: self.z | other.z, - } - } - - #[inline] - fn not(self) -> Self { - Self { - x: !self.x, - y: !self.y, - z: !self.z, - } - } -} - -impl MaskVector for XYZW { - #[inline] - fn bitand(self, other: Self) -> Self { - Self { - x: self.x & other.x, - y: self.y & other.y, - z: self.z & other.z, - w: self.w & other.w, - } - } - - #[inline] - fn bitor(self, other: Self) -> Self { - Self { - x: self.x | other.x, - y: self.y | other.y, - z: self.z | other.z, - w: self.w | other.w, - } - } - - #[inline] - fn not(self) -> Self { - Self { - x: !self.x, - y: !self.y, - z: !self.z, - w: !self.w, - } - } -} - -impl MaskVector2 for XY { - #[inline(always)] - fn new(x: bool, y: bool) -> Self { - Self { - x: MaskConst::MASK[x as usize], - y: MaskConst::MASK[y as usize], - } - } - - #[inline] - fn bitmask(self) -> u32 { - (self.x as u32 & 0x1) | (self.y as u32 & 0x1) << 1 - } - - #[inline] - fn any(self) -> bool { - ((self.x | self.y) & 0x1) != 0 - } - - #[inline] - fn all(self) -> bool { - ((self.x & self.y) & 0x1) != 0 - } - - #[inline] - fn into_bool_array(self) -> [bool; 2] { - [self.x != 0, self.y != 0] - } - - #[inline] - fn into_u32_array(self) -> [u32; 2] { - [self.x, self.y] - } -} - -impl MaskVector3 for XYZ { - #[inline(always)] - fn new(x: bool, y: bool, z: bool) -> Self { - // A SSE2 mask can be any bit pattern but for the `Vec3Mask` implementation of select - // we expect either 0 or 0xff_ff_ff_ff. This should be a safe assumption as this type - // can only be created via this function or by `Vec3` methods. - Self { - x: MaskConst::MASK[x as usize], - y: MaskConst::MASK[y as usize], - z: MaskConst::MASK[z as usize], - } - } - - #[inline] - fn bitmask(self) -> u32 { - (self.x & 0x1) | (self.y & 0x1) << 1 | (self.z & 0x1) << 2 - } - - #[inline] - fn any(self) -> bool { - ((self.x | self.y | self.z) & 0x1) != 0 - } - - #[inline] - fn all(self) -> bool { - ((self.x & self.y & self.z) & 0x1) != 0 - } - - #[inline] - fn into_bool_array(self) -> [bool; 3] { - [self.x != 0, self.y != 0, self.z != 0] - } - - #[inline] - fn into_u32_array(self) -> [u32; 3] { - [self.x, self.y, self.z] - } -} - -impl MaskVector4 for XYZW { - #[inline(always)] - fn new(x: bool, y: bool, z: bool, w: bool) -> Self { - // A SSE2 mask can be any bit pattern but for the `Vec4Mask` implementation of select - // we expect either 0 or 0xff_ff_ff_ff. This should be a safe assumption as this type - // can only be created via this function or by `Vec4` methods. - Self { - x: MaskConst::MASK[x as usize], - y: MaskConst::MASK[y as usize], - z: MaskConst::MASK[z as usize], - w: MaskConst::MASK[w as usize], - } - } - - #[inline] - fn bitmask(self) -> u32 { - (self.x & 0x1) | (self.y & 0x1) << 1 | (self.z & 0x1) << 2 | (self.w & 0x1) << 3 - } - - #[inline] - fn any(self) -> bool { - ((self.x | self.y | self.z | self.w) & 0x1) != 0 - } - - #[inline] - fn all(self) -> bool { - ((self.x & self.y & self.z & self.w) & 0x1) != 0 - } - - #[inline] - fn into_bool_array(self) -> [bool; 4] { - [self.x != 0, self.y != 0, self.z != 0, self.w != 0] - } - - #[inline] - fn into_u32_array(self) -> [u32; 4] { - [self.x, self.y, self.z, self.w] - } -} -*/ - -// bool - -impl MaskVectorConst for XY { - const FALSE: Self = Self { x: false, y: false }; -} - -impl MaskVectorConst for XYZ { - const FALSE: Self = Self { - x: false, - y: false, - z: false, - }; -} - -impl MaskVectorConst for XYZW { - const FALSE: Self = Self { - x: false, - y: false, - z: false, - w: false, - }; -} - -impl MaskVector for XY { - #[inline] - fn bitand(self, other: Self) -> Self { - Self { - x: self.x && other.x, - y: self.y && other.y, - } - } - - #[inline] - fn bitor(self, other: Self) -> Self { - Self { - x: self.x || other.x, - y: self.y || other.y, - } - } - - #[inline] - fn not(self) -> Self { - Self { - x: !self.x, - y: !self.y, - } - } -} - -impl MaskVector for XYZ { - #[inline] - fn bitand(self, other: Self) -> Self { - Self { - x: self.x && other.x, - y: self.y && other.y, - z: self.z && other.z, - } - } - - #[inline] - fn bitor(self, other: Self) -> Self { - Self { - x: self.x || other.x, - y: self.y || other.y, - z: self.z || other.z, - } - } - - #[inline] - fn not(self) -> Self { - Self { - x: !self.x, - y: !self.y, - z: !self.z, - } - } -} - -impl MaskVector for XYZW { - #[inline] - fn bitand(self, other: Self) -> Self { - Self { - x: self.x && other.x, - y: self.y && other.y, - z: self.z && other.z, - w: self.w && other.w, - } - } - - #[inline] - fn bitor(self, other: Self) -> Self { - Self { - x: self.x || other.x, - y: self.y || other.y, - z: self.z || other.z, - w: self.w || other.w, - } - } - - #[inline] - fn not(self) -> Self { - Self { - x: !self.x, - y: !self.y, - z: !self.z, - w: !self.w, - } - } -} - -impl MaskVector2 for XY { - #[inline(always)] - fn new(x: bool, y: bool) -> Self { - Self { x, y } - } - - #[inline] - fn bitmask(self) -> u32 { - (self.x as u32) | (self.y as u32) << 1 - } - - #[inline] - fn any(self) -> bool { - self.x || self.y - } - - #[inline] - fn all(self) -> bool { - self.x && self.y - } - - #[inline] - fn into_bool_array(self) -> [bool; 2] { - [self.x, self.y] - } - - #[inline] - fn into_u32_array(self) -> [u32; 2] { - [ - MaskConst::MASK[self.x as usize], - MaskConst::MASK[self.y as usize], - ] - } -} - -impl MaskVector3 for XYZ { - #[inline(always)] - fn new(x: bool, y: bool, z: bool) -> Self { - Self { x, y, z } - } - - #[inline] - fn bitmask(self) -> u32 { - (self.x as u32) | (self.y as u32) << 1 | (self.z as u32) << 2 - } - - #[inline] - fn any(self) -> bool { - self.x || self.y || self.z - } - - #[inline] - fn all(self) -> bool { - self.x && self.y && self.z - } - - #[inline] - fn into_bool_array(self) -> [bool; 3] { - [self.x, self.y, self.z] - } - - #[inline] - fn into_u32_array(self) -> [u32; 3] { - [ - MaskConst::MASK[self.x as usize], - MaskConst::MASK[self.y as usize], - MaskConst::MASK[self.z as usize], - ] - } -} - -impl MaskVector4 for XYZW { - #[inline(always)] - fn new(x: bool, y: bool, z: bool, w: bool) -> Self { - Self { x, y, z, w } - } - - #[inline] - fn bitmask(self) -> u32 { - (self.x as u32) | (self.y as u32) << 1 | (self.z as u32) << 2 | (self.w as u32) << 3 - } - - #[inline] - fn any(self) -> bool { - self.x || self.y || self.z || self.w - } - - #[inline] - fn all(self) -> bool { - self.x && self.y && self.z && self.w - } - - #[inline] - fn into_bool_array(self) -> [bool; 4] { - [self.x, self.y, self.z, self.w] - } - - #[inline] - fn into_u32_array(self) -> [u32; 4] { - [ - MaskConst::MASK[self.x as usize], - MaskConst::MASK[self.y as usize], - MaskConst::MASK[self.z as usize], - MaskConst::MASK[self.w as usize], - ] - } -} diff --git a/src/core/scalar/matrix.rs b/src/core/scalar/matrix.rs deleted file mode 100644 index 34b0211f..00000000 --- a/src/core/scalar/matrix.rs +++ /dev/null @@ -1,285 +0,0 @@ -use crate::core::{ - storage::{Columns2, Columns3, Columns4, XY, XYZ, XYZF32A16, XYZW}, - traits::{ - matrix::{ - FloatMatrix2x2, FloatMatrix3x3, FloatMatrix4x4, Matrix, Matrix2x2, Matrix3x3, - Matrix4x4, MatrixConst, - }, - projection::ProjectionMatrix, - scalar::{FloatEx, NanConstEx, NumEx}, - vector::*, - }, -}; - -impl MatrixConst for Columns2> { - const ZERO: Self = Self { - x_axis: XY::ZERO, - y_axis: XY::ZERO, - }; - const IDENTITY: Self = Self { - x_axis: XY::X, - y_axis: XY::Y, - }; -} - -impl NanConstEx for Columns2> { - const NAN: Self = Self { - x_axis: XY::NAN, - y_axis: XY::NAN, - }; -} - -impl Matrix for Columns2> {} - -impl Matrix2x2> for Columns2> { - #[inline(always)] - fn from_cols(x_axis: XY, y_axis: XY) -> Self { - Self { x_axis, y_axis } - } - - #[inline(always)] - fn x_axis(&self) -> &XY { - &self.x_axis - } - - #[inline(always)] - fn y_axis(&self) -> &XY { - &self.y_axis - } -} - -impl FloatMatrix2x2> for Columns2> {} - -impl MatrixConst for Columns3> { - const ZERO: Self = Self { - x_axis: XYZ::ZERO, - y_axis: XYZ::ZERO, - z_axis: XYZ::ZERO, - }; - const IDENTITY: Self = Self { - x_axis: XYZ::X, - y_axis: XYZ::Y, - z_axis: XYZ::Z, - }; -} - -impl NanConstEx for Columns3> { - const NAN: Self = Self { - x_axis: XYZ::NAN, - y_axis: XYZ::NAN, - z_axis: XYZ::NAN, - }; -} - -impl Matrix for Columns3> {} - -impl Matrix3x3> for Columns3> { - #[inline(always)] - fn from_cols(x_axis: XYZ, y_axis: XYZ, z_axis: XYZ) -> Self { - Self { - x_axis, - y_axis, - z_axis, - } - } - - #[inline(always)] - fn x_axis(&self) -> &XYZ { - &self.x_axis - } - - #[inline(always)] - fn y_axis(&self) -> &XYZ { - &self.y_axis - } - - #[inline(always)] - fn z_axis(&self) -> &XYZ { - &self.z_axis - } - - #[inline] - fn mul_vector(&self, other: XYZ) -> XYZ { - // default implementation uses splat_x etc, which might not be optimal. Need to check. - let mut res = self.x_axis.mul_scalar(other.x); - res = self.y_axis.mul_scalar(other.y).add(res); - res = self.z_axis.mul_scalar(other.z).add(res); - res - } -} - -impl FloatMatrix3x3> for Columns3> { - #[inline] - fn transform_point2(&self, other: XY) -> XY { - // TODO: This is untested, probably slower than the high level code that uses a SIMD mat2 - Columns2::from_cols(self.x_axis.into(), self.y_axis.into()) - .mul_vector(other) - .add(self.z_axis.into()) - } - - #[inline] - fn transform_vector2(&self, other: XY) -> XY { - // TODO: This is untested, probably slower than the high level code that uses a SIMD mat2 - Columns2::from_cols(self.x_axis.into(), self.y_axis.into()).mul_vector(other) - } -} - -impl MatrixConst for Columns3 { - const ZERO: Self = Self { - x_axis: XYZF32A16::ZERO, - y_axis: XYZF32A16::ZERO, - z_axis: XYZF32A16::ZERO, - }; - const IDENTITY: Self = Self { - x_axis: XYZF32A16::X, - y_axis: XYZF32A16::Y, - z_axis: XYZF32A16::Z, - }; -} - -impl NanConstEx for Columns3 { - const NAN: Self = Self { - x_axis: XYZF32A16::NAN, - y_axis: XYZF32A16::NAN, - z_axis: XYZF32A16::NAN, - }; -} - -impl Matrix for Columns3 {} - -impl Matrix3x3 for Columns3 { - #[inline(always)] - fn from_cols(x_axis: XYZF32A16, y_axis: XYZF32A16, z_axis: XYZF32A16) -> Self { - Self { - x_axis, - y_axis, - z_axis, - } - } - - #[inline(always)] - fn x_axis(&self) -> &XYZF32A16 { - &self.x_axis - } - - #[inline(always)] - fn y_axis(&self) -> &XYZF32A16 { - &self.y_axis - } - - #[inline(always)] - fn z_axis(&self) -> &XYZF32A16 { - &self.z_axis - } -} - -impl FloatMatrix3x3 for Columns3 { - #[inline] - fn transform_point2(&self, other: XY) -> XY { - // TODO: This is untested, probably slower than the high level code that uses a SIMD mat2 - Columns2::from_cols(self.x_axis.into_xy(), self.y_axis.into_xy()) - .mul_vector(other) - .add(self.z_axis.into_xy()) - } - - #[inline] - fn transform_vector2(&self, other: XY) -> XY { - // TODO: This is untested, probably slower than the high level code that uses a SIMD mat2 - Columns2::from_cols(self.x_axis.into_xy(), self.y_axis.into_xy()).mul_vector(other) - } -} - -impl MatrixConst for Columns4> { - const ZERO: Self = Self { - x_axis: XYZW::ZERO, - y_axis: XYZW::ZERO, - z_axis: XYZW::ZERO, - w_axis: XYZW::ZERO, - }; - const IDENTITY: Self = Self { - x_axis: XYZW::X, - y_axis: XYZW::Y, - z_axis: XYZW::Z, - w_axis: XYZW::W, - }; -} - -impl NanConstEx for Columns4> { - const NAN: Self = Self { - x_axis: XYZW::NAN, - y_axis: XYZW::NAN, - z_axis: XYZW::NAN, - w_axis: XYZW::NAN, - }; -} - -impl Matrix for Columns4> {} - -impl Matrix4x4> for Columns4> { - #[rustfmt::skip] - #[inline(always)] - fn from_cols(x_axis: XYZW, y_axis: XYZW, z_axis: XYZW, w_axis: XYZW) -> Self { - Self { x_axis, y_axis, z_axis, w_axis } - } - - #[inline(always)] - fn x_axis(&self) -> &XYZW { - &self.x_axis - } - - #[inline(always)] - fn y_axis(&self) -> &XYZW { - &self.y_axis - } - - #[inline(always)] - fn z_axis(&self) -> &XYZW { - &self.z_axis - } - - #[inline(always)] - fn w_axis(&self) -> &XYZW { - &self.w_axis - } -} - -impl FloatMatrix4x4> for Columns4> { - type SIMDVector3 = XYZ; - - #[inline(always)] - fn transform_float4_as_point3(&self, other: XYZ) -> XYZ { - self.transform_point3(other) - } - - #[inline(always)] - fn transform_float4_as_vector3(&self, other: XYZ) -> XYZ { - self.transform_vector3(other) - } - - #[inline(always)] - fn project_float4_as_point3(&self, other: XYZ) -> XYZ { - self.project_point3(other) - } -} - -impl ProjectionMatrix> for Columns4> {} - -impl From>> for Columns3 { - fn from(v: Columns3>) -> Columns3 { - Self { - x_axis: v.x_axis.into(), - y_axis: v.y_axis.into(), - z_axis: v.z_axis.into(), - } - } -} - -impl From> for Columns3> { - fn from(v: Columns3) -> Columns3> { - Self { - x_axis: v.x_axis.into(), - y_axis: v.y_axis.into(), - z_axis: v.z_axis.into(), - } - } -} diff --git a/src/core/scalar/quaternion.rs b/src/core/scalar/quaternion.rs deleted file mode 100644 index 60d12596..00000000 --- a/src/core/scalar/quaternion.rs +++ /dev/null @@ -1,98 +0,0 @@ -use crate::core::{ - storage::{XYZ, XYZW}, - traits::{quaternion::Quaternion, scalar::*, vector::*}, -}; - -impl Quaternion for XYZW { - // fallback - type SIMDVector3 = XYZ; - - #[inline(always)] - fn conjugate(self) -> Self { - Self::new(-self.x, -self.y, -self.z, self.w) - } - - #[inline] - fn lerp(self, end: Self, s: T) -> Self { - glam_assert!(FloatVector4::is_normalized(self)); - glam_assert!(FloatVector4::is_normalized(end)); - - let start = self; - let end = end; - let dot = start.dot(end); - let bias = if dot >= T::ZERO { T::ONE } else { T::NEG_ONE }; - let interpolated = start.add(end.mul_scalar(bias).sub(start).mul_scalar(s)); - interpolated.normalize() - } - - #[inline] - fn slerp(self, mut end: Self, s: T) -> Self { - // http://number-none.com/product/Understanding%20Slerp,%20Then%20Not%20Using%20It/ - - glam_assert!(FloatVector4::is_normalized(self)); - glam_assert!(FloatVector4::is_normalized(end)); - - let mut dot = self.dot(end); - - // Note that a rotation can be represented by two quaternions: `q` and - // `-q`. The slerp path between `q` and `end` will be different from the - // path between `-q` and `end`. One path will take the long way around and - // one will take the short way. In order to correct for this, the `dot` - // product between `self` and `end` should be positive. If the `dot` - // product is negative, slerp between `self` and `-end`. - if dot < T::ZERO { - end = end.mul_scalar(T::NEG_ONE); - dot = -dot; - } - - if dot > T::from_f32(0.9995) { - // assumes lerp returns a normalized quaternion - self.lerp(end, s) - } else { - // assumes scalar_acos clamps the input to [-1.0, 1.0] - let theta = dot.acos_approx(); - let scale1 = (theta * (T::ONE - s)).sin(); - let scale2 = (theta * s).sin(); - let theta_sin = theta.sin(); - - self.mul_scalar(scale1) - .add(end.mul_scalar(scale2)) - .mul_scalar(theta_sin.recip()) - } - } - - #[inline] - fn mul_vector3(self, other: XYZ) -> XYZ { - glam_assert!(FloatVector4::is_normalized(self)); - let w = self.w; - let b = XYZ { - x: self.x, - y: self.y, - z: self.z, - }; - let b2 = b.dot(b); - other - .mul_scalar(w * w - b2) - .add(b.mul_scalar(other.dot(b) * T::TWO)) - .add(b.cross(other).mul_scalar(w * T::TWO)) - } - - #[inline] - fn mul_quaternion(self, other: Self) -> Self { - glam_assert!(FloatVector4::is_normalized(self)); - glam_assert!(FloatVector4::is_normalized(other)); - let (x0, y0, z0, w0) = self.into_tuple(); - let (x1, y1, z1, w1) = other.into_tuple(); - Self::new( - w0 * x1 + x0 * w1 + y0 * z1 - z0 * y1, - w0 * y1 - x0 * z1 + y0 * w1 + z0 * x1, - w0 * z1 + x0 * y1 - y0 * x1 + z0 * w1, - w0 * w1 - x0 * x1 - y0 * y1 - z0 * z1, - ) - } - - #[inline(always)] - fn mul_float4_as_vector3(self, other: XYZ) -> XYZ { - self.mul_vector3(other) - } -} diff --git a/src/core/scalar/vector.rs b/src/core/scalar/vector.rs deleted file mode 100644 index cc7d2465..00000000 --- a/src/core/scalar/vector.rs +++ /dev/null @@ -1,1465 +0,0 @@ -use crate::core::{ - storage::{XY, XYZ, XYZF32A16, XYZW}, - traits::{scalar::*, vector::*}, -}; - -impl VectorConst for XY { - const ZERO: Self = Self { - x: ::ZERO, - y: ::ZERO, - }; - const ONE: Self = Self { - x: ::ONE, - y: ::ONE, - }; -} - -impl NanConstEx for XY { - const NAN: Self = Self { - x: ::NAN, - y: ::NAN, - }; -} - -impl Vector2Const for XY { - const X: Self = Self { - x: ::ONE, - y: ::ZERO, - }; - const Y: Self = Self { - x: ::ZERO, - y: ::ONE, - }; -} - -impl VectorConst for XYZ { - const ZERO: Self = Self { - x: ::ZERO, - y: ::ZERO, - z: ::ZERO, - }; - const ONE: Self = Self { - x: ::ONE, - y: ::ONE, - z: ::ONE, - }; -} - -impl NanConstEx for XYZ { - const NAN: Self = Self { - x: ::NAN, - y: ::NAN, - z: ::NAN, - }; -} - -impl Vector3Const for XYZ { - const X: Self = Self { - x: ::ONE, - y: ::ZERO, - z: ::ZERO, - }; - const Y: Self = Self { - x: ::ZERO, - y: ::ONE, - z: ::ZERO, - }; - const Z: Self = Self { - x: ::ZERO, - y: ::ZERO, - z: ::ONE, - }; -} - -impl VectorConst for XYZW { - const ZERO: Self = Self { - x: ::ZERO, - y: ::ZERO, - z: ::ZERO, - w: ::ZERO, - }; - const ONE: Self = Self { - x: ::ONE, - y: ::ONE, - z: ::ONE, - w: ::ONE, - }; -} - -impl NanConstEx for XYZW { - const NAN: Self = Self { - x: ::NAN, - y: ::NAN, - z: ::NAN, - w: ::NAN, - }; -} - -impl Vector4Const for XYZW { - const X: Self = Self { - x: ::ONE, - y: ::ZERO, - z: ::ZERO, - w: ::ZERO, - }; - const Y: Self = Self { - x: ::ZERO, - y: ::ONE, - z: ::ZERO, - w: ::ZERO, - }; - const Z: Self = Self { - x: ::ZERO, - y: ::ZERO, - z: ::ONE, - w: ::ZERO, - }; - const W: Self = Self { - x: ::ZERO, - y: ::ZERO, - z: ::ZERO, - w: ::ONE, - }; -} - -impl Vector for XY { - type Mask = XY; - - #[inline] - fn splat(s: T) -> Self { - Self { x: s, y: s } - } - - #[inline] - fn select(mask: Self::Mask, if_true: Self, if_false: Self) -> Self { - Self { - x: if mask.x { if_true.x } else { if_false.x }, - y: if mask.y { if_true.y } else { if_false.y }, - } - } - - #[inline] - fn cmpeq(self, other: Self) -> Self::Mask { - Self::Mask { - x: self.x.eq(&other.x), - y: self.y.eq(&other.y), - } - } - - #[inline] - fn cmpne(self, other: Self) -> Self::Mask { - Self::Mask { - x: self.x.ne(&other.x), - y: self.y.ne(&other.y), - } - } - - #[inline] - fn cmpge(self, other: Self) -> Self::Mask { - Self::Mask { - x: self.x.ge(&other.x), - y: self.y.ge(&other.y), - } - } - - #[inline] - fn cmpgt(self, other: Self) -> Self::Mask { - Self::Mask { - x: self.x.gt(&other.x), - y: self.y.gt(&other.y), - } - } - - #[inline] - fn cmple(self, other: Self) -> Self::Mask { - Self::Mask { - x: self.x.le(&other.x), - y: self.y.le(&other.y), - } - } - - #[inline] - fn cmplt(self, other: Self) -> Self::Mask { - Self::Mask { - x: self.x.lt(&other.x), - y: self.y.lt(&other.y), - } - } - - #[inline] - fn add(self, other: Self) -> Self { - Self { - x: self.x + other.x, - y: self.y + other.y, - } - } - - #[inline] - fn div(self, other: Self) -> Self { - Self { - x: self.x / other.x, - y: self.y / other.y, - } - } - - #[inline] - fn mul(self, other: Self) -> Self { - Self { - x: self.x * other.x, - y: self.y * other.y, - } - } - - #[inline] - fn sub(self, other: Self) -> Self { - Self { - x: self.x - other.x, - y: self.y - other.y, - } - } - - #[inline] - fn add_scalar(self, other: T) -> Self { - Self { - x: self.x + other, - y: self.y + other, - } - } - - #[inline] - fn sub_scalar(self, other: T) -> Self { - Self { - x: self.x - other, - y: self.y - other, - } - } - - #[inline] - fn mul_scalar(self, other: T) -> Self { - Self { - x: self.x * other, - y: self.y * other, - } - } - - #[inline] - fn div_scalar(self, other: T) -> Self { - Self { - x: self.x / other, - y: self.y / other, - } - } - - #[inline] - fn rem(self, other: Self) -> Self { - Self { - x: self.x % other.x, - y: self.y % other.y, - } - } - - #[inline] - fn rem_scalar(self, other: T) -> Self { - Self { - x: self.x % other, - y: self.y % other, - } - } - - #[inline] - fn min(self, other: Self) -> Self { - Self { - x: self.x.min(other.x), - y: self.y.min(other.y), - } - } - - #[inline] - fn max(self, other: Self) -> Self { - Self { - x: self.x.max(other.x), - y: self.y.max(other.y), - } - } -} - -impl Vector for XYZ { - type Mask = XYZ; - - #[inline] - fn splat(s: T) -> Self { - Self { x: s, y: s, z: s } - } - - #[inline] - fn select(mask: Self::Mask, if_true: Self, if_false: Self) -> Self { - Self { - x: if mask.x { if_true.x } else { if_false.x }, - y: if mask.y { if_true.y } else { if_false.y }, - z: if mask.z { if_true.z } else { if_false.z }, - } - } - - #[inline] - fn cmpeq(self, other: Self) -> Self::Mask { - Self::Mask { - x: self.x.eq(&other.x), - y: self.y.eq(&other.y), - z: self.z.eq(&other.z), - } - } - - #[inline] - fn cmpne(self, other: Self) -> Self::Mask { - Self::Mask { - x: self.x.ne(&other.x), - y: self.y.ne(&other.y), - z: self.z.ne(&other.z), - } - } - - #[inline] - fn cmpge(self, other: Self) -> Self::Mask { - Self::Mask { - x: self.x.ge(&other.x), - y: self.y.ge(&other.y), - z: self.z.ge(&other.z), - } - } - - #[inline] - fn cmpgt(self, other: Self) -> Self::Mask { - Self::Mask { - x: self.x.gt(&other.x), - y: self.y.gt(&other.y), - z: self.z.gt(&other.z), - } - } - - #[inline] - fn cmple(self, other: Self) -> Self::Mask { - Self::Mask { - x: self.x.le(&other.x), - y: self.y.le(&other.y), - z: self.z.le(&other.z), - } - } - - #[inline] - fn cmplt(self, other: Self) -> Self::Mask { - Self::Mask { - x: self.x.lt(&other.x), - y: self.y.lt(&other.y), - z: self.z.lt(&other.z), - } - } - - #[inline] - fn add(self, other: Self) -> Self { - Self { - x: self.x + other.x, - y: self.y + other.y, - z: self.z + other.z, - } - } - - #[inline] - fn div(self, other: Self) -> Self { - Self { - x: self.x / other.x, - y: self.y / other.y, - z: self.z / other.z, - } - } - - #[inline] - fn mul(self, other: Self) -> Self { - Self { - x: self.x * other.x, - y: self.y * other.y, - z: self.z * other.z, - } - } - - #[inline] - fn sub(self, other: Self) -> Self { - Self { - x: self.x - other.x, - y: self.y - other.y, - z: self.z - other.z, - } - } - - fn add_scalar(self, other: T) -> Self { - Self { - x: self.x + other, - y: self.y + other, - z: self.z + other, - } - } - - fn sub_scalar(self, other: T) -> Self { - Self { - x: self.x - other, - y: self.y - other, - z: self.z - other, - } - } - - #[inline] - fn mul_scalar(self, other: T) -> Self { - Self { - x: self.x * other, - y: self.y * other, - z: self.z * other, - } - } - - #[inline] - fn div_scalar(self, other: T) -> Self { - Self { - x: self.x / other, - y: self.y / other, - z: self.z / other, - } - } - - #[inline] - fn rem(self, other: Self) -> Self { - Self { - x: self.x % other.x, - y: self.y % other.y, - z: self.z % other.z, - } - } - - #[inline] - fn rem_scalar(self, other: T) -> Self { - Self { - x: self.x % other, - y: self.y % other, - z: self.z % other, - } - } - - #[inline] - fn min(self, other: Self) -> Self { - Self { - x: self.x.min(other.x), - y: self.y.min(other.y), - z: self.z.min(other.z), - } - } - - #[inline] - fn max(self, other: Self) -> Self { - Self { - x: self.x.max(other.x), - y: self.y.max(other.y), - z: self.z.max(other.z), - } - } -} - -impl Vector for XYZW { - type Mask = XYZW; - - #[inline] - fn splat(s: T) -> Self { - Self { - x: s, - y: s, - z: s, - w: s, - } - } - - #[inline] - fn select(mask: Self::Mask, if_true: Self, if_false: Self) -> Self { - Self { - x: if mask.x { if_true.x } else { if_false.x }, - y: if mask.y { if_true.y } else { if_false.y }, - z: if mask.z { if_true.z } else { if_false.z }, - w: if mask.w { if_true.w } else { if_false.w }, - } - } - - #[inline] - fn cmpeq(self, other: Self) -> Self::Mask { - Self::Mask { - x: self.x.eq(&other.x), - y: self.y.eq(&other.y), - z: self.z.eq(&other.z), - w: self.w.eq(&other.w), - } - } - - #[inline] - fn cmpne(self, other: Self) -> Self::Mask { - Self::Mask { - x: self.x.ne(&other.x), - y: self.y.ne(&other.y), - z: self.z.ne(&other.z), - w: self.w.ne(&other.w), - } - } - - #[inline] - fn cmpge(self, other: Self) -> Self::Mask { - Self::Mask { - x: self.x.ge(&other.x), - y: self.y.ge(&other.y), - z: self.z.ge(&other.z), - w: self.w.ge(&other.w), - } - } - - #[inline] - fn cmpgt(self, other: Self) -> Self::Mask { - Self::Mask { - x: self.x.gt(&other.x), - y: self.y.gt(&other.y), - z: self.z.gt(&other.z), - w: self.w.gt(&other.w), - } - } - - #[inline] - fn cmple(self, other: Self) -> Self::Mask { - Self::Mask { - x: self.x.le(&other.x), - y: self.y.le(&other.y), - z: self.z.le(&other.z), - w: self.w.le(&other.w), - } - } - - #[inline] - fn cmplt(self, other: Self) -> Self::Mask { - Self::Mask { - x: self.x.lt(&other.x), - y: self.y.lt(&other.y), - z: self.z.lt(&other.z), - w: self.w.lt(&other.w), - } - } - - #[inline] - fn add(self, other: Self) -> Self { - Self { - x: self.x + other.x, - y: self.y + other.y, - z: self.z + other.z, - w: self.w + other.w, - } - } - - #[inline] - fn div(self, other: Self) -> Self { - Self { - x: self.x / other.x, - y: self.y / other.y, - z: self.z / other.z, - w: self.w / other.w, - } - } - - #[inline] - fn mul(self, other: Self) -> Self { - Self { - x: self.x * other.x, - y: self.y * other.y, - z: self.z * other.z, - w: self.w * other.w, - } - } - - #[inline] - fn sub(self, other: Self) -> Self { - Self { - x: self.x - other.x, - y: self.y - other.y, - z: self.z - other.z, - w: self.w - other.w, - } - } - - fn add_scalar(self, other: T) -> Self { - Self { - x: self.x + other, - y: self.y + other, - z: self.z + other, - w: self.w + other, - } - } - - fn sub_scalar(self, other: T) -> Self { - Self { - x: self.x - other, - y: self.y - other, - z: self.z - other, - w: self.w - other, - } - } - - #[inline] - fn mul_scalar(self, other: T) -> Self { - Self { - x: self.x * other, - y: self.y * other, - z: self.z * other, - w: self.w * other, - } - } - - #[inline] - fn div_scalar(self, other: T) -> Self { - Self { - x: self.x / other, - y: self.y / other, - z: self.z / other, - w: self.w / other, - } - } - - #[inline] - fn rem(self, other: Self) -> Self { - Self { - x: self.x % other.x, - y: self.y % other.y, - z: self.z % other.z, - w: self.w % other.w, - } - } - - #[inline] - fn rem_scalar(self, other: T) -> Self { - Self { - x: self.x % other, - y: self.y % other, - z: self.z % other, - w: self.w % other, - } - } - - #[inline] - fn min(self, other: Self) -> Self { - Self { - x: self.x.min(other.x), - y: self.y.min(other.y), - z: self.z.min(other.z), - w: self.w.min(other.w), - } - } - - #[inline] - fn max(self, other: Self) -> Self { - Self { - x: self.x.max(other.x), - y: self.y.max(other.y), - z: self.z.max(other.z), - w: self.w.max(other.w), - } - } -} - -impl Vector2 for XY { - #[inline(always)] - fn new(x: T, y: T) -> Self { - Self { x, y } - } - - #[inline(always)] - fn x(self) -> T { - self.x - } - - #[inline(always)] - fn y(self) -> T { - self.y - } - - #[inline(always)] - fn as_ref_xy(&self) -> &XY { - self - } - - #[inline(always)] - fn as_mut_xy(&mut self) -> &mut XY { - self - } - - #[inline] - fn min_element(self) -> T { - self.x.min(self.y) - } - - #[inline] - fn max_element(self) -> T { - self.x.max(self.y) - } - - #[inline] - fn clamp(self, min: Self, max: Self) -> Self { - glam_assert!(min.x <= max.x); - glam_assert!(min.y <= max.y); - // we intentionally do not use `f32::clamp` because we don't - // want panics unless `glam-assert` feature is on. - Self { - x: self.x.max(min.x).min(max.x), - y: self.y.max(min.y).min(max.y), - } - } -} - -impl Vector3 for XYZ { - #[inline(always)] - fn new(x: T, y: T, z: T) -> Self { - Self { x, y, z } - } - - #[inline(always)] - fn x(self) -> T { - self.x - } - - #[inline(always)] - fn y(self) -> T { - self.y - } - - #[inline(always)] - fn z(self) -> T { - self.z - } - - #[inline(always)] - fn as_ref_xyz(&self) -> &XYZ { - self - } - - #[inline(always)] - fn as_mut_xyz(&mut self) -> &mut XYZ { - self - } - - #[inline] - fn min_element(self) -> T { - self.x.min(self.y.min(self.z)) - } - - #[inline] - fn max_element(self) -> T { - self.x.max(self.y.max(self.z)) - } - - #[inline] - fn clamp(self, min: Self, max: Self) -> Self { - glam_assert!(min.x <= max.x); - glam_assert!(min.y <= max.y); - glam_assert!(min.z <= max.z); - // we intentionally do not use `f32::clamp` because we don't - // want panics unless `glam-assert` feature is on. - Self::new( - self.x.max(min.x).min(max.x), - self.y.max(min.y).min(max.y), - self.z.max(min.z).min(max.z), - ) - } -} - -impl Vector4 for XYZW { - #[inline(always)] - fn new(x: T, y: T, z: T, w: T) -> Self { - Self { x, y, z, w } - } - - #[inline(always)] - fn x(self) -> T { - self.x - } - - #[inline(always)] - fn y(self) -> T { - self.y - } - - #[inline(always)] - fn z(self) -> T { - self.z - } - - #[inline(always)] - fn w(self) -> T { - self.w - } - - #[inline(always)] - fn as_ref_xyzw(&self) -> &XYZW { - self - } - - #[inline(always)] - fn as_mut_xyzw(&mut self) -> &mut XYZW { - self - } - - #[inline] - fn min_element(self) -> T { - self.x.min(self.y.min(self.z.min(self.w))) - } - - #[inline] - fn max_element(self) -> T { - self.x.max(self.y.max(self.z.max(self.w))) - } - - #[inline] - fn clamp(self, min: Self, max: Self) -> Self { - glam_assert!(min.x <= max.x); - glam_assert!(min.y <= max.y); - glam_assert!(min.z <= max.z); - glam_assert!(min.w <= max.w); - // we intentionally do not use `f32::clamp` because we don't - // want panics unless `glam-assert` feature is on. - Self { - x: self.x.max(min.x).min(max.x), - y: self.y.max(min.y).min(max.y), - z: self.z.max(min.z).min(max.z), - w: self.w.max(min.w).min(max.w), - } - } -} - -impl SignedVector for XY { - #[inline] - fn neg(self) -> Self { - Self { - x: self.x.neg(), - y: self.y.neg(), - } - } -} - -impl SignedVector2 for XY {} - -impl SignedVector for XYZ { - #[inline] - fn neg(self) -> Self { - Self { - x: self.x.neg(), - y: self.y.neg(), - z: self.z.neg(), - } - } -} - -impl SignedVector for XYZW { - #[inline] - fn neg(self) -> Self { - Self { - x: self.x.neg(), - y: self.y.neg(), - z: self.z.neg(), - w: self.w.neg(), - } - } -} - -impl SignedVector3 for XYZ {} -impl SignedVector4 for XYZW {} - -impl FloatVector2 for XY {} -impl FloatVector3 for XYZ {} -impl FloatVector4 for XYZW {} - -impl From> for XY { - #[inline(always)] - fn from(v: XYZ) -> Self { - Self { x: v.x, y: v.y } - } -} - -impl From> for XY { - #[inline(always)] - fn from(v: XYZW) -> Self { - Self { x: v.x, y: v.y } - } -} - -impl From> for XYZ { - #[inline(always)] - fn from(v: XYZW) -> Self { - Self { - x: v.x, - y: v.y, - z: v.z, - } - } -} - -impl VectorConst for XYZF32A16 { - const ZERO: Self = Self { - x: 0.0, - y: 0.0, - z: 0.0, - }; - const ONE: Self = Self { - x: 1.0, - y: 1.0, - z: 1.0, - }; -} - -impl NanConstEx for XYZF32A16 { - const NAN: Self = Self { - x: f32::NAN, - y: f32::NAN, - z: f32::NAN, - }; -} - -impl Vector3Const for XYZF32A16 { - const X: Self = Self { - x: 1.0, - y: 0.0, - z: 0.0, - }; - const Y: Self = Self { - x: 0.0, - y: 1.0, - z: 0.0, - }; - const Z: Self = Self { - x: 0.0, - y: 0.0, - z: 1.0, - }; -} - -impl Vector for XYZF32A16 { - type Mask = XYZ; - - #[inline] - fn splat(s: f32) -> Self { - Self { x: s, y: s, z: s } - } - - #[inline] - fn select(mask: Self::Mask, if_true: Self, if_false: Self) -> Self { - XYZ::select(mask, if_true.into(), if_false.into()).into() - } - - #[inline] - fn cmpeq(self, other: Self) -> Self::Mask { - XYZ::cmpeq(self.into(), other.into()) - } - - #[inline] - fn cmpne(self, other: Self) -> Self::Mask { - XYZ::cmpne(self.into(), other.into()) - } - - #[inline] - fn cmpge(self, other: Self) -> Self::Mask { - XYZ::cmpge(self.into(), other.into()) - } - - #[inline] - fn cmpgt(self, other: Self) -> Self::Mask { - XYZ::cmpgt(self.into(), other.into()) - } - - #[inline] - fn cmple(self, other: Self) -> Self::Mask { - XYZ::cmple(self.into(), other.into()) - } - - #[inline] - fn cmplt(self, other: Self) -> Self::Mask { - XYZ::cmplt(self.into(), other.into()) - } - - #[inline] - fn add(self, other: Self) -> Self { - XYZ::add(self.into(), other.into()).into() - } - - #[inline] - fn div(self, other: Self) -> Self { - XYZ::div(self.into(), other.into()).into() - } - - #[inline] - fn mul(self, other: Self) -> Self { - XYZ::mul(self.into(), other.into()).into() - } - - #[inline] - fn rem(self, other: Self) -> Self { - XYZ::rem(self.into(), other.into()).into() - } - - #[inline] - fn sub(self, other: Self) -> Self { - XYZ::sub(self.into(), other.into()).into() - } - - #[inline] - fn add_scalar(self, other: f32) -> Self { - XYZ::add_scalar(self.into(), other).into() - } - - #[inline] - fn sub_scalar(self, other: f32) -> Self { - XYZ::sub_scalar(self.into(), other).into() - } - - #[inline] - fn mul_scalar(self, other: f32) -> Self { - XYZ::mul_scalar(self.into(), other).into() - } - - #[inline] - fn div_scalar(self, other: f32) -> Self { - XYZ::div_scalar(self.into(), other).into() - } - - #[inline] - fn rem_scalar(self, other: f32) -> Self { - XYZ::rem_scalar(self.into(), other).into() - } - - #[inline] - fn min(self, other: Self) -> Self { - XYZ::min(self.into(), other.into()).into() - } - - #[inline] - fn max(self, other: Self) -> Self { - XYZ::max(self.into(), other.into()).into() - } -} - -impl Vector3 for XYZF32A16 { - #[inline(always)] - fn new(x: f32, y: f32, z: f32) -> Self { - XYZF32A16 { x, y, z } - } - - #[inline(always)] - fn x(self) -> f32 { - self.x - } - - #[inline(always)] - fn y(self) -> f32 { - self.y - } - - #[inline(always)] - fn z(self) -> f32 { - self.z - } - - #[inline(always)] - fn as_ref_xyz(&self) -> &XYZ { - unsafe { &*(self as *const Self).cast() } - } - - #[inline(always)] - fn as_mut_xyz(&mut self) -> &mut XYZ { - unsafe { &mut *(self as *mut Self).cast() } - } - - #[inline(always)] - fn min_element(self) -> f32 { - XYZ::min_element(self.into()) - } - - #[inline(always)] - fn max_element(self) -> f32 { - XYZ::max_element(self.into()) - } - - #[inline(always)] - fn clamp(self, min: Self, max: Self) -> Self { - XYZ::clamp(self.into(), min.into(), max.into()).into() - } -} - -impl SignedVector for XYZF32A16 { - #[inline(always)] - fn neg(self) -> Self { - XYZ::neg(self.into()).into() - } -} - -impl SignedVector3 for XYZF32A16 {} -impl FloatVector3 for XYZF32A16 {} - -// 2D bitwise and shifting - -impl ScalarShiftOps for XY -where - T: IntegerShiftOps, - Rhs: Copy, -{ - #[inline(always)] - fn scalar_shl(self, rhs: Rhs) -> Self { - Self { - x: self.x << rhs, - y: self.y << rhs, - } - } - - #[inline(always)] - fn scalar_shr(self, rhs: Rhs) -> Self { - Self { - x: self.x >> rhs, - y: self.y >> rhs, - } - } -} - -impl ScalarBitOps for XY -where - T: Copy + IntegerBitOps, -{ - #[inline(always)] - fn scalar_bitand(self, rhs: T) -> Self { - Self { - x: self.x & rhs, - y: self.y & rhs, - } - } - - #[inline(always)] - fn scalar_bitor(self, rhs: T) -> Self { - Self { - x: self.x | rhs, - y: self.y | rhs, - } - } - - #[inline(always)] - fn scalar_bitxor(self, rhs: T) -> Self { - Self { - x: self.x ^ rhs, - y: self.y ^ rhs, - } - } -} - -impl VectorShiftOps> for XY -where - T: Copy + IntegerShiftOps, -{ - #[inline(always)] - fn vector_shl(self, rhs: XY) -> Self { - Self { - x: self.x << rhs.x, - y: self.y << rhs.y, - } - } - - #[inline(always)] - fn vector_shr(self, rhs: XY) -> Self { - Self { - x: self.x >> rhs.x, - y: self.y >> rhs.y, - } - } -} - -impl VectorBitOps> for XY -where - T: Copy + IntegerBitOps, -{ - #[inline(always)] - fn not(self) -> Self { - Self { - x: !self.x, - y: !self.y, - } - } - - #[inline(always)] - fn vector_bitand(self, rhs: Self) -> Self { - Self { - x: self.x & rhs.x, - y: self.y & rhs.y, - } - } - - #[inline(always)] - fn vector_bitor(self, rhs: Self) -> Self { - Self { - x: self.x | rhs.x, - y: self.y | rhs.y, - } - } - - #[inline(always)] - fn vector_bitxor(self, rhs: Self) -> Self { - Self { - x: self.x ^ rhs.x, - y: self.y ^ rhs.y, - } - } -} - -// 3D bitwise and shifting - -impl ScalarShiftOps for XYZ -where - T: IntegerShiftOps, - Rhs: Copy, -{ - #[inline(always)] - fn scalar_shl(self, rhs: Rhs) -> Self { - Self { - x: self.x << rhs, - y: self.y << rhs, - z: self.z << rhs, - } - } - - #[inline(always)] - fn scalar_shr(self, rhs: Rhs) -> Self { - Self { - x: self.x >> rhs, - y: self.y >> rhs, - z: self.z >> rhs, - } - } -} - -impl ScalarBitOps for XYZ -where - T: Copy + IntegerBitOps, -{ - #[inline(always)] - fn scalar_bitand(self, rhs: T) -> Self { - Self { - x: self.x & rhs, - y: self.y & rhs, - z: self.z & rhs, - } - } - - #[inline(always)] - fn scalar_bitor(self, rhs: T) -> Self { - Self { - x: self.x | rhs, - y: self.y | rhs, - z: self.z | rhs, - } - } - - #[inline(always)] - fn scalar_bitxor(self, rhs: T) -> Self { - Self { - x: self.x ^ rhs, - y: self.y ^ rhs, - z: self.z ^ rhs, - } - } -} - -impl VectorShiftOps> for XYZ -where - T: Copy + IntegerShiftOps, -{ - #[inline(always)] - fn vector_shl(self, rhs: XYZ) -> Self { - Self { - x: self.x << rhs.x, - y: self.y << rhs.y, - z: self.z << rhs.z, - } - } - - #[inline(always)] - fn vector_shr(self, rhs: XYZ) -> Self { - Self { - x: self.x >> rhs.x, - y: self.y >> rhs.y, - z: self.z >> rhs.z, - } - } -} - -impl VectorBitOps> for XYZ -where - T: Copy + IntegerBitOps, -{ - #[inline(always)] - fn not(self) -> Self { - Self { - x: !self.x, - y: !self.y, - z: !self.z, - } - } - - #[inline(always)] - fn vector_bitand(self, rhs: Self) -> Self { - Self { - x: self.x & rhs.x, - y: self.y & rhs.y, - z: self.z & rhs.z, - } - } - - #[inline(always)] - fn vector_bitor(self, rhs: Self) -> Self { - Self { - x: self.x | rhs.x, - y: self.y | rhs.y, - z: self.z | rhs.z, - } - } - - #[inline(always)] - fn vector_bitxor(self, rhs: Self) -> Self { - Self { - x: self.x ^ rhs.x, - y: self.y ^ rhs.y, - z: self.z ^ rhs.z, - } - } -} - -// 4D bitwise and shifting - -impl ScalarShiftOps for XYZW -where - T: IntegerShiftOps, - Rhs: Copy, -{ - #[inline(always)] - fn scalar_shl(self, rhs: Rhs) -> Self { - Self { - x: self.x << rhs, - y: self.y << rhs, - z: self.z << rhs, - w: self.w << rhs, - } - } - - #[inline(always)] - fn scalar_shr(self, rhs: Rhs) -> Self { - Self { - x: self.x >> rhs, - y: self.y >> rhs, - z: self.z >> rhs, - w: self.w >> rhs, - } - } -} - -impl ScalarBitOps for XYZW -where - T: Copy + IntegerBitOps, -{ - #[inline(always)] - fn scalar_bitand(self, rhs: T) -> Self { - Self { - x: self.x & rhs, - y: self.y & rhs, - z: self.z & rhs, - w: self.w & rhs, - } - } - - #[inline(always)] - fn scalar_bitor(self, rhs: T) -> Self { - Self { - x: self.x | rhs, - y: self.y | rhs, - z: self.z | rhs, - w: self.w | rhs, - } - } - - #[inline(always)] - fn scalar_bitxor(self, rhs: T) -> Self { - Self { - x: self.x ^ rhs, - y: self.y ^ rhs, - z: self.z ^ rhs, - w: self.w ^ rhs, - } - } -} - -impl VectorShiftOps> for XYZW -where - T: Copy + IntegerShiftOps, -{ - #[inline(always)] - fn vector_shl(self, rhs: XYZW) -> Self { - Self { - x: self.x << rhs.x, - y: self.y << rhs.y, - z: self.z << rhs.z, - w: self.w << rhs.w, - } - } - - #[inline(always)] - fn vector_shr(self, rhs: XYZW) -> Self { - Self { - x: self.x >> rhs.x, - y: self.y >> rhs.y, - z: self.z >> rhs.z, - w: self.w >> rhs.w, - } - } -} - -impl VectorBitOps> for XYZW -where - T: Copy + IntegerBitOps, -{ - #[inline(always)] - fn not(self) -> Self { - Self { - x: !self.x, - y: !self.y, - z: !self.z, - w: !self.w, - } - } - - #[inline(always)] - fn vector_bitand(self, rhs: Self) -> Self { - Self { - x: self.x & rhs.x, - y: self.y & rhs.y, - z: self.z & rhs.z, - w: self.w & rhs.w, - } - } - - #[inline(always)] - fn vector_bitor(self, rhs: Self) -> Self { - Self { - x: self.x | rhs.x, - y: self.y | rhs.y, - z: self.z | rhs.z, - w: self.w | rhs.w, - } - } - - #[inline(always)] - fn vector_bitxor(self, rhs: Self) -> Self { - Self { - x: self.x ^ rhs.x, - y: self.y ^ rhs.y, - z: self.z ^ rhs.z, - w: self.w ^ rhs.w, - } - } -} diff --git a/src/core/sse2.rs b/src/core/sse2.rs deleted file mode 100644 index 4b78bfa7..00000000 --- a/src/core/sse2.rs +++ /dev/null @@ -1,4 +0,0 @@ -mod float; -pub mod matrix; -pub mod quaternion; -pub mod vector; diff --git a/src/core/sse2/matrix.rs b/src/core/sse2/matrix.rs deleted file mode 100644 index 58509283..00000000 --- a/src/core/sse2/matrix.rs +++ /dev/null @@ -1,558 +0,0 @@ -#[cfg(target_arch = "x86")] -use core::arch::x86::*; -#[cfg(target_arch = "x86_64")] -use core::arch::x86_64::*; - -use core::mem::MaybeUninit; - -use crate::core::{ - storage::{Align16, Columns2, Columns3, Columns4, XY, XYZ}, - traits::{ - matrix::{ - FloatMatrix2x2, FloatMatrix3x3, FloatMatrix4x4, Matrix, Matrix2x2, Matrix3x3, - Matrix4x4, MatrixConst, - }, - projection::ProjectionMatrix, - scalar::NanConstEx, - vector::{FloatVector4, Vector, Vector4, Vector4Const}, - }, -}; - -// __m128 as a Matrix2x2 -impl MatrixConst for __m128 { - const ZERO: __m128 = const_f32x4!([0.0, 0.0, 0.0, 0.0]); - const IDENTITY: __m128 = const_f32x4!([1.0, 0.0, 0.0, 1.0]); -} - -impl Matrix for __m128 {} - -impl Matrix2x2> for __m128 { - #[inline(always)] - fn new(m00: f32, m01: f32, m10: f32, m11: f32) -> Self { - unsafe { _mm_set_ps(m11, m10, m01, m00) } - } - - #[inline(always)] - fn from_cols(x_axis: XY, y_axis: XY) -> Self { - Matrix2x2::new(x_axis.x, x_axis.y, y_axis.x, y_axis.y) - } - - #[inline(always)] - fn x_axis(&self) -> &XY { - unsafe { &(*(self as *const Self).cast::>>()).x_axis } - } - - #[inline(always)] - fn y_axis(&self) -> &XY { - unsafe { &(*(self as *const Self).cast::>>()).y_axis } - } - - #[inline] - fn determinant(&self) -> f32 { - // self.x_axis.x * self.y_axis.y - self.x_axis.y * self.y_axis.x - unsafe { - let abcd = *self; - let dcba = _mm_shuffle_ps(abcd, abcd, 0b00_01_10_11); - let prod = _mm_mul_ps(abcd, dcba); - let det = _mm_sub_ps(prod, _mm_shuffle_ps(prod, prod, 0b01_01_01_01)); - _mm_cvtss_f32(det) - } - } - - #[inline(always)] - fn transpose(&self) -> Self { - unsafe { _mm_shuffle_ps(*self, *self, 0b11_01_10_00) } - } - - #[inline] - fn mul_vector(&self, other: XY) -> XY { - unsafe { - let abcd = *self; - let xxyy = _mm_set_ps(other.y, other.y, other.x, other.x); - let axbxcydy = _mm_mul_ps(abcd, xxyy); - let cydyaxbx = _mm_shuffle_ps(axbxcydy, axbxcydy, 0b01_00_11_10); - let result = _mm_add_ps(axbxcydy, cydyaxbx); - let mut out: MaybeUninit>> = MaybeUninit::uninit(); - _mm_store_ps(out.as_mut_ptr().cast(), result); - out.assume_init().0 - } - } - - #[inline] - fn mul_matrix(&self, other: &Self) -> Self { - unsafe { - let abcd = *self; - let other = *other; - let xxyy0 = _mm_shuffle_ps(other, other, 0b01_01_00_00); - let xxyy1 = _mm_shuffle_ps(other, other, 0b11_11_10_10); - let axbxcydy0 = _mm_mul_ps(abcd, xxyy0); - let axbxcydy1 = _mm_mul_ps(abcd, xxyy1); - let cydyaxbx0 = _mm_shuffle_ps(axbxcydy0, axbxcydy0, 0b01_00_11_10); - let cydyaxbx1 = _mm_shuffle_ps(axbxcydy1, axbxcydy1, 0b01_00_11_10); - let result0 = _mm_add_ps(axbxcydy0, cydyaxbx0); - let result1 = _mm_add_ps(axbxcydy1, cydyaxbx1); - _mm_shuffle_ps(result0, result1, 0b01_00_01_00) - } - } - - #[inline] - fn mul_scalar(&self, other: f32) -> Self { - unsafe { _mm_mul_ps(*self, _mm_set_ps1(other)) } - } - - #[inline] - fn add_matrix(&self, other: &Self) -> Self { - unsafe { _mm_add_ps(*self, *other) } - } - - #[inline] - fn sub_matrix(&self, other: &Self) -> Self { - unsafe { _mm_sub_ps(*self, *other) } - } -} - -impl FloatMatrix2x2> for __m128 { - #[inline] - fn abs_diff_eq(&self, other: &Self, max_abs_diff: f32) -> bool { - FloatVector4::abs_diff_eq(*self, *other, max_abs_diff) - } - - #[inline] - fn inverse(&self) -> Self { - unsafe { - const SIGN: __m128 = const_f32x4!([1.0, -1.0, -1.0, 1.0]); - let abcd = *self; - let dcba = _mm_shuffle_ps(abcd, abcd, 0b00_01_10_11); - let prod = _mm_mul_ps(abcd, dcba); - let sub = _mm_sub_ps(prod, _mm_shuffle_ps(prod, prod, 0b01_01_01_01)); - let det = _mm_shuffle_ps(sub, sub, 0b00_00_00_00); - let tmp = _mm_div_ps(SIGN, det); - glam_assert!(tmp.is_finite()); - let dbca = _mm_shuffle_ps(abcd, abcd, 0b00_10_01_11); - _mm_mul_ps(dbca, tmp) - } - } - - #[inline] - fn neg_matrix(&self) -> Self { - unsafe { _mm_xor_ps(*self, _mm_set1_ps(-0.0)) } - } -} - -impl MatrixConst for Columns3<__m128> { - const ZERO: Columns3<__m128> = Columns3 { - x_axis: __m128::ZERO, - y_axis: __m128::ZERO, - z_axis: __m128::ZERO, - }; - const IDENTITY: Columns3<__m128> = Columns3 { - x_axis: __m128::X, - y_axis: __m128::Y, - z_axis: __m128::Z, - }; -} - -impl NanConstEx for Columns3<__m128> { - const NAN: Columns3<__m128> = Columns3 { - x_axis: __m128::NAN, - y_axis: __m128::NAN, - z_axis: __m128::NAN, - }; -} - -impl Matrix for Columns3<__m128> {} - -impl Matrix3x3 for Columns3<__m128> { - #[inline(always)] - fn from_cols(x_axis: __m128, y_axis: __m128, z_axis: __m128) -> Self { - Self { - x_axis, - y_axis, - z_axis, - } - } - - #[inline(always)] - fn x_axis(&self) -> &__m128 { - &self.x_axis - } - - #[inline(always)] - fn y_axis(&self) -> &__m128 { - &self.y_axis - } - - #[inline(always)] - fn z_axis(&self) -> &__m128 { - &self.z_axis - } - - #[inline] - fn transpose(&self) -> Self { - unsafe { - let tmp0 = _mm_shuffle_ps(self.x_axis, self.y_axis, 0b01_00_01_00); - let tmp1 = _mm_shuffle_ps(self.x_axis, self.y_axis, 0b11_10_11_10); - - Self { - x_axis: _mm_shuffle_ps(tmp0, self.z_axis, 0b00_00_10_00), - y_axis: _mm_shuffle_ps(tmp0, self.z_axis, 0b01_01_11_01), - z_axis: _mm_shuffle_ps(tmp1, self.z_axis, 0b10_10_10_00), - } - } - } -} - -impl FloatMatrix3x3 for Columns3<__m128> { - #[inline] - fn transform_point2(&self, other: XY) -> XY { - let mut res = self.x_axis.mul_scalar(other.x); - res = self.y_axis.mul_scalar(other.y).add(res); - res = self.z_axis.add(res); - res.into() - } - - #[inline] - fn transform_vector2(&self, other: XY) -> XY { - let mut res = self.x_axis.mul_scalar(other.x); - res = self.y_axis.mul_scalar(other.y).add(res); - res.into() - } -} - -impl MatrixConst for Columns4<__m128> { - const ZERO: Columns4<__m128> = Columns4 { - x_axis: __m128::ZERO, - y_axis: __m128::ZERO, - z_axis: __m128::ZERO, - w_axis: __m128::ZERO, - }; - const IDENTITY: Columns4<__m128> = Columns4 { - x_axis: __m128::X, - y_axis: __m128::Y, - z_axis: __m128::Z, - w_axis: __m128::W, - }; -} - -impl NanConstEx for Columns4<__m128> { - const NAN: Columns4<__m128> = Columns4 { - x_axis: __m128::NAN, - y_axis: __m128::NAN, - z_axis: __m128::NAN, - w_axis: __m128::NAN, - }; -} - -impl Matrix for Columns4<__m128> {} - -impl Matrix4x4 for Columns4<__m128> { - #[inline(always)] - fn from_cols(x_axis: __m128, y_axis: __m128, z_axis: __m128, w_axis: __m128) -> Self { - Self { - x_axis, - y_axis, - z_axis, - w_axis, - } - } - - #[inline(always)] - fn x_axis(&self) -> &__m128 { - &self.x_axis - } - - #[inline(always)] - fn y_axis(&self) -> &__m128 { - &self.y_axis - } - - #[inline(always)] - fn z_axis(&self) -> &__m128 { - &self.z_axis - } - - #[inline(always)] - fn w_axis(&self) -> &__m128 { - &self.w_axis - } - - #[inline] - fn determinant(&self) -> f32 { - unsafe { - // SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; - // SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; - // SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; - // SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; - // SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; - // SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; - - // Based on https://github.com/g-truc/glm `glm_mat4_determinant_lowp` - let swp2a = _mm_shuffle_ps(self.z_axis, self.z_axis, 0b00_01_01_10); - let swp3a = _mm_shuffle_ps(self.w_axis, self.w_axis, 0b11_10_11_11); - let swp2b = _mm_shuffle_ps(self.z_axis, self.z_axis, 0b11_10_11_11); - let swp3b = _mm_shuffle_ps(self.w_axis, self.w_axis, 0b00_01_01_10); - let swp2c = _mm_shuffle_ps(self.z_axis, self.z_axis, 0b00_00_01_10); - let swp3c = _mm_shuffle_ps(self.w_axis, self.w_axis, 0b01_10_00_00); - - let mula = _mm_mul_ps(swp2a, swp3a); - let mulb = _mm_mul_ps(swp2b, swp3b); - let mulc = _mm_mul_ps(swp2c, swp3c); - let sube = _mm_sub_ps(mula, mulb); - let subf = _mm_sub_ps(_mm_movehl_ps(mulc, mulc), mulc); - - let subfaca = _mm_shuffle_ps(sube, sube, 0b10_01_00_00); - let swpfaca = _mm_shuffle_ps(self.y_axis, self.y_axis, 0b00_00_00_01); - let mulfaca = _mm_mul_ps(swpfaca, subfaca); - - let subtmpb = _mm_shuffle_ps(sube, subf, 0b00_00_11_01); - let subfacb = _mm_shuffle_ps(subtmpb, subtmpb, 0b11_01_01_00); - let swpfacb = _mm_shuffle_ps(self.y_axis, self.y_axis, 0b01_01_10_10); - let mulfacb = _mm_mul_ps(swpfacb, subfacb); - - let subres = _mm_sub_ps(mulfaca, mulfacb); - let subtmpc = _mm_shuffle_ps(sube, subf, 0b01_00_10_10); - let subfacc = _mm_shuffle_ps(subtmpc, subtmpc, 0b11_11_10_00); - let swpfacc = _mm_shuffle_ps(self.y_axis, self.y_axis, 0b10_11_11_11); - let mulfacc = _mm_mul_ps(swpfacc, subfacc); - - let addres = _mm_add_ps(subres, mulfacc); - let detcof = _mm_mul_ps(addres, _mm_setr_ps(1.0, -1.0, 1.0, -1.0)); - - Vector4::dot(self.x_axis, detcof) - } - } - - #[inline] - fn transpose(&self) -> Self { - unsafe { - // Based on https://github.com/microsoft/DirectXMath `XMMatrixTranspose` - let tmp0 = _mm_shuffle_ps(self.x_axis, self.y_axis, 0b01_00_01_00); - let tmp1 = _mm_shuffle_ps(self.x_axis, self.y_axis, 0b11_10_11_10); - let tmp2 = _mm_shuffle_ps(self.z_axis, self.w_axis, 0b01_00_01_00); - let tmp3 = _mm_shuffle_ps(self.z_axis, self.w_axis, 0b11_10_11_10); - - Self { - x_axis: _mm_shuffle_ps(tmp0, tmp2, 0b10_00_10_00), - y_axis: _mm_shuffle_ps(tmp0, tmp2, 0b11_01_11_01), - z_axis: _mm_shuffle_ps(tmp1, tmp3, 0b10_00_10_00), - w_axis: _mm_shuffle_ps(tmp1, tmp3, 0b11_01_11_01), - } - } - } -} - -impl FloatMatrix4x4 for Columns4<__m128> { - type SIMDVector3 = __m128; - - fn inverse(&self) -> Self { - unsafe { - // Based on https://github.com/g-truc/glm `glm_mat4_inverse` - let fac0 = { - let swp0a = _mm_shuffle_ps(self.w_axis, self.z_axis, 0b11_11_11_11); - let swp0b = _mm_shuffle_ps(self.w_axis, self.z_axis, 0b10_10_10_10); - - let swp00 = _mm_shuffle_ps(self.z_axis, self.y_axis, 0b10_10_10_10); - let swp01 = _mm_shuffle_ps(swp0a, swp0a, 0b10_00_00_00); - let swp02 = _mm_shuffle_ps(swp0b, swp0b, 0b10_00_00_00); - let swp03 = _mm_shuffle_ps(self.z_axis, self.y_axis, 0b11_11_11_11); - - let mul00 = _mm_mul_ps(swp00, swp01); - let mul01 = _mm_mul_ps(swp02, swp03); - _mm_sub_ps(mul00, mul01) - }; - let fac1 = { - let swp0a = _mm_shuffle_ps(self.w_axis, self.z_axis, 0b11_11_11_11); - let swp0b = _mm_shuffle_ps(self.w_axis, self.z_axis, 0b01_01_01_01); - - let swp00 = _mm_shuffle_ps(self.z_axis, self.y_axis, 0b01_01_01_01); - let swp01 = _mm_shuffle_ps(swp0a, swp0a, 0b10_00_00_00); - let swp02 = _mm_shuffle_ps(swp0b, swp0b, 0b10_00_00_00); - let swp03 = _mm_shuffle_ps(self.z_axis, self.y_axis, 0b11_11_11_11); - - let mul00 = _mm_mul_ps(swp00, swp01); - let mul01 = _mm_mul_ps(swp02, swp03); - _mm_sub_ps(mul00, mul01) - }; - let fac2 = { - let swp0a = _mm_shuffle_ps(self.w_axis, self.z_axis, 0b10_10_10_10); - let swp0b = _mm_shuffle_ps(self.w_axis, self.z_axis, 0b01_01_01_01); - - let swp00 = _mm_shuffle_ps(self.z_axis, self.y_axis, 0b01_01_01_01); - let swp01 = _mm_shuffle_ps(swp0a, swp0a, 0b10_00_00_00); - let swp02 = _mm_shuffle_ps(swp0b, swp0b, 0b10_00_00_00); - let swp03 = _mm_shuffle_ps(self.z_axis, self.y_axis, 0b10_10_10_10); - - let mul00 = _mm_mul_ps(swp00, swp01); - let mul01 = _mm_mul_ps(swp02, swp03); - _mm_sub_ps(mul00, mul01) - }; - let fac3 = { - let swp0a = _mm_shuffle_ps(self.w_axis, self.z_axis, 0b11_11_11_11); - let swp0b = _mm_shuffle_ps(self.w_axis, self.z_axis, 0b00_00_00_00); - - let swp00 = _mm_shuffle_ps(self.z_axis, self.y_axis, 0b00_00_00_00); - let swp01 = _mm_shuffle_ps(swp0a, swp0a, 0b10_00_00_00); - let swp02 = _mm_shuffle_ps(swp0b, swp0b, 0b10_00_00_00); - let swp03 = _mm_shuffle_ps(self.z_axis, self.y_axis, 0b11_11_11_11); - - let mul00 = _mm_mul_ps(swp00, swp01); - let mul01 = _mm_mul_ps(swp02, swp03); - _mm_sub_ps(mul00, mul01) - }; - let fac4 = { - let swp0a = _mm_shuffle_ps(self.w_axis, self.z_axis, 0b10_10_10_10); - let swp0b = _mm_shuffle_ps(self.w_axis, self.z_axis, 0b00_00_00_00); - - let swp00 = _mm_shuffle_ps(self.z_axis, self.y_axis, 0b00_00_00_00); - let swp01 = _mm_shuffle_ps(swp0a, swp0a, 0b10_00_00_00); - let swp02 = _mm_shuffle_ps(swp0b, swp0b, 0b10_00_00_00); - let swp03 = _mm_shuffle_ps(self.z_axis, self.y_axis, 0b10_10_10_10); - - let mul00 = _mm_mul_ps(swp00, swp01); - let mul01 = _mm_mul_ps(swp02, swp03); - _mm_sub_ps(mul00, mul01) - }; - let fac5 = { - let swp0a = _mm_shuffle_ps(self.w_axis, self.z_axis, 0b01_01_01_01); - let swp0b = _mm_shuffle_ps(self.w_axis, self.z_axis, 0b00_00_00_00); - - let swp00 = _mm_shuffle_ps(self.z_axis, self.y_axis, 0b00_00_00_00); - let swp01 = _mm_shuffle_ps(swp0a, swp0a, 0b10_00_00_00); - let swp02 = _mm_shuffle_ps(swp0b, swp0b, 0b10_00_00_00); - let swp03 = _mm_shuffle_ps(self.z_axis, self.y_axis, 0b01_01_01_01); - - let mul00 = _mm_mul_ps(swp00, swp01); - let mul01 = _mm_mul_ps(swp02, swp03); - _mm_sub_ps(mul00, mul01) - }; - let sign_a = _mm_set_ps(1.0, -1.0, 1.0, -1.0); - let sign_b = _mm_set_ps(-1.0, 1.0, -1.0, 1.0); - - let temp0 = _mm_shuffle_ps(self.y_axis, self.x_axis, 0b00_00_00_00); - let vec0 = _mm_shuffle_ps(temp0, temp0, 0b10_10_10_00); - - let temp1 = _mm_shuffle_ps(self.y_axis, self.x_axis, 0b01_01_01_01); - let vec1 = _mm_shuffle_ps(temp1, temp1, 0b10_10_10_00); - - let temp2 = _mm_shuffle_ps(self.y_axis, self.x_axis, 0b10_10_10_10); - let vec2 = _mm_shuffle_ps(temp2, temp2, 0b10_10_10_00); - - let temp3 = _mm_shuffle_ps(self.y_axis, self.x_axis, 0b11_11_11_11); - let vec3 = _mm_shuffle_ps(temp3, temp3, 0b10_10_10_00); - - let mul00 = _mm_mul_ps(vec1, fac0); - let mul01 = _mm_mul_ps(vec2, fac1); - let mul02 = _mm_mul_ps(vec3, fac2); - let sub00 = _mm_sub_ps(mul00, mul01); - let add00 = _mm_add_ps(sub00, mul02); - let inv0 = _mm_mul_ps(sign_b, add00); - - let mul03 = _mm_mul_ps(vec0, fac0); - let mul04 = _mm_mul_ps(vec2, fac3); - let mul05 = _mm_mul_ps(vec3, fac4); - let sub01 = _mm_sub_ps(mul03, mul04); - let add01 = _mm_add_ps(sub01, mul05); - let inv1 = _mm_mul_ps(sign_a, add01); - - let mul06 = _mm_mul_ps(vec0, fac1); - let mul07 = _mm_mul_ps(vec1, fac3); - let mul08 = _mm_mul_ps(vec3, fac5); - let sub02 = _mm_sub_ps(mul06, mul07); - let add02 = _mm_add_ps(sub02, mul08); - let inv2 = _mm_mul_ps(sign_b, add02); - - let mul09 = _mm_mul_ps(vec0, fac2); - let mul10 = _mm_mul_ps(vec1, fac4); - let mul11 = _mm_mul_ps(vec2, fac5); - let sub03 = _mm_sub_ps(mul09, mul10); - let add03 = _mm_add_ps(sub03, mul11); - let inv3 = _mm_mul_ps(sign_a, add03); - - let row0 = _mm_shuffle_ps(inv0, inv1, 0b00_00_00_00); - let row1 = _mm_shuffle_ps(inv2, inv3, 0b00_00_00_00); - let row2 = _mm_shuffle_ps(row0, row1, 0b10_00_10_00); - - let dot0 = Vector4::dot(self.x_axis, row2); - glam_assert!(dot0 != 0.0); - - let rcp0 = _mm_set1_ps(dot0.recip()); - - Self { - x_axis: _mm_mul_ps(inv0, rcp0), - y_axis: _mm_mul_ps(inv1, rcp0), - z_axis: _mm_mul_ps(inv2, rcp0), - w_axis: _mm_mul_ps(inv3, rcp0), - } - } - } - - #[inline(always)] - fn transform_point3(&self, other: XYZ) -> XYZ { - self.x_axis - .mul_scalar(other.x) - .add(self.y_axis.mul_scalar(other.y)) - .add(self.z_axis.mul_scalar(other.z)) - .add(self.w_axis) - .into() - } - - #[inline(always)] - fn transform_vector3(&self, other: XYZ) -> XYZ { - self.x_axis - .mul_scalar(other.x) - .add(self.y_axis.mul_scalar(other.y)) - .add(self.z_axis.mul_scalar(other.z)) - .into() - } - - #[inline] - fn transform_float4_as_point3(&self, other: __m128) -> __m128 { - let mut res = self.x_axis.mul(Vector4::splat_x(other)); - res = self.y_axis.mul_add(Vector4::splat_y(other), res); - res = self.z_axis.mul_add(Vector4::splat_z(other), res); - res = self.w_axis.add(res); - res - } - - #[inline] - fn transform_float4_as_vector3(&self, other: __m128) -> __m128 { - let mut res = self.x_axis.mul(Vector4::splat_x(other)); - res = self.y_axis.mul_add(Vector4::splat_y(other), res); - res = self.z_axis.mul_add(Vector4::splat_z(other), res); - res - } - - #[inline] - fn project_float4_as_point3(&self, other: __m128) -> __m128 { - let mut res = self.x_axis.mul(Vector4::splat_x(other)); - res = self.y_axis.mul_add(Vector4::splat_y(other), res); - res = self.z_axis.mul_add(Vector4::splat_z(other), res); - res = self.w_axis.add(res); - res = res.mul(res.splat_w().recip()); - res - } -} - -impl ProjectionMatrix for Columns4<__m128> {} - -impl From>> for Columns3<__m128> { - #[inline(always)] - fn from(v: Columns3>) -> Columns3<__m128> { - Self { - x_axis: v.x_axis.into(), - y_axis: v.y_axis.into(), - z_axis: v.z_axis.into(), - } - } -} - -impl From> for Columns3> { - #[inline(always)] - fn from(v: Columns3<__m128>) -> Columns3> { - Self { - x_axis: v.x_axis.into(), - y_axis: v.y_axis.into(), - z_axis: v.z_axis.into(), - } - } -} diff --git a/src/core/sse2/quaternion.rs b/src/core/sse2/quaternion.rs deleted file mode 100644 index 196eb249..00000000 --- a/src/core/sse2/quaternion.rs +++ /dev/null @@ -1,147 +0,0 @@ -#[cfg(target_arch = "x86")] -use core::arch::x86::*; -#[cfg(target_arch = "x86_64")] -use core::arch::x86_64::*; - -use super::float::*; -use crate::core::{ - storage::XYZ, - traits::{quaternion::Quaternion, scalar::*, vector::*}, -}; - -impl Quaternion for __m128 { - type SIMDVector3 = __m128; - - #[inline(always)] - fn conjugate(self) -> Self { - const SIGN: __m128 = const_f32x4!([-0.0, -0.0, -0.0, 0.0]); - unsafe { _mm_xor_ps(self, SIGN) } - } - - #[inline] - fn lerp(self, end: Self, s: f32) -> Self { - glam_assert!(FloatVector4::is_normalized(self)); - glam_assert!(FloatVector4::is_normalized(end)); - - unsafe { - const NEG_ZERO: __m128 = const_f32x4!([-0.0; 4]); - let start = self; - let end = end; - let dot = Vector4::dot_into_vec(start, end); - // Calculate the bias, if the dot product is positive or zero, there is no bias - // but if it is negative, we want to flip the 'end' rotation XYZW components - let bias = _mm_and_ps(dot, NEG_ZERO); - let interpolated = _mm_add_ps( - _mm_mul_ps(_mm_sub_ps(_mm_xor_ps(end, bias), start), _mm_set_ps1(s)), - start, - ); - FloatVector4::normalize(interpolated) - } - } - - #[inline] - fn slerp(self, mut end: Self, s: f32) -> Self { - // http://number-none.com/product/Understanding%20Slerp,%20Then%20Not%20Using%20It/ - glam_assert!(FloatVector4::is_normalized(self)); - glam_assert!(FloatVector4::is_normalized(end)); - - const DOT_THRESHOLD: f32 = 0.9995; - - let mut dot = Vector4::dot(self, end); - - // Note that a rotation can be represented by two quaternions: `q` and - // `-q`. The slerp path between `q` and `end` will be different from the - // path between `-q` and `end`. One path will take the long way around and - // one will take the short way. In order to correct for this, the `dot` - // product between `self` and `end` should be positive. If the `dot` - // product is negative, slerp between `self` and `-end`. - if dot < 0.0 { - const PS_NEGATIVE_ONE: __m128 = const_f32x4!([-1.0; 4]); - end = unsafe { _mm_mul_ps(PS_NEGATIVE_ONE, end) }; - dot = -dot; - } - - if dot > DOT_THRESHOLD { - // assumes lerp returns a normalized quaternion - self.lerp(end, s) - } else { - // assumes scalar_acos clamps the input to [-1.0, 1.0] - let theta = dot.acos_approx(); - - let x = 1.0 - s; - let y = s; - let z = 1.0; - - unsafe { - let tmp = _mm_mul_ps(_mm_set_ps1(theta), _mm_set_ps(0.0, z, y, x)); - let tmp = m128_sin(tmp); - - let scale1 = _mm_shuffle_ps(tmp, tmp, 0b00_00_00_00); - let scale2 = _mm_shuffle_ps(tmp, tmp, 0b01_01_01_01); - let theta_sin = _mm_shuffle_ps(tmp, tmp, 0b10_10_10_10); - - self.mul(scale1).add(end.mul(scale2)).div(theta_sin) - } - } - } - - #[inline] - fn mul_quaternion(self, other: Self) -> Self { - glam_assert!(FloatVector4::is_normalized(self)); - glam_assert!(FloatVector4::is_normalized(other)); - unsafe { - // Based on https://github.com/nfrechette/rtm `rtm::quat_mul` - let lhs = self; - let rhs = other; - - const CONTROL_WZYX: __m128 = const_f32x4!([1.0, -1.0, 1.0, -1.0]); - const CONTROL_ZWXY: __m128 = const_f32x4!([1.0, 1.0, -1.0, -1.0]); - const CONTROL_YXWZ: __m128 = const_f32x4!([-1.0, 1.0, 1.0, -1.0]); - - let r_xxxx = _mm_shuffle_ps(lhs, lhs, 0b00_00_00_00); - let r_yyyy = _mm_shuffle_ps(lhs, lhs, 0b01_01_01_01); - let r_zzzz = _mm_shuffle_ps(lhs, lhs, 0b10_10_10_10); - let r_wwww = _mm_shuffle_ps(lhs, lhs, 0b11_11_11_11); - - let lxrw_lyrw_lzrw_lwrw = _mm_mul_ps(r_wwww, rhs); - let l_wzyx = _mm_shuffle_ps(rhs, rhs, 0b00_01_10_11); - - let lwrx_lzrx_lyrx_lxrx = _mm_mul_ps(r_xxxx, l_wzyx); - let l_zwxy = _mm_shuffle_ps(l_wzyx, l_wzyx, 0b10_11_00_01); - - let lwrx_nlzrx_lyrx_nlxrx = _mm_mul_ps(lwrx_lzrx_lyrx_lxrx, CONTROL_WZYX); - - let lzry_lwry_lxry_lyry = _mm_mul_ps(r_yyyy, l_zwxy); - let l_yxwz = _mm_shuffle_ps(l_zwxy, l_zwxy, 0b00_01_10_11); - - let lzry_lwry_nlxry_nlyry = _mm_mul_ps(lzry_lwry_lxry_lyry, CONTROL_ZWXY); - - let lyrz_lxrz_lwrz_lzrz = _mm_mul_ps(r_zzzz, l_yxwz); - let result0 = _mm_add_ps(lxrw_lyrw_lzrw_lwrw, lwrx_nlzrx_lyrx_nlxrx); - - let nlyrz_lxrz_lwrz_wlzrz = _mm_mul_ps(lyrz_lxrz_lwrz_lzrz, CONTROL_YXWZ); - let result1 = _mm_add_ps(lzry_lwry_nlxry_nlyry, nlyrz_lxrz_lwrz_wlzrz); - _mm_add_ps(result0, result1) - } - } - - #[inline] - fn mul_vector3(self, other: XYZ) -> XYZ { - self.mul_float4_as_vector3(other.into()).into() - } - - #[inline] - fn mul_float4_as_vector3(self, other: __m128) -> __m128 { - glam_assert!(FloatVector4::is_normalized(self)); - unsafe { - const TWO: __m128 = const_f32x4!([2.0; 4]); - let w = _mm_shuffle_ps(self, self, 0b11_11_11_11); - let b = self; - let b2 = Vector3::dot_into_vec(b, b); - other - .mul(w.mul(w).sub(b2)) - .add(b.mul(Vector3::dot_into_vec(other, b).mul(TWO))) - .add(b.cross(other).mul(w.mul(TWO))) - } - } -} diff --git a/src/core/sse2/vector.rs b/src/core/sse2/vector.rs deleted file mode 100644 index d5380ce8..00000000 --- a/src/core/sse2/vector.rs +++ /dev/null @@ -1,871 +0,0 @@ -#![allow(clippy::many_single_char_names)] - -#[cfg(target_arch = "x86")] -use core::arch::x86::*; -#[cfg(target_arch = "x86_64")] -use core::arch::x86_64::*; - -use super::float::*; -use crate::core::{ - storage::{Align16, XY, XYZ, XYZW}, - traits::{scalar::*, vector::*}, -}; -use core::mem::MaybeUninit; - -impl MaskVectorConst for __m128 { - const FALSE: __m128 = const_f32x4!([0.0; 4]); -} - -impl MaskVector for __m128 { - #[inline(always)] - fn bitand(self, other: Self) -> Self { - unsafe { _mm_and_ps(self, other) } - } - - #[inline(always)] - fn bitor(self, other: Self) -> Self { - unsafe { _mm_or_ps(self, other) } - } - - #[inline] - fn not(self) -> Self { - unsafe { _mm_andnot_ps(self, _mm_set_ps1(f32::from_bits(0xff_ff_ff_ff))) } - } -} - -impl MaskVector3 for __m128 { - #[inline(always)] - fn new(x: bool, y: bool, z: bool) -> Self { - // A SSE2 mask can be any bit pattern but for the `MaskVector3` implementation of select we - // expect either 0 or 0xff_ff_ff_ff. This should be a safe assumption as this type can only - // be created via this function or by `Vector3` methods. - - unsafe { - _mm_set_ps( - 0.0, - f32::from_bits(MaskConst::MASK[z as usize]), - f32::from_bits(MaskConst::MASK[y as usize]), - f32::from_bits(MaskConst::MASK[x as usize]), - ) - } - } - - #[inline(always)] - fn bitmask(self) -> u32 { - unsafe { (_mm_movemask_ps(self) as u32) & 0x7 } - } - - #[inline(always)] - fn any(self) -> bool { - unsafe { (_mm_movemask_ps(self) & 0x7) != 0 } - } - - #[inline(always)] - fn all(self) -> bool { - unsafe { (_mm_movemask_ps(self) & 0x7) == 0x7 } - } - - #[inline] - fn into_bool_array(self) -> [bool; 3] { - let bitmask = MaskVector3::bitmask(self); - [(bitmask & 1) != 0, (bitmask & 2) != 0, (bitmask & 4) != 0] - } - - #[inline] - fn into_u32_array(self) -> [u32; 3] { - let bitmask = MaskVector3::bitmask(self); - [ - MaskConst::MASK[(bitmask & 1) as usize], - MaskConst::MASK[((bitmask >> 1) & 1) as usize], - MaskConst::MASK[((bitmask >> 2) & 1) as usize], - ] - } -} - -impl MaskVector4 for __m128 { - #[inline(always)] - fn new(x: bool, y: bool, z: bool, w: bool) -> Self { - // A SSE2 mask can be any bit pattern but for the `Vec4Mask` implementation of select we - // expect either 0 or 0xff_ff_ff_ff. This should be a safe assumption as this type can only - // be created via this function or by `Vec4` methods. - - const MASK: [u32; 2] = [0, 0xff_ff_ff_ff]; - unsafe { - _mm_set_ps( - f32::from_bits(MASK[w as usize]), - f32::from_bits(MASK[z as usize]), - f32::from_bits(MASK[y as usize]), - f32::from_bits(MASK[x as usize]), - ) - } - } - #[inline(always)] - fn bitmask(self) -> u32 { - unsafe { _mm_movemask_ps(self) as u32 } - } - - #[inline(always)] - fn any(self) -> bool { - unsafe { _mm_movemask_ps(self) != 0 } - } - - #[inline(always)] - fn all(self) -> bool { - unsafe { _mm_movemask_ps(self) == 0xf } - } - - #[inline] - fn into_bool_array(self) -> [bool; 4] { - let bitmask = MaskVector4::bitmask(self); - [ - (bitmask & 1) != 0, - (bitmask & 2) != 0, - (bitmask & 4) != 0, - (bitmask & 8) != 0, - ] - } - - #[inline] - fn into_u32_array(self) -> [u32; 4] { - let bitmask = MaskVector4::bitmask(self); - [ - MaskConst::MASK[(bitmask & 1) as usize], - MaskConst::MASK[((bitmask >> 1) & 1) as usize], - MaskConst::MASK[((bitmask >> 2) & 1) as usize], - MaskConst::MASK[((bitmask >> 3) & 1) as usize], - ] - } -} - -/// Calculates the vector 3 dot product and returns answer in x lane of __m128. -#[inline(always)] -unsafe fn dot3_in_x(lhs: __m128, rhs: __m128) -> __m128 { - let x2_y2_z2_w2 = _mm_mul_ps(lhs, rhs); - let y2_0_0_0 = _mm_shuffle_ps(x2_y2_z2_w2, x2_y2_z2_w2, 0b00_00_00_01); - let z2_0_0_0 = _mm_shuffle_ps(x2_y2_z2_w2, x2_y2_z2_w2, 0b00_00_00_10); - let x2y2_0_0_0 = _mm_add_ss(x2_y2_z2_w2, y2_0_0_0); - _mm_add_ss(x2y2_0_0_0, z2_0_0_0) -} - -/// Calculates the vector 4 dot product and returns answer in x lane of __m128. -#[inline(always)] -unsafe fn dot4_in_x(lhs: __m128, rhs: __m128) -> __m128 { - let x2_y2_z2_w2 = _mm_mul_ps(lhs, rhs); - let z2_w2_0_0 = _mm_shuffle_ps(x2_y2_z2_w2, x2_y2_z2_w2, 0b00_00_11_10); - let x2z2_y2w2_0_0 = _mm_add_ps(x2_y2_z2_w2, z2_w2_0_0); - let y2w2_0_0_0 = _mm_shuffle_ps(x2z2_y2w2_0_0, x2z2_y2w2_0_0, 0b00_00_00_01); - _mm_add_ps(x2z2_y2w2_0_0, y2w2_0_0_0) -} - -impl VectorConst for __m128 { - const ZERO: __m128 = const_f32x4!([0.0; 4]); - const ONE: __m128 = const_f32x4!([1.0; 4]); -} - -impl Vector3Const for __m128 { - const X: __m128 = const_f32x4!([1.0, 0.0, 0.0, 0.0]); - const Y: __m128 = const_f32x4!([0.0, 1.0, 0.0, 0.0]); - const Z: __m128 = const_f32x4!([0.0, 0.0, 1.0, 0.0]); -} - -impl Vector4Const for __m128 { - const X: __m128 = const_f32x4!([1.0, 0.0, 0.0, 0.0]); - const Y: __m128 = const_f32x4!([0.0, 1.0, 0.0, 0.0]); - const Z: __m128 = const_f32x4!([0.0, 0.0, 1.0, 0.0]); - const W: __m128 = const_f32x4!([0.0, 0.0, 0.0, 1.0]); -} - -impl NanConstEx for __m128 { - const NAN: __m128 = const_f32x4!([f32::NAN; 4]); -} - -impl Vector for __m128 { - type Mask = __m128; - - #[inline(always)] - fn splat(s: f32) -> Self { - unsafe { _mm_set_ps1(s) } - } - - #[inline(always)] - fn select(mask: Self::Mask, if_true: Self, if_false: Self) -> Self { - unsafe { _mm_or_ps(_mm_andnot_ps(mask, if_false), _mm_and_ps(if_true, mask)) } - } - - #[inline(always)] - fn cmpeq(self, other: Self) -> Self::Mask { - unsafe { _mm_cmpeq_ps(self, other) } - } - - #[inline(always)] - fn cmpne(self, other: Self) -> Self::Mask { - unsafe { _mm_cmpneq_ps(self, other) } - } - - #[inline(always)] - fn cmpge(self, other: Self) -> Self::Mask { - unsafe { _mm_cmpge_ps(self, other) } - } - - #[inline(always)] - fn cmpgt(self, other: Self) -> Self::Mask { - unsafe { _mm_cmpgt_ps(self, other) } - } - - #[inline(always)] - fn cmple(self, other: Self) -> Self::Mask { - unsafe { _mm_cmple_ps(self, other) } - } - - #[inline(always)] - fn cmplt(self, other: Self) -> Self::Mask { - unsafe { _mm_cmplt_ps(self, other) } - } - - #[inline(always)] - fn add(self, other: Self) -> Self { - unsafe { _mm_add_ps(self, other) } - } - - #[inline(always)] - fn div(self, other: Self) -> Self { - unsafe { _mm_div_ps(self, other) } - } - - #[inline(always)] - fn mul(self, other: Self) -> Self { - unsafe { _mm_mul_ps(self, other) } - } - - #[inline(always)] - fn sub(self, other: Self) -> Self { - unsafe { _mm_sub_ps(self, other) } - } - - #[inline(always)] - fn add_scalar(self, other: f32) -> Self { - unsafe { _mm_add_ps(self, _mm_set_ps1(other)) } - } - - #[inline(always)] - fn sub_scalar(self, other: f32) -> Self { - unsafe { _mm_sub_ps(self, _mm_set_ps1(other)) } - } - - #[inline(always)] - fn mul_scalar(self, other: f32) -> Self { - unsafe { _mm_mul_ps(self, _mm_set_ps1(other)) } - } - - #[inline(always)] - fn div_scalar(self, other: f32) -> Self { - unsafe { _mm_div_ps(self, _mm_set_ps1(other)) } - } - - #[inline(always)] - fn rem(self, other: Self) -> Self { - unsafe { - let n = m128_floor(_mm_div_ps(self, other)); - _mm_sub_ps(self, _mm_mul_ps(n, other)) - } - } - - #[inline(always)] - fn rem_scalar(self, other: f32) -> Self { - unsafe { self.rem(_mm_set1_ps(other)) } - } - - #[inline(always)] - fn min(self, other: Self) -> Self { - unsafe { _mm_min_ps(self, other) } - } - - #[inline(always)] - fn max(self, other: Self) -> Self { - unsafe { _mm_max_ps(self, other) } - } -} - -impl Vector3 for __m128 { - #[inline(always)] - fn new(x: f32, y: f32, z: f32) -> Self { - unsafe { _mm_set_ps(z, z, y, x) } - } - - #[inline(always)] - fn x(self) -> f32 { - unsafe { _mm_cvtss_f32(self) } - } - - #[inline(always)] - fn y(self) -> f32 { - unsafe { _mm_cvtss_f32(_mm_shuffle_ps(self, self, 0b01_01_01_01)) } - } - - #[inline(always)] - fn z(self) -> f32 { - unsafe { _mm_cvtss_f32(_mm_shuffle_ps(self, self, 0b10_10_10_10)) } - } - - #[inline(always)] - fn splat_x(self) -> Self { - unsafe { _mm_shuffle_ps(self, self, 0b00_00_00_00) } - } - - #[inline(always)] - fn splat_y(self) -> Self { - unsafe { _mm_shuffle_ps(self, self, 0b01_01_01_01) } - } - - #[inline(always)] - fn splat_z(self) -> Self { - unsafe { _mm_shuffle_ps(self, self, 0b10_10_10_10) } - } - - #[inline(always)] - fn from_slice_unaligned(slice: &[f32]) -> Self { - Vector3::new(slice[0], slice[1], slice[2]) - } - - #[inline(always)] - fn write_to_slice_unaligned(self, slice: &mut [f32]) { - let xyz = self.as_ref_xyz(); - slice[0] = xyz.x; - slice[1] = xyz.y; - slice[2] = xyz.z; - } - - #[inline(always)] - fn as_ref_xyz(&self) -> &XYZ { - unsafe { &*(self as *const Self).cast() } - } - - #[inline(always)] - fn as_mut_xyz(&mut self) -> &mut XYZ { - unsafe { &mut *(self as *mut Self).cast() } - } - - #[inline(always)] - fn into_xy(self) -> XY { - let mut out: MaybeUninit>> = MaybeUninit::uninit(); - unsafe { - _mm_store_ps(out.as_mut_ptr().cast(), self); - out.assume_init().0 - } - } - - #[inline] - fn into_xyzw(self, w: f32) -> XYZW { - unsafe { - let mut t = _mm_move_ss(self, _mm_set_ss(w)); - t = _mm_shuffle_ps(t, t, 0b00_10_01_00); - // TODO: need a SIMD path - *_mm_move_ss(t, self).as_ref_xyzw() - } - } - - #[inline(always)] - fn from_array(a: [f32; 3]) -> Self { - unsafe { _mm_set_ps(a[2], a[2], a[1], a[0]) } - } - - #[inline(always)] - fn into_array(self) -> [f32; 3] { - let mut out: MaybeUninit> = MaybeUninit::uninit(); - unsafe { - _mm_store_ps(out.as_mut_ptr().cast(), self); - out.assume_init().0 - } - } - - #[inline(always)] - fn from_tuple(t: (f32, f32, f32)) -> Self { - unsafe { _mm_set_ps(t.2, t.2, t.1, t.0) } - } - - #[inline(always)] - fn into_tuple(self) -> (f32, f32, f32) { - let mut out: MaybeUninit> = MaybeUninit::uninit(); - unsafe { - _mm_store_ps(out.as_mut_ptr().cast(), self); - out.assume_init().0 - } - } - - #[inline] - fn min_element(self) -> f32 { - unsafe { - let v = self; - let v = _mm_min_ps(v, _mm_shuffle_ps(v, v, 0b01_01_10_10)); - let v = _mm_min_ps(v, _mm_shuffle_ps(v, v, 0b00_00_00_01)); - _mm_cvtss_f32(v) - } - } - - #[inline] - fn max_element(self) -> f32 { - unsafe { - let v = self; - let v = _mm_max_ps(v, _mm_shuffle_ps(v, v, 0b00_00_10_10)); - let v = _mm_max_ps(v, _mm_shuffle_ps(v, v, 0b00_00_00_01)); - _mm_cvtss_f32(v) - } - } - - #[inline] - fn dot(self, other: Self) -> f32 { - unsafe { _mm_cvtss_f32(dot3_in_x(self, other)) } - } - - #[inline] - fn dot_into_vec(self, other: Self) -> Self { - unsafe { - let dot_in_x = dot3_in_x(self, other); - _mm_shuffle_ps(dot_in_x, dot_in_x, 0b00_00_00_00) - } - } - - #[inline] - fn cross(self, other: Self) -> Self { - unsafe { - // x <- a.y*b.z - a.z*b.y - // y <- a.z*b.x - a.x*b.z - // z <- a.x*b.y - a.y*b.x - // We can save a shuffle by grouping it in this wacky order: - // (self.zxy() * other - self * other.zxy()).zxy() - let lhszxy = _mm_shuffle_ps(self, self, 0b01_01_00_10); - let rhszxy = _mm_shuffle_ps(other, other, 0b01_01_00_10); - let lhszxy_rhs = _mm_mul_ps(lhszxy, other); - let rhszxy_lhs = _mm_mul_ps(rhszxy, self); - let sub = _mm_sub_ps(lhszxy_rhs, rhszxy_lhs); - _mm_shuffle_ps(sub, sub, 0b01_01_00_10) - } - } - - #[inline] - fn clamp(self, min: Self, max: Self) -> Self { - glam_assert!( - MaskVector3::all(min.cmple(max)), - "clamp: expected min <= max" - ); - self.max(min).min(max) - } -} - -impl Vector4 for __m128 { - #[inline(always)] - fn new(x: f32, y: f32, z: f32, w: f32) -> Self { - unsafe { _mm_set_ps(w, z, y, x) } - } - - #[inline(always)] - fn x(self) -> f32 { - unsafe { _mm_cvtss_f32(self) } - } - - #[inline(always)] - fn y(self) -> f32 { - unsafe { _mm_cvtss_f32(_mm_shuffle_ps(self, self, 0b01_01_01_01)) } - } - - #[inline(always)] - fn z(self) -> f32 { - unsafe { _mm_cvtss_f32(_mm_shuffle_ps(self, self, 0b10_10_10_10)) } - } - - #[inline(always)] - fn w(self) -> f32 { - unsafe { _mm_cvtss_f32(_mm_shuffle_ps(self, self, 0b11_11_11_11)) } - } - - #[inline(always)] - fn splat_x(self) -> Self { - unsafe { _mm_shuffle_ps(self, self, 0b00_00_00_00) } - } - - #[inline(always)] - fn splat_y(self) -> Self { - unsafe { _mm_shuffle_ps(self, self, 0b01_01_01_01) } - } - - #[inline(always)] - fn splat_z(self) -> Self { - unsafe { _mm_shuffle_ps(self, self, 0b10_10_10_10) } - } - - #[inline(always)] - fn splat_w(self) -> Self { - unsafe { _mm_shuffle_ps(self, self, 0b11_11_11_11) } - } - - #[inline(always)] - fn from_slice_unaligned(slice: &[f32]) -> Self { - assert!(slice.len() >= 4); - unsafe { _mm_loadu_ps(slice.as_ptr()) } - } - - #[inline(always)] - fn write_to_slice_unaligned(self, slice: &mut [f32]) { - unsafe { - assert!(slice.len() >= 4); - _mm_storeu_ps(slice.as_mut_ptr(), self); - } - } - - #[inline(always)] - fn as_ref_xyzw(&self) -> &XYZW { - unsafe { &*(self as *const Self).cast() } - } - - #[inline(always)] - fn as_mut_xyzw(&mut self) -> &mut XYZW { - unsafe { &mut *(self as *mut Self).cast() } - } - - #[inline(always)] - fn into_xy(self) -> XY { - let mut out: MaybeUninit>> = MaybeUninit::uninit(); - unsafe { - _mm_store_ps(out.as_mut_ptr().cast(), self); - out.assume_init().0 - } - } - - #[inline(always)] - fn into_xyz(self) -> XYZ { - let mut out: MaybeUninit>> = MaybeUninit::uninit(); - unsafe { - _mm_store_ps(out.as_mut_ptr().cast(), self); - out.assume_init().0 - } - } - - #[inline(always)] - fn from_array(a: [f32; 4]) -> Self { - unsafe { _mm_loadu_ps(a.as_ptr()) } - } - - #[inline(always)] - fn into_array(self) -> [f32; 4] { - let mut out: MaybeUninit> = MaybeUninit::uninit(); - unsafe { - _mm_store_ps(out.as_mut_ptr().cast(), self); - out.assume_init().0 - } - } - - #[inline(always)] - fn from_tuple(t: (f32, f32, f32, f32)) -> Self { - unsafe { _mm_set_ps(t.3, t.2, t.1, t.0) } - } - - #[inline(always)] - fn into_tuple(self) -> (f32, f32, f32, f32) { - let mut out: MaybeUninit> = MaybeUninit::uninit(); - unsafe { - _mm_store_ps(out.as_mut_ptr().cast(), self); - out.assume_init().0 - } - } - - #[inline] - fn min_element(self) -> f32 { - unsafe { - let v = self; - let v = _mm_min_ps(v, _mm_shuffle_ps(v, v, 0b00_00_11_10)); - let v = _mm_min_ps(v, _mm_shuffle_ps(v, v, 0b00_00_00_01)); - _mm_cvtss_f32(v) - } - } - - #[inline] - fn max_element(self) -> f32 { - unsafe { - let v = self; - let v = _mm_max_ps(v, _mm_shuffle_ps(v, v, 0b00_00_11_10)); - let v = _mm_max_ps(v, _mm_shuffle_ps(v, v, 0b00_00_00_01)); - _mm_cvtss_f32(v) - } - } - - #[inline] - fn dot(self, other: Self) -> f32 { - unsafe { _mm_cvtss_f32(dot4_in_x(self, other)) } - } - - #[inline] - fn dot_into_vec(self, other: Self) -> Self { - unsafe { - let dot_in_x = dot4_in_x(self, other); - _mm_shuffle_ps(dot_in_x, dot_in_x, 0b00_00_00_00) - } - } - - #[inline] - fn clamp(self, min: Self, max: Self) -> Self { - glam_assert!( - MaskVector4::all(min.cmple(max)), - "clamp: expected min <= max" - ); - self.max(min).min(max) - } -} - -impl SignedVector for __m128 { - #[inline(always)] - fn neg(self) -> Self { - unsafe { _mm_sub_ps(Self::ZERO, self) } - } -} - -impl SignedVector3 for __m128 { - #[inline] - fn abs(self) -> Self { - unsafe { m128_abs(self) } - } - - #[inline] - fn signum(self) -> Self { - const NEG_ONE: __m128 = const_f32x4!([-1.0; 4]); - let mask = self.cmpge(Self::ZERO); - let result = Self::select(mask, Self::ONE, NEG_ONE); - let mask = unsafe { _mm_cmpunord_ps(self, self) }; - Self::select(mask, self, result) - } -} - -impl FloatVector3 for __m128 { - #[inline] - fn is_finite(self) -> bool { - let (x, y, z) = Vector3::into_tuple(self); - x.is_finite() && y.is_finite() && z.is_finite() - } - - #[inline] - fn is_nan(self) -> bool { - MaskVector3::any(FloatVector3::is_nan_mask(self)) - } - - #[inline(always)] - fn is_nan_mask(self) -> Self::Mask { - unsafe { _mm_cmpunord_ps(self, self) } - } - - #[inline(always)] - #[cfg(target_feature = "fma")] - fn mul_add(self, b: Self, c: Self) -> Self { - unsafe { _mm_fmadd_ps(self, b, c) } - } - - #[inline] - fn floor(self) -> Self { - unsafe { m128_floor(self) } - } - - #[inline] - fn ceil(self) -> Self { - unsafe { m128_ceil(self) } - } - - #[inline] - fn round(self) -> Self { - unsafe { m128_round(self) } - } - - #[inline(always)] - fn recip(self) -> Self { - unsafe { _mm_div_ps(Self::ONE, self) } - } - - #[inline] - fn exp(self) -> Self { - let (x, y, z) = Vector3::into_tuple(self); - unsafe { _mm_set_ps(0.0, z.exp(), y.exp(), x.exp()) } - } - - #[inline] - fn powf(self, n: f32) -> Self { - let (x, y, z) = Vector3::into_tuple(self); - unsafe { _mm_set_ps(0.0, z.powf(n), y.powf(n), x.powf(n)) } - } - - #[inline] - fn length(self) -> f32 { - unsafe { - let dot = dot3_in_x(self, self); - _mm_cvtss_f32(_mm_sqrt_ps(dot)) - } - } - - #[inline] - fn length_recip(self) -> f32 { - unsafe { - let dot = dot3_in_x(self, self); - _mm_cvtss_f32(_mm_div_ps(Self::ONE, _mm_sqrt_ps(dot))) - } - } - - #[inline] - fn normalize(self) -> Self { - unsafe { - let length = _mm_sqrt_ps(Vector3::dot_into_vec(self, self)); - #[allow(clippy::let_and_return)] - let normalized = _mm_div_ps(self, length); - glam_assert!(FloatVector3::is_finite(normalized)); - normalized - } - } -} - -impl SignedVector4 for __m128 { - #[inline] - fn abs(self) -> Self { - unsafe { m128_abs(self) } - } - - #[inline] - fn signum(self) -> Self { - const NEG_ONE: __m128 = const_f32x4!([-1.0; 4]); - let mask = self.cmpge(Self::ZERO); - let result = Self::select(mask, Self::ONE, NEG_ONE); - let mask = unsafe { _mm_cmpunord_ps(self, self) }; - Self::select(mask, self, result) - } -} - -impl FloatVector4 for __m128 { - #[inline] - fn is_finite(self) -> bool { - let (x, y, z, w) = Vector4::into_tuple(self); - x.is_finite() && y.is_finite() && z.is_finite() && w.is_finite() - } - - #[inline] - fn is_nan(self) -> bool { - MaskVector4::any(FloatVector4::is_nan_mask(self)) - } - - #[inline(always)] - fn is_nan_mask(self) -> Self::Mask { - unsafe { _mm_cmpunord_ps(self, self) } - } - - #[inline(always)] - #[cfg(target_feature = "fma")] - fn mul_add(self, b: Self, c: Self) -> Self { - unsafe { _mm_fmadd_ps(self, b, c) } - } - - #[inline] - fn floor(self) -> Self { - unsafe { m128_floor(self) } - } - - #[inline] - fn ceil(self) -> Self { - unsafe { m128_ceil(self) } - } - - #[inline] - fn round(self) -> Self { - unsafe { m128_round(self) } - } - - #[inline(always)] - fn recip(self) -> Self { - unsafe { _mm_div_ps(Self::ONE, self) } - } - - #[inline] - fn exp(self) -> Self { - let (x, y, z, w) = Vector4::into_tuple(self); - unsafe { _mm_set_ps(w.exp(), z.exp(), y.exp(), x.exp()) } - } - - #[inline] - fn powf(self, n: f32) -> Self { - let (x, y, z, w) = Vector4::into_tuple(self); - unsafe { _mm_set_ps(w.powf(n), z.powf(n), y.powf(n), x.powf(n)) } - } - - #[inline] - fn length(self) -> f32 { - unsafe { - let dot = dot4_in_x(self, self); - _mm_cvtss_f32(_mm_sqrt_ps(dot)) - } - } - - #[inline] - fn length_recip(self) -> f32 { - unsafe { - let dot = dot4_in_x(self, self); - _mm_cvtss_f32(_mm_div_ps(Self::ONE, _mm_sqrt_ps(dot))) - } - } - - #[inline] - fn normalize(self) -> Self { - unsafe { - let dot = Vector4::dot_into_vec(self, self); - #[allow(clippy::let_and_return)] - let normalized = _mm_div_ps(self, _mm_sqrt_ps(dot)); - glam_assert!(FloatVector4::is_finite(normalized)); - normalized - } - } -} - -impl From> for __m128 { - #[inline(always)] - fn from(v: XYZW) -> __m128 { - unsafe { _mm_set_ps(v.w, v.z, v.y, v.x) } - } -} - -impl From> for __m128 { - #[inline(always)] - fn from(v: XYZ) -> __m128 { - unsafe { _mm_set_ps(v.z, v.z, v.y, v.x) } - } -} - -impl From> for __m128 { - #[inline(always)] - fn from(v: XY) -> __m128 { - unsafe { _mm_set_ps(v.y, v.y, v.y, v.x) } - } -} - -impl From<__m128> for XYZW { - #[inline(always)] - fn from(v: __m128) -> XYZW { - let mut out: MaybeUninit>> = MaybeUninit::uninit(); - unsafe { - _mm_store_ps(out.as_mut_ptr().cast(), v); - out.assume_init().0 - } - } -} - -impl From<__m128> for XYZ { - #[inline(always)] - fn from(v: __m128) -> XYZ { - let mut out: MaybeUninit>> = MaybeUninit::uninit(); - unsafe { - _mm_store_ps(out.as_mut_ptr().cast(), v); - out.assume_init().0 - } - } -} - -impl From<__m128> for XY { - #[inline(always)] - fn from(v: __m128) -> XY { - let mut out: MaybeUninit>> = MaybeUninit::uninit(); - unsafe { - _mm_store_ps(out.as_mut_ptr().cast(), v); - out.assume_init().0 - } - } -} diff --git a/src/core/storage.rs b/src/core/storage.rs deleted file mode 100644 index 19bf35d0..00000000 --- a/src/core/storage.rs +++ /dev/null @@ -1,128 +0,0 @@ -#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd)] -#[cfg_attr(target_arch = "spirv", repr(simd))] -#[cfg_attr(not(target_arch = "spirv"), repr(C))] -pub struct XY { - pub x: T, - pub y: T, -} - -#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd)] -#[cfg_attr(target_arch = "spirv", repr(simd))] -#[cfg_attr(not(target_arch = "spirv"), repr(C))] -pub struct XYZ { - pub x: T, - pub y: T, - pub z: T, -} - -#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd)] -#[cfg_attr(target_arch = "spirv", repr(simd))] -#[cfg_attr(not(target_arch = "spirv"), repr(C))] -pub struct XYZW { - pub x: T, - pub y: T, - pub z: T, - pub w: T, -} - -#[derive(Clone, Copy, Default, PartialEq, PartialOrd)] -#[cfg_attr(not(target_arch = "spirv"), repr(C))] -pub struct Columns2 { - pub x_axis: V, - pub y_axis: V, -} - -#[derive(Clone, Copy, Default, PartialEq, PartialOrd)] -#[cfg_attr(not(target_arch = "spirv"), repr(C))] -pub struct Columns3 { - pub x_axis: V, - pub y_axis: V, - pub z_axis: V, -} - -#[derive(Clone, Copy, Default, PartialEq, PartialOrd)] -#[cfg_attr(not(target_arch = "spirv"), repr(C))] -pub struct Columns4 { - pub x_axis: V, - pub y_axis: V, - pub z_axis: V, - pub w_axis: V, -} - -/// The `XYZF32A16` is used for the `Vec3A` type, that is a 16 btye aligned `XYZ` type. -#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd)] -#[cfg_attr(target_arch = "spirv", repr(simd))] -#[cfg_attr(not(target_arch = "spirv"), repr(C, align(16)))] -pub struct XYZF32A16 { - pub x: f32, - pub y: f32, - pub z: f32, -} - -impl From> for XYZF32A16 { - #[inline(always)] - fn from(v: XYZW) -> Self { - Self { - x: v.x, - y: v.y, - z: v.z, - } - } -} - -impl From> for XYZF32A16 { - #[inline(always)] - fn from(v: XYZ) -> Self { - Self { - x: v.x, - y: v.y, - z: v.z, - } - } -} - -impl From for XYZ { - #[inline(always)] - fn from(v: XYZF32A16) -> Self { - Self { - x: v.x, - y: v.y, - z: v.z, - } - } -} - -impl From for XY { - #[inline(always)] - fn from(v: XYZF32A16) -> Self { - Self { x: v.x, y: v.y } - } -} - -#[derive(Clone, Copy, Default, PartialEq, PartialOrd)] -#[repr(C, align(16))] -pub(crate) struct Align16(pub T); - -impl Align16 { - #[allow(dead_code)] - pub fn as_ptr(&self) -> *const T { - &self.0 - } - - #[allow(dead_code)] - pub fn as_mut_ptr(&mut self) -> *mut T { - &mut self.0 - } -} - -#[test] -fn test_align16() { - use core::{mem, ptr}; - let mut a = Align16::(1.0); - assert_eq!(mem::align_of_val(&a), 16); - unsafe { - assert_eq!(ptr::read(a.as_ptr()).to_bits(), f32::to_bits(1.0)); - ptr::write(a.as_mut_ptr(), -1.0); - } - assert_eq!(a.0.to_bits(), f32::to_bits(-1.0)); -} diff --git a/src/core/traits.rs b/src/core/traits.rs deleted file mode 100644 index 917ae32b..00000000 --- a/src/core/traits.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub mod matrix; -pub mod projection; -pub mod quaternion; -pub mod scalar; -pub mod vector; diff --git a/src/core/traits/matrix.rs b/src/core/traits/matrix.rs deleted file mode 100644 index f1b00eb0..00000000 --- a/src/core/traits/matrix.rs +++ /dev/null @@ -1,985 +0,0 @@ -use crate::core::{ - storage::{XY, XYZ, XYZW}, - traits::{ - quaternion::Quaternion, - scalar::{FloatEx, NumEx}, - vector::*, - }, -}; - -pub trait MatrixConst { - const ZERO: Self; - const IDENTITY: Self; -} - -/// Base matrix trait that sets up trait bounds -pub trait Matrix: Sized + Copy + Clone {} - -/// 2x2 Matrix trait for all types of T -pub trait Matrix2x2>: Matrix { - #[inline(always)] - fn new(m00: T, m01: T, m10: T, m11: T) -> Self { - Self::from_cols(V2::new(m00, m01), V2::new(m10, m11)) - } - - fn from_cols(x_axis: V2, y_axis: V2) -> Self; - - fn x_axis(&self) -> &V2; - fn y_axis(&self) -> &V2; - - #[inline(always)] - fn from_cols_array(m: &[T; 4]) -> Self { - Self::new(m[0], m[1], m[2], m[3]) - } - - #[rustfmt::skip] - #[inline(always)] - fn to_cols_array(&self) -> [T; 4] { - let x_axis = self.x_axis(); - let y_axis = self.y_axis(); - [x_axis.x(), x_axis.y(), - y_axis.x(), y_axis.y()] - } - - #[inline(always)] - fn from_cols_array_2d(m: &[[T; 2]; 2]) -> Self { - Self::from_cols(V2::from_array(m[0]), V2::from_array(m[1])) - } - - #[inline(always)] - fn to_cols_array_2d(&self) -> [[T; 2]; 2] { - [self.x_axis().into_array(), self.y_axis().into_array()] - } - - #[inline(always)] - fn from_cols_slice(m: &[T]) -> Self { - Self::new(m[0], m[1], m[2], m[3]) - } - - #[inline(always)] - fn write_cols_to_slice(&self, slice: &mut [T]) { - let x_axis = self.x_axis(); - let y_axis = self.y_axis(); - slice[0] = x_axis.x(); - slice[1] = x_axis.y(); - slice[2] = y_axis.x(); - slice[3] = y_axis.y(); - } - - #[rustfmt::skip] - #[inline(always)] - fn from_diagonal(diagonal: XY) -> Self { - Self::new( - diagonal.x, T::ZERO, - T::ZERO, diagonal.y) - } - - #[inline] - fn determinant(&self) -> T { - let x_axis = self.x_axis(); - let y_axis = self.y_axis(); - x_axis.x() * y_axis.y() - x_axis.y() * y_axis.x() - } - - #[inline(always)] - fn transpose(&self) -> Self { - let x_axis = self.x_axis(); - let y_axis = self.y_axis(); - Self::new(x_axis.x(), y_axis.x(), x_axis.y(), y_axis.y()) - } - - #[inline] - fn mul_vector(&self, other: V2) -> V2 { - let x_axis = self.x_axis(); - let y_axis = self.y_axis(); - #[allow(clippy::suspicious_operation_groupings)] - V2::new( - (x_axis.x() * other.x()) + (y_axis.x() * other.y()), - (x_axis.y() * other.x()) + (y_axis.y() * other.y()), - ) - } - - #[inline] - fn mul_matrix(&self, other: &Self) -> Self { - Self::from_cols( - self.mul_vector(*other.x_axis()), - self.mul_vector(*other.y_axis()), - ) - } - - #[inline] - fn mul_scalar(&self, other: T) -> Self { - Self::from_cols( - self.x_axis().mul_scalar(other), - self.y_axis().mul_scalar(other), - ) - } - - #[inline] - fn add_matrix(&self, other: &Self) -> Self { - Self::from_cols( - self.x_axis().add(*other.x_axis()), - self.y_axis().add(*other.y_axis()), - ) - } - - #[inline] - fn sub_matrix(&self, other: &Self) -> Self { - Self::from_cols( - self.x_axis().sub(*other.x_axis()), - self.y_axis().sub(*other.y_axis()), - ) - } -} - -/// 2x2 matrix trait for float types of T -pub trait FloatMatrix2x2>: Matrix2x2 { - #[inline] - fn abs_diff_eq(&self, other: &Self, max_abs_diff: T) -> bool - where - >::Mask: MaskVector2, - { - self.x_axis().abs_diff_eq(*other.x_axis(), max_abs_diff) - && self.y_axis().abs_diff_eq(*other.y_axis(), max_abs_diff) - } - - #[inline] - fn neg_matrix(&self) -> Self { - Self::from_cols(self.x_axis().neg(), self.y_axis().neg()) - } - - #[inline] - fn from_scale_angle(scale: V2, angle: T) -> Self { - let (sin, cos) = angle.sin_cos(); - let (scale_x, scale_y) = scale.into_tuple(); - Self::new(cos * scale_x, sin * scale_x, -sin * scale_y, cos * scale_y) - } - - #[inline] - fn from_angle(angle: T) -> Self { - let (sin, cos) = angle.sin_cos(); - Self::new(cos, sin, -sin, cos) - } - - #[inline] - fn inverse(&self) -> Self { - let inv_det = { - let det = self.determinant(); - glam_assert!(det != T::ZERO); - det.recip() - }; - let x_axis = self.x_axis(); - let y_axis = self.y_axis(); - Self::new( - y_axis.y() * inv_det, - x_axis.y() * -inv_det, - y_axis.x() * -inv_det, - x_axis.x() * inv_det, - ) - } -} - -pub trait Matrix3x3>: Matrix { - fn from_cols(x_axis: V3, y_axis: V3, z_axis: V3) -> Self; - - fn x_axis(&self) -> &V3; - fn y_axis(&self) -> &V3; - fn z_axis(&self) -> &V3; - - #[rustfmt::skip] - #[inline(always)] - fn from_cols_array(m: &[T; 9]) -> Self { - Self::from_cols( - V3::new(m[0], m[1], m[2]), - V3::new(m[3], m[4], m[5]), - V3::new(m[6], m[7], m[8])) - } - - #[rustfmt::skip] - #[inline(always)] - fn to_cols_array(&self) -> [T; 9] { - let x_axis = self.x_axis(); - let y_axis = self.y_axis(); - let z_axis = self.z_axis(); - [ - x_axis.x(), x_axis.y(), x_axis.z(), - y_axis.x(), y_axis.y(), y_axis.z(), - z_axis.x(), z_axis.y(), z_axis.z(), - ] - } - - #[inline(always)] - fn from_cols_array_2d(m: &[[T; 3]; 3]) -> Self { - Self::from_cols( - V3::from_array(m[0]), - V3::from_array(m[1]), - V3::from_array(m[2]), - ) - } - - #[inline(always)] - fn to_cols_array_2d(&self) -> [[T; 3]; 3] { - [ - self.x_axis().into_array(), - self.y_axis().into_array(), - self.z_axis().into_array(), - ] - } - - #[inline(always)] - fn from_cols_slice(m: &[T]) -> Self { - Self::from_cols( - V3::new(m[0], m[1], m[2]), - V3::new(m[3], m[4], m[5]), - V3::new(m[6], m[7], m[8]), - ) - } - - #[inline(always)] - fn write_cols_to_slice(&self, slice: &mut [T]) { - let x_axis = self.x_axis(); - let y_axis = self.y_axis(); - let z_axis = self.z_axis(); - slice[0] = x_axis.x(); - slice[1] = x_axis.y(); - slice[2] = x_axis.z(); - slice[3] = y_axis.x(); - slice[4] = y_axis.y(); - slice[5] = y_axis.z(); - slice[6] = z_axis.x(); - slice[7] = z_axis.y(); - slice[8] = z_axis.z(); - } - - #[rustfmt::skip] - #[inline(always)] - fn from_diagonal(diagonal: XYZ) -> Self { - Self::from_cols( - V3::new(diagonal.x, T::ZERO, T::ZERO), - V3::new(T::ZERO, diagonal.y, T::ZERO), - V3::new(T::ZERO, T::ZERO, diagonal.z), - ) - } - - #[inline(always)] - fn from_scale(scale: XY) -> Self { - // Do not panic as long as any component is non-zero - glam_assert!(scale.cmpne(XY::::ZERO).any()); - Self::from_cols( - V3::new(scale.x, T::ZERO, T::ZERO), - V3::new(T::ZERO, scale.y, T::ZERO), - V3::Z, - ) - } - - #[inline(always)] - fn from_translation(translation: XY) -> Self { - Self::from_cols(V3::X, V3::Y, V3::new(translation.x, translation.y, T::ONE)) - } - - #[inline] - fn determinant(&self) -> T { - self.z_axis().dot(self.x_axis().cross(*self.y_axis())) - } - - #[inline] - fn transpose(&self) -> Self { - let x_axis = self.x_axis(); - let y_axis = self.y_axis(); - let z_axis = self.z_axis(); - Self::from_cols( - V3::new(x_axis.x(), y_axis.x(), z_axis.x()), - V3::new(x_axis.y(), y_axis.y(), z_axis.y()), - V3::new(x_axis.z(), y_axis.z(), z_axis.z()), - ) - } - - #[inline] - fn mul_vector(&self, other: V3) -> V3 { - let mut res = self.x_axis().mul(other.splat_x()); - res = res.add(self.y_axis().mul(other.splat_y())); - res = res.add(self.z_axis().mul(other.splat_z())); - res - } - - #[inline] - fn mul_matrix(&self, other: &Self) -> Self { - Self::from_cols( - self.mul_vector(*other.x_axis()), - self.mul_vector(*other.y_axis()), - self.mul_vector(*other.z_axis()), - ) - } - - #[inline] - fn mul_scalar(&self, other: T) -> Self { - Self::from_cols( - self.x_axis().mul_scalar(other), - self.y_axis().mul_scalar(other), - self.z_axis().mul_scalar(other), - ) - } - - #[inline] - fn add_matrix(&self, other: &Self) -> Self { - Self::from_cols( - self.x_axis().add(*other.x_axis()), - self.y_axis().add(*other.y_axis()), - self.z_axis().add(*other.z_axis()), - ) - } - - #[inline] - fn sub_matrix(&self, other: &Self) -> Self { - Self::from_cols( - self.x_axis().sub(*other.x_axis()), - self.y_axis().sub(*other.y_axis()), - self.z_axis().sub(*other.z_axis()), - ) - } -} - -pub trait FloatMatrix3x3>: Matrix3x3 { - #[inline] - fn abs_diff_eq(&self, other: &Self, max_abs_diff: T) -> bool - where - >::Mask: MaskVector3, - { - self.x_axis().abs_diff_eq(*other.x_axis(), max_abs_diff) - && self.y_axis().abs_diff_eq(*other.y_axis(), max_abs_diff) - && self.z_axis().abs_diff_eq(*other.z_axis(), max_abs_diff) - } - - #[inline] - fn neg_matrix(&self) -> Self { - Self::from_cols( - self.x_axis().neg(), - self.y_axis().neg(), - self.z_axis().neg(), - ) - } - - #[inline] - fn from_angle(angle: T) -> Self { - let (sin, cos) = angle.sin_cos(); - Self::from_cols( - V3::new(cos, sin, T::ZERO), - V3::new(-sin, cos, T::ZERO), - V3::Z, - ) - } - #[inline] - fn from_scale_angle_translation(scale: XY, angle: T, translation: XY) -> Self { - let (sin, cos) = angle.sin_cos(); - Self::from_cols( - V3::new(cos * scale.x, sin * scale.x, T::ZERO), - V3::new(-sin * scale.y, cos * scale.y, T::ZERO), - V3::new(translation.x, translation.y, T::ONE), - ) - } - - #[inline] - fn from_axis_angle(axis: XYZ, angle: T) -> Self { - glam_assert!(axis.is_normalized()); - let (sin, cos) = angle.sin_cos(); - let (xsin, ysin, zsin) = axis.mul_scalar(sin).into_tuple(); - let (x, y, z) = axis.into_tuple(); - let (x2, y2, z2) = axis.mul(axis).into_tuple(); - let omc = T::ONE - cos; - let xyomc = x * y * omc; - let xzomc = x * z * omc; - let yzomc = y * z * omc; - Self::from_cols( - V3::new(x2 * omc + cos, xyomc + zsin, xzomc - ysin), - V3::new(xyomc - zsin, y2 * omc + cos, yzomc + xsin), - V3::new(xzomc + ysin, yzomc - xsin, z2 * omc + cos), - ) - } - - #[inline] - fn from_quaternion(rotation: XYZW) -> Self { - glam_assert!(rotation.is_normalized()); - let x2 = rotation.x + rotation.x; - let y2 = rotation.y + rotation.y; - let z2 = rotation.z + rotation.z; - let xx = rotation.x * x2; - let xy = rotation.x * y2; - let xz = rotation.x * z2; - let yy = rotation.y * y2; - let yz = rotation.y * z2; - let zz = rotation.z * z2; - let wx = rotation.w * x2; - let wy = rotation.w * y2; - let wz = rotation.w * z2; - - Self::from_cols( - V3::new(T::ONE - (yy + zz), xy + wz, xz - wy), - V3::new(xy - wz, T::ONE - (xx + zz), yz + wx), - V3::new(xz + wy, yz - wx, T::ONE - (xx + yy)), - ) - } - - #[inline] - fn from_rotation_x(angle: T) -> Self { - let (sina, cosa) = angle.sin_cos(); - Self::from_cols( - V3::X, - V3::new(T::ZERO, cosa, sina), - V3::new(T::ZERO, -sina, cosa), - ) - } - - #[inline] - fn from_rotation_y(angle: T) -> Self { - let (sina, cosa) = angle.sin_cos(); - Self::from_cols( - V3::new(cosa, T::ZERO, -sina), - V3::Y, - V3::new(sina, T::ZERO, cosa), - ) - } - - #[inline] - fn from_rotation_z(angle: T) -> Self { - let (sina, cosa) = angle.sin_cos(); - Self::from_cols( - V3::new(cosa, sina, T::ZERO), - V3::new(-sina, cosa, T::ZERO), - V3::Z, - ) - } - - fn transform_point2(&self, other: XY) -> XY; - fn transform_vector2(&self, other: XY) -> XY; - - #[inline] - fn inverse(&self) -> Self - where - >::Mask: MaskVector3, - { - let x_axis = self.x_axis(); - let y_axis = self.y_axis(); - let z_axis = self.z_axis(); - let tmp0 = y_axis.cross(*z_axis); - let tmp1 = z_axis.cross(*x_axis); - let tmp2 = x_axis.cross(*y_axis); - let det = z_axis.dot_into_vec(tmp2); - glam_assert!(det.cmpne(V3::ZERO).all()); - let inv_det = det.recip(); - // TODO: Work out if it's possible to get rid of the transpose - Self::from_cols(tmp0.mul(inv_det), tmp1.mul(inv_det), tmp2.mul(inv_det)).transpose() - } - - #[inline] - fn is_finite(&self) -> bool { - self.x_axis().is_finite() && self.y_axis().is_finite() && self.z_axis().is_finite() - } - - #[inline] - fn is_nan(&self) -> bool { - self.x_axis().is_nan() || self.y_axis().is_nan() || self.z_axis().is_nan() - } -} - -pub trait Matrix4x4>: Matrix { - fn from_cols(x_axis: V4, y_axis: V4, z_axis: V4, w_axis: V4) -> Self; - - fn x_axis(&self) -> &V4; - fn y_axis(&self) -> &V4; - fn z_axis(&self) -> &V4; - fn w_axis(&self) -> &V4; - - #[rustfmt::skip] - #[inline(always)] - fn from_cols_array(m: &[T; 16]) -> Self { - Self::from_cols( - V4::new( m[0], m[1], m[2], m[3]), - V4::new( m[4], m[5], m[6], m[7]), - V4::new( m[8], m[9], m[10], m[11]), - V4::new(m[12], m[13], m[14], m[15])) - } - - #[rustfmt::skip] - #[inline(always)] - fn to_cols_array(&self) -> [T; 16] { - let x_axis = self.x_axis(); - let y_axis = self.y_axis(); - let z_axis = self.z_axis(); - let w_axis = self.w_axis(); - [ - x_axis.x(), x_axis.y(), x_axis.z(), x_axis.w(), - y_axis.x(), y_axis.y(), y_axis.z(), y_axis.w(), - z_axis.x(), z_axis.y(), z_axis.z(), z_axis.w(), - w_axis.x(), w_axis.y(), w_axis.z(), w_axis.w(), - ] - } - - #[inline(always)] - fn from_cols_array_2d(m: &[[T; 4]; 4]) -> Self { - Self::from_cols( - Vector4::from_array(m[0]), - Vector4::from_array(m[1]), - Vector4::from_array(m[2]), - Vector4::from_array(m[3]), - ) - } - - #[inline(always)] - fn to_cols_array_2d(&self) -> [[T; 4]; 4] { - [ - self.x_axis().into_array(), - self.y_axis().into_array(), - self.z_axis().into_array(), - self.w_axis().into_array(), - ] - } - - #[rustfmt::skip] - #[inline(always)] - fn from_cols_slice(m: &[T]) -> Self { - Self::from_cols( - V4::new( m[0], m[1], m[2], m[3]), - V4::new( m[4], m[5], m[6], m[7]), - V4::new( m[8], m[9], m[10], m[11]), - V4::new(m[12], m[13], m[14], m[15])) - } - - #[inline(always)] - fn write_cols_to_slice(&self, slice: &mut [T]) { - let x_axis = self.x_axis(); - let y_axis = self.y_axis(); - let z_axis = self.z_axis(); - let w_axis = self.w_axis(); - slice[0] = x_axis.x(); - slice[1] = x_axis.y(); - slice[2] = x_axis.z(); - slice[3] = x_axis.w(); - - slice[4] = y_axis.x(); - slice[5] = y_axis.y(); - slice[6] = y_axis.z(); - slice[7] = y_axis.w(); - - slice[8] = z_axis.x(); - slice[9] = z_axis.y(); - slice[10] = z_axis.z(); - slice[11] = z_axis.w(); - - slice[12] = w_axis.x(); - slice[13] = w_axis.y(); - slice[14] = w_axis.z(); - slice[15] = w_axis.w(); - } - - #[inline(always)] - fn from_diagonal(diagonal: XYZW) -> Self { - Self::from_cols( - V4::new(diagonal.x, T::ZERO, T::ZERO, T::ZERO), - V4::new(T::ZERO, diagonal.y, T::ZERO, T::ZERO), - V4::new(T::ZERO, T::ZERO, diagonal.z, T::ZERO), - V4::new(T::ZERO, T::ZERO, T::ZERO, diagonal.w), - ) - } - - #[inline(always)] - fn from_scale(scale: XYZ) -> Self { - // Do not panic as long as any component is non-zero - glam_assert!(scale.cmpne(XYZ::::ZERO).any()); - Self::from_cols( - V4::new(scale.x, T::ZERO, T::ZERO, T::ZERO), - V4::new(T::ZERO, scale.y, T::ZERO, T::ZERO), - V4::new(T::ZERO, T::ZERO, scale.z, T::ZERO), - V4::W, - ) - } - - #[inline(always)] - fn from_translation(translation: XYZ) -> Self { - Self::from_cols( - V4::X, - V4::Y, - V4::Z, - V4::new(translation.x, translation.y, translation.z, T::ONE), - ) - } - - #[inline] - fn determinant(&self) -> T { - let (m00, m01, m02, m03) = self.x_axis().into_tuple(); - let (m10, m11, m12, m13) = self.y_axis().into_tuple(); - let (m20, m21, m22, m23) = self.z_axis().into_tuple(); - let (m30, m31, m32, m33) = self.w_axis().into_tuple(); - - 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) - } - - #[inline] - fn transpose(&self) -> Self { - let (m00, m01, m02, m03) = self.x_axis().into_tuple(); - let (m10, m11, m12, m13) = self.y_axis().into_tuple(); - let (m20, m21, m22, m23) = self.z_axis().into_tuple(); - let (m30, m31, m32, m33) = self.w_axis().into_tuple(); - - Self::from_cols( - V4::new(m00, m10, m20, m30), - V4::new(m01, m11, m21, m31), - V4::new(m02, m12, m22, m32), - V4::new(m03, m13, m23, m33), - ) - } - - #[inline] - fn mul_vector(&self, other: V4) -> V4 { - let mut res = self.x_axis().mul(other.splat_x()); - res = res.add(self.y_axis().mul(other.splat_y())); - res = res.add(self.z_axis().mul(other.splat_z())); - res = res.add(self.w_axis().mul(other.splat_w())); - res - } - - #[inline] - fn mul_matrix(&self, other: &Self) -> Self { - Self::from_cols( - self.mul_vector(*other.x_axis()), - self.mul_vector(*other.y_axis()), - self.mul_vector(*other.z_axis()), - self.mul_vector(*other.w_axis()), - ) - } - - #[inline] - fn mul_scalar(&self, other: T) -> Self { - Self::from_cols( - self.x_axis().mul_scalar(other), - self.y_axis().mul_scalar(other), - self.z_axis().mul_scalar(other), - self.w_axis().mul_scalar(other), - ) - } - - #[inline] - fn add_matrix(&self, other: &Self) -> Self { - // TODO: Make Vector4::add take a ref? - Self::from_cols( - self.x_axis().add(*other.x_axis()), - self.y_axis().add(*other.y_axis()), - self.z_axis().add(*other.z_axis()), - self.w_axis().add(*other.w_axis()), - ) - } - - #[inline] - fn sub_matrix(&self, other: &Self) -> Self { - // TODO: Make Vector4::sub take a ref? - Self::from_cols( - self.x_axis().sub(*other.x_axis()), - self.y_axis().sub(*other.y_axis()), - self.z_axis().sub(*other.z_axis()), - self.w_axis().sub(*other.w_axis()), - ) - } -} - -pub trait FloatMatrix4x4 + Quaternion>: - Matrix4x4 -{ - // Vector3 represented by a SIMD type if available - type SIMDVector3; - - #[inline] - fn abs_diff_eq(&self, other: &Self, max_abs_diff: T) -> bool - where - >::Mask: MaskVector4, - { - self.x_axis().abs_diff_eq(*other.x_axis(), max_abs_diff) - && self.y_axis().abs_diff_eq(*other.y_axis(), max_abs_diff) - && self.z_axis().abs_diff_eq(*other.z_axis(), max_abs_diff) - && self.w_axis().abs_diff_eq(*other.w_axis(), max_abs_diff) - } - - #[inline] - fn neg_matrix(&self) -> Self { - Self::from_cols( - self.x_axis().neg(), - self.y_axis().neg(), - self.z_axis().neg(), - self.w_axis().neg(), - ) - } - - #[inline] - fn quaternion_to_axes(rotation: V4) -> (V4, V4, V4) { - glam_assert!(rotation.is_normalized()); - let (x, y, z, w) = rotation.into_tuple(); - let x2 = x + x; - let y2 = y + y; - let z2 = z + z; - let xx = x * x2; - let xy = x * y2; - let xz = x * z2; - let yy = y * y2; - let yz = y * z2; - let zz = z * z2; - let wx = w * x2; - let wy = w * y2; - let wz = w * z2; - - let x_axis = V4::new(T::ONE - (yy + zz), xy + wz, xz - wy, T::ZERO); - let y_axis = V4::new(xy - wz, T::ONE - (xx + zz), yz + wx, T::ZERO); - let z_axis = V4::new(xz + wy, yz - wx, T::ONE - (xx + yy), T::ZERO); - (x_axis, y_axis, z_axis) - } - - #[inline] - fn from_quaternion(rotation: V4) -> Self { - let (x_axis, y_axis, z_axis) = Self::quaternion_to_axes(rotation); - Self::from_cols(x_axis, y_axis, z_axis, V4::W) - } - - fn to_scale_quaternion_translation(&self) -> (XYZ, V4, XYZ) { - let det = self.determinant(); - glam_assert!(det != T::ZERO); - - let scale: XYZ = Vector3::new( - self.x_axis().length() * det.signum(), - self.y_axis().length(), - self.z_axis().length(), - ); - - glam_assert!(scale.cmpne(XYZ::::ZERO).all()); - - let inv_scale = scale.recip(); - - let rotation = Quaternion::from_rotation_axes( - self.x_axis().mul_scalar(inv_scale.x).into_xyz(), - self.y_axis().mul_scalar(inv_scale.y).into_xyz(), - self.z_axis().mul_scalar(inv_scale.z).into_xyz(), - ); - - let translation = self.w_axis().into_xyz(); - - (scale, rotation, translation) - } - - #[inline] - fn from_scale_quaternion_translation(scale: XYZ, rotation: V4, translation: XYZ) -> Self { - let (x_axis, y_axis, z_axis) = Self::quaternion_to_axes(rotation); - Self::from_cols( - x_axis.mul_scalar(scale.x), - y_axis.mul_scalar(scale.y), - z_axis.mul_scalar(scale.z), - V4::from_xyz(translation, T::ONE), - ) - } - - #[inline] - fn from_quaternion_translation(rotation: V4, translation: XYZ) -> Self { - let (x_axis, y_axis, z_axis) = Self::quaternion_to_axes(rotation); - Self::from_cols(x_axis, y_axis, z_axis, V4::from_xyz(translation, T::ONE)) - } - - #[inline] - fn from_axis_angle(axis: XYZ, angle: T) -> Self { - glam_assert!(axis.is_normalized()); - let (sin, cos) = angle.sin_cos(); - let axis_sin = axis.mul_scalar(sin); - let axis_sq = axis.mul(axis); - let omc = T::ONE - cos; - let xyomc = axis.x * axis.y * omc; - let xzomc = axis.x * axis.z * omc; - let yzomc = axis.y * axis.z * omc; - Self::from_cols( - V4::new( - axis_sq.x * omc + cos, - xyomc + axis_sin.z, - xzomc - axis_sin.y, - T::ZERO, - ), - V4::new( - xyomc - axis_sin.z, - axis_sq.y * omc + cos, - yzomc + axis_sin.x, - T::ZERO, - ), - V4::new( - xzomc + axis_sin.y, - yzomc - axis_sin.x, - axis_sq.z * omc + cos, - T::ZERO, - ), - V4::W, - ) - } - - #[inline] - fn from_rotation_x(angle: T) -> Self { - let (sina, cosa) = angle.sin_cos(); - Self::from_cols( - V4::X, - V4::new(T::ZERO, cosa, sina, T::ZERO), - V4::new(T::ZERO, -sina, cosa, T::ZERO), - V4::W, - ) - } - - #[inline] - fn from_rotation_y(angle: T) -> Self { - let (sina, cosa) = angle.sin_cos(); - Self::from_cols( - V4::new(cosa, T::ZERO, -sina, T::ZERO), - V4::Y, - V4::new(sina, T::ZERO, cosa, T::ZERO), - V4::W, - ) - } - - #[inline] - fn from_rotation_z(angle: T) -> Self { - let (sina, cosa) = angle.sin_cos(); - Self::from_cols( - V4::new(cosa, sina, T::ZERO, T::ZERO), - V4::new(-sina, cosa, T::ZERO, T::ZERO), - V4::Z, - V4::W, - ) - } - - #[inline] - fn look_to_lh(eye: XYZ, dir: XYZ, up: XYZ) -> Self { - let f = dir.normalize(); - let s = up.cross(f).normalize(); - let u = f.cross(s); - Self::from_cols( - V4::new(s.x, u.x, f.x, T::ZERO), - V4::new(s.y, u.y, f.y, T::ZERO), - V4::new(s.z, u.z, f.z, T::ZERO), - V4::new(-s.dot(eye), -u.dot(eye), -f.dot(eye), T::ONE), - ) - } - - #[inline] - fn look_at_lh(eye: XYZ, center: XYZ, up: XYZ) -> Self { - glam_assert!(up.is_normalized()); - Self::look_to_lh(eye, center.sub(eye), up) - } - - #[inline] - fn look_at_rh(eye: XYZ, center: XYZ, up: XYZ) -> Self { - glam_assert!(up.is_normalized()); - Self::look_to_lh(eye, eye.sub(center), up) - } - - #[inline] - fn transform_point3(&self, other: XYZ) -> XYZ { - let mut res = self.x_axis().mul_scalar(other.x); - res = self.y_axis().mul_scalar(other.y).add(res); - res = self.z_axis().mul_scalar(other.z).add(res); - res = self.w_axis().add(res); - res.into_xyz() - } - - #[inline] - fn transform_vector3(&self, other: XYZ) -> XYZ { - let mut res = self.x_axis().mul_scalar(other.x); - res = self.y_axis().mul_scalar(other.y).add(res); - res = self.z_axis().mul_scalar(other.z).add(res); - res.into_xyz() - } - - #[inline] - fn project_point3(&self, other: XYZ) -> XYZ { - let mut res = self.x_axis().mul_scalar(other.x); - res = self.y_axis().mul_scalar(other.y).add(res); - res = self.z_axis().mul_scalar(other.z).add(res); - res = self.w_axis().add(res); - res = res.mul(res.splat_w().recip()); - res.into_xyz() - } - - fn transform_float4_as_point3(&self, other: Self::SIMDVector3) -> Self::SIMDVector3; - fn transform_float4_as_vector3(&self, other: Self::SIMDVector3) -> Self::SIMDVector3; - fn project_float4_as_point3(&self, other: Self::SIMDVector3) -> Self::SIMDVector3; - - fn inverse(&self) -> Self { - let (m00, m01, m02, m03) = self.x_axis().into_tuple(); - let (m10, m11, m12, m13) = self.y_axis().into_tuple(); - let (m20, m21, m22, m23) = self.z_axis().into_tuple(); - let (m30, m31, m32, m33) = self.w_axis().into_tuple(); - - let coef00 = m22 * m33 - m32 * m23; - let coef02 = m12 * m33 - m32 * m13; - let coef03 = m12 * m23 - m22 * m13; - - let coef04 = m21 * m33 - m31 * m23; - let coef06 = m11 * m33 - m31 * m13; - let coef07 = m11 * m23 - m21 * m13; - - let coef08 = m21 * m32 - m31 * m22; - let coef10 = m11 * m32 - m31 * m12; - let coef11 = m11 * m22 - m21 * m12; - - let coef12 = m20 * m33 - m30 * m23; - let coef14 = m10 * m33 - m30 * m13; - let coef15 = m10 * m23 - m20 * m13; - - let coef16 = m20 * m32 - m30 * m22; - let coef18 = m10 * m32 - m30 * m12; - let coef19 = m10 * m22 - m20 * m12; - - let coef20 = m20 * m31 - m30 * m21; - let coef22 = m10 * m31 - m30 * m11; - let coef23 = m10 * m21 - m20 * m11; - - let fac0 = V4::new(coef00, coef00, coef02, coef03); - let fac1 = V4::new(coef04, coef04, coef06, coef07); - let fac2 = V4::new(coef08, coef08, coef10, coef11); - let fac3 = V4::new(coef12, coef12, coef14, coef15); - let fac4 = V4::new(coef16, coef16, coef18, coef19); - let fac5 = V4::new(coef20, coef20, coef22, coef23); - - let vec0 = V4::new(m10, m00, m00, m00); - let vec1 = V4::new(m11, m01, m01, m01); - let vec2 = V4::new(m12, m02, m02, m02); - let vec3 = V4::new(m13, m03, m03, m03); - - let inv0 = vec1.mul(fac0).sub(vec2.mul(fac1)).add(vec3.mul(fac2)); - let inv1 = vec0.mul(fac0).sub(vec2.mul(fac3)).add(vec3.mul(fac4)); - let inv2 = vec0.mul(fac1).sub(vec1.mul(fac3)).add(vec3.mul(fac5)); - let inv3 = vec0.mul(fac2).sub(vec1.mul(fac4)).add(vec2.mul(fac5)); - - let sign_a = Vector4::new(T::ONE, -T::ONE, T::ONE, -T::ONE); - let sign_b = Vector4::new(-T::ONE, T::ONE, -T::ONE, T::ONE); - - let inverse = Self::from_cols( - inv0.mul(sign_a), - inv1.mul(sign_b), - inv2.mul(sign_a), - inv3.mul(sign_b), - ); - - let col0 = V4::new( - inverse.x_axis().x(), - inverse.y_axis().x(), - inverse.z_axis().x(), - inverse.w_axis().x(), - ); - - let dot0 = self.x_axis().mul(col0); - let dot1 = dot0.x() + dot0.y() + dot0.z() + dot0.w(); - - glam_assert!(dot1 != T::ZERO); - - let rcp_det = dot1.recip(); - inverse.mul_scalar(rcp_det) - } -} diff --git a/src/core/traits/projection.rs b/src/core/traits/projection.rs deleted file mode 100644 index bc90b567..00000000 --- a/src/core/traits/projection.rs +++ /dev/null @@ -1,164 +0,0 @@ -use crate::core::traits::{ - matrix::FloatMatrix4x4, quaternion::Quaternion, scalar::FloatEx, vector::*, -}; - -pub trait ProjectionMatrix + Quaternion>: - FloatMatrix4x4 -{ - /// Creates a right-handed perspective projection matrix with [-1,1] depth range. - /// This is the same as the OpenGL [`gluPerspective`] function. - /// [`gluPerspective`]: - fn perspective_rh_gl(fov_y_radians: T, aspect_ratio: T, z_near: T, z_far: T) -> Self { - let inv_length = T::ONE / (z_near - z_far); - let f = T::ONE / (T::HALF * fov_y_radians).tan(); - let a = f / aspect_ratio; - let b = (z_near + z_far) * inv_length; - let c = (T::TWO * z_near * z_far) * inv_length; - Self::from_cols( - V4::new(a, T::ZERO, T::ZERO, T::ZERO), - V4::new(T::ZERO, f, T::ZERO, T::ZERO), - V4::new(T::ZERO, T::ZERO, b, -T::ONE), - V4::new(T::ZERO, T::ZERO, c, T::ZERO), - ) - } - - /// Creates a left-handed perspective projection matrix with [0,1] depth range. - fn perspective_lh(fov_y_radians: T, aspect_ratio: T, z_near: T, z_far: T) -> Self { - glam_assert!(z_near > T::ZERO && z_far > T::ZERO); - let (sin_fov, cos_fov) = (T::HALF * fov_y_radians).sin_cos(); - let h = cos_fov / sin_fov; - let w = h / aspect_ratio; - let r = z_far / (z_far - z_near); - Self::from_cols( - V4::new(w, T::ZERO, T::ZERO, T::ZERO), - V4::new(T::ZERO, h, T::ZERO, T::ZERO), - V4::new(T::ZERO, T::ZERO, r, T::ONE), - V4::new(T::ZERO, T::ZERO, -r * z_near, T::ZERO), - ) - } - - /// Creates a right-handed perspective projection matrix with [0,1] depth range. - fn perspective_rh(fov_y_radians: T, aspect_ratio: T, z_near: T, z_far: T) -> Self { - glam_assert!(z_near > T::ZERO && z_far > T::ZERO); - let (sin_fov, cos_fov) = (T::HALF * fov_y_radians).sin_cos(); - let h = cos_fov / sin_fov; - let w = h / aspect_ratio; - let r = z_far / (z_near - z_far); - Self::from_cols( - V4::new(w, T::ZERO, T::ZERO, T::ZERO), - V4::new(T::ZERO, h, T::ZERO, T::ZERO), - V4::new(T::ZERO, T::ZERO, r, -T::ONE), - V4::new(T::ZERO, T::ZERO, r * z_near, T::ZERO), - ) - } - - /// Creates an infinite left-handed perspective projection matrix with [0,1] depth range. - fn perspective_infinite_lh(fov_y_radians: T, aspect_ratio: T, z_near: T) -> Self { - glam_assert!(z_near > T::ZERO); - let (sin_fov, cos_fov) = (T::HALF * fov_y_radians).sin_cos(); - let h = cos_fov / sin_fov; - let w = h / aspect_ratio; - Self::from_cols( - V4::new(w, T::ZERO, T::ZERO, T::ZERO), - V4::new(T::ZERO, h, T::ZERO, T::ZERO), - V4::new(T::ZERO, T::ZERO, T::ONE, T::ONE), - V4::new(T::ZERO, T::ZERO, -z_near, T::ZERO), - ) - } - - /// Creates an infinite left-handed perspective projection matrix with [0,1] depth range. - fn perspective_infinite_reverse_lh(fov_y_radians: T, aspect_ratio: T, z_near: T) -> Self { - glam_assert!(z_near > T::ZERO); - let (sin_fov, cos_fov) = (T::HALF * fov_y_radians).sin_cos(); - let h = cos_fov / sin_fov; - let w = h / aspect_ratio; - Self::from_cols( - V4::new(w, T::ZERO, T::ZERO, T::ZERO), - V4::new(T::ZERO, h, T::ZERO, T::ZERO), - V4::new(T::ZERO, T::ZERO, T::ZERO, T::ONE), - V4::new(T::ZERO, T::ZERO, z_near, T::ZERO), - ) - } - - /// Creates an infinite right-handed perspective projection matrix with - /// [0,1] depth range. - fn perspective_infinite_rh(fov_y_radians: T, aspect_ratio: T, z_near: T) -> Self { - glam_assert!(z_near > T::ZERO); - let f = T::ONE / (T::HALF * fov_y_radians).tan(); - Self::from_cols( - V4::new(f / aspect_ratio, T::ZERO, T::ZERO, T::ZERO), - V4::new(T::ZERO, f, T::ZERO, T::ZERO), - V4::new(T::ZERO, T::ZERO, -T::ONE, -T::ONE), - V4::new(T::ZERO, T::ZERO, -z_near, T::ZERO), - ) - } - - /// Creates an infinite reverse right-handed perspective projection matrix - /// with [0,1] depth range. - fn perspective_infinite_reverse_rh(fov_y_radians: T, aspect_ratio: T, z_near: T) -> Self { - glam_assert!(z_near > T::ZERO); - let f = T::ONE / (T::HALF * fov_y_radians).tan(); - Self::from_cols( - V4::new(f / aspect_ratio, T::ZERO, T::ZERO, T::ZERO), - V4::new(T::ZERO, f, T::ZERO, T::ZERO), - V4::new(T::ZERO, T::ZERO, T::ZERO, -T::ONE), - V4::new(T::ZERO, T::ZERO, z_near, T::ZERO), - ) - } - - /// Creates a right-handed orthographic projection matrix with [-1,1] depth - /// range. This is the same as the OpenGL [`glOrtho`] function in OpenGL. - /// See - /// [`glOrtho`]: - fn orthographic_rh_gl(left: T, right: T, bottom: T, top: T, near: T, far: T) -> Self { - let a = T::TWO / (right - left); - let b = T::TWO / (top - bottom); - let c = -T::TWO / (far - near); - let tx = -(right + left) / (right - left); - let ty = -(top + bottom) / (top - bottom); - let tz = -(far + near) / (far - near); - - Self::from_cols( - V4::new(a, T::ZERO, T::ZERO, T::ZERO), - V4::new(T::ZERO, b, T::ZERO, T::ZERO), - V4::new(T::ZERO, T::ZERO, c, T::ZERO), - V4::new(tx, ty, tz, T::ONE), - ) - } - - /// Creates a left-handed orthographic projection matrix with [0,1] depth range. - fn orthographic_lh(left: T, right: T, bottom: T, top: T, near: T, far: T) -> Self { - let rcp_width = T::ONE / (right - left); - let rcp_height = T::ONE / (top - bottom); - let r = T::ONE / (far - near); - Self::from_cols( - V4::new(rcp_width + rcp_width, T::ZERO, T::ZERO, T::ZERO), - V4::new(T::ZERO, rcp_height + rcp_height, T::ZERO, T::ZERO), - V4::new(T::ZERO, T::ZERO, r, T::ZERO), - V4::new( - -(left + right) * rcp_width, - -(top + bottom) * rcp_height, - -r * near, - T::ONE, - ), - ) - } - - /// Creates a right-handed orthographic projection matrix with [0,1] depth range. - fn orthographic_rh(left: T, right: T, bottom: T, top: T, near: T, far: T) -> Self { - let rcp_width = T::ONE / (right - left); - let rcp_height = T::ONE / (top - bottom); - let r = T::ONE / (near - far); - Self::from_cols( - V4::new(rcp_width + rcp_width, T::ZERO, T::ZERO, T::ZERO), - V4::new(T::ZERO, rcp_height + rcp_height, T::ZERO, T::ZERO), - V4::new(T::ZERO, T::ZERO, r, T::ZERO), - V4::new( - -(left + right) * rcp_width, - -(top + bottom) * rcp_height, - r * near, - T::ONE, - ), - ) - } -} diff --git a/src/core/traits/quaternion.rs b/src/core/traits/quaternion.rs deleted file mode 100644 index 8a3836c8..00000000 --- a/src/core/traits/quaternion.rs +++ /dev/null @@ -1,140 +0,0 @@ -use crate::core::{ - storage::XYZ, - traits::{ - scalar::{FloatEx, NumEx}, - vector::*, - }, -}; - -pub trait Quaternion: FloatVector4 { - type SIMDVector3; - - #[inline] - fn from_axis_angle(axis: XYZ, angle: T) -> Self { - glam_assert!(FloatVector3::is_normalized(axis)); - let (s, c) = (angle * T::HALF).sin_cos(); - let v = axis.mul_scalar(s); - Self::new(v.x, v.y, v.z, c) - } - - #[inline] - fn from_rotation_x(angle: T) -> Self { - let (s, c) = (angle * T::HALF).sin_cos(); - Self::new(s, T::ZERO, T::ZERO, c) - } - - #[inline] - fn from_rotation_y(angle: T) -> Self { - let (s, c) = (angle * T::HALF).sin_cos(); - Self::new(T::ZERO, s, T::ZERO, c) - } - - #[inline] - fn from_rotation_z(angle: T) -> Self { - let (s, c) = (angle * T::HALF).sin_cos(); - Self::new(T::ZERO, T::ZERO, s, c) - } - - /// From the columns of a 3x3 rotation matrix. - #[inline] - fn from_rotation_axes(x_axis: XYZ, y_axis: XYZ, z_axis: XYZ) -> Self { - // Based on https://github.com/microsoft/DirectXMath `XM$quaternionRotationMatrix` - // TODO: sse2 version - let (m00, m01, m02) = x_axis.into_tuple(); - let (m10, m11, m12) = y_axis.into_tuple(); - let (m20, m21, m22) = z_axis.into_tuple(); - if m22 <= T::ZERO { - // x^2 + y^2 >= z^2 + w^2 - let dif10 = m11 - m00; - let omm22 = T::ONE - m22; - if dif10 <= T::ZERO { - // x^2 >= y^2 - let four_xsq = omm22 - dif10; - let inv4x = T::HALF / four_xsq.sqrt(); - Self::new( - four_xsq * inv4x, - (m01 + m10) * inv4x, - (m02 + m20) * inv4x, - (m12 - m21) * inv4x, - ) - } else { - // y^2 >= x^2 - let four_ysq = omm22 + dif10; - let inv4y = T::HALF / four_ysq.sqrt(); - Self::new( - (m01 + m10) * inv4y, - four_ysq * inv4y, - (m12 + m21) * inv4y, - (m20 - m02) * inv4y, - ) - } - } else { - // z^2 + w^2 >= x^2 + y^2 - let sum10 = m11 + m00; - let opm22 = T::ONE + m22; - if sum10 <= T::ZERO { - // z^2 >= w^2 - let four_zsq = opm22 - sum10; - let inv4z = T::HALF / four_zsq.sqrt(); - Self::new( - (m02 + m20) * inv4z, - (m12 + m21) * inv4z, - four_zsq * inv4z, - (m01 - m10) * inv4z, - ) - } else { - // w^2 >= z^2 - let four_wsq = opm22 + sum10; - let inv4w = T::HALF / four_wsq.sqrt(); - Self::new( - (m12 - m21) * inv4w, - (m20 - m02) * inv4w, - (m01 - m10) * inv4w, - four_wsq * inv4w, - ) - } - } - } - - fn to_axis_angle(self) -> (XYZ, T) { - // const EPSILON: f32 = 1.0e-8; - // const EPSILON_SQUARED: f32 = EPSILON * EPSILON; - let (x, y, z, w) = Vector4::into_tuple(self); - let angle = w.acos_approx() * T::TWO; - let scale_sq = NumEx::max(T::ONE - w * w, T::ZERO); - // TODO: constants for epslions? - if scale_sq >= T::from_f32(1.0e-8 * 1.0e-8) { - (XYZ { x, y, z }.mul_scalar(scale_sq.sqrt().recip()), angle) - } else { - (Vector3Const::X, angle) - } - } - - #[inline] - fn is_near_identity(self) -> bool { - // Based on https://github.com/nfrechette/rtm `rtm::quat_near_identity` - let threshold_angle = T::from_f64(0.002_847_144_6); - // Because of floating point precision, we cannot represent very small rotations. - // The closest f32 to 1.0 that is not 1.0 itself yields: - // 0.99999994.acos() * 2.0 = 0.000690533954 rad - // - // An error threshold of 1.e-6 is used by default. - // (1.0 - 1.e-6).acos() * 2.0 = 0.00284714461 rad - // (1.0 - 1.e-7).acos() * 2.0 = 0.00097656250 rad - // - // We don't really care about the angle value itself, only if it's close to 0. - // This will happen whenever quat.w is close to 1.0. - // If the quat.w is close to -1.0, the angle will be near 2*PI which is close to - // a negative 0 rotation. By forcing quat.w to be positive, we'll end up with - // the shortest path. - let positive_w_angle = self.as_ref_xyzw().w.abs().acos_approx() * T::TWO; - positive_w_angle < threshold_angle - } - - fn conjugate(self) -> Self; - fn lerp(self, end: Self, s: T) -> Self; - fn slerp(self, end: Self, s: T) -> Self; - fn mul_quaternion(self, other: Self) -> Self; - fn mul_vector3(self, other: XYZ) -> XYZ; - fn mul_float4_as_vector3(self, other: Self::SIMDVector3) -> Self::SIMDVector3; -} diff --git a/src/core/traits/scalar.rs b/src/core/traits/scalar.rs deleted file mode 100644 index bf2b1352..00000000 --- a/src/core/traits/scalar.rs +++ /dev/null @@ -1,434 +0,0 @@ -// Wait until this bug is fix and float cmp to zero don't report a warning. -// https://github.com/rust-lang/rust-clippy/issues/3804 -#![allow(clippy::float_cmp)] -// num_traits is optional as it adds 70% to compile times. It is needed by no_std builds -#[cfg(feature = "libm")] -pub use num_traits::{Float, Num, Signed}; - -use core::{ - marker::Sized, - ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Not, Rem, Shl, Shr, Sub}, -}; - -// Stub the necessary parts of num traits -#[cfg(not(feature = "libm"))] -pub trait Num: PartialEq {} - -#[cfg(not(feature = "libm"))] -pub trait Signed: Sized + Num + core::ops::Neg { - fn abs(self) -> Self; - fn signum(self) -> Self; -} - -#[cfg(not(feature = "libm"))] -pub trait Float: Num + Copy + core::ops::Neg { - fn asin(self) -> Self; - fn acos(self) -> Self; - fn ceil(self) -> Self; - fn exp(self) -> Self; - fn floor(self) -> Self; - fn is_finite(self) -> bool; - fn is_nan(self) -> bool; - fn mul_add(self, b: Self, c: Self) -> Self; - fn powf(self, n: Self) -> Self; - fn recip(self) -> Self; - fn round(self) -> Self; - fn sqrt(self) -> Self; - fn sin(self) -> Self; - fn sin_cos(self) -> (Self, Self); - fn tan(self) -> Self; -} - -#[cfg(not(feature = "libm"))] -macro_rules! impl_num_trait { - ($t:ident) => { - impl Num for $t {} - }; -} - -#[cfg(not(feature = "libm"))] -macro_rules! impl_signed_trait { - ($t:ident) => { - impl_num_trait!($t); - - impl Signed for $t { - #[inline(always)] - fn abs(self) -> Self { - $t::abs(self) - } - #[inline(always)] - fn signum(self) -> Self { - $t::signum(self) - } - } - }; -} - -#[cfg(not(feature = "libm"))] -macro_rules! impl_float_trait { - ($t:ident) => { - impl_signed_trait!($t); - - impl Float for $t { - #[inline(always)] - fn asin(self) -> Self { - $t::asin(self) - } - #[inline(always)] - fn acos(self) -> Self { - $t::acos(self) - } - #[inline(always)] - fn ceil(self) -> Self { - $t::ceil(self) - } - #[inline(always)] - fn exp(self) -> Self { - $t::exp(self) - } - #[inline(always)] - fn floor(self) -> Self { - $t::floor(self) - } - #[inline(always)] - fn is_finite(self) -> bool { - $t::is_finite(self) - } - #[inline(always)] - fn is_nan(self) -> bool { - $t::is_nan(self) - } - #[inline(always)] - fn mul_add(self, b: Self, c: Self) -> Self { - $t::mul_add(self, b, c) - } - #[inline(always)] - fn powf(self, n: Self) -> Self { - $t::powf(self, n) - } - #[inline(always)] - fn recip(self) -> Self { - $t::recip(self) - } - #[inline(always)] - fn round(self) -> Self { - $t::round(self) - } - #[inline(always)] - fn sin(self) -> Self { - $t::sin(self) - } - #[inline(always)] - fn sin_cos(self) -> (Self, Self) { - $t::sin_cos(self) - } - #[inline(always)] - fn sqrt(self) -> Self { - $t::sqrt(self) - } - #[inline(always)] - fn tan(self) -> Self { - $t::tan(self) - } - } - }; -} - -#[cfg(not(feature = "libm"))] -impl_float_trait!(f32); -#[cfg(not(feature = "libm"))] -impl_float_trait!(f64); -#[cfg(not(feature = "libm"))] -impl_signed_trait!(i32); -#[cfg(not(feature = "libm"))] -impl_num_trait!(u32); - -pub trait MaskConst: Sized { - const MASK: [Self; 2]; -} - -pub trait NumConstEx: Sized { - const ZERO: Self; - const ONE: Self; -} - -pub trait FloatConstEx: Sized { - const NEG_ONE: Self; - const TWO: Self; - const HALF: Self; -} - -pub trait NanConstEx: Sized { - const NAN: Self; -} - -pub trait NumEx: - Num - + NumConstEx - + Copy - + Clone - + PartialEq - + PartialOrd - + Add - + Div - + Mul - + Sub - + Rem -{ - fn min(self, other: Self) -> Self; - fn max(self, other: Self) -> Self; -} - -pub trait SignedEx: Signed + NumEx {} - -pub trait FloatEx: Float + FloatConstEx + SignedEx + NanConstEx { - /// Returns a very close approximation of `self.clamp(-1.0, 1.0).acos()`. - fn acos_approx(self) -> Self; - fn from_f32(f: f32) -> Self; - fn from_f64(f: f64) -> Self; -} - -impl NumConstEx for f32 { - const ZERO: Self = 0.0; - const ONE: Self = 1.0; -} - -impl NanConstEx for f32 { - const NAN: Self = f32::NAN; -} - -impl FloatConstEx for f32 { - const NEG_ONE: Self = -1.0; - const TWO: Self = 2.0; - const HALF: Self = 0.5; -} - -impl NumEx for f32 { - #[inline(always)] - fn min(self, other: Self) -> Self { - f32::min(self, other) - } - #[inline(always)] - fn max(self, other: Self) -> Self { - f32::max(self, other) - } -} - -impl SignedEx for f32 {} - -impl FloatEx for f32 { - #[inline(always)] - fn from_f32(v: f32) -> Self { - v - } - #[inline(always)] - fn from_f64(v: f64) -> Self { - v as Self - } - #[inline(always)] - fn acos_approx(self) -> Self { - // Based on https://github.com/microsoft/DirectXMath `XMScalarAcos` - // Clamp input to [-1,1]. - let nonnegative = self >= 0.0; - let x = self.abs(); - let mut omx = 1.0 - x; - if omx < 0.0 { - omx = 0.0; - } - let root = omx.sqrt(); - - // 7-degree minimax approximation - #[allow(clippy::approx_constant)] - let mut result = ((((((-0.001_262_491_1 * x + 0.006_670_09) * x - 0.017_088_126) * x - + 0.030_891_88) - * x - - 0.050_174_303) - * x - + 0.088_978_99) - * x - - 0.214_598_8) - * x - + 1.570_796_3; - result *= root; - - // acos(x) = pi - acos(-x) when x < 0 - if nonnegative { - result - } else { - core::f32::consts::PI - result - } - } -} - -impl NumConstEx for f64 { - const ZERO: Self = 0.0; - const ONE: Self = 1.0; -} - -impl NanConstEx for f64 { - const NAN: Self = f64::NAN; -} - -impl FloatConstEx for f64 { - const NEG_ONE: Self = -1.0; - const TWO: Self = 2.0; - const HALF: Self = 0.5; -} - -impl NumEx for f64 { - #[inline(always)] - fn min(self, other: Self) -> Self { - f64::min(self, other) - } - #[inline(always)] - fn max(self, other: Self) -> Self { - f64::max(self, other) - } -} - -impl SignedEx for f64 {} - -impl FloatEx for f64 { - #[inline(always)] - fn from_f32(v: f32) -> Self { - v as Self - } - #[inline(always)] - fn from_f64(v: f64) -> Self { - v - } - #[inline(always)] - fn acos_approx(self) -> Self { - f64::acos(self.max(-1.0).min(1.0)) - } -} - -impl NumConstEx for i32 { - const ZERO: Self = 0; - const ONE: Self = 1; -} - -impl NumEx for i32 { - #[inline(always)] - fn min(self, other: Self) -> Self { - core::cmp::min(self, other) - } - #[inline(always)] - fn max(self, other: Self) -> Self { - core::cmp::max(self, other) - } -} - -impl SignedEx for i32 {} - -impl NumConstEx for u32 { - const ZERO: Self = 0; - const ONE: Self = 1; -} - -impl NumEx for u32 { - #[inline(always)] - fn min(self, other: Self) -> Self { - core::cmp::min(self, other) - } - #[inline(always)] - fn max(self, other: Self) -> Self { - core::cmp::max(self, other) - } -} - -pub trait IntegerShiftOps: Sized + Shl + Shr {} - -pub trait IntegerBitOps: - Sized + Not + BitAnd + BitOr + BitXor -{ -} - -impl IntegerShiftOps for i32 {} -impl IntegerShiftOps for i32 {} -impl IntegerShiftOps for i32 {} -impl IntegerShiftOps for i32 {} -impl IntegerShiftOps for i32 {} -impl IntegerShiftOps for i32 {} - -impl IntegerShiftOps for u32 {} -impl IntegerShiftOps for u32 {} -impl IntegerShiftOps for u32 {} -impl IntegerShiftOps for u32 {} -impl IntegerShiftOps for u32 {} -impl IntegerShiftOps for u32 {} - -impl IntegerBitOps for i32 {} -impl IntegerBitOps for u32 {} - -#[cfg(test)] -macro_rules! assert_approx_eq { - ($a:expr, $b:expr) => {{ - assert_approx_eq!($a, $b, core::f32::EPSILON); - }}; - ($a:expr, $b:expr, $eps:expr) => {{ - let (a, b) = (&$a, &$b); - let eps = $eps; - assert!( - (a - b).abs() <= eps, - "assertion failed: `(left !== right)` \ - (left: `{:?}`, right: `{:?}`, expect diff: `{:?}`, real diff: `{:?}`)", - *a, - *b, - eps, - (a - b).abs() - ); - }}; -} - -#[cfg(test)] -macro_rules! assert_relative_eq { - ($a:expr, $b:expr) => {{ - assert_relative_eq!($a, $b, core::f32::EPSILON); - }}; - ($a:expr, $b:expr, $eps:expr) => {{ - let (a, b) = (&$a, &$b); - let eps = $eps; - let diff = (a - b).abs(); - let largest = a.abs().max(b.abs()); - assert!( - diff <= largest * eps, - "assertion failed: `(left !== right)` \ - (left: `{:?}`, right: `{:?}`, expect diff: `{:?}`, real diff: `{:?}`)", - *a, - *b, - largest * eps, - diff - ); - }}; -} - -#[test] -fn test_scalar_acos() { - fn test_scalar_acos_angle(a: f32) { - // 1e-6 is the lowest epsilon that will pass - assert_relative_eq!(a.acos_approx(), a.acos(), 1e-6); - // assert_approx_eq!(scalar_acos(a), a.acos(), 1e-6); - } - - // test 1024 floats between -1.0 and 1.0 inclusive - const MAX_TESTS: u32 = 1024 / 2; - const SIGN: u32 = 0x80_00_00_00; - const PTVE_ONE: u32 = 0x3f_80_00_00; // 1.0_f32.to_bits(); - const NGVE_ONE: u32 = SIGN | PTVE_ONE; - const STEP_SIZE: usize = (PTVE_ONE / MAX_TESTS) as usize; - for f in (SIGN..=NGVE_ONE).step_by(STEP_SIZE).map(f32::from_bits) { - test_scalar_acos_angle(f); - } - for f in (0..=PTVE_ONE).step_by(STEP_SIZE).map(f32::from_bits) { - test_scalar_acos_angle(f); - } - - // input is clamped to -1.0..1.0 - assert_approx_eq!(2.0_f32.acos_approx(), 0.0); - assert_approx_eq!((-2.0_f32).acos_approx(), core::f32::consts::PI); - - // input is clamped to -1.0..1.0 - assert_eq!(2.0_f64.acos_approx(), 0.0); - assert!(((-2.0_f64).acos_approx() - core::f64::consts::PI).abs() < f64::EPSILON); -} diff --git a/src/core/traits/vector.rs b/src/core/traits/vector.rs deleted file mode 100644 index 555cc3fa..00000000 --- a/src/core/traits/vector.rs +++ /dev/null @@ -1,864 +0,0 @@ -use super::scalar::{FloatEx, SignedEx}; -use crate::core::storage::{XY, XYZ, XYZW}; -use core::ops::{Add, Mul, Sub}; - -/// Mask vector constants that are independent of vector length -pub trait MaskVectorConst: Sized { - const FALSE: Self; -} - -/// Mask vector methods that are independent of vector dimension. -pub trait MaskVector: MaskVectorConst { - fn bitand(self, other: Self) -> Self; - fn bitor(self, other: Self) -> Self; - fn not(self) -> Self; -} - -/// Mask vector methods specific to 2D vectors. -pub trait MaskVector2: MaskVector { - fn new(x: bool, y: bool) -> Self; - fn bitmask(self) -> u32; - fn any(self) -> bool; - fn all(self) -> bool; - fn into_bool_array(self) -> [bool; 2]; - fn into_u32_array(self) -> [u32; 2]; -} - -/// Mask vector methods specific to 3D vectors. -pub trait MaskVector3: MaskVector { - fn new(x: bool, y: bool, z: bool) -> Self; - fn bitmask(self) -> u32; - fn any(self) -> bool; - fn all(self) -> bool; - fn into_bool_array(self) -> [bool; 3]; - fn into_u32_array(self) -> [u32; 3]; -} - -/// Mask vector methods specific to 4D vectors. -pub trait MaskVector4: MaskVector { - fn new(x: bool, y: bool, z: bool, w: bool) -> Self; - fn bitmask(self) -> u32; - fn any(self) -> bool; - fn all(self) -> bool; - fn into_bool_array(self) -> [bool; 4]; - fn into_u32_array(self) -> [u32; 4]; -} - -/// Vector constants that are independent of vector dimension. -pub trait VectorConst { - const ZERO: Self; - const ONE: Self; -} - -/// Vector constants specific to 2D vectors. -pub trait Vector2Const: VectorConst { - const X: Self; - const Y: Self; -} - -/// Vector constants specific to 3D vectors. -pub trait Vector3Const: VectorConst { - const X: Self; - const Y: Self; - const Z: Self; -} - -/// Vector constants specific to 4D vectors. -pub trait Vector4Const: VectorConst { - const X: Self; - const Y: Self; - const Z: Self; - const W: Self; -} - -/// Vector methods that are independent of vector dimension. -/// -/// These methods typically need to be implemented for each type as while the method signature does -/// not imply any dimensionality, the implementation does. -pub trait Vector: Sized + Copy + Clone { - type Mask; - - fn splat(s: T) -> Self; - - fn select(mask: Self::Mask, a: Self, b: Self) -> Self; - - fn cmpeq(self, other: Self) -> Self::Mask; - fn cmpne(self, other: Self) -> Self::Mask; - fn cmpge(self, other: Self) -> Self::Mask; - fn cmpgt(self, other: Self) -> Self::Mask; - fn cmple(self, other: Self) -> Self::Mask; - fn cmplt(self, other: Self) -> Self::Mask; - - fn add(self, other: Self) -> Self; - fn div(self, other: Self) -> Self; - fn mul(self, other: Self) -> Self; - fn rem(self, rhs: Self) -> Self; - fn sub(self, other: Self) -> Self; - - fn scale(self, other: T) -> Self { - self.mul_scalar(other) - } - - fn add_scalar(self, other: T) -> Self; - fn sub_scalar(self, other: T) -> Self; - fn mul_scalar(self, other: T) -> Self; - fn div_scalar(self, other: T) -> Self; - fn rem_scalar(self, rhs: T) -> Self; - - fn min(self, other: Self) -> Self; - fn max(self, other: Self) -> Self; -} - -/// Vector methods specific to 2D vectors. -pub trait Vector2: Vector + Vector2Const -where - T: Copy + Mul + Sub + Add, -{ - fn new(x: T, y: T) -> Self; - fn x(self) -> T; - fn y(self) -> T; - - fn as_ref_xy(&self) -> &XY; - fn as_mut_xy(&mut self) -> &mut XY; - - // min and max behave differently for float and integer types in Rust, so we can't have a - // default implementation here. - fn min_element(self) -> T; - fn max_element(self) -> T; - fn clamp(self, min: Self, max: Self) -> Self; - - #[inline(always)] - fn splat_x(self) -> Self { - Self::splat(self.x()) - } - - #[inline(always)] - fn splat_y(self) -> Self { - Self::splat(self.y()) - } - - #[inline(always)] - fn from_slice_unaligned(slice: &[T]) -> Self { - Self::new(slice[0], slice[1]) - } - - #[inline(always)] - fn write_to_slice_unaligned(self, slice: &mut [T]) { - slice[0] = self.x(); - slice[1] = self.y(); - } - - #[inline(always)] - fn into_xyz(self, z: T) -> XYZ { - XYZ { - x: self.x(), - y: self.y(), - z, - } - } - - #[inline(always)] - fn into_xyzw(self, z: T, w: T) -> XYZW { - XYZW { - x: self.x(), - y: self.y(), - z, - w, - } - } - - #[inline(always)] - fn from_array(a: [T; 2]) -> Self { - Self::new(a[0], a[1]) - } - - #[inline(always)] - fn into_array(self) -> [T; 2] { - [self.x(), self.y()] - } - - #[inline(always)] - fn from_tuple(t: (T, T)) -> Self { - Self::new(t.0, t.1) - } - - #[inline(always)] - fn into_tuple(self) -> (T, T) { - (self.x(), self.y()) - } - - #[inline] - fn dot(self, other: Self) -> T { - (self.x() * other.x()) + (self.y() * other.y()) - } - - #[inline(always)] - fn dot_into_vec(self, other: Self) -> Self { - Self::splat(self.dot(other)) - } -} - -/// Vector methods specific to 3D vectors. -pub trait Vector3: Vector + Vector3Const -where - T: Copy + Mul + Sub + Add, -{ - fn new(x: T, y: T, z: T) -> Self; - fn x(self) -> T; - fn y(self) -> T; - fn z(self) -> T; - - fn as_ref_xyz(&self) -> &XYZ; - fn as_mut_xyz(&mut self) -> &mut XYZ; - - fn min_element(self) -> T; - fn max_element(self) -> T; - fn clamp(self, min: Self, max: Self) -> Self; - - #[inline(always)] - fn splat_x(self) -> Self { - Self::splat(self.x()) - } - - #[inline(always)] - fn splat_y(self) -> Self { - Self::splat(self.y()) - } - - #[inline(always)] - fn splat_z(self) -> Self { - Self::splat(self.z()) - } - - #[inline(always)] - fn from_slice_unaligned(slice: &[T]) -> Self { - Self::new(slice[0], slice[1], slice[2]) - } - - #[inline(always)] - fn write_to_slice_unaligned(self, slice: &mut [T]) { - slice[0] = self.x(); - slice[1] = self.y(); - slice[2] = self.z(); - } - - #[inline(always)] - fn from_xy(v2: XY, z: T) -> Self { - Self::new(v2.x, v2.y, z) - } - - #[inline(always)] - fn from_xyzw(v4: XYZW) -> Self { - Self::new(v4.x, v4.y, v4.z) - } - - #[inline(always)] - fn into_xy(self) -> XY { - XY { - x: self.x(), - y: self.y(), - } - } - - #[inline(always)] - fn into_xyzw(self, w: T) -> XYZW { - XYZW { - x: self.x(), - y: self.y(), - z: self.z(), - w, - } - } - - #[inline(always)] - fn from_array(a: [T; 3]) -> Self { - Self::new(a[0], a[1], a[2]) - } - - #[inline(always)] - fn into_array(self) -> [T; 3] { - [self.x(), self.y(), self.z()] - } - - #[inline(always)] - fn from_tuple(t: (T, T, T)) -> Self { - Self::new(t.0, t.1, t.2) - } - - #[inline(always)] - fn into_tuple(self) -> (T, T, T) { - (self.x(), self.y(), self.z()) - } - - #[inline] - fn dot(self, other: Self) -> T { - (self.x() * other.x()) + (self.y() * other.y()) + (self.z() * other.z()) - } - - #[inline(always)] - fn dot_into_vec(self, other: Self) -> Self { - Self::splat(self.dot(other)) - } - - #[inline] - fn cross(self, other: Self) -> Self { - Self::new( - self.y() * other.z() - other.y() * self.z(), - self.z() * other.x() - other.z() * self.x(), - self.x() * other.y() - other.x() * self.y(), - ) - } -} - -/// Vector methods specific to 3D vectors. -pub trait Vector4: Vector + Vector4Const -where - T: Copy + Mul + Sub + Add, -{ - fn new(x: T, y: T, z: T, w: T) -> Self; - - fn x(self) -> T; - fn y(self) -> T; - fn z(self) -> T; - fn w(self) -> T; - - fn as_ref_xyzw(&self) -> &XYZW; - fn as_mut_xyzw(&mut self) -> &mut XYZW; - - fn min_element(self) -> T; - fn max_element(self) -> T; - fn clamp(self, min: Self, max: Self) -> Self; - - #[inline(always)] - fn splat_x(self) -> Self { - Self::splat(self.x()) - } - - #[inline(always)] - fn splat_y(self) -> Self { - Self::splat(self.y()) - } - - #[inline(always)] - fn splat_z(self) -> Self { - Self::splat(self.z()) - } - - #[inline(always)] - fn splat_w(self) -> Self { - Self::splat(self.w()) - } - - #[inline(always)] - fn from_slice_unaligned(slice: &[T]) -> Self { - Self::new(slice[0], slice[1], slice[2], slice[3]) - } - - #[inline(always)] - fn write_to_slice_unaligned(self, slice: &mut [T]) { - slice[0] = self.x(); - slice[1] = self.y(); - slice[2] = self.z(); - slice[3] = self.w(); - } - - #[inline(always)] - fn from_xy(v2: XY, z: T, w: T) -> Self { - Self::new(v2.x, v2.y, z, w) - } - - #[inline(always)] - fn from_xyz(v3: XYZ, w: T) -> Self { - Self::new(v3.x, v3.y, v3.z, w) - } - - #[inline(always)] - fn into_xy(self) -> XY { - XY { - x: self.x(), - y: self.y(), - } - } - - #[inline(always)] - fn into_xyz(self) -> XYZ { - XYZ { - x: self.x(), - y: self.y(), - z: self.z(), - } - } - - #[inline(always)] - fn from_array(a: [T; 4]) -> Self { - Self::new(a[0], a[1], a[2], a[3]) - } - - #[inline(always)] - fn into_array(self) -> [T; 4] { - [self.x(), self.y(), self.z(), self.w()] - } - - #[inline(always)] - fn from_tuple(t: (T, T, T, T)) -> Self { - Self::new(t.0, t.1, t.2, t.3) - } - - #[inline(always)] - fn into_tuple(self) -> (T, T, T, T) { - (self.x(), self.y(), self.z(), self.w()) - } - - #[inline] - fn dot(self, other: Self) -> T { - (self.x() * other.x()) - + (self.y() * other.y()) - + (self.z() * other.z()) - + (self.w() * other.w()) - } - - #[inline(always)] - fn dot_into_vec(self, other: Self) -> Self { - Self::splat(self.dot(other)) - } -} - -/// Vector methods for vectors of signed types that are independent of vector dimension. -/// -/// These methods typically need to be implemented for each type as while the method signature does -/// not imply any dimensionality, the implementation does. -pub trait SignedVector: Vector { - fn neg(self) -> Self; -} - -/// Vector methods specific to 2D vectors of signed types. -pub trait SignedVector2: SignedVector + Vector2 { - #[inline] - fn abs(self) -> Self { - Self::new(self.x().abs(), self.y().abs()) - } - - #[inline] - fn signum(self) -> Self { - Self::new(self.x().signum(), self.y().signum()) - } - - #[inline] - fn perp(self) -> Self { - Self::new(-self.y(), self.x()) - } - - #[inline] - fn perp_dot(self, other: Self) -> T { - (self.x() * other.y()) - (self.y() * other.x()) - } - - #[inline] - fn rotate(self, other: Self) -> Self { - Self::new( - self.x() * other.x() - self.y() * other.y(), - self.y() * other.x() + self.x() * other.y(), - ) - } -} - -/// Vector methods specific to 3D vectors of signed types. -pub trait SignedVector3: SignedVector + Vector3 { - #[inline] - fn abs(self) -> Self { - Self::new(self.x().abs(), self.y().abs(), self.z().abs()) - } - - #[inline] - fn signum(self) -> Self { - Self::new(self.x().signum(), self.y().signum(), self.z().signum()) - } -} - -pub trait SignedVector4: SignedVector + Vector4 { - #[inline] - fn abs(self) -> Self { - Self::new( - self.x().abs(), - self.y().abs(), - self.z().abs(), - self.w().abs(), - ) - } - - #[inline] - fn signum(self) -> Self { - Self::new( - self.x().signum(), - self.y().signum(), - self.z().signum(), - self.w().signum(), - ) - } -} - -pub trait FloatVector2: SignedVector2 { - #[inline] - fn from_angle(angle: T) -> Self { - let (sin, cos) = angle.sin_cos(); - Self::new(cos, sin) - } - - #[inline] - fn floor(self) -> Self { - Self::new(self.x().floor(), self.y().floor()) - } - - #[inline] - fn ceil(self) -> Self { - Self::new(self.x().ceil(), self.y().ceil()) - } - - #[inline] - fn round(self) -> Self { - Self::new(self.x().round(), self.y().round()) - } - - #[inline] - fn recip(self) -> Self { - Self::new(self.x().recip(), self.y().recip()) - } - - #[inline] - fn exp(self) -> Self { - Self::new(self.x().exp(), self.y().exp()) - } - - #[inline] - fn powf(self, n: T) -> Self { - Self::new(self.x().powf(n), self.y().powf(n)) - } - - #[inline] - fn is_finite(self) -> bool { - self.x().is_finite() && self.y().is_finite() - } - - #[inline] - fn is_nan(self) -> bool { - self.x().is_nan() || self.y().is_nan() - } - - #[inline] - fn mul_add(self, b: Self, c: Self) -> Self { - Self::new( - self.x().mul_add(b.x(), c.x()), - self.y().mul_add(b.y(), c.y()), - ) - } - - #[inline] - fn is_nan_mask(self) -> Self::Mask - where - >::Mask: MaskVector2, - { - Self::Mask::new(self.x().is_nan(), self.y().is_nan()) - } - - #[inline] - fn length(self) -> T { - self.dot(self).sqrt() - } - - #[inline] - fn length_recip(self) -> T { - self.length().recip() - } - - #[inline] - fn normalize(self) -> Self { - #[allow(clippy::let_and_return)] - let normalized = self.mul_scalar(self.length_recip()); - glam_assert!(normalized.is_finite()); - normalized - } - - #[inline(always)] - fn length_squared(self) -> T { - self.dot(self) - } - - #[inline] - fn is_normalized(self) -> bool { - // TODO: do something with epsilon - (self.length_squared() - T::ONE).abs() <= T::from_f64(1e-4) - } - - #[inline] - fn abs_diff_eq(self, other: Self, max_abs_diff: T) -> bool - where - >::Mask: MaskVector2, - { - self.sub(other).abs().cmple(Self::splat(max_abs_diff)).all() - } - - #[inline] - fn angle_between(self, other: Self) -> T { - let angle = (self.dot(other) / (self.length_squared() * other.length_squared()).sqrt()) - .acos_approx(); - - angle * self.perp_dot(other).signum() - } -} - -pub trait FloatVector3: SignedVector3 { - #[inline] - fn floor(self) -> Self { - Self::new(self.x().floor(), self.y().floor(), self.z().floor()) - } - - #[inline] - fn ceil(self) -> Self { - Self::new(self.x().ceil(), self.y().ceil(), self.z().ceil()) - } - - #[inline] - fn round(self) -> Self { - Self::new(self.x().round(), self.y().round(), self.z().round()) - } - - #[inline] - fn recip(self) -> Self { - Self::new(self.x().recip(), self.y().recip(), self.z().recip()) - } - - #[inline] - fn exp(self) -> Self { - Self::new(self.x().exp(), self.y().exp(), self.z().exp()) - } - - #[inline] - fn powf(self, n: T) -> Self { - Self::new(self.x().powf(n), self.y().powf(n), self.z().powf(n)) - } - - #[inline] - fn is_finite(self) -> bool { - self.x().is_finite() && self.y().is_finite() && self.z().is_finite() - } - - #[inline] - fn is_nan(self) -> bool { - self.x().is_nan() || self.y().is_nan() || self.z().is_nan() - } - - #[inline] - fn mul_add(self, b: Self, c: Self) -> Self { - Self::new( - self.x().mul_add(b.x(), c.x()), - self.y().mul_add(b.y(), c.y()), - self.z().mul_add(b.z(), c.z()), - ) - } - - #[inline] - fn is_nan_mask(self) -> Self::Mask - where - >::Mask: MaskVector3, - { - Self::Mask::new(self.x().is_nan(), self.y().is_nan(), self.z().is_nan()) - } - - #[inline] - fn length(self) -> T { - self.dot(self).sqrt() - } - - #[inline] - fn length_recip(self) -> T { - self.length().recip() - } - - #[inline] - fn normalize(self) -> Self { - #[allow(clippy::let_and_return)] - let normalized = self.mul_scalar(self.length_recip()); - glam_assert!(normalized.is_finite()); - normalized - } - - #[inline(always)] - fn length_squared(self) -> T { - self.dot(self) - } - - #[inline] - fn is_normalized(self) -> bool { - // TODO: do something with epsilon - (self.length_squared() - T::ONE).abs() <= T::from_f64(1e-4) - } - - #[inline] - fn abs_diff_eq(self, other: Self, max_abs_diff: T) -> bool - where - >::Mask: MaskVector3, - { - self.sub(other).abs().cmple(Self::splat(max_abs_diff)).all() - } - - fn angle_between(self, other: Self) -> T { - self.dot(other) - .div(self.length_squared().mul(other.length_squared()).sqrt()) - .acos_approx() - } -} - -pub trait FloatVector4: SignedVector4 { - #[inline] - fn floor(self) -> Self { - Self::new( - self.x().floor(), - self.y().floor(), - self.z().floor(), - self.w().floor(), - ) - } - - #[inline] - fn ceil(self) -> Self { - Self::new( - self.x().ceil(), - self.y().ceil(), - self.z().ceil(), - self.w().ceil(), - ) - } - - #[inline] - fn round(self) -> Self { - Self::new( - self.x().round(), - self.y().round(), - self.z().round(), - self.w().round(), - ) - } - - #[inline] - fn recip(self) -> Self { - Self::new( - self.x().recip(), - self.y().recip(), - self.z().recip(), - self.w().recip(), - ) - } - - #[inline] - fn exp(self) -> Self { - Self::new( - self.x().exp(), - self.y().exp(), - self.z().exp(), - self.w().exp(), - ) - } - - #[inline] - fn powf(self, n: T) -> Self { - Self::new( - self.x().powf(n), - self.y().powf(n), - self.z().powf(n), - self.w().powf(n), - ) - } - - #[inline] - fn is_finite(self) -> bool { - self.x().is_finite() && self.y().is_finite() && self.z().is_finite() && self.w().is_finite() - } - - #[inline] - fn is_nan(self) -> bool { - self.x().is_nan() || self.y().is_nan() || self.z().is_nan() || self.w().is_nan() - } - - #[inline] - fn mul_add(self, b: Self, c: Self) -> Self { - Self::new( - self.x().mul_add(b.x(), c.x()), - self.y().mul_add(b.y(), c.y()), - self.z().mul_add(b.z(), c.z()), - self.w().mul_add(b.w(), c.w()), - ) - } - - #[inline] - fn is_nan_mask(self) -> Self::Mask - where - >::Mask: MaskVector4, - { - Self::Mask::new( - self.x().is_nan(), - self.y().is_nan(), - self.z().is_nan(), - self.w().is_nan(), - ) - } - - #[inline] - fn length(self) -> T { - self.dot(self).sqrt() - } - - #[inline] - fn length_recip(self) -> T { - self.length().recip() - } - - #[inline] - fn normalize(self) -> Self { - #[allow(clippy::let_and_return)] - let normalized = self.mul_scalar(self.length_recip()); - glam_assert!(normalized.is_finite()); - normalized - } - - #[inline(always)] - fn length_squared(self) -> T { - self.dot(self) - } - - #[inline] - fn is_normalized(self) -> bool { - // TODO: do something with epsilon - (self.length_squared() - T::ONE).abs() <= T::from_f64(1e-4) - } - - #[inline] - fn abs_diff_eq(self, other: Self, max_abs_diff: T) -> bool - where - >::Mask: MaskVector4, - { - self.sub(other).abs().cmple(Self::splat(max_abs_diff)).all() - } -} - -pub trait ScalarShiftOps { - fn scalar_shl(self, rhs: Rhs) -> Self; - fn scalar_shr(self, rhs: Rhs) -> Self; -} - -pub trait VectorShiftOps { - fn vector_shl(self, rhs: Rhs) -> Self; - fn vector_shr(self, rhs: Rhs) -> Self; -} - -pub trait ScalarBitOps { - fn scalar_bitand(self, rhs: Rhs) -> Self; - fn scalar_bitor(self, rhs: Rhs) -> Self; - fn scalar_bitxor(self, rhs: Rhs) -> Self; -} - -pub trait VectorBitOps { - fn not(self) -> Self; - fn vector_bitand(self, rhs: Rhs) -> Self; - fn vector_bitor(self, rhs: Rhs) -> Self; - fn vector_bitxor(self, rhs: Rhs) -> Self; -} diff --git a/src/core/wasm32.rs b/src/core/wasm32.rs deleted file mode 100644 index 23a1dff8..00000000 --- a/src/core/wasm32.rs +++ /dev/null @@ -1,4 +0,0 @@ -// mod float; -pub mod matrix; -pub mod quaternion; -pub mod vector; diff --git a/src/core/wasm32/float.rs b/src/core/wasm32/float.rs deleted file mode 100644 index 0bd80b40..00000000 --- a/src/core/wasm32/float.rs +++ /dev/null @@ -1,113 +0,0 @@ -use core::arch::wasm32::*; - -macro_rules! const_u32x4 { - ($ux4:expr) => { - unsafe { $crate::cast::UVec4Cast { ux4: $ux4 }.v128 } - }; -} - -const PS_NEGATIVE_ZERO: v128 = const_u32x4!([0x8000_0000; 4]); -const PS_PI: v128 = const_f32x4!([core::f32::consts::PI; 4]); -const PS_HALF_PI: v128 = const_f32x4!([core::f32::consts::FRAC_PI_2; 4]); -const PS_SIN_COEFFICIENTS0: v128 = - const_f32x4!([-0.16666667, 0.008_333_331, -0.00019840874, 2.752_556_2e-6]); -const PS_SIN_COEFFICIENTS1: v128 = const_f32x4!([ - -2.388_985_9e-8, - -0.16665852, /*Est1*/ - 0.008_313_95, /*Est2*/ - -0.000_185_246_7 /*Est3*/ -]); -const PS_ONE: v128 = const_f32x4!([1.0; 4]); -const PS_TWO_PI: v128 = const_f32x4!([core::f32::consts::TAU; 4]); -const PS_RECIPROCAL_TWO_PI: v128 = const_f32x4!([0.159_154_94; 4]); - -#[inline(always)] -pub(crate) fn v128_mul_add(a: v128, b: v128, c: v128) -> v128 { - f32x4_add(f32x4_mul(a, b), c) -} - -#[inline(always)] -pub(crate) fn v128_neg_mul_sub(a: v128, b: v128, c: v128) -> v128 { - f32x4_sub(c, f32x4_mul(a, b)) -} - -/// Returns a vector whose components are the corresponding components of Angles modulo 2PI. -#[inline] -pub(crate) fn v128_mod_angles(angles: v128) -> v128 { - // Based on https://github.com/microsoft/DirectXMath `XMVectorModAngles` - let v = f32x4_mul(angles, PS_RECIPROCAL_TWO_PI); - let v = f32x4_nearest(v); - v128_neg_mul_sub(PS_TWO_PI, v, angles) -} - -/// Computes the sine of the angle in each lane of `v`. Values outside -/// the bounds of PI may produce an increasing error as the input angle -/// drifts from `[-PI, PI]`. -#[inline] -pub(crate) fn v128_sin(v: v128) -> v128 { - // Based on https://github.com/microsoft/DirectXMath `XMVectorSin` - - // 11-degree minimax approximation - - // Force the value within the bounds of pi - let mut x = v128_mod_angles(v); - - // Map in [-pi/2,pi/2] with sin(y) = sin(x). - let sign = v128_and(x, PS_NEGATIVE_ZERO); - // pi when x >= 0, -pi when x < 0 - let c = v128_or(PS_PI, sign); - // |x| - let absx = v128_andnot(sign, x); - let rflx = f32x4_sub(c, x); - let comp = f32x4_le(absx, PS_HALF_PI); - let select0 = v128_and(comp, x); - let select1 = v128_andnot(comp, rflx); - x = v128_or(select0, select1); - - let x2 = f32x4_mul(x, x); - - // Compute polynomial approximation - const SC1: v128 = PS_SIN_COEFFICIENTS1; - let v_constants_b = i32x4_shuffle::<0, 0, 4, 4>(SC1, SC1); - - const SC0: v128 = PS_SIN_COEFFICIENTS0; - let mut v_constants = i32x4_shuffle::<3, 3, 7, 7>(SC0, SC0); - let mut result = v128_mul_add(v_constants_b, x2, v_constants); - - v_constants = i32x4_shuffle::<2, 2, 6, 6>(SC0, SC0); - result = v128_mul_add(result, x2, v_constants); - - v_constants = i32x4_shuffle::<1, 1, 5, 5>(SC0, SC0); - result = v128_mul_add(result, x2, v_constants); - - v_constants = i32x4_shuffle::<0, 0, 4, 4>(SC0, SC0); - result = v128_mul_add(result, x2, v_constants); - - result = v128_mul_add(result, x2, PS_ONE); - result = f32x4_mul(result, x); - - result -} - -#[test] -fn test_wasm32_v128_sin() { - use crate::core::traits::vector::*; - use core::f32::consts::PI; - - fn test_wasm32_v128_sin_angle(a: f32) { - let v = v128_sin(f32x4_splat(a)); - let v = v.as_ref_xyzw(); - let a_sin = a.sin(); - // dbg!((a, a_sin, v)); - assert!(v.abs_diff_eq(Vector::splat(a_sin), 1e-6)); - } - - let mut a = -PI; - let end = PI; - let step = PI / 8192.0; - - while a <= end { - test_wasm32_v128_sin_angle(a); - a += step; - } -} diff --git a/src/core/wasm32/matrix.rs b/src/core/wasm32/matrix.rs deleted file mode 100644 index d2a280ad..00000000 --- a/src/core/wasm32/matrix.rs +++ /dev/null @@ -1,532 +0,0 @@ -use core::{arch::wasm32::*, mem::MaybeUninit}; - -use crate::core::{ - storage::{Columns2, Columns3, Columns4, XY, XYZ}, - traits::{ - matrix::{ - FloatMatrix2x2, FloatMatrix3x3, FloatMatrix4x4, Matrix, Matrix2x2, Matrix3x3, - Matrix4x4, MatrixConst, - }, - projection::ProjectionMatrix, - scalar::NanConstEx, - vector::{FloatVector4, Vector, Vector4, Vector4Const, VectorConst}, - }, -}; - -// v128 as a Matrix2x2 -impl MatrixConst for v128 { - const ZERO: v128 = const_f32x4!([0.0, 0.0, 0.0, 0.0]); - const IDENTITY: v128 = const_f32x4!([1.0, 0.0, 0.0, 1.0]); -} - -impl Matrix for v128 {} - -impl Matrix2x2> for v128 { - #[inline(always)] - fn new(m00: f32, m01: f32, m10: f32, m11: f32) -> Self { - f32x4(m00, m01, m10, m11) - } - - #[inline(always)] - fn from_cols(x_axis: XY, y_axis: XY) -> Self { - Matrix2x2::new(x_axis.x, x_axis.y, y_axis.x, y_axis.y) - } - - #[inline(always)] - fn x_axis(&self) -> &XY { - unsafe { &(*(self as *const Self as *const Columns2>)).x_axis } - } - - #[inline(always)] - fn y_axis(&self) -> &XY { - unsafe { &(*(self as *const Self as *const Columns2>)).y_axis } - } - - #[inline] - fn determinant(&self) -> f32 { - // self.x_axis.x * self.y_axis.y - self.x_axis.y * self.y_axis.x - let abcd = *self; - let dcba = i32x4_shuffle::<3, 2, 5, 4>(abcd, abcd); - let prod = f32x4_mul(abcd, dcba); - let det = f32x4_sub(prod, i32x4_shuffle::<1, 1, 5, 5>(prod, prod)); - f32x4_extract_lane::<0>(det) - } - - #[inline(always)] - fn transpose(&self) -> Self { - i32x4_shuffle::<0, 2, 5, 7>(*self, *self) - } - - #[inline] - fn mul_vector(&self, other: XY) -> XY { - let abcd = *self; - let xxyy = f32x4(other.x, other.x, other.y, other.y); - let axbxcydy = f32x4_mul(abcd, xxyy); - let cydyaxbx = i32x4_shuffle::<2, 3, 4, 5>(axbxcydy, axbxcydy); - let result = f32x4_add(axbxcydy, cydyaxbx); - let mut out: MaybeUninit = MaybeUninit::uninit(); - unsafe { - v128_store(out.as_mut_ptr(), result); - *(&out.assume_init() as *const v128 as *const XY) - } - } - - #[inline] - fn mul_matrix(&self, other: &Self) -> Self { - let abcd = *self; - let other = *other; - let xxyy0 = i32x4_shuffle::<0, 0, 5, 5>(other, other); - let xxyy1 = i32x4_shuffle::<2, 2, 7, 7>(other, other); - let axbxcydy0 = f32x4_mul(abcd, xxyy0); - let axbxcydy1 = f32x4_mul(abcd, xxyy1); - let cydyaxbx0 = i32x4_shuffle::<2, 3, 4, 5>(axbxcydy0, axbxcydy0); - let cydyaxbx1 = i32x4_shuffle::<2, 3, 4, 5>(axbxcydy1, axbxcydy1); - let result0 = f32x4_add(axbxcydy0, cydyaxbx0); - let result1 = f32x4_add(axbxcydy1, cydyaxbx1); - i32x4_shuffle::<0, 1, 4, 5>(result0, result1) - } - - #[inline] - fn mul_scalar(&self, other: f32) -> Self { - f32x4_mul(*self, f32x4_splat(other)) - } - - #[inline] - fn add_matrix(&self, other: &Self) -> Self { - f32x4_add(*self, *other) - } - - #[inline] - fn sub_matrix(&self, other: &Self) -> Self { - f32x4_sub(*self, *other) - } -} - -impl FloatMatrix2x2> for v128 { - #[inline] - fn abs_diff_eq(&self, other: &Self, max_abs_diff: f32) -> bool { - FloatVector4::abs_diff_eq(*self, *other, max_abs_diff) - } - - #[inline] - fn neg_matrix(&self) -> Self { - f32x4_neg(*self) - } - - #[inline] - fn inverse(&self) -> Self { - const SIGN: v128 = const_f32x4!([1.0, -1.0, -1.0, 1.0]); - let abcd = *self; - let dcba = i32x4_shuffle::<3, 2, 5, 4>(abcd, abcd); - let prod = f32x4_mul(abcd, dcba); - let sub = f32x4_sub(prod, i32x4_shuffle::<1, 1, 5, 5>(prod, prod)); - let det = i32x4_shuffle::<0, 0, 4, 4>(sub, sub); - let tmp = f32x4_div(SIGN, det); - glam_assert!(tmp.is_finite()); - let dbca = i32x4_shuffle::<3, 1, 6, 4>(abcd, abcd); - f32x4_mul(dbca, tmp) - } -} - -impl MatrixConst for Columns3 { - const ZERO: Columns3 = Columns3 { - x_axis: VectorConst::ZERO, - y_axis: VectorConst::ZERO, - z_axis: VectorConst::ZERO, - }; - const IDENTITY: Columns3 = Columns3 { - x_axis: v128::X, - y_axis: v128::Y, - z_axis: v128::Z, - }; -} - -impl NanConstEx for Columns3 { - const NAN: Columns3 = Columns3 { - x_axis: v128::NAN, - y_axis: v128::NAN, - z_axis: v128::NAN, - }; -} - -impl Matrix for Columns3 {} - -impl Matrix3x3 for Columns3 { - #[inline(always)] - fn from_cols(x_axis: v128, y_axis: v128, z_axis: v128) -> Self { - Self { - x_axis, - y_axis, - z_axis, - } - } - - #[inline(always)] - fn x_axis(&self) -> &v128 { - &self.x_axis - } - - #[inline(always)] - fn y_axis(&self) -> &v128 { - &self.y_axis - } - - #[inline(always)] - fn z_axis(&self) -> &v128 { - &self.z_axis - } - - #[inline] - fn transpose(&self) -> Self { - let tmp0 = i32x4_shuffle::<0, 1, 4, 5>(self.x_axis, self.y_axis); - let tmp1 = i32x4_shuffle::<2, 3, 6, 7>(self.x_axis, self.y_axis); - - Self { - x_axis: i32x4_shuffle::<0, 2, 4, 4>(tmp0, self.z_axis), - y_axis: i32x4_shuffle::<1, 3, 5, 5>(tmp0, self.z_axis), - z_axis: i32x4_shuffle::<0, 2, 6, 6>(tmp1, self.z_axis), - } - } -} - -impl FloatMatrix3x3 for Columns3 { - #[inline] - fn transform_point2(&self, other: XY) -> XY { - let mut res = self.x_axis.mul_scalar(other.x); - res = self.y_axis.mul_scalar(other.y).add(res); - res = self.z_axis.add(res); - res.into() - } - - #[inline] - fn transform_vector2(&self, other: XY) -> XY { - let mut res = self.x_axis.mul_scalar(other.x); - res = self.y_axis.mul_scalar(other.y).add(res); - res.into() - } -} - -impl MatrixConst for Columns4 { - const ZERO: Columns4 = Columns4 { - x_axis: VectorConst::ZERO, - y_axis: VectorConst::ZERO, - z_axis: VectorConst::ZERO, - w_axis: VectorConst::ZERO, - }; - const IDENTITY: Columns4 = Columns4 { - x_axis: v128::X, - y_axis: v128::Y, - z_axis: v128::Z, - w_axis: v128::W, - }; -} - -impl NanConstEx for Columns4 { - const NAN: Columns4 = Columns4 { - x_axis: v128::NAN, - y_axis: v128::NAN, - z_axis: v128::NAN, - w_axis: v128::NAN, - }; -} - -impl Matrix for Columns4 {} - -impl Matrix4x4 for Columns4 { - #[inline(always)] - fn from_cols(x_axis: v128, y_axis: v128, z_axis: v128, w_axis: v128) -> Self { - Self { - x_axis, - y_axis, - z_axis, - w_axis, - } - } - - #[inline(always)] - fn x_axis(&self) -> &v128 { - &self.x_axis - } - - #[inline(always)] - fn y_axis(&self) -> &v128 { - &self.y_axis - } - - #[inline(always)] - fn z_axis(&self) -> &v128 { - &self.z_axis - } - - #[inline(always)] - fn w_axis(&self) -> &v128 { - &self.w_axis - } - - #[inline] - fn determinant(&self) -> f32 { - // Based on https://github.com/g-truc/glm `glm_mat4_determinant` - let swp2a = i32x4_shuffle::<2, 1, 1, 0>(self.z_axis, self.z_axis); - let swp3a = i32x4_shuffle::<3, 3, 2, 3>(self.w_axis, self.w_axis); - let swp2b = i32x4_shuffle::<3, 3, 2, 3>(self.z_axis, self.z_axis); - let swp3b = i32x4_shuffle::<2, 1, 1, 0>(self.w_axis, self.w_axis); - let swp2c = i32x4_shuffle::<2, 1, 0, 0>(self.z_axis, self.z_axis); - let swp3c = i32x4_shuffle::<0, 0, 2, 1>(self.w_axis, self.w_axis); - - let mula = f32x4_mul(swp2a, swp3a); - let mulb = f32x4_mul(swp2b, swp3b); - let mulc = f32x4_mul(swp2c, swp3c); - let sube = f32x4_sub(mula, mulb); - let subf = f32x4_sub(i32x4_shuffle::<6, 7, 2, 3>(mulc, mulc), mulc); - - let subfaca = i32x4_shuffle::<0, 0, 1, 2>(sube, sube); - let swpfaca = i32x4_shuffle::<1, 0, 0, 0>(self.y_axis, self.y_axis); - let mulfaca = f32x4_mul(swpfaca, subfaca); - - let subtmpb = i32x4_shuffle::<1, 3, 4, 4>(sube, subf); - let subfacb = i32x4_shuffle::<0, 1, 1, 3>(subtmpb, subtmpb); - let swpfacb = i32x4_shuffle::<2, 2, 1, 1>(self.y_axis, self.y_axis); - let mulfacb = f32x4_mul(swpfacb, subfacb); - - let subres = f32x4_sub(mulfaca, mulfacb); - let subtmpc = i32x4_shuffle::<2, 2, 4, 5>(sube, subf); - let subfacc = i32x4_shuffle::<0, 2, 3, 3>(subtmpc, subtmpc); - let swpfacc = i32x4_shuffle::<3, 3, 3, 2>(self.y_axis, self.y_axis); - let mulfacc = f32x4_mul(swpfacc, subfacc); - - let addres = f32x4_add(subres, mulfacc); - let detcof = f32x4_mul(addres, f32x4(1.0, -1.0, 1.0, -1.0)); - - Vector4::dot(self.x_axis, detcof) - } - - #[inline] - fn transpose(&self) -> Self { - // Based on https://github.com/microsoft/DirectXMath `XMMatrixTranspose` - let tmp0 = i32x4_shuffle::<0, 1, 4, 5>(self.x_axis, self.y_axis); - let tmp1 = i32x4_shuffle::<2, 3, 6, 7>(self.x_axis, self.y_axis); - let tmp2 = i32x4_shuffle::<0, 1, 4, 5>(self.z_axis, self.w_axis); - let tmp3 = i32x4_shuffle::<2, 3, 6, 7>(self.z_axis, self.w_axis); - - Self { - x_axis: i32x4_shuffle::<0, 2, 4, 6>(tmp0, tmp2), - y_axis: i32x4_shuffle::<1, 3, 5, 7>(tmp0, tmp2), - z_axis: i32x4_shuffle::<0, 2, 4, 6>(tmp1, tmp3), - w_axis: i32x4_shuffle::<1, 3, 5, 7>(tmp1, tmp3), - } - } -} - -impl FloatMatrix4x4 for Columns4 { - type SIMDVector3 = v128; - - fn inverse(&self) -> Self { - // Based on https://github.com/g-truc/glm `glm_mat4_inverse` - let fac0 = { - let swp0a = i32x4_shuffle::<3, 3, 7, 7>(self.w_axis, self.z_axis); - let swp0b = i32x4_shuffle::<2, 2, 6, 6>(self.w_axis, self.z_axis); - - let swp00 = i32x4_shuffle::<2, 2, 6, 6>(self.z_axis, self.y_axis); - let swp01 = i32x4_shuffle::<0, 0, 4, 6>(swp0a, swp0a); - let swp02 = i32x4_shuffle::<0, 0, 4, 6>(swp0b, swp0b); - let swp03 = i32x4_shuffle::<3, 3, 7, 7>(self.z_axis, self.y_axis); - - let mul00 = f32x4_mul(swp00, swp01); - let mul01 = f32x4_mul(swp02, swp03); - f32x4_sub(mul00, mul01) - }; - let fac1 = { - let swp0a = i32x4_shuffle::<3, 3, 7, 7>(self.w_axis, self.z_axis); - let swp0b = i32x4_shuffle::<1, 1, 5, 5>(self.w_axis, self.z_axis); - - let swp00 = i32x4_shuffle::<1, 1, 5, 5>(self.z_axis, self.y_axis); - let swp01 = i32x4_shuffle::<0, 0, 4, 6>(swp0a, swp0a); - let swp02 = i32x4_shuffle::<0, 0, 4, 6>(swp0b, swp0b); - let swp03 = i32x4_shuffle::<3, 3, 7, 7>(self.z_axis, self.y_axis); - - let mul00 = f32x4_mul(swp00, swp01); - let mul01 = f32x4_mul(swp02, swp03); - f32x4_sub(mul00, mul01) - }; - let fac2 = { - let swp0a = i32x4_shuffle::<2, 2, 6, 6>(self.w_axis, self.z_axis); - let swp0b = i32x4_shuffle::<1, 1, 5, 5>(self.w_axis, self.z_axis); - - let swp00 = i32x4_shuffle::<1, 1, 5, 5>(self.z_axis, self.y_axis); - let swp01 = i32x4_shuffle::<0, 0, 4, 6>(swp0a, swp0a); - let swp02 = i32x4_shuffle::<0, 0, 4, 6>(swp0b, swp0b); - let swp03 = i32x4_shuffle::<2, 2, 6, 6>(self.z_axis, self.y_axis); - - let mul00 = f32x4_mul(swp00, swp01); - let mul01 = f32x4_mul(swp02, swp03); - f32x4_sub(mul00, mul01) - }; - let fac3 = { - let swp0a = i32x4_shuffle::<3, 3, 7, 7>(self.w_axis, self.z_axis); - let swp0b = i32x4_shuffle::<0, 0, 4, 4>(self.w_axis, self.z_axis); - - let swp00 = i32x4_shuffle::<0, 0, 4, 4>(self.z_axis, self.y_axis); - let swp01 = i32x4_shuffle::<0, 0, 4, 6>(swp0a, swp0a); - let swp02 = i32x4_shuffle::<0, 0, 4, 6>(swp0b, swp0b); - let swp03 = i32x4_shuffle::<3, 3, 7, 7>(self.z_axis, self.y_axis); - - let mul00 = f32x4_mul(swp00, swp01); - let mul01 = f32x4_mul(swp02, swp03); - f32x4_sub(mul00, mul01) - }; - let fac4 = { - let swp0a = i32x4_shuffle::<2, 2, 6, 6>(self.w_axis, self.z_axis); - let swp0b = i32x4_shuffle::<0, 0, 4, 4>(self.w_axis, self.z_axis); - - let swp00 = i32x4_shuffle::<0, 0, 4, 4>(self.z_axis, self.y_axis); - let swp01 = i32x4_shuffle::<0, 0, 4, 6>(swp0a, swp0a); - let swp02 = i32x4_shuffle::<0, 0, 4, 6>(swp0b, swp0b); - let swp03 = i32x4_shuffle::<2, 2, 6, 6>(self.z_axis, self.y_axis); - - let mul00 = f32x4_mul(swp00, swp01); - let mul01 = f32x4_mul(swp02, swp03); - f32x4_sub(mul00, mul01) - }; - let fac5 = { - let swp0a = i32x4_shuffle::<1, 1, 5, 5>(self.w_axis, self.z_axis); - let swp0b = i32x4_shuffle::<0, 0, 4, 4>(self.w_axis, self.z_axis); - - let swp00 = i32x4_shuffle::<0, 0, 4, 4>(self.z_axis, self.y_axis); - let swp01 = i32x4_shuffle::<0, 0, 4, 6>(swp0a, swp0a); - let swp02 = i32x4_shuffle::<0, 0, 4, 6>(swp0b, swp0b); - let swp03 = i32x4_shuffle::<1, 1, 5, 5>(self.z_axis, self.y_axis); - - let mul00 = f32x4_mul(swp00, swp01); - let mul01 = f32x4_mul(swp02, swp03); - f32x4_sub(mul00, mul01) - }; - let sign_a = f32x4(-1.0, 1.0, -1.0, 1.0); - let sign_b = f32x4(1.0, -1.0, 1.0, -1.0); - - let temp0 = i32x4_shuffle::<0, 0, 4, 4>(self.y_axis, self.x_axis); - let vec0 = i32x4_shuffle::<0, 2, 6, 6>(temp0, temp0); - - let temp1 = i32x4_shuffle::<1, 1, 5, 5>(self.y_axis, self.x_axis); - let vec1 = i32x4_shuffle::<0, 2, 6, 6>(temp1, temp1); - - let temp2 = i32x4_shuffle::<2, 2, 6, 6>(self.y_axis, self.x_axis); - let vec2 = i32x4_shuffle::<0, 2, 6, 6>(temp2, temp2); - - let temp3 = i32x4_shuffle::<3, 3, 7, 7>(self.y_axis, self.x_axis); - let vec3 = i32x4_shuffle::<0, 2, 6, 6>(temp3, temp3); - - let mul00 = f32x4_mul(vec1, fac0); - let mul01 = f32x4_mul(vec2, fac1); - let mul02 = f32x4_mul(vec3, fac2); - let sub00 = f32x4_sub(mul00, mul01); - let add00 = f32x4_add(sub00, mul02); - let inv0 = f32x4_mul(sign_b, add00); - - let mul03 = f32x4_mul(vec0, fac0); - let mul04 = f32x4_mul(vec2, fac3); - let mul05 = f32x4_mul(vec3, fac4); - let sub01 = f32x4_sub(mul03, mul04); - let add01 = f32x4_add(sub01, mul05); - let inv1 = f32x4_mul(sign_a, add01); - - let mul06 = f32x4_mul(vec0, fac1); - let mul07 = f32x4_mul(vec1, fac3); - let mul08 = f32x4_mul(vec3, fac5); - let sub02 = f32x4_sub(mul06, mul07); - let add02 = f32x4_add(sub02, mul08); - let inv2 = f32x4_mul(sign_b, add02); - - let mul09 = f32x4_mul(vec0, fac2); - let mul10 = f32x4_mul(vec1, fac4); - let mul11 = f32x4_mul(vec2, fac5); - let sub03 = f32x4_sub(mul09, mul10); - let add03 = f32x4_add(sub03, mul11); - let inv3 = f32x4_mul(sign_a, add03); - - let row0 = i32x4_shuffle::<0, 0, 4, 4>(inv0, inv1); - let row1 = i32x4_shuffle::<0, 0, 4, 4>(inv2, inv3); - let row2 = i32x4_shuffle::<0, 2, 4, 6>(row0, row1); - - let dot0 = Vector4::dot(self.x_axis, row2); - glam_assert!(dot0 != 0.0); - - let rcp0 = f32x4_splat(dot0.recip()); - - Self { - x_axis: f32x4_mul(inv0, rcp0), - y_axis: f32x4_mul(inv1, rcp0), - z_axis: f32x4_mul(inv2, rcp0), - w_axis: f32x4_mul(inv3, rcp0), - } - } - - #[inline(always)] - fn transform_point3(&self, other: XYZ) -> XYZ { - self.x_axis - .mul_scalar(other.x) - .add(self.y_axis.mul_scalar(other.y)) - .add(self.z_axis.mul_scalar(other.z)) - .add(self.w_axis) - .into() - } - - #[inline(always)] - fn transform_vector3(&self, other: XYZ) -> XYZ { - self.x_axis - .mul_scalar(other.x) - .add(self.y_axis.mul_scalar(other.y)) - .add(self.z_axis.mul_scalar(other.z)) - .into() - } - - #[inline] - fn transform_float4_as_point3(&self, other: v128) -> v128 { - let mut res = self.x_axis.mul(Vector4::splat_x(other)); - res = res.add(self.y_axis.mul(Vector4::splat_y(other))); - res = res.add(self.z_axis.mul(Vector4::splat_z(other))); - res = self.w_axis.add(res); - res - } - - #[inline] - fn transform_float4_as_vector3(&self, other: v128) -> v128 { - let mut res = self.x_axis.mul(Vector4::splat_x(other)); - res = res.add(self.y_axis.mul(Vector4::splat_y(other))); - res = res.add(self.z_axis.mul(Vector4::splat_z(other))); - res - } - - #[inline] - fn project_float4_as_point3(&self, other: v128) -> v128 { - let mut res = self.x_axis.mul(Vector4::splat_x(other)); - res = res.add(self.y_axis.mul(Vector4::splat_y(other))); - res = res.add(self.z_axis.mul(Vector4::splat_z(other))); - res = self.w_axis.add(res); - res = res.mul(res.splat_w().recip()); - res - } -} - -impl ProjectionMatrix for Columns4 {} - -impl From>> for Columns3 { - #[inline(always)] - fn from(v: Columns3>) -> Columns3 { - Self { - x_axis: v.x_axis.into(), - y_axis: v.y_axis.into(), - z_axis: v.z_axis.into(), - } - } -} - -impl From> for Columns3> { - #[inline(always)] - fn from(v: Columns3) -> Columns3> { - Self { - x_axis: v.x_axis.into(), - y_axis: v.y_axis.into(), - z_axis: v.z_axis.into(), - } - } -} diff --git a/src/core/wasm32/quaternion.rs b/src/core/wasm32/quaternion.rs deleted file mode 100644 index 1899ee41..00000000 --- a/src/core/wasm32/quaternion.rs +++ /dev/null @@ -1,130 +0,0 @@ -use core::arch::wasm32::*; - -// use super::float::*; -use crate::core::{ - storage::XYZ, - traits::{quaternion::Quaternion, scalar::*, vector::*}, -}; - -impl Quaternion for v128 { - type SIMDVector3 = v128; - - #[inline(always)] - fn conjugate(self) -> Self { - const SIGN: v128 = const_f32x4!([-1.0, -1.0, -1.0, 1.0]); - f32x4_mul(self, SIGN) - } - - #[inline] - fn lerp(self, end: Self, s: f32) -> Self { - glam_assert!(FloatVector4::is_normalized(self)); - glam_assert!(FloatVector4::is_normalized(end)); - - const NEG_ZERO: v128 = const_f32x4!([-0.0; 4]); - let start = self; - let end = end; - let dot = Vector4::dot_into_vec(start, end); - // Calculate the bias, if the dot product is positive or zero, there is no bias - // but if it is negative, we want to flip the 'end' rotation XYZW components - let bias = v128_and(dot, NEG_ZERO); - let interpolated = f32x4_add( - f32x4_mul(f32x4_sub(v128_xor(end, bias), start), f32x4_splat(s)), - start, - ); - FloatVector4::normalize(interpolated) - } - - #[inline] - fn slerp(self, end: Self, s: f32) -> Self { - // http://number-none.com/product/Understanding%20Slerp,%20Then%20Not%20Using%20It/ - glam_assert!(FloatVector4::is_normalized(self)); - glam_assert!(FloatVector4::is_normalized(end)); - - const DOT_THRESHOLD: f32 = 0.9995; - - let dot = Vector4::dot(self, end); - - if dot > DOT_THRESHOLD { - // assumes lerp returns a normalized quaternion - self.lerp(end, s) - } else { - // assumes scalar_acos clamps the input to [-1.0, 1.0] - let theta = dot.acos_approx(); - - // TODO: v128_sin is broken - // let x = 1.0 - s; - // let y = s; - // let z = 1.0; - // let w = 0.0; - // let tmp = f32x4_mul(f32x4_splat(theta), f32x4(x, y, z, w)); - // let tmp = v128_sin(tmp); - let x = (theta * (1.0 - s)).sin(); - let y = (theta * s).sin(); - let z = theta.sin(); - let w = 0.0; - let tmp = f32x4(x, y, z, w); - - let scale1 = i32x4_shuffle::<0, 0, 4, 4>(tmp, tmp); - let scale2 = i32x4_shuffle::<1, 1, 5, 5>(tmp, tmp); - let theta_sin = i32x4_shuffle::<2, 2, 6, 6>(tmp, tmp); - - self.mul(scale1).add(end.mul(scale2)).div(theta_sin) - } - } - - #[inline] - fn mul_quaternion(self, other: Self) -> Self { - glam_assert!(FloatVector4::is_normalized(self)); - glam_assert!(FloatVector4::is_normalized(other)); - // Based on https://github.com/nfrechette/rtm `rtm::quat_mul` - let lhs = self; - let rhs = other; - - const CONTROL_WZYX: v128 = const_f32x4!([1.0, -1.0, 1.0, -1.0]); - const CONTROL_ZWXY: v128 = const_f32x4!([1.0, 1.0, -1.0, -1.0]); - const CONTROL_YXWZ: v128 = const_f32x4!([-1.0, 1.0, 1.0, -1.0]); - - let r_xxxx = i32x4_shuffle::<0, 0, 4, 4>(lhs, lhs); - let r_yyyy = i32x4_shuffle::<1, 1, 5, 5>(lhs, lhs); - let r_zzzz = i32x4_shuffle::<2, 2, 6, 6>(lhs, lhs); - let r_wwww = i32x4_shuffle::<3, 3, 7, 7>(lhs, lhs); - - let lxrw_lyrw_lzrw_lwrw = f32x4_mul(r_wwww, rhs); - let l_wzyx = i32x4_shuffle::<3, 2, 5, 4>(rhs, rhs); - - let lwrx_lzrx_lyrx_lxrx = f32x4_mul(r_xxxx, l_wzyx); - let l_zwxy = i32x4_shuffle::<1, 0, 7, 6>(l_wzyx, l_wzyx); - - let lwrx_nlzrx_lyrx_nlxrx = f32x4_mul(lwrx_lzrx_lyrx_lxrx, CONTROL_WZYX); - - let lzry_lwry_lxry_lyry = f32x4_mul(r_yyyy, l_zwxy); - let l_yxwz = i32x4_shuffle::<3, 2, 5, 4>(l_zwxy, l_zwxy); - - let lzry_lwry_nlxry_nlyry = f32x4_mul(lzry_lwry_lxry_lyry, CONTROL_ZWXY); - - let lyrz_lxrz_lwrz_lzrz = f32x4_mul(r_zzzz, l_yxwz); - let result0 = f32x4_add(lxrw_lyrw_lzrw_lwrw, lwrx_nlzrx_lyrx_nlxrx); - - let nlyrz_lxrz_lwrz_wlzrz = f32x4_mul(lyrz_lxrz_lwrz_lzrz, CONTROL_YXWZ); - let result1 = f32x4_add(lzry_lwry_nlxry_nlyry, nlyrz_lxrz_lwrz_wlzrz); - f32x4_add(result0, result1) - } - - #[inline] - fn mul_vector3(self, other: XYZ) -> XYZ { - self.mul_float4_as_vector3(other.into()).into() - } - - #[inline] - fn mul_float4_as_vector3(self, other: v128) -> v128 { - glam_assert!(FloatVector4::is_normalized(self)); - const TWO: v128 = const_f32x4!([2.0; 4]); - let w = i32x4_shuffle::<3, 3, 7, 7>(self, self); - let b = self; - let b2 = Vector3::dot_into_vec(b, b); - other - .mul(w.mul(w).sub(b2)) - .add(b.mul(Vector3::dot_into_vec(other, b).mul(TWO))) - .add(b.cross(other).mul(w.mul(TWO))) - } -} diff --git a/src/core/wasm32/vector.rs b/src/core/wasm32/vector.rs deleted file mode 100644 index 9ecaa77c..00000000 --- a/src/core/wasm32/vector.rs +++ /dev/null @@ -1,812 +0,0 @@ -use crate::core::{ - storage::{XY, XYZ, XYZW}, - traits::{scalar::*, vector::*}, -}; -use core::arch::wasm32::*; -use core::mem::MaybeUninit; - -#[inline(always)] -fn f32x4_isnan(v: v128) -> v128 { - f32x4_ne(v, v) -} - -/// Calculates the vector 3 dot product and returns answer in x lane of __m128. -#[inline(always)] -fn dot3_in_x(lhs: v128, rhs: v128) -> v128 { - let x2_y2_z2_w2 = f32x4_mul(lhs, rhs); - let y2_0_0_0 = i32x4_shuffle::<1, 0, 0, 0>(x2_y2_z2_w2, x2_y2_z2_w2); - let z2_0_0_0 = i32x4_shuffle::<2, 0, 0, 0>(x2_y2_z2_w2, x2_y2_z2_w2); - let x2y2_0_0_0 = f32x4_add(x2_y2_z2_w2, y2_0_0_0); - f32x4_add(x2y2_0_0_0, z2_0_0_0) -} - -/// Calculates the vector 4 dot product and returns answer in x lane of __m128. -#[inline(always)] -fn dot4_in_x(lhs: v128, rhs: v128) -> v128 { - let x2_y2_z2_w2 = f32x4_mul(lhs, rhs); - let z2_w2_0_0 = i32x4_shuffle::<2, 3, 0, 0>(x2_y2_z2_w2, x2_y2_z2_w2); - let x2z2_y2w2_0_0 = f32x4_add(x2_y2_z2_w2, z2_w2_0_0); - let y2w2_0_0_0 = i32x4_shuffle::<1, 0, 0, 0>(x2z2_y2w2_0_0, x2z2_y2w2_0_0); - f32x4_add(x2z2_y2w2_0_0, y2w2_0_0_0) -} - -impl MaskVectorConst for v128 { - const FALSE: v128 = const_f32x4!([0.0; 4]); -} - -impl MaskVector for v128 { - #[inline(always)] - fn bitand(self, other: Self) -> Self { - v128_and(self, other) - } - - #[inline(always)] - fn bitor(self, other: Self) -> Self { - v128_or(self, other) - } - - #[inline] - fn not(self) -> Self { - v128_not(self) - } -} - -impl MaskVector3 for v128 { - #[inline(always)] - fn new(x: bool, y: bool, z: bool) -> Self { - u32x4( - MaskConst::MASK[x as usize], - MaskConst::MASK[y as usize], - MaskConst::MASK[z as usize], - 0, - ) - } - - #[inline(always)] - fn bitmask(self) -> u32 { - (u32x4_bitmask(self) & 0x7) as u32 - } - - #[inline(always)] - fn any(self) -> bool { - (u32x4_bitmask(self) & 0x7) != 0 - } - - #[inline(always)] - fn all(self) -> bool { - (u32x4_bitmask(self) & 0x7) == 0x7 - } - - #[inline] - fn into_bool_array(self) -> [bool; 3] { - let bitmask = MaskVector3::bitmask(self); - [(bitmask & 1) != 0, (bitmask & 2) != 0, (bitmask & 4) != 0] - } - - #[inline] - fn into_u32_array(self) -> [u32; 3] { - let bitmask = MaskVector3::bitmask(self); - [ - MaskConst::MASK[(bitmask & 1) as usize], - MaskConst::MASK[((bitmask >> 1) & 1) as usize], - MaskConst::MASK[((bitmask >> 2) & 1) as usize], - ] - } -} - -impl MaskVector4 for v128 { - #[inline(always)] - fn new(x: bool, y: bool, z: bool, w: bool) -> Self { - u32x4( - MaskConst::MASK[x as usize], - MaskConst::MASK[y as usize], - MaskConst::MASK[z as usize], - MaskConst::MASK[w as usize], - ) - } - - #[inline(always)] - fn bitmask(self) -> u32 { - u32x4_bitmask(self) as u32 - } - - #[inline(always)] - fn any(self) -> bool { - u32x4_bitmask(self) != 0 - } - - #[inline(always)] - fn all(self) -> bool { - u32x4_bitmask(self) == 0xf - } - - #[inline] - fn into_bool_array(self) -> [bool; 4] { - let bitmask = MaskVector4::bitmask(self); - [ - (bitmask & 1) != 0, - (bitmask & 2) != 0, - (bitmask & 4) != 0, - (bitmask & 8) != 0, - ] - } - - #[inline] - fn into_u32_array(self) -> [u32; 4] { - let bitmask = MaskVector4::bitmask(self); - [ - MaskConst::MASK[(bitmask & 1) as usize], - MaskConst::MASK[((bitmask >> 1) & 1) as usize], - MaskConst::MASK[((bitmask >> 2) & 1) as usize], - MaskConst::MASK[((bitmask >> 3) & 1) as usize], - ] - } -} - -impl VectorConst for v128 { - const ZERO: v128 = const_f32x4!([0.0; 4]); - const ONE: v128 = const_f32x4!([1.0; 4]); -} - -impl NanConstEx for v128 { - const NAN: v128 = const_f32x4!([f32::NAN; 4]); -} - -impl Vector3Const for v128 { - const X: v128 = const_f32x4!([1.0, 0.0, 0.0, 0.0]); - const Y: v128 = const_f32x4!([0.0, 1.0, 0.0, 0.0]); - const Z: v128 = const_f32x4!([0.0, 0.0, 1.0, 0.0]); -} - -impl Vector4Const for v128 { - const X: v128 = const_f32x4!([1.0, 0.0, 0.0, 0.0]); - const Y: v128 = const_f32x4!([0.0, 1.0, 0.0, 0.0]); - const Z: v128 = const_f32x4!([0.0, 0.0, 1.0, 0.0]); - const W: v128 = const_f32x4!([0.0, 0.0, 0.0, 1.0]); -} - -impl Vector for v128 { - type Mask = v128; - - #[inline(always)] - fn splat(s: f32) -> Self { - f32x4_splat(s) - } - - #[inline(always)] - fn select(mask: Self::Mask, if_true: Self, if_false: Self) -> Self { - v128_bitselect(if_true, if_false, mask) - } - - #[inline(always)] - fn cmpeq(self, other: Self) -> Self::Mask { - f32x4_eq(self, other) - } - - #[inline(always)] - fn cmpne(self, other: Self) -> Self::Mask { - f32x4_ne(self, other) - } - - #[inline(always)] - fn cmpge(self, other: Self) -> Self::Mask { - f32x4_ge(self, other) - } - - #[inline(always)] - fn cmpgt(self, other: Self) -> Self::Mask { - f32x4_gt(self, other) - } - - #[inline(always)] - fn cmple(self, other: Self) -> Self::Mask { - f32x4_le(self, other) - } - - #[inline(always)] - fn cmplt(self, other: Self) -> Self::Mask { - f32x4_lt(self, other) - } - - #[inline(always)] - fn add(self, other: Self) -> Self { - f32x4_add(self, other) - } - - #[inline(always)] - fn div(self, other: Self) -> Self { - f32x4_div(self, other) - } - - #[inline(always)] - fn mul(self, other: Self) -> Self { - f32x4_mul(self, other) - } - - #[inline(always)] - fn sub(self, other: Self) -> Self { - f32x4_sub(self, other) - } - - #[inline(always)] - fn add_scalar(self, other: f32) -> Self { - f32x4_add(self, f32x4_splat(other)) - } - - #[inline(always)] - fn sub_scalar(self, other: f32) -> Self { - f32x4_sub(self, f32x4_splat(other)) - } - - #[inline(always)] - fn mul_scalar(self, other: f32) -> Self { - f32x4_mul(self, f32x4_splat(other)) - } - - #[inline(always)] - fn div_scalar(self, other: f32) -> Self { - f32x4_div(self, f32x4_splat(other)) - } - - #[inline(always)] - fn rem(self, other: Self) -> Self { - let n = f32x4_floor(f32x4_div(self, other)); - f32x4_sub(self, f32x4_mul(n, other)) - } - - #[inline(always)] - fn rem_scalar(self, other: f32) -> Self { - self.rem(f32x4_splat(other)) - } - - #[inline(always)] - fn min(self, other: Self) -> Self { - f32x4_pmin(self, other) - } - - #[inline(always)] - fn max(self, other: Self) -> Self { - f32x4_pmax(self, other) - } -} - -impl Vector3 for v128 { - #[inline(always)] - fn new(x: f32, y: f32, z: f32) -> Self { - f32x4(x, y, z, x) - } - - #[inline(always)] - fn x(self) -> f32 { - f32x4_extract_lane::<0>(self) - } - - #[inline(always)] - fn y(self) -> f32 { - f32x4_extract_lane::<1>(self) - } - - #[inline(always)] - fn z(self) -> f32 { - f32x4_extract_lane::<2>(self) - } - - #[inline(always)] - fn splat_x(self) -> Self { - i32x4_shuffle::<0, 0, 0, 0>(self, self) - } - - #[inline(always)] - fn splat_y(self) -> Self { - i32x4_shuffle::<1, 1, 1, 1>(self, self) - } - - #[inline(always)] - fn splat_z(self) -> Self { - i32x4_shuffle::<2, 2, 2, 2>(self, self) - } - - #[inline(always)] - fn from_slice_unaligned(slice: &[f32]) -> Self { - Vector3::new(slice[0], slice[1], slice[2]) - } - - #[inline(always)] - fn write_to_slice_unaligned(self, slice: &mut [f32]) { - let xyz = self.as_ref_xyz(); - slice[0] = xyz.x; - slice[1] = xyz.y; - slice[2] = xyz.z; - } - - #[inline(always)] - fn as_ref_xyz(&self) -> &XYZ { - unsafe { &*(self as *const Self as *const XYZ) } - } - - #[inline(always)] - fn as_mut_xyz(&mut self) -> &mut XYZ { - unsafe { &mut *(self as *mut Self as *mut XYZ) } - } - - #[inline(always)] - fn into_xy(self) -> XY { - XY { - x: f32x4_extract_lane::<0>(self), - y: f32x4_extract_lane::<1>(self), - } - } - - #[inline] - fn into_xyzw(self, w: f32) -> XYZW { - let v = f32x4_replace_lane::<3>(self, w); - unsafe { *(&v as *const v128 as *const XYZW) } - } - - #[inline(always)] - fn from_array(a: [f32; 3]) -> Self { - Vector3::new(a[0], a[1], a[2]) - } - - #[inline(always)] - fn into_array(self) -> [f32; 3] { - let mut out: MaybeUninit = MaybeUninit::uninit(); - unsafe { - v128_store(out.as_mut_ptr(), self); - *(&out.assume_init() as *const v128 as *const [f32; 3]) - } - } - - #[inline(always)] - fn from_tuple(t: (f32, f32, f32)) -> Self { - Vector3::new(t.0, t.1, t.2) - } - - #[inline(always)] - fn into_tuple(self) -> (f32, f32, f32) { - let mut out: MaybeUninit = MaybeUninit::uninit(); - unsafe { - v128_store(out.as_mut_ptr(), self); - *(&out.assume_init() as *const v128 as *const (f32, f32, f32)) - } - } - - #[inline] - fn min_element(self) -> f32 { - let v = self; - let v = f32x4_pmin(v, i32x4_shuffle::<2, 2, 1, 1>(v, v)); - let v = f32x4_pmin(v, i32x4_shuffle::<1, 0, 0, 0>(v, v)); - f32x4_extract_lane::<0>(v) - } - - #[inline] - fn max_element(self) -> f32 { - let v = self; - let v = f32x4_pmax(v, i32x4_shuffle::<2, 2, 0, 0>(v, v)); - let v = f32x4_pmax(v, i32x4_shuffle::<1, 0, 0, 0>(v, v)); - f32x4_extract_lane::<0>(v) - } - - #[inline] - fn dot(self, other: Self) -> f32 { - f32x4_extract_lane::<0>(dot3_in_x(self, other)) - } - - #[inline] - fn dot_into_vec(self, other: Self) -> Self { - let dot_in_x = dot3_in_x(self, other); - i32x4_shuffle::<0, 0, 0, 0>(dot_in_x, dot_in_x) - } - - #[inline] - fn cross(self, other: Self) -> Self { - // x <- a.y*b.z - a.z*b.y - // y <- a.z*b.x - a.x*b.z - // z <- a.x*b.y - a.y*b.x - // We can save a shuffle by grouping it in this wacky order: - // (self.zxy() * other - self * other.zxy()).zxy() - let lhszxy = i32x4_shuffle::<2, 0, 1, 1>(self, self); - let rhszxy = i32x4_shuffle::<2, 0, 1, 1>(other, other); - let lhszxy_rhs = f32x4_mul(lhszxy, other); - let rhszxy_lhs = f32x4_mul(rhszxy, self); - let sub = f32x4_sub(lhszxy_rhs, rhszxy_lhs); - i32x4_shuffle::<2, 0, 1, 1>(sub, sub) - } - - #[inline] - fn clamp(self, min: Self, max: Self) -> Self { - glam_assert!( - MaskVector3::all(min.cmple(max)), - "clamp: expected min <= max" - ); - self.max(min).min(max) - } -} - -impl Vector4 for v128 { - #[inline(always)] - fn new(x: f32, y: f32, z: f32, w: f32) -> Self { - f32x4(x, y, z, w) - } - - #[inline(always)] - fn x(self) -> f32 { - f32x4_extract_lane::<0>(self) - } - - #[inline(always)] - fn y(self) -> f32 { - f32x4_extract_lane::<1>(self) - } - - #[inline(always)] - fn z(self) -> f32 { - f32x4_extract_lane::<2>(self) - } - - #[inline(always)] - fn w(self) -> f32 { - f32x4_extract_lane::<3>(self) - } - - #[inline(always)] - fn splat_x(self) -> Self { - i32x4_shuffle::<0, 0, 0, 0>(self, self) - } - - #[inline(always)] - fn splat_y(self) -> Self { - i32x4_shuffle::<1, 1, 1, 1>(self, self) - } - - #[inline(always)] - fn splat_z(self) -> Self { - i32x4_shuffle::<2, 2, 2, 2>(self, self) - } - - #[inline(always)] - fn splat_w(self) -> Self { - i32x4_shuffle::<3, 3, 3, 3>(self, self) - } - - #[inline(always)] - fn from_slice_unaligned(slice: &[f32]) -> Self { - f32x4(slice[0], slice[1], slice[2], slice[3]) - } - - #[inline(always)] - fn write_to_slice_unaligned(self, slice: &mut [f32]) { - let xyzw = self.as_ref_xyzw(); - slice[0] = xyzw.x; - slice[1] = xyzw.y; - slice[2] = xyzw.z; - slice[3] = xyzw.w; - } - - #[inline(always)] - fn as_ref_xyzw(&self) -> &XYZW { - unsafe { &*(self as *const Self as *const XYZW) } - } - - #[inline(always)] - fn as_mut_xyzw(&mut self) -> &mut XYZW { - unsafe { &mut *(self as *mut Self as *mut XYZW) } - } - - #[inline(always)] - fn into_xy(self) -> XY { - XY { - x: f32x4_extract_lane::<0>(self), - y: f32x4_extract_lane::<1>(self), - } - } - - #[inline(always)] - fn into_xyz(self) -> XYZ { - XYZ { - x: f32x4_extract_lane::<0>(self), - y: f32x4_extract_lane::<1>(self), - z: f32x4_extract_lane::<2>(self), - } - } - - #[inline(always)] - fn from_array(a: [f32; 4]) -> Self { - Vector4::new(a[0], a[1], a[2], a[3]) - } - - #[inline(always)] - fn into_array(self) -> [f32; 4] { - let mut out: MaybeUninit = MaybeUninit::uninit(); - unsafe { - v128_store(out.as_mut_ptr(), self); - *(&out.assume_init() as *const v128 as *const [f32; 4]) - } - } - - #[inline(always)] - fn from_tuple(t: (f32, f32, f32, f32)) -> Self { - Vector4::new(t.0, t.1, t.2, t.3) - } - - #[inline(always)] - fn into_tuple(self) -> (f32, f32, f32, f32) { - let mut out: MaybeUninit = MaybeUninit::uninit(); - unsafe { - v128_store(out.as_mut_ptr(), self); - *(&out.assume_init() as *const v128 as *const (f32, f32, f32, f32)) - } - } - - #[inline] - fn min_element(self) -> f32 { - let v = self; - let v = f32x4_pmin(v, i32x4_shuffle::<2, 3, 0, 0>(v, v)); - let v = f32x4_pmin(v, i32x4_shuffle::<1, 0, 0, 0>(v, v)); - f32x4_extract_lane::<0>(v) - } - - #[inline] - fn max_element(self) -> f32 { - let v = self; - let v = f32x4_pmax(v, i32x4_shuffle::<2, 3, 0, 0>(v, v)); - let v = f32x4_pmax(v, i32x4_shuffle::<1, 0, 0, 0>(v, v)); - f32x4_extract_lane::<0>(v) - } - - #[inline] - fn dot(self, other: Self) -> f32 { - f32x4_extract_lane::<0>(dot4_in_x(self, other)) - } - - #[inline] - fn dot_into_vec(self, other: Self) -> Self { - let dot_in_x = dot4_in_x(self, other); - i32x4_shuffle::<0, 0, 0, 0>(dot_in_x, dot_in_x) - } - - #[inline] - fn clamp(self, min: Self, max: Self) -> Self { - glam_assert!( - MaskVector4::all(min.cmple(max)), - "clamp: expected min <= max" - ); - self.max(min).min(max) - } -} - -impl SignedVector for v128 { - #[inline(always)] - fn neg(self) -> Self { - f32x4_neg(self) - } -} - -impl SignedVector3 for v128 { - #[inline] - fn abs(self) -> Self { - f32x4_abs(self) - } - - #[inline] - fn signum(self) -> Self { - const NEG_ONE: v128 = const_f32x4!([-1.0; 4]); - let mask = self.cmpge(Self::ZERO); - let result = Self::select(mask, Self::ONE, NEG_ONE); - let mask = f32x4_isnan(self); - Self::select(mask, self, result) - } -} - -impl SignedVector4 for v128 { - #[inline] - fn abs(self) -> Self { - f32x4_abs(self) - } - - #[inline] - fn signum(self) -> Self { - const NEG_ONE: v128 = const_f32x4!([-1.0; 4]); - let mask = self.cmpge(Self::ZERO); - let result = Self::select(mask, Self::ONE, NEG_ONE); - let mask = f32x4_isnan(self); - Self::select(mask, self, result) - } -} - -impl FloatVector3 for v128 { - #[inline] - fn is_finite(self) -> bool { - let (x, y, z) = Vector3::into_tuple(self); - x.is_finite() && y.is_finite() && z.is_finite() - } - - #[inline] - fn is_nan(self) -> bool { - MaskVector3::any(FloatVector3::is_nan_mask(self)) - } - - #[inline(always)] - fn is_nan_mask(self) -> Self::Mask { - f32x4_isnan(self) - } - - #[inline] - fn floor(self) -> Self { - f32x4_floor(self) - } - - #[inline] - fn ceil(self) -> Self { - f32x4_ceil(self) - } - - #[inline] - fn round(self) -> Self { - // TODO: might differ to m128_round - f32x4_nearest(self) - } - - #[inline(always)] - fn recip(self) -> Self { - f32x4_div(Self::ONE, self) - } - - #[inline] - fn exp(self) -> Self { - let (x, y, z) = Vector3::into_tuple(self); - Vector3::new(x.exp(), y.exp(), z.exp()) - } - - #[inline] - fn powf(self, n: f32) -> Self { - let (x, y, z) = Vector3::into_tuple(self); - Vector3::new(x.powf(n), y.powf(n), z.powf(n)) - } - - #[inline] - fn length(self) -> f32 { - let dot = dot3_in_x(self, self); - f32x4_extract_lane::<0>(f32x4_sqrt(dot)) - } - - #[inline] - fn length_recip(self) -> f32 { - let dot = dot3_in_x(self, self); - f32x4_extract_lane::<0>(f32x4_div(Self::ONE, f32x4_sqrt(dot))) - } - - #[inline] - fn normalize(self) -> Self { - let length = f32x4_sqrt(Vector3::dot_into_vec(self, self)); - #[allow(clippy::let_and_return)] - let normalized = f32x4_div(self, length); - glam_assert!(FloatVector3::is_finite(normalized)); - normalized - } -} - -impl FloatVector4 for v128 { - #[inline] - fn is_finite(self) -> bool { - let (x, y, z, w) = Vector4::into_tuple(self); - x.is_finite() && y.is_finite() && z.is_finite() && w.is_finite() - } - - #[inline] - fn is_nan(self) -> bool { - MaskVector4::any(FloatVector4::is_nan_mask(self)) - } - - #[inline(always)] - fn is_nan_mask(self) -> Self::Mask { - f32x4_isnan(self) - } - - #[inline] - fn floor(self) -> Self { - f32x4_floor(self) - } - - #[inline] - fn ceil(self) -> Self { - f32x4_ceil(self) - } - - #[inline] - fn round(self) -> Self { - f32x4_nearest(self) - } - - #[inline(always)] - fn recip(self) -> Self { - f32x4_div(Self::ONE, self) - } - - #[inline] - fn exp(self) -> Self { - let (x, y, z, w) = Vector4::into_tuple(self); - f32x4(x.exp(), y.exp(), z.exp(), w.exp()) - } - - #[inline] - fn powf(self, n: f32) -> Self { - let (x, y, z, w) = Vector4::into_tuple(self); - f32x4(x.powf(n), y.powf(n), z.powf(n), w.powf(n)) - } - - #[inline] - fn length(self) -> f32 { - let dot = dot4_in_x(self, self); - f32x4_extract_lane::<0>(f32x4_sqrt(dot)) - } - - #[inline] - fn length_recip(self) -> f32 { - let dot = dot4_in_x(self, self); - f32x4_extract_lane::<0>(f32x4_div(Self::ONE, f32x4_sqrt(dot))) - } - - #[inline] - fn normalize(self) -> Self { - let dot = Vector4::dot_into_vec(self, self); - #[allow(clippy::let_and_return)] - let normalized = f32x4_div(self, f32x4_sqrt(dot)); - glam_assert!(FloatVector4::is_finite(normalized)); - normalized - } -} - -impl From> for v128 { - #[inline(always)] - fn from(v: XYZW) -> v128 { - f32x4(v.x, v.y, v.z, v.w) - } -} - -impl From> for v128 { - #[inline(always)] - fn from(v: XYZ) -> v128 { - f32x4(v.x, v.y, v.z, v.z) - } -} - -impl From> for v128 { - #[inline(always)] - fn from(v: XY) -> v128 { - f32x4(v.x, v.y, v.y, v.y) - } -} - -impl From for XYZW { - #[inline(always)] - fn from(v: v128) -> XYZW { - let mut out: MaybeUninit = MaybeUninit::uninit(); - unsafe { - v128_store(out.as_mut_ptr(), v); - *(&out.assume_init() as *const v128 as *const XYZW) - } - } -} - -impl From for XYZ { - #[inline(always)] - fn from(v: v128) -> XYZ { - let mut out: MaybeUninit = MaybeUninit::uninit(); - unsafe { - v128_store(out.as_mut_ptr(), v); - *(&out.assume_init() as *const v128 as *const XYZ) - } - } -} - -impl From for XY { - #[inline(always)] - fn from(v: v128) -> XY { - let mut out: MaybeUninit = MaybeUninit::uninit(); - unsafe { - v128_store(out.as_mut_ptr(), v); - *(&out.assume_init() as *const v128 as *const XY) - } - } -} diff --git a/src/deref.rs b/src/deref.rs new file mode 100644 index 00000000..c3ba55d9 --- /dev/null +++ b/src/deref.rs @@ -0,0 +1,50 @@ +#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd)] +#[cfg_attr(target_arch = "spirv", repr(simd))] +#[cfg_attr(not(target_arch = "spirv"), repr(C))] +pub struct XY { + pub x: T, + pub y: T, +} + +#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd)] +#[cfg_attr(target_arch = "spirv", repr(simd))] +#[cfg_attr(not(target_arch = "spirv"), repr(C))] +pub struct XYZ { + pub x: T, + pub y: T, + pub z: T, +} + +#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd)] +#[cfg_attr(target_arch = "spirv", repr(simd))] +#[cfg_attr(not(target_arch = "spirv"), repr(C))] +pub struct XYZW { + pub x: T, + pub y: T, + pub z: T, + pub w: T, +} + +#[derive(Clone, Copy, Default, PartialEq, PartialOrd)] +#[cfg_attr(not(target_arch = "spirv"), repr(C))] +pub struct Columns2 { + pub x_axis: V, + pub y_axis: V, +} + +#[derive(Clone, Copy, Default, PartialEq, PartialOrd)] +#[cfg_attr(not(target_arch = "spirv"), repr(C))] +pub struct Columns3 { + pub x_axis: V, + pub y_axis: V, + pub z_axis: V, +} + +#[derive(Clone, Copy, Default, PartialEq, PartialOrd)] +#[cfg_attr(not(target_arch = "spirv"), repr(C))] +pub struct Columns4 { + pub x_axis: V, + pub y_axis: V, + pub z_axis: V, + pub w_axis: V, +} diff --git a/src/euler.rs b/src/euler.rs index 558400a5..731bba49 100644 --- a/src/euler.rs +++ b/src/euler.rs @@ -4,8 +4,10 @@ Conversion from quaternions to Euler rotation sequences. From: http://bediyap.com/programming/convert-quaternion-to-euler-rotations/ */ -use super::quat::{DQuat, Quat}; -use crate::core::traits::scalar::*; +use super::{DQuat, Quat}; + +#[cfg(not(feature = "std"))] +use num_traits::Float; /// Euler rotation sequences. /// @@ -58,8 +60,8 @@ impl Default for EulerRot { } /// Conversion from quaternion to euler angles. -pub trait EulerFromQuaternion: Sized + Copy { - type Output: FloatEx; +pub(crate) trait EulerFromQuaternion: Sized + Copy { + type Output; /// Compute the angle of the first axis (X-x-x) fn first(self, q: Q) -> Self::Output; /// Compute then angle of the second axis (x-X-x) @@ -74,7 +76,7 @@ pub trait EulerFromQuaternion: Sized + Copy { } /// Conversion from euler angles to quaternion. -pub trait EulerToQuaternion: Copy { +pub(crate) trait EulerToQuaternion: Copy { type Output; /// Create the rotation quaternion for the three angles of this euler rotation sequence. fn new_quat(self, u: T, v: T, w: T) -> Self::Output; @@ -82,7 +84,7 @@ pub trait EulerToQuaternion: Copy { /// Adds a atan2 that handles the negative zero case. /// Basically forces positive zero in the x-argument for atan2. -pub trait Atan2Fixed { +pub(crate) trait Atan2Fixed { fn atan2_fixed(self, other: T) -> T; } @@ -104,36 +106,42 @@ macro_rules! impl_from_quat { fn first(self, q: $quat) -> $t { use EulerRot::*; match self { - ZYX => (Self::Output::TWO * (q.x * q.y + q.w * q.z)) + ZYX => (2.0 * (q.x * q.y + q.w * q.z)) .atan2(q.w * q.w + q.x * q.x - q.y * q.y - q.z * q.z), - ZXY => (-Self::Output::TWO * (q.x * q.y - q.w * q.z)) + ZXY => (-2.0 * (q.x * q.y - q.w * q.z)) .atan2(q.w * q.w - q.x * q.x + q.y * q.y - q.z * q.z), - YXZ => (Self::Output::TWO * (q.x * q.z + q.w * q.y)) + YXZ => (2.0 * (q.x * q.z + q.w * q.y)) .atan2(q.w * q.w - q.x * q.x - q.y * q.y + q.z * q.z), - YZX => (-Self::Output::TWO * (q.x * q.z - q.w * q.y)) + YZX => (-2.0 * (q.x * q.z - q.w * q.y)) .atan2(q.w * q.w + q.x * q.x - q.y * q.y - q.z * q.z), - XYZ => (-Self::Output::TWO * (q.y * q.z - q.w * q.x)) + XYZ => (-2.0 * (q.y * q.z - q.w * q.x)) .atan2(q.w * q.w - q.x * q.x - q.y * q.y + q.z * q.z), - XZY => (Self::Output::TWO * (q.y * q.z + q.w * q.x)) + XZY => (2.0 * (q.y * q.z + q.w * q.x)) .atan2(q.w * q.w - q.x * q.x + q.y * q.y - q.z * q.z), #[allow(deprecated)] - ZYZ => (Self::Output::TWO * (q.y * q.z + q.w * q.x)) - .atan2_fixed(-Self::Output::TWO * (q.x * q.z - q.w * q.y)), + ZYZ => { + (2.0 * (q.y * q.z + q.w * q.x)).atan2_fixed(-2.0 * (q.x * q.z - q.w * q.y)) + } #[allow(deprecated)] - ZXZ => (Self::Output::TWO * (q.x * q.z - q.w * q.y)) - .atan2_fixed(Self::Output::TWO * (q.y * q.z + q.w * q.x)), + ZXZ => { + (2.0 * (q.x * q.z - q.w * q.y)).atan2_fixed(2.0 * (q.y * q.z + q.w * q.x)) + } #[allow(deprecated)] - YXY => (Self::Output::TWO * (q.x * q.y + q.w * q.z)) - .atan2_fixed(-Self::Output::TWO * (q.y * q.z - q.w * q.x)), + YXY => { + (2.0 * (q.x * q.y + q.w * q.z)).atan2_fixed(-2.0 * (q.y * q.z - q.w * q.x)) + } #[allow(deprecated)] - YZY => (Self::Output::TWO * (q.y * q.z - q.w * q.x)) - .atan2_fixed(Self::Output::TWO * (q.x * q.y + q.w * q.z)), + YZY => { + (2.0 * (q.y * q.z - q.w * q.x)).atan2_fixed(2.0 * (q.x * q.y + q.w * q.z)) + } #[allow(deprecated)] - XYX => (Self::Output::TWO * (q.x * q.y - q.w * q.z)) - .atan2_fixed(Self::Output::TWO * (q.x * q.z + q.w * q.y)), + XYX => { + (2.0 * (q.x * q.y - q.w * q.z)).atan2_fixed(2.0 * (q.x * q.z + q.w * q.y)) + } #[allow(deprecated)] - XZX => (Self::Output::TWO * (q.x * q.z + q.w * q.y)) - .atan2_fixed(-Self::Output::TWO * (q.x * q.y - q.w * q.z)), + XZX => { + (2.0 * (q.x * q.z + q.w * q.y)).atan2_fixed(-2.0 * (q.x * q.y - q.w * q.z)) + } } } @@ -142,17 +150,17 @@ macro_rules! impl_from_quat { /// Clamp number to range [-1,1](-1,1) for asin() and acos(), else NaN is possible. #[inline(always)] - fn arc_clamp(val: T) -> T { - NumEx::min(NumEx::max(val, T::NEG_ONE), T::ONE) + fn arc_clamp(val: $t) -> $t { + <$t>::min(<$t>::max(val, -1.0), 1.0) } match self { - ZYX => arc_clamp(-Self::Output::TWO * (q.x * q.z - q.w * q.y)).asin(), - ZXY => arc_clamp(Self::Output::TWO * (q.y * q.z + q.w * q.x)).asin(), - YXZ => arc_clamp(-Self::Output::TWO * (q.y * q.z - q.w * q.x)).asin(), - YZX => arc_clamp(Self::Output::TWO * (q.x * q.y + q.w * q.z)).asin(), - XYZ => arc_clamp(Self::Output::TWO * (q.x * q.z + q.w * q.y)).asin(), - XZY => arc_clamp(-Self::Output::TWO * (q.x * q.y - q.w * q.z)).asin(), + ZYX => arc_clamp(-2.0 * (q.x * q.z - q.w * q.y)).asin(), + ZXY => arc_clamp(2.0 * (q.y * q.z + q.w * q.x)).asin(), + YXZ => arc_clamp(-2.0 * (q.y * q.z - q.w * q.x)).asin(), + YZX => arc_clamp(2.0 * (q.x * q.y + q.w * q.z)).asin(), + XYZ => arc_clamp(2.0 * (q.x * q.z + q.w * q.y)).asin(), + XZY => arc_clamp(-2.0 * (q.x * q.y - q.w * q.z)).asin(), #[allow(deprecated)] ZYZ => arc_clamp(q.w * q.w - q.x * q.x - q.y * q.y + q.z * q.z).acos(), #[allow(deprecated)] @@ -172,36 +180,42 @@ macro_rules! impl_from_quat { use EulerRot::*; #[allow(deprecated)] match self { - ZYX => (Self::Output::TWO * (q.y * q.z + q.w * q.x)) + ZYX => (2.0 * (q.y * q.z + q.w * q.x)) .atan2(q.w * q.w - q.x * q.x - q.y * q.y + q.z * q.z), - ZXY => (-Self::Output::TWO * (q.x * q.z - q.w * q.y)) + ZXY => (-2.0 * (q.x * q.z - q.w * q.y)) .atan2(q.w * q.w - q.x * q.x - q.y * q.y + q.z * q.z), - YXZ => (Self::Output::TWO * (q.x * q.y + q.w * q.z)) + YXZ => (2.0 * (q.x * q.y + q.w * q.z)) .atan2(q.w * q.w - q.x * q.x + q.y * q.y - q.z * q.z), - YZX => (-Self::Output::TWO * (q.y * q.z - q.w * q.x)) + YZX => (-2.0 * (q.y * q.z - q.w * q.x)) .atan2(q.w * q.w - q.x * q.x + q.y * q.y - q.z * q.z), - XYZ => (-Self::Output::TWO * (q.x * q.y - q.w * q.z)) + XYZ => (-2.0 * (q.x * q.y - q.w * q.z)) .atan2(q.w * q.w + q.x * q.x - q.y * q.y - q.z * q.z), - XZY => (Self::Output::TWO * (q.x * q.z + q.w * q.y)) + XZY => (2.0 * (q.x * q.z + q.w * q.y)) .atan2(q.w * q.w + q.x * q.x - q.y * q.y - q.z * q.z), #[allow(deprecated)] - ZYZ => (Self::Output::TWO * (q.y * q.z - q.w * q.x)) - .atan2_fixed(Self::Output::TWO * (q.x * q.z + q.w * q.y)), + ZYZ => { + (2.0 * (q.y * q.z - q.w * q.x)).atan2_fixed(2.0 * (q.x * q.z + q.w * q.y)) + } #[allow(deprecated)] - ZXZ => (Self::Output::TWO * (q.x * q.z + q.w * q.y)) - .atan2_fixed(-Self::Output::TWO * (q.y * q.z - q.w * q.x)), + ZXZ => { + (2.0 * (q.x * q.z + q.w * q.y)).atan2_fixed(-2.0 * (q.y * q.z - q.w * q.x)) + } #[allow(deprecated)] - YXY => (Self::Output::TWO * (q.x * q.y - q.w * q.z)) - .atan2_fixed(Self::Output::TWO * (q.y * q.z + q.w * q.x)), + YXY => { + (2.0 * (q.x * q.y - q.w * q.z)).atan2_fixed(2.0 * (q.y * q.z + q.w * q.x)) + } #[allow(deprecated)] - YZY => (Self::Output::TWO * (q.y * q.z + q.w * q.x)) - .atan2_fixed(-Self::Output::TWO * (q.x * q.y - q.w * q.z)), + YZY => { + (2.0 * (q.y * q.z + q.w * q.x)).atan2_fixed(-2.0 * (q.x * q.y - q.w * q.z)) + } #[allow(deprecated)] - XYX => (Self::Output::TWO * (q.x * q.y + q.w * q.z)) - .atan2_fixed(-Self::Output::TWO * (q.x * q.z - q.w * q.y)), + XYX => { + (2.0 * (q.x * q.y + q.w * q.z)).atan2_fixed(-2.0 * (q.x * q.z - q.w * q.y)) + } #[allow(deprecated)] - XZX => (Self::Output::TWO * (q.x * q.z - q.w * q.y)) - .atan2_fixed(Self::Output::TWO * (q.x * q.y + q.w * q.z)), + XZX => { + (2.0 * (q.x * q.z - q.w * q.y)).atan2_fixed(2.0 * (q.x * q.y + q.w * q.z)) + } } } } diff --git a/src/f32.rs b/src/f32.rs new file mode 100644 index 00000000..3a31e2a0 --- /dev/null +++ b/src/f32.rs @@ -0,0 +1,140 @@ +mod affine2; +mod affine3a; +mod mat3; +mod vec2; +mod vec3; + +#[cfg(any( + not(any(target_feature = "sse2", target_feature = "simd128")), + feature = "scalar-math" +))] +mod scalar; + +#[cfg(all(target_feature = "sse2", not(feature = "scalar-math")))] +mod sse2; + +#[cfg(all(target_feature = "simd128", not(feature = "scalar-math")))] +mod wasm32; + +#[cfg(any( + not(any(target_feature = "sse2", target_feature = "simd128")), + feature = "scalar-math" +))] +use scalar::*; + +#[cfg(all(target_feature = "sse2", not(feature = "scalar-math")))] +use sse2::*; + +#[cfg(all(target_feature = "simd128", not(feature = "scalar-math")))] +use wasm32::*; + +pub use affine2::Affine2; +pub use affine3a::Affine3A; +pub use mat2::{mat2, Mat2}; +pub use mat3::{mat3, Mat3}; +pub use mat3a::{mat3a, Mat3A}; +pub use mat4::{mat4, Mat4}; +pub use quat::{quat, Quat}; +pub use vec2::{vec2, Vec2}; +pub use vec3::{vec3, Vec3}; +pub use vec3a::{vec3a, Vec3A}; +pub use vec4::{vec4, Vec4}; + +#[cfg(all( + not(feature = "cuda"), + any(feature = "scalar-math", target_arch = "spirv") +))] +mod const_test_affine2 { + const_assert_eq!( + core::mem::align_of::(), + core::mem::align_of::() + ); + const_assert_eq!(24, core::mem::size_of::()); +} + +#[cfg(not(any(feature = "scalar-math", target_arch = "spirv")))] +mod const_test_affine2 { + const_assert_eq!(16, core::mem::align_of::()); + const_assert_eq!(32, core::mem::size_of::()); +} + +mod const_test_mat2 { + #[cfg(any(feature = "scalar-math", target_arch = "spirv"))] + const_assert_eq!( + core::mem::align_of::(), + core::mem::align_of::() + ); + #[cfg(not(any(feature = "scalar-math", target_arch = "spirv")))] + const_assert_eq!(16, core::mem::align_of::()); + const_assert_eq!(16, core::mem::size_of::()); +} + +mod const_test_mat3 { + const_assert_eq!( + core::mem::align_of::(), + core::mem::align_of::() + ); + const_assert_eq!(36, core::mem::size_of::()); +} + +mod const_test_mat3a { + const_assert_eq!(16, core::mem::align_of::()); + const_assert_eq!(48, core::mem::size_of::()); +} + +mod const_test_mat4 { + const_assert_eq!( + core::mem::align_of::(), + core::mem::align_of::() + ); + const_assert_eq!(64, core::mem::size_of::()); +} + +mod const_test_quat { + #[cfg(any(feature = "scalar-math", target_arch = "spirv"))] + const_assert_eq!( + core::mem::align_of::(), + core::mem::align_of::() + ); + #[cfg(not(any(feature = "scalar-math", target_arch = "spirv")))] + const_assert_eq!(16, core::mem::align_of::()); + const_assert_eq!(16, core::mem::size_of::()); +} + +mod const_test_vec2 { + #[cfg(not(feature = "cuda"))] + const_assert_eq!( + core::mem::align_of::(), + core::mem::align_of::() + ); + #[cfg(feature = "cuda")] + const_assert_eq!(8, core::mem::align_of::()); + const_assert_eq!(8, core::mem::size_of::()); +} + +mod const_test_vec3 { + const_assert_eq!( + core::mem::align_of::(), + core::mem::align_of::() + ); + const_assert_eq!(12, core::mem::size_of::()); +} + +mod const_test_vec3a { + const_assert_eq!(16, core::mem::align_of::()); + const_assert_eq!(16, core::mem::size_of::()); +} + +mod const_test_vec4 { + #[cfg(all( + any(feature = "scalar-math", target_arch = "spirv"), + not(feature = "cuda") + ))] + const_assert_eq!( + core::mem::align_of::(), + core::mem::align_of::() + ); + #[cfg(not(any(feature = "scalar-math", target_arch = "spirv")))] + const_assert_eq!(16, core::mem::align_of::()); + const_assert_eq!(16, core::mem::size_of::()); +} diff --git a/src/f32/affine2.rs b/src/f32/affine2.rs new file mode 100644 index 00000000..e8d77c08 --- /dev/null +++ b/src/f32/affine2.rs @@ -0,0 +1,435 @@ +// Generated from affine.rs template. Edit the template, not the generated file. + +use crate::{Mat2, Mat3, Mat3A, Vec2, Vec3A}; +use core::ops::{Add, Deref, DerefMut, Mul, Sub}; + +/// A 2D affine transform, which can represent translation, rotation, scaling and shear. +#[derive(Copy, Clone)] +#[repr(C)] +pub struct Affine2 { + pub matrix2: Mat2, + pub translation: Vec2, +} + +impl Affine2 { + /// The degenerate zero transform. + /// + /// This transforms any finite vector and point to zero. + /// The zero transform is non-invertible. + pub const ZERO: Self = Self { + matrix2: Mat2::ZERO, + translation: Vec2::ZERO, + }; + + /// The identity transform. + /// + /// Multiplying a vector with this returns the same vector. + pub const IDENTITY: Self = Self { + matrix2: Mat2::IDENTITY, + translation: Vec2::ZERO, + }; + + /// All NAN:s. + pub const NAN: Self = Self { + matrix2: Mat2::NAN, + translation: Vec2::NAN, + }; + + /// Creates an affine transform from three column vectors. + #[inline(always)] + pub const fn from_cols(x_axis: Vec2, y_axis: Vec2, z_axis: Vec2) -> Self { + Self { + matrix2: Mat2::from_cols(x_axis, y_axis), + translation: z_axis, + } + } + + /// Creates an affine transform from a `[f32; 6]` array stored in column major order. + /// If your data is stored in row major you will need to `transpose` the returned + /// matrix. + #[inline] + pub fn from_cols_array(m: &[f32; 6]) -> Self { + Self { + matrix2: Mat2::from_cols_slice(&m[0..4]), + translation: Vec2::from_slice(&m[4..6]), + } + } + + /// Creates a `[f32; 6]` array storing data in column major order. + /// If you require data in row major order `transpose` the matrix first. + #[inline] + pub fn to_cols_array(&self) -> [f32; 6] { + let x = &self.matrix2.x_axis; + let y = &self.matrix2.y_axis; + let z = &self.translation; + [x.x, x.y, y.x, y.y, z.x, z.y] + } + + /// Creates an affine transform from a `[[f32; 2]; 3]` + /// 2D array stored in column major order. + /// If your data is in row major order you will need to `transpose` the returned + /// matrix. + #[inline] + pub fn from_cols_array_2d(m: &[[f32; 2]; 3]) -> Self { + Self { + matrix2: Mat2::from_cols(m[0].into(), m[1].into()), + translation: m[2].into(), + } + } + + /// Creates a `[[f32; 2]; 3]` 2D array storing data in + /// column major order. + /// If you require data in row major order `transpose` the matrix first. + #[inline] + pub fn to_cols_array_2d(&self) -> [[f32; 2]; 3] { + [ + self.matrix2.x_axis.into(), + self.matrix2.y_axis.into(), + self.translation.into(), + ] + } + + /// Creates an affine transform from the first 6 values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 6 elements long. + #[inline] + pub fn from_cols_slice(slice: &[f32]) -> Self { + Self { + matrix2: Mat2::from_cols_slice(&slice[0..4]), + translation: Vec2::from_slice(&slice[4..6]), + } + } + + /// Writes the columns of `self` to the first 6 elements in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 6 elements long. + #[inline] + pub fn write_cols_to_slice(self, slice: &mut [f32]) { + self.matrix2.write_cols_to_slice(&mut slice[0..4]); + self.translation.write_to_slice(&mut slice[4..6]); + } + + /// Creates an affine transform that changes scale. + /// Note that if any scale is zero the transform will be non-invertible. + #[inline] + pub fn from_scale(scale: Vec2) -> Self { + Self { + matrix2: Mat2::from_diagonal(scale), + translation: Vec2::ZERO, + } + } + + /// Creates an affine transform from the given rotation `angle`. + #[inline] + pub fn from_angle(angle: f32) -> Self { + Self { + matrix2: Mat2::from_angle(angle), + translation: Vec2::ZERO, + } + } + + /// Creates an affine transformation from the given 2D `translation`. + #[inline] + pub fn from_translation(translation: Vec2) -> Self { + Self { + matrix2: Mat2::IDENTITY, + translation, + } + } + + /// Creates an affine transform from a 2x2 matrix (expressing scale, shear and rotation) + #[inline] + pub fn from_mat2(matrix2: Mat2) -> Self { + Self { + matrix2, + translation: Vec2::ZERO, + } + } + + /// Creates an affine transform from a 2x2 matrix (expressing scale, shear and rotation) and a + /// translation vector. + /// + /// Equivalent to + /// `Affine2::from_translation(translation) * Affine2::from_mat2(mat2)` + #[inline] + pub fn from_mat2_translation(matrix2: Mat2, translation: Vec2) -> Self { + Self { + matrix2, + translation, + } + } + + /// Creates an affine transform from the given 2D `scale`, rotation `angle` (in radians) and + /// `translation`. + /// + /// Equivalent to `Affine2::from_translation(translation) * + /// Affine2::from_angle(angle) * Affine2::from_scale(scale)` + #[inline] + pub fn from_scale_angle_translation(scale: Vec2, angle: f32, translation: Vec2) -> Self { + let rotation = Mat2::from_angle(angle); + Self { + matrix2: Mat2::from_cols(rotation.x_axis * scale.x, rotation.y_axis * scale.y), + translation, + } + } + + /// Creates an affine transform from the given 2D rotation `angle` (in radians) and + /// `translation`. + /// + /// Equivalent to `Affine2::from_translation(translation) * Affine2::from_angle(angle)` + #[inline] + pub fn from_angle_translation(angle: f32, translation: Vec2) -> Self { + Self { + matrix2: Mat2::from_angle(angle), + translation, + } + } + + /// The given `Mat3` must be an affine transform, + #[inline] + pub fn from_mat3(m: Mat3) -> Self { + use crate::swizzles::Vec3Swizzles; + Self { + matrix2: Mat2::from_cols(m.x_axis.xy(), m.y_axis.xy()), + translation: m.z_axis.xy(), + } + } + + /// Transforms the given 2D point, applying shear, scale, rotation and translation. + #[inline] + pub fn transform_point2(&self, rhs: Vec2) -> Vec2 { + self.matrix2 * rhs + self.translation + } + + /// Transforms the given 2D vector, applying shear, scale and rotation (but NOT + /// translation). + /// + /// To also apply translation, use [`Self::transform_point2`] instead. + #[inline] + pub fn transform_vector2(&self, rhs: Vec2) -> Vec2 { + self.matrix2 * rhs + } + + /// Returns `true` if, and only if, all elements are finite. + /// + /// If any element is either `NaN`, positive or negative infinity, this will return + /// `false`. + #[inline] + pub fn is_finite(&self) -> bool { + self.matrix2.is_finite() && self.translation.is_finite() + } + + /// Returns `true` if any elements are `NaN`. + #[inline] + pub fn is_nan(&self) -> bool { + self.matrix2.is_nan() || self.translation.is_nan() + } + + /// Returns true if the absolute difference of all elements between `self` and `rhs` + /// is less than or equal to `max_abs_diff`. + /// + /// This can be used to compare if two 3x4 matrices contain similar elements. It works + /// best when comparing with a known value. The `max_abs_diff` that should be used used + /// depends on the values being compared against. + /// + /// For more see + /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/). + #[inline] + pub fn abs_diff_eq(&self, rhs: Self, max_abs_diff: f32) -> bool { + self.matrix2.abs_diff_eq(rhs.matrix2, max_abs_diff) + && self.translation.abs_diff_eq(rhs.translation, max_abs_diff) + } + + /// Return the inverse of this transform. + /// + /// Note that if the transform is not invertible the result will be invalid. + #[must_use] + #[inline] + pub fn inverse(&self) -> Self { + let matrix2 = self.matrix2.inverse(); + // transform negative translation by the matrix inverse: + let translation = -(matrix2 * self.translation); + + Self { + matrix2, + translation, + } + } +} + +impl Default for Affine2 { + #[inline(always)] + fn default() -> Self { + Self::IDENTITY + } +} + +impl Deref for Affine2 { + type Target = crate::deref::Columns3; + #[inline(always)] + fn deref(&self) -> &Self::Target { + unsafe { &*(self as *const Self as *const Self::Target) } + } +} + +impl DerefMut for Affine2 { + #[inline(always)] + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { &mut *(self as *mut Self as *mut Self::Target) } + } +} + +impl PartialEq for Affine2 { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.matrix2.eq(&rhs.matrix2) && self.translation.eq(&rhs.translation) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl core::fmt::Debug for Affine2 { + fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + fmt.debug_struct(stringify!(Affine2)) + .field("matrix2", &self.matrix2) + .field("translation", &self.translation) + .finish() + } +} + +#[cfg(not(target_arch = "spirv"))] +impl core::fmt::Display for Affine2 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!( + f, + "[{}, {}, {}]", + self.matrix2.x_axis, self.matrix2.y_axis, self.translation + ) + } +} + +impl<'a> core::iter::Product<&'a Self> for Affine2 { + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::IDENTITY, |a, &b| a * b) + } +} + +impl Mul for Affine2 { + type Output = Affine2; + + #[inline] + fn mul(self, rhs: Affine2) -> Self::Output { + Self { + matrix2: self.matrix2 * rhs.matrix2, + translation: self.matrix2 * rhs.translation + self.translation, + } + } +} + +impl Mul for f32 { + type Output = Affine2; + #[inline] + fn mul(self, rhs: Affine2) -> Self::Output { + Affine2 { + matrix2: self * rhs.matrix2, + translation: self * rhs.translation, + } + } +} + +impl Mul for Affine2 { + type Output = Self; + #[inline] + fn mul(self, rhs: f32) -> Self::Output { + Self { + matrix2: self.matrix2 * rhs, + translation: self.translation * rhs, + } + } +} + +impl Add for Affine2 { + type Output = Self; + #[inline] + fn add(self, rhs: Self) -> Self::Output { + Self { + matrix2: self.matrix2 + rhs.matrix2, + translation: self.translation + rhs.translation, + } + } +} + +impl Sub for Affine2 { + type Output = Self; + #[inline] + fn sub(self, rhs: Self) -> Self::Output { + Self { + matrix2: self.matrix2 - rhs.matrix2, + translation: self.translation - rhs.translation, + } + } +} + +impl From for Mat3 { + #[inline] + fn from(m: Affine2) -> Mat3 { + Self::from_cols( + m.matrix2.x_axis.extend(0.0), + m.matrix2.y_axis.extend(0.0), + m.translation.extend(1.0), + ) + } +} + +impl Mul for Affine2 { + type Output = Mat3; + + #[inline] + fn mul(self, rhs: Mat3) -> Self::Output { + Mat3::from(self) * rhs + } +} + +impl Mul for Mat3 { + type Output = Mat3; + + #[inline] + fn mul(self, rhs: Affine2) -> Self::Output { + self * Mat3::from(rhs) + } +} + +impl From for Mat3A { + #[inline] + fn from(m: Affine2) -> Mat3A { + Self::from_cols( + Vec3A::from((m.matrix2.x_axis, 0.0)), + Vec3A::from((m.matrix2.y_axis, 0.0)), + Vec3A::from((m.translation, 1.0)), + ) + } +} + +impl Mul for Affine2 { + type Output = Mat3A; + + #[inline] + fn mul(self, rhs: Mat3A) -> Self::Output { + Mat3A::from(self) * rhs + } +} + +impl Mul for Mat3A { + type Output = Mat3A; + + #[inline] + fn mul(self, rhs: Affine2) -> Self::Output { + self * Mat3A::from(rhs) + } +} diff --git a/src/f32/affine3a.rs b/src/f32/affine3a.rs new file mode 100644 index 00000000..b8dc27d6 --- /dev/null +++ b/src/f32/affine3a.rs @@ -0,0 +1,566 @@ +// Generated from affine.rs template. Edit the template, not the generated file. + +use crate::{Mat3, Mat3A, Mat4, Quat, Vec3, Vec3A}; +use core::ops::{Add, Deref, DerefMut, Mul, Sub}; + +/// A 3D affine transform, which can represent translation, rotation, scaling and shear. +#[derive(Copy, Clone)] +#[repr(C)] +pub struct Affine3A { + pub matrix3: Mat3A, + pub translation: Vec3A, +} + +impl Affine3A { + /// The degenerate zero transform. + /// + /// This transforms any finite vector and point to zero. + /// The zero transform is non-invertible. + pub const ZERO: Self = Self { + matrix3: Mat3A::ZERO, + translation: Vec3A::ZERO, + }; + + /// The identity transform. + /// + /// Multiplying a vector with this returns the same vector. + pub const IDENTITY: Self = Self { + matrix3: Mat3A::IDENTITY, + translation: Vec3A::ZERO, + }; + + /// All NAN:s. + pub const NAN: Self = Self { + matrix3: Mat3A::NAN, + translation: Vec3A::NAN, + }; + + /// Creates an affine transform from three column vectors. + #[inline(always)] + pub const fn from_cols(x_axis: Vec3A, y_axis: Vec3A, z_axis: Vec3A, w_axis: Vec3A) -> Self { + Self { + matrix3: Mat3A::from_cols(x_axis, y_axis, z_axis), + translation: w_axis, + } + } + + /// Creates an affine transform from a `[f32; 12]` array stored in column major order. + /// If your data is stored in row major you will need to `transpose` the returned + /// matrix. + #[inline] + pub fn from_cols_array(m: &[f32; 12]) -> Self { + Self { + matrix3: Mat3A::from_cols_slice(&m[0..9]), + translation: Vec3A::from_slice(&m[9..12]), + } + } + + /// Creates a `[f32; 12]` array storing data in column major order. + /// If you require data in row major order `transpose` the matrix first. + #[inline] + pub fn to_cols_array(&self) -> [f32; 12] { + let x = &self.matrix3.x_axis; + let y = &self.matrix3.y_axis; + let z = &self.matrix3.z_axis; + let w = &self.translation; + [x.x, x.y, x.z, y.x, y.y, y.z, z.x, z.y, z.z, w.x, w.y, w.z] + } + + /// Creates an affine transform from a `[[f32; 3]; 4]` + /// 3D array stored in column major order. + /// If your data is in row major order you will need to `transpose` the returned + /// matrix. + #[inline] + pub fn from_cols_array_2d(m: &[[f32; 3]; 4]) -> Self { + Self { + matrix3: Mat3A::from_cols(m[0].into(), m[1].into(), m[2].into()), + translation: m[3].into(), + } + } + + /// Creates a `[[f32; 3]; 4]` 3D array storing data in + /// column major order. + /// If you require data in row major order `transpose` the matrix first. + #[inline] + pub fn to_cols_array_2d(&self) -> [[f32; 3]; 4] { + [ + self.matrix3.x_axis.into(), + self.matrix3.y_axis.into(), + self.matrix3.z_axis.into(), + self.translation.into(), + ] + } + + /// Creates an affine transform from the first 12 values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 12 elements long. + #[inline] + pub fn from_cols_slice(slice: &[f32]) -> Self { + Self { + matrix3: Mat3A::from_cols_slice(&slice[0..9]), + translation: Vec3A::from_slice(&slice[9..12]), + } + } + + /// Writes the columns of `self` to the first 12 elements in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 12 elements long. + #[inline] + pub fn write_cols_to_slice(self, slice: &mut [f32]) { + self.matrix3.write_cols_to_slice(&mut slice[0..9]); + self.translation.write_to_slice(&mut slice[9..12]); + } + + /// Creates an affine transform that changes scale. + /// Note that if any scale is zero the transform will be non-invertible. + #[inline] + pub fn from_scale(scale: Vec3) -> Self { + Self { + matrix3: Mat3A::from_diagonal(scale), + translation: Vec3A::ZERO, + } + } + /// Creates an affine transform from the given `rotation` quaternion. + #[inline] + pub fn from_quat(rotation: Quat) -> Self { + Self { + matrix3: Mat3A::from_quat(rotation), + translation: Vec3A::ZERO, + } + } + + /// Creates an affine transform containing a 3D rotation around a normalized + /// rotation `axis` of `angle` (in radians). + #[inline] + pub fn from_axis_angle(axis: Vec3, angle: f32) -> Self { + Self { + matrix3: Mat3A::from_axis_angle(axis, angle), + translation: Vec3A::ZERO, + } + } + + /// Creates an affine transform containing a 3D rotation around the x axis of + /// `angle` (in radians). + #[inline] + pub fn from_rotation_x(angle: f32) -> Self { + Self { + matrix3: Mat3A::from_rotation_x(angle), + translation: Vec3A::ZERO, + } + } + + /// Creates an affine transform containing a 3D rotation around the y axis of + /// `angle` (in radians). + #[inline] + pub fn from_rotation_y(angle: f32) -> Self { + Self { + matrix3: Mat3A::from_rotation_y(angle), + translation: Vec3A::ZERO, + } + } + + /// Creates an affine transform containing a 3D rotation around the z axis of + /// `angle` (in radians). + #[inline] + pub fn from_rotation_z(angle: f32) -> Self { + Self { + matrix3: Mat3A::from_rotation_z(angle), + translation: Vec3A::ZERO, + } + } + + /// Creates an affine transformation from the given 3D `translation`. + #[inline] + pub fn from_translation(translation: Vec3) -> Self { + #[allow(clippy::useless_conversion)] + Self { + matrix3: Mat3A::IDENTITY, + translation: translation.into(), + } + } + + /// Creates an affine transform from a 3x3 matrix (expressing scale, shear and + /// rotation) + #[inline] + pub fn from_mat3(mat3: Mat3) -> Self { + #[allow(clippy::useless_conversion)] + Self { + matrix3: mat3.into(), + translation: Vec3A::ZERO, + } + } + + /// Creates an affine transform from a 3x3 matrix (expressing scale, shear and rotation) + /// and a translation vector. + /// + /// Equivalent to `Affine3A::from_translation(translation) * Affine3A::from_mat3(mat3)` + #[inline] + pub fn from_mat3_translation(mat3: Mat3, translation: Vec3) -> Self { + #[allow(clippy::useless_conversion)] + Self { + matrix3: mat3.into(), + translation: translation.into(), + } + } + + /// Creates an affine transform from the given 3D `scale`, `rotation` and + /// `translation`. + /// + /// Equivalent to `Affine3A::from_translation(translation) * + /// Affine3A::from_quat(rotation) * Affine3A::from_scale(scale)` + #[inline] + pub fn from_scale_rotation_translation(scale: Vec3, rotation: Quat, translation: Vec3) -> Self { + let rotation = Mat3A::from_quat(rotation); + #[allow(clippy::useless_conversion)] + Self { + matrix3: Mat3A::from_cols( + rotation.x_axis * scale.x, + rotation.y_axis * scale.y, + rotation.z_axis * scale.z, + ), + translation: translation.into(), + } + } + + /// Creates an affine transform from the given 3D `rotation` and `translation`. + /// + /// Equivalent to `Affine3A::from_translation(translation) * Affine3A::from_quat(rotation)` + #[inline] + pub fn from_rotation_translation(rotation: Quat, translation: Vec3) -> Self { + #[allow(clippy::useless_conversion)] + Self { + matrix3: Mat3A::from_quat(rotation), + translation: translation.into(), + } + } + + /// The given `Mat4` must be an affine transform, + /// i.e. contain no perspective transform. + #[inline] + pub fn from_mat4(m: Mat4) -> Self { + Self { + matrix3: Mat3A::from_cols( + Vec3A::from_vec4(m.x_axis), + Vec3A::from_vec4(m.y_axis), + Vec3A::from_vec4(m.z_axis), + ), + translation: Vec3A::from_vec4(m.w_axis), + } + } + + /// Extracts `scale`, `rotation` and `translation` from `self`. + /// + /// The transform is expected to be non-degenerate and without shearing, or the output + /// will be invalid. + /// + /// # Panics + /// + /// Will panic if the determinant `self.matrix3` is zero or if the resulting scale + /// vector contains any zero elements when `glam_assert` is enabled. + #[inline] + pub fn to_scale_rotation_translation(&self) -> (Vec3, Quat, Vec3) { + #[cfg(not(feature = "std"))] + use num_traits::Float; + + // TODO: migrate to core module + let det = self.matrix3.determinant(); + glam_assert!(det != 0.0); + + let scale = Vec3::new( + self.matrix3.x_axis.length() * det.signum(), + self.matrix3.y_axis.length(), + self.matrix3.z_axis.length(), + ); + + glam_assert!(scale.cmpne(Vec3::ZERO).all()); + + let inv_scale = scale.recip(); + + #[allow(clippy::useless_conversion)] + let rotation = Quat::from_mat3(&Mat3::from_cols( + (self.matrix3.x_axis * inv_scale.x).into(), + (self.matrix3.y_axis * inv_scale.y).into(), + (self.matrix3.z_axis * inv_scale.z).into(), + )); + + #[allow(clippy::useless_conversion)] + (scale, rotation, self.translation.into()) + } + + #[inline] + fn look_to_lh(eye: Vec3, dir: Vec3, up: Vec3) -> Self { + let f = dir.normalize(); + let s = up.cross(f).normalize(); + let u = f.cross(s); + Self { + matrix3: Mat3A::from_cols( + Vec3A::new(s.x, u.x, f.x), + Vec3A::new(s.y, u.y, f.y), + Vec3A::new(s.z, u.z, f.z), + ), + translation: Vec3A::new(-s.dot(eye), -u.dot(eye), -f.dot(eye)), + } + } + + /// Creates a left-handed view transform using a camera position, an up direction, and + /// a focal point. + /// + /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=forward`. + /// + /// # Panics + /// + /// Will panic if `up` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn look_at_lh(eye: Vec3, center: Vec3, up: Vec3) -> Self { + glam_assert!(up.is_normalized()); + Self::look_to_lh(eye, center - eye, up) + } + + /// Creates a right-handed view transform using a camera position, an up direction, and + /// a focal point. + /// + /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=back`. + /// + /// # Panics + /// + /// Will panic if `up` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn look_at_rh(eye: Vec3, center: Vec3, up: Vec3) -> Self { + glam_assert!(up.is_normalized()); + Self::look_to_lh(eye, eye - center, up) + } + + /// Transforms the given 3D points, applying shear, scale, rotation and translation. + #[inline] + pub fn transform_point3(&self, rhs: Vec3) -> Vec3 { + #[allow(clippy::useless_conversion)] + ((self.matrix3.x_axis * rhs.x) + + (self.matrix3.y_axis * rhs.y) + + (self.matrix3.z_axis * rhs.z) + + self.translation) + .into() + } + + /// Transforms the given 3D vector, applying shear, scale and rotation (but NOT + /// translation). + /// + /// To also apply translation, use [`Self::transform_point3`] instead. + #[inline] + pub fn transform_vector3(&self, rhs: Vec3) -> Vec3 { + #[allow(clippy::useless_conversion)] + ((self.matrix3.x_axis * rhs.x) + + (self.matrix3.y_axis * rhs.y) + + (self.matrix3.z_axis * rhs.z)) + .into() + } + + /// Transforms the given `Vec3A`, applying shear, scale, rotation and translation. + #[inline] + pub fn transform_point3a(&self, rhs: Vec3A) -> Vec3A { + self.matrix3 * rhs + self.translation + } + + /// Transforms the given `Vec3A`, applying shear, scale and rotation (but NOT + /// translation). + /// + /// To also apply translation, use [`Self::transform_point3`] instead. + #[inline] + pub fn transform_vector3a(&self, rhs: Vec3A) -> Vec3A { + self.matrix3 * rhs + } + + /// Returns `true` if, and only if, all elements are finite. + /// + /// If any element is either `NaN`, positive or negative infinity, this will return + /// `false`. + #[inline] + pub fn is_finite(&self) -> bool { + self.matrix3.is_finite() && self.translation.is_finite() + } + + /// Returns `true` if any elements are `NaN`. + #[inline] + pub fn is_nan(&self) -> bool { + self.matrix3.is_nan() || self.translation.is_nan() + } + + /// Returns true if the absolute difference of all elements between `self` and `rhs` + /// is less than or equal to `max_abs_diff`. + /// + /// This can be used to compare if two 3x4 matrices contain similar elements. It works + /// best when comparing with a known value. The `max_abs_diff` that should be used used + /// depends on the values being compared against. + /// + /// For more see + /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/). + #[inline] + pub fn abs_diff_eq(&self, rhs: Self, max_abs_diff: f32) -> bool { + self.matrix3.abs_diff_eq(rhs.matrix3, max_abs_diff) + && self.translation.abs_diff_eq(rhs.translation, max_abs_diff) + } + + /// Return the inverse of this transform. + /// + /// Note that if the transform is not invertible the result will be invalid. + #[must_use] + #[inline] + pub fn inverse(&self) -> Self { + let matrix3 = self.matrix3.inverse(); + // transform negative translation by the matrix inverse: + let translation = -(matrix3 * self.translation); + + Self { + matrix3, + translation, + } + } +} + +impl Default for Affine3A { + #[inline(always)] + fn default() -> Self { + Self::IDENTITY + } +} + +impl Deref for Affine3A { + type Target = crate::deref::Columns4; + #[inline(always)] + fn deref(&self) -> &Self::Target { + unsafe { &*(self as *const Self as *const Self::Target) } + } +} + +impl DerefMut for Affine3A { + #[inline(always)] + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { &mut *(self as *mut Self as *mut Self::Target) } + } +} + +impl PartialEq for Affine3A { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.matrix3.eq(&rhs.matrix3) && self.translation.eq(&rhs.translation) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl core::fmt::Debug for Affine3A { + fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + fmt.debug_struct(stringify!(Affine3A)) + .field("matrix3", &self.matrix3) + .field("translation", &self.translation) + .finish() + } +} + +#[cfg(not(target_arch = "spirv"))] +impl core::fmt::Display for Affine3A { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!( + f, + "[{}, {}, {}, {}]", + self.matrix3.x_axis, self.matrix3.y_axis, self.matrix3.z_axis, self.translation + ) + } +} + +impl<'a> core::iter::Product<&'a Self> for Affine3A { + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::IDENTITY, |a, &b| a * b) + } +} + +impl Mul for Affine3A { + type Output = Affine3A; + + #[inline] + fn mul(self, rhs: Affine3A) -> Self::Output { + Self { + matrix3: self.matrix3 * rhs.matrix3, + translation: self.matrix3 * rhs.translation + self.translation, + } + } +} + +impl Mul for f32 { + type Output = Affine3A; + #[inline] + fn mul(self, rhs: Affine3A) -> Self::Output { + Affine3A { + matrix3: self * rhs.matrix3, + translation: self * rhs.translation, + } + } +} + +impl Mul for Affine3A { + type Output = Self; + #[inline] + fn mul(self, rhs: f32) -> Self::Output { + Self { + matrix3: self.matrix3 * rhs, + translation: self.translation * rhs, + } + } +} + +impl Add for Affine3A { + type Output = Self; + #[inline] + fn add(self, rhs: Self) -> Self::Output { + Self { + matrix3: self.matrix3 + rhs.matrix3, + translation: self.translation + rhs.translation, + } + } +} + +impl Sub for Affine3A { + type Output = Self; + #[inline] + fn sub(self, rhs: Self) -> Self::Output { + Self { + matrix3: self.matrix3 - rhs.matrix3, + translation: self.translation - rhs.translation, + } + } +} + +impl From for Mat4 { + #[inline] + fn from(m: Affine3A) -> Mat4 { + Mat4::from_cols( + m.matrix3.x_axis.extend(0.0), + m.matrix3.y_axis.extend(0.0), + m.matrix3.z_axis.extend(0.0), + m.translation.extend(1.0), + ) + } +} + +impl Mul for Affine3A { + type Output = Mat4; + + #[inline] + fn mul(self, rhs: Mat4) -> Self::Output { + Mat4::from(self) * rhs + } +} + +impl Mul for Mat4 { + type Output = Mat4; + + #[inline] + fn mul(self, rhs: Affine3A) -> Self::Output { + self * Mat4::from(rhs) + } +} diff --git a/src/f32/mat3.rs b/src/f32/mat3.rs new file mode 100644 index 00000000..f034bfaa --- /dev/null +++ b/src/f32/mat3.rs @@ -0,0 +1,705 @@ +// Generated from mat.rs template. Edit the template, not the generated file. + +use crate::{swizzles::*, DMat3, EulerRot, Mat2, Mat3A, Mat4, Quat, Vec2, Vec3, Vec3A}; +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::iter::{Product, Sum}; +use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; + +#[cfg(not(feature = "std"))] +use num_traits::Float; + +/// Creates a 3x3 matrix from column vectors. +#[inline(always)] +pub const fn mat3(x_axis: Vec3, y_axis: Vec3, z_axis: Vec3) -> Mat3 { + Mat3::from_cols(x_axis, y_axis, z_axis) +} + +/// A 3x3 column major matrix. +/// +/// This 3x3 matrix type features convenience methods for creating and using linear and +/// affine transformations. If you are primarily dealing with 2D affine transformations the +/// [`Affine2`](crate::Affine2) type is much faster and more space efficient than +/// using a 3x3 matrix. +/// +/// Linear transformations including 3D rotation and scale can be created using methods +/// such as [`Self::from_diagonal()`], [`Self::from_quat()`], [`Self::from_axis_angle()`], +/// [`Self::from_rotation_x()`], [`Self::from_rotation_y()`], or +/// [`Self::from_rotation_z()`]. +/// +/// The resulting matrices can be use to transform 3D vectors using regular vector +/// multiplication. +/// +/// Affine transformations including 2D translation, rotation and scale can be created +/// using methods such as [`Self::from_translation()`], [`Self::from_angle()`], +/// [`Self::from_scale()`] and [`Self::from_scale_angle_translation()`]. +/// +/// The [`Self::transform_point2()`] and [`Self::transform_vector2()`] convenience methods +/// are provided for performing affine transforms on 2D vectors and points. These multiply +/// 2D inputs as 3D vectors with an implicit `z` value of `1` for points and `0` for +/// vectors respectively. These methods assume that `Self` contains a valid affine +/// transform. +#[derive(Clone, Copy)] +pub struct Mat3 { + pub x_axis: Vec3, + pub y_axis: Vec3, + pub z_axis: Vec3, +} + +impl Mat3 { + /// A 3x3 matrix with all elements set to `0.0`. + pub const ZERO: Self = Self::from_cols(Vec3::ZERO, Vec3::ZERO, Vec3::ZERO); + + /// A 3x3 identity matrix, where all diagonal elements are `1`, and all off-diagonal elements are `0`. + pub const IDENTITY: Self = Self::from_cols(Vec3::X, Vec3::Y, Vec3::Z); + + /// All NAN:s. + pub const NAN: Self = Self::from_cols(Vec3::NAN, Vec3::NAN, Vec3::NAN); + + #[allow(clippy::too_many_arguments)] + #[inline(always)] + const fn new( + m00: f32, + m01: f32, + m02: f32, + m10: f32, + m11: f32, + m12: f32, + m20: f32, + m21: f32, + m22: f32, + ) -> Self { + Self { + x_axis: Vec3::new(m00, m01, m02), + y_axis: Vec3::new(m10, m11, m12), + z_axis: Vec3::new(m20, m21, m22), + } + } + + /// Creates a 3x3 matrix from two column vectors. + #[inline(always)] + pub const fn from_cols(x_axis: Vec3, y_axis: Vec3, z_axis: Vec3) -> Self { + Self { + x_axis, + y_axis, + z_axis, + } + } + + /// Creates a 3x3 matrix from a `[f32; 9]` array stored in column major order. + /// If your data is stored in row major you will need to `transpose` the returned + /// matrix. + #[inline] + pub const fn from_cols_array(m: &[f32; 9]) -> Self { + Self::new(m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8]) + } + + /// Creates a `[f32; 9]` array storing data in column major order. + /// If you require data in row major order `transpose` the matrix first. + #[inline] + pub fn to_cols_array(&self) -> [f32; 9] { + [ + self.x_axis.x, + self.x_axis.y, + self.x_axis.z, + self.y_axis.x, + self.y_axis.y, + self.y_axis.z, + self.z_axis.x, + self.z_axis.y, + self.z_axis.z, + ] + } + + /// Creates a 3x3 matrix from a `[[f32; 3]; 3]` 3D array stored in column major order. + /// If your data is in row major order you will need to `transpose` the returned + /// matrix. + #[inline] + pub const fn from_cols_array_2d(m: &[[f32; 3]; 3]) -> Self { + Self::from_cols( + Vec3::from_array(m[0]), + Vec3::from_array(m[1]), + Vec3::from_array(m[2]), + ) + } + + /// Creates a `[[f32; 3]; 3]` 3D array storing data in column major order. + /// If you require data in row major order `transpose` the matrix first. + #[inline] + pub fn to_cols_array_2d(&self) -> [[f32; 3]; 3] { + [ + self.x_axis.to_array(), + self.y_axis.to_array(), + self.z_axis.to_array(), + ] + } + + /// Creates a 3x3 matrix with its diagonal set to `diagonal` and all other entries set to 0. + #[doc(alias = "scale")] + #[inline] + pub fn from_diagonal(diagonal: Vec3) -> Self { + Self::new( + diagonal.x, 0.0, 0.0, 0.0, diagonal.y, 0.0, 0.0, 0.0, diagonal.z, + ) + } + + /// Creates a 3x3 matrix from a 4x4 matrix, discarding the 3rd row and column. + pub fn from_mat4(m: Mat4) -> Self { + Self::from_cols(m.x_axis.xyz(), m.y_axis.xyz(), m.z_axis.xyz()) + } + + /// Creates a 3D rotation matrix from the given quaternion. + /// + /// # Panics + /// + /// Will panic if `rotation` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn from_quat(rotation: Quat) -> Self { + glam_assert!(rotation.is_normalized()); + + let x2 = rotation.x + rotation.x; + let y2 = rotation.y + rotation.y; + let z2 = rotation.z + rotation.z; + let xx = rotation.x * x2; + let xy = rotation.x * y2; + let xz = rotation.x * z2; + let yy = rotation.y * y2; + let yz = rotation.y * z2; + let zz = rotation.z * z2; + let wx = rotation.w * x2; + let wy = rotation.w * y2; + let wz = rotation.w * z2; + + Self::from_cols( + Vec3::new(1.0 - (yy + zz), xy + wz, xz - wy), + Vec3::new(xy - wz, 1.0 - (xx + zz), yz + wx), + Vec3::new(xz + wy, yz - wx, 1.0 - (xx + yy)), + ) + } + + /// Creates a 3D rotation matrix from a normalized rotation `axis` and `angle` (in + /// radians). + /// + /// # Panics + /// + /// Will panic if `axis` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn from_axis_angle(axis: Vec3, angle: f32) -> Self { + glam_assert!(axis.is_normalized()); + + let (sin, cos) = angle.sin_cos(); + let (xsin, ysin, zsin) = axis.mul(sin).into(); + let (x, y, z) = axis.into(); + let (x2, y2, z2) = axis.mul(axis).into(); + let omc = 1.0 - cos; + let xyomc = x * y * omc; + let xzomc = x * z * omc; + let yzomc = y * z * omc; + Self::from_cols( + Vec3::new(x2 * omc + cos, xyomc + zsin, xzomc - ysin), + Vec3::new(xyomc - zsin, y2 * omc + cos, yzomc + xsin), + Vec3::new(xzomc + ysin, yzomc - xsin, z2 * omc + cos), + ) + } + + #[inline] + /// Creates a 3D rotation matrix from the given euler rotation sequence and the angles (in + /// radians). + pub fn from_euler(order: EulerRot, a: f32, b: f32, c: f32) -> Self { + let quat = Quat::from_euler(order, a, b, c); + Self::from_quat(quat) + } + + /// Creates a 3D rotation matrix from `angle` (in radians) around the x axis. + #[inline] + pub fn from_rotation_x(angle: f32) -> Self { + let (sina, cosa) = angle.sin_cos(); + Self::from_cols( + Vec3::X, + Vec3::new(0.0, cosa, sina), + Vec3::new(0.0, -sina, cosa), + ) + } + + /// Creates a 3D rotation matrix from `angle` (in radians) around the y axis. + #[inline] + pub fn from_rotation_y(angle: f32) -> Self { + let (sina, cosa) = angle.sin_cos(); + Self::from_cols( + Vec3::new(cosa, 0.0, -sina), + Vec3::Y, + Vec3::new(sina, 0.0, cosa), + ) + } + + /// Creates a 3D rotation matrix from `angle` (in radians) around the z axis. + #[inline] + pub fn from_rotation_z(angle: f32) -> Self { + let (sina, cosa) = angle.sin_cos(); + Self::from_cols( + Vec3::new(cosa, sina, 0.0), + Vec3::new(-sina, cosa, 0.0), + Vec3::Z, + ) + } + + /// Creates an affine transformation matrix from the given 2D `translation`. + /// + /// The resulting matrix can be used to transform 2D points and vectors. See + /// [`Self::transform_point2()`] and [`Self::transform_vector2()`]. + #[inline] + pub fn from_translation(translation: Vec2) -> Self { + Self::from_cols( + Vec3::X, + Vec3::Y, + Vec3::new(translation.x, translation.y, 1.0), + ) + } + + /// Creates an affine transformation matrix from the given 2D rotation `angle` (in + /// radians). + /// + /// The resulting matrix can be used to transform 2D points and vectors. See + /// [`Self::transform_point2()`] and [`Self::transform_vector2()`]. + #[inline] + pub fn from_angle(angle: f32) -> Self { + let (sin, cos) = angle.sin_cos(); + Self::from_cols(Vec3::new(cos, sin, 0.0), Vec3::new(-sin, cos, 0.0), Vec3::Z) + } + + /// Creates an affine transformation matrix from the given 2D `scale`, rotation `angle` (in + /// radians) and `translation`. + /// + /// The resulting matrix can be used to transform 2D points and vectors. See + /// [`Self::transform_point2()`] and [`Self::transform_vector2()`]. + #[inline] + pub fn from_scale_angle_translation(scale: Vec2, angle: f32, translation: Vec2) -> Self { + let (sin, cos) = angle.sin_cos(); + Self::from_cols( + Vec3::new(cos * scale.x, sin * scale.x, 0.0), + Vec3::new(-sin * scale.y, cos * scale.y, 0.0), + Vec3::new(translation.x, translation.y, 1.0), + ) + } + + /// Creates an affine transformation matrix from the given non-uniform 2D `scale`. + /// + /// The resulting matrix can be used to transform 2D points and vectors. See + /// [`Self::transform_point2()`] and [`Self::transform_vector2()`]. + /// + /// # Panics + /// + /// Will panic if all elements of `scale` are zero when `glam_assert` is enabled. + #[inline] + pub fn from_scale(scale: Vec2) -> Self { + // Do not panic as long as any component is non-zero + glam_assert!(scale.cmpne(Vec2::ZERO).any()); + + Self::from_cols( + Vec3::new(scale.x, 0.0, 0.0), + Vec3::new(0.0, scale.y, 0.0), + Vec3::Z, + ) + } + + /// Creates an affine transformation matrix from the given 2x2 matrix. + /// + /// The resulting matrix can be used to transform 2D points and vectors. See + /// [`Self::transform_point2()`] and [`Self::transform_vector2()`]. + #[inline] + pub fn from_mat2(m: Mat2) -> Self { + Self::from_cols((m.x_axis, 0.0).into(), (m.y_axis, 0.0).into(), Vec3::Z) + } + + /// Creates a 3x3 matrix from the first 9 values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 9 elements long. + #[inline] + pub const fn from_cols_slice(slice: &[f32]) -> Self { + Self::new( + slice[0], slice[1], slice[2], slice[3], slice[4], slice[5], slice[6], slice[7], + slice[8], + ) + } + + /// Writes the columns of `self` to the first 9 elements in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 9 elements long. + #[inline] + pub fn write_cols_to_slice(self, slice: &mut [f32]) { + slice[0] = self.x_axis.x; + slice[1] = self.x_axis.y; + slice[2] = self.x_axis.z; + slice[3] = self.y_axis.x; + slice[4] = self.y_axis.y; + slice[5] = self.y_axis.z; + slice[6] = self.z_axis.x; + slice[7] = self.z_axis.y; + slice[8] = self.z_axis.z; + } + + /// Returns the matrix column for the given `index`. + /// + /// # Panics + /// + /// Panics if `index` is greater than 2. + #[inline] + pub fn col(&self, index: usize) -> Vec3 { + match index { + 0 => self.x_axis, + 1 => self.y_axis, + 2 => self.z_axis, + _ => panic!("index out of bounds"), + } + } + + /// Returns a mutable reference to the matrix column for the given `index`. + /// + /// # Panics + /// + /// Panics if `index` is greater than 2. + #[inline] + pub fn col_mut(&mut self, index: usize) -> &mut Vec3 { + match index { + 0 => &mut self.x_axis, + 1 => &mut self.y_axis, + 2 => &mut self.z_axis, + _ => panic!("index out of bounds"), + } + } + + /// Returns the matrix row for the given `index`. + /// + /// # Panics + /// + /// Panics if `index` is greater than 2. + #[inline] + pub fn row(&self, index: usize) -> Vec3 { + match index { + 0 => Vec3::new(self.x_axis.x, self.y_axis.x, self.z_axis.x), + 1 => Vec3::new(self.x_axis.y, self.y_axis.y, self.z_axis.y), + 2 => Vec3::new(self.x_axis.z, self.y_axis.z, self.z_axis.z), + _ => panic!("index out of bounds"), + } + } + + /// Returns `true` if, and only if, all elements are finite. + /// If any element is either `NaN`, positive or negative infinity, this will return `false`. + #[inline] + pub fn is_finite(&self) -> bool { + self.x_axis.is_finite() && self.y_axis.is_finite() && self.z_axis.is_finite() + } + + /// Returns `true` if any elements are `NaN`. + #[inline] + pub fn is_nan(&self) -> bool { + self.x_axis.is_nan() || self.y_axis.is_nan() || self.z_axis.is_nan() + } + + /// Returns the transpose of `self`. + #[must_use] + #[inline] + pub fn transpose(&self) -> Self { + Self { + x_axis: Vec3::new(self.x_axis.x, self.y_axis.x, self.z_axis.x), + y_axis: Vec3::new(self.x_axis.y, self.y_axis.y, self.z_axis.y), + z_axis: Vec3::new(self.x_axis.z, self.y_axis.z, self.z_axis.z), + } + } + + /// Returns the determinant of `self`. + pub fn determinant(&self) -> f32 { + self.z_axis.dot(self.x_axis.cross(self.y_axis)) + } + + /// Returns the inverse of `self`. + /// + /// If the matrix is not invertible the returned matrix will be invalid. + /// + /// # Panics + /// + /// Will panic if the determinant of `self` is zero when `glam_assert` is enabled. + #[must_use] + pub fn inverse(&self) -> Self { + let tmp0 = self.y_axis.cross(self.z_axis); + let tmp1 = self.z_axis.cross(self.x_axis); + let tmp2 = self.x_axis.cross(self.y_axis); + let det = self.z_axis.dot(tmp2); + glam_assert!(det != 0.0); + let inv_det = Vec3::splat(det.recip()); + Self::from_cols(tmp0.mul(inv_det), tmp1.mul(inv_det), tmp2.mul(inv_det)).transpose() + } + + /// Transforms the given 2D vector as a point. + /// + /// This is the equivalent of multiplying `rhs` as a 3D vector where `z` is `1`. + /// + /// This method assumes that `self` contains a valid affine transform. + #[inline] + pub fn transform_point2(&self, rhs: Vec2) -> Vec2 { + Mat2::from_cols(self.x_axis.xy(), self.y_axis.xy()) * rhs + self.z_axis.xy() + } + + /// Rotates the given 2D vector. + /// + /// This is the equivalent of multiplying `rhs` as a 3D vector where `z` is `0`. + /// + /// This method assumes that `self` contains a valid affine transform. + #[inline] + pub fn transform_vector2(&self, rhs: Vec2) -> Vec2 { + Mat2::from_cols(self.x_axis.xy(), self.y_axis.xy()) * rhs + } + + /// Transforms a 3D vector. + #[inline] + pub fn mul_vec3(&self, rhs: Vec3) -> Vec3 { + let mut res = self.x_axis.mul(rhs.x); + res = res.add(self.y_axis.mul(rhs.y)); + res = res.add(self.z_axis.mul(rhs.z)); + res + } + + /// Transforms a `Vec3A`. + #[inline] + pub fn mul_vec3a(&self, rhs: Vec3A) -> Vec3A { + self.mul_vec3(rhs.into()).into() + } + + /// Multiplies two 3x3 matrices. + #[inline] + pub fn mul_mat3(&self, rhs: &Self) -> Self { + Self::from_cols( + self.mul(rhs.x_axis), + self.mul(rhs.y_axis), + self.mul(rhs.z_axis), + ) + } + + /// Adds two 3x3 matrices. + #[inline] + pub fn add_mat3(&self, rhs: &Self) -> Self { + Self::from_cols( + self.x_axis.add(rhs.x_axis), + self.y_axis.add(rhs.y_axis), + self.z_axis.add(rhs.z_axis), + ) + } + + /// Subtracts two 3x3 matrices. + #[inline] + pub fn sub_mat3(&self, rhs: &Self) -> Self { + Self::from_cols( + self.x_axis.sub(rhs.x_axis), + self.y_axis.sub(rhs.y_axis), + self.z_axis.sub(rhs.z_axis), + ) + } + + /// Multiplies a 3x3 matrix by a scalar. + #[inline] + pub fn mul_scalar(&self, rhs: f32) -> Self { + Self::from_cols( + self.x_axis.mul(rhs), + self.y_axis.mul(rhs), + self.z_axis.mul(rhs), + ) + } + + /// Returns true if the absolute difference of all elements between `self` and `rhs` + /// is less than or equal to `max_abs_diff`. + /// + /// This can be used to compare if two matrices contain similar elements. It works best + /// when comparing with a known value. The `max_abs_diff` that should be used used + /// depends on the values being compared against. + /// + /// For more see + /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/). + #[inline] + pub fn abs_diff_eq(&self, rhs: Self, max_abs_diff: f32) -> bool { + self.x_axis.abs_diff_eq(rhs.x_axis, max_abs_diff) + && self.y_axis.abs_diff_eq(rhs.y_axis, max_abs_diff) + && self.z_axis.abs_diff_eq(rhs.z_axis, max_abs_diff) + } + + #[inline] + pub fn as_dmat3(&self) -> DMat3 { + DMat3::from_cols( + self.x_axis.as_dvec3(), + self.y_axis.as_dvec3(), + self.z_axis.as_dvec3(), + ) + } +} + +impl Default for Mat3 { + #[inline] + fn default() -> Self { + Self::IDENTITY + } +} + +impl Add for Mat3 { + type Output = Self; + #[inline] + fn add(self, rhs: Self) -> Self::Output { + self.add_mat3(&rhs) + } +} + +impl AddAssign for Mat3 { + #[inline] + fn add_assign(&mut self, rhs: Self) { + *self = self.add_mat3(&rhs); + } +} + +impl Sub for Mat3 { + type Output = Self; + #[inline] + fn sub(self, rhs: Self) -> Self::Output { + self.sub_mat3(&rhs) + } +} + +impl SubAssign for Mat3 { + #[inline] + fn sub_assign(&mut self, rhs: Self) { + *self = self.sub_mat3(&rhs); + } +} + +impl Neg for Mat3 { + type Output = Self; + #[inline] + fn neg(self) -> Self::Output { + Self::from_cols(self.x_axis.neg(), self.y_axis.neg(), self.z_axis.neg()) + } +} + +impl Mul for Mat3 { + type Output = Self; + #[inline] + fn mul(self, rhs: Self) -> Self::Output { + self.mul_mat3(&rhs) + } +} + +impl MulAssign for Mat3 { + #[inline] + fn mul_assign(&mut self, rhs: Self) { + *self = self.mul_mat3(&rhs); + } +} + +impl Mul for Mat3 { + type Output = Vec3; + #[inline] + fn mul(self, rhs: Vec3) -> Self::Output { + self.mul_vec3(rhs) + } +} + +impl Mul for f32 { + type Output = Mat3; + #[inline] + fn mul(self, rhs: Mat3) -> Self::Output { + rhs.mul_scalar(self) + } +} + +impl Mul for Mat3 { + type Output = Self; + #[inline] + fn mul(self, rhs: f32) -> Self::Output { + self.mul_scalar(rhs) + } +} + +impl MulAssign for Mat3 { + #[inline] + fn mul_assign(&mut self, rhs: f32) { + *self = self.mul_scalar(rhs); + } +} + +impl Mul for Mat3 { + type Output = Vec3A; + #[inline] + fn mul(self, rhs: Vec3A) -> Vec3A { + self.mul_vec3a(rhs) + } +} + +impl From for Mat3 { + #[inline] + fn from(m: Mat3A) -> Self { + Self { + x_axis: m.x_axis.into(), + y_axis: m.y_axis.into(), + z_axis: m.z_axis.into(), + } + } +} + +impl<'a> Sum<&'a Self> for Mat3 { + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, |a, &b| Self::add(a, b)) + } +} + +impl<'a> Product<&'a Self> for Mat3 { + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::IDENTITY, |a, &b| Self::mul(a, b)) + } +} + +impl PartialEq for Mat3 { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.x_axis.eq(&rhs.x_axis) && self.y_axis.eq(&rhs.y_axis) && self.z_axis.eq(&rhs.z_axis) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsRef<[f32; 9]> for Mat3 { + #[inline] + fn as_ref(&self) -> &[f32; 9] { + unsafe { &*(self as *const Self as *const [f32; 9]) } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsMut<[f32; 9]> for Mat3 { + #[inline] + fn as_mut(&mut self) -> &mut [f32; 9] { + unsafe { &mut *(self as *mut Self as *mut [f32; 9]) } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Debug for Mat3 { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct(stringify!(Mat3)) + .field("x_axis", &self.x_axis) + .field("y_axis", &self.y_axis) + .field("z_axis", &self.z_axis) + .finish() + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Display for Mat3 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "[{}, {}, {}]", self.x_axis, self.y_axis, self.z_axis) + } +} diff --git a/src/f32/scalar.rs b/src/f32/scalar.rs new file mode 100644 index 00000000..24171e51 --- /dev/null +++ b/src/f32/scalar.rs @@ -0,0 +1,6 @@ +pub mod mat2; +pub mod mat3a; +pub mod mat4; +pub mod quat; +pub mod vec3a; +pub mod vec4; diff --git a/src/f32/scalar/mat2.rs b/src/f32/scalar/mat2.rs new file mode 100644 index 00000000..a6f4272f --- /dev/null +++ b/src/f32/scalar/mat2.rs @@ -0,0 +1,431 @@ +// Generated from mat.rs template. Edit the template, not the generated file. + +use crate::{swizzles::*, DMat2, Mat3, Vec2}; +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::iter::{Product, Sum}; +use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; + +#[cfg(not(feature = "std"))] +use num_traits::Float; + +/// Creates a 2x2 matrix from column vectors. +#[inline(always)] +pub const fn mat2(x_axis: Vec2, y_axis: Vec2) -> Mat2 { + Mat2::from_cols(x_axis, y_axis) +} + +/// A 2x2 column major matrix. +#[derive(Clone, Copy)] +#[cfg_attr( + not(any(feature = "scalar-math", target_arch = "spirv")), + repr(C, align(16)) +)] +#[cfg_attr(feature = "cuda", repr(C, align(8)))] +pub struct Mat2 { + pub x_axis: Vec2, + pub y_axis: Vec2, +} + +impl Mat2 { + /// A 2x2 matrix with all elements set to `0.0`. + pub const ZERO: Self = Self::from_cols(Vec2::ZERO, Vec2::ZERO); + + /// A 2x2 identity matrix, where all diagonal elements are `1`, and all off-diagonal elements are `0`. + pub const IDENTITY: Self = Self::from_cols(Vec2::X, Vec2::Y); + + /// All NAN:s. + pub const NAN: Self = Self::from_cols(Vec2::NAN, Vec2::NAN); + + #[allow(clippy::too_many_arguments)] + #[inline(always)] + const fn new(m00: f32, m01: f32, m10: f32, m11: f32) -> Self { + Self { + x_axis: Vec2::new(m00, m01), + y_axis: Vec2::new(m10, m11), + } + } + + /// Creates a 2x2 matrix from two column vectors. + #[inline(always)] + pub const fn from_cols(x_axis: Vec2, y_axis: Vec2) -> Self { + Self { x_axis, y_axis } + } + + /// Creates a 2x2 matrix from a `[f32; 4]` array stored in column major order. + /// If your data is stored in row major you will need to `transpose` the returned + /// matrix. + #[inline] + pub const fn from_cols_array(m: &[f32; 4]) -> Self { + Self::new(m[0], m[1], m[2], m[3]) + } + + /// Creates a `[f32; 4]` array storing data in column major order. + /// If you require data in row major order `transpose` the matrix first. + #[inline] + pub fn to_cols_array(&self) -> [f32; 4] { + [self.x_axis.x, self.x_axis.y, self.y_axis.x, self.y_axis.y] + } + + /// Creates a 2x2 matrix from a `[[f32; 2]; 2]` 2D array stored in column major order. + /// If your data is in row major order you will need to `transpose` the returned + /// matrix. + #[inline] + pub const fn from_cols_array_2d(m: &[[f32; 2]; 2]) -> Self { + Self::from_cols(Vec2::from_array(m[0]), Vec2::from_array(m[1])) + } + + /// Creates a `[[f32; 2]; 2]` 2D array storing data in column major order. + /// If you require data in row major order `transpose` the matrix first. + #[inline] + pub fn to_cols_array_2d(&self) -> [[f32; 2]; 2] { + [self.x_axis.to_array(), self.y_axis.to_array()] + } + + /// Creates a 2x2 matrix with its diagonal set to `diagonal` and all other entries set to 0. + #[doc(alias = "scale")] + #[inline] + pub fn from_diagonal(diagonal: Vec2) -> Self { + Self::new(diagonal.x, 0.0, 0.0, diagonal.y) + } + + /// Creates a 2x2 matrix containing the combining non-uniform `scale` and rotation of + /// `angle` (in radians). + #[inline] + pub fn from_scale_angle(scale: Vec2, angle: f32) -> Self { + let (sin, cos) = angle.sin_cos(); + Self::new(cos * scale.x, sin * scale.x, -sin * scale.y, cos * scale.y) + } + + /// Creates a 2x2 matrix containing a rotation of `angle` (in radians). + #[inline] + pub fn from_angle(angle: f32) -> Self { + let (sin, cos) = angle.sin_cos(); + Self::new(cos, sin, -sin, cos) + } + + /// Creates a 2x2 matrix from a 3x3 matrix, discarding the 2nd row and column. + #[inline] + pub fn from_mat3(m: Mat3) -> Self { + Self::from_cols(m.x_axis.xy(), m.y_axis.xy()) + } + + /// Creates a 2x2 matrix from the first 4 values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 4 elements long. + #[inline] + pub const fn from_cols_slice(slice: &[f32]) -> Self { + Self::new(slice[0], slice[1], slice[2], slice[3]) + } + + /// Writes the columns of `self` to the first 4 elements in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 4 elements long. + #[inline] + pub fn write_cols_to_slice(self, slice: &mut [f32]) { + slice[0] = self.x_axis.x; + slice[1] = self.x_axis.y; + slice[2] = self.y_axis.x; + slice[3] = self.y_axis.y; + } + + /// Returns the matrix column for the given `index`. + /// + /// # Panics + /// + /// Panics if `index` is greater than 1. + #[inline] + pub fn col(&self, index: usize) -> Vec2 { + match index { + 0 => self.x_axis, + 1 => self.y_axis, + _ => panic!("index out of bounds"), + } + } + + /// Returns a mutable reference to the matrix column for the given `index`. + /// + /// # Panics + /// + /// Panics if `index` is greater than 1. + #[inline] + pub fn col_mut(&mut self, index: usize) -> &mut Vec2 { + match index { + 0 => &mut self.x_axis, + 1 => &mut self.y_axis, + _ => panic!("index out of bounds"), + } + } + + /// Returns the matrix row for the given `index`. + /// + /// # Panics + /// + /// Panics if `index` is greater than 1. + #[inline] + pub fn row(&self, index: usize) -> Vec2 { + match index { + 0 => Vec2::new(self.x_axis.x, self.y_axis.x), + 1 => Vec2::new(self.x_axis.y, self.y_axis.y), + _ => panic!("index out of bounds"), + } + } + + /// Returns `true` if, and only if, all elements are finite. + /// If any element is either `NaN`, positive or negative infinity, this will return `false`. + #[inline] + pub fn is_finite(&self) -> bool { + self.x_axis.is_finite() && self.y_axis.is_finite() + } + + /// Returns `true` if any elements are `NaN`. + #[inline] + pub fn is_nan(&self) -> bool { + self.x_axis.is_nan() || self.y_axis.is_nan() + } + + /// Returns the transpose of `self`. + #[must_use] + #[inline] + pub fn transpose(&self) -> Self { + Self { + x_axis: Vec2::new(self.x_axis.x, self.y_axis.x), + y_axis: Vec2::new(self.x_axis.y, self.y_axis.y), + } + } + + /// Returns the determinant of `self`. + #[inline] + pub fn determinant(&self) -> f32 { + self.x_axis.x * self.y_axis.y - self.x_axis.y * self.y_axis.x + } + + /// Returns the inverse of `self`. + /// + /// If the matrix is not invertible the returned matrix will be invalid. + /// + /// # Panics + /// + /// Will panic if the determinant of `self` is zero when `glam_assert` is enabled. + #[must_use] + pub fn inverse(&self) -> Self { + let inv_det = { + let det = self.determinant(); + glam_assert!(det != 0.0); + det.recip() + }; + Self::new( + self.y_axis.y * inv_det, + self.x_axis.y * -inv_det, + self.y_axis.x * -inv_det, + self.x_axis.x * inv_det, + ) + } + + /// Transforms a 2D vector. + #[inline] + pub fn mul_vec2(&self, rhs: Vec2) -> Vec2 { + #[allow(clippy::suspicious_operation_groupings)] + Vec2::new( + (self.x_axis.x * rhs.x) + (self.y_axis.x * rhs.y), + (self.x_axis.y * rhs.x) + (self.y_axis.y * rhs.y), + ) + } + + /// Multiplies two 2x2 matrices. + #[inline] + pub fn mul_mat2(&self, rhs: &Self) -> Self { + Self::from_cols(self.mul(rhs.x_axis), self.mul(rhs.y_axis)) + } + + /// Adds two 2x2 matrices. + #[inline] + pub fn add_mat2(&self, rhs: &Self) -> Self { + Self::from_cols(self.x_axis.add(rhs.x_axis), self.y_axis.add(rhs.y_axis)) + } + + /// Subtracts two 2x2 matrices. + #[inline] + pub fn sub_mat2(&self, rhs: &Self) -> Self { + Self::from_cols(self.x_axis.sub(rhs.x_axis), self.y_axis.sub(rhs.y_axis)) + } + + /// Multiplies a 2x2 matrix by a scalar. + #[inline] + pub fn mul_scalar(&self, rhs: f32) -> Self { + Self::from_cols(self.x_axis.mul(rhs), self.y_axis.mul(rhs)) + } + + /// Returns true if the absolute difference of all elements between `self` and `rhs` + /// is less than or equal to `max_abs_diff`. + /// + /// This can be used to compare if two matrices contain similar elements. It works best + /// when comparing with a known value. The `max_abs_diff` that should be used used + /// depends on the values being compared against. + /// + /// For more see + /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/). + #[inline] + pub fn abs_diff_eq(&self, rhs: Self, max_abs_diff: f32) -> bool { + self.x_axis.abs_diff_eq(rhs.x_axis, max_abs_diff) + && self.y_axis.abs_diff_eq(rhs.y_axis, max_abs_diff) + } + + #[inline] + pub fn as_dmat2(&self) -> DMat2 { + DMat2::from_cols(self.x_axis.as_dvec2(), self.y_axis.as_dvec2()) + } +} + +impl Default for Mat2 { + #[inline] + fn default() -> Self { + Self::IDENTITY + } +} + +impl Add for Mat2 { + type Output = Self; + #[inline] + fn add(self, rhs: Self) -> Self::Output { + self.add_mat2(&rhs) + } +} + +impl AddAssign for Mat2 { + #[inline] + fn add_assign(&mut self, rhs: Self) { + *self = self.add_mat2(&rhs); + } +} + +impl Sub for Mat2 { + type Output = Self; + #[inline] + fn sub(self, rhs: Self) -> Self::Output { + self.sub_mat2(&rhs) + } +} + +impl SubAssign for Mat2 { + #[inline] + fn sub_assign(&mut self, rhs: Self) { + *self = self.sub_mat2(&rhs); + } +} + +impl Neg for Mat2 { + type Output = Self; + #[inline] + fn neg(self) -> Self::Output { + Self::from_cols(self.x_axis.neg(), self.y_axis.neg()) + } +} + +impl Mul for Mat2 { + type Output = Self; + #[inline] + fn mul(self, rhs: Self) -> Self::Output { + self.mul_mat2(&rhs) + } +} + +impl MulAssign for Mat2 { + #[inline] + fn mul_assign(&mut self, rhs: Self) { + *self = self.mul_mat2(&rhs); + } +} + +impl Mul for Mat2 { + type Output = Vec2; + #[inline] + fn mul(self, rhs: Vec2) -> Self::Output { + self.mul_vec2(rhs) + } +} + +impl Mul for f32 { + type Output = Mat2; + #[inline] + fn mul(self, rhs: Mat2) -> Self::Output { + rhs.mul_scalar(self) + } +} + +impl Mul for Mat2 { + type Output = Self; + #[inline] + fn mul(self, rhs: f32) -> Self::Output { + self.mul_scalar(rhs) + } +} + +impl MulAssign for Mat2 { + #[inline] + fn mul_assign(&mut self, rhs: f32) { + *self = self.mul_scalar(rhs); + } +} + +impl<'a> Sum<&'a Self> for Mat2 { + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, |a, &b| Self::add(a, b)) + } +} + +impl<'a> Product<&'a Self> for Mat2 { + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::IDENTITY, |a, &b| Self::mul(a, b)) + } +} + +impl PartialEq for Mat2 { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.x_axis.eq(&rhs.x_axis) && self.y_axis.eq(&rhs.y_axis) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsRef<[f32; 4]> for Mat2 { + #[inline] + fn as_ref(&self) -> &[f32; 4] { + unsafe { &*(self as *const Self as *const [f32; 4]) } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsMut<[f32; 4]> for Mat2 { + #[inline] + fn as_mut(&mut self) -> &mut [f32; 4] { + unsafe { &mut *(self as *mut Self as *mut [f32; 4]) } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Debug for Mat2 { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct(stringify!(Mat2)) + .field("x_axis", &self.x_axis) + .field("y_axis", &self.y_axis) + .finish() + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Display for Mat2 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "[{}, {}]", self.x_axis, self.y_axis) + } +} diff --git a/src/f32/scalar/mat3a.rs b/src/f32/scalar/mat3a.rs new file mode 100644 index 00000000..d20d661c --- /dev/null +++ b/src/f32/scalar/mat3a.rs @@ -0,0 +1,693 @@ +// Generated from mat.rs template. Edit the template, not the generated file. + +use crate::{swizzles::*, DMat3, EulerRot, Mat2, Mat3, Mat4, Quat, Vec2, Vec3, Vec3A}; +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::iter::{Product, Sum}; +use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; + +#[cfg(not(feature = "std"))] +use num_traits::Float; + +/// Creates a 3x3 matrix from column vectors. +#[inline(always)] +pub const fn mat3a(x_axis: Vec3A, y_axis: Vec3A, z_axis: Vec3A) -> Mat3A { + Mat3A::from_cols(x_axis, y_axis, z_axis) +} + +/// A 3x3 column major matrix. +/// +/// This 3x3 matrix type features convenience methods for creating and using linear and +/// affine transformations. If you are primarily dealing with 2D affine transformations the +/// [`Affine2`](crate::Affine2) type is much faster and more space efficient than +/// using a 3x3 matrix. +/// +/// Linear transformations including 3D rotation and scale can be created using methods +/// such as [`Self::from_diagonal()`], [`Self::from_quat()`], [`Self::from_axis_angle()`], +/// [`Self::from_rotation_x()`], [`Self::from_rotation_y()`], or +/// [`Self::from_rotation_z()`]. +/// +/// The resulting matrices can be use to transform 3D vectors using regular vector +/// multiplication. +/// +/// Affine transformations including 2D translation, rotation and scale can be created +/// using methods such as [`Self::from_translation()`], [`Self::from_angle()`], +/// [`Self::from_scale()`] and [`Self::from_scale_angle_translation()`]. +/// +/// The [`Self::transform_point2()`] and [`Self::transform_vector2()`] convenience methods +/// are provided for performing affine transforms on 2D vectors and points. These multiply +/// 2D inputs as 3D vectors with an implicit `z` value of `1` for points and `0` for +/// vectors respectively. These methods assume that `Self` contains a valid affine +/// transform. +#[derive(Clone, Copy)] +pub struct Mat3A { + pub x_axis: Vec3A, + pub y_axis: Vec3A, + pub z_axis: Vec3A, +} + +impl Mat3A { + /// A 3x3 matrix with all elements set to `0.0`. + pub const ZERO: Self = Self::from_cols(Vec3A::ZERO, Vec3A::ZERO, Vec3A::ZERO); + + /// A 3x3 identity matrix, where all diagonal elements are `1`, and all off-diagonal elements are `0`. + pub const IDENTITY: Self = Self::from_cols(Vec3A::X, Vec3A::Y, Vec3A::Z); + + /// All NAN:s. + pub const NAN: Self = Self::from_cols(Vec3A::NAN, Vec3A::NAN, Vec3A::NAN); + + #[allow(clippy::too_many_arguments)] + #[inline(always)] + const fn new( + m00: f32, + m01: f32, + m02: f32, + m10: f32, + m11: f32, + m12: f32, + m20: f32, + m21: f32, + m22: f32, + ) -> Self { + Self { + x_axis: Vec3A::new(m00, m01, m02), + y_axis: Vec3A::new(m10, m11, m12), + z_axis: Vec3A::new(m20, m21, m22), + } + } + + /// Creates a 3x3 matrix from two column vectors. + #[inline(always)] + pub const fn from_cols(x_axis: Vec3A, y_axis: Vec3A, z_axis: Vec3A) -> Self { + Self { + x_axis, + y_axis, + z_axis, + } + } + + /// Creates a 3x3 matrix from a `[f32; 9]` array stored in column major order. + /// If your data is stored in row major you will need to `transpose` the returned + /// matrix. + #[inline] + pub const fn from_cols_array(m: &[f32; 9]) -> Self { + Self::new(m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8]) + } + + /// Creates a `[f32; 9]` array storing data in column major order. + /// If you require data in row major order `transpose` the matrix first. + #[inline] + pub fn to_cols_array(&self) -> [f32; 9] { + [ + self.x_axis.x, + self.x_axis.y, + self.x_axis.z, + self.y_axis.x, + self.y_axis.y, + self.y_axis.z, + self.z_axis.x, + self.z_axis.y, + self.z_axis.z, + ] + } + + /// Creates a 3x3 matrix from a `[[f32; 3]; 3]` 3D array stored in column major order. + /// If your data is in row major order you will need to `transpose` the returned + /// matrix. + #[inline] + pub const fn from_cols_array_2d(m: &[[f32; 3]; 3]) -> Self { + Self::from_cols( + Vec3A::from_array(m[0]), + Vec3A::from_array(m[1]), + Vec3A::from_array(m[2]), + ) + } + + /// Creates a `[[f32; 3]; 3]` 3D array storing data in column major order. + /// If you require data in row major order `transpose` the matrix first. + #[inline] + pub fn to_cols_array_2d(&self) -> [[f32; 3]; 3] { + [ + self.x_axis.to_array(), + self.y_axis.to_array(), + self.z_axis.to_array(), + ] + } + + /// Creates a 3x3 matrix with its diagonal set to `diagonal` and all other entries set to 0. + #[doc(alias = "scale")] + #[inline] + pub fn from_diagonal(diagonal: Vec3) -> Self { + Self::new( + diagonal.x, 0.0, 0.0, 0.0, diagonal.y, 0.0, 0.0, 0.0, diagonal.z, + ) + } + + /// Creates a 3x3 matrix from a 4x4 matrix, discarding the 3rd row and column. + pub fn from_mat4(m: Mat4) -> Self { + Self::from_cols(m.x_axis.into(), m.y_axis.into(), m.z_axis.into()) + } + + /// Creates a 3D rotation matrix from the given quaternion. + /// + /// # Panics + /// + /// Will panic if `rotation` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn from_quat(rotation: Quat) -> Self { + glam_assert!(rotation.is_normalized()); + + let x2 = rotation.x + rotation.x; + let y2 = rotation.y + rotation.y; + let z2 = rotation.z + rotation.z; + let xx = rotation.x * x2; + let xy = rotation.x * y2; + let xz = rotation.x * z2; + let yy = rotation.y * y2; + let yz = rotation.y * z2; + let zz = rotation.z * z2; + let wx = rotation.w * x2; + let wy = rotation.w * y2; + let wz = rotation.w * z2; + + Self::from_cols( + Vec3A::new(1.0 - (yy + zz), xy + wz, xz - wy), + Vec3A::new(xy - wz, 1.0 - (xx + zz), yz + wx), + Vec3A::new(xz + wy, yz - wx, 1.0 - (xx + yy)), + ) + } + + /// Creates a 3D rotation matrix from a normalized rotation `axis` and `angle` (in + /// radians). + /// + /// # Panics + /// + /// Will panic if `axis` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn from_axis_angle(axis: Vec3, angle: f32) -> Self { + glam_assert!(axis.is_normalized()); + + let (sin, cos) = angle.sin_cos(); + let (xsin, ysin, zsin) = axis.mul(sin).into(); + let (x, y, z) = axis.into(); + let (x2, y2, z2) = axis.mul(axis).into(); + let omc = 1.0 - cos; + let xyomc = x * y * omc; + let xzomc = x * z * omc; + let yzomc = y * z * omc; + Self::from_cols( + Vec3A::new(x2 * omc + cos, xyomc + zsin, xzomc - ysin), + Vec3A::new(xyomc - zsin, y2 * omc + cos, yzomc + xsin), + Vec3A::new(xzomc + ysin, yzomc - xsin, z2 * omc + cos), + ) + } + + #[inline] + /// Creates a 3D rotation matrix from the given euler rotation sequence and the angles (in + /// radians). + pub fn from_euler(order: EulerRot, a: f32, b: f32, c: f32) -> Self { + let quat = Quat::from_euler(order, a, b, c); + Self::from_quat(quat) + } + + /// Creates a 3D rotation matrix from `angle` (in radians) around the x axis. + #[inline] + pub fn from_rotation_x(angle: f32) -> Self { + let (sina, cosa) = angle.sin_cos(); + Self::from_cols( + Vec3A::X, + Vec3A::new(0.0, cosa, sina), + Vec3A::new(0.0, -sina, cosa), + ) + } + + /// Creates a 3D rotation matrix from `angle` (in radians) around the y axis. + #[inline] + pub fn from_rotation_y(angle: f32) -> Self { + let (sina, cosa) = angle.sin_cos(); + Self::from_cols( + Vec3A::new(cosa, 0.0, -sina), + Vec3A::Y, + Vec3A::new(sina, 0.0, cosa), + ) + } + + /// Creates a 3D rotation matrix from `angle` (in radians) around the z axis. + #[inline] + pub fn from_rotation_z(angle: f32) -> Self { + let (sina, cosa) = angle.sin_cos(); + Self::from_cols( + Vec3A::new(cosa, sina, 0.0), + Vec3A::new(-sina, cosa, 0.0), + Vec3A::Z, + ) + } + + /// Creates an affine transformation matrix from the given 2D `translation`. + /// + /// The resulting matrix can be used to transform 2D points and vectors. See + /// [`Self::transform_point2()`] and [`Self::transform_vector2()`]. + #[inline] + pub fn from_translation(translation: Vec2) -> Self { + Self::from_cols( + Vec3A::X, + Vec3A::Y, + Vec3A::new(translation.x, translation.y, 1.0), + ) + } + + /// Creates an affine transformation matrix from the given 2D rotation `angle` (in + /// radians). + /// + /// The resulting matrix can be used to transform 2D points and vectors. See + /// [`Self::transform_point2()`] and [`Self::transform_vector2()`]. + #[inline] + pub fn from_angle(angle: f32) -> Self { + let (sin, cos) = angle.sin_cos(); + Self::from_cols( + Vec3A::new(cos, sin, 0.0), + Vec3A::new(-sin, cos, 0.0), + Vec3A::Z, + ) + } + + /// Creates an affine transformation matrix from the given 2D `scale`, rotation `angle` (in + /// radians) and `translation`. + /// + /// The resulting matrix can be used to transform 2D points and vectors. See + /// [`Self::transform_point2()`] and [`Self::transform_vector2()`]. + #[inline] + pub fn from_scale_angle_translation(scale: Vec2, angle: f32, translation: Vec2) -> Self { + let (sin, cos) = angle.sin_cos(); + Self::from_cols( + Vec3A::new(cos * scale.x, sin * scale.x, 0.0), + Vec3A::new(-sin * scale.y, cos * scale.y, 0.0), + Vec3A::new(translation.x, translation.y, 1.0), + ) + } + + /// Creates an affine transformation matrix from the given non-uniform 2D `scale`. + /// + /// The resulting matrix can be used to transform 2D points and vectors. See + /// [`Self::transform_point2()`] and [`Self::transform_vector2()`]. + /// + /// # Panics + /// + /// Will panic if all elements of `scale` are zero when `glam_assert` is enabled. + #[inline] + pub fn from_scale(scale: Vec2) -> Self { + // Do not panic as long as any component is non-zero + glam_assert!(scale.cmpne(Vec2::ZERO).any()); + + Self::from_cols( + Vec3A::new(scale.x, 0.0, 0.0), + Vec3A::new(0.0, scale.y, 0.0), + Vec3A::Z, + ) + } + + /// Creates an affine transformation matrix from the given 2x2 matrix. + /// + /// The resulting matrix can be used to transform 2D points and vectors. See + /// [`Self::transform_point2()`] and [`Self::transform_vector2()`]. + #[inline] + pub fn from_mat2(m: Mat2) -> Self { + Self::from_cols((m.x_axis, 0.0).into(), (m.y_axis, 0.0).into(), Vec3A::Z) + } + + /// Creates a 3x3 matrix from the first 9 values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 9 elements long. + #[inline] + pub const fn from_cols_slice(slice: &[f32]) -> Self { + Self::new( + slice[0], slice[1], slice[2], slice[3], slice[4], slice[5], slice[6], slice[7], + slice[8], + ) + } + + /// Writes the columns of `self` to the first 9 elements in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 9 elements long. + #[inline] + pub fn write_cols_to_slice(self, slice: &mut [f32]) { + slice[0] = self.x_axis.x; + slice[1] = self.x_axis.y; + slice[2] = self.x_axis.z; + slice[3] = self.y_axis.x; + slice[4] = self.y_axis.y; + slice[5] = self.y_axis.z; + slice[6] = self.z_axis.x; + slice[7] = self.z_axis.y; + slice[8] = self.z_axis.z; + } + + /// Returns the matrix column for the given `index`. + /// + /// # Panics + /// + /// Panics if `index` is greater than 2. + #[inline] + pub fn col(&self, index: usize) -> Vec3A { + match index { + 0 => self.x_axis, + 1 => self.y_axis, + 2 => self.z_axis, + _ => panic!("index out of bounds"), + } + } + + /// Returns a mutable reference to the matrix column for the given `index`. + /// + /// # Panics + /// + /// Panics if `index` is greater than 2. + #[inline] + pub fn col_mut(&mut self, index: usize) -> &mut Vec3A { + match index { + 0 => &mut self.x_axis, + 1 => &mut self.y_axis, + 2 => &mut self.z_axis, + _ => panic!("index out of bounds"), + } + } + + /// Returns the matrix row for the given `index`. + /// + /// # Panics + /// + /// Panics if `index` is greater than 2. + #[inline] + pub fn row(&self, index: usize) -> Vec3A { + match index { + 0 => Vec3A::new(self.x_axis.x, self.y_axis.x, self.z_axis.x), + 1 => Vec3A::new(self.x_axis.y, self.y_axis.y, self.z_axis.y), + 2 => Vec3A::new(self.x_axis.z, self.y_axis.z, self.z_axis.z), + _ => panic!("index out of bounds"), + } + } + + /// Returns `true` if, and only if, all elements are finite. + /// If any element is either `NaN`, positive or negative infinity, this will return `false`. + #[inline] + pub fn is_finite(&self) -> bool { + self.x_axis.is_finite() && self.y_axis.is_finite() && self.z_axis.is_finite() + } + + /// Returns `true` if any elements are `NaN`. + #[inline] + pub fn is_nan(&self) -> bool { + self.x_axis.is_nan() || self.y_axis.is_nan() || self.z_axis.is_nan() + } + + /// Returns the transpose of `self`. + #[must_use] + #[inline] + pub fn transpose(&self) -> Self { + Self { + x_axis: Vec3A::new(self.x_axis.x, self.y_axis.x, self.z_axis.x), + y_axis: Vec3A::new(self.x_axis.y, self.y_axis.y, self.z_axis.y), + z_axis: Vec3A::new(self.x_axis.z, self.y_axis.z, self.z_axis.z), + } + } + + /// Returns the determinant of `self`. + pub fn determinant(&self) -> f32 { + self.z_axis.dot(self.x_axis.cross(self.y_axis)) + } + + /// Returns the inverse of `self`. + /// + /// If the matrix is not invertible the returned matrix will be invalid. + /// + /// # Panics + /// + /// Will panic if the determinant of `self` is zero when `glam_assert` is enabled. + #[must_use] + pub fn inverse(&self) -> Self { + let tmp0 = self.y_axis.cross(self.z_axis); + let tmp1 = self.z_axis.cross(self.x_axis); + let tmp2 = self.x_axis.cross(self.y_axis); + let det = self.z_axis.dot(tmp2); + glam_assert!(det != 0.0); + let inv_det = Vec3A::splat(det.recip()); + Self::from_cols(tmp0.mul(inv_det), tmp1.mul(inv_det), tmp2.mul(inv_det)).transpose() + } + + /// Transforms the given 2D vector as a point. + /// + /// This is the equivalent of multiplying `rhs` as a 3D vector where `z` is `1`. + /// + /// This method assumes that `self` contains a valid affine transform. + #[inline] + pub fn transform_point2(&self, rhs: Vec2) -> Vec2 { + Mat2::from_cols(self.x_axis.xy(), self.y_axis.xy()) * rhs + self.z_axis.xy() + } + + /// Rotates the given 2D vector. + /// + /// This is the equivalent of multiplying `rhs` as a 3D vector where `z` is `0`. + /// + /// This method assumes that `self` contains a valid affine transform. + #[inline] + pub fn transform_vector2(&self, rhs: Vec2) -> Vec2 { + Mat2::from_cols(self.x_axis.xy(), self.y_axis.xy()) * rhs + } + + /// Transforms a 3D vector. + #[inline] + pub fn mul_vec3(&self, rhs: Vec3) -> Vec3 { + self.mul_vec3a(rhs.into()).into() + } + + /// Transforms a `Vec3A`. + #[inline] + pub fn mul_vec3a(&self, rhs: Vec3A) -> Vec3A { + let mut res = self.x_axis.mul(rhs.xxx()); + res = res.add(self.y_axis.mul(rhs.yyy())); + res = res.add(self.z_axis.mul(rhs.zzz())); + res + } + + /// Multiplies two 3x3 matrices. + #[inline] + pub fn mul_mat3(&self, rhs: &Self) -> Self { + Self::from_cols( + self.mul(rhs.x_axis), + self.mul(rhs.y_axis), + self.mul(rhs.z_axis), + ) + } + + /// Adds two 3x3 matrices. + #[inline] + pub fn add_mat3(&self, rhs: &Self) -> Self { + Self::from_cols( + self.x_axis.add(rhs.x_axis), + self.y_axis.add(rhs.y_axis), + self.z_axis.add(rhs.z_axis), + ) + } + + /// Subtracts two 3x3 matrices. + #[inline] + pub fn sub_mat3(&self, rhs: &Self) -> Self { + Self::from_cols( + self.x_axis.sub(rhs.x_axis), + self.y_axis.sub(rhs.y_axis), + self.z_axis.sub(rhs.z_axis), + ) + } + + /// Multiplies a 3x3 matrix by a scalar. + #[inline] + pub fn mul_scalar(&self, rhs: f32) -> Self { + Self::from_cols( + self.x_axis.mul(rhs), + self.y_axis.mul(rhs), + self.z_axis.mul(rhs), + ) + } + + /// Returns true if the absolute difference of all elements between `self` and `rhs` + /// is less than or equal to `max_abs_diff`. + /// + /// This can be used to compare if two matrices contain similar elements. It works best + /// when comparing with a known value. The `max_abs_diff` that should be used used + /// depends on the values being compared against. + /// + /// For more see + /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/). + #[inline] + pub fn abs_diff_eq(&self, rhs: Self, max_abs_diff: f32) -> bool { + self.x_axis.abs_diff_eq(rhs.x_axis, max_abs_diff) + && self.y_axis.abs_diff_eq(rhs.y_axis, max_abs_diff) + && self.z_axis.abs_diff_eq(rhs.z_axis, max_abs_diff) + } + + #[inline] + pub fn as_dmat3(&self) -> DMat3 { + DMat3::from_cols( + self.x_axis.as_dvec3(), + self.y_axis.as_dvec3(), + self.z_axis.as_dvec3(), + ) + } +} + +impl Default for Mat3A { + #[inline] + fn default() -> Self { + Self::IDENTITY + } +} + +impl Add for Mat3A { + type Output = Self; + #[inline] + fn add(self, rhs: Self) -> Self::Output { + self.add_mat3(&rhs) + } +} + +impl AddAssign for Mat3A { + #[inline] + fn add_assign(&mut self, rhs: Self) { + *self = self.add_mat3(&rhs); + } +} + +impl Sub for Mat3A { + type Output = Self; + #[inline] + fn sub(self, rhs: Self) -> Self::Output { + self.sub_mat3(&rhs) + } +} + +impl SubAssign for Mat3A { + #[inline] + fn sub_assign(&mut self, rhs: Self) { + *self = self.sub_mat3(&rhs); + } +} + +impl Neg for Mat3A { + type Output = Self; + #[inline] + fn neg(self) -> Self::Output { + Self::from_cols(self.x_axis.neg(), self.y_axis.neg(), self.z_axis.neg()) + } +} + +impl Mul for Mat3A { + type Output = Self; + #[inline] + fn mul(self, rhs: Self) -> Self::Output { + self.mul_mat3(&rhs) + } +} + +impl MulAssign for Mat3A { + #[inline] + fn mul_assign(&mut self, rhs: Self) { + *self = self.mul_mat3(&rhs); + } +} + +impl Mul for Mat3A { + type Output = Vec3A; + #[inline] + fn mul(self, rhs: Vec3A) -> Self::Output { + self.mul_vec3a(rhs) + } +} + +impl Mul for f32 { + type Output = Mat3A; + #[inline] + fn mul(self, rhs: Mat3A) -> Self::Output { + rhs.mul_scalar(self) + } +} + +impl Mul for Mat3A { + type Output = Self; + #[inline] + fn mul(self, rhs: f32) -> Self::Output { + self.mul_scalar(rhs) + } +} + +impl MulAssign for Mat3A { + #[inline] + fn mul_assign(&mut self, rhs: f32) { + *self = self.mul_scalar(rhs); + } +} + +impl Mul for Mat3A { + type Output = Vec3; + #[inline] + fn mul(self, rhs: Vec3) -> Vec3 { + self.mul_vec3a(rhs.into()).into() + } +} + +impl From for Mat3A { + #[inline] + fn from(m: Mat3) -> Self { + Self { + x_axis: m.x_axis.into(), + y_axis: m.y_axis.into(), + z_axis: m.z_axis.into(), + } + } +} + +impl<'a> Sum<&'a Self> for Mat3A { + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, |a, &b| Self::add(a, b)) + } +} + +impl<'a> Product<&'a Self> for Mat3A { + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::IDENTITY, |a, &b| Self::mul(a, b)) + } +} + +impl PartialEq for Mat3A { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.x_axis.eq(&rhs.x_axis) && self.y_axis.eq(&rhs.y_axis) && self.z_axis.eq(&rhs.z_axis) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Debug for Mat3A { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct(stringify!(Mat3A)) + .field("x_axis", &self.x_axis) + .field("y_axis", &self.y_axis) + .field("z_axis", &self.z_axis) + .finish() + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Display for Mat3A { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "[{}, {}, {}]", self.x_axis, self.y_axis, self.z_axis) + } +} diff --git a/src/f32/scalar/mat4.rs b/src/f32/scalar/mat4.rs new file mode 100644 index 00000000..24735a3d --- /dev/null +++ b/src/f32/scalar/mat4.rs @@ -0,0 +1,1226 @@ +// Generated from mat.rs template. Edit the template, not the generated file. + +use crate::{swizzles::*, DMat4, EulerRot, Mat3, Quat, Vec3, Vec3A, Vec4}; +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::iter::{Product, Sum}; +use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; + +#[cfg(not(feature = "std"))] +use num_traits::Float; + +/// Creates a 4x4 matrix from column vectors. +#[inline(always)] +pub const fn mat4(x_axis: Vec4, y_axis: Vec4, z_axis: Vec4, w_axis: Vec4) -> Mat4 { + Mat4::from_cols(x_axis, y_axis, z_axis, w_axis) +} + +/// A 4x4 column major matrix. +/// +/// This 4x4 matrix type features convenience methods for creating and using affine transforms and +/// perspective projections. If you are primarily dealing with 3D affine transformations +/// considering using [`Affine3A`](crate::Affine3A) which is faster than a 4x4 matrix +/// for some affine operations. +/// +/// Affine transformations including 3D translation, rotation and scale can be created +/// using methods such as [`Self::from_translation()`], [`Self::from_quat()`], +/// [`Self::from_scale()`] and [`Self::from_scale_rotation_translation()`]. +/// +/// Othographic projections can be created using the methods [`Self::orthographic_lh()`] for +/// left-handed coordinate systems and [`Self::orthographic_rh()`] for right-handed +/// systems. The resulting matrix is also an affine transformation. +/// +/// The [`Self::transform_point3()`] and [`Self::transform_vector3()`] convenience methods +/// are provided for performing affine transformations on 3D vectors and points. These +/// multiply 3D inputs as 4D vectors with an implicit `w` value of `1` for points and `0` +/// for vectors respectively. These methods assume that `Self` contains a valid affine +/// transform. +/// +/// Perspective projections can be created using methods such as +/// [`Self::perspective_lh()`], [`Self::perspective_infinite_lh()`] and +/// [`Self::perspective_infinite_reverse_lh()`] for left-handed co-ordinate systems and +/// [`Self::perspective_rh()`], [`Self::perspective_infinite_rh()`] and +/// [`Self::perspective_infinite_reverse_rh()`] for right-handed co-ordinate systems. +/// +/// The resulting perspective project can be use to transform 3D vectors as points with +/// perspective correction using the [`Self::project_point3()`] convenience method. +#[derive(Clone, Copy)] +#[cfg_attr( + any( + not(any(feature = "scalar-math", target_arch = "spirv")), + feature = "cuda" + ), + repr(C, align(16)) +)] +pub struct Mat4 { + pub x_axis: Vec4, + pub y_axis: Vec4, + pub z_axis: Vec4, + pub w_axis: Vec4, +} + +impl Mat4 { + /// A 4x4 matrix with all elements set to `0.0`. + pub const ZERO: Self = Self::from_cols(Vec4::ZERO, Vec4::ZERO, Vec4::ZERO, Vec4::ZERO); + + /// A 4x4 identity matrix, where all diagonal elements are `1`, and all off-diagonal elements are `0`. + pub const IDENTITY: Self = Self::from_cols(Vec4::X, Vec4::Y, Vec4::Z, Vec4::W); + + /// All NAN:s. + pub const NAN: Self = Self::from_cols(Vec4::NAN, Vec4::NAN, Vec4::NAN, Vec4::NAN); + + #[allow(clippy::too_many_arguments)] + #[inline(always)] + const fn new( + m00: f32, + m01: f32, + m02: f32, + m03: f32, + m10: f32, + m11: f32, + m12: f32, + m13: f32, + m20: f32, + m21: f32, + m22: f32, + m23: f32, + m30: f32, + m31: f32, + m32: f32, + m33: f32, + ) -> Self { + Self { + x_axis: Vec4::new(m00, m01, m02, m03), + y_axis: Vec4::new(m10, m11, m12, m13), + z_axis: Vec4::new(m20, m21, m22, m23), + w_axis: Vec4::new(m30, m31, m32, m33), + } + } + + /// Creates a 4x4 matrix from two column vectors. + #[inline(always)] + pub const fn from_cols(x_axis: Vec4, y_axis: Vec4, z_axis: Vec4, w_axis: Vec4) -> Self { + Self { + x_axis, + y_axis, + z_axis, + w_axis, + } + } + + /// Creates a 4x4 matrix from a `[f32; 16]` array stored in column major order. + /// If your data is stored in row major you will need to `transpose` the returned + /// matrix. + #[inline] + pub const fn from_cols_array(m: &[f32; 16]) -> Self { + Self::new( + m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], m[9], m[10], m[11], m[12], m[13], + m[14], m[15], + ) + } + + /// Creates a `[f32; 16]` array storing data in column major order. + /// If you require data in row major order `transpose` the matrix first. + #[inline] + pub fn to_cols_array(&self) -> [f32; 16] { + [ + self.x_axis.x, + self.x_axis.y, + self.x_axis.z, + self.x_axis.w, + self.y_axis.x, + self.y_axis.y, + self.y_axis.z, + self.y_axis.w, + self.z_axis.x, + self.z_axis.y, + self.z_axis.z, + self.z_axis.w, + self.w_axis.x, + self.w_axis.y, + self.w_axis.z, + self.w_axis.w, + ] + } + + /// Creates a 4x4 matrix from a `[[f32; 4]; 4]` 4D array stored in column major order. + /// If your data is in row major order you will need to `transpose` the returned + /// matrix. + #[inline] + pub const fn from_cols_array_2d(m: &[[f32; 4]; 4]) -> Self { + Self::from_cols( + Vec4::from_array(m[0]), + Vec4::from_array(m[1]), + Vec4::from_array(m[2]), + Vec4::from_array(m[3]), + ) + } + + /// Creates a `[[f32; 4]; 4]` 4D array storing data in column major order. + /// If you require data in row major order `transpose` the matrix first. + #[inline] + pub fn to_cols_array_2d(&self) -> [[f32; 4]; 4] { + [ + self.x_axis.to_array(), + self.y_axis.to_array(), + self.z_axis.to_array(), + self.w_axis.to_array(), + ] + } + + /// Creates a 4x4 matrix with its diagonal set to `diagonal` and all other entries set to 0. + #[doc(alias = "scale")] + #[inline] + pub fn from_diagonal(diagonal: Vec4) -> Self { + Self::new( + diagonal.x, 0.0, 0.0, 0.0, 0.0, diagonal.y, 0.0, 0.0, 0.0, 0.0, diagonal.z, 0.0, 0.0, + 0.0, 0.0, diagonal.w, + ) + } + + fn quat_to_axes(rotation: Quat) -> (Vec4, Vec4, Vec4) { + glam_assert!(rotation.is_normalized()); + + let (x, y, z, w) = rotation.into(); + let x2 = x + x; + let y2 = y + y; + let z2 = z + z; + let xx = x * x2; + let xy = x * y2; + let xz = x * z2; + let yy = y * y2; + let yz = y * z2; + let zz = z * z2; + let wx = w * x2; + let wy = w * y2; + let wz = w * z2; + + let x_axis = Vec4::new(1.0 - (yy + zz), xy + wz, xz - wy, 0.0); + let y_axis = Vec4::new(xy - wz, 1.0 - (xx + zz), yz + wx, 0.0); + let z_axis = Vec4::new(xz + wy, yz - wx, 1.0 - (xx + yy), 0.0); + (x_axis, y_axis, z_axis) + } + + /// Creates an affine transformation matrix from the given 3D `scale`, `rotation` and + /// `translation`. + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + /// + /// # Panics + /// + /// Will panic if `rotation` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn from_scale_rotation_translation(scale: Vec3, rotation: Quat, translation: Vec3) -> Self { + let (x_axis, y_axis, z_axis) = Self::quat_to_axes(rotation); + Self::from_cols( + x_axis.mul(scale.x), + y_axis.mul(scale.y), + z_axis.mul(scale.z), + Vec4::from((translation, 1.0)), + ) + } + + /// Creates an affine transformation matrix from the given 3D `translation`. + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + /// + /// # Panics + /// + /// Will panic if `rotation` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn from_rotation_translation(rotation: Quat, translation: Vec3) -> Self { + let (x_axis, y_axis, z_axis) = Self::quat_to_axes(rotation); + Self::from_cols(x_axis, y_axis, z_axis, Vec4::from((translation, 1.0))) + } + + /// Extracts `scale`, `rotation` and `translation` from `self`. The input matrix is + /// expected to be a 3D affine transformation matrix otherwise the output will be invalid. + /// + /// # Panics + /// + /// Will panic if the determinant of `self` is zero or if the resulting scale vector + /// contains any zero elements when `glam_assert` is enabled. + #[inline] + pub fn to_scale_rotation_translation(&self) -> (Vec3, Quat, Vec3) { + let det = self.determinant(); + glam_assert!(det != 0.0); + + let scale = Vec3::new( + self.x_axis.length() * det.signum(), + self.y_axis.length(), + self.z_axis.length(), + ); + + glam_assert!(scale.cmpne(Vec3::ZERO).all()); + + let inv_scale = scale.recip(); + + let rotation = Quat::from_rotation_axes( + self.x_axis.mul(inv_scale.x).xyz(), + self.y_axis.mul(inv_scale.y).xyz(), + self.z_axis.mul(inv_scale.z).xyz(), + ); + + let translation = self.w_axis.xyz(); + + (scale, rotation, translation) + } + + /// Creates an affine transformation matrix from the given `rotation` quaternion. + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + /// + /// # Panics + /// + /// Will panic if `rotation` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn from_quat(rotation: Quat) -> Self { + let (x_axis, y_axis, z_axis) = Self::quat_to_axes(rotation); + Self::from_cols(x_axis, y_axis, z_axis, Vec4::W) + } + + /// Creates an affine transformation matrix from the given 3x3 linear transformation + /// matrix. + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + #[inline] + pub fn from_mat3(m: Mat3) -> Self { + Self::from_cols( + Vec4::from((m.x_axis, 0.0)), + Vec4::from((m.y_axis, 0.0)), + Vec4::from((m.z_axis, 0.0)), + Vec4::W, + ) + } + + /// Creates an affine transformation matrix from the given 3D `translation`. + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + #[inline] + pub fn from_translation(translation: Vec3) -> Self { + Self::from_cols( + Vec4::X, + Vec4::Y, + Vec4::Z, + Vec4::new(translation.x, translation.y, translation.z, 1.0), + ) + } + + /// Creates an affine transformation matrix containing a 3D rotation around a normalized + /// rotation `axis` of `angle` (in radians). + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + /// + /// # Panics + /// + /// Will panic if `axis` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn from_axis_angle(axis: Vec3, angle: f32) -> Self { + glam_assert!(axis.is_normalized()); + + let (sin, cos) = angle.sin_cos(); + let axis_sin = axis.mul(sin); + let axis_sq = axis.mul(axis); + let omc = 1.0 - cos; + let xyomc = axis.x * axis.y * omc; + let xzomc = axis.x * axis.z * omc; + let yzomc = axis.y * axis.z * omc; + Self::from_cols( + Vec4::new( + axis_sq.x * omc + cos, + xyomc + axis_sin.z, + xzomc - axis_sin.y, + 0.0, + ), + Vec4::new( + xyomc - axis_sin.z, + axis_sq.y * omc + cos, + yzomc + axis_sin.x, + 0.0, + ), + Vec4::new( + xzomc + axis_sin.y, + yzomc - axis_sin.x, + axis_sq.z * omc + cos, + 0.0, + ), + Vec4::W, + ) + } + + #[inline] + /// Creates a affine transformation matrix containing a rotation from the given euler + /// rotation sequence and angles (in radians). + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + pub fn from_euler(order: EulerRot, a: f32, b: f32, c: f32) -> Self { + let quat = Quat::from_euler(order, a, b, c); + Self::from_quat(quat) + } + + /// Creates an affine transformation matrix containing a 3D rotation around the x axis of + /// `angle` (in radians). + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + #[inline] + pub fn from_rotation_x(angle: f32) -> Self { + let (sina, cosa) = angle.sin_cos(); + Self::from_cols( + Vec4::X, + Vec4::new(0.0, cosa, sina, 0.0), + Vec4::new(0.0, -sina, cosa, 0.0), + Vec4::W, + ) + } + + /// Creates an affine transformation matrix containing a 3D rotation around the y axis of + /// `angle` (in radians). + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + #[inline] + pub fn from_rotation_y(angle: f32) -> Self { + let (sina, cosa) = angle.sin_cos(); + Self::from_cols( + Vec4::new(cosa, 0.0, -sina, 0.0), + Vec4::Y, + Vec4::new(sina, 0.0, cosa, 0.0), + Vec4::W, + ) + } + + /// Creates an affine transformation matrix containing a 3D rotation around the z axis of + /// `angle` (in radians). + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + #[inline] + pub fn from_rotation_z(angle: f32) -> Self { + let (sina, cosa) = angle.sin_cos(); + Self::from_cols( + Vec4::new(cosa, sina, 0.0, 0.0), + Vec4::new(-sina, cosa, 0.0, 0.0), + Vec4::Z, + Vec4::W, + ) + } + + /// Creates an affine transformation matrix containing the given 3D non-uniform `scale`. + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + /// + /// # Panics + /// + /// Will panic if all elements of `scale` are zero when `glam_assert` is enabled. + #[inline] + pub fn from_scale(scale: Vec3) -> Self { + // Do not panic as long as any component is non-zero + glam_assert!(scale.cmpne(Vec3::ZERO).any()); + + Self::from_cols( + Vec4::new(scale.x, 0.0, 0.0, 0.0), + Vec4::new(0.0, scale.y, 0.0, 0.0), + Vec4::new(0.0, 0.0, scale.z, 0.0), + Vec4::W, + ) + } + + /// Creates a 4x4 matrix from the first 16 values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 16 elements long. + #[inline] + pub const fn from_cols_slice(slice: &[f32]) -> Self { + Self::new( + slice[0], slice[1], slice[2], slice[3], slice[4], slice[5], slice[6], slice[7], + slice[8], slice[9], slice[10], slice[11], slice[12], slice[13], slice[14], slice[15], + ) + } + + /// Writes the columns of `self` to the first 16 elements in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 16 elements long. + #[inline] + pub fn write_cols_to_slice(self, slice: &mut [f32]) { + slice[0] = self.x_axis.x; + slice[1] = self.x_axis.y; + slice[2] = self.x_axis.z; + slice[3] = self.x_axis.w; + slice[4] = self.y_axis.x; + slice[5] = self.y_axis.y; + slice[6] = self.y_axis.z; + slice[7] = self.y_axis.w; + slice[8] = self.z_axis.x; + slice[9] = self.z_axis.y; + slice[10] = self.z_axis.z; + slice[11] = self.z_axis.w; + slice[12] = self.w_axis.x; + slice[13] = self.w_axis.y; + slice[14] = self.w_axis.z; + slice[15] = self.w_axis.w; + } + + /// Returns the matrix column for the given `index`. + /// + /// # Panics + /// + /// Panics if `index` is greater than 3. + #[inline] + pub fn col(&self, index: usize) -> Vec4 { + match index { + 0 => self.x_axis, + 1 => self.y_axis, + 2 => self.z_axis, + 3 => self.w_axis, + _ => panic!("index out of bounds"), + } + } + + /// Returns a mutable reference to the matrix column for the given `index`. + /// + /// # Panics + /// + /// Panics if `index` is greater than 3. + #[inline] + pub fn col_mut(&mut self, index: usize) -> &mut Vec4 { + match index { + 0 => &mut self.x_axis, + 1 => &mut self.y_axis, + 2 => &mut self.z_axis, + 3 => &mut self.w_axis, + _ => panic!("index out of bounds"), + } + } + + /// Returns the matrix row for the given `index`. + /// + /// # Panics + /// + /// Panics if `index` is greater than 3. + #[inline] + pub fn row(&self, index: usize) -> Vec4 { + match index { + 0 => Vec4::new(self.x_axis.x, self.y_axis.x, self.z_axis.x, self.w_axis.x), + 1 => Vec4::new(self.x_axis.y, self.y_axis.y, self.z_axis.y, self.w_axis.y), + 2 => Vec4::new(self.x_axis.z, self.y_axis.z, self.z_axis.z, self.w_axis.z), + 3 => Vec4::new(self.x_axis.w, self.y_axis.w, self.z_axis.w, self.w_axis.w), + _ => panic!("index out of bounds"), + } + } + + /// Returns `true` if, and only if, all elements are finite. + /// If any element is either `NaN`, positive or negative infinity, this will return `false`. + #[inline] + pub fn is_finite(&self) -> bool { + self.x_axis.is_finite() + && self.y_axis.is_finite() + && self.z_axis.is_finite() + && self.w_axis.is_finite() + } + + /// Returns `true` if any elements are `NaN`. + #[inline] + pub fn is_nan(&self) -> bool { + self.x_axis.is_nan() || self.y_axis.is_nan() || self.z_axis.is_nan() || self.w_axis.is_nan() + } + + /// Returns the transpose of `self`. + #[must_use] + #[inline] + pub fn transpose(&self) -> Self { + Self { + x_axis: Vec4::new(self.x_axis.x, self.y_axis.x, self.z_axis.x, self.w_axis.x), + y_axis: Vec4::new(self.x_axis.y, self.y_axis.y, self.z_axis.y, self.w_axis.y), + z_axis: Vec4::new(self.x_axis.z, self.y_axis.z, self.z_axis.z, self.w_axis.z), + w_axis: Vec4::new(self.x_axis.w, self.y_axis.w, self.z_axis.w, self.w_axis.w), + } + } + + /// Returns the determinant of `self`. + pub fn determinant(&self) -> f32 { + let (m00, m01, m02, m03) = self.x_axis.into(); + let (m10, m11, m12, m13) = self.y_axis.into(); + let (m20, m21, m22, m23) = self.z_axis.into(); + let (m30, m31, m32, m33) = self.w_axis.into(); + + 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) + } + + /// Returns the inverse of `self`. + /// + /// If the matrix is not invertible the returned matrix will be invalid. + /// + /// # Panics + /// + /// Will panic if the determinant of `self` is zero when `glam_assert` is enabled. + #[must_use] + pub fn inverse(&self) -> Self { + let (m00, m01, m02, m03) = self.x_axis.into(); + let (m10, m11, m12, m13) = self.y_axis.into(); + let (m20, m21, m22, m23) = self.z_axis.into(); + let (m30, m31, m32, m33) = self.w_axis.into(); + + let coef00 = m22 * m33 - m32 * m23; + let coef02 = m12 * m33 - m32 * m13; + let coef03 = m12 * m23 - m22 * m13; + + let coef04 = m21 * m33 - m31 * m23; + let coef06 = m11 * m33 - m31 * m13; + let coef07 = m11 * m23 - m21 * m13; + + let coef08 = m21 * m32 - m31 * m22; + let coef10 = m11 * m32 - m31 * m12; + let coef11 = m11 * m22 - m21 * m12; + + let coef12 = m20 * m33 - m30 * m23; + let coef14 = m10 * m33 - m30 * m13; + let coef15 = m10 * m23 - m20 * m13; + + let coef16 = m20 * m32 - m30 * m22; + let coef18 = m10 * m32 - m30 * m12; + let coef19 = m10 * m22 - m20 * m12; + + let coef20 = m20 * m31 - m30 * m21; + let coef22 = m10 * m31 - m30 * m11; + let coef23 = m10 * m21 - m20 * m11; + + let fac0 = Vec4::new(coef00, coef00, coef02, coef03); + let fac1 = Vec4::new(coef04, coef04, coef06, coef07); + let fac2 = Vec4::new(coef08, coef08, coef10, coef11); + let fac3 = Vec4::new(coef12, coef12, coef14, coef15); + let fac4 = Vec4::new(coef16, coef16, coef18, coef19); + let fac5 = Vec4::new(coef20, coef20, coef22, coef23); + + let vec0 = Vec4::new(m10, m00, m00, m00); + let vec1 = Vec4::new(m11, m01, m01, m01); + let vec2 = Vec4::new(m12, m02, m02, m02); + let vec3 = Vec4::new(m13, m03, m03, m03); + + let inv0 = vec1.mul(fac0).sub(vec2.mul(fac1)).add(vec3.mul(fac2)); + let inv1 = vec0.mul(fac0).sub(vec2.mul(fac3)).add(vec3.mul(fac4)); + let inv2 = vec0.mul(fac1).sub(vec1.mul(fac3)).add(vec3.mul(fac5)); + let inv3 = vec0.mul(fac2).sub(vec1.mul(fac4)).add(vec2.mul(fac5)); + + let sign_a = Vec4::new(1.0, -1.0, 1.0, -1.0); + let sign_b = Vec4::new(-1.0, 1.0, -1.0, 1.0); + + let inverse = Self::from_cols( + inv0.mul(sign_a), + inv1.mul(sign_b), + inv2.mul(sign_a), + inv3.mul(sign_b), + ); + + let col0 = Vec4::new( + inverse.x_axis.x, + inverse.y_axis.x, + inverse.z_axis.x, + inverse.w_axis.x, + ); + + let dot0 = self.x_axis.mul(col0); + let dot1 = dot0.x + dot0.y + dot0.z + dot0.w; + + glam_assert!(dot1 != 0.0); + + let rcp_det = dot1.recip(); + inverse.mul(rcp_det) + } + + #[inline] + fn look_to_lh(eye: Vec3, dir: Vec3, up: Vec3) -> Self { + let f = dir.normalize(); + let s = up.cross(f).normalize(); + let u = f.cross(s); + Self::from_cols( + Vec4::new(s.x, u.x, f.x, 0.0), + Vec4::new(s.y, u.y, f.y, 0.0), + Vec4::new(s.z, u.z, f.z, 0.0), + Vec4::new(-s.dot(eye), -u.dot(eye), -f.dot(eye), 1.0), + ) + } + + /// Creates a left-handed view matrix using a camera position, an up direction, and a focal + /// point. + /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=forward`. + /// + /// # Panics + /// + /// Will panic if `up` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn look_at_lh(eye: Vec3, center: Vec3, up: Vec3) -> Self { + glam_assert!(up.is_normalized()); + Self::look_to_lh(eye, center.sub(eye), up) + } + + /// Creates a right-handed view matrix using a camera position, an up direction, and a focal + /// point. + /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=back`. + /// + /// # Panics + /// + /// Will panic if `up` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn look_at_rh(eye: Vec3, center: Vec3, up: Vec3) -> Self { + glam_assert!(up.is_normalized()); + Self::look_to_lh(eye, eye.sub(center), up) + } + + /// Creates a right-handed perspective projection matrix with [-1,1] depth range. + /// This is the same as the OpenGL `gluPerspective` function. + /// See + #[inline] + pub fn perspective_rh_gl( + fov_y_radians: f32, + aspect_ratio: f32, + z_near: f32, + z_far: f32, + ) -> Self { + let inv_length = 1.0 / (z_near - z_far); + let f = 1.0 / (0.5 * fov_y_radians).tan(); + let a = f / aspect_ratio; + let b = (z_near + z_far) * inv_length; + let c = (2.0 * z_near * z_far) * inv_length; + Self::from_cols( + Vec4::new(a, 0.0, 0.0, 0.0), + Vec4::new(0.0, f, 0.0, 0.0), + Vec4::new(0.0, 0.0, b, -1.0), + Vec4::new(0.0, 0.0, c, 0.0), + ) + } + + /// Creates a left-handed perspective projection matrix with `[0,1]` depth range. + /// + /// # Panics + /// + /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is + /// enabled. + #[inline] + pub fn perspective_lh(fov_y_radians: f32, aspect_ratio: f32, z_near: f32, z_far: f32) -> Self { + glam_assert!(z_near > 0.0 && z_far > 0.0); + let (sin_fov, cos_fov) = (0.5 * fov_y_radians).sin_cos(); + let h = cos_fov / sin_fov; + let w = h / aspect_ratio; + let r = z_far / (z_far - z_near); + Self::from_cols( + Vec4::new(w, 0.0, 0.0, 0.0), + Vec4::new(0.0, h, 0.0, 0.0), + Vec4::new(0.0, 0.0, r, 1.0), + Vec4::new(0.0, 0.0, -r * z_near, 0.0), + ) + } + + /// Creates a right-handed perspective projection matrix with `[0,1]` depth range. + /// + /// # Panics + /// + /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is + /// enabled. + #[inline] + pub fn perspective_rh(fov_y_radians: f32, aspect_ratio: f32, z_near: f32, z_far: f32) -> Self { + glam_assert!(z_near > 0.0 && z_far > 0.0); + let (sin_fov, cos_fov) = (0.5 * fov_y_radians).sin_cos(); + let h = cos_fov / sin_fov; + let w = h / aspect_ratio; + let r = z_far / (z_near - z_far); + Self::from_cols( + Vec4::new(w, 0.0, 0.0, 0.0), + Vec4::new(0.0, h, 0.0, 0.0), + Vec4::new(0.0, 0.0, r, -1.0), + Vec4::new(0.0, 0.0, r * z_near, 0.0), + ) + } + + /// Creates an infinite left-handed perspective projection matrix with `[0,1]` depth range. + /// + /// # Panics + /// + /// Will panic if `z_near` is less than or equal to zero when `glam_assert` is enabled. + #[inline] + pub fn perspective_infinite_lh(fov_y_radians: f32, aspect_ratio: f32, z_near: f32) -> Self { + glam_assert!(z_near > 0.0); + let (sin_fov, cos_fov) = (0.5 * fov_y_radians).sin_cos(); + let h = cos_fov / sin_fov; + let w = h / aspect_ratio; + Self::from_cols( + Vec4::new(w, 0.0, 0.0, 0.0), + Vec4::new(0.0, h, 0.0, 0.0), + Vec4::new(0.0, 0.0, 1.0, 1.0), + Vec4::new(0.0, 0.0, -z_near, 0.0), + ) + } + + /// Creates an infinite left-handed perspective projection matrix with `[0,1]` depth range. + /// + /// # Panics + /// + /// Will panic if `z_near` is less than or equal to zero when `glam_assert` is enabled. + #[inline] + pub fn perspective_infinite_reverse_lh( + fov_y_radians: f32, + aspect_ratio: f32, + z_near: f32, + ) -> Self { + glam_assert!(z_near > 0.0); + let (sin_fov, cos_fov) = (0.5 * fov_y_radians).sin_cos(); + let h = cos_fov / sin_fov; + let w = h / aspect_ratio; + Self::from_cols( + Vec4::new(w, 0.0, 0.0, 0.0), + Vec4::new(0.0, h, 0.0, 0.0), + Vec4::new(0.0, 0.0, 0.0, 1.0), + Vec4::new(0.0, 0.0, z_near, 0.0), + ) + } + + /// Creates an infinite right-handed perspective projection matrix with + /// `[0,1]` depth range. + #[inline] + pub fn perspective_infinite_rh(fov_y_radians: f32, aspect_ratio: f32, z_near: f32) -> Self { + glam_assert!(z_near > 0.0); + let f = 1.0 / (0.5 * fov_y_radians).tan(); + Self::from_cols( + Vec4::new(f / aspect_ratio, 0.0, 0.0, 0.0), + Vec4::new(0.0, f, 0.0, 0.0), + Vec4::new(0.0, 0.0, -1.0, -1.0), + Vec4::new(0.0, 0.0, -z_near, 0.0), + ) + } + + /// Creates an infinite reverse right-handed perspective projection matrix + /// with `[0,1]` depth range. + #[inline] + pub fn perspective_infinite_reverse_rh( + fov_y_radians: f32, + aspect_ratio: f32, + z_near: f32, + ) -> Self { + glam_assert!(z_near > 0.0); + let f = 1.0 / (0.5 * fov_y_radians).tan(); + Self::from_cols( + Vec4::new(f / aspect_ratio, 0.0, 0.0, 0.0), + Vec4::new(0.0, f, 0.0, 0.0), + Vec4::new(0.0, 0.0, 0.0, -1.0), + Vec4::new(0.0, 0.0, z_near, 0.0), + ) + } + + /// Creates a right-handed orthographic projection matrix with `[-1,1]` depth + /// range. This is the same as the OpenGL `glOrtho` function in OpenGL. + /// See + /// + #[inline] + pub fn orthographic_rh_gl( + left: f32, + right: f32, + bottom: f32, + top: f32, + near: f32, + far: f32, + ) -> Self { + let a = 2.0 / (right - left); + let b = 2.0 / (top - bottom); + let c = -2.0 / (far - near); + let tx = -(right + left) / (right - left); + let ty = -(top + bottom) / (top - bottom); + let tz = -(far + near) / (far - near); + + Self::from_cols( + Vec4::new(a, 0.0, 0.0, 0.0), + Vec4::new(0.0, b, 0.0, 0.0), + Vec4::new(0.0, 0.0, c, 0.0), + Vec4::new(tx, ty, tz, 1.0), + ) + } + + /// Creates a left-handed orthographic projection matrix with `[0,1]` depth range. + #[inline] + pub fn orthographic_lh( + left: f32, + right: f32, + bottom: f32, + top: f32, + near: f32, + far: f32, + ) -> Self { + let rcp_width = 1.0 / (right - left); + let rcp_height = 1.0 / (top - bottom); + let r = 1.0 / (far - near); + Self::from_cols( + Vec4::new(rcp_width + rcp_width, 0.0, 0.0, 0.0), + Vec4::new(0.0, rcp_height + rcp_height, 0.0, 0.0), + Vec4::new(0.0, 0.0, r, 0.0), + Vec4::new( + -(left + right) * rcp_width, + -(top + bottom) * rcp_height, + -r * near, + 1.0, + ), + ) + } + + /// Creates a right-handed orthographic projection matrix with `[0,1]` depth range. + #[inline] + pub fn orthographic_rh( + left: f32, + right: f32, + bottom: f32, + top: f32, + near: f32, + far: f32, + ) -> Self { + let rcp_width = 1.0 / (right - left); + let rcp_height = 1.0 / (top - bottom); + let r = 1.0 / (near - far); + Self::from_cols( + Vec4::new(rcp_width + rcp_width, 0.0, 0.0, 0.0), + Vec4::new(0.0, rcp_height + rcp_height, 0.0, 0.0), + Vec4::new(0.0, 0.0, r, 0.0), + Vec4::new( + -(left + right) * rcp_width, + -(top + bottom) * rcp_height, + r * near, + 1.0, + ), + ) + } + + /// Transforms the given 3D vector as a point, applying perspective correction. + /// + /// This is the equivalent of multiplying the 3D vector as a 4D vector where `w` is `1.0`. + /// The perspective divide is performed meaning the resulting 3D vector is divided by `w`. + /// + /// This method assumes that `self` contains a projective transform. + #[inline] + pub fn project_point3(&self, rhs: Vec3) -> Vec3 { + let mut res = self.x_axis.mul(rhs.x); + res = self.y_axis.mul(rhs.y).add(res); + res = self.z_axis.mul(rhs.z).add(res); + res = self.w_axis.add(res); + res = res.mul(res.wwww().recip()); + res.xyz() + } + + /// Transforms the given 3D vector as a point. + /// + /// This is the equivalent of multiplying the 3D vector as a 4D vector where `w` is + /// `1.0`. + /// + /// This method assumes that `self` contains a valid affine transform. It does not perform + /// a persective divide, if `self` contains a perspective transform, or if you are unsure, + /// the [`Self::project_point3()`] method should be used instead. + /// + /// # Panics + /// + /// Will panic if the 3rd row of `self` is not `(0, 0, 0, 1)` when `glam_assert` is enabled. + #[inline] + pub fn transform_point3(&self, rhs: Vec3) -> Vec3 { + glam_assert!(self.row(3) == Vec4::W); + let mut res = self.x_axis.mul(rhs.x); + res = self.y_axis.mul(rhs.y).add(res); + res = self.z_axis.mul(rhs.z).add(res); + res = self.w_axis.add(res); + res.xyz() + } + + /// Transforms the give 3D vector as a direction. + /// + /// This is the equivalent of multiplying the 3D vector as a 4D vector where `w` is + /// `0.0`. + /// + /// This method assumes that `self` contains a valid affine transform. + /// + /// # Panics + /// + /// Will panic if the 3rd row of `self` is not `(0, 0, 0, 1)` when `glam_assert` is enabled. + #[inline] + pub fn transform_vector3(&self, rhs: Vec3) -> Vec3 { + glam_assert!(self.row(3) == Vec4::W); + let mut res = self.x_axis.mul(rhs.x); + res = self.y_axis.mul(rhs.y).add(res); + res = self.z_axis.mul(rhs.z).add(res); + res.xyz() + } + + /// Transforms the given `Vec3A` as 3D point. + /// + /// This is the equivalent of multiplying the `Vec3A` as a 4D vector where `w` is `1.0`. + #[inline] + pub fn transform_point3a(&self, rhs: Vec3A) -> Vec3A { + self.transform_point3(rhs.into()).into() + } + + /// Transforms the give `Vec3A` as 3D vector. + /// + /// This is the equivalent of multiplying the `Vec3A` as a 4D vector where `w` is `0.0`. + #[inline] + pub fn transform_vector3a(&self, rhs: Vec3A) -> Vec3A { + self.transform_vector3(rhs.into()).into() + } + + /// Transforms a 4D vector. + #[inline] + pub fn mul_vec4(&self, rhs: Vec4) -> Vec4 { + let mut res = self.x_axis.mul(rhs.x); + res = res.add(self.y_axis.mul(rhs.y)); + res = res.add(self.z_axis.mul(rhs.z)); + res = res.add(self.w_axis.mul(rhs.w)); + res + } + + /// Multiplies two 4x4 matrices. + #[inline] + pub fn mul_mat4(&self, rhs: &Self) -> Self { + Self::from_cols( + self.mul(rhs.x_axis), + self.mul(rhs.y_axis), + self.mul(rhs.z_axis), + self.mul(rhs.w_axis), + ) + } + + /// Adds two 4x4 matrices. + #[inline] + pub fn add_mat4(&self, rhs: &Self) -> Self { + Self::from_cols( + self.x_axis.add(rhs.x_axis), + self.y_axis.add(rhs.y_axis), + self.z_axis.add(rhs.z_axis), + self.w_axis.add(rhs.w_axis), + ) + } + + /// Subtracts two 4x4 matrices. + #[inline] + pub fn sub_mat4(&self, rhs: &Self) -> Self { + Self::from_cols( + self.x_axis.sub(rhs.x_axis), + self.y_axis.sub(rhs.y_axis), + self.z_axis.sub(rhs.z_axis), + self.w_axis.sub(rhs.w_axis), + ) + } + + /// Multiplies a 4x4 matrix by a scalar. + #[inline] + pub fn mul_scalar(&self, rhs: f32) -> Self { + Self::from_cols( + self.x_axis.mul(rhs), + self.y_axis.mul(rhs), + self.z_axis.mul(rhs), + self.w_axis.mul(rhs), + ) + } + + /// Returns true if the absolute difference of all elements between `self` and `rhs` + /// is less than or equal to `max_abs_diff`. + /// + /// This can be used to compare if two matrices contain similar elements. It works best + /// when comparing with a known value. The `max_abs_diff` that should be used used + /// depends on the values being compared against. + /// + /// For more see + /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/). + #[inline] + pub fn abs_diff_eq(&self, rhs: Self, max_abs_diff: f32) -> bool { + self.x_axis.abs_diff_eq(rhs.x_axis, max_abs_diff) + && self.y_axis.abs_diff_eq(rhs.y_axis, max_abs_diff) + && self.z_axis.abs_diff_eq(rhs.z_axis, max_abs_diff) + && self.w_axis.abs_diff_eq(rhs.w_axis, max_abs_diff) + } + + #[inline] + pub fn as_dmat4(&self) -> DMat4 { + DMat4::from_cols( + self.x_axis.as_dvec4(), + self.y_axis.as_dvec4(), + self.z_axis.as_dvec4(), + self.w_axis.as_dvec4(), + ) + } +} + +impl Default for Mat4 { + #[inline] + fn default() -> Self { + Self::IDENTITY + } +} + +impl Add for Mat4 { + type Output = Self; + #[inline] + fn add(self, rhs: Self) -> Self::Output { + self.add_mat4(&rhs) + } +} + +impl AddAssign for Mat4 { + #[inline] + fn add_assign(&mut self, rhs: Self) { + *self = self.add_mat4(&rhs); + } +} + +impl Sub for Mat4 { + type Output = Self; + #[inline] + fn sub(self, rhs: Self) -> Self::Output { + self.sub_mat4(&rhs) + } +} + +impl SubAssign for Mat4 { + #[inline] + fn sub_assign(&mut self, rhs: Self) { + *self = self.sub_mat4(&rhs); + } +} + +impl Neg for Mat4 { + type Output = Self; + #[inline] + fn neg(self) -> Self::Output { + Self::from_cols( + self.x_axis.neg(), + self.y_axis.neg(), + self.z_axis.neg(), + self.w_axis.neg(), + ) + } +} + +impl Mul for Mat4 { + type Output = Self; + #[inline] + fn mul(self, rhs: Self) -> Self::Output { + self.mul_mat4(&rhs) + } +} + +impl MulAssign for Mat4 { + #[inline] + fn mul_assign(&mut self, rhs: Self) { + *self = self.mul_mat4(&rhs); + } +} + +impl Mul for Mat4 { + type Output = Vec4; + #[inline] + fn mul(self, rhs: Vec4) -> Self::Output { + self.mul_vec4(rhs) + } +} + +impl Mul for f32 { + type Output = Mat4; + #[inline] + fn mul(self, rhs: Mat4) -> Self::Output { + rhs.mul_scalar(self) + } +} + +impl Mul for Mat4 { + type Output = Self; + #[inline] + fn mul(self, rhs: f32) -> Self::Output { + self.mul_scalar(rhs) + } +} + +impl MulAssign for Mat4 { + #[inline] + fn mul_assign(&mut self, rhs: f32) { + *self = self.mul_scalar(rhs); + } +} + +impl<'a> Sum<&'a Self> for Mat4 { + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, |a, &b| Self::add(a, b)) + } +} + +impl<'a> Product<&'a Self> for Mat4 { + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::IDENTITY, |a, &b| Self::mul(a, b)) + } +} + +impl PartialEq for Mat4 { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.x_axis.eq(&rhs.x_axis) + && self.y_axis.eq(&rhs.y_axis) + && self.z_axis.eq(&rhs.z_axis) + && self.w_axis.eq(&rhs.w_axis) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsRef<[f32; 16]> for Mat4 { + #[inline] + fn as_ref(&self) -> &[f32; 16] { + unsafe { &*(self as *const Self as *const [f32; 16]) } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsMut<[f32; 16]> for Mat4 { + #[inline] + fn as_mut(&mut self) -> &mut [f32; 16] { + unsafe { &mut *(self as *mut Self as *mut [f32; 16]) } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Debug for Mat4 { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct(stringify!(Mat4)) + .field("x_axis", &self.x_axis) + .field("y_axis", &self.y_axis) + .field("z_axis", &self.z_axis) + .field("w_axis", &self.w_axis) + .finish() + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Display for Mat4 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "[{}, {}, {}, {}]", + self.x_axis, self.y_axis, self.z_axis, self.w_axis + ) + } +} diff --git a/src/f32/scalar/quat.rs b/src/f32/scalar/quat.rs new file mode 100644 index 00000000..4990efed --- /dev/null +++ b/src/f32/scalar/quat.rs @@ -0,0 +1,854 @@ +// Generated from quat.rs template. Edit the template, not the generated file. + +use crate::{ + euler::{EulerFromQuaternion, EulerRot, EulerToQuaternion}, + DQuat, FloatEx, Mat3, Mat4, Vec2, Vec3, Vec3A, Vec4, +}; + +#[cfg(not(feature = "std"))] +use num_traits::Float; + +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::iter::{Product, Sum}; +use core::ops::{Add, Deref, Div, Mul, MulAssign, Neg, Sub}; + +/// Creates a quaternion from `x`, `y`, `z` and `w` values. +/// +/// This should generally not be called manually unless you know what you are doing. Use +/// one of the other constructors instead such as `identity` or `from_axis_angle`. +#[inline] +pub const fn quat(x: f32, y: f32, z: f32, w: f32) -> Quat { + Quat::from_xyzw(x, y, z, w) +} + +/// A quaternion representing an orientation. +/// +/// This quaternion is intended to be of unit length but may denormalize due to +/// floating point "error creep" which can occur when successive quaternion +/// operations are applied. +#[derive(Clone, Copy)] +#[cfg_attr( + not(any(feature = "scalar-math", target_arch = "spirv")), + repr(C, align(16)) +)] +pub struct Quat { + x: f32, + y: f32, + z: f32, + w: f32, +} + +impl Quat { + /// All zeros. + const ZERO: Self = Self::from_array([0.0; 4]); + + /// The identity quaternion. Corresponds to no rotation. + pub const IDENTITY: Self = Self::from_xyzw(0.0, 0.0, 0.0, 1.0); + + /// All NANs. + pub const NAN: Self = Self::from_array([f32::NAN; 4]); + + /// Creates a new rotation quaternion. + /// + /// This should generally not be called manually unless you know what you are doing. + /// Use one of the other constructors instead such as `identity` or `from_axis_angle`. + /// + /// `from_xyzw` is mostly used by unit tests and `serde` deserialization. + /// + /// # Preconditions + /// + /// This function does not check if the input is normalized, it is up to the user to + /// provide normalized input or to normalized the resulting quaternion. + #[inline(always)] + pub const fn from_xyzw(x: f32, y: f32, z: f32, w: f32) -> Self { + Self { x, y, z, w } + } + + /// Creates a rotation quaternion from an array. + /// + /// # Preconditions + /// + /// This function does not check if the input is normalized, it is up to the user to + /// provide normalized input or to normalized the resulting quaternion. + #[inline] + pub const fn from_array(a: [f32; 4]) -> Self { + Self::from_xyzw(a[0], a[1], a[2], a[3]) + } + + /// Creates a new rotation quaternion from a 4D vector. + /// + /// # Preconditions + /// + /// This function does not check if the input is normalized, it is up to the user to + /// provide normalized input or to normalized the resulting quaternion. + #[inline] + pub fn from_vec4(v: Vec4) -> Self { + Self { + x: v.x, + y: v.y, + z: v.z, + w: v.w, + } + } + + /// Creates a rotation quaternion from a slice. + /// + /// # Preconditions + /// + /// This function does not check if the input is normalized, it is up to the user to + /// provide normalized input or to normalized the resulting quaternion. + /// + /// # Panics + /// + /// Panics if `slice` length is less than 4. + #[inline] + pub fn from_slice(slice: &[f32]) -> Self { + Self::from_xyzw(slice[0], slice[1], slice[2], slice[3]) + } + + /// Writes the quaternion to an unaligned slice. + /// + /// # Panics + /// + /// Panics if `slice` length is less than 4. + #[inline] + pub fn write_to_slice(self, slice: &mut [f32]) { + slice[0] = self.x; + slice[1] = self.y; + slice[2] = self.z; + slice[3] = self.w; + } + + /// Create a quaternion for a normalized rotation `axis` and `angle` (in radians). + /// The axis must be normalized (unit-length). + /// + /// # Panics + /// + /// Will panic if `axis` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn from_axis_angle(axis: Vec3, angle: f32) -> Self { + glam_assert!(axis.is_normalized()); + let (s, c) = (angle * 0.5).sin_cos(); + let v = axis * s; + Self::from_xyzw(v.x, v.y, v.z, c) + } + + /// Create a quaternion that rotates `v.length()` radians around `v.normalize()`. + /// + /// `from_scaled_axis(Vec3::ZERO)` results in the identity quaternion. + #[inline] + pub fn from_scaled_axis(v: Vec3) -> Self { + let length = v.length(); + if length == 0.0 { + Self::IDENTITY + } else { + Self::from_axis_angle(v / length, length) + } + } + + /// Creates a quaternion from the `angle` (in radians) around the x axis. + #[inline] + pub fn from_rotation_x(angle: f32) -> Self { + let (s, c) = (angle * 0.5).sin_cos(); + Self::from_xyzw(s, 0.0, 0.0, c) + } + + /// Creates a quaternion from the `angle` (in radians) around the y axis. + #[inline] + pub fn from_rotation_y(angle: f32) -> Self { + let (s, c) = (angle * 0.5).sin_cos(); + Self::from_xyzw(0.0, s, 0.0, c) + } + + /// Creates a quaternion from the `angle` (in radians) around the z axis. + #[inline] + pub fn from_rotation_z(angle: f32) -> Self { + let (s, c) = (angle * 0.5).sin_cos(); + Self::from_xyzw(0.0, 0.0, s, c) + } + + #[inline] + /// Creates a quaternion from the given Euler rotation sequence and the angles (in radians). + pub fn from_euler(euler: EulerRot, a: f32, b: f32, c: f32) -> Self { + euler.new_quat(a, b, c) + } + + /// From the columns of a 3x3 rotation matrix. + #[inline] + pub(crate) fn from_rotation_axes(x_axis: Vec3, y_axis: Vec3, z_axis: Vec3) -> Self { + // Based on https://github.com/microsoft/DirectXMath `XM$quaternionRotationMatrix` + // TODO: sse2 version + let (m00, m01, m02) = x_axis.into(); + let (m10, m11, m12) = y_axis.into(); + let (m20, m21, m22) = z_axis.into(); + if m22 <= 0.0 { + // x^2 + y^2 >= z^2 + w^2 + let dif10 = m11 - m00; + let omm22 = 1.0 - m22; + if dif10 <= 0.0 { + // x^2 >= y^2 + let four_xsq = omm22 - dif10; + let inv4x = 0.5 / four_xsq.sqrt(); + Self::from_xyzw( + four_xsq * inv4x, + (m01 + m10) * inv4x, + (m02 + m20) * inv4x, + (m12 - m21) * inv4x, + ) + } else { + // y^2 >= x^2 + let four_ysq = omm22 + dif10; + let inv4y = 0.5 / four_ysq.sqrt(); + Self::from_xyzw( + (m01 + m10) * inv4y, + four_ysq * inv4y, + (m12 + m21) * inv4y, + (m20 - m02) * inv4y, + ) + } + } else { + // z^2 + w^2 >= x^2 + y^2 + let sum10 = m11 + m00; + let opm22 = 1.0 + m22; + if sum10 <= 0.0 { + // z^2 >= w^2 + let four_zsq = opm22 - sum10; + let inv4z = 0.5 / four_zsq.sqrt(); + Self::from_xyzw( + (m02 + m20) * inv4z, + (m12 + m21) * inv4z, + four_zsq * inv4z, + (m01 - m10) * inv4z, + ) + } else { + // w^2 >= z^2 + let four_wsq = opm22 + sum10; + let inv4w = 0.5 / four_wsq.sqrt(); + Self::from_xyzw( + (m12 - m21) * inv4w, + (m20 - m02) * inv4w, + (m01 - m10) * inv4w, + four_wsq * inv4w, + ) + } + } + } + + /// Creates a quaternion from a 3x3 rotation matrix. + #[inline] + pub fn from_mat3(mat: &Mat3) -> Self { + Self::from_rotation_axes(mat.x_axis, mat.y_axis, mat.z_axis) + } + + /// Creates a quaternion from a 3x3 rotation matrix inside a homogeneous 4x4 matrix. + #[inline] + pub fn from_mat4(mat: &Mat4) -> Self { + Self::from_rotation_axes( + mat.x_axis.truncate(), + mat.y_axis.truncate(), + mat.z_axis.truncate(), + ) + } + + /// Gets the minimal rotation for transforming `from` to `to`. The rotation is in the + /// plane spanned by the two vectors. Will rotate at most 180 degrees. + /// + /// The input vectors must be normalized (unit-length). + /// + /// `from_rotation_arc(from, to) * from ≈ to`. + /// + /// For near-singular cases (from≈to and from≈-to) the current implementation + /// is only accurate to about 0.001 (for `f32`). + /// + /// # Panics + /// + /// Will panic if `from` or `to` are not normalized when `glam_assert` is enabled. + pub fn from_rotation_arc(from: Vec3, to: Vec3) -> Self { + glam_assert!(from.is_normalized()); + glam_assert!(to.is_normalized()); + + const ONE_MINUS_EPS: f32 = 1.0 - 2.0 * core::f32::EPSILON; + let dot = from.dot(to); + if dot > ONE_MINUS_EPS { + // 0° singulary: from ≈ to + Self::IDENTITY + } else if dot < -ONE_MINUS_EPS { + // 180° singulary: from ≈ -to + use core::f32::consts::PI; // half a turn = 𝛕/2 = 180° + Self::from_axis_angle(from.any_orthonormal_vector(), PI) + } else { + let c = from.cross(to); + Self::from_xyzw(c.x, c.y, c.z, 1.0 + dot).normalize() + } + } + + /// Gets the minimal rotation for transforming `from` to either `to` or `-to`. This means + /// that the resulting quaternion will rotate `from` so that it is colinear with `to`. + /// + /// The rotation is in the plane spanned by the two vectors. Will rotate at most 90 + /// degrees. + /// + /// The input vectors must be normalized (unit-length). + /// + /// `to.dot(from_rotation_arc_colinear(from, to) * from).abs() ≈ 1`. + /// + /// # Panics + /// + /// Will panic if `from` or `to` are not normalized when `glam_assert` is enabled. + #[inline] + pub fn from_rotation_arc_colinear(from: Vec3, to: Vec3) -> Self { + if from.dot(to) < 0.0 { + Self::from_rotation_arc(from, -to) + } else { + Self::from_rotation_arc(from, to) + } + } + + /// Gets the minimal rotation for transforming `from` to `to`. The resulting rotation is + /// around the z axis. Will rotate at most 180 degrees. + /// + /// The input vectors must be normalized (unit-length). + /// + /// `from_rotation_arc_2d(from, to) * from ≈ to`. + /// + /// For near-singular cases (from≈to and from≈-to) the current implementation + /// is only accurate to about 0.001 (for `f32`). + /// + /// # Panics + /// + /// Will panic if `from` or `to` are not normalized when `glam_assert` is enabled. + pub fn from_rotation_arc_2d(from: Vec2, to: Vec2) -> Self { + glam_assert!(from.is_normalized()); + glam_assert!(to.is_normalized()); + + const ONE_MINUS_EPSILON: f32 = 1.0 - 2.0 * core::f32::EPSILON; + let dot = from.dot(to); + if dot > ONE_MINUS_EPSILON { + // 0° singulary: from ≈ to + Self::IDENTITY + } else if dot < -ONE_MINUS_EPSILON { + // 180° singulary: from ≈ -to + const COS_FRAC_PI_2: f32 = 0.0; + const SIN_FRAC_PI_2: f32 = 1.0; + // rotation around z by PI radians + Self::from_xyzw(0.0, 0.0, SIN_FRAC_PI_2, COS_FRAC_PI_2) + } else { + // vector3 cross where z=0 + let z = from.x * to.y - to.x * from.y; + let w = 1.0 + dot; + // calculate length with x=0 and y=0 to normalize + let len_rcp = 1.0 / (z * z + w * w).sqrt(); + Self::from_xyzw(0.0, 0.0, z * len_rcp, w * len_rcp) + } + } + + /// Returns the rotation axis and angle (in radians) of `self`. + #[inline] + pub fn to_axis_angle(self) -> (Vec3, f32) { + const EPSILON: f32 = 1.0e-8; + const EPSILON_SQUARED: f32 = EPSILON * EPSILON; + let w = self.w; + let angle = w.acos_approx() * 2.0; + let scale_sq = f32::max(1.0 - w * w, 0.0); + if scale_sq >= EPSILON_SQUARED { + ( + Vec3::new(self.x, self.y, self.z) * scale_sq.sqrt().recip(), + angle, + ) + } else { + (Vec3::X, angle) + } + } + + /// Returns the rotation axis scaled by the rotation in radians. + #[inline] + pub fn to_scaled_axis(self) -> Vec3 { + let (axis, angle) = self.to_axis_angle(); + axis * angle + } + + /// Returns the rotation angles for the given euler rotation sequence. + #[inline] + pub fn to_euler(self, euler: EulerRot) -> (f32, f32, f32) { + euler.convert_quat(self) + } + + /// `[x, y, z, w]` + #[inline] + pub fn to_array(&self) -> [f32; 4] { + [self.x, self.y, self.z, self.w] + } + + /// Returns the vector part of the quaternion. + #[inline] + pub fn xyz(self) -> Vec3 { + Vec3::new(self.x, self.y, self.z) + } + + /// Returns the quaternion conjugate of `self`. For a unit quaternion the + /// conjugate is also the inverse. + #[must_use] + #[inline] + pub fn conjugate(self) -> Self { + Self { + x: -self.x, + y: -self.y, + z: -self.z, + w: self.w, + } + } + + /// Returns the inverse of a normalized quaternion. + /// + /// Typically quaternion inverse returns the conjugate of a normalized quaternion. + /// Because `self` is assumed to already be unit length this method *does not* normalize + /// before returning the conjugate. + /// + /// # Panics + /// + /// Will panic if `self` is not normalized when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn inverse(self) -> Self { + glam_assert!(self.is_normalized()); + self.conjugate() + } + + /// Computes the dot product of `self` and `rhs`. The dot product is + /// equal to the cosine of the angle between two quaternion rotations. + #[inline] + pub fn dot(self, rhs: Self) -> f32 { + Vec4::from(self).dot(Vec4::from(rhs)) + } + + /// Computes the length of `self`. + #[doc(alias = "magnitude")] + #[inline] + pub fn length(self) -> f32 { + Vec4::from(self).length() + } + + /// Computes the squared length of `self`. + /// + /// This is generally faster than `length()` as it avoids a square + /// root operation. + #[doc(alias = "magnitude2")] + #[inline] + pub fn length_squared(self) -> f32 { + Vec4::from(self).length_squared() + } + + /// Computes `1.0 / length()`. + /// + /// For valid results, `self` must _not_ be of length zero. + #[inline] + pub fn length_recip(self) -> f32 { + Vec4::from(self).length_recip() + } + + /// Returns `self` normalized to length 1.0. + /// + /// For valid results, `self` must _not_ be of length zero. + /// + /// Panics + /// + /// Will panic if `self` is zero length when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn normalize(self) -> Self { + Self::from_vec4(Vec4::from(self).normalize()) + } + + /// Returns `true` if, and only if, all elements are finite. + /// If any element is either `NaN`, positive or negative infinity, this will return `false`. + #[inline] + pub fn is_finite(self) -> bool { + Vec4::from(self).is_finite() + } + + #[inline] + pub fn is_nan(self) -> bool { + Vec4::from(self).is_nan() + } + + /// Returns whether `self` of length `1.0` or not. + /// + /// Uses a precision threshold of `1e-6`. + #[inline] + pub fn is_normalized(self) -> bool { + Vec4::from(self).is_normalized() + } + + #[inline] + pub fn is_near_identity(self) -> bool { + // Based on https://github.com/nfrechette/rtm `rtm::quat_near_identity` + let threshold_angle = 0.002_847_144_6; + // Because of floating point precision, we cannot represent very small rotations. + // The closest f32 to 1.0 that is not 1.0 itself yields: + // 0.99999994.acos() * 2.0 = 0.000690533954 rad + // + // An error threshold of 1.e-6 is used by default. + // (1.0 - 1.e-6).acos() * 2.0 = 0.00284714461 rad + // (1.0 - 1.e-7).acos() * 2.0 = 0.00097656250 rad + // + // We don't really care about the angle value itself, only if it's close to 0. + // This will happen whenever quat.w is close to 1.0. + // If the quat.w is close to -1.0, the angle will be near 2*PI which is close to + // a negative 0 rotation. By forcing quat.w to be positive, we'll end up with + // the shortest path. + let positive_w_angle = self.w.abs().acos_approx() * 2.0; + positive_w_angle < threshold_angle + } + + /// Returns the angle (in radians) for the minimal rotation + /// for transforming this quaternion into another. + /// + /// Both quaternions must be normalized. + /// + /// # Panics + /// + /// Will panic if `self` or `rhs` are not normalized when `glam_assert` is enabled. + #[inline] + pub fn angle_between(self, rhs: Self) -> f32 { + glam_assert!(self.is_normalized() && rhs.is_normalized()); + self.dot(rhs).abs().acos_approx() * 2.0 + } + + /// Returns true if the absolute difference of all elements between `self` and `rhs` + /// is less than or equal to `max_abs_diff`. + /// + /// This can be used to compare if two quaternions contain similar elements. It works + /// best when comparing with a known value. The `max_abs_diff` that should be used used + /// depends on the values being compared against. + /// + /// For more see + /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/). + #[inline] + pub fn abs_diff_eq(self, rhs: Self, max_abs_diff: f32) -> bool { + Vec4::from(self).abs_diff_eq(Vec4::from(rhs), max_abs_diff) + } + + /// Performs a linear interpolation between `self` and `rhs` based on + /// the value `s`. + /// + /// When `s` is `0.0`, the result will be equal to `self`. When `s` + /// is `1.0`, the result will be equal to `rhs`. + /// + /// # Panics + /// + /// Will panic if `self` or `end` are not normalized when `glam_assert` is enabled. + #[inline] + #[doc(alias = "mix")] + pub fn lerp(self, end: Self, s: f32) -> Self { + glam_assert!(self.is_normalized()); + glam_assert!(end.is_normalized()); + + let start = self; + let dot = start.dot(end); + let bias = if dot >= 0.0 { 1.0 } else { -1.0 }; + let interpolated = start.add(end.mul(bias).sub(start).mul(s)); + interpolated.normalize() + } + + /// Performs a spherical linear interpolation between `self` and `end` + /// based on the value `s`. + /// + /// When `s` is `0.0`, the result will be equal to `self`. When `s` + /// is `1.0`, the result will be equal to `end`. + /// + /// # Panics + /// + /// Will panic if `self` or `end` are not normalized when `glam_assert` is enabled. + #[inline] + pub fn slerp(self, mut end: Self, s: f32) -> Self { + // http://number-none.com/product/Understanding%20Slerp,%20Then%20Not%20Using%20It/ + glam_assert!(self.is_normalized()); + glam_assert!(end.is_normalized()); + + const DOT_THRESHOLD: f32 = 0.9995; + + // Note that a rotation can be represented by two quaternions: `q` and + // `-q`. The slerp path between `q` and `end` will be different from the + // path between `-q` and `end`. One path will take the long way around and + // one will take the short way. In order to correct for this, the `dot` + // product between `self` and `end` should be positive. If the `dot` + // product is negative, slerp between `self` and `-end`. + let mut dot = self.dot(end); + if dot < 0.0 { + end = -end; + dot = -dot; + } + + if dot > DOT_THRESHOLD { + // assumes lerp returns a normalized quaternion + self.lerp(end, s) + } else { + let theta = dot.acos_approx(); + + let scale1 = (theta * (1.0 - s)).sin(); + let scale2 = (theta * s).sin(); + let theta_sin = theta.sin(); + + self.mul(scale1).add(end.mul(scale2)).mul(theta_sin.recip()) + } + } + + /// Multiplies a quaternion and a 3D vector, returning the rotated vector. + /// + /// # Panics + /// + /// Will panic if `self` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn mul_vec3(self, rhs: Vec3) -> Vec3 { + glam_assert!(self.is_normalized()); + + let w = self.w; + let b = Vec3::new(self.x, self.y, self.z); + let b2 = b.dot(b); + rhs.mul(w * w - b2) + .add(b.mul(rhs.dot(b) * 2.0)) + .add(b.cross(rhs).mul(w * 2.0)) + } + + /// Multiplies two quaternions. If they each represent a rotation, the result will + /// represent the combined rotation. + /// + /// Note that due to floating point rounding the result may not be perfectly normalized. + /// + /// # Panics + /// + /// Will panic if `self` or `rhs` are not normalized when `glam_assert` is enabled. + #[inline] + pub fn mul_quat(self, rhs: Self) -> Self { + glam_assert!(self.is_normalized()); + glam_assert!(rhs.is_normalized()); + + let (x0, y0, z0, w0) = self.into(); + let (x1, y1, z1, w1) = rhs.into(); + Self::from_xyzw( + w0 * x1 + x0 * w1 + y0 * z1 - z0 * y1, + w0 * y1 - x0 * z1 + y0 * w1 + z0 * x1, + w0 * z1 + x0 * y1 - y0 * x1 + z0 * w1, + w0 * w1 - x0 * x1 - y0 * y1 - z0 * z1, + ) + } + + /// Creates a quaternion from a 3x3 rotation matrix inside a 3D affine transform. + #[inline] + pub fn from_affine3(a: &crate::Affine3A) -> Self { + #[allow(clippy::useless_conversion)] + Self::from_rotation_axes( + a.matrix3.x_axis.into(), + a.matrix3.y_axis.into(), + a.matrix3.z_axis.into(), + ) + } + + /// Multiplies a quaternion and a 3D vector, returning the rotated vector. + #[inline] + pub fn mul_vec3a(self, rhs: Vec3A) -> Vec3A { + self.mul_vec3(rhs.into()).into() + } + + #[inline] + pub fn as_f64(self) -> DQuat { + DQuat::from_xyzw(self.x as f64, self.y as f64, self.z as f64, self.w as f64) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Debug for Quat { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_tuple(stringify!(Quat)) + .field(&self.x) + .field(&self.y) + .field(&self.z) + .field(&self.w) + .finish() + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Display for Quat { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(fmt, "[{}, {}, {}, {}]", self.x, self.y, self.z, self.w) + } +} + +impl Add for Quat { + type Output = Self; + /// Adds two quaternions. + /// + /// The sum is not guaranteed to be normalized. + /// + /// Note that addition is not the same as combining the rotations represented by the + /// two quaternions! That corresponds to multiplication. + #[inline] + fn add(self, rhs: Self) -> Self { + Self::from_vec4(Vec4::from(self) + Vec4::from(rhs)) + } +} + +impl Sub for Quat { + type Output = Self; + /// Subtracts the `rhs` quaternion from `self`. + /// + /// The difference is not guaranteed to be normalized. + #[inline] + fn sub(self, rhs: Self) -> Self { + Self::from_vec4(Vec4::from(self) - Vec4::from(rhs)) + } +} + +impl Mul for Quat { + type Output = Self; + /// Multiplies a quaternion by a scalar value. + /// + /// The product is not guaranteed to be normalized. + #[inline] + fn mul(self, rhs: f32) -> Self { + Self::from_vec4(Vec4::from(self) * rhs) + } +} + +impl Div for Quat { + type Output = Self; + /// Divides a quaternion by a scalar value. + /// The quotient is not guaranteed to be normalized. + #[inline] + fn div(self, rhs: f32) -> Self { + Self::from_vec4(Vec4::from(self) / rhs) + } +} + +impl Mul for Quat { + type Output = Self; + /// Multiplies two quaternions. If they each represent a rotation, the result will + /// represent the combined rotation. + /// + /// Note that due to floating point rounding the result may not be perfectly + /// normalized. + /// + /// # Panics + /// + /// Will panic if `self` or `rhs` are not normalized when `glam_assert` is enabled. + #[inline] + fn mul(self, rhs: Self) -> Self { + self.mul_quat(rhs) + } +} + +impl MulAssign for Quat { + /// Multiplies two quaternions. If they each represent a rotation, the result will + /// represent the combined rotation. + /// + /// Note that due to floating point rounding the result may not be perfectly + /// normalized. + /// + /// # Panics + /// + /// Will panic if `self` or `rhs` are not normalized when `glam_assert` is enabled. + #[inline] + fn mul_assign(&mut self, rhs: Self) { + *self = self.mul_quat(rhs); + } +} + +impl Mul for Quat { + type Output = Vec3; + /// Multiplies a quaternion and a 3D vector, returning the rotated vector. + /// + /// # Panics + /// + /// Will panic if `self` is not normalized when `glam_assert` is enabled. + #[inline] + fn mul(self, rhs: Vec3) -> Self::Output { + self.mul_vec3(rhs) + } +} + +impl Neg for Quat { + type Output = Self; + #[inline] + fn neg(self) -> Self { + self * -1.0 + } +} + +impl Default for Quat { + #[inline] + fn default() -> Self { + Self::IDENTITY + } +} + +impl PartialEq for Quat { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + Vec4::from(*self).eq(&Vec4::from(*rhs)) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsRef<[f32; 4]> for Quat { + #[inline] + fn as_ref(&self) -> &[f32; 4] { + unsafe { &*(self as *const Self as *const [f32; 4]) } + } +} + +impl<'a> Sum<&'a Self> for Quat { + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, |a, &b| Self::add(a, b)) + } +} + +impl<'a> Product<&'a Self> for Quat { + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::IDENTITY, |a, &b| Self::mul(a, b)) + } +} + +impl Mul for Quat { + type Output = Vec3A; + #[inline] + fn mul(self, rhs: Vec3A) -> Self::Output { + self.mul_vec3a(rhs) + } +} + +impl From for Vec4 { + #[inline] + fn from(q: Quat) -> Self { + Self::new(q.x, q.y, q.z, q.w) + } +} + +impl From for (f32, f32, f32, f32) { + #[inline] + fn from(q: Quat) -> Self { + (q.x, q.y, q.z, q.w) + } +} + +impl From for [f32; 4] { + #[inline] + fn from(q: Quat) -> Self { + [q.x, q.y, q.z, q.w] + } +} + +impl Deref for Quat { + type Target = crate::deref::XYZW; + #[inline] + fn deref(&self) -> &Self::Target { + unsafe { &*(self as *const Self).cast() } + } +} diff --git a/src/f32/scalar/vec2.rs b/src/f32/scalar/vec2.rs new file mode 100644 index 00000000..593ef26f --- /dev/null +++ b/src/f32/scalar/vec2.rs @@ -0,0 +1,953 @@ + + + + + + + + + + + + + + + + + + + + + + + + +/// Creates a 2-dimensional vector. +#[inline(always)] +pub fn vec2(x: f32, y: f32) -> Vec2 { + Vec2::new(x, y) +} + + +/// A 2-dimensional vector. +#[derive(Clone, Copy)] +#[cfg_attr(feature = "cuda", repr(C, align(8)))] +#[cfg_attr(not(feature = "cuda"), repr(transparent))] +pub struct Vec2(pub(crate) crate::XY::); + +impl Vec2 { + /// All zeroes. + pub const ZERO: Self = Self(crate::XY::::ZERO); + + /// All ones. + pub const ONE: Self = Self(crate::XY::::ONE); + + + /// `[1, 0]`: a unit-length vector pointing along the positive X axis. + pub const X: Self = Self(crate::XY::::X); + + /// `[0, 1]`: a unit-length vector pointing along the positive Y axis. + pub const Y: Self = Self(crate::XY::::Y); + + /// The unit axes. + pub const AXES: [Self; 2] = [Self::X, Self::Y]; + + /// Creates a new vector. + #[inline(always)] + pub fn new(x: f32, y: f32) -> Self { + Self(Vector2::new(x, y)) + } + + /// Creates a 3D vector from `self` and the given `z` value. + #[inline(always)] + pub fn extend(self, z: f32) -> Vec3 { + Vec3::new(self.x, self.y, z) + } + + /// `[x, y]` + #[inline(always)] + pub fn to_array(&self) -> [f32; 2] { + [self.x, self.y] + } + + + /// Creates a vector with all elements set to `v`. + #[inline(always)] + pub fn splat(v: f32) -> Self { + Self(crate::XY::::splat(v)) + } + + /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use + /// for each element of `self`. + /// + /// A true element in the mask uses the corresponding element from `if_true`, and false + /// uses the element from `if_false`. + #[inline(always)] + pub fn select(mask: BVec2, if_true: Self, if_false: Self) -> Self { + Self(crate::XY::::select(mask.0, if_true.0, if_false.0)) + } + + /// Computes the dot product of `self` and `other`. + #[inline(always)] + pub fn dot(self, other: Self) -> f32 { + FloatVector2::dot(self.0, other.0) + } + + /// Returns a vector containing the minimum values for each element of `self` and `other`. + /// + /// In other words this computes `[self.x.min(other.x), self.y.min(other.y), ..]`. + #[inline(always)] + pub fn min(self, other: Self) -> Self { + Self(self.0.min(other.0)) + } + + /// Returns a vector containing the maximum values for each element of `self` and `other`. + /// + /// In other words this computes `[self.x.max(other.x), self.y.max(other.y), ..]`. + #[inline(always)] + pub fn max(self, other: Self) -> Self { + Self(self.0.max(other.0)) + } + + /// Component-wise clamping of values, similar to [`f32::clamp`]. + /// + /// Each element in `min` must be less-or-equal to the corresponding element in `max`. + /// + /// # Panics + /// + /// Will panic if `min` is greater than `max` when `glam_assert` is enabled. + #[inline(always)] + pub fn clamp(self, min: Self, max: Self) -> Self { + Self(FloatVector2::clamp(self.0, min.0, max.0)) + } + + /// Returns the horizontal minimum of `self`. + /// + /// In other words this computes `min(x, y, ..)`. + #[inline(always)] + pub fn min_element(self) -> f32 { + FloatVector2::min_element(self.0) + } + + /// Returns the horizontal maximum of `self`. + /// + /// In other words this computes `max(x, y, ..)`. + #[inline(always)] + pub fn max_element(self) -> f32 { + FloatVector2::max_element(self.0) + } + + /// Returns a vector mask containing the result of a `==` comparison for each element of + /// `self` and `other`. + /// + /// In other words, this computes `[self.x == other.x, self.y == other.y, ..]` for all + /// elements. + #[inline(always)] + pub fn cmpeq(self, other: Self) -> BVec2 { + BVec2(self.0.cmpeq(other.0)) + } + + /// Returns a vector mask containing the result of a `!=` comparison for each element of + /// `self` and `other`. + /// + /// In other words this computes `[self.x != other.x, self.y != other.y, ..]` for all + /// elements. + #[inline(always)] + pub fn cmpne(self, other: Self) -> BVec2 { + BVec2(self.0.cmpne(other.0)) + } + + /// Returns a vector mask containing the result of a `>=` comparison for each element of + /// `self` and `other`. + /// + /// In other words this computes `[self.x >= other.x, self.y >= other.y, ..]` for all + /// elements. + #[inline(always)] + pub fn cmpge(self, other: Self) -> BVec2 { + BVec2(self.0.cmpge(other.0)) + } + + /// Returns a vector mask containing the result of a `>` comparison for each element of + /// `self` and `other`. + /// + /// In other words this computes `[self.x > other.x, self.y > other.y, ..]` for all + /// elements. + #[inline(always)] + pub fn cmpgt(self, other: Self) -> BVec2 { + BVec2(self.0.cmpgt(other.0)) + } + + /// Returns a vector mask containing the result of a `<=` comparison for each element of + /// `self` and `other`. + /// + /// In other words this computes `[self.x <= other.x, self.y <= other.y, ..]` for all + /// elements. + #[inline(always)] + pub fn cmple(self, other: Self) -> BVec2 { + BVec2(self.0.cmple(other.0)) + } + + /// Returns a vector mask containing the result of a `<` comparison for each element of + /// `self` and `other`. + /// + /// In other words this computes `[self.x < other.x, self.y < other.y, ..]` for all + /// elements. + #[inline(always)] + pub fn cmplt(self, other: Self) -> BVec2 { + BVec2(self.0.cmplt(other.0)) + } + + /// Creates a vector from the first N values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than N elements long. + #[inline(always)] + pub fn from_slice(slice: &[f32]) -> Self { + Self(FloatVector2::from_slice_unaligned(slice)) + } + + /// Writes the elements of `self` to the first 2 elements in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than N elements long. + #[inline(always)] + pub fn write_to_slice(self, slice: &mut [f32]) { + FloatVector2::write_to_slice_unaligned(self.0, slice) + } + + + /// Returns a vector containing the absolute value of each element of `self`. + #[inline(always)] + pub fn abs(self) -> Self { + Self(FloatVector2::abs(self.0)) + } + + /// Returns a vector with elements representing the sign of `self`. + /// + /// - `1.0` if the number is positive, `+0.0` or `INFINITY` + /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` + /// - `NAN` if the number is `NAN` + #[inline(always)] + pub fn signum(self) -> Self { + Self(FloatVector2::signum(self.0)) + } + + + + /// All NAN. + pub const NAN: Self = Self( as crate::core::traits::scalar::NanConstEx>::NAN); + + /// Returns `true` if, and only if, all elements are finite. If any element is either + /// `NaN`, positive or negative infinity, this will return `false`. + #[inline(always)] + pub fn is_finite(self) -> bool { + FloatVector2::is_finite(self.0) + } + + /// Returns `true` if any elements are `NaN`. + #[inline(always)] + pub fn is_nan(self) -> bool { + FloatVector2::is_nan(self.0) + } + + /// Performs `is_nan` on each element of self, returning a vector mask of the results. + /// + /// In other words, this computes `[x.is_nan(), y.is_nan(), z.is_nan(), w.is_nan()]`. + #[inline(always)] + pub fn is_nan_mask(self) -> BVec2 { + BVec2(FloatVector2::is_nan_mask(self.0)) + } + + /// Computes the length of `self`. + #[doc(alias = "magnitude")] + #[inline(always)] + pub fn length(self) -> f32 { + FloatVector2::length(self.0) + } + + /// Computes the squared length of `self`. + /// + /// This is faster than `length()` as it avoids a square root operation. + #[doc(alias = "magnitude2")] + #[inline(always)] + pub fn length_squared(self) -> f32 { + FloatVector2::length_squared(self.0) + } + + /// Computes `1.0 / length()`. + /// + /// For valid results, `self` must _not_ be of length zero. + #[inline(always)] + pub fn length_recip(self) -> f32 { + FloatVector2::length_recip(self.0) + } + + /// Computes the Euclidean distance between two points in space. + #[inline] + pub fn distance(self, other: Self) -> f32 { + (self - other).length() + } + + /// Compute the squared euclidean distance between two points in space. + #[inline] + pub fn distance_squared(self, other: Self) -> f32 { + (self - other).length_squared() + } + + /// Returns `self` normalized to length 1.0. + /// + /// For valid results, `self` must _not_ be of length zero, nor very close to zero. + /// + /// See also [`Self::try_normalize`] and [`Self::normalize_or_zero`]. + /// + /// Panics + /// + /// Will panic if `self` is zero length when `glam_assert` is enabled. + #[must_use] + #[inline(always)] + pub fn normalize(self) -> Self { + Self(FloatVector2::normalize(self.0)) + } + + /// Returns `self` normalized to length 1.0 if possible, else returns `None`. + /// + /// In particular, if the input is zero (or very close to zero), or non-finite, + /// the result of this operation will be `None`. + /// + /// See also [`Self::normalize_or_zero`]. + #[must_use] + #[inline] + pub fn try_normalize(self) -> Option { + let rcp = self.length_recip(); + if rcp.is_finite() && rcp > 0.0 { + Some(self * rcp) + } else { + None + } + } + + /// Returns `self` normalized to length 1.0 if possible, else returns zero. + /// + /// In particular, if the input is zero (or very close to zero), or non-finite, + /// the result of this operation will be zero. + /// + /// See also [`Self::try_normalize`]. + #[must_use] + #[inline] + pub fn normalize_or_zero(self) -> Self { + let rcp = self.length_recip(); + if rcp.is_finite() && rcp > 0.0 { + self * rcp + } else { + Self::ZERO + } + } + + /// Returns whether `self` is length `1.0` or not. + /// + /// Uses a precision threshold of `1e-6`. + #[inline(always)] + pub fn is_normalized(self) -> bool { + FloatVector2::is_normalized(self.0) + } + + /// Returns the vector projection of `self` onto `other`. + /// + /// `other` must be of non-zero length. + /// + /// # Panics + /// + /// Will panic if `other` is zero length when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn project_onto(self, other: Self) -> Self { + let other_len_sq_rcp = other.dot(other).recip(); + glam_assert!(other_len_sq_rcp.is_finite()); + other * self.dot(other) * other_len_sq_rcp + } + + /// Returns the vector rejection of `self` from `other`. + /// + /// The vector rejection is the vector perpendicular to the projection of `self` onto + /// `other`, in other words the result of `self - self.project_onto(other)`. + /// + /// `other` must be of non-zero length. + /// + /// # Panics + /// + /// Will panic if `other` has a length of zero when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn reject_from(self, other: Self) -> Self { + self - self.project_onto(other) + } + + /// Returns the vector projection of `self` onto `other`. + /// + /// `other` must be normalized. + /// + /// # Panics + /// + /// Will panic if `other` is not normalized when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn project_onto_normalized(self, other: Self) -> Self { + glam_assert!(other.is_normalized()); + other * self.dot(other) + } + + /// Returns the vector rejection of `self` from `other`. + /// + /// The vector rejection is the vector perpendicular to the projection of `self` onto + /// `other`, in other words the result of `self - self.project_onto(other)`. + /// + /// `other` must be normalized. + /// + /// # Panics + /// + /// Will panic if `other` is not normalized when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn reject_from_normalized(self, other: Self) -> Self { + self - self.project_onto_normalized(other) + } + + /// Returns a vector containing the nearest integer to a number for each element of `self`. + /// Round half-way cases away from 0.0. + #[inline(always)] + pub fn round(self) -> Self { + Self(FloatVector2::round(self.0)) + } + + /// Returns a vector containing the largest integer less than or equal to a number for each + /// element of `self`. + #[inline(always)] + pub fn floor(self) -> Self { + Self(FloatVector2::floor(self.0)) + } + + /// Returns a vector containing the smallest integer greater than or equal to a number for + /// each element of `self`. + #[inline(always)] + pub fn ceil(self) -> Self { + Self(FloatVector2::ceil(self.0)) + } + + /// Returns a vector containing the fractional part of the vector, e.g. `self - + /// self.floor()`. + /// + /// Note that this is fast but not precise for large numbers. + #[inline(always)] + pub fn fract(self) -> Self { + self - self.floor() + } + + /// Returns a vector containing `e^self` (the exponential function) for each element of + /// `self`. + #[inline(always)] + pub fn exp(self) -> Self { + Self(FloatVector2::exp(self.0)) + } + + /// Returns a vector containing each element of `self` raised to the power of `n`. + #[inline(always)] + pub fn powf(self, n: f32) -> Self { + Self(FloatVector2::powf(self.0, n)) + } + + /// Returns a vector containing the reciprocal `1.0/n` of each element of `self`. + #[inline(always)] + pub fn recip(self) -> Self { + Self(FloatVector2::recip(self.0)) + } + + /// Performs a linear interpolation between `self` and `other` based on the value `s`. + /// + /// When `s` is `0.0`, the result will be equal to `self`. When `s` is `1.0`, the result + /// will be equal to `other`. When `s` is outside of range [0,1], the result is linearly + /// extrapolated. + #[doc(alias = "mix")] + #[inline] + pub fn lerp(self, other: Self, s: f32) -> Self { + self + ((other - self) * s) + } + + /// Returns true if the absolute difference of all elements between `self` and `other` is + /// less than or equal to `max_abs_diff`. + /// + /// This can be used to compare if two vectors contain similar elements. It works best when + /// comparing with a known value. The `max_abs_diff` that should be used used depends on + /// the values being compared against. + /// + /// For more see + /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/). + #[inline(always)] + pub fn abs_diff_eq(self, other: Self, max_abs_diff: f32) -> bool { + FloatVector2::abs_diff_eq(self.0, other.0, max_abs_diff) + } + + /// Returns a vector with a length no less than `min` and no more than `max` + /// + /// # Panics + /// + /// Will panic if `min` is greater than `max` when `glam_assert` is enabled. + #[inline] + pub fn clamp_length(self, min: f32, max: f32) -> Self { + glam_assert!(min <= max); + let length_sq = self.length_squared(); + if length_sq < min * min { + self * (length_sq.sqrt().recip() * min) + } else if length_sq > max * max { + self * (length_sq.sqrt().recip() * max) + } else { + self + } + } + + /// Returns a vector with a length no more than `max` + pub fn clamp_length_max(self, max: f32) -> Self { + let length_sq = self.length_squared(); + if length_sq > max * max { + self * (length_sq.sqrt().recip() * max) + } else { + self + } + } + + /// Returns a vector with a length no less than `min` + pub fn clamp_length_min(self, min: f32) -> Self { + let length_sq = self.length_squared(); + if length_sq < min * min { + self * (length_sq.sqrt().recip() * min) + } else { + self + } + } + + /// Fused multiply-add. Computes `(self * a) + b` element-wise with only one rounding + /// error, yielding a more accurate result than an unfused multiply-add. + /// + /// Using `mul_add` *may* be more performant than an unfused multiply-add if the target + /// architecture has a dedicated fma CPU instruction. However, this is not always true, + /// and will be heavily dependant on designing algorithms with specific target hardware in + /// mind. + #[inline(always)] + pub fn mul_add(self, a: Self, b: Self) -> Self { + Self(FloatVector2::mul_add(self.0, a.0, b.0)) + } + + + /// Creates a 2D vector containing `[angle.cos(), angle.sin()]`. This can be used in + /// conjunction with the `rotate` method, e.g. `Vec2::from_angle(PI).rotate(Vec2::Y)` will + /// create the vector [-1, 0] and rotate `Vec2::Y` around it returning `-Vec2::Y`. + #[inline(always)] + pub fn from_angle(angle: f32) -> Self { + Self(FloatVector2::from_angle(angle)) + } + + /// Returns the angle (in radians) between `self` and `other`. + /// + /// The input vectors do not need to be unit length however they must be non-zero. + #[inline(always)] + pub fn angle_between(self, other: Self) -> f32 { + self.0.angle_between(other.0) + } + + + + + /// Returns a vector that is equal to `self` rotated by 90 degrees. + #[inline(always)] + pub fn perp(self) -> Self { + Self(self.0.perp()) + } + + /// The perpendicular dot product of `self` and `other`. + /// Also known as the wedge product, 2D cross product, and determinant. + #[doc(alias = "wedge")] + #[doc(alias = "cross")] + #[doc(alias = "determinant")] + #[inline(always)] + pub fn perp_dot(self, other: Self) -> f32 { + self.0.perp_dot(other.0) + } + + /// Returns `other` rotated by the angle of `self`. If `self` is normalized, + /// then this just rotation. This is what you usually want. Otherwise, + /// it will be like a rotation with a multiplication by `self`'s length. + #[must_use] + #[inline(always)] + pub fn rotate(self, other: Self) -> Self { + Self(self.0.rotate(other.0)) + } + + + + + + /// Casts all elements of `self` to `f64`. + #[inline(always)] + pub fn as_dvec2(&self) -> DVec2 { + DVec2::new(self.x as f64, self.y as f64) + } + + + + + /// Casts all elements of `self` to `i32`. + #[inline(always)] + pub fn as_ivec2(&self) -> IVec2 { + IVec2::new(self.x as i32, self.y as i32) + } + + + + + /// Casts all elements of `self` to `u32`. + #[inline(always)] + pub fn as_uvec2(&self) -> UVec2 { + UVec2::new(self.x as u32, self.y as u32) + } + + +} + +impl Default for Vec2 { + #[inline(always)] + fn default() -> Self { + Self(crate::XY::::ZERO) + } +} + +impl PartialEq for Vec2 { + #[inline(always)] + fn eq(&self, other: &Self) -> bool { + self.cmpeq(*other).all() + } +} + +impl From for crate::XY:: { + #[inline(always)] + fn from(t: Vec2) -> Self { + t.0 + } +} + +impl From> for Vec2 { + #[inline(always)] + fn from(t: crate::XY::) -> Self { + Self(t) + } +} + +impl Div for Vec2 { + type Output = Self; + #[inline(always)] + fn div(self, other: Vec2) -> Self { + Self(self.0.div(other.0)) + } +} + +impl DivAssign for Vec2 { + #[inline(always)] + fn div_assign(&mut self, other: Vec2) { + self.0 = self.0.div(other.0) + } +} + +impl Div for Vec2 { + type Output = Self; + #[inline(always)] + fn div(self, other: f32) -> Self { + Self(self.0.div_scalar(other)) + } +} + +impl DivAssign for Vec2 { + #[inline(always)] + fn div_assign(&mut self, other: f32) { + self.0 = self.0.div_scalar(other) + } +} + +impl Div for f32 { + type Output = Vec2; + #[inline(always)] + fn div(self, other: Vec2) -> Vec2 { + Vec2(crate::XY::::splat(self).div(other.0)) + } +} + +impl Mul for Vec2 { + type Output = Self; + #[inline(always)] + fn mul(self, other: Vec2) -> Self { + Self(self.0.mul(other.0)) + } +} + +impl MulAssign for Vec2 { + #[inline(always)] + fn mul_assign(&mut self, other: Vec2) { + self.0 = self.0.mul(other.0) + } +} + +impl Mul for Vec2 { + type Output = Self; + #[inline(always)] + fn mul(self, other: f32) -> Self { + Self(self.0.mul_scalar(other)) + } +} + +impl MulAssign for Vec2 { + #[inline(always)] + fn mul_assign(&mut self, other: f32) { + self.0 = self.0.mul_scalar(other) + } +} + +impl Mul for f32 { + type Output = Vec2; + #[inline(always)] + fn mul(self, other: Vec2) -> Vec2 { + Vec2(crate::XY::::splat(self).mul(other.0)) + } +} + +impl Add for Vec2 { + type Output = Self; + #[inline(always)] + fn add(self, other: Vec2) -> Self { + Self(self.0.add(other.0)) + } +} + +impl AddAssign for Vec2 { + #[inline(always)] + fn add_assign(&mut self, other: Vec2) { + self.0 = self.0.add(other.0) + } +} + +impl Add for Vec2 { + type Output = Self; + #[inline(always)] + fn add(self, other: f32) -> Self { + Self(self.0.add_scalar(other)) + } +} + +impl AddAssign for Vec2 { + #[inline(always)] + fn add_assign(&mut self, other: f32) { + self.0 = self.0.add_scalar(other) + } +} + +impl Add for f32 { + type Output = Vec2; + #[inline(always)] + fn add(self, other: Vec2) -> Vec2 { + Vec2(crate::XY::::splat(self).add(other.0)) + } +} + +impl Sub for Vec2 { + type Output = Self; + #[inline(always)] + fn sub(self, other: Vec2) -> Self { + Self(self.0.sub(other.0)) + } +} + +impl SubAssign for Vec2 { + #[inline(always)] + fn sub_assign(&mut self, other: Vec2) { + self.0 = self.0.sub(other.0) + } +} + +impl Sub for Vec2 { + type Output = Self; + #[inline(always)] + fn sub(self, other: f32) -> Self { + Self(self.0.sub_scalar(other)) + } +} + +impl SubAssign for Vec2 { + #[inline(always)] + fn sub_assign(&mut self, other: f32) { + self.0 = self.0.sub_scalar(other) + } +} + +impl Sub for f32 { + type Output = Vec2; + #[inline(always)] + fn sub(self, other: Vec2) -> Vec2 { + Vec2(crate::XY::::splat(self).sub(other.0)) + } +} + +impl Rem for Vec2 { + type Output = Self; + #[inline(always)] + fn rem(self, other: Vec2) -> Self { + Self(self.0.rem(other.0)) + } +} + +impl RemAssign for Vec2 { + #[inline(always)] + fn rem_assign(&mut self, other: Vec2) { + self.0 = self.0.rem(other.0) + } +} + +impl Rem for Vec2 { + type Output = Self; + #[inline(always)] + fn rem(self, other: f32) -> Self { + Self(self.0.rem_scalar(other)) + } +} + +impl RemAssign for Vec2 { + #[inline(always)] + fn rem_assign(&mut self, other: f32) { + self.0 = self.0.rem_scalar(other) + } +} + +impl Rem for f32 { + type Output = Vec2; + #[inline(always)] + fn rem(self, other: Vec2) -> Vec2 { + Vec2(crate::XY::::splat(self).rem(other.0)) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsRef<[f32; 2]> for Vec2 { + #[inline(always)] + fn as_ref(&self) -> &[f32; 2] { + unsafe { &*(self as *const Vec2 as *const [f32; 2]) } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsMut<[f32; 2]> for Vec2 { + #[inline(always)] + fn as_mut(&mut self) -> &mut [f32; 2] { + unsafe { &mut *(self as *mut Vec2 as *mut [f32; 2]) } + } +} + +impl From<[f32; 2]> for Vec2 { + #[inline(always)] + fn from(a: [f32; 2]) -> Self { + Self(FloatVector2::from_array(a)) + } +} + +impl From for [f32; 2] { + #[inline(always)] + fn from(v: Vec2) -> Self { + v.into_array() + } +} + +impl<'a> Sum<&'a Self> for Vec2 { + #[inline] + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, |a, &b| Self::add(a, b)) + } +} + +impl<'a> Product<&'a Self> for Vec2 { + #[inline] + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ONE, |a, &b| Self::mul(a, b)) + } +} + + +impl Index for Vec2 { + type Output = f32; + #[inline(always)] + fn index(&self, index: usize) -> &Self::Output { + match index { + 0 => &self.x, + 1 => &self.y, + _ => panic!("index out of bounds"), + } + } +} + +impl IndexMut for Vec2 { + #[inline(always)] + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + match index { + 0 => &mut self.x, + 1 => &mut self.y, + _ => panic!("index out of bounds"), + } + } +} +#[cfg(not(target_arch = "spirv"))] +impl fmt::Display for Vec2 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "[{}, {}]", self.x, self.y) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Debug for Vec2 { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_tuple(stringify!(Vec2)) + .field(&self.x) + .field(&self.y) + .finish() + } +} + +impl From<(f32, f32)> for Vec2 { + #[inline(always)] + fn from(t: (f32, f32)) -> Self { + Self($inner::from_tuple(t)) + } +} + +impl From for (f32, f32) { + #[inline(always)] + fn from(v: Vec2) -> Self { + v.0.into_tuple() + } +} + +impl Deref for Vec2 { + type Target = crate::XY; + #[inline(always)] + fn deref(&self) -> &Self::Target { + self.0.as_ref_xy() + } +} + +impl DerefMut for Vec2 { + #[inline(always)] + fn deref_mut(&mut self) -> &mut Self::Target { + self.0.as_mut_xy() + } +} + diff --git a/src/f32/scalar/vec3a.rs b/src/f32/scalar/vec3a.rs new file mode 100644 index 00000000..d170b2f0 --- /dev/null +++ b/src/f32/scalar/vec3a.rs @@ -0,0 +1,1136 @@ +// Generated from vec.rs template. Edit the template, not the generated file. + +use crate::{BVec3, Vec2, Vec3, Vec4}; + +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::iter::{Product, Sum}; +use core::{f32, ops::*}; + +#[cfg(not(feature = "std"))] +use num_traits::Float; + +/// Creates a 3-dimensional vector. +#[inline(always)] +pub const fn vec3a(x: f32, y: f32, z: f32) -> Vec3A { + Vec3A::new(x, y, z) +} + +/// A 3-dimensional vector with SIMD support. +/// +/// This type is 16 byte aligned. A SIMD vector type is used for storage on supported platforms for +/// better performance than the `Vec3` type. +/// +/// It is possible to convert between `Vec3` and `Vec3A` types using `From` trait implementations. +#[derive(Clone, Copy)] +#[repr(C, align(16))] +pub struct Vec3A { + pub x: f32, + pub y: f32, + pub z: f32, +} + +impl Vec3A { + /// All zeroes. + pub const ZERO: Self = Self::splat(0.0); + + /// All ones. + pub const ONE: Self = Self::splat(1.0); + + /// All negative ones. + pub const NEG_ONE: Self = Self::splat(-1.0); + + /// All NAN. + pub const NAN: Self = Self::splat(f32::NAN); + + /// `[1.0, 0.0, 0.0]`: a unit-length vector pointing along the positive X axis. + pub const X: Self = Self::from_array([1.0, 0.0, 0.0]); + + /// `[0.0, 1.0, 0.0]`: a unit-length vector pointing along the positive Y axis. + pub const Y: Self = Self::from_array([0.0, 1.0, 0.0]); + + /// `[0.0, 0.0, 1.0]`: a unit-length vector pointing along the positive Z axis. + pub const Z: Self = Self::from_array([0.0, 0.0, 1.0]); + + /// The unit axes. + pub const AXES: [Self; 3] = [Self::X, Self::Y, Self::Z]; + + /// Creates a new vector. + #[inline(always)] + pub const fn new(x: f32, y: f32, z: f32) -> Self { + Self { x, y, z } + } + + /// Creates a vector with all elements set to `v`. + #[inline] + pub const fn splat(v: f32) -> Self { + Self { x: v, y: v, z: v } + } + + /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use + /// for each element of `self`. + /// + /// A true element in the mask uses the corresponding element from `if_true`, and false + /// uses the element from `if_false`. + #[inline] + pub fn select(mask: BVec3, if_true: Self, if_false: Self) -> Self { + Self { + x: if mask.x { if_true.x } else { if_false.x }, + y: if mask.y { if_true.y } else { if_false.y }, + z: if mask.z { if_true.z } else { if_false.z }, + } + } + + /// Creates a new vector from an array. + #[inline] + pub const fn from_array(a: [f32; 3]) -> Self { + Self::new(a[0], a[1], a[2]) + } + + /// `[x, y, z]` + #[inline] + pub const fn to_array(&self) -> [f32; 3] { + [self.x, self.y, self.z] + } + + /// Creates a vector from the first N values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than N elements long. + #[inline] + pub const fn from_slice(slice: &[f32]) -> Self { + Self::new(slice[0], slice[1], slice[2]) + } + + /// Writes the elements of `self` to the first 3 elements in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than N elements long. + #[inline] + pub fn write_to_slice(self, slice: &mut [f32]) { + slice[0] = self.x; + slice[1] = self.y; + slice[2] = self.z; + } + + /// Internal method for creating a 3D vector from a 4D vector, discarding `w`. + #[allow(dead_code)] + #[inline] + pub(crate) fn from_vec4(v: Vec4) -> Self { + Self { + x: v.x, + y: v.y, + z: v.z, + } + } + + /// Creates a 4D vector from `self` and the given `w` value. + #[inline] + pub fn extend(self, w: f32) -> Vec4 { + Vec4::new(self.x, self.y, self.z, w) + } + + /// Creates a 2D vector from the `x` and `y` elements of `self`, discarding `z`. + /// + /// Truncation may also be performed by using `self.xy()` or `Vec2::from()`. + #[inline] + pub fn truncate(self) -> Vec2 { + use crate::swizzles::Vec3Swizzles; + self.xy() + } + + /// Computes the dot product of `self` and `rhs`. + #[inline] + pub fn dot(self, rhs: Self) -> f32 { + (self.x * rhs.x) + (self.y * rhs.y) + (self.z * rhs.z) + } + + /// Computes the cross product of `self` and `rhs`. + #[inline] + pub fn cross(self, rhs: Self) -> Self { + Self { + x: self.y * rhs.z - rhs.y * self.z, + y: self.z * rhs.x - rhs.z * self.x, + z: self.x * rhs.y - rhs.x * self.y, + } + } + + /// Returns a vector containing the minimum values for each element of `self` and `rhs`. + /// + /// In other words this computes `[self.x.min(rhs.x), self.y.min(rhs.y), ..]`. + #[inline] + pub fn min(self, rhs: Self) -> Self { + Self { + x: self.x.min(rhs.x), + y: self.y.min(rhs.y), + z: self.z.min(rhs.z), + } + } + + /// Returns a vector containing the maximum values for each element of `self` and `rhs`. + /// + /// In other words this computes `[self.x.max(rhs.x), self.y.max(rhs.y), ..]`. + #[inline] + pub fn max(self, rhs: Self) -> Self { + Self { + x: self.x.max(rhs.x), + y: self.y.max(rhs.y), + z: self.z.max(rhs.z), + } + } + + /// Component-wise clamping of values, similar to [`f32::clamp`]. + /// + /// Each element in `min` must be less-or-equal to the corresponding element in `max`. + /// + /// # Panics + /// + /// Will panic if `min` is greater than `max` when `glam_assert` is enabled. + #[inline] + pub fn clamp(self, min: Self, max: Self) -> Self { + glam_assert!(min.cmple(max).all(), "clamp: expected min <= max"); + self.max(min).min(max) + } + + /// Returns the horizontal minimum of `self`. + /// + /// In other words this computes `min(x, y, ..)`. + #[inline] + pub fn min_element(self) -> f32 { + self.x.min(self.y.min(self.z)) + } + + /// Returns the horizontal maximum of `self`. + /// + /// In other words this computes `max(x, y, ..)`. + #[inline] + pub fn max_element(self) -> f32 { + self.x.max(self.y.max(self.z)) + } + + /// Returns a vector mask containing the result of a `==` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words, this computes `[self.x == rhs.x, self.y == rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpeq(self, rhs: Self) -> BVec3 { + BVec3::new(self.x.eq(&rhs.x), self.y.eq(&rhs.y), self.z.eq(&rhs.z)) + } + + /// Returns a vector mask containing the result of a `!=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x != rhs.x, self.y != rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpne(self, rhs: Self) -> BVec3 { + BVec3::new(self.x.ne(&rhs.x), self.y.ne(&rhs.y), self.z.ne(&rhs.z)) + } + + /// Returns a vector mask containing the result of a `>=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x >= rhs.x, self.y >= rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpge(self, rhs: Self) -> BVec3 { + BVec3::new(self.x.ge(&rhs.x), self.y.ge(&rhs.y), self.z.ge(&rhs.z)) + } + + /// Returns a vector mask containing the result of a `>` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x > rhs.x, self.y > rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpgt(self, rhs: Self) -> BVec3 { + BVec3::new(self.x.gt(&rhs.x), self.y.gt(&rhs.y), self.z.gt(&rhs.z)) + } + + /// Returns a vector mask containing the result of a `<=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x <= rhs.x, self.y <= rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmple(self, rhs: Self) -> BVec3 { + BVec3::new(self.x.le(&rhs.x), self.y.le(&rhs.y), self.z.le(&rhs.z)) + } + + /// Returns a vector mask containing the result of a `<` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x < rhs.x, self.y < rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmplt(self, rhs: Self) -> BVec3 { + BVec3::new(self.x.lt(&rhs.x), self.y.lt(&rhs.y), self.z.lt(&rhs.z)) + } + + /// Returns a vector containing the absolute value of each element of `self`. + #[inline] + pub fn abs(self) -> Self { + Self { + x: self.x.abs(), + y: self.y.abs(), + z: self.z.abs(), + } + } + + /// Returns a vector with elements representing the sign of `self`. + /// + /// - `1.0` if the number is positive, `+0.0` or `INFINITY` + /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` + /// - `NAN` if the number is `NAN` + #[inline] + pub fn signum(self) -> Self { + Self { + x: self.x.signum(), + y: self.y.signum(), + z: self.z.signum(), + } + } + + /// Returns `true` if, and only if, all elements are finite. If any element is either + /// `NaN`, positive or negative infinity, this will return `false`. + #[inline] + pub fn is_finite(self) -> bool { + self.x.is_finite() && self.y.is_finite() && self.z.is_finite() + } + + /// Returns `true` if any elements are `NaN`. + #[inline] + pub fn is_nan(self) -> bool { + self.x.is_nan() || self.y.is_nan() || self.z.is_nan() + } + + /// Performs `is_nan` on each element of self, returning a vector mask of the results. + /// + /// In other words, this computes `[x.is_nan(), y.is_nan(), z.is_nan(), w.is_nan()]`. + #[inline] + pub fn is_nan_mask(self) -> BVec3 { + BVec3::new(self.x.is_nan(), self.y.is_nan(), self.z.is_nan()) + } + + /// Computes the length of `self`. + #[doc(alias = "magnitude")] + #[inline] + pub fn length(self) -> f32 { + self.dot(self).sqrt() + } + + /// Computes the squared length of `self`. + /// + /// This is faster than `length()` as it avoids a square root operation. + #[doc(alias = "magnitude2")] + #[inline] + pub fn length_squared(self) -> f32 { + self.dot(self) + } + + /// Computes `1.0 / length()`. + /// + /// For valid results, `self` must _not_ be of length zero. + #[inline] + pub fn length_recip(self) -> f32 { + self.length().recip() + } + + /// Computes the Euclidean distance between two points in space. + #[inline] + pub fn distance(self, rhs: Self) -> f32 { + (self - rhs).length() + } + + /// Compute the squared euclidean distance between two points in space. + #[inline] + pub fn distance_squared(self, rhs: Self) -> f32 { + (self - rhs).length_squared() + } + + /// Returns `self` normalized to length 1.0. + /// + /// For valid results, `self` must _not_ be of length zero, nor very close to zero. + /// + /// See also [`Self::try_normalize`] and [`Self::normalize_or_zero`]. + /// + /// Panics + /// + /// Will panic if `self` is zero length when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn normalize(self) -> Self { + #[allow(clippy::let_and_return)] + let normalized = self.mul(self.length_recip()); + glam_assert!(normalized.is_finite()); + normalized + } + + /// Returns `self` normalized to length 1.0 if possible, else returns `None`. + /// + /// In particular, if the input is zero (or very close to zero), or non-finite, + /// the result of this operation will be `None`. + /// + /// See also [`Self::normalize_or_zero`]. + #[must_use] + #[inline] + pub fn try_normalize(self) -> Option { + let rcp = self.length_recip(); + if rcp.is_finite() && rcp > 0.0 { + Some(self * rcp) + } else { + None + } + } + + /// Returns `self` normalized to length 1.0 if possible, else returns zero. + /// + /// In particular, if the input is zero (or very close to zero), or non-finite, + /// the result of this operation will be zero. + /// + /// See also [`Self::try_normalize`]. + #[must_use] + #[inline] + pub fn normalize_or_zero(self) -> Self { + let rcp = self.length_recip(); + if rcp.is_finite() && rcp > 0.0 { + self * rcp + } else { + Self::ZERO + } + } + + /// Returns whether `self` is length `1.0` or not. + /// + /// Uses a precision threshold of `1e-6`. + #[inline] + pub fn is_normalized(self) -> bool { + // TODO: do something with epsilon + (self.length_squared() - 1.0).abs() <= 1e-4 + } + + /// Returns the vector projection of `self` onto `rhs`. + /// + /// `rhs` must be of non-zero length. + /// + /// # Panics + /// + /// Will panic if `rhs` is zero length when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn project_onto(self, rhs: Self) -> Self { + let other_len_sq_rcp = rhs.dot(rhs).recip(); + glam_assert!(other_len_sq_rcp.is_finite()); + rhs * self.dot(rhs) * other_len_sq_rcp + } + + /// Returns the vector rejection of `self` from `rhs`. + /// + /// The vector rejection is the vector perpendicular to the projection of `self` onto + /// `rhs`, in rhs words the result of `self - self.project_onto(rhs)`. + /// + /// `rhs` must be of non-zero length. + /// + /// # Panics + /// + /// Will panic if `rhs` has a length of zero when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn reject_from(self, rhs: Self) -> Self { + self - self.project_onto(rhs) + } + + /// Returns the vector projection of `self` onto `rhs`. + /// + /// `rhs` must be normalized. + /// + /// # Panics + /// + /// Will panic if `rhs` is not normalized when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn project_onto_normalized(self, rhs: Self) -> Self { + glam_assert!(rhs.is_normalized()); + rhs * self.dot(rhs) + } + + /// Returns the vector rejection of `self` from `rhs`. + /// + /// The vector rejection is the vector perpendicular to the projection of `self` onto + /// `rhs`, in rhs words the result of `self - self.project_onto(rhs)`. + /// + /// `rhs` must be normalized. + /// + /// # Panics + /// + /// Will panic if `rhs` is not normalized when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn reject_from_normalized(self, rhs: Self) -> Self { + self - self.project_onto_normalized(rhs) + } + + /// Returns a vector containing the nearest integer to a number for each element of `self`. + /// Round half-way cases away from 0.0. + #[inline] + pub fn round(self) -> Self { + Self { + x: self.x.round(), + y: self.y.round(), + z: self.z.round(), + } + } + + /// Returns a vector containing the largest integer less than or equal to a number for each + /// element of `self`. + #[inline] + pub fn floor(self) -> Self { + Self { + x: self.x.floor(), + y: self.y.floor(), + z: self.z.floor(), + } + } + + /// Returns a vector containing the smallest integer greater than or equal to a number for + /// each element of `self`. + #[inline] + pub fn ceil(self) -> Self { + Self { + x: self.x.ceil(), + y: self.y.ceil(), + z: self.z.ceil(), + } + } + + /// Returns a vector containing the fractional part of the vector, e.g. `self - + /// self.floor()`. + /// + /// Note that this is fast but not precise for large numbers. + #[inline] + pub fn fract(self) -> Self { + self - self.floor() + } + + /// Returns a vector containing `e^self` (the exponential function) for each element of + /// `self`. + #[inline] + pub fn exp(self) -> Self { + Self::new(self.x.exp(), self.y.exp(), self.z.exp()) + } + + /// Returns a vector containing each element of `self` raised to the power of `n`. + #[inline] + pub fn powf(self, n: f32) -> Self { + Self::new(self.x.powf(n), self.y.powf(n), self.z.powf(n)) + } + + /// Returns a vector containing the reciprocal `1.0/n` of each element of `self`. + #[inline] + pub fn recip(self) -> Self { + Self { + x: self.x.recip(), + y: self.y.recip(), + z: self.z.recip(), + } + } + + /// Performs a linear interpolation between `self` and `rhs` based on the value `s`. + /// + /// When `s` is `0.0`, the result will be equal to `self`. When `s` is `1.0`, the result + /// will be equal to `rhs`. When `s` is outside of range `[0, 1]`, the result is linearly + /// extrapolated. + #[doc(alias = "mix")] + #[inline] + pub fn lerp(self, rhs: Self, s: f32) -> Self { + self + ((rhs - self) * s) + } + + /// Returns true if the absolute difference of all elements between `self` and `rhs` is + /// less than or equal to `max_abs_diff`. + /// + /// This can be used to compare if two vectors contain similar elements. It works best when + /// comparing with a known value. The `max_abs_diff` that should be used used depends on + /// the values being compared against. + /// + /// For more see + /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/). + #[inline] + pub fn abs_diff_eq(self, rhs: Self, max_abs_diff: f32) -> bool { + self.sub(rhs).abs().cmple(Self::splat(max_abs_diff)).all() + } + + /// Returns a vector with a length no less than `min` and no more than `max` + /// + /// # Panics + /// + /// Will panic if `min` is greater than `max` when `glam_assert` is enabled. + #[inline] + pub fn clamp_length(self, min: f32, max: f32) -> Self { + glam_assert!(min <= max); + let length_sq = self.length_squared(); + if length_sq < min * min { + self * (length_sq.sqrt().recip() * min) + } else if length_sq > max * max { + self * (length_sq.sqrt().recip() * max) + } else { + self + } + } + + /// Returns a vector with a length no more than `max` + pub fn clamp_length_max(self, max: f32) -> Self { + let length_sq = self.length_squared(); + if length_sq > max * max { + self * (length_sq.sqrt().recip() * max) + } else { + self + } + } + + /// Returns a vector with a length no less than `min` + pub fn clamp_length_min(self, min: f32) -> Self { + let length_sq = self.length_squared(); + if length_sq < min * min { + self * (length_sq.sqrt().recip() * min) + } else { + self + } + } + + /// Fused multiply-add. Computes `(self * a) + b` element-wise with only one rounding + /// error, yielding a more accurate result than an unfused multiply-add. + /// + /// Using `mul_add` *may* be more performant than an unfused multiply-add if the target + /// architecture has a dedicated fma CPU instruction. However, this is not always true, + /// and will be heavily dependant on designing algorithms with specific target hardware in + /// mind. + #[inline] + pub fn mul_add(self, a: Self, b: Self) -> Self { + Self::new( + self.x.mul_add(a.x, b.x), + self.y.mul_add(a.y, b.y), + self.z.mul_add(a.z, b.z), + ) + } + + /// Returns the angle (in radians) between two vectors. + /// + /// The input vectors do not need to be unit length however they must be non-zero. + #[inline] + pub fn angle_between(self, rhs: Self) -> f32 { + use crate::FloatEx; + self.dot(rhs) + .div(self.length_squared().mul(rhs.length_squared()).sqrt()) + .acos_approx() + } + + /// Returns some vector that is orthogonal to the given one. + /// + /// The input vector must be finite and non-zero. + /// + /// The output vector is not necessarily unit-length. + /// For that use [`Self::any_orthonormal_vector`] instead. + #[inline] + pub fn any_orthogonal_vector(&self) -> Self { + // This can probably be optimized + if self.x.abs() > self.y.abs() { + Self::new(-self.z, 0.0, self.x) // self.cross(Self::Y) + } else { + Self::new(0.0, self.z, -self.y) // self.cross(Self::X) + } + } + + /// Returns any unit-length vector that is orthogonal to the given one. + /// The input vector must be finite and non-zero. + /// + /// # Panics + /// + /// Will panic if `self` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn any_orthonormal_vector(&self) -> Self { + glam_assert!(self.is_normalized()); + // From https://graphics.pixar.com/library/OrthonormalB/paper.pdf + #[cfg(feature = "std")] + let sign = (1.0_f32).copysign(self.z); + #[cfg(not(feature = "std"))] + let sign = self.z.signum(); + let a = -1.0 / (sign + self.z); + let b = self.x * self.y * a; + Self::new(b, sign + self.y * self.y * a, -self.y) + } + + /// Given a unit-length vector return two other vectors that together form an orthonormal + /// basis. That is, all three vectors are orthogonal to each other and are normalized. + /// + /// # Panics + /// + /// Will panic if `self` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn any_orthonormal_pair(&self) -> (Self, Self) { + glam_assert!(self.is_normalized()); + // From https://graphics.pixar.com/library/OrthonormalB/paper.pdf + #[cfg(feature = "std")] + let sign = (1.0_f32).copysign(self.z); + #[cfg(not(feature = "std"))] + let sign = self.z.signum(); + let a = -1.0 / (sign + self.z); + let b = self.x * self.y * a; + ( + Self::new(1.0 + sign * self.x * self.x * a, sign * b, -sign * self.x), + Self::new(b, sign + self.y * self.y * a, -self.y), + ) + } + + /// Casts all elements of `self` to `f64`. + #[inline] + pub fn as_dvec3(&self) -> crate::DVec3 { + crate::DVec3::new(self.x as f64, self.y as f64, self.z as f64) + } + + /// Casts all elements of `self` to `i32`. + #[inline] + pub fn as_ivec3(&self) -> crate::IVec3 { + crate::IVec3::new(self.x as i32, self.y as i32, self.z as i32) + } + + /// Casts all elements of `self` to `u32`. + #[inline] + pub fn as_uvec3(&self) -> crate::UVec3 { + crate::UVec3::new(self.x as u32, self.y as u32, self.z as u32) + } +} + +impl Default for Vec3A { + #[inline(always)] + fn default() -> Self { + Self::ZERO + } +} + +impl PartialEq for Vec3A { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.cmpeq(*rhs).all() + } +} + +impl Div for Vec3A { + type Output = Self; + #[inline] + fn div(self, rhs: Self) -> Self { + Self { + x: self.x.div(rhs.x), + y: self.y.div(rhs.y), + z: self.z.div(rhs.z), + } + } +} + +impl DivAssign for Vec3A { + #[inline] + fn div_assign(&mut self, rhs: Self) { + self.x.div_assign(rhs.x); + self.y.div_assign(rhs.y); + self.z.div_assign(rhs.z); + } +} + +impl Div for Vec3A { + type Output = Self; + #[inline] + fn div(self, rhs: f32) -> Self { + Self { + x: self.x.div(rhs), + y: self.y.div(rhs), + z: self.z.div(rhs), + } + } +} + +impl DivAssign for Vec3A { + #[inline] + fn div_assign(&mut self, rhs: f32) { + self.x.div_assign(rhs); + self.y.div_assign(rhs); + self.z.div_assign(rhs); + } +} + +impl Div for f32 { + type Output = Vec3A; + #[inline] + fn div(self, rhs: Vec3A) -> Vec3A { + Vec3A { + x: self.div(rhs.x), + y: self.div(rhs.y), + z: self.div(rhs.z), + } + } +} + +impl Mul for Vec3A { + type Output = Self; + #[inline] + fn mul(self, rhs: Self) -> Self { + Self { + x: self.x.mul(rhs.x), + y: self.y.mul(rhs.y), + z: self.z.mul(rhs.z), + } + } +} + +impl MulAssign for Vec3A { + #[inline] + fn mul_assign(&mut self, rhs: Self) { + self.x.mul_assign(rhs.x); + self.y.mul_assign(rhs.y); + self.z.mul_assign(rhs.z); + } +} + +impl Mul for Vec3A { + type Output = Self; + #[inline] + fn mul(self, rhs: f32) -> Self { + Self { + x: self.x.mul(rhs), + y: self.y.mul(rhs), + z: self.z.mul(rhs), + } + } +} + +impl MulAssign for Vec3A { + #[inline] + fn mul_assign(&mut self, rhs: f32) { + self.x.mul_assign(rhs); + self.y.mul_assign(rhs); + self.z.mul_assign(rhs); + } +} + +impl Mul for f32 { + type Output = Vec3A; + #[inline] + fn mul(self, rhs: Vec3A) -> Vec3A { + Vec3A { + x: self.mul(rhs.x), + y: self.mul(rhs.y), + z: self.mul(rhs.z), + } + } +} + +impl Add for Vec3A { + type Output = Self; + #[inline] + fn add(self, rhs: Self) -> Self { + Self { + x: self.x.add(rhs.x), + y: self.y.add(rhs.y), + z: self.z.add(rhs.z), + } + } +} + +impl AddAssign for Vec3A { + #[inline] + fn add_assign(&mut self, rhs: Self) { + self.x.add_assign(rhs.x); + self.y.add_assign(rhs.y); + self.z.add_assign(rhs.z); + } +} + +impl Add for Vec3A { + type Output = Self; + #[inline] + fn add(self, rhs: f32) -> Self { + Self { + x: self.x.add(rhs), + y: self.y.add(rhs), + z: self.z.add(rhs), + } + } +} + +impl AddAssign for Vec3A { + #[inline] + fn add_assign(&mut self, rhs: f32) { + self.x.add_assign(rhs); + self.y.add_assign(rhs); + self.z.add_assign(rhs); + } +} + +impl Add for f32 { + type Output = Vec3A; + #[inline] + fn add(self, rhs: Vec3A) -> Vec3A { + Vec3A { + x: self.add(rhs.x), + y: self.add(rhs.y), + z: self.add(rhs.z), + } + } +} + +impl Sub for Vec3A { + type Output = Self; + #[inline] + fn sub(self, rhs: Self) -> Self { + Self { + x: self.x.sub(rhs.x), + y: self.y.sub(rhs.y), + z: self.z.sub(rhs.z), + } + } +} + +impl SubAssign for Vec3A { + #[inline] + fn sub_assign(&mut self, rhs: Vec3A) { + self.x.sub_assign(rhs.x); + self.y.sub_assign(rhs.y); + self.z.sub_assign(rhs.z); + } +} + +impl Sub for Vec3A { + type Output = Self; + #[inline] + fn sub(self, rhs: f32) -> Self { + Self { + x: self.x.sub(rhs), + y: self.y.sub(rhs), + z: self.z.sub(rhs), + } + } +} + +impl SubAssign for Vec3A { + #[inline] + fn sub_assign(&mut self, rhs: f32) { + self.x.sub_assign(rhs); + self.y.sub_assign(rhs); + self.z.sub_assign(rhs); + } +} + +impl Sub for f32 { + type Output = Vec3A; + #[inline] + fn sub(self, rhs: Vec3A) -> Vec3A { + Vec3A { + x: self.sub(rhs.x), + y: self.sub(rhs.y), + z: self.sub(rhs.z), + } + } +} + +impl Rem for Vec3A { + type Output = Self; + #[inline] + fn rem(self, rhs: Self) -> Self { + Self { + x: self.x.rem(rhs.x), + y: self.y.rem(rhs.y), + z: self.z.rem(rhs.z), + } + } +} + +impl RemAssign for Vec3A { + #[inline] + fn rem_assign(&mut self, rhs: Self) { + self.x.rem_assign(rhs.x); + self.y.rem_assign(rhs.y); + self.z.rem_assign(rhs.z); + } +} + +impl Rem for Vec3A { + type Output = Self; + #[inline] + fn rem(self, rhs: f32) -> Self { + Self { + x: self.x.rem(rhs), + y: self.y.rem(rhs), + z: self.z.rem(rhs), + } + } +} + +impl RemAssign for Vec3A { + #[inline] + fn rem_assign(&mut self, rhs: f32) { + self.x.rem_assign(rhs); + self.y.rem_assign(rhs); + self.z.rem_assign(rhs); + } +} + +impl Rem for f32 { + type Output = Vec3A; + #[inline] + fn rem(self, rhs: Vec3A) -> Vec3A { + Vec3A { + x: self.rem(rhs.x), + y: self.rem(rhs.y), + z: self.rem(rhs.z), + } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsRef<[f32; 3]> for Vec3A { + #[inline] + fn as_ref(&self) -> &[f32; 3] { + unsafe { &*(self as *const Vec3A as *const [f32; 3]) } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsMut<[f32; 3]> for Vec3A { + #[inline] + fn as_mut(&mut self) -> &mut [f32; 3] { + unsafe { &mut *(self as *mut Vec3A as *mut [f32; 3]) } + } +} + +impl<'a> Sum<&'a Self> for Vec3A { + #[inline] + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, |a, &b| Self::add(a, b)) + } +} + +impl<'a> Product<&'a Self> for Vec3A { + #[inline] + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ONE, |a, &b| Self::mul(a, b)) + } +} + +impl Neg for Vec3A { + type Output = Self; + #[inline] + fn neg(self) -> Self { + Self { + x: self.x.neg(), + y: self.y.neg(), + z: self.z.neg(), + } + } +} + +impl Index for Vec3A { + type Output = f32; + #[inline] + fn index(&self, index: usize) -> &Self::Output { + match index { + 0 => &self.x, + 1 => &self.y, + 2 => &self.z, + _ => panic!("index out of bounds"), + } + } +} + +impl IndexMut for Vec3A { + #[inline] + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + match index { + 0 => &mut self.x, + 1 => &mut self.y, + 2 => &mut self.z, + _ => panic!("index out of bounds"), + } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Display for Vec3A { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "[{}, {}, {}]", self.x, self.y, self.z) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Debug for Vec3A { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_tuple(stringify!(Vec3A)) + .field(&self.x) + .field(&self.y) + .field(&self.z) + .finish() + } +} + +impl From<[f32; 3]> for Vec3A { + #[inline] + fn from(a: [f32; 3]) -> Self { + Self::new(a[0], a[1], a[2]) + } +} + +impl From for [f32; 3] { + #[inline] + fn from(v: Vec3A) -> Self { + [v.x, v.y, v.z] + } +} + +impl From<(f32, f32, f32)> for Vec3A { + #[inline] + fn from(t: (f32, f32, f32)) -> Self { + Self::new(t.0, t.1, t.2) + } +} + +impl From for (f32, f32, f32) { + #[inline] + fn from(v: Vec3A) -> Self { + (v.x, v.y, v.z) + } +} + +impl From for Vec3A { + #[inline] + fn from(v: Vec3) -> Self { + Self::new(v.x, v.y, v.z) + } +} + +impl From for Vec3A { + /// Creates a `Vec3A` from the `x`, `y` and `z` elements of `self` discarding `w`. + /// + /// On architectures where SIMD is supported such as SSE2 on `x86_64` this conversion is a noop. + #[inline] + fn from(v: Vec4) -> Self { + Self { + x: v.x, + y: v.y, + z: v.z, + } + } +} + +impl From<(Vec2, f32)> for Vec3A { + #[inline] + fn from((v, z): (Vec2, f32)) -> Self { + Self::new(v.x, v.y, z) + } +} diff --git a/src/f32/scalar/vec4.rs b/src/f32/scalar/vec4.rs new file mode 100644 index 00000000..667326aa --- /dev/null +++ b/src/f32/scalar/vec4.rs @@ -0,0 +1,1150 @@ +// Generated from vec.rs template. Edit the template, not the generated file. + +use crate::{BVec4, Vec2, Vec3, Vec3A}; + +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::iter::{Product, Sum}; +use core::{f32, ops::*}; + +#[cfg(not(feature = "std"))] +use num_traits::Float; + +/// Creates a 4-dimensional vector. +#[inline(always)] +pub const fn vec4(x: f32, y: f32, z: f32, w: f32) -> Vec4 { + Vec4::new(x, y, z, w) +} + +/// A 4-dimensional vector. +#[derive(Clone, Copy)] +#[cfg_attr( + any( + not(any(feature = "scalar-math", target_arch = "spirv")), + feature = "cuda" + ), + repr(C, align(16)) +)] +pub struct Vec4 { + pub x: f32, + pub y: f32, + pub z: f32, + pub w: f32, +} + +impl Vec4 { + /// All zeroes. + pub const ZERO: Self = Self::splat(0.0); + + /// All ones. + pub const ONE: Self = Self::splat(1.0); + + /// All negative ones. + pub const NEG_ONE: Self = Self::splat(-1.0); + + /// All NAN. + pub const NAN: Self = Self::splat(f32::NAN); + + /// `[1.0, 0.0, 0.0, 0.0]`: a unit-length vector pointing along the positive X axis. + pub const X: Self = Self::from_array([1.0, 0.0, 0.0, 0.0]); + + /// `[0.0, 1.0, 0.0, 0.0]`: a unit-length vector pointing along the positive Y axis. + pub const Y: Self = Self::from_array([0.0, 1.0, 0.0, 0.0]); + + /// `[0.0, 0.0, 1.0, 0.0]`: a unit-length vector pointing along the positive Z axis. + pub const Z: Self = Self::from_array([0.0, 0.0, 1.0, 0.0]); + + /// `[0.0, 0.0, 0.0, 1.0]`: a unit-length vector pointing along the positive W axis. + pub const W: Self = Self::from_array([0.0, 0.0, 0.0, 1.0]); + + /// The unit axes. + pub const AXES: [Self; 4] = [Self::X, Self::Y, Self::Z, Self::W]; + + /// Creates a new vector. + #[inline(always)] + pub const fn new(x: f32, y: f32, z: f32, w: f32) -> Self { + Self { x, y, z, w } + } + + /// Creates a vector with all elements set to `v`. + #[inline] + pub const fn splat(v: f32) -> Self { + Self { + x: v, + + y: v, + + z: v, + + w: v, + } + } + + /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use + /// for each element of `self`. + /// + /// A true element in the mask uses the corresponding element from `if_true`, and false + /// uses the element from `if_false`. + #[inline] + pub fn select(mask: BVec4, if_true: Self, if_false: Self) -> Self { + Self { + x: if mask.x { if_true.x } else { if_false.x }, + y: if mask.y { if_true.y } else { if_false.y }, + z: if mask.z { if_true.z } else { if_false.z }, + w: if mask.w { if_true.w } else { if_false.w }, + } + } + + /// Creates a new vector from an array. + #[inline] + pub const fn from_array(a: [f32; 4]) -> Self { + Self::new(a[0], a[1], a[2], a[3]) + } + + /// `[x, y, z, w]` + #[inline] + pub const fn to_array(&self) -> [f32; 4] { + [self.x, self.y, self.z, self.w] + } + + /// Creates a vector from the first N values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than N elements long. + #[inline] + pub const fn from_slice(slice: &[f32]) -> Self { + Self::new(slice[0], slice[1], slice[2], slice[3]) + } + + /// Writes the elements of `self` to the first 4 elements in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than N elements long. + #[inline] + pub fn write_to_slice(self, slice: &mut [f32]) { + slice[0] = self.x; + slice[1] = self.y; + slice[2] = self.z; + slice[3] = self.w; + } + + /// Creates a 2D vector from the `x`, `y` and `z` elements of `self`, discarding `w`. + /// + /// Truncation to `Vec3` may also be performed by using `self.xyz()` or `Vec3::from()`. + /// + /// To truncate to `Vec3A` use `Vec3A::from()`. + #[inline] + pub fn truncate(self) -> Vec3 { + use crate::swizzles::Vec4Swizzles; + self.xyz() + } + + /// Computes the dot product of `self` and `rhs`. + #[inline] + pub fn dot(self, rhs: Self) -> f32 { + (self.x * rhs.x) + (self.y * rhs.y) + (self.z * rhs.z) + (self.w * rhs.w) + } + + /// Returns a vector containing the minimum values for each element of `self` and `rhs`. + /// + /// In other words this computes `[self.x.min(rhs.x), self.y.min(rhs.y), ..]`. + #[inline] + pub fn min(self, rhs: Self) -> Self { + Self { + x: self.x.min(rhs.x), + y: self.y.min(rhs.y), + z: self.z.min(rhs.z), + w: self.w.min(rhs.w), + } + } + + /// Returns a vector containing the maximum values for each element of `self` and `rhs`. + /// + /// In other words this computes `[self.x.max(rhs.x), self.y.max(rhs.y), ..]`. + #[inline] + pub fn max(self, rhs: Self) -> Self { + Self { + x: self.x.max(rhs.x), + y: self.y.max(rhs.y), + z: self.z.max(rhs.z), + w: self.w.max(rhs.w), + } + } + + /// Component-wise clamping of values, similar to [`f32::clamp`]. + /// + /// Each element in `min` must be less-or-equal to the corresponding element in `max`. + /// + /// # Panics + /// + /// Will panic if `min` is greater than `max` when `glam_assert` is enabled. + #[inline] + pub fn clamp(self, min: Self, max: Self) -> Self { + glam_assert!(min.cmple(max).all(), "clamp: expected min <= max"); + self.max(min).min(max) + } + + /// Returns the horizontal minimum of `self`. + /// + /// In other words this computes `min(x, y, ..)`. + #[inline] + pub fn min_element(self) -> f32 { + self.x.min(self.y.min(self.z.min(self.w))) + } + + /// Returns the horizontal maximum of `self`. + /// + /// In other words this computes `max(x, y, ..)`. + #[inline] + pub fn max_element(self) -> f32 { + self.x.max(self.y.max(self.z.max(self.w))) + } + + /// Returns a vector mask containing the result of a `==` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words, this computes `[self.x == rhs.x, self.y == rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpeq(self, rhs: Self) -> BVec4 { + BVec4::new( + self.x.eq(&rhs.x), + self.y.eq(&rhs.y), + self.z.eq(&rhs.z), + self.w.eq(&rhs.w), + ) + } + + /// Returns a vector mask containing the result of a `!=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x != rhs.x, self.y != rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpne(self, rhs: Self) -> BVec4 { + BVec4::new( + self.x.ne(&rhs.x), + self.y.ne(&rhs.y), + self.z.ne(&rhs.z), + self.w.ne(&rhs.w), + ) + } + + /// Returns a vector mask containing the result of a `>=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x >= rhs.x, self.y >= rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpge(self, rhs: Self) -> BVec4 { + BVec4::new( + self.x.ge(&rhs.x), + self.y.ge(&rhs.y), + self.z.ge(&rhs.z), + self.w.ge(&rhs.w), + ) + } + + /// Returns a vector mask containing the result of a `>` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x > rhs.x, self.y > rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpgt(self, rhs: Self) -> BVec4 { + BVec4::new( + self.x.gt(&rhs.x), + self.y.gt(&rhs.y), + self.z.gt(&rhs.z), + self.w.gt(&rhs.w), + ) + } + + /// Returns a vector mask containing the result of a `<=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x <= rhs.x, self.y <= rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmple(self, rhs: Self) -> BVec4 { + BVec4::new( + self.x.le(&rhs.x), + self.y.le(&rhs.y), + self.z.le(&rhs.z), + self.w.le(&rhs.w), + ) + } + + /// Returns a vector mask containing the result of a `<` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x < rhs.x, self.y < rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmplt(self, rhs: Self) -> BVec4 { + BVec4::new( + self.x.lt(&rhs.x), + self.y.lt(&rhs.y), + self.z.lt(&rhs.z), + self.w.lt(&rhs.w), + ) + } + + /// Returns a vector containing the absolute value of each element of `self`. + #[inline] + pub fn abs(self) -> Self { + Self { + x: self.x.abs(), + y: self.y.abs(), + z: self.z.abs(), + w: self.w.abs(), + } + } + + /// Returns a vector with elements representing the sign of `self`. + /// + /// - `1.0` if the number is positive, `+0.0` or `INFINITY` + /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` + /// - `NAN` if the number is `NAN` + #[inline] + pub fn signum(self) -> Self { + Self { + x: self.x.signum(), + y: self.y.signum(), + z: self.z.signum(), + w: self.w.signum(), + } + } + + /// Returns `true` if, and only if, all elements are finite. If any element is either + /// `NaN`, positive or negative infinity, this will return `false`. + #[inline] + pub fn is_finite(self) -> bool { + self.x.is_finite() && self.y.is_finite() && self.z.is_finite() && self.w.is_finite() + } + + /// Returns `true` if any elements are `NaN`. + #[inline] + pub fn is_nan(self) -> bool { + self.x.is_nan() || self.y.is_nan() || self.z.is_nan() || self.w.is_nan() + } + + /// Performs `is_nan` on each element of self, returning a vector mask of the results. + /// + /// In other words, this computes `[x.is_nan(), y.is_nan(), z.is_nan(), w.is_nan()]`. + #[inline] + pub fn is_nan_mask(self) -> BVec4 { + BVec4::new( + self.x.is_nan(), + self.y.is_nan(), + self.z.is_nan(), + self.w.is_nan(), + ) + } + + /// Computes the length of `self`. + #[doc(alias = "magnitude")] + #[inline] + pub fn length(self) -> f32 { + self.dot(self).sqrt() + } + + /// Computes the squared length of `self`. + /// + /// This is faster than `length()` as it avoids a square root operation. + #[doc(alias = "magnitude2")] + #[inline] + pub fn length_squared(self) -> f32 { + self.dot(self) + } + + /// Computes `1.0 / length()`. + /// + /// For valid results, `self` must _not_ be of length zero. + #[inline] + pub fn length_recip(self) -> f32 { + self.length().recip() + } + + /// Computes the Euclidean distance between two points in space. + #[inline] + pub fn distance(self, rhs: Self) -> f32 { + (self - rhs).length() + } + + /// Compute the squared euclidean distance between two points in space. + #[inline] + pub fn distance_squared(self, rhs: Self) -> f32 { + (self - rhs).length_squared() + } + + /// Returns `self` normalized to length 1.0. + /// + /// For valid results, `self` must _not_ be of length zero, nor very close to zero. + /// + /// See also [`Self::try_normalize`] and [`Self::normalize_or_zero`]. + /// + /// Panics + /// + /// Will panic if `self` is zero length when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn normalize(self) -> Self { + #[allow(clippy::let_and_return)] + let normalized = self.mul(self.length_recip()); + glam_assert!(normalized.is_finite()); + normalized + } + + /// Returns `self` normalized to length 1.0 if possible, else returns `None`. + /// + /// In particular, if the input is zero (or very close to zero), or non-finite, + /// the result of this operation will be `None`. + /// + /// See also [`Self::normalize_or_zero`]. + #[must_use] + #[inline] + pub fn try_normalize(self) -> Option { + let rcp = self.length_recip(); + if rcp.is_finite() && rcp > 0.0 { + Some(self * rcp) + } else { + None + } + } + + /// Returns `self` normalized to length 1.0 if possible, else returns zero. + /// + /// In particular, if the input is zero (or very close to zero), or non-finite, + /// the result of this operation will be zero. + /// + /// See also [`Self::try_normalize`]. + #[must_use] + #[inline] + pub fn normalize_or_zero(self) -> Self { + let rcp = self.length_recip(); + if rcp.is_finite() && rcp > 0.0 { + self * rcp + } else { + Self::ZERO + } + } + + /// Returns whether `self` is length `1.0` or not. + /// + /// Uses a precision threshold of `1e-6`. + #[inline] + pub fn is_normalized(self) -> bool { + // TODO: do something with epsilon + (self.length_squared() - 1.0).abs() <= 1e-4 + } + + /// Returns the vector projection of `self` onto `rhs`. + /// + /// `rhs` must be of non-zero length. + /// + /// # Panics + /// + /// Will panic if `rhs` is zero length when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn project_onto(self, rhs: Self) -> Self { + let other_len_sq_rcp = rhs.dot(rhs).recip(); + glam_assert!(other_len_sq_rcp.is_finite()); + rhs * self.dot(rhs) * other_len_sq_rcp + } + + /// Returns the vector rejection of `self` from `rhs`. + /// + /// The vector rejection is the vector perpendicular to the projection of `self` onto + /// `rhs`, in rhs words the result of `self - self.project_onto(rhs)`. + /// + /// `rhs` must be of non-zero length. + /// + /// # Panics + /// + /// Will panic if `rhs` has a length of zero when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn reject_from(self, rhs: Self) -> Self { + self - self.project_onto(rhs) + } + + /// Returns the vector projection of `self` onto `rhs`. + /// + /// `rhs` must be normalized. + /// + /// # Panics + /// + /// Will panic if `rhs` is not normalized when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn project_onto_normalized(self, rhs: Self) -> Self { + glam_assert!(rhs.is_normalized()); + rhs * self.dot(rhs) + } + + /// Returns the vector rejection of `self` from `rhs`. + /// + /// The vector rejection is the vector perpendicular to the projection of `self` onto + /// `rhs`, in rhs words the result of `self - self.project_onto(rhs)`. + /// + /// `rhs` must be normalized. + /// + /// # Panics + /// + /// Will panic if `rhs` is not normalized when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn reject_from_normalized(self, rhs: Self) -> Self { + self - self.project_onto_normalized(rhs) + } + + /// Returns a vector containing the nearest integer to a number for each element of `self`. + /// Round half-way cases away from 0.0. + #[inline] + pub fn round(self) -> Self { + Self { + x: self.x.round(), + y: self.y.round(), + z: self.z.round(), + w: self.w.round(), + } + } + + /// Returns a vector containing the largest integer less than or equal to a number for each + /// element of `self`. + #[inline] + pub fn floor(self) -> Self { + Self { + x: self.x.floor(), + y: self.y.floor(), + z: self.z.floor(), + w: self.w.floor(), + } + } + + /// Returns a vector containing the smallest integer greater than or equal to a number for + /// each element of `self`. + #[inline] + pub fn ceil(self) -> Self { + Self { + x: self.x.ceil(), + y: self.y.ceil(), + z: self.z.ceil(), + w: self.w.ceil(), + } + } + + /// Returns a vector containing the fractional part of the vector, e.g. `self - + /// self.floor()`. + /// + /// Note that this is fast but not precise for large numbers. + #[inline] + pub fn fract(self) -> Self { + self - self.floor() + } + + /// Returns a vector containing `e^self` (the exponential function) for each element of + /// `self`. + #[inline] + pub fn exp(self) -> Self { + Self::new(self.x.exp(), self.y.exp(), self.z.exp(), self.w.exp()) + } + + /// Returns a vector containing each element of `self` raised to the power of `n`. + #[inline] + pub fn powf(self, n: f32) -> Self { + Self::new( + self.x.powf(n), + self.y.powf(n), + self.z.powf(n), + self.w.powf(n), + ) + } + + /// Returns a vector containing the reciprocal `1.0/n` of each element of `self`. + #[inline] + pub fn recip(self) -> Self { + Self { + x: self.x.recip(), + y: self.y.recip(), + z: self.z.recip(), + w: self.w.recip(), + } + } + + /// Performs a linear interpolation between `self` and `rhs` based on the value `s`. + /// + /// When `s` is `0.0`, the result will be equal to `self`. When `s` is `1.0`, the result + /// will be equal to `rhs`. When `s` is outside of range `[0, 1]`, the result is linearly + /// extrapolated. + #[doc(alias = "mix")] + #[inline] + pub fn lerp(self, rhs: Self, s: f32) -> Self { + self + ((rhs - self) * s) + } + + /// Returns true if the absolute difference of all elements between `self` and `rhs` is + /// less than or equal to `max_abs_diff`. + /// + /// This can be used to compare if two vectors contain similar elements. It works best when + /// comparing with a known value. The `max_abs_diff` that should be used used depends on + /// the values being compared against. + /// + /// For more see + /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/). + #[inline] + pub fn abs_diff_eq(self, rhs: Self, max_abs_diff: f32) -> bool { + self.sub(rhs).abs().cmple(Self::splat(max_abs_diff)).all() + } + + /// Returns a vector with a length no less than `min` and no more than `max` + /// + /// # Panics + /// + /// Will panic if `min` is greater than `max` when `glam_assert` is enabled. + #[inline] + pub fn clamp_length(self, min: f32, max: f32) -> Self { + glam_assert!(min <= max); + let length_sq = self.length_squared(); + if length_sq < min * min { + self * (length_sq.sqrt().recip() * min) + } else if length_sq > max * max { + self * (length_sq.sqrt().recip() * max) + } else { + self + } + } + + /// Returns a vector with a length no more than `max` + pub fn clamp_length_max(self, max: f32) -> Self { + let length_sq = self.length_squared(); + if length_sq > max * max { + self * (length_sq.sqrt().recip() * max) + } else { + self + } + } + + /// Returns a vector with a length no less than `min` + pub fn clamp_length_min(self, min: f32) -> Self { + let length_sq = self.length_squared(); + if length_sq < min * min { + self * (length_sq.sqrt().recip() * min) + } else { + self + } + } + + /// Fused multiply-add. Computes `(self * a) + b` element-wise with only one rounding + /// error, yielding a more accurate result than an unfused multiply-add. + /// + /// Using `mul_add` *may* be more performant than an unfused multiply-add if the target + /// architecture has a dedicated fma CPU instruction. However, this is not always true, + /// and will be heavily dependant on designing algorithms with specific target hardware in + /// mind. + #[inline] + pub fn mul_add(self, a: Self, b: Self) -> Self { + Self::new( + self.x.mul_add(a.x, b.x), + self.y.mul_add(a.y, b.y), + self.z.mul_add(a.z, b.z), + self.w.mul_add(a.w, b.w), + ) + } + + /// Casts all elements of `self` to `f64`. + #[inline] + pub fn as_dvec4(&self) -> crate::DVec4 { + crate::DVec4::new(self.x as f64, self.y as f64, self.z as f64, self.w as f64) + } + + /// Casts all elements of `self` to `i32`. + #[inline] + pub fn as_ivec4(&self) -> crate::IVec4 { + crate::IVec4::new(self.x as i32, self.y as i32, self.z as i32, self.w as i32) + } + + /// Casts all elements of `self` to `u32`. + #[inline] + pub fn as_uvec4(&self) -> crate::UVec4 { + crate::UVec4::new(self.x as u32, self.y as u32, self.z as u32, self.w as u32) + } +} + +impl Default for Vec4 { + #[inline(always)] + fn default() -> Self { + Self::ZERO + } +} + +impl PartialEq for Vec4 { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.cmpeq(*rhs).all() + } +} + +impl Div for Vec4 { + type Output = Self; + #[inline] + fn div(self, rhs: Self) -> Self { + Self { + x: self.x.div(rhs.x), + y: self.y.div(rhs.y), + z: self.z.div(rhs.z), + w: self.w.div(rhs.w), + } + } +} + +impl DivAssign for Vec4 { + #[inline] + fn div_assign(&mut self, rhs: Self) { + self.x.div_assign(rhs.x); + self.y.div_assign(rhs.y); + self.z.div_assign(rhs.z); + self.w.div_assign(rhs.w); + } +} + +impl Div for Vec4 { + type Output = Self; + #[inline] + fn div(self, rhs: f32) -> Self { + Self { + x: self.x.div(rhs), + y: self.y.div(rhs), + z: self.z.div(rhs), + w: self.w.div(rhs), + } + } +} + +impl DivAssign for Vec4 { + #[inline] + fn div_assign(&mut self, rhs: f32) { + self.x.div_assign(rhs); + self.y.div_assign(rhs); + self.z.div_assign(rhs); + self.w.div_assign(rhs); + } +} + +impl Div for f32 { + type Output = Vec4; + #[inline] + fn div(self, rhs: Vec4) -> Vec4 { + Vec4 { + x: self.div(rhs.x), + y: self.div(rhs.y), + z: self.div(rhs.z), + w: self.div(rhs.w), + } + } +} + +impl Mul for Vec4 { + type Output = Self; + #[inline] + fn mul(self, rhs: Self) -> Self { + Self { + x: self.x.mul(rhs.x), + y: self.y.mul(rhs.y), + z: self.z.mul(rhs.z), + w: self.w.mul(rhs.w), + } + } +} + +impl MulAssign for Vec4 { + #[inline] + fn mul_assign(&mut self, rhs: Self) { + self.x.mul_assign(rhs.x); + self.y.mul_assign(rhs.y); + self.z.mul_assign(rhs.z); + self.w.mul_assign(rhs.w); + } +} + +impl Mul for Vec4 { + type Output = Self; + #[inline] + fn mul(self, rhs: f32) -> Self { + Self { + x: self.x.mul(rhs), + y: self.y.mul(rhs), + z: self.z.mul(rhs), + w: self.w.mul(rhs), + } + } +} + +impl MulAssign for Vec4 { + #[inline] + fn mul_assign(&mut self, rhs: f32) { + self.x.mul_assign(rhs); + self.y.mul_assign(rhs); + self.z.mul_assign(rhs); + self.w.mul_assign(rhs); + } +} + +impl Mul for f32 { + type Output = Vec4; + #[inline] + fn mul(self, rhs: Vec4) -> Vec4 { + Vec4 { + x: self.mul(rhs.x), + y: self.mul(rhs.y), + z: self.mul(rhs.z), + w: self.mul(rhs.w), + } + } +} + +impl Add for Vec4 { + type Output = Self; + #[inline] + fn add(self, rhs: Self) -> Self { + Self { + x: self.x.add(rhs.x), + y: self.y.add(rhs.y), + z: self.z.add(rhs.z), + w: self.w.add(rhs.w), + } + } +} + +impl AddAssign for Vec4 { + #[inline] + fn add_assign(&mut self, rhs: Self) { + self.x.add_assign(rhs.x); + self.y.add_assign(rhs.y); + self.z.add_assign(rhs.z); + self.w.add_assign(rhs.w); + } +} + +impl Add for Vec4 { + type Output = Self; + #[inline] + fn add(self, rhs: f32) -> Self { + Self { + x: self.x.add(rhs), + y: self.y.add(rhs), + z: self.z.add(rhs), + w: self.w.add(rhs), + } + } +} + +impl AddAssign for Vec4 { + #[inline] + fn add_assign(&mut self, rhs: f32) { + self.x.add_assign(rhs); + self.y.add_assign(rhs); + self.z.add_assign(rhs); + self.w.add_assign(rhs); + } +} + +impl Add for f32 { + type Output = Vec4; + #[inline] + fn add(self, rhs: Vec4) -> Vec4 { + Vec4 { + x: self.add(rhs.x), + y: self.add(rhs.y), + z: self.add(rhs.z), + w: self.add(rhs.w), + } + } +} + +impl Sub for Vec4 { + type Output = Self; + #[inline] + fn sub(self, rhs: Self) -> Self { + Self { + x: self.x.sub(rhs.x), + y: self.y.sub(rhs.y), + z: self.z.sub(rhs.z), + w: self.w.sub(rhs.w), + } + } +} + +impl SubAssign for Vec4 { + #[inline] + fn sub_assign(&mut self, rhs: Vec4) { + self.x.sub_assign(rhs.x); + self.y.sub_assign(rhs.y); + self.z.sub_assign(rhs.z); + self.w.sub_assign(rhs.w); + } +} + +impl Sub for Vec4 { + type Output = Self; + #[inline] + fn sub(self, rhs: f32) -> Self { + Self { + x: self.x.sub(rhs), + y: self.y.sub(rhs), + z: self.z.sub(rhs), + w: self.w.sub(rhs), + } + } +} + +impl SubAssign for Vec4 { + #[inline] + fn sub_assign(&mut self, rhs: f32) { + self.x.sub_assign(rhs); + self.y.sub_assign(rhs); + self.z.sub_assign(rhs); + self.w.sub_assign(rhs); + } +} + +impl Sub for f32 { + type Output = Vec4; + #[inline] + fn sub(self, rhs: Vec4) -> Vec4 { + Vec4 { + x: self.sub(rhs.x), + y: self.sub(rhs.y), + z: self.sub(rhs.z), + w: self.sub(rhs.w), + } + } +} + +impl Rem for Vec4 { + type Output = Self; + #[inline] + fn rem(self, rhs: Self) -> Self { + Self { + x: self.x.rem(rhs.x), + y: self.y.rem(rhs.y), + z: self.z.rem(rhs.z), + w: self.w.rem(rhs.w), + } + } +} + +impl RemAssign for Vec4 { + #[inline] + fn rem_assign(&mut self, rhs: Self) { + self.x.rem_assign(rhs.x); + self.y.rem_assign(rhs.y); + self.z.rem_assign(rhs.z); + self.w.rem_assign(rhs.w); + } +} + +impl Rem for Vec4 { + type Output = Self; + #[inline] + fn rem(self, rhs: f32) -> Self { + Self { + x: self.x.rem(rhs), + y: self.y.rem(rhs), + z: self.z.rem(rhs), + w: self.w.rem(rhs), + } + } +} + +impl RemAssign for Vec4 { + #[inline] + fn rem_assign(&mut self, rhs: f32) { + self.x.rem_assign(rhs); + self.y.rem_assign(rhs); + self.z.rem_assign(rhs); + self.w.rem_assign(rhs); + } +} + +impl Rem for f32 { + type Output = Vec4; + #[inline] + fn rem(self, rhs: Vec4) -> Vec4 { + Vec4 { + x: self.rem(rhs.x), + y: self.rem(rhs.y), + z: self.rem(rhs.z), + w: self.rem(rhs.w), + } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsRef<[f32; 4]> for Vec4 { + #[inline] + fn as_ref(&self) -> &[f32; 4] { + unsafe { &*(self as *const Vec4 as *const [f32; 4]) } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsMut<[f32; 4]> for Vec4 { + #[inline] + fn as_mut(&mut self) -> &mut [f32; 4] { + unsafe { &mut *(self as *mut Vec4 as *mut [f32; 4]) } + } +} + +impl<'a> Sum<&'a Self> for Vec4 { + #[inline] + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, |a, &b| Self::add(a, b)) + } +} + +impl<'a> Product<&'a Self> for Vec4 { + #[inline] + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ONE, |a, &b| Self::mul(a, b)) + } +} + +impl Neg for Vec4 { + type Output = Self; + #[inline] + fn neg(self) -> Self { + Self { + x: self.x.neg(), + y: self.y.neg(), + z: self.z.neg(), + w: self.w.neg(), + } + } +} + +impl Index for Vec4 { + type Output = f32; + #[inline] + fn index(&self, index: usize) -> &Self::Output { + match index { + 0 => &self.x, + 1 => &self.y, + 2 => &self.z, + 3 => &self.w, + _ => panic!("index out of bounds"), + } + } +} + +impl IndexMut for Vec4 { + #[inline] + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + match index { + 0 => &mut self.x, + 1 => &mut self.y, + 2 => &mut self.z, + 3 => &mut self.w, + _ => panic!("index out of bounds"), + } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Display for Vec4 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "[{}, {}, {}, {}]", self.x, self.y, self.z, self.w) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Debug for Vec4 { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_tuple(stringify!(Vec4)) + .field(&self.x) + .field(&self.y) + .field(&self.z) + .field(&self.w) + .finish() + } +} + +impl From<[f32; 4]> for Vec4 { + #[inline] + fn from(a: [f32; 4]) -> Self { + Self::new(a[0], a[1], a[2], a[3]) + } +} + +impl From for [f32; 4] { + #[inline] + fn from(v: Vec4) -> Self { + [v.x, v.y, v.z, v.w] + } +} + +impl From<(f32, f32, f32, f32)> for Vec4 { + #[inline] + fn from(t: (f32, f32, f32, f32)) -> Self { + Self::new(t.0, t.1, t.2, t.3) + } +} + +impl From for (f32, f32, f32, f32) { + #[inline] + fn from(v: Vec4) -> Self { + (v.x, v.y, v.z, v.w) + } +} + +impl From<(Vec3A, f32)> for Vec4 { + #[inline] + fn from((v, w): (Vec3A, f32)) -> Self { + v.extend(w) + } +} + +impl From<(f32, Vec3A)> for Vec4 { + #[inline] + fn from((x, v): (f32, Vec3A)) -> Self { + Self::new(x, v.x, v.y, v.z) + } +} + +impl From<(Vec3, f32)> for Vec4 { + #[inline] + fn from((v, w): (Vec3, f32)) -> Self { + Self::new(v.x, v.y, v.z, w) + } +} + +impl From<(f32, Vec3)> for Vec4 { + #[inline] + fn from((x, v): (f32, Vec3)) -> Self { + Self::new(x, v.x, v.y, v.z) + } +} + +impl From<(Vec2, f32, f32)> for Vec4 { + #[inline] + fn from((v, z, w): (Vec2, f32, f32)) -> Self { + Self::new(v.x, v.y, z, w) + } +} + +impl From<(Vec2, Vec2)> for Vec4 { + #[inline] + fn from((v, u): (Vec2, Vec2)) -> Self { + Self::new(v.x, v.y, u.x, u.y) + } +} diff --git a/src/f32/sse2.rs b/src/f32/sse2.rs new file mode 100644 index 00000000..24171e51 --- /dev/null +++ b/src/f32/sse2.rs @@ -0,0 +1,6 @@ +pub mod mat2; +pub mod mat3a; +pub mod mat4; +pub mod quat; +pub mod vec3a; +pub mod vec4; diff --git a/src/f32/sse2/mat2.rs b/src/f32/sse2/mat2.rs new file mode 100644 index 00000000..053aaf1d --- /dev/null +++ b/src/f32/sse2/mat2.rs @@ -0,0 +1,479 @@ +// Generated from mat.rs template. Edit the template, not the generated file. + +use crate::{swizzles::*, DMat2, Mat3, Vec2}; +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::iter::{Product, Sum}; +use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; + +#[cfg(target_arch = "x86")] +use core::arch::x86::*; +#[cfg(target_arch = "x86_64")] +use core::arch::x86_64::*; + +#[cfg(not(feature = "std"))] +use num_traits::Float; + +union UnionCast { + a: [f32; 4], + v: Mat2, +} + +/// Creates a 2x2 matrix from column vectors. +#[inline(always)] +pub const fn mat2(x_axis: Vec2, y_axis: Vec2) -> Mat2 { + Mat2::from_cols(x_axis, y_axis) +} + +/// A 2x2 column major matrix. +#[derive(Clone, Copy)] +#[repr(transparent)] +pub struct Mat2(pub(crate) __m128); + +impl Mat2 { + /// A 2x2 matrix with all elements set to `0.0`. + pub const ZERO: Self = Self::from_cols(Vec2::ZERO, Vec2::ZERO); + + /// A 2x2 identity matrix, where all diagonal elements are `1`, and all off-diagonal elements are `0`. + pub const IDENTITY: Self = Self::from_cols(Vec2::X, Vec2::Y); + + /// All NAN:s. + pub const NAN: Self = Self::from_cols(Vec2::NAN, Vec2::NAN); + + #[allow(clippy::too_many_arguments)] + #[inline(always)] + const fn new(m00: f32, m01: f32, m10: f32, m11: f32) -> Self { + unsafe { + UnionCast { + a: [m00, m01, m10, m11], + } + .v + } + } + + /// Creates a 2x2 matrix from two column vectors. + #[inline(always)] + pub const fn from_cols(x_axis: Vec2, y_axis: Vec2) -> Self { + unsafe { + UnionCast { + a: [x_axis.x, x_axis.y, y_axis.x, y_axis.y], + } + .v + } + } + + /// Creates a 2x2 matrix from a `[f32; 4]` array stored in column major order. + /// If your data is stored in row major you will need to `transpose` the returned + /// matrix. + #[inline] + pub const fn from_cols_array(m: &[f32; 4]) -> Self { + Self::new(m[0], m[1], m[2], m[3]) + } + + /// Creates a `[f32; 4]` array storing data in column major order. + /// If you require data in row major order `transpose` the matrix first. + #[inline] + pub fn to_cols_array(&self) -> [f32; 4] { + [self.x_axis.x, self.x_axis.y, self.y_axis.x, self.y_axis.y] + } + + /// Creates a 2x2 matrix from a `[[f32; 2]; 2]` 2D array stored in column major order. + /// If your data is in row major order you will need to `transpose` the returned + /// matrix. + #[inline] + pub const fn from_cols_array_2d(m: &[[f32; 2]; 2]) -> Self { + Self::from_cols(Vec2::from_array(m[0]), Vec2::from_array(m[1])) + } + + /// Creates a `[[f32; 2]; 2]` 2D array storing data in column major order. + /// If you require data in row major order `transpose` the matrix first. + #[inline] + pub fn to_cols_array_2d(&self) -> [[f32; 2]; 2] { + [self.x_axis.to_array(), self.y_axis.to_array()] + } + + /// Creates a 2x2 matrix with its diagonal set to `diagonal` and all other entries set to 0. + #[doc(alias = "scale")] + #[inline] + pub fn from_diagonal(diagonal: Vec2) -> Self { + Self::new(diagonal.x, 0.0, 0.0, diagonal.y) + } + + /// Creates a 2x2 matrix containing the combining non-uniform `scale` and rotation of + /// `angle` (in radians). + #[inline] + pub fn from_scale_angle(scale: Vec2, angle: f32) -> Self { + let (sin, cos) = angle.sin_cos(); + Self::new(cos * scale.x, sin * scale.x, -sin * scale.y, cos * scale.y) + } + + /// Creates a 2x2 matrix containing a rotation of `angle` (in radians). + #[inline] + pub fn from_angle(angle: f32) -> Self { + let (sin, cos) = angle.sin_cos(); + Self::new(cos, sin, -sin, cos) + } + + /// Creates a 2x2 matrix from a 3x3 matrix, discarding the 2nd row and column. + #[inline] + pub fn from_mat3(m: Mat3) -> Self { + Self::from_cols(m.x_axis.xy(), m.y_axis.xy()) + } + + /// Creates a 2x2 matrix from the first 4 values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 4 elements long. + #[inline] + pub const fn from_cols_slice(slice: &[f32]) -> Self { + Self::new(slice[0], slice[1], slice[2], slice[3]) + } + + /// Writes the columns of `self` to the first 4 elements in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 4 elements long. + #[inline] + pub fn write_cols_to_slice(self, slice: &mut [f32]) { + slice[0] = self.x_axis.x; + slice[1] = self.x_axis.y; + slice[2] = self.y_axis.x; + slice[3] = self.y_axis.y; + } + + /// Returns the matrix column for the given `index`. + /// + /// # Panics + /// + /// Panics if `index` is greater than 1. + #[inline] + pub fn col(&self, index: usize) -> Vec2 { + match index { + 0 => self.x_axis, + 1 => self.y_axis, + _ => panic!("index out of bounds"), + } + } + + /// Returns a mutable reference to the matrix column for the given `index`. + /// + /// # Panics + /// + /// Panics if `index` is greater than 1. + #[inline] + pub fn col_mut(&mut self, index: usize) -> &mut Vec2 { + match index { + 0 => &mut self.x_axis, + 1 => &mut self.y_axis, + _ => panic!("index out of bounds"), + } + } + + /// Returns the matrix row for the given `index`. + /// + /// # Panics + /// + /// Panics if `index` is greater than 1. + #[inline] + pub fn row(&self, index: usize) -> Vec2 { + match index { + 0 => Vec2::new(self.x_axis.x, self.y_axis.x), + 1 => Vec2::new(self.x_axis.y, self.y_axis.y), + _ => panic!("index out of bounds"), + } + } + + /// Returns `true` if, and only if, all elements are finite. + /// If any element is either `NaN`, positive or negative infinity, this will return `false`. + #[inline] + pub fn is_finite(&self) -> bool { + self.x_axis.is_finite() && self.y_axis.is_finite() + } + + /// Returns `true` if any elements are `NaN`. + #[inline] + pub fn is_nan(&self) -> bool { + self.x_axis.is_nan() || self.y_axis.is_nan() + } + + /// Returns the transpose of `self`. + #[must_use] + #[inline] + pub fn transpose(&self) -> Self { + Self(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_01_10_00) }) + } + + /// Returns the determinant of `self`. + #[inline] + pub fn determinant(&self) -> f32 { + unsafe { + let abcd = self.0; + let dcba = _mm_shuffle_ps(abcd, abcd, 0b00_01_10_11); + let prod = _mm_mul_ps(abcd, dcba); + let det = _mm_sub_ps(prod, _mm_shuffle_ps(prod, prod, 0b01_01_01_01)); + _mm_cvtss_f32(det) + } + } + + /// Returns the inverse of `self`. + /// + /// If the matrix is not invertible the returned matrix will be invalid. + /// + /// # Panics + /// + /// Will panic if the determinant of `self` is zero when `glam_assert` is enabled. + #[must_use] + pub fn inverse(&self) -> Self { + unsafe { + const SIGN: __m128 = const_f32x4!([1.0, -1.0, -1.0, 1.0]); + let abcd = self.0; + let dcba = _mm_shuffle_ps(abcd, abcd, 0b00_01_10_11); + let prod = _mm_mul_ps(abcd, dcba); + let sub = _mm_sub_ps(prod, _mm_shuffle_ps(prod, prod, 0b01_01_01_01)); + let det = _mm_shuffle_ps(sub, sub, 0b00_00_00_00); + let tmp = _mm_div_ps(SIGN, det); + glam_assert!(Mat2(tmp).is_finite()); + let dbca = _mm_shuffle_ps(abcd, abcd, 0b00_10_01_11); + Self(_mm_mul_ps(dbca, tmp)) + } + } + + /// Transforms a 2D vector. + #[inline] + pub fn mul_vec2(&self, rhs: Vec2) -> Vec2 { + unsafe { + use crate::Align16; + use core::mem::MaybeUninit; + let abcd = self.0; + let xxyy = _mm_set_ps(rhs.y, rhs.y, rhs.x, rhs.x); + let axbxcydy = _mm_mul_ps(abcd, xxyy); + let cydyaxbx = _mm_shuffle_ps(axbxcydy, axbxcydy, 0b01_00_11_10); + let result = _mm_add_ps(axbxcydy, cydyaxbx); + let mut out: MaybeUninit> = MaybeUninit::uninit(); + _mm_store_ps(out.as_mut_ptr().cast(), result); + out.assume_init().0 + } + } + + /// Multiplies two 2x2 matrices. + #[inline] + pub fn mul_mat2(&self, rhs: &Self) -> Self { + unsafe { + let abcd = self.0; + let rhs = rhs.0; + let xxyy0 = _mm_shuffle_ps(rhs, rhs, 0b01_01_00_00); + let xxyy1 = _mm_shuffle_ps(rhs, rhs, 0b11_11_10_10); + let axbxcydy0 = _mm_mul_ps(abcd, xxyy0); + let axbxcydy1 = _mm_mul_ps(abcd, xxyy1); + let cydyaxbx0 = _mm_shuffle_ps(axbxcydy0, axbxcydy0, 0b01_00_11_10); + let cydyaxbx1 = _mm_shuffle_ps(axbxcydy1, axbxcydy1, 0b01_00_11_10); + let result0 = _mm_add_ps(axbxcydy0, cydyaxbx0); + let result1 = _mm_add_ps(axbxcydy1, cydyaxbx1); + Self(_mm_shuffle_ps(result0, result1, 0b01_00_01_00)) + } + } + + /// Adds two 2x2 matrices. + #[inline] + pub fn add_mat2(&self, rhs: &Self) -> Self { + Self(unsafe { _mm_add_ps(self.0, rhs.0) }) + } + + /// Subtracts two 2x2 matrices. + #[inline] + pub fn sub_mat2(&self, rhs: &Self) -> Self { + Self(unsafe { _mm_sub_ps(self.0, rhs.0) }) + } + + /// Multiplies a 2x2 matrix by a scalar. + #[inline] + pub fn mul_scalar(&self, rhs: f32) -> Self { + Self(unsafe { _mm_mul_ps(self.0, _mm_set_ps1(rhs)) }) + } + + /// Returns true if the absolute difference of all elements between `self` and `rhs` + /// is less than or equal to `max_abs_diff`. + /// + /// This can be used to compare if two matrices contain similar elements. It works best + /// when comparing with a known value. The `max_abs_diff` that should be used used + /// depends on the values being compared against. + /// + /// For more see + /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/). + #[inline] + pub fn abs_diff_eq(&self, rhs: Self, max_abs_diff: f32) -> bool { + self.x_axis.abs_diff_eq(rhs.x_axis, max_abs_diff) + && self.y_axis.abs_diff_eq(rhs.y_axis, max_abs_diff) + } + + #[inline] + pub fn as_dmat2(&self) -> DMat2 { + DMat2::from_cols(self.x_axis.as_dvec2(), self.y_axis.as_dvec2()) + } +} + +impl Default for Mat2 { + #[inline] + fn default() -> Self { + Self::IDENTITY + } +} + +impl Add for Mat2 { + type Output = Self; + #[inline] + fn add(self, rhs: Self) -> Self::Output { + self.add_mat2(&rhs) + } +} + +impl AddAssign for Mat2 { + #[inline] + fn add_assign(&mut self, rhs: Self) { + *self = self.add_mat2(&rhs); + } +} + +impl Sub for Mat2 { + type Output = Self; + #[inline] + fn sub(self, rhs: Self) -> Self::Output { + self.sub_mat2(&rhs) + } +} + +impl SubAssign for Mat2 { + #[inline] + fn sub_assign(&mut self, rhs: Self) { + *self = self.sub_mat2(&rhs); + } +} + +impl Neg for Mat2 { + type Output = Self; + #[inline] + fn neg(self) -> Self::Output { + Self(unsafe { _mm_xor_ps(self.0, _mm_set1_ps(-0.0)) }) + } +} + +impl Mul for Mat2 { + type Output = Self; + #[inline] + fn mul(self, rhs: Self) -> Self::Output { + self.mul_mat2(&rhs) + } +} + +impl MulAssign for Mat2 { + #[inline] + fn mul_assign(&mut self, rhs: Self) { + *self = self.mul_mat2(&rhs); + } +} + +impl Mul for Mat2 { + type Output = Vec2; + #[inline] + fn mul(self, rhs: Vec2) -> Self::Output { + self.mul_vec2(rhs) + } +} + +impl Mul for f32 { + type Output = Mat2; + #[inline] + fn mul(self, rhs: Mat2) -> Self::Output { + rhs.mul_scalar(self) + } +} + +impl Mul for Mat2 { + type Output = Self; + #[inline] + fn mul(self, rhs: f32) -> Self::Output { + self.mul_scalar(rhs) + } +} + +impl MulAssign for Mat2 { + #[inline] + fn mul_assign(&mut self, rhs: f32) { + *self = self.mul_scalar(rhs); + } +} + +impl<'a> Sum<&'a Self> for Mat2 { + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, |a, &b| Self::add(a, b)) + } +} + +impl<'a> Product<&'a Self> for Mat2 { + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::IDENTITY, |a, &b| Self::mul(a, b)) + } +} + +impl PartialEq for Mat2 { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.x_axis.eq(&rhs.x_axis) && self.y_axis.eq(&rhs.y_axis) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsRef<[f32; 4]> for Mat2 { + #[inline] + fn as_ref(&self) -> &[f32; 4] { + unsafe { &*(self as *const Self as *const [f32; 4]) } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsMut<[f32; 4]> for Mat2 { + #[inline] + fn as_mut(&mut self) -> &mut [f32; 4] { + unsafe { &mut *(self as *mut Self as *mut [f32; 4]) } + } +} + +impl core::ops::Deref for Mat2 { + type Target = crate::deref::Columns2; + #[inline] + fn deref(&self) -> &Self::Target { + unsafe { &*(self as *const Self as *const Self::Target) } + } +} + +impl core::ops::DerefMut for Mat2 { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { &mut *(self as *mut Self as *mut Self::Target) } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Debug for Mat2 { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct(stringify!(Mat2)) + .field("x_axis", &self.x_axis) + .field("y_axis", &self.y_axis) + .finish() + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Display for Mat2 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "[{}, {}]", self.x_axis, self.y_axis) + } +} diff --git a/src/f32/sse2/mat3a.rs b/src/f32/sse2/mat3a.rs new file mode 100644 index 00000000..87e52d4a --- /dev/null +++ b/src/f32/sse2/mat3a.rs @@ -0,0 +1,703 @@ +// Generated from mat.rs template. Edit the template, not the generated file. + +use crate::{swizzles::*, DMat3, EulerRot, Mat2, Mat3, Mat4, Quat, Vec2, Vec3, Vec3A}; +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::iter::{Product, Sum}; +use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; + +#[cfg(target_arch = "x86")] +use core::arch::x86::*; +#[cfg(target_arch = "x86_64")] +use core::arch::x86_64::*; + +#[cfg(not(feature = "std"))] +use num_traits::Float; + +/// Creates a 3x3 matrix from column vectors. +#[inline(always)] +pub const fn mat3a(x_axis: Vec3A, y_axis: Vec3A, z_axis: Vec3A) -> Mat3A { + Mat3A::from_cols(x_axis, y_axis, z_axis) +} + +/// A 3x3 column major matrix. +/// +/// This 3x3 matrix type features convenience methods for creating and using linear and +/// affine transformations. If you are primarily dealing with 2D affine transformations the +/// [`Affine2`](crate::Affine2) type is much faster and more space efficient than +/// using a 3x3 matrix. +/// +/// Linear transformations including 3D rotation and scale can be created using methods +/// such as [`Self::from_diagonal()`], [`Self::from_quat()`], [`Self::from_axis_angle()`], +/// [`Self::from_rotation_x()`], [`Self::from_rotation_y()`], or +/// [`Self::from_rotation_z()`]. +/// +/// The resulting matrices can be use to transform 3D vectors using regular vector +/// multiplication. +/// +/// Affine transformations including 2D translation, rotation and scale can be created +/// using methods such as [`Self::from_translation()`], [`Self::from_angle()`], +/// [`Self::from_scale()`] and [`Self::from_scale_angle_translation()`]. +/// +/// The [`Self::transform_point2()`] and [`Self::transform_vector2()`] convenience methods +/// are provided for performing affine transforms on 2D vectors and points. These multiply +/// 2D inputs as 3D vectors with an implicit `z` value of `1` for points and `0` for +/// vectors respectively. These methods assume that `Self` contains a valid affine +/// transform. +#[derive(Clone, Copy)] +pub struct Mat3A { + pub x_axis: Vec3A, + pub y_axis: Vec3A, + pub z_axis: Vec3A, +} + +impl Mat3A { + /// A 3x3 matrix with all elements set to `0.0`. + pub const ZERO: Self = Self::from_cols(Vec3A::ZERO, Vec3A::ZERO, Vec3A::ZERO); + + /// A 3x3 identity matrix, where all diagonal elements are `1`, and all off-diagonal elements are `0`. + pub const IDENTITY: Self = Self::from_cols(Vec3A::X, Vec3A::Y, Vec3A::Z); + + /// All NAN:s. + pub const NAN: Self = Self::from_cols(Vec3A::NAN, Vec3A::NAN, Vec3A::NAN); + + #[allow(clippy::too_many_arguments)] + #[inline(always)] + const fn new( + m00: f32, + m01: f32, + m02: f32, + m10: f32, + m11: f32, + m12: f32, + m20: f32, + m21: f32, + m22: f32, + ) -> Self { + Self { + x_axis: Vec3A::new(m00, m01, m02), + y_axis: Vec3A::new(m10, m11, m12), + z_axis: Vec3A::new(m20, m21, m22), + } + } + + /// Creates a 3x3 matrix from two column vectors. + #[inline(always)] + pub const fn from_cols(x_axis: Vec3A, y_axis: Vec3A, z_axis: Vec3A) -> Self { + Self { + x_axis, + y_axis, + z_axis, + } + } + + /// Creates a 3x3 matrix from a `[f32; 9]` array stored in column major order. + /// If your data is stored in row major you will need to `transpose` the returned + /// matrix. + #[inline] + pub const fn from_cols_array(m: &[f32; 9]) -> Self { + Self::new(m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8]) + } + + /// Creates a `[f32; 9]` array storing data in column major order. + /// If you require data in row major order `transpose` the matrix first. + #[inline] + pub fn to_cols_array(&self) -> [f32; 9] { + [ + self.x_axis.x, + self.x_axis.y, + self.x_axis.z, + self.y_axis.x, + self.y_axis.y, + self.y_axis.z, + self.z_axis.x, + self.z_axis.y, + self.z_axis.z, + ] + } + + /// Creates a 3x3 matrix from a `[[f32; 3]; 3]` 3D array stored in column major order. + /// If your data is in row major order you will need to `transpose` the returned + /// matrix. + #[inline] + pub const fn from_cols_array_2d(m: &[[f32; 3]; 3]) -> Self { + Self::from_cols( + Vec3A::from_array(m[0]), + Vec3A::from_array(m[1]), + Vec3A::from_array(m[2]), + ) + } + + /// Creates a `[[f32; 3]; 3]` 3D array storing data in column major order. + /// If you require data in row major order `transpose` the matrix first. + #[inline] + pub fn to_cols_array_2d(&self) -> [[f32; 3]; 3] { + [ + self.x_axis.to_array(), + self.y_axis.to_array(), + self.z_axis.to_array(), + ] + } + + /// Creates a 3x3 matrix with its diagonal set to `diagonal` and all other entries set to 0. + #[doc(alias = "scale")] + #[inline] + pub fn from_diagonal(diagonal: Vec3) -> Self { + Self::new( + diagonal.x, 0.0, 0.0, 0.0, diagonal.y, 0.0, 0.0, 0.0, diagonal.z, + ) + } + + /// Creates a 3x3 matrix from a 4x4 matrix, discarding the 3rd row and column. + pub fn from_mat4(m: Mat4) -> Self { + Self::from_cols(m.x_axis.into(), m.y_axis.into(), m.z_axis.into()) + } + + /// Creates a 3D rotation matrix from the given quaternion. + /// + /// # Panics + /// + /// Will panic if `rotation` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn from_quat(rotation: Quat) -> Self { + glam_assert!(rotation.is_normalized()); + + let x2 = rotation.x + rotation.x; + let y2 = rotation.y + rotation.y; + let z2 = rotation.z + rotation.z; + let xx = rotation.x * x2; + let xy = rotation.x * y2; + let xz = rotation.x * z2; + let yy = rotation.y * y2; + let yz = rotation.y * z2; + let zz = rotation.z * z2; + let wx = rotation.w * x2; + let wy = rotation.w * y2; + let wz = rotation.w * z2; + + Self::from_cols( + Vec3A::new(1.0 - (yy + zz), xy + wz, xz - wy), + Vec3A::new(xy - wz, 1.0 - (xx + zz), yz + wx), + Vec3A::new(xz + wy, yz - wx, 1.0 - (xx + yy)), + ) + } + + /// Creates a 3D rotation matrix from a normalized rotation `axis` and `angle` (in + /// radians). + /// + /// # Panics + /// + /// Will panic if `axis` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn from_axis_angle(axis: Vec3, angle: f32) -> Self { + glam_assert!(axis.is_normalized()); + + let (sin, cos) = angle.sin_cos(); + let (xsin, ysin, zsin) = axis.mul(sin).into(); + let (x, y, z) = axis.into(); + let (x2, y2, z2) = axis.mul(axis).into(); + let omc = 1.0 - cos; + let xyomc = x * y * omc; + let xzomc = x * z * omc; + let yzomc = y * z * omc; + Self::from_cols( + Vec3A::new(x2 * omc + cos, xyomc + zsin, xzomc - ysin), + Vec3A::new(xyomc - zsin, y2 * omc + cos, yzomc + xsin), + Vec3A::new(xzomc + ysin, yzomc - xsin, z2 * omc + cos), + ) + } + + #[inline] + /// Creates a 3D rotation matrix from the given euler rotation sequence and the angles (in + /// radians). + pub fn from_euler(order: EulerRot, a: f32, b: f32, c: f32) -> Self { + let quat = Quat::from_euler(order, a, b, c); + Self::from_quat(quat) + } + + /// Creates a 3D rotation matrix from `angle` (in radians) around the x axis. + #[inline] + pub fn from_rotation_x(angle: f32) -> Self { + let (sina, cosa) = angle.sin_cos(); + Self::from_cols( + Vec3A::X, + Vec3A::new(0.0, cosa, sina), + Vec3A::new(0.0, -sina, cosa), + ) + } + + /// Creates a 3D rotation matrix from `angle` (in radians) around the y axis. + #[inline] + pub fn from_rotation_y(angle: f32) -> Self { + let (sina, cosa) = angle.sin_cos(); + Self::from_cols( + Vec3A::new(cosa, 0.0, -sina), + Vec3A::Y, + Vec3A::new(sina, 0.0, cosa), + ) + } + + /// Creates a 3D rotation matrix from `angle` (in radians) around the z axis. + #[inline] + pub fn from_rotation_z(angle: f32) -> Self { + let (sina, cosa) = angle.sin_cos(); + Self::from_cols( + Vec3A::new(cosa, sina, 0.0), + Vec3A::new(-sina, cosa, 0.0), + Vec3A::Z, + ) + } + + /// Creates an affine transformation matrix from the given 2D `translation`. + /// + /// The resulting matrix can be used to transform 2D points and vectors. See + /// [`Self::transform_point2()`] and [`Self::transform_vector2()`]. + #[inline] + pub fn from_translation(translation: Vec2) -> Self { + Self::from_cols( + Vec3A::X, + Vec3A::Y, + Vec3A::new(translation.x, translation.y, 1.0), + ) + } + + /// Creates an affine transformation matrix from the given 2D rotation `angle` (in + /// radians). + /// + /// The resulting matrix can be used to transform 2D points and vectors. See + /// [`Self::transform_point2()`] and [`Self::transform_vector2()`]. + #[inline] + pub fn from_angle(angle: f32) -> Self { + let (sin, cos) = angle.sin_cos(); + Self::from_cols( + Vec3A::new(cos, sin, 0.0), + Vec3A::new(-sin, cos, 0.0), + Vec3A::Z, + ) + } + + /// Creates an affine transformation matrix from the given 2D `scale`, rotation `angle` (in + /// radians) and `translation`. + /// + /// The resulting matrix can be used to transform 2D points and vectors. See + /// [`Self::transform_point2()`] and [`Self::transform_vector2()`]. + #[inline] + pub fn from_scale_angle_translation(scale: Vec2, angle: f32, translation: Vec2) -> Self { + let (sin, cos) = angle.sin_cos(); + Self::from_cols( + Vec3A::new(cos * scale.x, sin * scale.x, 0.0), + Vec3A::new(-sin * scale.y, cos * scale.y, 0.0), + Vec3A::new(translation.x, translation.y, 1.0), + ) + } + + /// Creates an affine transformation matrix from the given non-uniform 2D `scale`. + /// + /// The resulting matrix can be used to transform 2D points and vectors. See + /// [`Self::transform_point2()`] and [`Self::transform_vector2()`]. + /// + /// # Panics + /// + /// Will panic if all elements of `scale` are zero when `glam_assert` is enabled. + #[inline] + pub fn from_scale(scale: Vec2) -> Self { + // Do not panic as long as any component is non-zero + glam_assert!(scale.cmpne(Vec2::ZERO).any()); + + Self::from_cols( + Vec3A::new(scale.x, 0.0, 0.0), + Vec3A::new(0.0, scale.y, 0.0), + Vec3A::Z, + ) + } + + /// Creates an affine transformation matrix from the given 2x2 matrix. + /// + /// The resulting matrix can be used to transform 2D points and vectors. See + /// [`Self::transform_point2()`] and [`Self::transform_vector2()`]. + #[inline] + pub fn from_mat2(m: Mat2) -> Self { + Self::from_cols((m.x_axis, 0.0).into(), (m.y_axis, 0.0).into(), Vec3A::Z) + } + + /// Creates a 3x3 matrix from the first 9 values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 9 elements long. + #[inline] + pub const fn from_cols_slice(slice: &[f32]) -> Self { + Self::new( + slice[0], slice[1], slice[2], slice[3], slice[4], slice[5], slice[6], slice[7], + slice[8], + ) + } + + /// Writes the columns of `self` to the first 9 elements in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 9 elements long. + #[inline] + pub fn write_cols_to_slice(self, slice: &mut [f32]) { + slice[0] = self.x_axis.x; + slice[1] = self.x_axis.y; + slice[2] = self.x_axis.z; + slice[3] = self.y_axis.x; + slice[4] = self.y_axis.y; + slice[5] = self.y_axis.z; + slice[6] = self.z_axis.x; + slice[7] = self.z_axis.y; + slice[8] = self.z_axis.z; + } + + /// Returns the matrix column for the given `index`. + /// + /// # Panics + /// + /// Panics if `index` is greater than 2. + #[inline] + pub fn col(&self, index: usize) -> Vec3A { + match index { + 0 => self.x_axis, + 1 => self.y_axis, + 2 => self.z_axis, + _ => panic!("index out of bounds"), + } + } + + /// Returns a mutable reference to the matrix column for the given `index`. + /// + /// # Panics + /// + /// Panics if `index` is greater than 2. + #[inline] + pub fn col_mut(&mut self, index: usize) -> &mut Vec3A { + match index { + 0 => &mut self.x_axis, + 1 => &mut self.y_axis, + 2 => &mut self.z_axis, + _ => panic!("index out of bounds"), + } + } + + /// Returns the matrix row for the given `index`. + /// + /// # Panics + /// + /// Panics if `index` is greater than 2. + #[inline] + pub fn row(&self, index: usize) -> Vec3A { + match index { + 0 => Vec3A::new(self.x_axis.x, self.y_axis.x, self.z_axis.x), + 1 => Vec3A::new(self.x_axis.y, self.y_axis.y, self.z_axis.y), + 2 => Vec3A::new(self.x_axis.z, self.y_axis.z, self.z_axis.z), + _ => panic!("index out of bounds"), + } + } + + /// Returns `true` if, and only if, all elements are finite. + /// If any element is either `NaN`, positive or negative infinity, this will return `false`. + #[inline] + pub fn is_finite(&self) -> bool { + self.x_axis.is_finite() && self.y_axis.is_finite() && self.z_axis.is_finite() + } + + /// Returns `true` if any elements are `NaN`. + #[inline] + pub fn is_nan(&self) -> bool { + self.x_axis.is_nan() || self.y_axis.is_nan() || self.z_axis.is_nan() + } + + /// Returns the transpose of `self`. + #[must_use] + #[inline] + pub fn transpose(&self) -> Self { + unsafe { + let tmp0 = _mm_shuffle_ps(self.x_axis.0, self.y_axis.0, 0b01_00_01_00); + let tmp1 = _mm_shuffle_ps(self.x_axis.0, self.y_axis.0, 0b11_10_11_10); + + Self { + x_axis: Vec3A(_mm_shuffle_ps(tmp0, self.z_axis.0, 0b00_00_10_00)), + y_axis: Vec3A(_mm_shuffle_ps(tmp0, self.z_axis.0, 0b01_01_11_01)), + z_axis: Vec3A(_mm_shuffle_ps(tmp1, self.z_axis.0, 0b10_10_10_00)), + } + } + } + + /// Returns the determinant of `self`. + pub fn determinant(&self) -> f32 { + self.z_axis.dot(self.x_axis.cross(self.y_axis)) + } + + /// Returns the inverse of `self`. + /// + /// If the matrix is not invertible the returned matrix will be invalid. + /// + /// # Panics + /// + /// Will panic if the determinant of `self` is zero when `glam_assert` is enabled. + #[must_use] + pub fn inverse(&self) -> Self { + let tmp0 = self.y_axis.cross(self.z_axis); + let tmp1 = self.z_axis.cross(self.x_axis); + let tmp2 = self.x_axis.cross(self.y_axis); + let det = self.z_axis.dot(tmp2); + glam_assert!(det != 0.0); + let inv_det = Vec3A::splat(det.recip()); + Self::from_cols(tmp0.mul(inv_det), tmp1.mul(inv_det), tmp2.mul(inv_det)).transpose() + } + + /// Transforms the given 2D vector as a point. + /// + /// This is the equivalent of multiplying `rhs` as a 3D vector where `z` is `1`. + /// + /// This method assumes that `self` contains a valid affine transform. + #[inline] + pub fn transform_point2(&self, rhs: Vec2) -> Vec2 { + Mat2::from_cols(self.x_axis.xy(), self.y_axis.xy()) * rhs + self.z_axis.xy() + } + + /// Rotates the given 2D vector. + /// + /// This is the equivalent of multiplying `rhs` as a 3D vector where `z` is `0`. + /// + /// This method assumes that `self` contains a valid affine transform. + #[inline] + pub fn transform_vector2(&self, rhs: Vec2) -> Vec2 { + Mat2::from_cols(self.x_axis.xy(), self.y_axis.xy()) * rhs + } + + /// Transforms a 3D vector. + #[inline] + pub fn mul_vec3(&self, rhs: Vec3) -> Vec3 { + self.mul_vec3a(rhs.into()).into() + } + + /// Transforms a `Vec3A`. + #[inline] + pub fn mul_vec3a(&self, rhs: Vec3A) -> Vec3A { + let mut res = self.x_axis.mul(rhs.xxx()); + res = res.add(self.y_axis.mul(rhs.yyy())); + res = res.add(self.z_axis.mul(rhs.zzz())); + res + } + + /// Multiplies two 3x3 matrices. + #[inline] + pub fn mul_mat3(&self, rhs: &Self) -> Self { + Self::from_cols( + self.mul(rhs.x_axis), + self.mul(rhs.y_axis), + self.mul(rhs.z_axis), + ) + } + + /// Adds two 3x3 matrices. + #[inline] + pub fn add_mat3(&self, rhs: &Self) -> Self { + Self::from_cols( + self.x_axis.add(rhs.x_axis), + self.y_axis.add(rhs.y_axis), + self.z_axis.add(rhs.z_axis), + ) + } + + /// Subtracts two 3x3 matrices. + #[inline] + pub fn sub_mat3(&self, rhs: &Self) -> Self { + Self::from_cols( + self.x_axis.sub(rhs.x_axis), + self.y_axis.sub(rhs.y_axis), + self.z_axis.sub(rhs.z_axis), + ) + } + + /// Multiplies a 3x3 matrix by a scalar. + #[inline] + pub fn mul_scalar(&self, rhs: f32) -> Self { + Self::from_cols( + self.x_axis.mul(rhs), + self.y_axis.mul(rhs), + self.z_axis.mul(rhs), + ) + } + + /// Returns true if the absolute difference of all elements between `self` and `rhs` + /// is less than or equal to `max_abs_diff`. + /// + /// This can be used to compare if two matrices contain similar elements. It works best + /// when comparing with a known value. The `max_abs_diff` that should be used used + /// depends on the values being compared against. + /// + /// For more see + /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/). + #[inline] + pub fn abs_diff_eq(&self, rhs: Self, max_abs_diff: f32) -> bool { + self.x_axis.abs_diff_eq(rhs.x_axis, max_abs_diff) + && self.y_axis.abs_diff_eq(rhs.y_axis, max_abs_diff) + && self.z_axis.abs_diff_eq(rhs.z_axis, max_abs_diff) + } + + #[inline] + pub fn as_dmat3(&self) -> DMat3 { + DMat3::from_cols( + self.x_axis.as_dvec3(), + self.y_axis.as_dvec3(), + self.z_axis.as_dvec3(), + ) + } +} + +impl Default for Mat3A { + #[inline] + fn default() -> Self { + Self::IDENTITY + } +} + +impl Add for Mat3A { + type Output = Self; + #[inline] + fn add(self, rhs: Self) -> Self::Output { + self.add_mat3(&rhs) + } +} + +impl AddAssign for Mat3A { + #[inline] + fn add_assign(&mut self, rhs: Self) { + *self = self.add_mat3(&rhs); + } +} + +impl Sub for Mat3A { + type Output = Self; + #[inline] + fn sub(self, rhs: Self) -> Self::Output { + self.sub_mat3(&rhs) + } +} + +impl SubAssign for Mat3A { + #[inline] + fn sub_assign(&mut self, rhs: Self) { + *self = self.sub_mat3(&rhs); + } +} + +impl Neg for Mat3A { + type Output = Self; + #[inline] + fn neg(self) -> Self::Output { + Self::from_cols(self.x_axis.neg(), self.y_axis.neg(), self.z_axis.neg()) + } +} + +impl Mul for Mat3A { + type Output = Self; + #[inline] + fn mul(self, rhs: Self) -> Self::Output { + self.mul_mat3(&rhs) + } +} + +impl MulAssign for Mat3A { + #[inline] + fn mul_assign(&mut self, rhs: Self) { + *self = self.mul_mat3(&rhs); + } +} + +impl Mul for Mat3A { + type Output = Vec3A; + #[inline] + fn mul(self, rhs: Vec3A) -> Self::Output { + self.mul_vec3a(rhs) + } +} + +impl Mul for f32 { + type Output = Mat3A; + #[inline] + fn mul(self, rhs: Mat3A) -> Self::Output { + rhs.mul_scalar(self) + } +} + +impl Mul for Mat3A { + type Output = Self; + #[inline] + fn mul(self, rhs: f32) -> Self::Output { + self.mul_scalar(rhs) + } +} + +impl MulAssign for Mat3A { + #[inline] + fn mul_assign(&mut self, rhs: f32) { + *self = self.mul_scalar(rhs); + } +} + +impl Mul for Mat3A { + type Output = Vec3; + #[inline] + fn mul(self, rhs: Vec3) -> Vec3 { + self.mul_vec3a(rhs.into()).into() + } +} + +impl From for Mat3A { + #[inline] + fn from(m: Mat3) -> Self { + Self { + x_axis: m.x_axis.into(), + y_axis: m.y_axis.into(), + z_axis: m.z_axis.into(), + } + } +} + +impl<'a> Sum<&'a Self> for Mat3A { + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, |a, &b| Self::add(a, b)) + } +} + +impl<'a> Product<&'a Self> for Mat3A { + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::IDENTITY, |a, &b| Self::mul(a, b)) + } +} + +impl PartialEq for Mat3A { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.x_axis.eq(&rhs.x_axis) && self.y_axis.eq(&rhs.y_axis) && self.z_axis.eq(&rhs.z_axis) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Debug for Mat3A { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct(stringify!(Mat3A)) + .field("x_axis", &self.x_axis) + .field("y_axis", &self.y_axis) + .field("z_axis", &self.z_axis) + .finish() + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Display for Mat3A { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "[{}, {}, {}]", self.x_axis, self.y_axis, self.z_axis) + } +} diff --git a/src/f32/sse2/mat4.rs b/src/f32/sse2/mat4.rs new file mode 100644 index 00000000..19ca243f --- /dev/null +++ b/src/f32/sse2/mat4.rs @@ -0,0 +1,1327 @@ +// Generated from mat.rs template. Edit the template, not the generated file. + +use crate::{swizzles::*, DMat4, EulerRot, Mat3, Quat, Vec3, Vec3A, Vec4}; +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::iter::{Product, Sum}; +use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; + +#[cfg(target_arch = "x86")] +use core::arch::x86::*; +#[cfg(target_arch = "x86_64")] +use core::arch::x86_64::*; + +#[cfg(not(feature = "std"))] +use num_traits::Float; + +/// Creates a 4x4 matrix from column vectors. +#[inline(always)] +pub const fn mat4(x_axis: Vec4, y_axis: Vec4, z_axis: Vec4, w_axis: Vec4) -> Mat4 { + Mat4::from_cols(x_axis, y_axis, z_axis, w_axis) +} + +/// A 4x4 column major matrix. +/// +/// This 4x4 matrix type features convenience methods for creating and using affine transforms and +/// perspective projections. If you are primarily dealing with 3D affine transformations +/// considering using [`Affine3A`](crate::Affine3A) which is faster than a 4x4 matrix +/// for some affine operations. +/// +/// Affine transformations including 3D translation, rotation and scale can be created +/// using methods such as [`Self::from_translation()`], [`Self::from_quat()`], +/// [`Self::from_scale()`] and [`Self::from_scale_rotation_translation()`]. +/// +/// Othographic projections can be created using the methods [`Self::orthographic_lh()`] for +/// left-handed coordinate systems and [`Self::orthographic_rh()`] for right-handed +/// systems. The resulting matrix is also an affine transformation. +/// +/// The [`Self::transform_point3()`] and [`Self::transform_vector3()`] convenience methods +/// are provided for performing affine transformations on 3D vectors and points. These +/// multiply 3D inputs as 4D vectors with an implicit `w` value of `1` for points and `0` +/// for vectors respectively. These methods assume that `Self` contains a valid affine +/// transform. +/// +/// Perspective projections can be created using methods such as +/// [`Self::perspective_lh()`], [`Self::perspective_infinite_lh()`] and +/// [`Self::perspective_infinite_reverse_lh()`] for left-handed co-ordinate systems and +/// [`Self::perspective_rh()`], [`Self::perspective_infinite_rh()`] and +/// [`Self::perspective_infinite_reverse_rh()`] for right-handed co-ordinate systems. +/// +/// The resulting perspective project can be use to transform 3D vectors as points with +/// perspective correction using the [`Self::project_point3()`] convenience method. +#[derive(Clone, Copy)] +pub struct Mat4 { + pub x_axis: Vec4, + pub y_axis: Vec4, + pub z_axis: Vec4, + pub w_axis: Vec4, +} + +impl Mat4 { + /// A 4x4 matrix with all elements set to `0.0`. + pub const ZERO: Self = Self::from_cols(Vec4::ZERO, Vec4::ZERO, Vec4::ZERO, Vec4::ZERO); + + /// A 4x4 identity matrix, where all diagonal elements are `1`, and all off-diagonal elements are `0`. + pub const IDENTITY: Self = Self::from_cols(Vec4::X, Vec4::Y, Vec4::Z, Vec4::W); + + /// All NAN:s. + pub const NAN: Self = Self::from_cols(Vec4::NAN, Vec4::NAN, Vec4::NAN, Vec4::NAN); + + #[allow(clippy::too_many_arguments)] + #[inline(always)] + const fn new( + m00: f32, + m01: f32, + m02: f32, + m03: f32, + m10: f32, + m11: f32, + m12: f32, + m13: f32, + m20: f32, + m21: f32, + m22: f32, + m23: f32, + m30: f32, + m31: f32, + m32: f32, + m33: f32, + ) -> Self { + Self { + x_axis: Vec4::new(m00, m01, m02, m03), + y_axis: Vec4::new(m10, m11, m12, m13), + z_axis: Vec4::new(m20, m21, m22, m23), + w_axis: Vec4::new(m30, m31, m32, m33), + } + } + + /// Creates a 4x4 matrix from two column vectors. + #[inline(always)] + pub const fn from_cols(x_axis: Vec4, y_axis: Vec4, z_axis: Vec4, w_axis: Vec4) -> Self { + Self { + x_axis, + y_axis, + z_axis, + w_axis, + } + } + + /// Creates a 4x4 matrix from a `[f32; 16]` array stored in column major order. + /// If your data is stored in row major you will need to `transpose` the returned + /// matrix. + #[inline] + pub const fn from_cols_array(m: &[f32; 16]) -> Self { + Self::new( + m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], m[9], m[10], m[11], m[12], m[13], + m[14], m[15], + ) + } + + /// Creates a `[f32; 16]` array storing data in column major order. + /// If you require data in row major order `transpose` the matrix first. + #[inline] + pub fn to_cols_array(&self) -> [f32; 16] { + [ + self.x_axis.x, + self.x_axis.y, + self.x_axis.z, + self.x_axis.w, + self.y_axis.x, + self.y_axis.y, + self.y_axis.z, + self.y_axis.w, + self.z_axis.x, + self.z_axis.y, + self.z_axis.z, + self.z_axis.w, + self.w_axis.x, + self.w_axis.y, + self.w_axis.z, + self.w_axis.w, + ] + } + + /// Creates a 4x4 matrix from a `[[f32; 4]; 4]` 4D array stored in column major order. + /// If your data is in row major order you will need to `transpose` the returned + /// matrix. + #[inline] + pub const fn from_cols_array_2d(m: &[[f32; 4]; 4]) -> Self { + Self::from_cols( + Vec4::from_array(m[0]), + Vec4::from_array(m[1]), + Vec4::from_array(m[2]), + Vec4::from_array(m[3]), + ) + } + + /// Creates a `[[f32; 4]; 4]` 4D array storing data in column major order. + /// If you require data in row major order `transpose` the matrix first. + #[inline] + pub fn to_cols_array_2d(&self) -> [[f32; 4]; 4] { + [ + self.x_axis.to_array(), + self.y_axis.to_array(), + self.z_axis.to_array(), + self.w_axis.to_array(), + ] + } + + /// Creates a 4x4 matrix with its diagonal set to `diagonal` and all other entries set to 0. + #[doc(alias = "scale")] + #[inline] + pub fn from_diagonal(diagonal: Vec4) -> Self { + Self::new( + diagonal.x, 0.0, 0.0, 0.0, 0.0, diagonal.y, 0.0, 0.0, 0.0, 0.0, diagonal.z, 0.0, 0.0, + 0.0, 0.0, diagonal.w, + ) + } + + fn quat_to_axes(rotation: Quat) -> (Vec4, Vec4, Vec4) { + glam_assert!(rotation.is_normalized()); + + let (x, y, z, w) = rotation.into(); + let x2 = x + x; + let y2 = y + y; + let z2 = z + z; + let xx = x * x2; + let xy = x * y2; + let xz = x * z2; + let yy = y * y2; + let yz = y * z2; + let zz = z * z2; + let wx = w * x2; + let wy = w * y2; + let wz = w * z2; + + let x_axis = Vec4::new(1.0 - (yy + zz), xy + wz, xz - wy, 0.0); + let y_axis = Vec4::new(xy - wz, 1.0 - (xx + zz), yz + wx, 0.0); + let z_axis = Vec4::new(xz + wy, yz - wx, 1.0 - (xx + yy), 0.0); + (x_axis, y_axis, z_axis) + } + + /// Creates an affine transformation matrix from the given 3D `scale`, `rotation` and + /// `translation`. + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + /// + /// # Panics + /// + /// Will panic if `rotation` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn from_scale_rotation_translation(scale: Vec3, rotation: Quat, translation: Vec3) -> Self { + let (x_axis, y_axis, z_axis) = Self::quat_to_axes(rotation); + Self::from_cols( + x_axis.mul(scale.x), + y_axis.mul(scale.y), + z_axis.mul(scale.z), + Vec4::from((translation, 1.0)), + ) + } + + /// Creates an affine transformation matrix from the given 3D `translation`. + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + /// + /// # Panics + /// + /// Will panic if `rotation` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn from_rotation_translation(rotation: Quat, translation: Vec3) -> Self { + let (x_axis, y_axis, z_axis) = Self::quat_to_axes(rotation); + Self::from_cols(x_axis, y_axis, z_axis, Vec4::from((translation, 1.0))) + } + + /// Extracts `scale`, `rotation` and `translation` from `self`. The input matrix is + /// expected to be a 3D affine transformation matrix otherwise the output will be invalid. + /// + /// # Panics + /// + /// Will panic if the determinant of `self` is zero or if the resulting scale vector + /// contains any zero elements when `glam_assert` is enabled. + #[inline] + pub fn to_scale_rotation_translation(&self) -> (Vec3, Quat, Vec3) { + let det = self.determinant(); + glam_assert!(det != 0.0); + + let scale = Vec3::new( + self.x_axis.length() * det.signum(), + self.y_axis.length(), + self.z_axis.length(), + ); + + glam_assert!(scale.cmpne(Vec3::ZERO).all()); + + let inv_scale = scale.recip(); + + let rotation = Quat::from_rotation_axes( + self.x_axis.mul(inv_scale.x).xyz(), + self.y_axis.mul(inv_scale.y).xyz(), + self.z_axis.mul(inv_scale.z).xyz(), + ); + + let translation = self.w_axis.xyz(); + + (scale, rotation, translation) + } + + /// Creates an affine transformation matrix from the given `rotation` quaternion. + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + /// + /// # Panics + /// + /// Will panic if `rotation` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn from_quat(rotation: Quat) -> Self { + let (x_axis, y_axis, z_axis) = Self::quat_to_axes(rotation); + Self::from_cols(x_axis, y_axis, z_axis, Vec4::W) + } + + /// Creates an affine transformation matrix from the given 3x3 linear transformation + /// matrix. + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + #[inline] + pub fn from_mat3(m: Mat3) -> Self { + Self::from_cols( + Vec4::from((m.x_axis, 0.0)), + Vec4::from((m.y_axis, 0.0)), + Vec4::from((m.z_axis, 0.0)), + Vec4::W, + ) + } + + /// Creates an affine transformation matrix from the given 3D `translation`. + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + #[inline] + pub fn from_translation(translation: Vec3) -> Self { + Self::from_cols( + Vec4::X, + Vec4::Y, + Vec4::Z, + Vec4::new(translation.x, translation.y, translation.z, 1.0), + ) + } + + /// Creates an affine transformation matrix containing a 3D rotation around a normalized + /// rotation `axis` of `angle` (in radians). + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + /// + /// # Panics + /// + /// Will panic if `axis` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn from_axis_angle(axis: Vec3, angle: f32) -> Self { + glam_assert!(axis.is_normalized()); + + let (sin, cos) = angle.sin_cos(); + let axis_sin = axis.mul(sin); + let axis_sq = axis.mul(axis); + let omc = 1.0 - cos; + let xyomc = axis.x * axis.y * omc; + let xzomc = axis.x * axis.z * omc; + let yzomc = axis.y * axis.z * omc; + Self::from_cols( + Vec4::new( + axis_sq.x * omc + cos, + xyomc + axis_sin.z, + xzomc - axis_sin.y, + 0.0, + ), + Vec4::new( + xyomc - axis_sin.z, + axis_sq.y * omc + cos, + yzomc + axis_sin.x, + 0.0, + ), + Vec4::new( + xzomc + axis_sin.y, + yzomc - axis_sin.x, + axis_sq.z * omc + cos, + 0.0, + ), + Vec4::W, + ) + } + + #[inline] + /// Creates a affine transformation matrix containing a rotation from the given euler + /// rotation sequence and angles (in radians). + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + pub fn from_euler(order: EulerRot, a: f32, b: f32, c: f32) -> Self { + let quat = Quat::from_euler(order, a, b, c); + Self::from_quat(quat) + } + + /// Creates an affine transformation matrix containing a 3D rotation around the x axis of + /// `angle` (in radians). + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + #[inline] + pub fn from_rotation_x(angle: f32) -> Self { + let (sina, cosa) = angle.sin_cos(); + Self::from_cols( + Vec4::X, + Vec4::new(0.0, cosa, sina, 0.0), + Vec4::new(0.0, -sina, cosa, 0.0), + Vec4::W, + ) + } + + /// Creates an affine transformation matrix containing a 3D rotation around the y axis of + /// `angle` (in radians). + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + #[inline] + pub fn from_rotation_y(angle: f32) -> Self { + let (sina, cosa) = angle.sin_cos(); + Self::from_cols( + Vec4::new(cosa, 0.0, -sina, 0.0), + Vec4::Y, + Vec4::new(sina, 0.0, cosa, 0.0), + Vec4::W, + ) + } + + /// Creates an affine transformation matrix containing a 3D rotation around the z axis of + /// `angle` (in radians). + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + #[inline] + pub fn from_rotation_z(angle: f32) -> Self { + let (sina, cosa) = angle.sin_cos(); + Self::from_cols( + Vec4::new(cosa, sina, 0.0, 0.0), + Vec4::new(-sina, cosa, 0.0, 0.0), + Vec4::Z, + Vec4::W, + ) + } + + /// Creates an affine transformation matrix containing the given 3D non-uniform `scale`. + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + /// + /// # Panics + /// + /// Will panic if all elements of `scale` are zero when `glam_assert` is enabled. + #[inline] + pub fn from_scale(scale: Vec3) -> Self { + // Do not panic as long as any component is non-zero + glam_assert!(scale.cmpne(Vec3::ZERO).any()); + + Self::from_cols( + Vec4::new(scale.x, 0.0, 0.0, 0.0), + Vec4::new(0.0, scale.y, 0.0, 0.0), + Vec4::new(0.0, 0.0, scale.z, 0.0), + Vec4::W, + ) + } + + /// Creates a 4x4 matrix from the first 16 values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 16 elements long. + #[inline] + pub const fn from_cols_slice(slice: &[f32]) -> Self { + Self::new( + slice[0], slice[1], slice[2], slice[3], slice[4], slice[5], slice[6], slice[7], + slice[8], slice[9], slice[10], slice[11], slice[12], slice[13], slice[14], slice[15], + ) + } + + /// Writes the columns of `self` to the first 16 elements in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 16 elements long. + #[inline] + pub fn write_cols_to_slice(self, slice: &mut [f32]) { + slice[0] = self.x_axis.x; + slice[1] = self.x_axis.y; + slice[2] = self.x_axis.z; + slice[3] = self.x_axis.w; + slice[4] = self.y_axis.x; + slice[5] = self.y_axis.y; + slice[6] = self.y_axis.z; + slice[7] = self.y_axis.w; + slice[8] = self.z_axis.x; + slice[9] = self.z_axis.y; + slice[10] = self.z_axis.z; + slice[11] = self.z_axis.w; + slice[12] = self.w_axis.x; + slice[13] = self.w_axis.y; + slice[14] = self.w_axis.z; + slice[15] = self.w_axis.w; + } + + /// Returns the matrix column for the given `index`. + /// + /// # Panics + /// + /// Panics if `index` is greater than 3. + #[inline] + pub fn col(&self, index: usize) -> Vec4 { + match index { + 0 => self.x_axis, + 1 => self.y_axis, + 2 => self.z_axis, + 3 => self.w_axis, + _ => panic!("index out of bounds"), + } + } + + /// Returns a mutable reference to the matrix column for the given `index`. + /// + /// # Panics + /// + /// Panics if `index` is greater than 3. + #[inline] + pub fn col_mut(&mut self, index: usize) -> &mut Vec4 { + match index { + 0 => &mut self.x_axis, + 1 => &mut self.y_axis, + 2 => &mut self.z_axis, + 3 => &mut self.w_axis, + _ => panic!("index out of bounds"), + } + } + + /// Returns the matrix row for the given `index`. + /// + /// # Panics + /// + /// Panics if `index` is greater than 3. + #[inline] + pub fn row(&self, index: usize) -> Vec4 { + match index { + 0 => Vec4::new(self.x_axis.x, self.y_axis.x, self.z_axis.x, self.w_axis.x), + 1 => Vec4::new(self.x_axis.y, self.y_axis.y, self.z_axis.y, self.w_axis.y), + 2 => Vec4::new(self.x_axis.z, self.y_axis.z, self.z_axis.z, self.w_axis.z), + 3 => Vec4::new(self.x_axis.w, self.y_axis.w, self.z_axis.w, self.w_axis.w), + _ => panic!("index out of bounds"), + } + } + + /// Returns `true` if, and only if, all elements are finite. + /// If any element is either `NaN`, positive or negative infinity, this will return `false`. + #[inline] + pub fn is_finite(&self) -> bool { + self.x_axis.is_finite() + && self.y_axis.is_finite() + && self.z_axis.is_finite() + && self.w_axis.is_finite() + } + + /// Returns `true` if any elements are `NaN`. + #[inline] + pub fn is_nan(&self) -> bool { + self.x_axis.is_nan() || self.y_axis.is_nan() || self.z_axis.is_nan() || self.w_axis.is_nan() + } + + /// Returns the transpose of `self`. + #[must_use] + #[inline] + pub fn transpose(&self) -> Self { + unsafe { + // Based on https://github.com/microsoft/DirectXMath `XMMatrixTranspose` + let tmp0 = _mm_shuffle_ps(self.x_axis.0, self.y_axis.0, 0b01_00_01_00); + let tmp1 = _mm_shuffle_ps(self.x_axis.0, self.y_axis.0, 0b11_10_11_10); + let tmp2 = _mm_shuffle_ps(self.z_axis.0, self.w_axis.0, 0b01_00_01_00); + let tmp3 = _mm_shuffle_ps(self.z_axis.0, self.w_axis.0, 0b11_10_11_10); + + Self { + x_axis: Vec4(_mm_shuffle_ps(tmp0, tmp2, 0b10_00_10_00)), + y_axis: Vec4(_mm_shuffle_ps(tmp0, tmp2, 0b11_01_11_01)), + z_axis: Vec4(_mm_shuffle_ps(tmp1, tmp3, 0b10_00_10_00)), + w_axis: Vec4(_mm_shuffle_ps(tmp1, tmp3, 0b11_01_11_01)), + } + } + } + + /// Returns the determinant of `self`. + pub fn determinant(&self) -> f32 { + unsafe { + // Based on https://github.com/g-truc/glm `glm_mat4_determinant_lowp` + let swp2a = _mm_shuffle_ps(self.z_axis.0, self.z_axis.0, 0b00_01_01_10); + let swp3a = _mm_shuffle_ps(self.w_axis.0, self.w_axis.0, 0b11_10_11_11); + let swp2b = _mm_shuffle_ps(self.z_axis.0, self.z_axis.0, 0b11_10_11_11); + let swp3b = _mm_shuffle_ps(self.w_axis.0, self.w_axis.0, 0b00_01_01_10); + let swp2c = _mm_shuffle_ps(self.z_axis.0, self.z_axis.0, 0b00_00_01_10); + let swp3c = _mm_shuffle_ps(self.w_axis.0, self.w_axis.0, 0b01_10_00_00); + + let mula = _mm_mul_ps(swp2a, swp3a); + let mulb = _mm_mul_ps(swp2b, swp3b); + let mulc = _mm_mul_ps(swp2c, swp3c); + let sube = _mm_sub_ps(mula, mulb); + let subf = _mm_sub_ps(_mm_movehl_ps(mulc, mulc), mulc); + + let subfaca = _mm_shuffle_ps(sube, sube, 0b10_01_00_00); + let swpfaca = _mm_shuffle_ps(self.y_axis.0, self.y_axis.0, 0b00_00_00_01); + let mulfaca = _mm_mul_ps(swpfaca, subfaca); + + let subtmpb = _mm_shuffle_ps(sube, subf, 0b00_00_11_01); + let subfacb = _mm_shuffle_ps(subtmpb, subtmpb, 0b11_01_01_00); + let swpfacb = _mm_shuffle_ps(self.y_axis.0, self.y_axis.0, 0b01_01_10_10); + let mulfacb = _mm_mul_ps(swpfacb, subfacb); + + let subres = _mm_sub_ps(mulfaca, mulfacb); + let subtmpc = _mm_shuffle_ps(sube, subf, 0b01_00_10_10); + let subfacc = _mm_shuffle_ps(subtmpc, subtmpc, 0b11_11_10_00); + let swpfacc = _mm_shuffle_ps(self.y_axis.0, self.y_axis.0, 0b10_11_11_11); + let mulfacc = _mm_mul_ps(swpfacc, subfacc); + + let addres = _mm_add_ps(subres, mulfacc); + let detcof = _mm_mul_ps(addres, _mm_setr_ps(1.0, -1.0, 1.0, -1.0)); + + crate::sse2::dot4(self.x_axis.0, detcof) + } + } + + /// Returns the inverse of `self`. + /// + /// If the matrix is not invertible the returned matrix will be invalid. + /// + /// # Panics + /// + /// Will panic if the determinant of `self` is zero when `glam_assert` is enabled. + #[must_use] + pub fn inverse(&self) -> Self { + unsafe { + // Based on https://github.com/g-truc/glm `glm_mat4_inverse` + let fac0 = { + let swp0a = _mm_shuffle_ps(self.w_axis.0, self.z_axis.0, 0b11_11_11_11); + let swp0b = _mm_shuffle_ps(self.w_axis.0, self.z_axis.0, 0b10_10_10_10); + + let swp00 = _mm_shuffle_ps(self.z_axis.0, self.y_axis.0, 0b10_10_10_10); + let swp01 = _mm_shuffle_ps(swp0a, swp0a, 0b10_00_00_00); + let swp02 = _mm_shuffle_ps(swp0b, swp0b, 0b10_00_00_00); + let swp03 = _mm_shuffle_ps(self.z_axis.0, self.y_axis.0, 0b11_11_11_11); + + let mul00 = _mm_mul_ps(swp00, swp01); + let mul01 = _mm_mul_ps(swp02, swp03); + _mm_sub_ps(mul00, mul01) + }; + let fac1 = { + let swp0a = _mm_shuffle_ps(self.w_axis.0, self.z_axis.0, 0b11_11_11_11); + let swp0b = _mm_shuffle_ps(self.w_axis.0, self.z_axis.0, 0b01_01_01_01); + + let swp00 = _mm_shuffle_ps(self.z_axis.0, self.y_axis.0, 0b01_01_01_01); + let swp01 = _mm_shuffle_ps(swp0a, swp0a, 0b10_00_00_00); + let swp02 = _mm_shuffle_ps(swp0b, swp0b, 0b10_00_00_00); + let swp03 = _mm_shuffle_ps(self.z_axis.0, self.y_axis.0, 0b11_11_11_11); + + let mul00 = _mm_mul_ps(swp00, swp01); + let mul01 = _mm_mul_ps(swp02, swp03); + _mm_sub_ps(mul00, mul01) + }; + let fac2 = { + let swp0a = _mm_shuffle_ps(self.w_axis.0, self.z_axis.0, 0b10_10_10_10); + let swp0b = _mm_shuffle_ps(self.w_axis.0, self.z_axis.0, 0b01_01_01_01); + + let swp00 = _mm_shuffle_ps(self.z_axis.0, self.y_axis.0, 0b01_01_01_01); + let swp01 = _mm_shuffle_ps(swp0a, swp0a, 0b10_00_00_00); + let swp02 = _mm_shuffle_ps(swp0b, swp0b, 0b10_00_00_00); + let swp03 = _mm_shuffle_ps(self.z_axis.0, self.y_axis.0, 0b10_10_10_10); + + let mul00 = _mm_mul_ps(swp00, swp01); + let mul01 = _mm_mul_ps(swp02, swp03); + _mm_sub_ps(mul00, mul01) + }; + let fac3 = { + let swp0a = _mm_shuffle_ps(self.w_axis.0, self.z_axis.0, 0b11_11_11_11); + let swp0b = _mm_shuffle_ps(self.w_axis.0, self.z_axis.0, 0b00_00_00_00); + + let swp00 = _mm_shuffle_ps(self.z_axis.0, self.y_axis.0, 0b00_00_00_00); + let swp01 = _mm_shuffle_ps(swp0a, swp0a, 0b10_00_00_00); + let swp02 = _mm_shuffle_ps(swp0b, swp0b, 0b10_00_00_00); + let swp03 = _mm_shuffle_ps(self.z_axis.0, self.y_axis.0, 0b11_11_11_11); + + let mul00 = _mm_mul_ps(swp00, swp01); + let mul01 = _mm_mul_ps(swp02, swp03); + _mm_sub_ps(mul00, mul01) + }; + let fac4 = { + let swp0a = _mm_shuffle_ps(self.w_axis.0, self.z_axis.0, 0b10_10_10_10); + let swp0b = _mm_shuffle_ps(self.w_axis.0, self.z_axis.0, 0b00_00_00_00); + + let swp00 = _mm_shuffle_ps(self.z_axis.0, self.y_axis.0, 0b00_00_00_00); + let swp01 = _mm_shuffle_ps(swp0a, swp0a, 0b10_00_00_00); + let swp02 = _mm_shuffle_ps(swp0b, swp0b, 0b10_00_00_00); + let swp03 = _mm_shuffle_ps(self.z_axis.0, self.y_axis.0, 0b10_10_10_10); + + let mul00 = _mm_mul_ps(swp00, swp01); + let mul01 = _mm_mul_ps(swp02, swp03); + _mm_sub_ps(mul00, mul01) + }; + let fac5 = { + let swp0a = _mm_shuffle_ps(self.w_axis.0, self.z_axis.0, 0b01_01_01_01); + let swp0b = _mm_shuffle_ps(self.w_axis.0, self.z_axis.0, 0b00_00_00_00); + + let swp00 = _mm_shuffle_ps(self.z_axis.0, self.y_axis.0, 0b00_00_00_00); + let swp01 = _mm_shuffle_ps(swp0a, swp0a, 0b10_00_00_00); + let swp02 = _mm_shuffle_ps(swp0b, swp0b, 0b10_00_00_00); + let swp03 = _mm_shuffle_ps(self.z_axis.0, self.y_axis.0, 0b01_01_01_01); + + let mul00 = _mm_mul_ps(swp00, swp01); + let mul01 = _mm_mul_ps(swp02, swp03); + _mm_sub_ps(mul00, mul01) + }; + let sign_a = _mm_set_ps(1.0, -1.0, 1.0, -1.0); + let sign_b = _mm_set_ps(-1.0, 1.0, -1.0, 1.0); + + let temp0 = _mm_shuffle_ps(self.y_axis.0, self.x_axis.0, 0b00_00_00_00); + let vec0 = _mm_shuffle_ps(temp0, temp0, 0b10_10_10_00); + + let temp1 = _mm_shuffle_ps(self.y_axis.0, self.x_axis.0, 0b01_01_01_01); + let vec1 = _mm_shuffle_ps(temp1, temp1, 0b10_10_10_00); + + let temp2 = _mm_shuffle_ps(self.y_axis.0, self.x_axis.0, 0b10_10_10_10); + let vec2 = _mm_shuffle_ps(temp2, temp2, 0b10_10_10_00); + + let temp3 = _mm_shuffle_ps(self.y_axis.0, self.x_axis.0, 0b11_11_11_11); + let vec3 = _mm_shuffle_ps(temp3, temp3, 0b10_10_10_00); + + let mul00 = _mm_mul_ps(vec1, fac0); + let mul01 = _mm_mul_ps(vec2, fac1); + let mul02 = _mm_mul_ps(vec3, fac2); + let sub00 = _mm_sub_ps(mul00, mul01); + let add00 = _mm_add_ps(sub00, mul02); + let inv0 = _mm_mul_ps(sign_b, add00); + + let mul03 = _mm_mul_ps(vec0, fac0); + let mul04 = _mm_mul_ps(vec2, fac3); + let mul05 = _mm_mul_ps(vec3, fac4); + let sub01 = _mm_sub_ps(mul03, mul04); + let add01 = _mm_add_ps(sub01, mul05); + let inv1 = _mm_mul_ps(sign_a, add01); + + let mul06 = _mm_mul_ps(vec0, fac1); + let mul07 = _mm_mul_ps(vec1, fac3); + let mul08 = _mm_mul_ps(vec3, fac5); + let sub02 = _mm_sub_ps(mul06, mul07); + let add02 = _mm_add_ps(sub02, mul08); + let inv2 = _mm_mul_ps(sign_b, add02); + + let mul09 = _mm_mul_ps(vec0, fac2); + let mul10 = _mm_mul_ps(vec1, fac4); + let mul11 = _mm_mul_ps(vec2, fac5); + let sub03 = _mm_sub_ps(mul09, mul10); + let add03 = _mm_add_ps(sub03, mul11); + let inv3 = _mm_mul_ps(sign_a, add03); + + let row0 = _mm_shuffle_ps(inv0, inv1, 0b00_00_00_00); + let row1 = _mm_shuffle_ps(inv2, inv3, 0b00_00_00_00); + let row2 = _mm_shuffle_ps(row0, row1, 0b10_00_10_00); + + let dot0 = crate::sse2::dot4(self.x_axis.0, row2); + glam_assert!(dot0 != 0.0); + + let rcp0 = _mm_set1_ps(dot0.recip()); + + Self { + x_axis: Vec4(_mm_mul_ps(inv0, rcp0)), + y_axis: Vec4(_mm_mul_ps(inv1, rcp0)), + z_axis: Vec4(_mm_mul_ps(inv2, rcp0)), + w_axis: Vec4(_mm_mul_ps(inv3, rcp0)), + } + } + } + + #[inline] + fn look_to_lh(eye: Vec3, dir: Vec3, up: Vec3) -> Self { + let f = dir.normalize(); + let s = up.cross(f).normalize(); + let u = f.cross(s); + Self::from_cols( + Vec4::new(s.x, u.x, f.x, 0.0), + Vec4::new(s.y, u.y, f.y, 0.0), + Vec4::new(s.z, u.z, f.z, 0.0), + Vec4::new(-s.dot(eye), -u.dot(eye), -f.dot(eye), 1.0), + ) + } + + /// Creates a left-handed view matrix using a camera position, an up direction, and a focal + /// point. + /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=forward`. + /// + /// # Panics + /// + /// Will panic if `up` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn look_at_lh(eye: Vec3, center: Vec3, up: Vec3) -> Self { + glam_assert!(up.is_normalized()); + Self::look_to_lh(eye, center.sub(eye), up) + } + + /// Creates a right-handed view matrix using a camera position, an up direction, and a focal + /// point. + /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=back`. + /// + /// # Panics + /// + /// Will panic if `up` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn look_at_rh(eye: Vec3, center: Vec3, up: Vec3) -> Self { + glam_assert!(up.is_normalized()); + Self::look_to_lh(eye, eye.sub(center), up) + } + + /// Creates a right-handed perspective projection matrix with [-1,1] depth range. + /// This is the same as the OpenGL `gluPerspective` function. + /// See + #[inline] + pub fn perspective_rh_gl( + fov_y_radians: f32, + aspect_ratio: f32, + z_near: f32, + z_far: f32, + ) -> Self { + let inv_length = 1.0 / (z_near - z_far); + let f = 1.0 / (0.5 * fov_y_radians).tan(); + let a = f / aspect_ratio; + let b = (z_near + z_far) * inv_length; + let c = (2.0 * z_near * z_far) * inv_length; + Self::from_cols( + Vec4::new(a, 0.0, 0.0, 0.0), + Vec4::new(0.0, f, 0.0, 0.0), + Vec4::new(0.0, 0.0, b, -1.0), + Vec4::new(0.0, 0.0, c, 0.0), + ) + } + + /// Creates a left-handed perspective projection matrix with `[0,1]` depth range. + /// + /// # Panics + /// + /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is + /// enabled. + #[inline] + pub fn perspective_lh(fov_y_radians: f32, aspect_ratio: f32, z_near: f32, z_far: f32) -> Self { + glam_assert!(z_near > 0.0 && z_far > 0.0); + let (sin_fov, cos_fov) = (0.5 * fov_y_radians).sin_cos(); + let h = cos_fov / sin_fov; + let w = h / aspect_ratio; + let r = z_far / (z_far - z_near); + Self::from_cols( + Vec4::new(w, 0.0, 0.0, 0.0), + Vec4::new(0.0, h, 0.0, 0.0), + Vec4::new(0.0, 0.0, r, 1.0), + Vec4::new(0.0, 0.0, -r * z_near, 0.0), + ) + } + + /// Creates a right-handed perspective projection matrix with `[0,1]` depth range. + /// + /// # Panics + /// + /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is + /// enabled. + #[inline] + pub fn perspective_rh(fov_y_radians: f32, aspect_ratio: f32, z_near: f32, z_far: f32) -> Self { + glam_assert!(z_near > 0.0 && z_far > 0.0); + let (sin_fov, cos_fov) = (0.5 * fov_y_radians).sin_cos(); + let h = cos_fov / sin_fov; + let w = h / aspect_ratio; + let r = z_far / (z_near - z_far); + Self::from_cols( + Vec4::new(w, 0.0, 0.0, 0.0), + Vec4::new(0.0, h, 0.0, 0.0), + Vec4::new(0.0, 0.0, r, -1.0), + Vec4::new(0.0, 0.0, r * z_near, 0.0), + ) + } + + /// Creates an infinite left-handed perspective projection matrix with `[0,1]` depth range. + /// + /// # Panics + /// + /// Will panic if `z_near` is less than or equal to zero when `glam_assert` is enabled. + #[inline] + pub fn perspective_infinite_lh(fov_y_radians: f32, aspect_ratio: f32, z_near: f32) -> Self { + glam_assert!(z_near > 0.0); + let (sin_fov, cos_fov) = (0.5 * fov_y_radians).sin_cos(); + let h = cos_fov / sin_fov; + let w = h / aspect_ratio; + Self::from_cols( + Vec4::new(w, 0.0, 0.0, 0.0), + Vec4::new(0.0, h, 0.0, 0.0), + Vec4::new(0.0, 0.0, 1.0, 1.0), + Vec4::new(0.0, 0.0, -z_near, 0.0), + ) + } + + /// Creates an infinite left-handed perspective projection matrix with `[0,1]` depth range. + /// + /// # Panics + /// + /// Will panic if `z_near` is less than or equal to zero when `glam_assert` is enabled. + #[inline] + pub fn perspective_infinite_reverse_lh( + fov_y_radians: f32, + aspect_ratio: f32, + z_near: f32, + ) -> Self { + glam_assert!(z_near > 0.0); + let (sin_fov, cos_fov) = (0.5 * fov_y_radians).sin_cos(); + let h = cos_fov / sin_fov; + let w = h / aspect_ratio; + Self::from_cols( + Vec4::new(w, 0.0, 0.0, 0.0), + Vec4::new(0.0, h, 0.0, 0.0), + Vec4::new(0.0, 0.0, 0.0, 1.0), + Vec4::new(0.0, 0.0, z_near, 0.0), + ) + } + + /// Creates an infinite right-handed perspective projection matrix with + /// `[0,1]` depth range. + #[inline] + pub fn perspective_infinite_rh(fov_y_radians: f32, aspect_ratio: f32, z_near: f32) -> Self { + glam_assert!(z_near > 0.0); + let f = 1.0 / (0.5 * fov_y_radians).tan(); + Self::from_cols( + Vec4::new(f / aspect_ratio, 0.0, 0.0, 0.0), + Vec4::new(0.0, f, 0.0, 0.0), + Vec4::new(0.0, 0.0, -1.0, -1.0), + Vec4::new(0.0, 0.0, -z_near, 0.0), + ) + } + + /// Creates an infinite reverse right-handed perspective projection matrix + /// with `[0,1]` depth range. + #[inline] + pub fn perspective_infinite_reverse_rh( + fov_y_radians: f32, + aspect_ratio: f32, + z_near: f32, + ) -> Self { + glam_assert!(z_near > 0.0); + let f = 1.0 / (0.5 * fov_y_radians).tan(); + Self::from_cols( + Vec4::new(f / aspect_ratio, 0.0, 0.0, 0.0), + Vec4::new(0.0, f, 0.0, 0.0), + Vec4::new(0.0, 0.0, 0.0, -1.0), + Vec4::new(0.0, 0.0, z_near, 0.0), + ) + } + + /// Creates a right-handed orthographic projection matrix with `[-1,1]` depth + /// range. This is the same as the OpenGL `glOrtho` function in OpenGL. + /// See + /// + #[inline] + pub fn orthographic_rh_gl( + left: f32, + right: f32, + bottom: f32, + top: f32, + near: f32, + far: f32, + ) -> Self { + let a = 2.0 / (right - left); + let b = 2.0 / (top - bottom); + let c = -2.0 / (far - near); + let tx = -(right + left) / (right - left); + let ty = -(top + bottom) / (top - bottom); + let tz = -(far + near) / (far - near); + + Self::from_cols( + Vec4::new(a, 0.0, 0.0, 0.0), + Vec4::new(0.0, b, 0.0, 0.0), + Vec4::new(0.0, 0.0, c, 0.0), + Vec4::new(tx, ty, tz, 1.0), + ) + } + + /// Creates a left-handed orthographic projection matrix with `[0,1]` depth range. + #[inline] + pub fn orthographic_lh( + left: f32, + right: f32, + bottom: f32, + top: f32, + near: f32, + far: f32, + ) -> Self { + let rcp_width = 1.0 / (right - left); + let rcp_height = 1.0 / (top - bottom); + let r = 1.0 / (far - near); + Self::from_cols( + Vec4::new(rcp_width + rcp_width, 0.0, 0.0, 0.0), + Vec4::new(0.0, rcp_height + rcp_height, 0.0, 0.0), + Vec4::new(0.0, 0.0, r, 0.0), + Vec4::new( + -(left + right) * rcp_width, + -(top + bottom) * rcp_height, + -r * near, + 1.0, + ), + ) + } + + /// Creates a right-handed orthographic projection matrix with `[0,1]` depth range. + #[inline] + pub fn orthographic_rh( + left: f32, + right: f32, + bottom: f32, + top: f32, + near: f32, + far: f32, + ) -> Self { + let rcp_width = 1.0 / (right - left); + let rcp_height = 1.0 / (top - bottom); + let r = 1.0 / (near - far); + Self::from_cols( + Vec4::new(rcp_width + rcp_width, 0.0, 0.0, 0.0), + Vec4::new(0.0, rcp_height + rcp_height, 0.0, 0.0), + Vec4::new(0.0, 0.0, r, 0.0), + Vec4::new( + -(left + right) * rcp_width, + -(top + bottom) * rcp_height, + r * near, + 1.0, + ), + ) + } + + /// Transforms the given 3D vector as a point, applying perspective correction. + /// + /// This is the equivalent of multiplying the 3D vector as a 4D vector where `w` is `1.0`. + /// The perspective divide is performed meaning the resulting 3D vector is divided by `w`. + /// + /// This method assumes that `self` contains a projective transform. + #[inline] + pub fn project_point3(&self, rhs: Vec3) -> Vec3 { + let mut res = self.x_axis.mul(rhs.x); + res = self.y_axis.mul(rhs.y).add(res); + res = self.z_axis.mul(rhs.z).add(res); + res = self.w_axis.add(res); + res = res.mul(res.wwww().recip()); + res.xyz() + } + + /// Transforms the given 3D vector as a point. + /// + /// This is the equivalent of multiplying the 3D vector as a 4D vector where `w` is + /// `1.0`. + /// + /// This method assumes that `self` contains a valid affine transform. It does not perform + /// a persective divide, if `self` contains a perspective transform, or if you are unsure, + /// the [`Self::project_point3()`] method should be used instead. + /// + /// # Panics + /// + /// Will panic if the 3rd row of `self` is not `(0, 0, 0, 1)` when `glam_assert` is enabled. + #[inline] + pub fn transform_point3(&self, rhs: Vec3) -> Vec3 { + glam_assert!(self.row(3) == Vec4::W); + let mut res = self.x_axis.mul(rhs.x); + res = self.y_axis.mul(rhs.y).add(res); + res = self.z_axis.mul(rhs.z).add(res); + res = self.w_axis.add(res); + res.xyz() + } + + /// Transforms the give 3D vector as a direction. + /// + /// This is the equivalent of multiplying the 3D vector as a 4D vector where `w` is + /// `0.0`. + /// + /// This method assumes that `self` contains a valid affine transform. + /// + /// # Panics + /// + /// Will panic if the 3rd row of `self` is not `(0, 0, 0, 1)` when `glam_assert` is enabled. + #[inline] + pub fn transform_vector3(&self, rhs: Vec3) -> Vec3 { + glam_assert!(self.row(3) == Vec4::W); + let mut res = self.x_axis.mul(rhs.x); + res = self.y_axis.mul(rhs.y).add(res); + res = self.z_axis.mul(rhs.z).add(res); + res.xyz() + } + + /// Transforms the given `Vec3A` as 3D point. + /// + /// This is the equivalent of multiplying the `Vec3A` as a 4D vector where `w` is `1.0`. + #[inline] + pub fn transform_point3a(&self, rhs: Vec3A) -> Vec3A { + let mut res = self.x_axis.mul(rhs.xxxx()); + res = self.y_axis.mul(rhs.yyyy()).add(res); + res = self.z_axis.mul(rhs.zzzz()).add(res); + res = self.w_axis.add(res); + res.into() + } + + /// Transforms the give `Vec3A` as 3D vector. + /// + /// This is the equivalent of multiplying the `Vec3A` as a 4D vector where `w` is `0.0`. + #[inline] + pub fn transform_vector3a(&self, rhs: Vec3A) -> Vec3A { + let mut res = self.x_axis.mul(rhs.xxxx()); + res = self.y_axis.mul(rhs.yyyy()).add(res); + res = self.z_axis.mul(rhs.zzzz()).add(res); + res.into() + } + + /// Transforms a 4D vector. + #[inline] + pub fn mul_vec4(&self, rhs: Vec4) -> Vec4 { + let mut res = self.x_axis.mul(rhs.xxxx()); + res = res.add(self.y_axis.mul(rhs.yyyy())); + res = res.add(self.z_axis.mul(rhs.zzzz())); + res = res.add(self.w_axis.mul(rhs.wwww())); + res + } + + /// Multiplies two 4x4 matrices. + #[inline] + pub fn mul_mat4(&self, rhs: &Self) -> Self { + Self::from_cols( + self.mul(rhs.x_axis), + self.mul(rhs.y_axis), + self.mul(rhs.z_axis), + self.mul(rhs.w_axis), + ) + } + + /// Adds two 4x4 matrices. + #[inline] + pub fn add_mat4(&self, rhs: &Self) -> Self { + Self::from_cols( + self.x_axis.add(rhs.x_axis), + self.y_axis.add(rhs.y_axis), + self.z_axis.add(rhs.z_axis), + self.w_axis.add(rhs.w_axis), + ) + } + + /// Subtracts two 4x4 matrices. + #[inline] + pub fn sub_mat4(&self, rhs: &Self) -> Self { + Self::from_cols( + self.x_axis.sub(rhs.x_axis), + self.y_axis.sub(rhs.y_axis), + self.z_axis.sub(rhs.z_axis), + self.w_axis.sub(rhs.w_axis), + ) + } + + /// Multiplies a 4x4 matrix by a scalar. + #[inline] + pub fn mul_scalar(&self, rhs: f32) -> Self { + Self::from_cols( + self.x_axis.mul(rhs), + self.y_axis.mul(rhs), + self.z_axis.mul(rhs), + self.w_axis.mul(rhs), + ) + } + + /// Returns true if the absolute difference of all elements between `self` and `rhs` + /// is less than or equal to `max_abs_diff`. + /// + /// This can be used to compare if two matrices contain similar elements. It works best + /// when comparing with a known value. The `max_abs_diff` that should be used used + /// depends on the values being compared against. + /// + /// For more see + /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/). + #[inline] + pub fn abs_diff_eq(&self, rhs: Self, max_abs_diff: f32) -> bool { + self.x_axis.abs_diff_eq(rhs.x_axis, max_abs_diff) + && self.y_axis.abs_diff_eq(rhs.y_axis, max_abs_diff) + && self.z_axis.abs_diff_eq(rhs.z_axis, max_abs_diff) + && self.w_axis.abs_diff_eq(rhs.w_axis, max_abs_diff) + } + + #[inline] + pub fn as_dmat4(&self) -> DMat4 { + DMat4::from_cols( + self.x_axis.as_dvec4(), + self.y_axis.as_dvec4(), + self.z_axis.as_dvec4(), + self.w_axis.as_dvec4(), + ) + } +} + +impl Default for Mat4 { + #[inline] + fn default() -> Self { + Self::IDENTITY + } +} + +impl Add for Mat4 { + type Output = Self; + #[inline] + fn add(self, rhs: Self) -> Self::Output { + self.add_mat4(&rhs) + } +} + +impl AddAssign for Mat4 { + #[inline] + fn add_assign(&mut self, rhs: Self) { + *self = self.add_mat4(&rhs); + } +} + +impl Sub for Mat4 { + type Output = Self; + #[inline] + fn sub(self, rhs: Self) -> Self::Output { + self.sub_mat4(&rhs) + } +} + +impl SubAssign for Mat4 { + #[inline] + fn sub_assign(&mut self, rhs: Self) { + *self = self.sub_mat4(&rhs); + } +} + +impl Neg for Mat4 { + type Output = Self; + #[inline] + fn neg(self) -> Self::Output { + Self::from_cols( + self.x_axis.neg(), + self.y_axis.neg(), + self.z_axis.neg(), + self.w_axis.neg(), + ) + } +} + +impl Mul for Mat4 { + type Output = Self; + #[inline] + fn mul(self, rhs: Self) -> Self::Output { + self.mul_mat4(&rhs) + } +} + +impl MulAssign for Mat4 { + #[inline] + fn mul_assign(&mut self, rhs: Self) { + *self = self.mul_mat4(&rhs); + } +} + +impl Mul for Mat4 { + type Output = Vec4; + #[inline] + fn mul(self, rhs: Vec4) -> Self::Output { + self.mul_vec4(rhs) + } +} + +impl Mul for f32 { + type Output = Mat4; + #[inline] + fn mul(self, rhs: Mat4) -> Self::Output { + rhs.mul_scalar(self) + } +} + +impl Mul for Mat4 { + type Output = Self; + #[inline] + fn mul(self, rhs: f32) -> Self::Output { + self.mul_scalar(rhs) + } +} + +impl MulAssign for Mat4 { + #[inline] + fn mul_assign(&mut self, rhs: f32) { + *self = self.mul_scalar(rhs); + } +} + +impl<'a> Sum<&'a Self> for Mat4 { + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, |a, &b| Self::add(a, b)) + } +} + +impl<'a> Product<&'a Self> for Mat4 { + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::IDENTITY, |a, &b| Self::mul(a, b)) + } +} + +impl PartialEq for Mat4 { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.x_axis.eq(&rhs.x_axis) + && self.y_axis.eq(&rhs.y_axis) + && self.z_axis.eq(&rhs.z_axis) + && self.w_axis.eq(&rhs.w_axis) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsRef<[f32; 16]> for Mat4 { + #[inline] + fn as_ref(&self) -> &[f32; 16] { + unsafe { &*(self as *const Self as *const [f32; 16]) } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsMut<[f32; 16]> for Mat4 { + #[inline] + fn as_mut(&mut self) -> &mut [f32; 16] { + unsafe { &mut *(self as *mut Self as *mut [f32; 16]) } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Debug for Mat4 { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct(stringify!(Mat4)) + .field("x_axis", &self.x_axis) + .field("y_axis", &self.y_axis) + .field("z_axis", &self.z_axis) + .field("w_axis", &self.w_axis) + .finish() + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Display for Mat4 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "[{}, {}, {}, {}]", + self.x_axis, self.y_axis, self.z_axis, self.w_axis + ) + } +} diff --git a/src/f32/sse2/quat.rs b/src/f32/sse2/quat.rs new file mode 100644 index 00000000..9b273bfa --- /dev/null +++ b/src/f32/sse2/quat.rs @@ -0,0 +1,911 @@ +// Generated from quat.rs template. Edit the template, not the generated file. + +use crate::{ + euler::{EulerFromQuaternion, EulerRot, EulerToQuaternion}, + DQuat, FloatEx, Mat3, Mat4, Vec2, Vec3, Vec3A, Vec4, +}; + +#[cfg(not(feature = "std"))] +use num_traits::Float; + +#[cfg(target_arch = "x86")] +use core::arch::x86::*; +#[cfg(target_arch = "x86_64")] +use core::arch::x86_64::*; + +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::iter::{Product, Sum}; +use core::ops::{Add, Deref, Div, Mul, MulAssign, Neg, Sub}; + +union UnionCast { + a: [f32; 4], + v: Quat, +} + +/// Creates a quaternion from `x`, `y`, `z` and `w` values. +/// +/// This should generally not be called manually unless you know what you are doing. Use +/// one of the other constructors instead such as `identity` or `from_axis_angle`. +#[inline] +pub const fn quat(x: f32, y: f32, z: f32, w: f32) -> Quat { + Quat::from_xyzw(x, y, z, w) +} + +/// A quaternion representing an orientation. +/// +/// This quaternion is intended to be of unit length but may denormalize due to +/// floating point "error creep" which can occur when successive quaternion +/// operations are applied. +/// +/// This type is 16 byte aligned. +#[derive(Clone, Copy)] +#[repr(transparent)] +pub struct Quat(pub(crate) __m128); + +impl Quat { + /// All zeros. + const ZERO: Self = Self::from_array([0.0; 4]); + + /// The identity quaternion. Corresponds to no rotation. + pub const IDENTITY: Self = Self::from_xyzw(0.0, 0.0, 0.0, 1.0); + + /// All NANs. + pub const NAN: Self = Self::from_array([f32::NAN; 4]); + + /// Creates a new rotation quaternion. + /// + /// This should generally not be called manually unless you know what you are doing. + /// Use one of the other constructors instead such as `identity` or `from_axis_angle`. + /// + /// `from_xyzw` is mostly used by unit tests and `serde` deserialization. + /// + /// # Preconditions + /// + /// This function does not check if the input is normalized, it is up to the user to + /// provide normalized input or to normalized the resulting quaternion. + #[inline(always)] + pub const fn from_xyzw(x: f32, y: f32, z: f32, w: f32) -> Self { + unsafe { UnionCast { a: [x, y, z, w] }.v } + } + + /// Creates a rotation quaternion from an array. + /// + /// # Preconditions + /// + /// This function does not check if the input is normalized, it is up to the user to + /// provide normalized input or to normalized the resulting quaternion. + #[inline] + pub const fn from_array(a: [f32; 4]) -> Self { + Self::from_xyzw(a[0], a[1], a[2], a[3]) + } + + /// Creates a new rotation quaternion from a 4D vector. + /// + /// # Preconditions + /// + /// This function does not check if the input is normalized, it is up to the user to + /// provide normalized input or to normalized the resulting quaternion. + #[inline] + pub fn from_vec4(v: Vec4) -> Self { + Self(v.0) + } + + /// Creates a rotation quaternion from a slice. + /// + /// # Preconditions + /// + /// This function does not check if the input is normalized, it is up to the user to + /// provide normalized input or to normalized the resulting quaternion. + /// + /// # Panics + /// + /// Panics if `slice` length is less than 4. + #[inline] + pub fn from_slice(slice: &[f32]) -> Self { + assert!(slice.len() >= 4); + Self(unsafe { _mm_loadu_ps(slice.as_ptr()) }) + } + + /// Writes the quaternion to an unaligned slice. + /// + /// # Panics + /// + /// Panics if `slice` length is less than 4. + #[inline] + pub fn write_to_slice(self, slice: &mut [f32]) { + assert!(slice.len() >= 4); + unsafe { _mm_storeu_ps(slice.as_mut_ptr(), self.0) } + } + + /// Create a quaternion for a normalized rotation `axis` and `angle` (in radians). + /// The axis must be normalized (unit-length). + /// + /// # Panics + /// + /// Will panic if `axis` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn from_axis_angle(axis: Vec3, angle: f32) -> Self { + glam_assert!(axis.is_normalized()); + let (s, c) = (angle * 0.5).sin_cos(); + let v = axis * s; + Self::from_xyzw(v.x, v.y, v.z, c) + } + + /// Create a quaternion that rotates `v.length()` radians around `v.normalize()`. + /// + /// `from_scaled_axis(Vec3::ZERO)` results in the identity quaternion. + #[inline] + pub fn from_scaled_axis(v: Vec3) -> Self { + let length = v.length(); + if length == 0.0 { + Self::IDENTITY + } else { + Self::from_axis_angle(v / length, length) + } + } + + /// Creates a quaternion from the `angle` (in radians) around the x axis. + #[inline] + pub fn from_rotation_x(angle: f32) -> Self { + let (s, c) = (angle * 0.5).sin_cos(); + Self::from_xyzw(s, 0.0, 0.0, c) + } + + /// Creates a quaternion from the `angle` (in radians) around the y axis. + #[inline] + pub fn from_rotation_y(angle: f32) -> Self { + let (s, c) = (angle * 0.5).sin_cos(); + Self::from_xyzw(0.0, s, 0.0, c) + } + + /// Creates a quaternion from the `angle` (in radians) around the z axis. + #[inline] + pub fn from_rotation_z(angle: f32) -> Self { + let (s, c) = (angle * 0.5).sin_cos(); + Self::from_xyzw(0.0, 0.0, s, c) + } + + #[inline] + /// Creates a quaternion from the given Euler rotation sequence and the angles (in radians). + pub fn from_euler(euler: EulerRot, a: f32, b: f32, c: f32) -> Self { + euler.new_quat(a, b, c) + } + + /// From the columns of a 3x3 rotation matrix. + #[inline] + pub(crate) fn from_rotation_axes(x_axis: Vec3, y_axis: Vec3, z_axis: Vec3) -> Self { + // Based on https://github.com/microsoft/DirectXMath `XM$quaternionRotationMatrix` + // TODO: sse2 version + let (m00, m01, m02) = x_axis.into(); + let (m10, m11, m12) = y_axis.into(); + let (m20, m21, m22) = z_axis.into(); + if m22 <= 0.0 { + // x^2 + y^2 >= z^2 + w^2 + let dif10 = m11 - m00; + let omm22 = 1.0 - m22; + if dif10 <= 0.0 { + // x^2 >= y^2 + let four_xsq = omm22 - dif10; + let inv4x = 0.5 / four_xsq.sqrt(); + Self::from_xyzw( + four_xsq * inv4x, + (m01 + m10) * inv4x, + (m02 + m20) * inv4x, + (m12 - m21) * inv4x, + ) + } else { + // y^2 >= x^2 + let four_ysq = omm22 + dif10; + let inv4y = 0.5 / four_ysq.sqrt(); + Self::from_xyzw( + (m01 + m10) * inv4y, + four_ysq * inv4y, + (m12 + m21) * inv4y, + (m20 - m02) * inv4y, + ) + } + } else { + // z^2 + w^2 >= x^2 + y^2 + let sum10 = m11 + m00; + let opm22 = 1.0 + m22; + if sum10 <= 0.0 { + // z^2 >= w^2 + let four_zsq = opm22 - sum10; + let inv4z = 0.5 / four_zsq.sqrt(); + Self::from_xyzw( + (m02 + m20) * inv4z, + (m12 + m21) * inv4z, + four_zsq * inv4z, + (m01 - m10) * inv4z, + ) + } else { + // w^2 >= z^2 + let four_wsq = opm22 + sum10; + let inv4w = 0.5 / four_wsq.sqrt(); + Self::from_xyzw( + (m12 - m21) * inv4w, + (m20 - m02) * inv4w, + (m01 - m10) * inv4w, + four_wsq * inv4w, + ) + } + } + } + + /// Creates a quaternion from a 3x3 rotation matrix. + #[inline] + pub fn from_mat3(mat: &Mat3) -> Self { + Self::from_rotation_axes(mat.x_axis, mat.y_axis, mat.z_axis) + } + + /// Creates a quaternion from a 3x3 rotation matrix inside a homogeneous 4x4 matrix. + #[inline] + pub fn from_mat4(mat: &Mat4) -> Self { + Self::from_rotation_axes( + mat.x_axis.truncate(), + mat.y_axis.truncate(), + mat.z_axis.truncate(), + ) + } + + /// Gets the minimal rotation for transforming `from` to `to`. The rotation is in the + /// plane spanned by the two vectors. Will rotate at most 180 degrees. + /// + /// The input vectors must be normalized (unit-length). + /// + /// `from_rotation_arc(from, to) * from ≈ to`. + /// + /// For near-singular cases (from≈to and from≈-to) the current implementation + /// is only accurate to about 0.001 (for `f32`). + /// + /// # Panics + /// + /// Will panic if `from` or `to` are not normalized when `glam_assert` is enabled. + pub fn from_rotation_arc(from: Vec3, to: Vec3) -> Self { + glam_assert!(from.is_normalized()); + glam_assert!(to.is_normalized()); + + const ONE_MINUS_EPS: f32 = 1.0 - 2.0 * core::f32::EPSILON; + let dot = from.dot(to); + if dot > ONE_MINUS_EPS { + // 0° singulary: from ≈ to + Self::IDENTITY + } else if dot < -ONE_MINUS_EPS { + // 180° singulary: from ≈ -to + use core::f32::consts::PI; // half a turn = 𝛕/2 = 180° + Self::from_axis_angle(from.any_orthonormal_vector(), PI) + } else { + let c = from.cross(to); + Self::from_xyzw(c.x, c.y, c.z, 1.0 + dot).normalize() + } + } + + /// Gets the minimal rotation for transforming `from` to either `to` or `-to`. This means + /// that the resulting quaternion will rotate `from` so that it is colinear with `to`. + /// + /// The rotation is in the plane spanned by the two vectors. Will rotate at most 90 + /// degrees. + /// + /// The input vectors must be normalized (unit-length). + /// + /// `to.dot(from_rotation_arc_colinear(from, to) * from).abs() ≈ 1`. + /// + /// # Panics + /// + /// Will panic if `from` or `to` are not normalized when `glam_assert` is enabled. + #[inline] + pub fn from_rotation_arc_colinear(from: Vec3, to: Vec3) -> Self { + if from.dot(to) < 0.0 { + Self::from_rotation_arc(from, -to) + } else { + Self::from_rotation_arc(from, to) + } + } + + /// Gets the minimal rotation for transforming `from` to `to`. The resulting rotation is + /// around the z axis. Will rotate at most 180 degrees. + /// + /// The input vectors must be normalized (unit-length). + /// + /// `from_rotation_arc_2d(from, to) * from ≈ to`. + /// + /// For near-singular cases (from≈to and from≈-to) the current implementation + /// is only accurate to about 0.001 (for `f32`). + /// + /// # Panics + /// + /// Will panic if `from` or `to` are not normalized when `glam_assert` is enabled. + pub fn from_rotation_arc_2d(from: Vec2, to: Vec2) -> Self { + glam_assert!(from.is_normalized()); + glam_assert!(to.is_normalized()); + + const ONE_MINUS_EPSILON: f32 = 1.0 - 2.0 * core::f32::EPSILON; + let dot = from.dot(to); + if dot > ONE_MINUS_EPSILON { + // 0° singulary: from ≈ to + Self::IDENTITY + } else if dot < -ONE_MINUS_EPSILON { + // 180° singulary: from ≈ -to + const COS_FRAC_PI_2: f32 = 0.0; + const SIN_FRAC_PI_2: f32 = 1.0; + // rotation around z by PI radians + Self::from_xyzw(0.0, 0.0, SIN_FRAC_PI_2, COS_FRAC_PI_2) + } else { + // vector3 cross where z=0 + let z = from.x * to.y - to.x * from.y; + let w = 1.0 + dot; + // calculate length with x=0 and y=0 to normalize + let len_rcp = 1.0 / (z * z + w * w).sqrt(); + Self::from_xyzw(0.0, 0.0, z * len_rcp, w * len_rcp) + } + } + + /// Returns the rotation axis and angle (in radians) of `self`. + #[inline] + pub fn to_axis_angle(self) -> (Vec3, f32) { + const EPSILON: f32 = 1.0e-8; + const EPSILON_SQUARED: f32 = EPSILON * EPSILON; + let w = self.w; + let angle = w.acos_approx() * 2.0; + let scale_sq = f32::max(1.0 - w * w, 0.0); + if scale_sq >= EPSILON_SQUARED { + ( + Vec3::new(self.x, self.y, self.z) * scale_sq.sqrt().recip(), + angle, + ) + } else { + (Vec3::X, angle) + } + } + + /// Returns the rotation axis scaled by the rotation in radians. + #[inline] + pub fn to_scaled_axis(self) -> Vec3 { + let (axis, angle) = self.to_axis_angle(); + axis * angle + } + + /// Returns the rotation angles for the given euler rotation sequence. + #[inline] + pub fn to_euler(self, euler: EulerRot) -> (f32, f32, f32) { + euler.convert_quat(self) + } + + /// `[x, y, z, w]` + #[inline] + pub fn to_array(&self) -> [f32; 4] { + [self.x, self.y, self.z, self.w] + } + + /// Returns the vector part of the quaternion. + #[inline] + pub fn xyz(self) -> Vec3 { + Vec3::new(self.x, self.y, self.z) + } + + /// Returns the quaternion conjugate of `self`. For a unit quaternion the + /// conjugate is also the inverse. + #[must_use] + #[inline] + pub fn conjugate(self) -> Self { + const SIGN: __m128 = const_f32x4!([-0.0, -0.0, -0.0, 0.0]); + Self(unsafe { _mm_xor_ps(self.0, SIGN) }) + } + + /// Returns the inverse of a normalized quaternion. + /// + /// Typically quaternion inverse returns the conjugate of a normalized quaternion. + /// Because `self` is assumed to already be unit length this method *does not* normalize + /// before returning the conjugate. + /// + /// # Panics + /// + /// Will panic if `self` is not normalized when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn inverse(self) -> Self { + glam_assert!(self.is_normalized()); + self.conjugate() + } + + /// Computes the dot product of `self` and `rhs`. The dot product is + /// equal to the cosine of the angle between two quaternion rotations. + #[inline] + pub fn dot(self, rhs: Self) -> f32 { + Vec4::from(self).dot(Vec4::from(rhs)) + } + + /// Computes the length of `self`. + #[doc(alias = "magnitude")] + #[inline] + pub fn length(self) -> f32 { + Vec4::from(self).length() + } + + /// Computes the squared length of `self`. + /// + /// This is generally faster than `length()` as it avoids a square + /// root operation. + #[doc(alias = "magnitude2")] + #[inline] + pub fn length_squared(self) -> f32 { + Vec4::from(self).length_squared() + } + + /// Computes `1.0 / length()`. + /// + /// For valid results, `self` must _not_ be of length zero. + #[inline] + pub fn length_recip(self) -> f32 { + Vec4::from(self).length_recip() + } + + /// Returns `self` normalized to length 1.0. + /// + /// For valid results, `self` must _not_ be of length zero. + /// + /// Panics + /// + /// Will panic if `self` is zero length when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn normalize(self) -> Self { + Self::from_vec4(Vec4::from(self).normalize()) + } + + /// Returns `true` if, and only if, all elements are finite. + /// If any element is either `NaN`, positive or negative infinity, this will return `false`. + #[inline] + pub fn is_finite(self) -> bool { + Vec4::from(self).is_finite() + } + + #[inline] + pub fn is_nan(self) -> bool { + Vec4::from(self).is_nan() + } + + /// Returns whether `self` of length `1.0` or not. + /// + /// Uses a precision threshold of `1e-6`. + #[inline] + pub fn is_normalized(self) -> bool { + Vec4::from(self).is_normalized() + } + + #[inline] + pub fn is_near_identity(self) -> bool { + // Based on https://github.com/nfrechette/rtm `rtm::quat_near_identity` + let threshold_angle = 0.002_847_144_6; + // Because of floating point precision, we cannot represent very small rotations. + // The closest f32 to 1.0 that is not 1.0 itself yields: + // 0.99999994.acos() * 2.0 = 0.000690533954 rad + // + // An error threshold of 1.e-6 is used by default. + // (1.0 - 1.e-6).acos() * 2.0 = 0.00284714461 rad + // (1.0 - 1.e-7).acos() * 2.0 = 0.00097656250 rad + // + // We don't really care about the angle value itself, only if it's close to 0. + // This will happen whenever quat.w is close to 1.0. + // If the quat.w is close to -1.0, the angle will be near 2*PI which is close to + // a negative 0 rotation. By forcing quat.w to be positive, we'll end up with + // the shortest path. + let positive_w_angle = self.w.abs().acos_approx() * 2.0; + positive_w_angle < threshold_angle + } + + /// Returns the angle (in radians) for the minimal rotation + /// for transforming this quaternion into another. + /// + /// Both quaternions must be normalized. + /// + /// # Panics + /// + /// Will panic if `self` or `rhs` are not normalized when `glam_assert` is enabled. + #[inline] + pub fn angle_between(self, rhs: Self) -> f32 { + glam_assert!(self.is_normalized() && rhs.is_normalized()); + self.dot(rhs).abs().acos_approx() * 2.0 + } + + /// Returns true if the absolute difference of all elements between `self` and `rhs` + /// is less than or equal to `max_abs_diff`. + /// + /// This can be used to compare if two quaternions contain similar elements. It works + /// best when comparing with a known value. The `max_abs_diff` that should be used used + /// depends on the values being compared against. + /// + /// For more see + /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/). + #[inline] + pub fn abs_diff_eq(self, rhs: Self, max_abs_diff: f32) -> bool { + Vec4::from(self).abs_diff_eq(Vec4::from(rhs), max_abs_diff) + } + + /// Performs a linear interpolation between `self` and `rhs` based on + /// the value `s`. + /// + /// When `s` is `0.0`, the result will be equal to `self`. When `s` + /// is `1.0`, the result will be equal to `rhs`. + /// + /// # Panics + /// + /// Will panic if `self` or `end` are not normalized when `glam_assert` is enabled. + #[inline] + #[doc(alias = "mix")] + pub fn lerp(self, end: Self, s: f32) -> Self { + glam_assert!(self.is_normalized()); + glam_assert!(end.is_normalized()); + + const NEG_ZERO: __m128 = const_f32x4!([-0.0; 4]); + let start = self.0; + let end = end.0; + unsafe { + let dot = crate::sse2::dot4_into_m128(start, end); + // Calculate the bias, if the dot product is positive or zero, there is no bias + // but if it is negative, we want to flip the 'end' rotation XYZW components + let bias = _mm_and_ps(dot, NEG_ZERO); + let interpolated = _mm_add_ps( + _mm_mul_ps(_mm_sub_ps(_mm_xor_ps(end, bias), start), _mm_set_ps1(s)), + start, + ); + Quat(interpolated).normalize() + } + } + + /// Performs a spherical linear interpolation between `self` and `end` + /// based on the value `s`. + /// + /// When `s` is `0.0`, the result will be equal to `self`. When `s` + /// is `1.0`, the result will be equal to `end`. + /// + /// # Panics + /// + /// Will panic if `self` or `end` are not normalized when `glam_assert` is enabled. + #[inline] + pub fn slerp(self, mut end: Self, s: f32) -> Self { + // http://number-none.com/product/Understanding%20Slerp,%20Then%20Not%20Using%20It/ + glam_assert!(self.is_normalized()); + glam_assert!(end.is_normalized()); + + const DOT_THRESHOLD: f32 = 0.9995; + + // Note that a rotation can be represented by two quaternions: `q` and + // `-q`. The slerp path between `q` and `end` will be different from the + // path between `-q` and `end`. One path will take the long way around and + // one will take the short way. In order to correct for this, the `dot` + // product between `self` and `end` should be positive. If the `dot` + // product is negative, slerp between `self` and `-end`. + let mut dot = self.dot(end); + if dot < 0.0 { + end = -end; + dot = -dot; + } + + if dot > DOT_THRESHOLD { + // assumes lerp returns a normalized quaternion + self.lerp(end, s) + } else { + let theta = dot.acos_approx(); + + let x = 1.0 - s; + let y = s; + let z = 1.0; + + unsafe { + let tmp = _mm_mul_ps(_mm_set_ps1(theta), _mm_set_ps(0.0, z, y, x)); + let tmp = crate::sse2::m128_sin(tmp); + + let scale1 = _mm_shuffle_ps(tmp, tmp, 0b00_00_00_00); + let scale2 = _mm_shuffle_ps(tmp, tmp, 0b01_01_01_01); + let theta_sin = _mm_shuffle_ps(tmp, tmp, 0b10_10_10_10); + + Self(_mm_div_ps( + _mm_add_ps(_mm_mul_ps(self.0, scale1), _mm_mul_ps(end.0, scale2)), + theta_sin, + )) + } + } + } + + /// Multiplies a quaternion and a 3D vector, returning the rotated vector. + /// + /// # Panics + /// + /// Will panic if `self` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn mul_vec3(self, rhs: Vec3) -> Vec3 { + glam_assert!(self.is_normalized()); + + self.mul_vec3a(rhs.into()).into() + } + + /// Multiplies two quaternions. If they each represent a rotation, the result will + /// represent the combined rotation. + /// + /// Note that due to floating point rounding the result may not be perfectly normalized. + /// + /// # Panics + /// + /// Will panic if `self` or `rhs` are not normalized when `glam_assert` is enabled. + #[inline] + pub fn mul_quat(self, rhs: Self) -> Self { + glam_assert!(self.is_normalized()); + glam_assert!(rhs.is_normalized()); + + // Based on https://github.com/nfrechette/rtm `rtm::quat_mul` + const CONTROL_WZYX: __m128 = const_f32x4!([1.0, -1.0, 1.0, -1.0]); + const CONTROL_ZWXY: __m128 = const_f32x4!([1.0, 1.0, -1.0, -1.0]); + const CONTROL_YXWZ: __m128 = const_f32x4!([-1.0, 1.0, 1.0, -1.0]); + + let lhs = self.0; + let rhs = rhs.0; + + unsafe { + let r_xxxx = _mm_shuffle_ps(lhs, lhs, 0b00_00_00_00); + let r_yyyy = _mm_shuffle_ps(lhs, lhs, 0b01_01_01_01); + let r_zzzz = _mm_shuffle_ps(lhs, lhs, 0b10_10_10_10); + let r_wwww = _mm_shuffle_ps(lhs, lhs, 0b11_11_11_11); + + let lxrw_lyrw_lzrw_lwrw = _mm_mul_ps(r_wwww, rhs); + let l_wzyx = _mm_shuffle_ps(rhs, rhs, 0b00_01_10_11); + + let lwrx_lzrx_lyrx_lxrx = _mm_mul_ps(r_xxxx, l_wzyx); + let l_zwxy = _mm_shuffle_ps(l_wzyx, l_wzyx, 0b10_11_00_01); + + let lwrx_nlzrx_lyrx_nlxrx = _mm_mul_ps(lwrx_lzrx_lyrx_lxrx, CONTROL_WZYX); + + let lzry_lwry_lxry_lyry = _mm_mul_ps(r_yyyy, l_zwxy); + let l_yxwz = _mm_shuffle_ps(l_zwxy, l_zwxy, 0b00_01_10_11); + + let lzry_lwry_nlxry_nlyry = _mm_mul_ps(lzry_lwry_lxry_lyry, CONTROL_ZWXY); + + let lyrz_lxrz_lwrz_lzrz = _mm_mul_ps(r_zzzz, l_yxwz); + let result0 = _mm_add_ps(lxrw_lyrw_lzrw_lwrw, lwrx_nlzrx_lyrx_nlxrx); + + let nlyrz_lxrz_lwrz_wlzrz = _mm_mul_ps(lyrz_lxrz_lwrz_lzrz, CONTROL_YXWZ); + let result1 = _mm_add_ps(lzry_lwry_nlxry_nlyry, nlyrz_lxrz_lwrz_wlzrz); + + Self(_mm_add_ps(result0, result1)) + } + } + + /// Creates a quaternion from a 3x3 rotation matrix inside a 3D affine transform. + #[inline] + pub fn from_affine3(a: &crate::Affine3A) -> Self { + #[allow(clippy::useless_conversion)] + Self::from_rotation_axes( + a.matrix3.x_axis.into(), + a.matrix3.y_axis.into(), + a.matrix3.z_axis.into(), + ) + } + + /// Multiplies a quaternion and a 3D vector, returning the rotated vector. + #[inline] + pub fn mul_vec3a(self, rhs: Vec3A) -> Vec3A { + unsafe { + const TWO: __m128 = const_f32x4!([2.0; 4]); + let w = _mm_shuffle_ps(self.0, self.0, 0b11_11_11_11); + let b = self.0; + let b2 = crate::sse2::dot3_into_m128(b, b); + Vec3A(_mm_add_ps( + _mm_add_ps( + _mm_mul_ps(rhs.0, _mm_sub_ps(_mm_mul_ps(w, w), b2)), + _mm_mul_ps(b, _mm_mul_ps(crate::sse2::dot3_into_m128(rhs.0, b), TWO)), + ), + _mm_mul_ps(Vec3A(b).cross(rhs).into(), _mm_mul_ps(w, TWO)), + )) + } + } + + #[inline] + pub fn as_f64(self) -> DQuat { + DQuat::from_xyzw(self.x as f64, self.y as f64, self.z as f64, self.w as f64) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Debug for Quat { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_tuple(stringify!(Quat)) + .field(&self.x) + .field(&self.y) + .field(&self.z) + .field(&self.w) + .finish() + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Display for Quat { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(fmt, "[{}, {}, {}, {}]", self.x, self.y, self.z, self.w) + } +} + +impl Add for Quat { + type Output = Self; + /// Adds two quaternions. + /// + /// The sum is not guaranteed to be normalized. + /// + /// Note that addition is not the same as combining the rotations represented by the + /// two quaternions! That corresponds to multiplication. + #[inline] + fn add(self, rhs: Self) -> Self { + Self::from_vec4(Vec4::from(self) + Vec4::from(rhs)) + } +} + +impl Sub for Quat { + type Output = Self; + /// Subtracts the `rhs` quaternion from `self`. + /// + /// The difference is not guaranteed to be normalized. + #[inline] + fn sub(self, rhs: Self) -> Self { + Self::from_vec4(Vec4::from(self) - Vec4::from(rhs)) + } +} + +impl Mul for Quat { + type Output = Self; + /// Multiplies a quaternion by a scalar value. + /// + /// The product is not guaranteed to be normalized. + #[inline] + fn mul(self, rhs: f32) -> Self { + Self::from_vec4(Vec4::from(self) * rhs) + } +} + +impl Div for Quat { + type Output = Self; + /// Divides a quaternion by a scalar value. + /// The quotient is not guaranteed to be normalized. + #[inline] + fn div(self, rhs: f32) -> Self { + Self::from_vec4(Vec4::from(self) / rhs) + } +} + +impl Mul for Quat { + type Output = Self; + /// Multiplies two quaternions. If they each represent a rotation, the result will + /// represent the combined rotation. + /// + /// Note that due to floating point rounding the result may not be perfectly + /// normalized. + /// + /// # Panics + /// + /// Will panic if `self` or `rhs` are not normalized when `glam_assert` is enabled. + #[inline] + fn mul(self, rhs: Self) -> Self { + self.mul_quat(rhs) + } +} + +impl MulAssign for Quat { + /// Multiplies two quaternions. If they each represent a rotation, the result will + /// represent the combined rotation. + /// + /// Note that due to floating point rounding the result may not be perfectly + /// normalized. + /// + /// # Panics + /// + /// Will panic if `self` or `rhs` are not normalized when `glam_assert` is enabled. + #[inline] + fn mul_assign(&mut self, rhs: Self) { + *self = self.mul_quat(rhs); + } +} + +impl Mul for Quat { + type Output = Vec3; + /// Multiplies a quaternion and a 3D vector, returning the rotated vector. + /// + /// # Panics + /// + /// Will panic if `self` is not normalized when `glam_assert` is enabled. + #[inline] + fn mul(self, rhs: Vec3) -> Self::Output { + self.mul_vec3(rhs) + } +} + +impl Neg for Quat { + type Output = Self; + #[inline] + fn neg(self) -> Self { + self * -1.0 + } +} + +impl Default for Quat { + #[inline] + fn default() -> Self { + Self::IDENTITY + } +} + +impl PartialEq for Quat { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + Vec4::from(*self).eq(&Vec4::from(*rhs)) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsRef<[f32; 4]> for Quat { + #[inline] + fn as_ref(&self) -> &[f32; 4] { + unsafe { &*(self as *const Self as *const [f32; 4]) } + } +} + +impl<'a> Sum<&'a Self> for Quat { + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, |a, &b| Self::add(a, b)) + } +} + +impl<'a> Product<&'a Self> for Quat { + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::IDENTITY, |a, &b| Self::mul(a, b)) + } +} + +impl Mul for Quat { + type Output = Vec3A; + #[inline] + fn mul(self, rhs: Vec3A) -> Self::Output { + self.mul_vec3a(rhs) + } +} + +impl From for Vec4 { + #[inline] + fn from(q: Quat) -> Self { + Self(q.0) + } +} + +impl From for (f32, f32, f32, f32) { + #[inline] + fn from(q: Quat) -> Self { + Vec4::from(q).into() + } +} + +impl From for [f32; 4] { + #[inline] + fn from(q: Quat) -> Self { + Vec4::from(q).into() + } +} + +impl From for __m128 { + // TODO: write test + #[inline] + fn from(q: Quat) -> Self { + q.0 + } +} + +impl Deref for Quat { + type Target = crate::deref::XYZW; + #[inline] + fn deref(&self) -> &Self::Target { + unsafe { &*(self as *const Self).cast() } + } +} diff --git a/src/f32/sse2/vec3a.rs b/src/f32/sse2/vec3a.rs new file mode 100644 index 00000000..c44b4285 --- /dev/null +++ b/src/f32/sse2/vec3a.rs @@ -0,0 +1,1098 @@ +// Generated from vec.rs template. Edit the template, not the generated file. + +use crate::{BVec3A, Vec2, Vec3, Vec4}; + +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::iter::{Product, Sum}; +use core::{f32, ops::*}; + +#[cfg(target_arch = "x86")] +use core::arch::x86::*; +#[cfg(target_arch = "x86_64")] +use core::arch::x86_64::*; + +#[cfg(not(feature = "std"))] +use num_traits::Float; + +union UnionCast { + a: [f32; 4], + v: Vec3A, +} + +/// Creates a 3-dimensional vector. +#[inline(always)] +pub const fn vec3a(x: f32, y: f32, z: f32) -> Vec3A { + Vec3A::new(x, y, z) +} + +/// A 3-dimensional vector with SIMD support. +/// +/// This type is 16 byte aligned. A SIMD vector type is used for storage on supported platforms for +/// better performance than the `Vec3` type. +/// +/// It is possible to convert between `Vec3` and `Vec3A` types using `From` trait implementations. +#[derive(Clone, Copy)] +#[repr(transparent)] +pub struct Vec3A(pub(crate) __m128); + +impl Vec3A { + /// All zeroes. + pub const ZERO: Self = Self::splat(0.0); + + /// All ones. + pub const ONE: Self = Self::splat(1.0); + + /// All negative ones. + pub const NEG_ONE: Self = Self::splat(-1.0); + + /// All NAN. + pub const NAN: Self = Self::splat(f32::NAN); + + /// `[1.0, 0.0, 0.0]`: a unit-length vector pointing along the positive X axis. + pub const X: Self = Self::from_array([1.0, 0.0, 0.0]); + + /// `[0.0, 1.0, 0.0]`: a unit-length vector pointing along the positive Y axis. + pub const Y: Self = Self::from_array([0.0, 1.0, 0.0]); + + /// `[0.0, 0.0, 1.0]`: a unit-length vector pointing along the positive Z axis. + pub const Z: Self = Self::from_array([0.0, 0.0, 1.0]); + + /// The unit axes. + pub const AXES: [Self; 3] = [Self::X, Self::Y, Self::Z]; + + /// Creates a new vector. + #[inline(always)] + pub const fn new(x: f32, y: f32, z: f32) -> Self { + unsafe { UnionCast { a: [x, y, z, z] }.v } + } + + /// Creates a vector with all elements set to `v`. + #[inline] + pub const fn splat(v: f32) -> Self { + unsafe { UnionCast { a: [v; 4] }.v } + } + + /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use + /// for each element of `self`. + /// + /// A true element in the mask uses the corresponding element from `if_true`, and false + /// uses the element from `if_false`. + #[inline] + pub fn select(mask: BVec3A, if_true: Self, if_false: Self) -> Self { + Self(unsafe { + _mm_or_ps( + _mm_andnot_ps(mask.0, if_false.0), + _mm_and_ps(if_true.0, mask.0), + ) + }) + } + + /// Creates a new vector from an array. + #[inline] + pub const fn from_array(a: [f32; 3]) -> Self { + Self::new(a[0], a[1], a[2]) + } + + /// `[x, y, z]` + #[inline] + pub const fn to_array(&self) -> [f32; 3] { + unsafe { *(self as *const Vec3A as *const [f32; 3]) } + } + + /// Creates a vector from the first N values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than N elements long. + #[inline] + pub const fn from_slice(slice: &[f32]) -> Self { + Self::new(slice[0], slice[1], slice[2]) + } + + /// Writes the elements of `self` to the first 3 elements in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than N elements long. + #[inline] + pub fn write_to_slice(self, slice: &mut [f32]) { + slice[0] = self.x; + slice[1] = self.y; + slice[2] = self.z; + } + + /// Internal method for creating a 3D vector from a 4D vector, discarding `w`. + #[allow(dead_code)] + #[inline] + pub(crate) fn from_vec4(v: Vec4) -> Self { + Self(v.0) + } + + /// Creates a 4D vector from `self` and the given `w` value. + #[inline] + pub fn extend(self, w: f32) -> Vec4 { + Vec4::new(self.x, self.y, self.z, w) + } + + /// Creates a 2D vector from the `x` and `y` elements of `self`, discarding `z`. + /// + /// Truncation may also be performed by using `self.xy()` or `Vec2::from()`. + #[inline] + pub fn truncate(self) -> Vec2 { + use crate::swizzles::Vec3Swizzles; + self.xy() + } + + /// Computes the dot product of `self` and `rhs`. + #[inline] + pub fn dot(self, rhs: Self) -> f32 { + unsafe { crate::sse2::dot3(self.0, rhs.0) } + } + + /// Computes the cross product of `self` and `rhs`. + #[inline] + pub fn cross(self, rhs: Self) -> Self { + unsafe { + // x <- a.y*b.z - a.z*b.y + // y <- a.z*b.x - a.x*b.z + // z <- a.x*b.y - a.y*b.x + // We can save a shuffle by grouping it in this wacky order: + // (self.zxy() * rhs - self * rhs.zxy()).zxy() + let lhszxy = _mm_shuffle_ps(self.0, self.0, 0b01_01_00_10); + let rhszxy = _mm_shuffle_ps(rhs.0, rhs.0, 0b01_01_00_10); + let lhszxy_rhs = _mm_mul_ps(lhszxy, rhs.0); + let rhszxy_lhs = _mm_mul_ps(rhszxy, self.0); + let sub = _mm_sub_ps(lhszxy_rhs, rhszxy_lhs); + Self(_mm_shuffle_ps(sub, sub, 0b01_01_00_10)) + } + } + + /// Returns a vector containing the minimum values for each element of `self` and `rhs`. + /// + /// In other words this computes `[self.x.min(rhs.x), self.y.min(rhs.y), ..]`. + #[inline] + pub fn min(self, rhs: Self) -> Self { + Self(unsafe { _mm_min_ps(self.0, rhs.0) }) + } + + /// Returns a vector containing the maximum values for each element of `self` and `rhs`. + /// + /// In other words this computes `[self.x.max(rhs.x), self.y.max(rhs.y), ..]`. + #[inline] + pub fn max(self, rhs: Self) -> Self { + Self(unsafe { _mm_max_ps(self.0, rhs.0) }) + } + + /// Component-wise clamping of values, similar to [`f32::clamp`]. + /// + /// Each element in `min` must be less-or-equal to the corresponding element in `max`. + /// + /// # Panics + /// + /// Will panic if `min` is greater than `max` when `glam_assert` is enabled. + #[inline] + pub fn clamp(self, min: Self, max: Self) -> Self { + glam_assert!(min.cmple(max).all(), "clamp: expected min <= max"); + self.max(min).min(max) + } + + /// Returns the horizontal minimum of `self`. + /// + /// In other words this computes `min(x, y, ..)`. + #[inline] + pub fn min_element(self) -> f32 { + unsafe { + let v = self.0; + let v = _mm_min_ps(v, _mm_shuffle_ps(v, v, 0b01_01_10_10)); + let v = _mm_min_ps(v, _mm_shuffle_ps(v, v, 0b00_00_00_01)); + _mm_cvtss_f32(v) + } + } + + /// Returns the horizontal maximum of `self`. + /// + /// In other words this computes `max(x, y, ..)`. + #[inline] + pub fn max_element(self) -> f32 { + unsafe { + let v = self.0; + let v = _mm_max_ps(v, _mm_shuffle_ps(v, v, 0b00_00_10_10)); + let v = _mm_max_ps(v, _mm_shuffle_ps(v, v, 0b00_00_00_01)); + _mm_cvtss_f32(v) + } + } + + /// Returns a vector mask containing the result of a `==` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words, this computes `[self.x == rhs.x, self.y == rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpeq(self, rhs: Self) -> BVec3A { + BVec3A(unsafe { _mm_cmpeq_ps(self.0, rhs.0) }) + } + + /// Returns a vector mask containing the result of a `!=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x != rhs.x, self.y != rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpne(self, rhs: Self) -> BVec3A { + BVec3A(unsafe { _mm_cmpneq_ps(self.0, rhs.0) }) + } + + /// Returns a vector mask containing the result of a `>=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x >= rhs.x, self.y >= rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpge(self, rhs: Self) -> BVec3A { + BVec3A(unsafe { _mm_cmpge_ps(self.0, rhs.0) }) + } + + /// Returns a vector mask containing the result of a `>` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x > rhs.x, self.y > rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpgt(self, rhs: Self) -> BVec3A { + BVec3A(unsafe { _mm_cmpgt_ps(self.0, rhs.0) }) + } + + /// Returns a vector mask containing the result of a `<=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x <= rhs.x, self.y <= rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmple(self, rhs: Self) -> BVec3A { + BVec3A(unsafe { _mm_cmple_ps(self.0, rhs.0) }) + } + + /// Returns a vector mask containing the result of a `<` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x < rhs.x, self.y < rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmplt(self, rhs: Self) -> BVec3A { + BVec3A(unsafe { _mm_cmplt_ps(self.0, rhs.0) }) + } + + /// Returns a vector containing the absolute value of each element of `self`. + #[inline] + pub fn abs(self) -> Self { + Self(unsafe { crate::sse2::m128_abs(self.0) }) + } + + /// Returns a vector with elements representing the sign of `self`. + /// + /// - `1.0` if the number is positive, `+0.0` or `INFINITY` + /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` + /// - `NAN` if the number is `NAN` + #[inline] + pub fn signum(self) -> Self { + let mask = self.cmpge(Self::ZERO); + let result = Self::select(mask, Self::ONE, Self::NEG_ONE); + let mask = self.is_nan_mask(); + Self::select(mask, self, result) + } + + /// Returns `true` if, and only if, all elements are finite. If any element is either + /// `NaN`, positive or negative infinity, this will return `false`. + #[inline] + pub fn is_finite(self) -> bool { + self.x.is_finite() && self.y.is_finite() && self.z.is_finite() + } + + /// Returns `true` if any elements are `NaN`. + #[inline] + pub fn is_nan(self) -> bool { + self.is_nan_mask().any() + } + + /// Performs `is_nan` on each element of self, returning a vector mask of the results. + /// + /// In other words, this computes `[x.is_nan(), y.is_nan(), z.is_nan(), w.is_nan()]`. + #[inline] + pub fn is_nan_mask(self) -> BVec3A { + BVec3A(unsafe { _mm_cmpunord_ps(self.0, self.0) }) + } + + /// Computes the length of `self`. + #[doc(alias = "magnitude")] + #[inline] + pub fn length(self) -> f32 { + unsafe { + let dot = crate::sse2::dot3_in_x(self.0, self.0); + _mm_cvtss_f32(_mm_sqrt_ps(dot)) + } + } + + /// Computes the squared length of `self`. + /// + /// This is faster than `length()` as it avoids a square root operation. + #[doc(alias = "magnitude2")] + #[inline] + pub fn length_squared(self) -> f32 { + self.dot(self) + } + + /// Computes `1.0 / length()`. + /// + /// For valid results, `self` must _not_ be of length zero. + #[inline] + pub fn length_recip(self) -> f32 { + unsafe { + let dot = crate::sse2::dot3_in_x(self.0, self.0); + _mm_cvtss_f32(_mm_div_ps(Self::ONE.0, _mm_sqrt_ps(dot))) + } + } + + /// Computes the Euclidean distance between two points in space. + #[inline] + pub fn distance(self, rhs: Self) -> f32 { + (self - rhs).length() + } + + /// Compute the squared euclidean distance between two points in space. + #[inline] + pub fn distance_squared(self, rhs: Self) -> f32 { + (self - rhs).length_squared() + } + + /// Returns `self` normalized to length 1.0. + /// + /// For valid results, `self` must _not_ be of length zero, nor very close to zero. + /// + /// See also [`Self::try_normalize`] and [`Self::normalize_or_zero`]. + /// + /// Panics + /// + /// Will panic if `self` is zero length when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn normalize(self) -> Self { + unsafe { + let length = _mm_sqrt_ps(crate::sse2::dot3_into_m128(self.0, self.0)); + #[allow(clippy::let_and_return)] + let normalized = Self(_mm_div_ps(self.0, length)); + glam_assert!(normalized.is_finite()); + normalized + } + } + + /// Returns `self` normalized to length 1.0 if possible, else returns `None`. + /// + /// In particular, if the input is zero (or very close to zero), or non-finite, + /// the result of this operation will be `None`. + /// + /// See also [`Self::normalize_or_zero`]. + #[must_use] + #[inline] + pub fn try_normalize(self) -> Option { + let rcp = self.length_recip(); + if rcp.is_finite() && rcp > 0.0 { + Some(self * rcp) + } else { + None + } + } + + /// Returns `self` normalized to length 1.0 if possible, else returns zero. + /// + /// In particular, if the input is zero (or very close to zero), or non-finite, + /// the result of this operation will be zero. + /// + /// See also [`Self::try_normalize`]. + #[must_use] + #[inline] + pub fn normalize_or_zero(self) -> Self { + let rcp = self.length_recip(); + if rcp.is_finite() && rcp > 0.0 { + self * rcp + } else { + Self::ZERO + } + } + + /// Returns whether `self` is length `1.0` or not. + /// + /// Uses a precision threshold of `1e-6`. + #[inline] + pub fn is_normalized(self) -> bool { + // TODO: do something with epsilon + (self.length_squared() - 1.0).abs() <= 1e-4 + } + + /// Returns the vector projection of `self` onto `rhs`. + /// + /// `rhs` must be of non-zero length. + /// + /// # Panics + /// + /// Will panic if `rhs` is zero length when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn project_onto(self, rhs: Self) -> Self { + let other_len_sq_rcp = rhs.dot(rhs).recip(); + glam_assert!(other_len_sq_rcp.is_finite()); + rhs * self.dot(rhs) * other_len_sq_rcp + } + + /// Returns the vector rejection of `self` from `rhs`. + /// + /// The vector rejection is the vector perpendicular to the projection of `self` onto + /// `rhs`, in rhs words the result of `self - self.project_onto(rhs)`. + /// + /// `rhs` must be of non-zero length. + /// + /// # Panics + /// + /// Will panic if `rhs` has a length of zero when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn reject_from(self, rhs: Self) -> Self { + self - self.project_onto(rhs) + } + + /// Returns the vector projection of `self` onto `rhs`. + /// + /// `rhs` must be normalized. + /// + /// # Panics + /// + /// Will panic if `rhs` is not normalized when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn project_onto_normalized(self, rhs: Self) -> Self { + glam_assert!(rhs.is_normalized()); + rhs * self.dot(rhs) + } + + /// Returns the vector rejection of `self` from `rhs`. + /// + /// The vector rejection is the vector perpendicular to the projection of `self` onto + /// `rhs`, in rhs words the result of `self - self.project_onto(rhs)`. + /// + /// `rhs` must be normalized. + /// + /// # Panics + /// + /// Will panic if `rhs` is not normalized when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn reject_from_normalized(self, rhs: Self) -> Self { + self - self.project_onto_normalized(rhs) + } + + /// Returns a vector containing the nearest integer to a number for each element of `self`. + /// Round half-way cases away from 0.0. + #[inline] + pub fn round(self) -> Self { + Self(unsafe { crate::sse2::m128_round(self.0) }) + } + + /// Returns a vector containing the largest integer less than or equal to a number for each + /// element of `self`. + #[inline] + pub fn floor(self) -> Self { + Self(unsafe { crate::sse2::m128_floor(self.0) }) + } + + /// Returns a vector containing the smallest integer greater than or equal to a number for + /// each element of `self`. + #[inline] + pub fn ceil(self) -> Self { + Self(unsafe { crate::sse2::m128_ceil(self.0) }) + } + + /// Returns a vector containing the fractional part of the vector, e.g. `self - + /// self.floor()`. + /// + /// Note that this is fast but not precise for large numbers. + #[inline] + pub fn fract(self) -> Self { + self - self.floor() + } + + /// Returns a vector containing `e^self` (the exponential function) for each element of + /// `self`. + #[inline] + pub fn exp(self) -> Self { + Self::new(self.x.exp(), self.y.exp(), self.z.exp()) + } + + /// Returns a vector containing each element of `self` raised to the power of `n`. + #[inline] + pub fn powf(self, n: f32) -> Self { + Self::new(self.x.powf(n), self.y.powf(n), self.z.powf(n)) + } + + /// Returns a vector containing the reciprocal `1.0/n` of each element of `self`. + #[inline] + pub fn recip(self) -> Self { + Self(unsafe { _mm_div_ps(Self::ONE.0, self.0) }) + } + + /// Performs a linear interpolation between `self` and `rhs` based on the value `s`. + /// + /// When `s` is `0.0`, the result will be equal to `self`. When `s` is `1.0`, the result + /// will be equal to `rhs`. When `s` is outside of range `[0, 1]`, the result is linearly + /// extrapolated. + #[doc(alias = "mix")] + #[inline] + pub fn lerp(self, rhs: Self, s: f32) -> Self { + self + ((rhs - self) * s) + } + + /// Returns true if the absolute difference of all elements between `self` and `rhs` is + /// less than or equal to `max_abs_diff`. + /// + /// This can be used to compare if two vectors contain similar elements. It works best when + /// comparing with a known value. The `max_abs_diff` that should be used used depends on + /// the values being compared against. + /// + /// For more see + /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/). + #[inline] + pub fn abs_diff_eq(self, rhs: Self, max_abs_diff: f32) -> bool { + self.sub(rhs).abs().cmple(Self::splat(max_abs_diff)).all() + } + + /// Returns a vector with a length no less than `min` and no more than `max` + /// + /// # Panics + /// + /// Will panic if `min` is greater than `max` when `glam_assert` is enabled. + #[inline] + pub fn clamp_length(self, min: f32, max: f32) -> Self { + glam_assert!(min <= max); + let length_sq = self.length_squared(); + if length_sq < min * min { + self * (length_sq.sqrt().recip() * min) + } else if length_sq > max * max { + self * (length_sq.sqrt().recip() * max) + } else { + self + } + } + + /// Returns a vector with a length no more than `max` + pub fn clamp_length_max(self, max: f32) -> Self { + let length_sq = self.length_squared(); + if length_sq > max * max { + self * (length_sq.sqrt().recip() * max) + } else { + self + } + } + + /// Returns a vector with a length no less than `min` + pub fn clamp_length_min(self, min: f32) -> Self { + let length_sq = self.length_squared(); + if length_sq < min * min { + self * (length_sq.sqrt().recip() * min) + } else { + self + } + } + + /// Fused multiply-add. Computes `(self * a) + b` element-wise with only one rounding + /// error, yielding a more accurate result than an unfused multiply-add. + /// + /// Using `mul_add` *may* be more performant than an unfused multiply-add if the target + /// architecture has a dedicated fma CPU instruction. However, this is not always true, + /// and will be heavily dependant on designing algorithms with specific target hardware in + /// mind. + #[inline] + pub fn mul_add(self, a: Self, b: Self) -> Self { + #[cfg(target_feature = "fma")] + unsafe { + _mm_fmadd_ps(self, b, c) + } + #[cfg(not(target_feature = "fma"))] + Self::new( + self.x.mul_add(a.x, b.x), + self.y.mul_add(a.y, b.y), + self.z.mul_add(a.z, b.z), + ) + } + + /// Returns the angle (in radians) between two vectors. + /// + /// The input vectors do not need to be unit length however they must be non-zero. + #[inline] + pub fn angle_between(self, rhs: Self) -> f32 { + use crate::FloatEx; + self.dot(rhs) + .div(self.length_squared().mul(rhs.length_squared()).sqrt()) + .acos_approx() + } + + /// Returns some vector that is orthogonal to the given one. + /// + /// The input vector must be finite and non-zero. + /// + /// The output vector is not necessarily unit-length. + /// For that use [`Self::any_orthonormal_vector`] instead. + #[inline] + pub fn any_orthogonal_vector(&self) -> Self { + // This can probably be optimized + if self.x.abs() > self.y.abs() { + Self::new(-self.z, 0.0, self.x) // self.cross(Self::Y) + } else { + Self::new(0.0, self.z, -self.y) // self.cross(Self::X) + } + } + + /// Returns any unit-length vector that is orthogonal to the given one. + /// The input vector must be finite and non-zero. + /// + /// # Panics + /// + /// Will panic if `self` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn any_orthonormal_vector(&self) -> Self { + glam_assert!(self.is_normalized()); + // From https://graphics.pixar.com/library/OrthonormalB/paper.pdf + #[cfg(feature = "std")] + let sign = (1.0_f32).copysign(self.z); + #[cfg(not(feature = "std"))] + let sign = self.z.signum(); + let a = -1.0 / (sign + self.z); + let b = self.x * self.y * a; + Self::new(b, sign + self.y * self.y * a, -self.y) + } + + /// Given a unit-length vector return two other vectors that together form an orthonormal + /// basis. That is, all three vectors are orthogonal to each other and are normalized. + /// + /// # Panics + /// + /// Will panic if `self` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn any_orthonormal_pair(&self) -> (Self, Self) { + glam_assert!(self.is_normalized()); + // From https://graphics.pixar.com/library/OrthonormalB/paper.pdf + #[cfg(feature = "std")] + let sign = (1.0_f32).copysign(self.z); + #[cfg(not(feature = "std"))] + let sign = self.z.signum(); + let a = -1.0 / (sign + self.z); + let b = self.x * self.y * a; + ( + Self::new(1.0 + sign * self.x * self.x * a, sign * b, -sign * self.x), + Self::new(b, sign + self.y * self.y * a, -self.y), + ) + } + + /// Casts all elements of `self` to `f64`. + #[inline] + pub fn as_dvec3(&self) -> crate::DVec3 { + crate::DVec3::new(self.x as f64, self.y as f64, self.z as f64) + } + + /// Casts all elements of `self` to `i32`. + #[inline] + pub fn as_ivec3(&self) -> crate::IVec3 { + crate::IVec3::new(self.x as i32, self.y as i32, self.z as i32) + } + + /// Casts all elements of `self` to `u32`. + #[inline] + pub fn as_uvec3(&self) -> crate::UVec3 { + crate::UVec3::new(self.x as u32, self.y as u32, self.z as u32) + } +} + +impl Default for Vec3A { + #[inline(always)] + fn default() -> Self { + Self::ZERO + } +} + +impl PartialEq for Vec3A { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.cmpeq(*rhs).all() + } +} + +impl Div for Vec3A { + type Output = Self; + #[inline] + fn div(self, rhs: Self) -> Self { + Self(unsafe { _mm_div_ps(self.0, rhs.0) }) + } +} + +impl DivAssign for Vec3A { + #[inline] + fn div_assign(&mut self, rhs: Self) { + self.0 = unsafe { _mm_div_ps(self.0, rhs.0) }; + } +} + +impl Div for Vec3A { + type Output = Self; + #[inline] + fn div(self, rhs: f32) -> Self { + Self(unsafe { _mm_div_ps(self.0, _mm_set1_ps(rhs)) }) + } +} + +impl DivAssign for Vec3A { + #[inline] + fn div_assign(&mut self, rhs: f32) { + self.0 = unsafe { _mm_div_ps(self.0, _mm_set1_ps(rhs)) }; + } +} + +impl Div for f32 { + type Output = Vec3A; + #[inline] + fn div(self, rhs: Vec3A) -> Vec3A { + Vec3A(unsafe { _mm_div_ps(_mm_set1_ps(self), rhs.0) }) + } +} + +impl Mul for Vec3A { + type Output = Self; + #[inline] + fn mul(self, rhs: Self) -> Self { + Self(unsafe { _mm_mul_ps(self.0, rhs.0) }) + } +} + +impl MulAssign for Vec3A { + #[inline] + fn mul_assign(&mut self, rhs: Self) { + self.0 = unsafe { _mm_mul_ps(self.0, rhs.0) }; + } +} + +impl Mul for Vec3A { + type Output = Self; + #[inline] + fn mul(self, rhs: f32) -> Self { + Self(unsafe { _mm_mul_ps(self.0, _mm_set1_ps(rhs)) }) + } +} + +impl MulAssign for Vec3A { + #[inline] + fn mul_assign(&mut self, rhs: f32) { + self.0 = unsafe { _mm_mul_ps(self.0, _mm_set1_ps(rhs)) }; + } +} + +impl Mul for f32 { + type Output = Vec3A; + #[inline] + fn mul(self, rhs: Vec3A) -> Vec3A { + Vec3A(unsafe { _mm_mul_ps(_mm_set1_ps(self), rhs.0) }) + } +} + +impl Add for Vec3A { + type Output = Self; + #[inline] + fn add(self, rhs: Self) -> Self { + Self(unsafe { _mm_add_ps(self.0, rhs.0) }) + } +} + +impl AddAssign for Vec3A { + #[inline] + fn add_assign(&mut self, rhs: Self) { + self.0 = unsafe { _mm_add_ps(self.0, rhs.0) }; + } +} + +impl Add for Vec3A { + type Output = Self; + #[inline] + fn add(self, rhs: f32) -> Self { + Self(unsafe { _mm_add_ps(self.0, _mm_set1_ps(rhs)) }) + } +} + +impl AddAssign for Vec3A { + #[inline] + fn add_assign(&mut self, rhs: f32) { + self.0 = unsafe { _mm_add_ps(self.0, _mm_set1_ps(rhs)) }; + } +} + +impl Add for f32 { + type Output = Vec3A; + #[inline] + fn add(self, rhs: Vec3A) -> Vec3A { + Vec3A(unsafe { _mm_add_ps(_mm_set1_ps(self), rhs.0) }) + } +} + +impl Sub for Vec3A { + type Output = Self; + #[inline] + fn sub(self, rhs: Self) -> Self { + Self(unsafe { _mm_sub_ps(self.0, rhs.0) }) + } +} + +impl SubAssign for Vec3A { + #[inline] + fn sub_assign(&mut self, rhs: Vec3A) { + self.0 = unsafe { _mm_sub_ps(self.0, rhs.0) }; + } +} + +impl Sub for Vec3A { + type Output = Self; + #[inline] + fn sub(self, rhs: f32) -> Self { + Self(unsafe { _mm_sub_ps(self.0, _mm_set1_ps(rhs)) }) + } +} + +impl SubAssign for Vec3A { + #[inline] + fn sub_assign(&mut self, rhs: f32) { + self.0 = unsafe { _mm_sub_ps(self.0, _mm_set1_ps(rhs)) }; + } +} + +impl Sub for f32 { + type Output = Vec3A; + #[inline] + fn sub(self, rhs: Vec3A) -> Vec3A { + Vec3A(unsafe { _mm_sub_ps(_mm_set1_ps(self), rhs.0) }) + } +} + +impl Rem for Vec3A { + type Output = Self; + #[inline] + fn rem(self, rhs: Self) -> Self { + unsafe { + let n = crate::sse2::m128_floor(_mm_div_ps(self.0, rhs.0)); + Self(_mm_sub_ps(self.0, _mm_mul_ps(n, rhs.0))) + } + } +} + +impl RemAssign for Vec3A { + #[inline] + fn rem_assign(&mut self, rhs: Self) { + *self = self.rem(rhs); + } +} + +impl Rem for Vec3A { + type Output = Self; + #[inline] + fn rem(self, rhs: f32) -> Self { + self.rem(Self::splat(rhs)) + } +} + +impl RemAssign for Vec3A { + #[inline] + fn rem_assign(&mut self, rhs: f32) { + *self = self.rem(Self::splat(rhs)); + } +} + +impl Rem for f32 { + type Output = Vec3A; + #[inline] + fn rem(self, rhs: Vec3A) -> Vec3A { + Vec3A::splat(self).rem(rhs) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsRef<[f32; 3]> for Vec3A { + #[inline] + fn as_ref(&self) -> &[f32; 3] { + unsafe { &*(self as *const Vec3A as *const [f32; 3]) } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsMut<[f32; 3]> for Vec3A { + #[inline] + fn as_mut(&mut self) -> &mut [f32; 3] { + unsafe { &mut *(self as *mut Vec3A as *mut [f32; 3]) } + } +} + +impl<'a> Sum<&'a Self> for Vec3A { + #[inline] + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, |a, &b| Self::add(a, b)) + } +} + +impl<'a> Product<&'a Self> for Vec3A { + #[inline] + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ONE, |a, &b| Self::mul(a, b)) + } +} + +impl Neg for Vec3A { + type Output = Self; + #[inline] + fn neg(self) -> Self { + Self(unsafe { _mm_sub_ps(Self::ZERO.0, self.0) }) + } +} + +impl Index for Vec3A { + type Output = f32; + #[inline] + fn index(&self, index: usize) -> &Self::Output { + match index { + 0 => &self.x, + 1 => &self.y, + 2 => &self.z, + _ => panic!("index out of bounds"), + } + } +} + +impl IndexMut for Vec3A { + #[inline] + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + match index { + 0 => &mut self.x, + 1 => &mut self.y, + 2 => &mut self.z, + _ => panic!("index out of bounds"), + } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Display for Vec3A { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "[{}, {}, {}]", self.x, self.y, self.z) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Debug for Vec3A { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_tuple(stringify!(Vec3A)) + .field(&self.x) + .field(&self.y) + .field(&self.z) + .finish() + } +} + +impl From for __m128 { + #[inline] + fn from(t: Vec3A) -> Self { + t.0 + } +} + +impl From<__m128> for Vec3A { + #[inline] + fn from(t: __m128) -> Self { + Self(t) + } +} + +impl From<[f32; 3]> for Vec3A { + #[inline] + fn from(a: [f32; 3]) -> Self { + Self::new(a[0], a[1], a[2]) + } +} + +impl From for [f32; 3] { + #[inline] + fn from(v: Vec3A) -> Self { + use crate::Align16; + use core::mem::MaybeUninit; + let mut out: MaybeUninit> = MaybeUninit::uninit(); + unsafe { + _mm_store_ps(out.as_mut_ptr().cast(), v.0); + out.assume_init().0 + } + } +} + +impl From<(f32, f32, f32)> for Vec3A { + #[inline] + fn from(t: (f32, f32, f32)) -> Self { + Self::new(t.0, t.1, t.2) + } +} + +impl From for (f32, f32, f32) { + #[inline] + fn from(v: Vec3A) -> Self { + use crate::Align16; + use core::mem::MaybeUninit; + let mut out: MaybeUninit> = MaybeUninit::uninit(); + unsafe { + _mm_store_ps(out.as_mut_ptr().cast(), v.0); + out.assume_init().0 + } + } +} + +impl From for Vec3A { + #[inline] + fn from(v: Vec3) -> Self { + Self::new(v.x, v.y, v.z) + } +} + +impl From for Vec3A { + /// Creates a `Vec3A` from the `x`, `y` and `z` elements of `self` discarding `w`. + /// + /// On architectures where SIMD is supported such as SSE2 on `x86_64` this conversion is a noop. + #[inline] + fn from(v: Vec4) -> Self { + Self(v.0) + } +} + +impl From<(Vec2, f32)> for Vec3A { + #[inline] + fn from((v, z): (Vec2, f32)) -> Self { + Self::new(v.x, v.y, z) + } +} + +impl Deref for Vec3A { + type Target = crate::deref::XYZ; + #[inline] + fn deref(&self) -> &Self::Target { + unsafe { &*(self as *const Self).cast() } + } +} + +impl DerefMut for Vec3A { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { &mut *(self as *mut Self).cast() } + } +} diff --git a/src/f32/sse2/vec4.rs b/src/f32/sse2/vec4.rs new file mode 100644 index 00000000..534527a0 --- /dev/null +++ b/src/f32/sse2/vec4.rs @@ -0,0 +1,1029 @@ +// Generated from vec.rs template. Edit the template, not the generated file. + +use crate::{BVec4A, Vec2, Vec3, Vec3A}; + +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::iter::{Product, Sum}; +use core::{f32, ops::*}; + +#[cfg(target_arch = "x86")] +use core::arch::x86::*; +#[cfg(target_arch = "x86_64")] +use core::arch::x86_64::*; + +#[cfg(not(feature = "std"))] +use num_traits::Float; + +union UnionCast { + a: [f32; 4], + v: Vec4, +} + +/// Creates a 4-dimensional vector. +#[inline(always)] +pub const fn vec4(x: f32, y: f32, z: f32, w: f32) -> Vec4 { + Vec4::new(x, y, z, w) +} + +/// A 4-dimensional vector with SIMD support. +/// +/// This type uses 16 byte aligned SIMD vector type for storage. +#[derive(Clone, Copy)] +#[repr(transparent)] +pub struct Vec4(pub(crate) __m128); + +impl Vec4 { + /// All zeroes. + pub const ZERO: Self = Self::splat(0.0); + + /// All ones. + pub const ONE: Self = Self::splat(1.0); + + /// All negative ones. + pub const NEG_ONE: Self = Self::splat(-1.0); + + /// All NAN. + pub const NAN: Self = Self::splat(f32::NAN); + + /// `[1.0, 0.0, 0.0, 0.0]`: a unit-length vector pointing along the positive X axis. + pub const X: Self = Self::from_array([1.0, 0.0, 0.0, 0.0]); + + /// `[0.0, 1.0, 0.0, 0.0]`: a unit-length vector pointing along the positive Y axis. + pub const Y: Self = Self::from_array([0.0, 1.0, 0.0, 0.0]); + + /// `[0.0, 0.0, 1.0, 0.0]`: a unit-length vector pointing along the positive Z axis. + pub const Z: Self = Self::from_array([0.0, 0.0, 1.0, 0.0]); + + /// `[0.0, 0.0, 0.0, 1.0]`: a unit-length vector pointing along the positive W axis. + pub const W: Self = Self::from_array([0.0, 0.0, 0.0, 1.0]); + + /// The unit axes. + pub const AXES: [Self; 4] = [Self::X, Self::Y, Self::Z, Self::W]; + + /// Creates a new vector. + #[inline(always)] + pub const fn new(x: f32, y: f32, z: f32, w: f32) -> Self { + unsafe { UnionCast { a: [x, y, z, w] }.v } + } + + /// Creates a vector with all elements set to `v`. + #[inline] + pub const fn splat(v: f32) -> Self { + unsafe { UnionCast { a: [v; 4] }.v } + } + + /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use + /// for each element of `self`. + /// + /// A true element in the mask uses the corresponding element from `if_true`, and false + /// uses the element from `if_false`. + #[inline] + pub fn select(mask: BVec4A, if_true: Self, if_false: Self) -> Self { + Self(unsafe { + _mm_or_ps( + _mm_andnot_ps(mask.0, if_false.0), + _mm_and_ps(if_true.0, mask.0), + ) + }) + } + + /// Creates a new vector from an array. + #[inline] + pub const fn from_array(a: [f32; 4]) -> Self { + Self::new(a[0], a[1], a[2], a[3]) + } + + /// `[x, y, z, w]` + #[inline] + pub const fn to_array(&self) -> [f32; 4] { + unsafe { *(self as *const Vec4 as *const [f32; 4]) } + } + + /// Creates a vector from the first N values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than N elements long. + #[inline] + pub const fn from_slice(slice: &[f32]) -> Self { + Self::new(slice[0], slice[1], slice[2], slice[3]) + } + + /// Writes the elements of `self` to the first 4 elements in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than N elements long. + #[inline] + pub fn write_to_slice(self, slice: &mut [f32]) { + unsafe { + assert!(slice.len() >= 4); + _mm_storeu_ps(slice.as_mut_ptr(), self.0); + } + } + + /// Creates a 2D vector from the `x`, `y` and `z` elements of `self`, discarding `w`. + /// + /// Truncation to `Vec3` may also be performed by using `self.xyz()` or `Vec3::from()`. + /// + /// To truncate to `Vec3A` use `Vec3A::from()`. + #[inline] + pub fn truncate(self) -> Vec3 { + use crate::swizzles::Vec4Swizzles; + self.xyz() + } + + /// Computes the dot product of `self` and `rhs`. + #[inline] + pub fn dot(self, rhs: Self) -> f32 { + unsafe { crate::sse2::dot4(self.0, rhs.0) } + } + + /// Returns a vector containing the minimum values for each element of `self` and `rhs`. + /// + /// In other words this computes `[self.x.min(rhs.x), self.y.min(rhs.y), ..]`. + #[inline] + pub fn min(self, rhs: Self) -> Self { + Self(unsafe { _mm_min_ps(self.0, rhs.0) }) + } + + /// Returns a vector containing the maximum values for each element of `self` and `rhs`. + /// + /// In other words this computes `[self.x.max(rhs.x), self.y.max(rhs.y), ..]`. + #[inline] + pub fn max(self, rhs: Self) -> Self { + Self(unsafe { _mm_max_ps(self.0, rhs.0) }) + } + + /// Component-wise clamping of values, similar to [`f32::clamp`]. + /// + /// Each element in `min` must be less-or-equal to the corresponding element in `max`. + /// + /// # Panics + /// + /// Will panic if `min` is greater than `max` when `glam_assert` is enabled. + #[inline] + pub fn clamp(self, min: Self, max: Self) -> Self { + glam_assert!(min.cmple(max).all(), "clamp: expected min <= max"); + self.max(min).min(max) + } + + /// Returns the horizontal minimum of `self`. + /// + /// In other words this computes `min(x, y, ..)`. + #[inline] + pub fn min_element(self) -> f32 { + unsafe { + let v = self.0; + let v = _mm_min_ps(v, _mm_shuffle_ps(v, v, 0b00_00_11_10)); + let v = _mm_min_ps(v, _mm_shuffle_ps(v, v, 0b00_00_00_01)); + _mm_cvtss_f32(v) + } + } + + /// Returns the horizontal maximum of `self`. + /// + /// In other words this computes `max(x, y, ..)`. + #[inline] + pub fn max_element(self) -> f32 { + unsafe { + let v = self.0; + let v = _mm_max_ps(v, _mm_shuffle_ps(v, v, 0b00_00_11_10)); + let v = _mm_max_ps(v, _mm_shuffle_ps(v, v, 0b00_00_00_01)); + _mm_cvtss_f32(v) + } + } + + /// Returns a vector mask containing the result of a `==` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words, this computes `[self.x == rhs.x, self.y == rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpeq(self, rhs: Self) -> BVec4A { + BVec4A(unsafe { _mm_cmpeq_ps(self.0, rhs.0) }) + } + + /// Returns a vector mask containing the result of a `!=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x != rhs.x, self.y != rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpne(self, rhs: Self) -> BVec4A { + BVec4A(unsafe { _mm_cmpneq_ps(self.0, rhs.0) }) + } + + /// Returns a vector mask containing the result of a `>=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x >= rhs.x, self.y >= rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpge(self, rhs: Self) -> BVec4A { + BVec4A(unsafe { _mm_cmpge_ps(self.0, rhs.0) }) + } + + /// Returns a vector mask containing the result of a `>` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x > rhs.x, self.y > rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpgt(self, rhs: Self) -> BVec4A { + BVec4A(unsafe { _mm_cmpgt_ps(self.0, rhs.0) }) + } + + /// Returns a vector mask containing the result of a `<=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x <= rhs.x, self.y <= rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmple(self, rhs: Self) -> BVec4A { + BVec4A(unsafe { _mm_cmple_ps(self.0, rhs.0) }) + } + + /// Returns a vector mask containing the result of a `<` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x < rhs.x, self.y < rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmplt(self, rhs: Self) -> BVec4A { + BVec4A(unsafe { _mm_cmplt_ps(self.0, rhs.0) }) + } + + /// Returns a vector containing the absolute value of each element of `self`. + #[inline] + pub fn abs(self) -> Self { + Self(unsafe { crate::sse2::m128_abs(self.0) }) + } + + /// Returns a vector with elements representing the sign of `self`. + /// + /// - `1.0` if the number is positive, `+0.0` or `INFINITY` + /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` + /// - `NAN` if the number is `NAN` + #[inline] + pub fn signum(self) -> Self { + let mask = self.cmpge(Self::ZERO); + let result = Self::select(mask, Self::ONE, Self::NEG_ONE); + let mask = self.is_nan_mask(); + Self::select(mask, self, result) + } + + /// Returns `true` if, and only if, all elements are finite. If any element is either + /// `NaN`, positive or negative infinity, this will return `false`. + #[inline] + pub fn is_finite(self) -> bool { + self.x.is_finite() && self.y.is_finite() && self.z.is_finite() && self.w.is_finite() + } + + /// Returns `true` if any elements are `NaN`. + #[inline] + pub fn is_nan(self) -> bool { + self.is_nan_mask().any() + } + + /// Performs `is_nan` on each element of self, returning a vector mask of the results. + /// + /// In other words, this computes `[x.is_nan(), y.is_nan(), z.is_nan(), w.is_nan()]`. + #[inline] + pub fn is_nan_mask(self) -> BVec4A { + BVec4A(unsafe { _mm_cmpunord_ps(self.0, self.0) }) + } + + /// Computes the length of `self`. + #[doc(alias = "magnitude")] + #[inline] + pub fn length(self) -> f32 { + unsafe { + let dot = crate::sse2::dot4_in_x(self.0, self.0); + _mm_cvtss_f32(_mm_sqrt_ps(dot)) + } + } + + /// Computes the squared length of `self`. + /// + /// This is faster than `length()` as it avoids a square root operation. + #[doc(alias = "magnitude2")] + #[inline] + pub fn length_squared(self) -> f32 { + self.dot(self) + } + + /// Computes `1.0 / length()`. + /// + /// For valid results, `self` must _not_ be of length zero. + #[inline] + pub fn length_recip(self) -> f32 { + unsafe { + let dot = crate::sse2::dot4_in_x(self.0, self.0); + _mm_cvtss_f32(_mm_div_ps(Self::ONE.0, _mm_sqrt_ps(dot))) + } + } + + /// Computes the Euclidean distance between two points in space. + #[inline] + pub fn distance(self, rhs: Self) -> f32 { + (self - rhs).length() + } + + /// Compute the squared euclidean distance between two points in space. + #[inline] + pub fn distance_squared(self, rhs: Self) -> f32 { + (self - rhs).length_squared() + } + + /// Returns `self` normalized to length 1.0. + /// + /// For valid results, `self` must _not_ be of length zero, nor very close to zero. + /// + /// See also [`Self::try_normalize`] and [`Self::normalize_or_zero`]. + /// + /// Panics + /// + /// Will panic if `self` is zero length when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn normalize(self) -> Self { + unsafe { + let length = _mm_sqrt_ps(crate::sse2::dot4_into_m128(self.0, self.0)); + #[allow(clippy::let_and_return)] + let normalized = Self(_mm_div_ps(self.0, length)); + glam_assert!(normalized.is_finite()); + normalized + } + } + + /// Returns `self` normalized to length 1.0 if possible, else returns `None`. + /// + /// In particular, if the input is zero (or very close to zero), or non-finite, + /// the result of this operation will be `None`. + /// + /// See also [`Self::normalize_or_zero`]. + #[must_use] + #[inline] + pub fn try_normalize(self) -> Option { + let rcp = self.length_recip(); + if rcp.is_finite() && rcp > 0.0 { + Some(self * rcp) + } else { + None + } + } + + /// Returns `self` normalized to length 1.0 if possible, else returns zero. + /// + /// In particular, if the input is zero (or very close to zero), or non-finite, + /// the result of this operation will be zero. + /// + /// See also [`Self::try_normalize`]. + #[must_use] + #[inline] + pub fn normalize_or_zero(self) -> Self { + let rcp = self.length_recip(); + if rcp.is_finite() && rcp > 0.0 { + self * rcp + } else { + Self::ZERO + } + } + + /// Returns whether `self` is length `1.0` or not. + /// + /// Uses a precision threshold of `1e-6`. + #[inline] + pub fn is_normalized(self) -> bool { + // TODO: do something with epsilon + (self.length_squared() - 1.0).abs() <= 1e-4 + } + + /// Returns the vector projection of `self` onto `rhs`. + /// + /// `rhs` must be of non-zero length. + /// + /// # Panics + /// + /// Will panic if `rhs` is zero length when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn project_onto(self, rhs: Self) -> Self { + let other_len_sq_rcp = rhs.dot(rhs).recip(); + glam_assert!(other_len_sq_rcp.is_finite()); + rhs * self.dot(rhs) * other_len_sq_rcp + } + + /// Returns the vector rejection of `self` from `rhs`. + /// + /// The vector rejection is the vector perpendicular to the projection of `self` onto + /// `rhs`, in rhs words the result of `self - self.project_onto(rhs)`. + /// + /// `rhs` must be of non-zero length. + /// + /// # Panics + /// + /// Will panic if `rhs` has a length of zero when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn reject_from(self, rhs: Self) -> Self { + self - self.project_onto(rhs) + } + + /// Returns the vector projection of `self` onto `rhs`. + /// + /// `rhs` must be normalized. + /// + /// # Panics + /// + /// Will panic if `rhs` is not normalized when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn project_onto_normalized(self, rhs: Self) -> Self { + glam_assert!(rhs.is_normalized()); + rhs * self.dot(rhs) + } + + /// Returns the vector rejection of `self` from `rhs`. + /// + /// The vector rejection is the vector perpendicular to the projection of `self` onto + /// `rhs`, in rhs words the result of `self - self.project_onto(rhs)`. + /// + /// `rhs` must be normalized. + /// + /// # Panics + /// + /// Will panic if `rhs` is not normalized when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn reject_from_normalized(self, rhs: Self) -> Self { + self - self.project_onto_normalized(rhs) + } + + /// Returns a vector containing the nearest integer to a number for each element of `self`. + /// Round half-way cases away from 0.0. + #[inline] + pub fn round(self) -> Self { + Self(unsafe { crate::sse2::m128_round(self.0) }) + } + + /// Returns a vector containing the largest integer less than or equal to a number for each + /// element of `self`. + #[inline] + pub fn floor(self) -> Self { + Self(unsafe { crate::sse2::m128_floor(self.0) }) + } + + /// Returns a vector containing the smallest integer greater than or equal to a number for + /// each element of `self`. + #[inline] + pub fn ceil(self) -> Self { + Self(unsafe { crate::sse2::m128_ceil(self.0) }) + } + + /// Returns a vector containing the fractional part of the vector, e.g. `self - + /// self.floor()`. + /// + /// Note that this is fast but not precise for large numbers. + #[inline] + pub fn fract(self) -> Self { + self - self.floor() + } + + /// Returns a vector containing `e^self` (the exponential function) for each element of + /// `self`. + #[inline] + pub fn exp(self) -> Self { + Self::new(self.x.exp(), self.y.exp(), self.z.exp(), self.w.exp()) + } + + /// Returns a vector containing each element of `self` raised to the power of `n`. + #[inline] + pub fn powf(self, n: f32) -> Self { + Self::new( + self.x.powf(n), + self.y.powf(n), + self.z.powf(n), + self.w.powf(n), + ) + } + + /// Returns a vector containing the reciprocal `1.0/n` of each element of `self`. + #[inline] + pub fn recip(self) -> Self { + Self(unsafe { _mm_div_ps(Self::ONE.0, self.0) }) + } + + /// Performs a linear interpolation between `self` and `rhs` based on the value `s`. + /// + /// When `s` is `0.0`, the result will be equal to `self`. When `s` is `1.0`, the result + /// will be equal to `rhs`. When `s` is outside of range `[0, 1]`, the result is linearly + /// extrapolated. + #[doc(alias = "mix")] + #[inline] + pub fn lerp(self, rhs: Self, s: f32) -> Self { + self + ((rhs - self) * s) + } + + /// Returns true if the absolute difference of all elements between `self` and `rhs` is + /// less than or equal to `max_abs_diff`. + /// + /// This can be used to compare if two vectors contain similar elements. It works best when + /// comparing with a known value. The `max_abs_diff` that should be used used depends on + /// the values being compared against. + /// + /// For more see + /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/). + #[inline] + pub fn abs_diff_eq(self, rhs: Self, max_abs_diff: f32) -> bool { + self.sub(rhs).abs().cmple(Self::splat(max_abs_diff)).all() + } + + /// Returns a vector with a length no less than `min` and no more than `max` + /// + /// # Panics + /// + /// Will panic if `min` is greater than `max` when `glam_assert` is enabled. + #[inline] + pub fn clamp_length(self, min: f32, max: f32) -> Self { + glam_assert!(min <= max); + let length_sq = self.length_squared(); + if length_sq < min * min { + self * (length_sq.sqrt().recip() * min) + } else if length_sq > max * max { + self * (length_sq.sqrt().recip() * max) + } else { + self + } + } + + /// Returns a vector with a length no more than `max` + pub fn clamp_length_max(self, max: f32) -> Self { + let length_sq = self.length_squared(); + if length_sq > max * max { + self * (length_sq.sqrt().recip() * max) + } else { + self + } + } + + /// Returns a vector with a length no less than `min` + pub fn clamp_length_min(self, min: f32) -> Self { + let length_sq = self.length_squared(); + if length_sq < min * min { + self * (length_sq.sqrt().recip() * min) + } else { + self + } + } + + /// Fused multiply-add. Computes `(self * a) + b` element-wise with only one rounding + /// error, yielding a more accurate result than an unfused multiply-add. + /// + /// Using `mul_add` *may* be more performant than an unfused multiply-add if the target + /// architecture has a dedicated fma CPU instruction. However, this is not always true, + /// and will be heavily dependant on designing algorithms with specific target hardware in + /// mind. + #[inline] + pub fn mul_add(self, a: Self, b: Self) -> Self { + #[cfg(target_feature = "fma")] + unsafe { + _mm_fmadd_ps(self, b, c) + } + #[cfg(not(target_feature = "fma"))] + Self::new( + self.x.mul_add(a.x, b.x), + self.y.mul_add(a.y, b.y), + self.z.mul_add(a.z, b.z), + self.w.mul_add(a.w, b.w), + ) + } + + /// Casts all elements of `self` to `f64`. + #[inline] + pub fn as_dvec4(&self) -> crate::DVec4 { + crate::DVec4::new(self.x as f64, self.y as f64, self.z as f64, self.w as f64) + } + + /// Casts all elements of `self` to `i32`. + #[inline] + pub fn as_ivec4(&self) -> crate::IVec4 { + crate::IVec4::new(self.x as i32, self.y as i32, self.z as i32, self.w as i32) + } + + /// Casts all elements of `self` to `u32`. + #[inline] + pub fn as_uvec4(&self) -> crate::UVec4 { + crate::UVec4::new(self.x as u32, self.y as u32, self.z as u32, self.w as u32) + } +} + +impl Default for Vec4 { + #[inline(always)] + fn default() -> Self { + Self::ZERO + } +} + +impl PartialEq for Vec4 { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.cmpeq(*rhs).all() + } +} + +impl Div for Vec4 { + type Output = Self; + #[inline] + fn div(self, rhs: Self) -> Self { + Self(unsafe { _mm_div_ps(self.0, rhs.0) }) + } +} + +impl DivAssign for Vec4 { + #[inline] + fn div_assign(&mut self, rhs: Self) { + self.0 = unsafe { _mm_div_ps(self.0, rhs.0) }; + } +} + +impl Div for Vec4 { + type Output = Self; + #[inline] + fn div(self, rhs: f32) -> Self { + Self(unsafe { _mm_div_ps(self.0, _mm_set1_ps(rhs)) }) + } +} + +impl DivAssign for Vec4 { + #[inline] + fn div_assign(&mut self, rhs: f32) { + self.0 = unsafe { _mm_div_ps(self.0, _mm_set1_ps(rhs)) }; + } +} + +impl Div for f32 { + type Output = Vec4; + #[inline] + fn div(self, rhs: Vec4) -> Vec4 { + Vec4(unsafe { _mm_div_ps(_mm_set1_ps(self), rhs.0) }) + } +} + +impl Mul for Vec4 { + type Output = Self; + #[inline] + fn mul(self, rhs: Self) -> Self { + Self(unsafe { _mm_mul_ps(self.0, rhs.0) }) + } +} + +impl MulAssign for Vec4 { + #[inline] + fn mul_assign(&mut self, rhs: Self) { + self.0 = unsafe { _mm_mul_ps(self.0, rhs.0) }; + } +} + +impl Mul for Vec4 { + type Output = Self; + #[inline] + fn mul(self, rhs: f32) -> Self { + Self(unsafe { _mm_mul_ps(self.0, _mm_set1_ps(rhs)) }) + } +} + +impl MulAssign for Vec4 { + #[inline] + fn mul_assign(&mut self, rhs: f32) { + self.0 = unsafe { _mm_mul_ps(self.0, _mm_set1_ps(rhs)) }; + } +} + +impl Mul for f32 { + type Output = Vec4; + #[inline] + fn mul(self, rhs: Vec4) -> Vec4 { + Vec4(unsafe { _mm_mul_ps(_mm_set1_ps(self), rhs.0) }) + } +} + +impl Add for Vec4 { + type Output = Self; + #[inline] + fn add(self, rhs: Self) -> Self { + Self(unsafe { _mm_add_ps(self.0, rhs.0) }) + } +} + +impl AddAssign for Vec4 { + #[inline] + fn add_assign(&mut self, rhs: Self) { + self.0 = unsafe { _mm_add_ps(self.0, rhs.0) }; + } +} + +impl Add for Vec4 { + type Output = Self; + #[inline] + fn add(self, rhs: f32) -> Self { + Self(unsafe { _mm_add_ps(self.0, _mm_set1_ps(rhs)) }) + } +} + +impl AddAssign for Vec4 { + #[inline] + fn add_assign(&mut self, rhs: f32) { + self.0 = unsafe { _mm_add_ps(self.0, _mm_set1_ps(rhs)) }; + } +} + +impl Add for f32 { + type Output = Vec4; + #[inline] + fn add(self, rhs: Vec4) -> Vec4 { + Vec4(unsafe { _mm_add_ps(_mm_set1_ps(self), rhs.0) }) + } +} + +impl Sub for Vec4 { + type Output = Self; + #[inline] + fn sub(self, rhs: Self) -> Self { + Self(unsafe { _mm_sub_ps(self.0, rhs.0) }) + } +} + +impl SubAssign for Vec4 { + #[inline] + fn sub_assign(&mut self, rhs: Vec4) { + self.0 = unsafe { _mm_sub_ps(self.0, rhs.0) }; + } +} + +impl Sub for Vec4 { + type Output = Self; + #[inline] + fn sub(self, rhs: f32) -> Self { + Self(unsafe { _mm_sub_ps(self.0, _mm_set1_ps(rhs)) }) + } +} + +impl SubAssign for Vec4 { + #[inline] + fn sub_assign(&mut self, rhs: f32) { + self.0 = unsafe { _mm_sub_ps(self.0, _mm_set1_ps(rhs)) }; + } +} + +impl Sub for f32 { + type Output = Vec4; + #[inline] + fn sub(self, rhs: Vec4) -> Vec4 { + Vec4(unsafe { _mm_sub_ps(_mm_set1_ps(self), rhs.0) }) + } +} + +impl Rem for Vec4 { + type Output = Self; + #[inline] + fn rem(self, rhs: Self) -> Self { + unsafe { + let n = crate::sse2::m128_floor(_mm_div_ps(self.0, rhs.0)); + Self(_mm_sub_ps(self.0, _mm_mul_ps(n, rhs.0))) + } + } +} + +impl RemAssign for Vec4 { + #[inline] + fn rem_assign(&mut self, rhs: Self) { + *self = self.rem(rhs); + } +} + +impl Rem for Vec4 { + type Output = Self; + #[inline] + fn rem(self, rhs: f32) -> Self { + self.rem(Self::splat(rhs)) + } +} + +impl RemAssign for Vec4 { + #[inline] + fn rem_assign(&mut self, rhs: f32) { + *self = self.rem(Self::splat(rhs)); + } +} + +impl Rem for f32 { + type Output = Vec4; + #[inline] + fn rem(self, rhs: Vec4) -> Vec4 { + Vec4::splat(self).rem(rhs) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsRef<[f32; 4]> for Vec4 { + #[inline] + fn as_ref(&self) -> &[f32; 4] { + unsafe { &*(self as *const Vec4 as *const [f32; 4]) } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsMut<[f32; 4]> for Vec4 { + #[inline] + fn as_mut(&mut self) -> &mut [f32; 4] { + unsafe { &mut *(self as *mut Vec4 as *mut [f32; 4]) } + } +} + +impl<'a> Sum<&'a Self> for Vec4 { + #[inline] + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, |a, &b| Self::add(a, b)) + } +} + +impl<'a> Product<&'a Self> for Vec4 { + #[inline] + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ONE, |a, &b| Self::mul(a, b)) + } +} + +impl Neg for Vec4 { + type Output = Self; + #[inline] + fn neg(self) -> Self { + Self(unsafe { _mm_sub_ps(Self::ZERO.0, self.0) }) + } +} + +impl Index for Vec4 { + type Output = f32; + #[inline] + fn index(&self, index: usize) -> &Self::Output { + match index { + 0 => &self.x, + 1 => &self.y, + 2 => &self.z, + 3 => &self.w, + _ => panic!("index out of bounds"), + } + } +} + +impl IndexMut for Vec4 { + #[inline] + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + match index { + 0 => &mut self.x, + 1 => &mut self.y, + 2 => &mut self.z, + 3 => &mut self.w, + _ => panic!("index out of bounds"), + } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Display for Vec4 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "[{}, {}, {}, {}]", self.x, self.y, self.z, self.w) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Debug for Vec4 { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_tuple(stringify!(Vec4)) + .field(&self.x) + .field(&self.y) + .field(&self.z) + .field(&self.w) + .finish() + } +} + +impl From for __m128 { + #[inline] + fn from(t: Vec4) -> Self { + t.0 + } +} + +impl From<__m128> for Vec4 { + #[inline] + fn from(t: __m128) -> Self { + Self(t) + } +} + +impl From<[f32; 4]> for Vec4 { + #[inline] + fn from(a: [f32; 4]) -> Self { + Self(unsafe { _mm_loadu_ps(a.as_ptr()) }) + } +} + +impl From for [f32; 4] { + #[inline] + fn from(v: Vec4) -> Self { + use crate::Align16; + use core::mem::MaybeUninit; + let mut out: MaybeUninit> = MaybeUninit::uninit(); + unsafe { + _mm_store_ps(out.as_mut_ptr().cast(), v.0); + out.assume_init().0 + } + } +} + +impl From<(f32, f32, f32, f32)> for Vec4 { + #[inline] + fn from(t: (f32, f32, f32, f32)) -> Self { + Self::new(t.0, t.1, t.2, t.3) + } +} + +impl From for (f32, f32, f32, f32) { + #[inline] + fn from(v: Vec4) -> Self { + use crate::Align16; + use core::mem::MaybeUninit; + let mut out: MaybeUninit> = MaybeUninit::uninit(); + unsafe { + _mm_store_ps(out.as_mut_ptr().cast(), v.0); + out.assume_init().0 + } + } +} + +impl From<(Vec3A, f32)> for Vec4 { + #[inline] + fn from((v, w): (Vec3A, f32)) -> Self { + v.extend(w) + } +} + +impl From<(f32, Vec3A)> for Vec4 { + #[inline] + fn from((x, v): (f32, Vec3A)) -> Self { + Self::new(x, v.x, v.y, v.z) + } +} + +impl From<(Vec3, f32)> for Vec4 { + #[inline] + fn from((v, w): (Vec3, f32)) -> Self { + Self::new(v.x, v.y, v.z, w) + } +} + +impl From<(f32, Vec3)> for Vec4 { + #[inline] + fn from((x, v): (f32, Vec3)) -> Self { + Self::new(x, v.x, v.y, v.z) + } +} + +impl From<(Vec2, f32, f32)> for Vec4 { + #[inline] + fn from((v, z, w): (Vec2, f32, f32)) -> Self { + Self::new(v.x, v.y, z, w) + } +} + +impl From<(Vec2, Vec2)> for Vec4 { + #[inline] + fn from((v, u): (Vec2, Vec2)) -> Self { + Self::new(v.x, v.y, u.x, u.y) + } +} + +impl Deref for Vec4 { + type Target = crate::deref::XYZW; + #[inline] + fn deref(&self) -> &Self::Target { + unsafe { &*(self as *const Self).cast() } + } +} + +impl DerefMut for Vec4 { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { &mut *(self as *mut Self).cast() } + } +} diff --git a/src/f32/vec2.rs b/src/f32/vec2.rs new file mode 100644 index 00000000..5cb55c7d --- /dev/null +++ b/src/f32/vec2.rs @@ -0,0 +1,1010 @@ +// Generated from vec.rs template. Edit the template, not the generated file. + +use crate::{BVec2, Vec3}; + +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::iter::{Product, Sum}; +use core::{f32, ops::*}; + +#[cfg(not(feature = "std"))] +use num_traits::Float; + +/// Creates a 2-dimensional vector. +#[inline(always)] +pub const fn vec2(x: f32, y: f32) -> Vec2 { + Vec2::new(x, y) +} + +/// A 2-dimensional vector. +#[derive(Clone, Copy)] +#[cfg_attr(feature = "cuda", repr(C, align(8)))] +pub struct Vec2 { + pub x: f32, + pub y: f32, +} + +impl Vec2 { + /// All zeroes. + pub const ZERO: Self = Self::splat(0.0); + + /// All ones. + pub const ONE: Self = Self::splat(1.0); + + /// All negative ones. + pub const NEG_ONE: Self = Self::splat(-1.0); + + /// All NAN. + pub const NAN: Self = Self::splat(f32::NAN); + + /// `[1.0, 0.0]`: a unit-length vector pointing along the positive X axis. + pub const X: Self = Self::from_array([1.0, 0.0]); + + /// `[0.0, 1.0]`: a unit-length vector pointing along the positive Y axis. + pub const Y: Self = Self::from_array([0.0, 1.0]); + + /// The unit axes. + pub const AXES: [Self; 2] = [Self::X, Self::Y]; + + /// Creates a new vector. + #[inline(always)] + pub const fn new(x: f32, y: f32) -> Self { + Self { x, y } + } + + /// Creates a vector with all elements set to `v`. + #[inline] + pub const fn splat(v: f32) -> Self { + Self { x: v, y: v } + } + + /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use + /// for each element of `self`. + /// + /// A true element in the mask uses the corresponding element from `if_true`, and false + /// uses the element from `if_false`. + #[inline] + pub fn select(mask: BVec2, if_true: Self, if_false: Self) -> Self { + Self { + x: if mask.x { if_true.x } else { if_false.x }, + y: if mask.y { if_true.y } else { if_false.y }, + } + } + + /// Creates a new vector from an array. + #[inline] + pub const fn from_array(a: [f32; 2]) -> Self { + Self::new(a[0], a[1]) + } + + /// `[x, y]` + #[inline] + pub const fn to_array(&self) -> [f32; 2] { + [self.x, self.y] + } + + /// Creates a vector from the first N values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than N elements long. + #[inline] + pub const fn from_slice(slice: &[f32]) -> Self { + Self::new(slice[0], slice[1]) + } + + /// Writes the elements of `self` to the first 2 elements in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than N elements long. + #[inline] + pub fn write_to_slice(self, slice: &mut [f32]) { + slice[0] = self.x; + slice[1] = self.y; + } + + /// Creates a 3D vector from `self` and the given `z` value. + #[inline] + pub const fn extend(self, z: f32) -> Vec3 { + Vec3::new(self.x, self.y, z) + } + + /// Computes the dot product of `self` and `rhs`. + #[inline] + pub fn dot(self, rhs: Self) -> f32 { + (self.x * rhs.x) + (self.y * rhs.y) + } + + /// Returns a vector containing the minimum values for each element of `self` and `rhs`. + /// + /// In other words this computes `[self.x.min(rhs.x), self.y.min(rhs.y), ..]`. + #[inline] + pub fn min(self, rhs: Self) -> Self { + Self { + x: self.x.min(rhs.x), + y: self.y.min(rhs.y), + } + } + + /// Returns a vector containing the maximum values for each element of `self` and `rhs`. + /// + /// In other words this computes `[self.x.max(rhs.x), self.y.max(rhs.y), ..]`. + #[inline] + pub fn max(self, rhs: Self) -> Self { + Self { + x: self.x.max(rhs.x), + y: self.y.max(rhs.y), + } + } + + /// Component-wise clamping of values, similar to [`f32::clamp`]. + /// + /// Each element in `min` must be less-or-equal to the corresponding element in `max`. + /// + /// # Panics + /// + /// Will panic if `min` is greater than `max` when `glam_assert` is enabled. + #[inline] + pub fn clamp(self, min: Self, max: Self) -> Self { + glam_assert!(min.cmple(max).all(), "clamp: expected min <= max"); + self.max(min).min(max) + } + + /// Returns the horizontal minimum of `self`. + /// + /// In other words this computes `min(x, y, ..)`. + #[inline] + pub fn min_element(self) -> f32 { + self.x.min(self.y) + } + + /// Returns the horizontal maximum of `self`. + /// + /// In other words this computes `max(x, y, ..)`. + #[inline] + pub fn max_element(self) -> f32 { + self.x.max(self.y) + } + + /// Returns a vector mask containing the result of a `==` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words, this computes `[self.x == rhs.x, self.y == rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpeq(self, rhs: Self) -> BVec2 { + BVec2::new(self.x.eq(&rhs.x), self.y.eq(&rhs.y)) + } + + /// Returns a vector mask containing the result of a `!=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x != rhs.x, self.y != rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpne(self, rhs: Self) -> BVec2 { + BVec2::new(self.x.ne(&rhs.x), self.y.ne(&rhs.y)) + } + + /// Returns a vector mask containing the result of a `>=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x >= rhs.x, self.y >= rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpge(self, rhs: Self) -> BVec2 { + BVec2::new(self.x.ge(&rhs.x), self.y.ge(&rhs.y)) + } + + /// Returns a vector mask containing the result of a `>` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x > rhs.x, self.y > rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpgt(self, rhs: Self) -> BVec2 { + BVec2::new(self.x.gt(&rhs.x), self.y.gt(&rhs.y)) + } + + /// Returns a vector mask containing the result of a `<=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x <= rhs.x, self.y <= rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmple(self, rhs: Self) -> BVec2 { + BVec2::new(self.x.le(&rhs.x), self.y.le(&rhs.y)) + } + + /// Returns a vector mask containing the result of a `<` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x < rhs.x, self.y < rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmplt(self, rhs: Self) -> BVec2 { + BVec2::new(self.x.lt(&rhs.x), self.y.lt(&rhs.y)) + } + + /// Returns a vector containing the absolute value of each element of `self`. + #[inline] + pub fn abs(self) -> Self { + Self { + x: self.x.abs(), + y: self.y.abs(), + } + } + + /// Returns a vector with elements representing the sign of `self`. + /// + /// - `1.0` if the number is positive, `+0.0` or `INFINITY` + /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` + /// - `NAN` if the number is `NAN` + #[inline] + pub fn signum(self) -> Self { + Self { + x: self.x.signum(), + y: self.y.signum(), + } + } + + /// Returns `true` if, and only if, all elements are finite. If any element is either + /// `NaN`, positive or negative infinity, this will return `false`. + #[inline] + pub fn is_finite(self) -> bool { + self.x.is_finite() && self.y.is_finite() + } + + /// Returns `true` if any elements are `NaN`. + #[inline] + pub fn is_nan(self) -> bool { + self.x.is_nan() || self.y.is_nan() + } + + /// Performs `is_nan` on each element of self, returning a vector mask of the results. + /// + /// In other words, this computes `[x.is_nan(), y.is_nan(), z.is_nan(), w.is_nan()]`. + #[inline] + pub fn is_nan_mask(self) -> BVec2 { + BVec2::new(self.x.is_nan(), self.y.is_nan()) + } + + /// Computes the length of `self`. + #[doc(alias = "magnitude")] + #[inline] + pub fn length(self) -> f32 { + self.dot(self).sqrt() + } + + /// Computes the squared length of `self`. + /// + /// This is faster than `length()` as it avoids a square root operation. + #[doc(alias = "magnitude2")] + #[inline] + pub fn length_squared(self) -> f32 { + self.dot(self) + } + + /// Computes `1.0 / length()`. + /// + /// For valid results, `self` must _not_ be of length zero. + #[inline] + pub fn length_recip(self) -> f32 { + self.length().recip() + } + + /// Computes the Euclidean distance between two points in space. + #[inline] + pub fn distance(self, rhs: Self) -> f32 { + (self - rhs).length() + } + + /// Compute the squared euclidean distance between two points in space. + #[inline] + pub fn distance_squared(self, rhs: Self) -> f32 { + (self - rhs).length_squared() + } + + /// Returns `self` normalized to length 1.0. + /// + /// For valid results, `self` must _not_ be of length zero, nor very close to zero. + /// + /// See also [`Self::try_normalize`] and [`Self::normalize_or_zero`]. + /// + /// Panics + /// + /// Will panic if `self` is zero length when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn normalize(self) -> Self { + #[allow(clippy::let_and_return)] + let normalized = self.mul(self.length_recip()); + glam_assert!(normalized.is_finite()); + normalized + } + + /// Returns `self` normalized to length 1.0 if possible, else returns `None`. + /// + /// In particular, if the input is zero (or very close to zero), or non-finite, + /// the result of this operation will be `None`. + /// + /// See also [`Self::normalize_or_zero`]. + #[must_use] + #[inline] + pub fn try_normalize(self) -> Option { + let rcp = self.length_recip(); + if rcp.is_finite() && rcp > 0.0 { + Some(self * rcp) + } else { + None + } + } + + /// Returns `self` normalized to length 1.0 if possible, else returns zero. + /// + /// In particular, if the input is zero (or very close to zero), or non-finite, + /// the result of this operation will be zero. + /// + /// See also [`Self::try_normalize`]. + #[must_use] + #[inline] + pub fn normalize_or_zero(self) -> Self { + let rcp = self.length_recip(); + if rcp.is_finite() && rcp > 0.0 { + self * rcp + } else { + Self::ZERO + } + } + + /// Returns whether `self` is length `1.0` or not. + /// + /// Uses a precision threshold of `1e-6`. + #[inline] + pub fn is_normalized(self) -> bool { + // TODO: do something with epsilon + (self.length_squared() - 1.0).abs() <= 1e-4 + } + + /// Returns the vector projection of `self` onto `rhs`. + /// + /// `rhs` must be of non-zero length. + /// + /// # Panics + /// + /// Will panic if `rhs` is zero length when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn project_onto(self, rhs: Self) -> Self { + let other_len_sq_rcp = rhs.dot(rhs).recip(); + glam_assert!(other_len_sq_rcp.is_finite()); + rhs * self.dot(rhs) * other_len_sq_rcp + } + + /// Returns the vector rejection of `self` from `rhs`. + /// + /// The vector rejection is the vector perpendicular to the projection of `self` onto + /// `rhs`, in rhs words the result of `self - self.project_onto(rhs)`. + /// + /// `rhs` must be of non-zero length. + /// + /// # Panics + /// + /// Will panic if `rhs` has a length of zero when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn reject_from(self, rhs: Self) -> Self { + self - self.project_onto(rhs) + } + + /// Returns the vector projection of `self` onto `rhs`. + /// + /// `rhs` must be normalized. + /// + /// # Panics + /// + /// Will panic if `rhs` is not normalized when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn project_onto_normalized(self, rhs: Self) -> Self { + glam_assert!(rhs.is_normalized()); + rhs * self.dot(rhs) + } + + /// Returns the vector rejection of `self` from `rhs`. + /// + /// The vector rejection is the vector perpendicular to the projection of `self` onto + /// `rhs`, in rhs words the result of `self - self.project_onto(rhs)`. + /// + /// `rhs` must be normalized. + /// + /// # Panics + /// + /// Will panic if `rhs` is not normalized when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn reject_from_normalized(self, rhs: Self) -> Self { + self - self.project_onto_normalized(rhs) + } + + /// Returns a vector containing the nearest integer to a number for each element of `self`. + /// Round half-way cases away from 0.0. + #[inline] + pub fn round(self) -> Self { + Self { + x: self.x.round(), + y: self.y.round(), + } + } + + /// Returns a vector containing the largest integer less than or equal to a number for each + /// element of `self`. + #[inline] + pub fn floor(self) -> Self { + Self { + x: self.x.floor(), + y: self.y.floor(), + } + } + + /// Returns a vector containing the smallest integer greater than or equal to a number for + /// each element of `self`. + #[inline] + pub fn ceil(self) -> Self { + Self { + x: self.x.ceil(), + y: self.y.ceil(), + } + } + + /// Returns a vector containing the fractional part of the vector, e.g. `self - + /// self.floor()`. + /// + /// Note that this is fast but not precise for large numbers. + #[inline] + pub fn fract(self) -> Self { + self - self.floor() + } + + /// Returns a vector containing `e^self` (the exponential function) for each element of + /// `self`. + #[inline] + pub fn exp(self) -> Self { + Self::new(self.x.exp(), self.y.exp()) + } + + /// Returns a vector containing each element of `self` raised to the power of `n`. + #[inline] + pub fn powf(self, n: f32) -> Self { + Self::new(self.x.powf(n), self.y.powf(n)) + } + + /// Returns a vector containing the reciprocal `1.0/n` of each element of `self`. + #[inline] + pub fn recip(self) -> Self { + Self { + x: self.x.recip(), + y: self.y.recip(), + } + } + + /// Performs a linear interpolation between `self` and `rhs` based on the value `s`. + /// + /// When `s` is `0.0`, the result will be equal to `self`. When `s` is `1.0`, the result + /// will be equal to `rhs`. When `s` is outside of range `[0, 1]`, the result is linearly + /// extrapolated. + #[doc(alias = "mix")] + #[inline] + pub fn lerp(self, rhs: Self, s: f32) -> Self { + self + ((rhs - self) * s) + } + + /// Returns true if the absolute difference of all elements between `self` and `rhs` is + /// less than or equal to `max_abs_diff`. + /// + /// This can be used to compare if two vectors contain similar elements. It works best when + /// comparing with a known value. The `max_abs_diff` that should be used used depends on + /// the values being compared against. + /// + /// For more see + /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/). + #[inline] + pub fn abs_diff_eq(self, rhs: Self, max_abs_diff: f32) -> bool { + self.sub(rhs).abs().cmple(Self::splat(max_abs_diff)).all() + } + + /// Returns a vector with a length no less than `min` and no more than `max` + /// + /// # Panics + /// + /// Will panic if `min` is greater than `max` when `glam_assert` is enabled. + #[inline] + pub fn clamp_length(self, min: f32, max: f32) -> Self { + glam_assert!(min <= max); + let length_sq = self.length_squared(); + if length_sq < min * min { + self * (length_sq.sqrt().recip() * min) + } else if length_sq > max * max { + self * (length_sq.sqrt().recip() * max) + } else { + self + } + } + + /// Returns a vector with a length no more than `max` + pub fn clamp_length_max(self, max: f32) -> Self { + let length_sq = self.length_squared(); + if length_sq > max * max { + self * (length_sq.sqrt().recip() * max) + } else { + self + } + } + + /// Returns a vector with a length no less than `min` + pub fn clamp_length_min(self, min: f32) -> Self { + let length_sq = self.length_squared(); + if length_sq < min * min { + self * (length_sq.sqrt().recip() * min) + } else { + self + } + } + + /// Fused multiply-add. Computes `(self * a) + b` element-wise with only one rounding + /// error, yielding a more accurate result than an unfused multiply-add. + /// + /// Using `mul_add` *may* be more performant than an unfused multiply-add if the target + /// architecture has a dedicated fma CPU instruction. However, this is not always true, + /// and will be heavily dependant on designing algorithms with specific target hardware in + /// mind. + #[inline] + pub fn mul_add(self, a: Self, b: Self) -> Self { + Self::new(self.x.mul_add(a.x, b.x), self.y.mul_add(a.y, b.y)) + } + + /// Creates a 2D vector containing `[angle.cos(), angle.sin()]`. This can be used in + /// conjunction with the `rotate` method, e.g. `Vec2::from_angle(PI).rotate(Vec2::Y)` will + /// create the vector [-1, 0] and rotate `Vec2::Y` around it returning `-Vec2::Y`. + #[inline] + pub fn from_angle(angle: f32) -> Self { + let (sin, cos) = angle.sin_cos(); + Self { x: cos, y: sin } + } + + /// Returns the angle (in radians) between `self` and `rhs`. + /// + /// The input vectors do not need to be unit length however they must be non-zero. + #[inline] + pub fn angle_between(self, rhs: Self) -> f32 { + use crate::FloatEx; + let angle = + (self.dot(rhs) / (self.length_squared() * rhs.length_squared()).sqrt()).acos_approx(); + + angle * self.perp_dot(rhs).signum() + } + + /// Returns a vector that is equal to `self` rotated by 90 degrees. + #[inline] + pub fn perp(self) -> Self { + Self { + x: -self.y, + y: self.x, + } + } + + /// The perpendicular dot product of `self` and `rhs`. + /// Also known as the wedge product, 2D cross product, and determinant. + #[doc(alias = "wedge")] + #[doc(alias = "cross")] + #[doc(alias = "determinant")] + #[inline] + pub fn perp_dot(self, rhs: Self) -> f32 { + (self.x * rhs.y) - (self.y * rhs.x) + } + + /// Returns `rhs` rotated by the angle of `self`. If `self` is normalized, + /// then this just rotation. This is what you usually want. Otherwise, + /// it will be like a rotation with a multiplication by `self`'s length. + #[must_use] + #[inline] + pub fn rotate(self, rhs: Self) -> Self { + Self { + x: self.x * rhs.x - self.y * rhs.y, + y: self.y * rhs.x + self.x * rhs.y, + } + } + + /// Casts all elements of `self` to `f64`. + #[inline] + pub fn as_dvec2(&self) -> crate::DVec2 { + crate::DVec2::new(self.x as f64, self.y as f64) + } + + /// Casts all elements of `self` to `i32`. + #[inline] + pub fn as_ivec2(&self) -> crate::IVec2 { + crate::IVec2::new(self.x as i32, self.y as i32) + } + + /// Casts all elements of `self` to `u32`. + #[inline] + pub fn as_uvec2(&self) -> crate::UVec2 { + crate::UVec2::new(self.x as u32, self.y as u32) + } +} + +impl Default for Vec2 { + #[inline(always)] + fn default() -> Self { + Self::ZERO + } +} + +impl PartialEq for Vec2 { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.cmpeq(*rhs).all() + } +} + +impl Div for Vec2 { + type Output = Self; + #[inline] + fn div(self, rhs: Self) -> Self { + Self { + x: self.x.div(rhs.x), + y: self.y.div(rhs.y), + } + } +} + +impl DivAssign for Vec2 { + #[inline] + fn div_assign(&mut self, rhs: Self) { + self.x.div_assign(rhs.x); + self.y.div_assign(rhs.y); + } +} + +impl Div for Vec2 { + type Output = Self; + #[inline] + fn div(self, rhs: f32) -> Self { + Self { + x: self.x.div(rhs), + y: self.y.div(rhs), + } + } +} + +impl DivAssign for Vec2 { + #[inline] + fn div_assign(&mut self, rhs: f32) { + self.x.div_assign(rhs); + self.y.div_assign(rhs); + } +} + +impl Div for f32 { + type Output = Vec2; + #[inline] + fn div(self, rhs: Vec2) -> Vec2 { + Vec2 { + x: self.div(rhs.x), + y: self.div(rhs.y), + } + } +} + +impl Mul for Vec2 { + type Output = Self; + #[inline] + fn mul(self, rhs: Self) -> Self { + Self { + x: self.x.mul(rhs.x), + y: self.y.mul(rhs.y), + } + } +} + +impl MulAssign for Vec2 { + #[inline] + fn mul_assign(&mut self, rhs: Self) { + self.x.mul_assign(rhs.x); + self.y.mul_assign(rhs.y); + } +} + +impl Mul for Vec2 { + type Output = Self; + #[inline] + fn mul(self, rhs: f32) -> Self { + Self { + x: self.x.mul(rhs), + y: self.y.mul(rhs), + } + } +} + +impl MulAssign for Vec2 { + #[inline] + fn mul_assign(&mut self, rhs: f32) { + self.x.mul_assign(rhs); + self.y.mul_assign(rhs); + } +} + +impl Mul for f32 { + type Output = Vec2; + #[inline] + fn mul(self, rhs: Vec2) -> Vec2 { + Vec2 { + x: self.mul(rhs.x), + y: self.mul(rhs.y), + } + } +} + +impl Add for Vec2 { + type Output = Self; + #[inline] + fn add(self, rhs: Self) -> Self { + Self { + x: self.x.add(rhs.x), + y: self.y.add(rhs.y), + } + } +} + +impl AddAssign for Vec2 { + #[inline] + fn add_assign(&mut self, rhs: Self) { + self.x.add_assign(rhs.x); + self.y.add_assign(rhs.y); + } +} + +impl Add for Vec2 { + type Output = Self; + #[inline] + fn add(self, rhs: f32) -> Self { + Self { + x: self.x.add(rhs), + y: self.y.add(rhs), + } + } +} + +impl AddAssign for Vec2 { + #[inline] + fn add_assign(&mut self, rhs: f32) { + self.x.add_assign(rhs); + self.y.add_assign(rhs); + } +} + +impl Add for f32 { + type Output = Vec2; + #[inline] + fn add(self, rhs: Vec2) -> Vec2 { + Vec2 { + x: self.add(rhs.x), + y: self.add(rhs.y), + } + } +} + +impl Sub for Vec2 { + type Output = Self; + #[inline] + fn sub(self, rhs: Self) -> Self { + Self { + x: self.x.sub(rhs.x), + y: self.y.sub(rhs.y), + } + } +} + +impl SubAssign for Vec2 { + #[inline] + fn sub_assign(&mut self, rhs: Vec2) { + self.x.sub_assign(rhs.x); + self.y.sub_assign(rhs.y); + } +} + +impl Sub for Vec2 { + type Output = Self; + #[inline] + fn sub(self, rhs: f32) -> Self { + Self { + x: self.x.sub(rhs), + y: self.y.sub(rhs), + } + } +} + +impl SubAssign for Vec2 { + #[inline] + fn sub_assign(&mut self, rhs: f32) { + self.x.sub_assign(rhs); + self.y.sub_assign(rhs); + } +} + +impl Sub for f32 { + type Output = Vec2; + #[inline] + fn sub(self, rhs: Vec2) -> Vec2 { + Vec2 { + x: self.sub(rhs.x), + y: self.sub(rhs.y), + } + } +} + +impl Rem for Vec2 { + type Output = Self; + #[inline] + fn rem(self, rhs: Self) -> Self { + Self { + x: self.x.rem(rhs.x), + y: self.y.rem(rhs.y), + } + } +} + +impl RemAssign for Vec2 { + #[inline] + fn rem_assign(&mut self, rhs: Self) { + self.x.rem_assign(rhs.x); + self.y.rem_assign(rhs.y); + } +} + +impl Rem for Vec2 { + type Output = Self; + #[inline] + fn rem(self, rhs: f32) -> Self { + Self { + x: self.x.rem(rhs), + y: self.y.rem(rhs), + } + } +} + +impl RemAssign for Vec2 { + #[inline] + fn rem_assign(&mut self, rhs: f32) { + self.x.rem_assign(rhs); + self.y.rem_assign(rhs); + } +} + +impl Rem for f32 { + type Output = Vec2; + #[inline] + fn rem(self, rhs: Vec2) -> Vec2 { + Vec2 { + x: self.rem(rhs.x), + y: self.rem(rhs.y), + } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsRef<[f32; 2]> for Vec2 { + #[inline] + fn as_ref(&self) -> &[f32; 2] { + unsafe { &*(self as *const Vec2 as *const [f32; 2]) } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsMut<[f32; 2]> for Vec2 { + #[inline] + fn as_mut(&mut self) -> &mut [f32; 2] { + unsafe { &mut *(self as *mut Vec2 as *mut [f32; 2]) } + } +} + +impl<'a> Sum<&'a Self> for Vec2 { + #[inline] + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, |a, &b| Self::add(a, b)) + } +} + +impl<'a> Product<&'a Self> for Vec2 { + #[inline] + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ONE, |a, &b| Self::mul(a, b)) + } +} + +impl Neg for Vec2 { + type Output = Self; + #[inline] + fn neg(self) -> Self { + Self { + x: self.x.neg(), + y: self.y.neg(), + } + } +} + +impl Index for Vec2 { + type Output = f32; + #[inline] + fn index(&self, index: usize) -> &Self::Output { + match index { + 0 => &self.x, + 1 => &self.y, + _ => panic!("index out of bounds"), + } + } +} + +impl IndexMut for Vec2 { + #[inline] + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + match index { + 0 => &mut self.x, + 1 => &mut self.y, + _ => panic!("index out of bounds"), + } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Display for Vec2 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "[{}, {}]", self.x, self.y) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Debug for Vec2 { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_tuple(stringify!(Vec2)) + .field(&self.x) + .field(&self.y) + .finish() + } +} + +impl From<[f32; 2]> for Vec2 { + #[inline] + fn from(a: [f32; 2]) -> Self { + Self::new(a[0], a[1]) + } +} + +impl From for [f32; 2] { + #[inline] + fn from(v: Vec2) -> Self { + [v.x, v.y] + } +} + +impl From<(f32, f32)> for Vec2 { + #[inline] + fn from(t: (f32, f32)) -> Self { + Self::new(t.0, t.1) + } +} + +impl From for (f32, f32) { + #[inline] + fn from(v: Vec2) -> Self { + (v.x, v.y) + } +} diff --git a/src/f32/vec3.rs b/src/f32/vec3.rs new file mode 100644 index 00000000..caea2137 --- /dev/null +++ b/src/f32/vec3.rs @@ -0,0 +1,1120 @@ +// Generated from vec.rs template. Edit the template, not the generated file. + +use crate::{BVec3, Vec2, Vec3A, Vec4}; + +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::iter::{Product, Sum}; +use core::{f32, ops::*}; + +#[cfg(not(feature = "std"))] +use num_traits::Float; + +/// Creates a 3-dimensional vector. +#[inline(always)] +pub const fn vec3(x: f32, y: f32, z: f32) -> Vec3 { + Vec3::new(x, y, z) +} + +/// A 3-dimensional vector. +#[derive(Clone, Copy)] +pub struct Vec3 { + pub x: f32, + pub y: f32, + pub z: f32, +} + +impl Vec3 { + /// All zeroes. + pub const ZERO: Self = Self::splat(0.0); + + /// All ones. + pub const ONE: Self = Self::splat(1.0); + + /// All negative ones. + pub const NEG_ONE: Self = Self::splat(-1.0); + + /// All NAN. + pub const NAN: Self = Self::splat(f32::NAN); + + /// `[1.0, 0.0, 0.0]`: a unit-length vector pointing along the positive X axis. + pub const X: Self = Self::from_array([1.0, 0.0, 0.0]); + + /// `[0.0, 1.0, 0.0]`: a unit-length vector pointing along the positive Y axis. + pub const Y: Self = Self::from_array([0.0, 1.0, 0.0]); + + /// `[0.0, 0.0, 1.0]`: a unit-length vector pointing along the positive Z axis. + pub const Z: Self = Self::from_array([0.0, 0.0, 1.0]); + + /// The unit axes. + pub const AXES: [Self; 3] = [Self::X, Self::Y, Self::Z]; + + /// Creates a new vector. + #[inline(always)] + pub const fn new(x: f32, y: f32, z: f32) -> Self { + Self { x, y, z } + } + + /// Creates a vector with all elements set to `v`. + #[inline] + pub const fn splat(v: f32) -> Self { + Self { x: v, y: v, z: v } + } + + /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use + /// for each element of `self`. + /// + /// A true element in the mask uses the corresponding element from `if_true`, and false + /// uses the element from `if_false`. + #[inline] + pub fn select(mask: BVec3, if_true: Self, if_false: Self) -> Self { + Self { + x: if mask.x { if_true.x } else { if_false.x }, + y: if mask.y { if_true.y } else { if_false.y }, + z: if mask.z { if_true.z } else { if_false.z }, + } + } + + /// Creates a new vector from an array. + #[inline] + pub const fn from_array(a: [f32; 3]) -> Self { + Self::new(a[0], a[1], a[2]) + } + + /// `[x, y, z]` + #[inline] + pub const fn to_array(&self) -> [f32; 3] { + [self.x, self.y, self.z] + } + + /// Creates a vector from the first N values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than N elements long. + #[inline] + pub const fn from_slice(slice: &[f32]) -> Self { + Self::new(slice[0], slice[1], slice[2]) + } + + /// Writes the elements of `self` to the first 3 elements in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than N elements long. + #[inline] + pub fn write_to_slice(self, slice: &mut [f32]) { + slice[0] = self.x; + slice[1] = self.y; + slice[2] = self.z; + } + + /// Internal method for creating a 3D vector from a 4D vector, discarding `w`. + #[allow(dead_code)] + #[inline] + pub(crate) fn from_vec4(v: Vec4) -> Self { + Self { + x: v.x, + y: v.y, + z: v.z, + } + } + + /// Creates a 4D vector from `self` and the given `w` value. + #[inline] + pub fn extend(self, w: f32) -> Vec4 { + Vec4::new(self.x, self.y, self.z, w) + } + + /// Creates a 2D vector from the `x` and `y` elements of `self`, discarding `z`. + /// + /// Truncation may also be performed by using `self.xy()` or `Vec2::from()`. + #[inline] + pub fn truncate(self) -> Vec2 { + use crate::swizzles::Vec3Swizzles; + self.xy() + } + + /// Computes the dot product of `self` and `rhs`. + #[inline] + pub fn dot(self, rhs: Self) -> f32 { + (self.x * rhs.x) + (self.y * rhs.y) + (self.z * rhs.z) + } + + /// Computes the cross product of `self` and `rhs`. + #[inline] + pub fn cross(self, rhs: Self) -> Self { + Self { + x: self.y * rhs.z - rhs.y * self.z, + y: self.z * rhs.x - rhs.z * self.x, + z: self.x * rhs.y - rhs.x * self.y, + } + } + + /// Returns a vector containing the minimum values for each element of `self` and `rhs`. + /// + /// In other words this computes `[self.x.min(rhs.x), self.y.min(rhs.y), ..]`. + #[inline] + pub fn min(self, rhs: Self) -> Self { + Self { + x: self.x.min(rhs.x), + y: self.y.min(rhs.y), + z: self.z.min(rhs.z), + } + } + + /// Returns a vector containing the maximum values for each element of `self` and `rhs`. + /// + /// In other words this computes `[self.x.max(rhs.x), self.y.max(rhs.y), ..]`. + #[inline] + pub fn max(self, rhs: Self) -> Self { + Self { + x: self.x.max(rhs.x), + y: self.y.max(rhs.y), + z: self.z.max(rhs.z), + } + } + + /// Component-wise clamping of values, similar to [`f32::clamp`]. + /// + /// Each element in `min` must be less-or-equal to the corresponding element in `max`. + /// + /// # Panics + /// + /// Will panic if `min` is greater than `max` when `glam_assert` is enabled. + #[inline] + pub fn clamp(self, min: Self, max: Self) -> Self { + glam_assert!(min.cmple(max).all(), "clamp: expected min <= max"); + self.max(min).min(max) + } + + /// Returns the horizontal minimum of `self`. + /// + /// In other words this computes `min(x, y, ..)`. + #[inline] + pub fn min_element(self) -> f32 { + self.x.min(self.y.min(self.z)) + } + + /// Returns the horizontal maximum of `self`. + /// + /// In other words this computes `max(x, y, ..)`. + #[inline] + pub fn max_element(self) -> f32 { + self.x.max(self.y.max(self.z)) + } + + /// Returns a vector mask containing the result of a `==` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words, this computes `[self.x == rhs.x, self.y == rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpeq(self, rhs: Self) -> BVec3 { + BVec3::new(self.x.eq(&rhs.x), self.y.eq(&rhs.y), self.z.eq(&rhs.z)) + } + + /// Returns a vector mask containing the result of a `!=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x != rhs.x, self.y != rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpne(self, rhs: Self) -> BVec3 { + BVec3::new(self.x.ne(&rhs.x), self.y.ne(&rhs.y), self.z.ne(&rhs.z)) + } + + /// Returns a vector mask containing the result of a `>=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x >= rhs.x, self.y >= rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpge(self, rhs: Self) -> BVec3 { + BVec3::new(self.x.ge(&rhs.x), self.y.ge(&rhs.y), self.z.ge(&rhs.z)) + } + + /// Returns a vector mask containing the result of a `>` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x > rhs.x, self.y > rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpgt(self, rhs: Self) -> BVec3 { + BVec3::new(self.x.gt(&rhs.x), self.y.gt(&rhs.y), self.z.gt(&rhs.z)) + } + + /// Returns a vector mask containing the result of a `<=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x <= rhs.x, self.y <= rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmple(self, rhs: Self) -> BVec3 { + BVec3::new(self.x.le(&rhs.x), self.y.le(&rhs.y), self.z.le(&rhs.z)) + } + + /// Returns a vector mask containing the result of a `<` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x < rhs.x, self.y < rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmplt(self, rhs: Self) -> BVec3 { + BVec3::new(self.x.lt(&rhs.x), self.y.lt(&rhs.y), self.z.lt(&rhs.z)) + } + + /// Returns a vector containing the absolute value of each element of `self`. + #[inline] + pub fn abs(self) -> Self { + Self { + x: self.x.abs(), + y: self.y.abs(), + z: self.z.abs(), + } + } + + /// Returns a vector with elements representing the sign of `self`. + /// + /// - `1.0` if the number is positive, `+0.0` or `INFINITY` + /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` + /// - `NAN` if the number is `NAN` + #[inline] + pub fn signum(self) -> Self { + Self { + x: self.x.signum(), + y: self.y.signum(), + z: self.z.signum(), + } + } + + /// Returns `true` if, and only if, all elements are finite. If any element is either + /// `NaN`, positive or negative infinity, this will return `false`. + #[inline] + pub fn is_finite(self) -> bool { + self.x.is_finite() && self.y.is_finite() && self.z.is_finite() + } + + /// Returns `true` if any elements are `NaN`. + #[inline] + pub fn is_nan(self) -> bool { + self.x.is_nan() || self.y.is_nan() || self.z.is_nan() + } + + /// Performs `is_nan` on each element of self, returning a vector mask of the results. + /// + /// In other words, this computes `[x.is_nan(), y.is_nan(), z.is_nan(), w.is_nan()]`. + #[inline] + pub fn is_nan_mask(self) -> BVec3 { + BVec3::new(self.x.is_nan(), self.y.is_nan(), self.z.is_nan()) + } + + /// Computes the length of `self`. + #[doc(alias = "magnitude")] + #[inline] + pub fn length(self) -> f32 { + self.dot(self).sqrt() + } + + /// Computes the squared length of `self`. + /// + /// This is faster than `length()` as it avoids a square root operation. + #[doc(alias = "magnitude2")] + #[inline] + pub fn length_squared(self) -> f32 { + self.dot(self) + } + + /// Computes `1.0 / length()`. + /// + /// For valid results, `self` must _not_ be of length zero. + #[inline] + pub fn length_recip(self) -> f32 { + self.length().recip() + } + + /// Computes the Euclidean distance between two points in space. + #[inline] + pub fn distance(self, rhs: Self) -> f32 { + (self - rhs).length() + } + + /// Compute the squared euclidean distance between two points in space. + #[inline] + pub fn distance_squared(self, rhs: Self) -> f32 { + (self - rhs).length_squared() + } + + /// Returns `self` normalized to length 1.0. + /// + /// For valid results, `self` must _not_ be of length zero, nor very close to zero. + /// + /// See also [`Self::try_normalize`] and [`Self::normalize_or_zero`]. + /// + /// Panics + /// + /// Will panic if `self` is zero length when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn normalize(self) -> Self { + #[allow(clippy::let_and_return)] + let normalized = self.mul(self.length_recip()); + glam_assert!(normalized.is_finite()); + normalized + } + + /// Returns `self` normalized to length 1.0 if possible, else returns `None`. + /// + /// In particular, if the input is zero (or very close to zero), or non-finite, + /// the result of this operation will be `None`. + /// + /// See also [`Self::normalize_or_zero`]. + #[must_use] + #[inline] + pub fn try_normalize(self) -> Option { + let rcp = self.length_recip(); + if rcp.is_finite() && rcp > 0.0 { + Some(self * rcp) + } else { + None + } + } + + /// Returns `self` normalized to length 1.0 if possible, else returns zero. + /// + /// In particular, if the input is zero (or very close to zero), or non-finite, + /// the result of this operation will be zero. + /// + /// See also [`Self::try_normalize`]. + #[must_use] + #[inline] + pub fn normalize_or_zero(self) -> Self { + let rcp = self.length_recip(); + if rcp.is_finite() && rcp > 0.0 { + self * rcp + } else { + Self::ZERO + } + } + + /// Returns whether `self` is length `1.0` or not. + /// + /// Uses a precision threshold of `1e-6`. + #[inline] + pub fn is_normalized(self) -> bool { + // TODO: do something with epsilon + (self.length_squared() - 1.0).abs() <= 1e-4 + } + + /// Returns the vector projection of `self` onto `rhs`. + /// + /// `rhs` must be of non-zero length. + /// + /// # Panics + /// + /// Will panic if `rhs` is zero length when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn project_onto(self, rhs: Self) -> Self { + let other_len_sq_rcp = rhs.dot(rhs).recip(); + glam_assert!(other_len_sq_rcp.is_finite()); + rhs * self.dot(rhs) * other_len_sq_rcp + } + + /// Returns the vector rejection of `self` from `rhs`. + /// + /// The vector rejection is the vector perpendicular to the projection of `self` onto + /// `rhs`, in rhs words the result of `self - self.project_onto(rhs)`. + /// + /// `rhs` must be of non-zero length. + /// + /// # Panics + /// + /// Will panic if `rhs` has a length of zero when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn reject_from(self, rhs: Self) -> Self { + self - self.project_onto(rhs) + } + + /// Returns the vector projection of `self` onto `rhs`. + /// + /// `rhs` must be normalized. + /// + /// # Panics + /// + /// Will panic if `rhs` is not normalized when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn project_onto_normalized(self, rhs: Self) -> Self { + glam_assert!(rhs.is_normalized()); + rhs * self.dot(rhs) + } + + /// Returns the vector rejection of `self` from `rhs`. + /// + /// The vector rejection is the vector perpendicular to the projection of `self` onto + /// `rhs`, in rhs words the result of `self - self.project_onto(rhs)`. + /// + /// `rhs` must be normalized. + /// + /// # Panics + /// + /// Will panic if `rhs` is not normalized when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn reject_from_normalized(self, rhs: Self) -> Self { + self - self.project_onto_normalized(rhs) + } + + /// Returns a vector containing the nearest integer to a number for each element of `self`. + /// Round half-way cases away from 0.0. + #[inline] + pub fn round(self) -> Self { + Self { + x: self.x.round(), + y: self.y.round(), + z: self.z.round(), + } + } + + /// Returns a vector containing the largest integer less than or equal to a number for each + /// element of `self`. + #[inline] + pub fn floor(self) -> Self { + Self { + x: self.x.floor(), + y: self.y.floor(), + z: self.z.floor(), + } + } + + /// Returns a vector containing the smallest integer greater than or equal to a number for + /// each element of `self`. + #[inline] + pub fn ceil(self) -> Self { + Self { + x: self.x.ceil(), + y: self.y.ceil(), + z: self.z.ceil(), + } + } + + /// Returns a vector containing the fractional part of the vector, e.g. `self - + /// self.floor()`. + /// + /// Note that this is fast but not precise for large numbers. + #[inline] + pub fn fract(self) -> Self { + self - self.floor() + } + + /// Returns a vector containing `e^self` (the exponential function) for each element of + /// `self`. + #[inline] + pub fn exp(self) -> Self { + Self::new(self.x.exp(), self.y.exp(), self.z.exp()) + } + + /// Returns a vector containing each element of `self` raised to the power of `n`. + #[inline] + pub fn powf(self, n: f32) -> Self { + Self::new(self.x.powf(n), self.y.powf(n), self.z.powf(n)) + } + + /// Returns a vector containing the reciprocal `1.0/n` of each element of `self`. + #[inline] + pub fn recip(self) -> Self { + Self { + x: self.x.recip(), + y: self.y.recip(), + z: self.z.recip(), + } + } + + /// Performs a linear interpolation between `self` and `rhs` based on the value `s`. + /// + /// When `s` is `0.0`, the result will be equal to `self`. When `s` is `1.0`, the result + /// will be equal to `rhs`. When `s` is outside of range `[0, 1]`, the result is linearly + /// extrapolated. + #[doc(alias = "mix")] + #[inline] + pub fn lerp(self, rhs: Self, s: f32) -> Self { + self + ((rhs - self) * s) + } + + /// Returns true if the absolute difference of all elements between `self` and `rhs` is + /// less than or equal to `max_abs_diff`. + /// + /// This can be used to compare if two vectors contain similar elements. It works best when + /// comparing with a known value. The `max_abs_diff` that should be used used depends on + /// the values being compared against. + /// + /// For more see + /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/). + #[inline] + pub fn abs_diff_eq(self, rhs: Self, max_abs_diff: f32) -> bool { + self.sub(rhs).abs().cmple(Self::splat(max_abs_diff)).all() + } + + /// Returns a vector with a length no less than `min` and no more than `max` + /// + /// # Panics + /// + /// Will panic if `min` is greater than `max` when `glam_assert` is enabled. + #[inline] + pub fn clamp_length(self, min: f32, max: f32) -> Self { + glam_assert!(min <= max); + let length_sq = self.length_squared(); + if length_sq < min * min { + self * (length_sq.sqrt().recip() * min) + } else if length_sq > max * max { + self * (length_sq.sqrt().recip() * max) + } else { + self + } + } + + /// Returns a vector with a length no more than `max` + pub fn clamp_length_max(self, max: f32) -> Self { + let length_sq = self.length_squared(); + if length_sq > max * max { + self * (length_sq.sqrt().recip() * max) + } else { + self + } + } + + /// Returns a vector with a length no less than `min` + pub fn clamp_length_min(self, min: f32) -> Self { + let length_sq = self.length_squared(); + if length_sq < min * min { + self * (length_sq.sqrt().recip() * min) + } else { + self + } + } + + /// Fused multiply-add. Computes `(self * a) + b` element-wise with only one rounding + /// error, yielding a more accurate result than an unfused multiply-add. + /// + /// Using `mul_add` *may* be more performant than an unfused multiply-add if the target + /// architecture has a dedicated fma CPU instruction. However, this is not always true, + /// and will be heavily dependant on designing algorithms with specific target hardware in + /// mind. + #[inline] + pub fn mul_add(self, a: Self, b: Self) -> Self { + Self::new( + self.x.mul_add(a.x, b.x), + self.y.mul_add(a.y, b.y), + self.z.mul_add(a.z, b.z), + ) + } + + /// Returns the angle (in radians) between two vectors. + /// + /// The input vectors do not need to be unit length however they must be non-zero. + #[inline] + pub fn angle_between(self, rhs: Self) -> f32 { + use crate::FloatEx; + self.dot(rhs) + .div(self.length_squared().mul(rhs.length_squared()).sqrt()) + .acos_approx() + } + + /// Returns some vector that is orthogonal to the given one. + /// + /// The input vector must be finite and non-zero. + /// + /// The output vector is not necessarily unit-length. + /// For that use [`Self::any_orthonormal_vector`] instead. + #[inline] + pub fn any_orthogonal_vector(&self) -> Self { + // This can probably be optimized + if self.x.abs() > self.y.abs() { + Self::new(-self.z, 0.0, self.x) // self.cross(Self::Y) + } else { + Self::new(0.0, self.z, -self.y) // self.cross(Self::X) + } + } + + /// Returns any unit-length vector that is orthogonal to the given one. + /// The input vector must be finite and non-zero. + /// + /// # Panics + /// + /// Will panic if `self` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn any_orthonormal_vector(&self) -> Self { + glam_assert!(self.is_normalized()); + // From https://graphics.pixar.com/library/OrthonormalB/paper.pdf + #[cfg(feature = "std")] + let sign = (1.0_f32).copysign(self.z); + #[cfg(not(feature = "std"))] + let sign = self.z.signum(); + let a = -1.0 / (sign + self.z); + let b = self.x * self.y * a; + Self::new(b, sign + self.y * self.y * a, -self.y) + } + + /// Given a unit-length vector return two other vectors that together form an orthonormal + /// basis. That is, all three vectors are orthogonal to each other and are normalized. + /// + /// # Panics + /// + /// Will panic if `self` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn any_orthonormal_pair(&self) -> (Self, Self) { + glam_assert!(self.is_normalized()); + // From https://graphics.pixar.com/library/OrthonormalB/paper.pdf + #[cfg(feature = "std")] + let sign = (1.0_f32).copysign(self.z); + #[cfg(not(feature = "std"))] + let sign = self.z.signum(); + let a = -1.0 / (sign + self.z); + let b = self.x * self.y * a; + ( + Self::new(1.0 + sign * self.x * self.x * a, sign * b, -sign * self.x), + Self::new(b, sign + self.y * self.y * a, -self.y), + ) + } + + /// Casts all elements of `self` to `f64`. + #[inline] + pub fn as_dvec3(&self) -> crate::DVec3 { + crate::DVec3::new(self.x as f64, self.y as f64, self.z as f64) + } + + /// Casts all elements of `self` to `i32`. + #[inline] + pub fn as_ivec3(&self) -> crate::IVec3 { + crate::IVec3::new(self.x as i32, self.y as i32, self.z as i32) + } + + /// Casts all elements of `self` to `u32`. + #[inline] + pub fn as_uvec3(&self) -> crate::UVec3 { + crate::UVec3::new(self.x as u32, self.y as u32, self.z as u32) + } +} + +impl Default for Vec3 { + #[inline(always)] + fn default() -> Self { + Self::ZERO + } +} + +impl PartialEq for Vec3 { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.cmpeq(*rhs).all() + } +} + +impl Div for Vec3 { + type Output = Self; + #[inline] + fn div(self, rhs: Self) -> Self { + Self { + x: self.x.div(rhs.x), + y: self.y.div(rhs.y), + z: self.z.div(rhs.z), + } + } +} + +impl DivAssign for Vec3 { + #[inline] + fn div_assign(&mut self, rhs: Self) { + self.x.div_assign(rhs.x); + self.y.div_assign(rhs.y); + self.z.div_assign(rhs.z); + } +} + +impl Div for Vec3 { + type Output = Self; + #[inline] + fn div(self, rhs: f32) -> Self { + Self { + x: self.x.div(rhs), + y: self.y.div(rhs), + z: self.z.div(rhs), + } + } +} + +impl DivAssign for Vec3 { + #[inline] + fn div_assign(&mut self, rhs: f32) { + self.x.div_assign(rhs); + self.y.div_assign(rhs); + self.z.div_assign(rhs); + } +} + +impl Div for f32 { + type Output = Vec3; + #[inline] + fn div(self, rhs: Vec3) -> Vec3 { + Vec3 { + x: self.div(rhs.x), + y: self.div(rhs.y), + z: self.div(rhs.z), + } + } +} + +impl Mul for Vec3 { + type Output = Self; + #[inline] + fn mul(self, rhs: Self) -> Self { + Self { + x: self.x.mul(rhs.x), + y: self.y.mul(rhs.y), + z: self.z.mul(rhs.z), + } + } +} + +impl MulAssign for Vec3 { + #[inline] + fn mul_assign(&mut self, rhs: Self) { + self.x.mul_assign(rhs.x); + self.y.mul_assign(rhs.y); + self.z.mul_assign(rhs.z); + } +} + +impl Mul for Vec3 { + type Output = Self; + #[inline] + fn mul(self, rhs: f32) -> Self { + Self { + x: self.x.mul(rhs), + y: self.y.mul(rhs), + z: self.z.mul(rhs), + } + } +} + +impl MulAssign for Vec3 { + #[inline] + fn mul_assign(&mut self, rhs: f32) { + self.x.mul_assign(rhs); + self.y.mul_assign(rhs); + self.z.mul_assign(rhs); + } +} + +impl Mul for f32 { + type Output = Vec3; + #[inline] + fn mul(self, rhs: Vec3) -> Vec3 { + Vec3 { + x: self.mul(rhs.x), + y: self.mul(rhs.y), + z: self.mul(rhs.z), + } + } +} + +impl Add for Vec3 { + type Output = Self; + #[inline] + fn add(self, rhs: Self) -> Self { + Self { + x: self.x.add(rhs.x), + y: self.y.add(rhs.y), + z: self.z.add(rhs.z), + } + } +} + +impl AddAssign for Vec3 { + #[inline] + fn add_assign(&mut self, rhs: Self) { + self.x.add_assign(rhs.x); + self.y.add_assign(rhs.y); + self.z.add_assign(rhs.z); + } +} + +impl Add for Vec3 { + type Output = Self; + #[inline] + fn add(self, rhs: f32) -> Self { + Self { + x: self.x.add(rhs), + y: self.y.add(rhs), + z: self.z.add(rhs), + } + } +} + +impl AddAssign for Vec3 { + #[inline] + fn add_assign(&mut self, rhs: f32) { + self.x.add_assign(rhs); + self.y.add_assign(rhs); + self.z.add_assign(rhs); + } +} + +impl Add for f32 { + type Output = Vec3; + #[inline] + fn add(self, rhs: Vec3) -> Vec3 { + Vec3 { + x: self.add(rhs.x), + y: self.add(rhs.y), + z: self.add(rhs.z), + } + } +} + +impl Sub for Vec3 { + type Output = Self; + #[inline] + fn sub(self, rhs: Self) -> Self { + Self { + x: self.x.sub(rhs.x), + y: self.y.sub(rhs.y), + z: self.z.sub(rhs.z), + } + } +} + +impl SubAssign for Vec3 { + #[inline] + fn sub_assign(&mut self, rhs: Vec3) { + self.x.sub_assign(rhs.x); + self.y.sub_assign(rhs.y); + self.z.sub_assign(rhs.z); + } +} + +impl Sub for Vec3 { + type Output = Self; + #[inline] + fn sub(self, rhs: f32) -> Self { + Self { + x: self.x.sub(rhs), + y: self.y.sub(rhs), + z: self.z.sub(rhs), + } + } +} + +impl SubAssign for Vec3 { + #[inline] + fn sub_assign(&mut self, rhs: f32) { + self.x.sub_assign(rhs); + self.y.sub_assign(rhs); + self.z.sub_assign(rhs); + } +} + +impl Sub for f32 { + type Output = Vec3; + #[inline] + fn sub(self, rhs: Vec3) -> Vec3 { + Vec3 { + x: self.sub(rhs.x), + y: self.sub(rhs.y), + z: self.sub(rhs.z), + } + } +} + +impl Rem for Vec3 { + type Output = Self; + #[inline] + fn rem(self, rhs: Self) -> Self { + Self { + x: self.x.rem(rhs.x), + y: self.y.rem(rhs.y), + z: self.z.rem(rhs.z), + } + } +} + +impl RemAssign for Vec3 { + #[inline] + fn rem_assign(&mut self, rhs: Self) { + self.x.rem_assign(rhs.x); + self.y.rem_assign(rhs.y); + self.z.rem_assign(rhs.z); + } +} + +impl Rem for Vec3 { + type Output = Self; + #[inline] + fn rem(self, rhs: f32) -> Self { + Self { + x: self.x.rem(rhs), + y: self.y.rem(rhs), + z: self.z.rem(rhs), + } + } +} + +impl RemAssign for Vec3 { + #[inline] + fn rem_assign(&mut self, rhs: f32) { + self.x.rem_assign(rhs); + self.y.rem_assign(rhs); + self.z.rem_assign(rhs); + } +} + +impl Rem for f32 { + type Output = Vec3; + #[inline] + fn rem(self, rhs: Vec3) -> Vec3 { + Vec3 { + x: self.rem(rhs.x), + y: self.rem(rhs.y), + z: self.rem(rhs.z), + } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsRef<[f32; 3]> for Vec3 { + #[inline] + fn as_ref(&self) -> &[f32; 3] { + unsafe { &*(self as *const Vec3 as *const [f32; 3]) } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsMut<[f32; 3]> for Vec3 { + #[inline] + fn as_mut(&mut self) -> &mut [f32; 3] { + unsafe { &mut *(self as *mut Vec3 as *mut [f32; 3]) } + } +} + +impl<'a> Sum<&'a Self> for Vec3 { + #[inline] + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, |a, &b| Self::add(a, b)) + } +} + +impl<'a> Product<&'a Self> for Vec3 { + #[inline] + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ONE, |a, &b| Self::mul(a, b)) + } +} + +impl Neg for Vec3 { + type Output = Self; + #[inline] + fn neg(self) -> Self { + Self { + x: self.x.neg(), + y: self.y.neg(), + z: self.z.neg(), + } + } +} + +impl Index for Vec3 { + type Output = f32; + #[inline] + fn index(&self, index: usize) -> &Self::Output { + match index { + 0 => &self.x, + 1 => &self.y, + 2 => &self.z, + _ => panic!("index out of bounds"), + } + } +} + +impl IndexMut for Vec3 { + #[inline] + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + match index { + 0 => &mut self.x, + 1 => &mut self.y, + 2 => &mut self.z, + _ => panic!("index out of bounds"), + } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Display for Vec3 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "[{}, {}, {}]", self.x, self.y, self.z) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Debug for Vec3 { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_tuple(stringify!(Vec3)) + .field(&self.x) + .field(&self.y) + .field(&self.z) + .finish() + } +} + +impl From<[f32; 3]> for Vec3 { + #[inline] + fn from(a: [f32; 3]) -> Self { + Self::new(a[0], a[1], a[2]) + } +} + +impl From for [f32; 3] { + #[inline] + fn from(v: Vec3) -> Self { + [v.x, v.y, v.z] + } +} + +impl From<(f32, f32, f32)> for Vec3 { + #[inline] + fn from(t: (f32, f32, f32)) -> Self { + Self::new(t.0, t.1, t.2) + } +} + +impl From for (f32, f32, f32) { + #[inline] + fn from(v: Vec3) -> Self { + (v.x, v.y, v.z) + } +} + +impl From for Vec3 { + #[inline] + fn from(v: Vec3A) -> Self { + Self { + x: v.x, + y: v.y, + z: v.z, + } + } +} + +impl From<(Vec2, f32)> for Vec3 { + #[inline] + fn from((v, z): (Vec2, f32)) -> Self { + Self::new(v.x, v.y, z) + } +} diff --git a/src/f32/wasm32.rs b/src/f32/wasm32.rs new file mode 100644 index 00000000..24171e51 --- /dev/null +++ b/src/f32/wasm32.rs @@ -0,0 +1,6 @@ +pub mod mat2; +pub mod mat3a; +pub mod mat4; +pub mod quat; +pub mod vec3a; +pub mod vec4; diff --git a/src/f32/wasm32/mat2.rs b/src/f32/wasm32/mat2.rs new file mode 100644 index 00000000..d4c22115 --- /dev/null +++ b/src/f32/wasm32/mat2.rs @@ -0,0 +1,454 @@ +// Generated from mat.rs template. Edit the template, not the generated file. + +use crate::{swizzles::*, DMat2, Mat3, Vec2}; +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::iter::{Product, Sum}; +use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; + +use core::arch::wasm32::*; + +#[cfg(not(feature = "std"))] +use num_traits::Float; + +/// Creates a 2x2 matrix from column vectors. +#[inline(always)] +pub const fn mat2(x_axis: Vec2, y_axis: Vec2) -> Mat2 { + Mat2::from_cols(x_axis, y_axis) +} + +/// A 2x2 column major matrix. +#[derive(Clone, Copy)] +#[repr(transparent)] +pub struct Mat2(pub(crate) v128); + +impl Mat2 { + /// A 2x2 matrix with all elements set to `0.0`. + pub const ZERO: Self = Self::from_cols(Vec2::ZERO, Vec2::ZERO); + + /// A 2x2 identity matrix, where all diagonal elements are `1`, and all off-diagonal elements are `0`. + pub const IDENTITY: Self = Self::from_cols(Vec2::X, Vec2::Y); + + /// All NAN:s. + pub const NAN: Self = Self::from_cols(Vec2::NAN, Vec2::NAN); + + #[allow(clippy::too_many_arguments)] + #[inline(always)] + const fn new(m00: f32, m01: f32, m10: f32, m11: f32) -> Self { + Self(f32x4(m00, m01, m10, m11)) + } + + /// Creates a 2x2 matrix from two column vectors. + #[inline(always)] + pub const fn from_cols(x_axis: Vec2, y_axis: Vec2) -> Self { + Self(f32x4(x_axis.x, x_axis.y, y_axis.x, y_axis.y)) + } + + /// Creates a 2x2 matrix from a `[f32; 4]` array stored in column major order. + /// If your data is stored in row major you will need to `transpose` the returned + /// matrix. + #[inline] + pub const fn from_cols_array(m: &[f32; 4]) -> Self { + Self::new(m[0], m[1], m[2], m[3]) + } + + /// Creates a `[f32; 4]` array storing data in column major order. + /// If you require data in row major order `transpose` the matrix first. + #[inline] + pub fn to_cols_array(&self) -> [f32; 4] { + [self.x_axis.x, self.x_axis.y, self.y_axis.x, self.y_axis.y] + } + + /// Creates a 2x2 matrix from a `[[f32; 2]; 2]` 2D array stored in column major order. + /// If your data is in row major order you will need to `transpose` the returned + /// matrix. + #[inline] + pub const fn from_cols_array_2d(m: &[[f32; 2]; 2]) -> Self { + Self::from_cols(Vec2::from_array(m[0]), Vec2::from_array(m[1])) + } + + /// Creates a `[[f32; 2]; 2]` 2D array storing data in column major order. + /// If you require data in row major order `transpose` the matrix first. + #[inline] + pub fn to_cols_array_2d(&self) -> [[f32; 2]; 2] { + [self.x_axis.to_array(), self.y_axis.to_array()] + } + + /// Creates a 2x2 matrix with its diagonal set to `diagonal` and all other entries set to 0. + #[doc(alias = "scale")] + #[inline] + pub fn from_diagonal(diagonal: Vec2) -> Self { + Self::new(diagonal.x, 0.0, 0.0, diagonal.y) + } + + /// Creates a 2x2 matrix containing the combining non-uniform `scale` and rotation of + /// `angle` (in radians). + #[inline] + pub fn from_scale_angle(scale: Vec2, angle: f32) -> Self { + let (sin, cos) = angle.sin_cos(); + Self::new(cos * scale.x, sin * scale.x, -sin * scale.y, cos * scale.y) + } + + /// Creates a 2x2 matrix containing a rotation of `angle` (in radians). + #[inline] + pub fn from_angle(angle: f32) -> Self { + let (sin, cos) = angle.sin_cos(); + Self::new(cos, sin, -sin, cos) + } + + /// Creates a 2x2 matrix from a 3x3 matrix, discarding the 2nd row and column. + #[inline] + pub fn from_mat3(m: Mat3) -> Self { + Self::from_cols(m.x_axis.xy(), m.y_axis.xy()) + } + + /// Creates a 2x2 matrix from the first 4 values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 4 elements long. + #[inline] + pub const fn from_cols_slice(slice: &[f32]) -> Self { + Self::new(slice[0], slice[1], slice[2], slice[3]) + } + + /// Writes the columns of `self` to the first 4 elements in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 4 elements long. + #[inline] + pub fn write_cols_to_slice(self, slice: &mut [f32]) { + slice[0] = self.x_axis.x; + slice[1] = self.x_axis.y; + slice[2] = self.y_axis.x; + slice[3] = self.y_axis.y; + } + + /// Returns the matrix column for the given `index`. + /// + /// # Panics + /// + /// Panics if `index` is greater than 1. + #[inline] + pub fn col(&self, index: usize) -> Vec2 { + match index { + 0 => self.x_axis, + 1 => self.y_axis, + _ => panic!("index out of bounds"), + } + } + + /// Returns a mutable reference to the matrix column for the given `index`. + /// + /// # Panics + /// + /// Panics if `index` is greater than 1. + #[inline] + pub fn col_mut(&mut self, index: usize) -> &mut Vec2 { + match index { + 0 => &mut self.x_axis, + 1 => &mut self.y_axis, + _ => panic!("index out of bounds"), + } + } + + /// Returns the matrix row for the given `index`. + /// + /// # Panics + /// + /// Panics if `index` is greater than 1. + #[inline] + pub fn row(&self, index: usize) -> Vec2 { + match index { + 0 => Vec2::new(self.x_axis.x, self.y_axis.x), + 1 => Vec2::new(self.x_axis.y, self.y_axis.y), + _ => panic!("index out of bounds"), + } + } + + /// Returns `true` if, and only if, all elements are finite. + /// If any element is either `NaN`, positive or negative infinity, this will return `false`. + #[inline] + pub fn is_finite(&self) -> bool { + self.x_axis.is_finite() && self.y_axis.is_finite() + } + + /// Returns `true` if any elements are `NaN`. + #[inline] + pub fn is_nan(&self) -> bool { + self.x_axis.is_nan() || self.y_axis.is_nan() + } + + /// Returns the transpose of `self`. + #[must_use] + #[inline] + pub fn transpose(&self) -> Self { + Self(i32x4_shuffle::<0, 2, 5, 7>(self.0, self.0)) + } + + /// Returns the determinant of `self`. + #[inline] + pub fn determinant(&self) -> f32 { + let abcd = self.0; + let dcba = i32x4_shuffle::<3, 2, 5, 4>(abcd, abcd); + let prod = f32x4_mul(abcd, dcba); + let det = f32x4_sub(prod, i32x4_shuffle::<1, 1, 5, 5>(prod, prod)); + f32x4_extract_lane::<0>(det) + } + + /// Returns the inverse of `self`. + /// + /// If the matrix is not invertible the returned matrix will be invalid. + /// + /// # Panics + /// + /// Will panic if the determinant of `self` is zero when `glam_assert` is enabled. + #[must_use] + pub fn inverse(&self) -> Self { + const SIGN: v128 = const_f32x4!([1.0, -1.0, -1.0, 1.0]); + let abcd = self.0; + let dcba = i32x4_shuffle::<3, 2, 5, 4>(abcd, abcd); + let prod = f32x4_mul(abcd, dcba); + let sub = f32x4_sub(prod, i32x4_shuffle::<1, 1, 5, 5>(prod, prod)); + let det = i32x4_shuffle::<0, 0, 4, 4>(sub, sub); + let tmp = f32x4_div(SIGN, det); + glam_assert!(Mat2(tmp).is_finite()); + let dbca = i32x4_shuffle::<3, 1, 6, 4>(abcd, abcd); + Self(f32x4_mul(dbca, tmp)) + } + + /// Transforms a 2D vector. + #[inline] + pub fn mul_vec2(&self, rhs: Vec2) -> Vec2 { + use core::mem::MaybeUninit; + let abcd = self.0; + let xxyy = f32x4(rhs.x, rhs.x, rhs.y, rhs.y); + let axbxcydy = f32x4_mul(abcd, xxyy); + let cydyaxbx = i32x4_shuffle::<2, 3, 4, 5>(axbxcydy, axbxcydy); + let result = f32x4_add(axbxcydy, cydyaxbx); + let mut out: MaybeUninit = MaybeUninit::uninit(); + unsafe { + v128_store(out.as_mut_ptr(), result); + *(&out.assume_init() as *const v128 as *const Vec2) + } + } + + /// Multiplies two 2x2 matrices. + #[inline] + pub fn mul_mat2(&self, rhs: &Self) -> Self { + let abcd = self.0; + let rhs = rhs.0; + let xxyy0 = i32x4_shuffle::<0, 0, 5, 5>(rhs, rhs); + let xxyy1 = i32x4_shuffle::<2, 2, 7, 7>(rhs, rhs); + let axbxcydy0 = f32x4_mul(abcd, xxyy0); + let axbxcydy1 = f32x4_mul(abcd, xxyy1); + let cydyaxbx0 = i32x4_shuffle::<2, 3, 4, 5>(axbxcydy0, axbxcydy0); + let cydyaxbx1 = i32x4_shuffle::<2, 3, 4, 5>(axbxcydy1, axbxcydy1); + let result0 = f32x4_add(axbxcydy0, cydyaxbx0); + let result1 = f32x4_add(axbxcydy1, cydyaxbx1); + Self(i32x4_shuffle::<0, 1, 4, 5>(result0, result1)) + } + + /// Adds two 2x2 matrices. + #[inline] + pub fn add_mat2(&self, rhs: &Self) -> Self { + Self(f32x4_add(self.0, rhs.0)) + } + + /// Subtracts two 2x2 matrices. + #[inline] + pub fn sub_mat2(&self, rhs: &Self) -> Self { + Self(f32x4_sub(self.0, rhs.0)) + } + + /// Multiplies a 2x2 matrix by a scalar. + #[inline] + pub fn mul_scalar(&self, rhs: f32) -> Self { + Self(f32x4_mul(self.0, f32x4_splat(rhs))) + } + + /// Returns true if the absolute difference of all elements between `self` and `rhs` + /// is less than or equal to `max_abs_diff`. + /// + /// This can be used to compare if two matrices contain similar elements. It works best + /// when comparing with a known value. The `max_abs_diff` that should be used used + /// depends on the values being compared against. + /// + /// For more see + /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/). + #[inline] + pub fn abs_diff_eq(&self, rhs: Self, max_abs_diff: f32) -> bool { + self.x_axis.abs_diff_eq(rhs.x_axis, max_abs_diff) + && self.y_axis.abs_diff_eq(rhs.y_axis, max_abs_diff) + } + + #[inline] + pub fn as_dmat2(&self) -> DMat2 { + DMat2::from_cols(self.x_axis.as_dvec2(), self.y_axis.as_dvec2()) + } +} + +impl Default for Mat2 { + #[inline] + fn default() -> Self { + Self::IDENTITY + } +} + +impl Add for Mat2 { + type Output = Self; + #[inline] + fn add(self, rhs: Self) -> Self::Output { + self.add_mat2(&rhs) + } +} + +impl AddAssign for Mat2 { + #[inline] + fn add_assign(&mut self, rhs: Self) { + *self = self.add_mat2(&rhs); + } +} + +impl Sub for Mat2 { + type Output = Self; + #[inline] + fn sub(self, rhs: Self) -> Self::Output { + self.sub_mat2(&rhs) + } +} + +impl SubAssign for Mat2 { + #[inline] + fn sub_assign(&mut self, rhs: Self) { + *self = self.sub_mat2(&rhs); + } +} + +impl Neg for Mat2 { + type Output = Self; + #[inline] + fn neg(self) -> Self::Output { + Self(f32x4_neg(self.0)) + } +} + +impl Mul for Mat2 { + type Output = Self; + #[inline] + fn mul(self, rhs: Self) -> Self::Output { + self.mul_mat2(&rhs) + } +} + +impl MulAssign for Mat2 { + #[inline] + fn mul_assign(&mut self, rhs: Self) { + *self = self.mul_mat2(&rhs); + } +} + +impl Mul for Mat2 { + type Output = Vec2; + #[inline] + fn mul(self, rhs: Vec2) -> Self::Output { + self.mul_vec2(rhs) + } +} + +impl Mul for f32 { + type Output = Mat2; + #[inline] + fn mul(self, rhs: Mat2) -> Self::Output { + rhs.mul_scalar(self) + } +} + +impl Mul for Mat2 { + type Output = Self; + #[inline] + fn mul(self, rhs: f32) -> Self::Output { + self.mul_scalar(rhs) + } +} + +impl MulAssign for Mat2 { + #[inline] + fn mul_assign(&mut self, rhs: f32) { + *self = self.mul_scalar(rhs); + } +} + +impl<'a> Sum<&'a Self> for Mat2 { + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, |a, &b| Self::add(a, b)) + } +} + +impl<'a> Product<&'a Self> for Mat2 { + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::IDENTITY, |a, &b| Self::mul(a, b)) + } +} + +impl PartialEq for Mat2 { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.x_axis.eq(&rhs.x_axis) && self.y_axis.eq(&rhs.y_axis) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsRef<[f32; 4]> for Mat2 { + #[inline] + fn as_ref(&self) -> &[f32; 4] { + unsafe { &*(self as *const Self as *const [f32; 4]) } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsMut<[f32; 4]> for Mat2 { + #[inline] + fn as_mut(&mut self) -> &mut [f32; 4] { + unsafe { &mut *(self as *mut Self as *mut [f32; 4]) } + } +} + +impl core::ops::Deref for Mat2 { + type Target = crate::deref::Columns2; + #[inline] + fn deref(&self) -> &Self::Target { + unsafe { &*(self as *const Self as *const Self::Target) } + } +} + +impl core::ops::DerefMut for Mat2 { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { &mut *(self as *mut Self as *mut Self::Target) } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Debug for Mat2 { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct(stringify!(Mat2)) + .field("x_axis", &self.x_axis) + .field("y_axis", &self.y_axis) + .finish() + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Display for Mat2 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "[{}, {}]", self.x_axis, self.y_axis) + } +} diff --git a/src/f32/wasm32/mat3a.rs b/src/f32/wasm32/mat3a.rs new file mode 100644 index 00000000..3d6f05cd --- /dev/null +++ b/src/f32/wasm32/mat3a.rs @@ -0,0 +1,698 @@ +// Generated from mat.rs template. Edit the template, not the generated file. + +use crate::{swizzles::*, DMat3, EulerRot, Mat2, Mat3, Mat4, Quat, Vec2, Vec3, Vec3A}; +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::iter::{Product, Sum}; +use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; + +use core::arch::wasm32::*; + +#[cfg(not(feature = "std"))] +use num_traits::Float; + +/// Creates a 3x3 matrix from column vectors. +#[inline(always)] +pub const fn mat3a(x_axis: Vec3A, y_axis: Vec3A, z_axis: Vec3A) -> Mat3A { + Mat3A::from_cols(x_axis, y_axis, z_axis) +} + +/// A 3x3 column major matrix. +/// +/// This 3x3 matrix type features convenience methods for creating and using linear and +/// affine transformations. If you are primarily dealing with 2D affine transformations the +/// [`Affine2`](crate::Affine2) type is much faster and more space efficient than +/// using a 3x3 matrix. +/// +/// Linear transformations including 3D rotation and scale can be created using methods +/// such as [`Self::from_diagonal()`], [`Self::from_quat()`], [`Self::from_axis_angle()`], +/// [`Self::from_rotation_x()`], [`Self::from_rotation_y()`], or +/// [`Self::from_rotation_z()`]. +/// +/// The resulting matrices can be use to transform 3D vectors using regular vector +/// multiplication. +/// +/// Affine transformations including 2D translation, rotation and scale can be created +/// using methods such as [`Self::from_translation()`], [`Self::from_angle()`], +/// [`Self::from_scale()`] and [`Self::from_scale_angle_translation()`]. +/// +/// The [`Self::transform_point2()`] and [`Self::transform_vector2()`] convenience methods +/// are provided for performing affine transforms on 2D vectors and points. These multiply +/// 2D inputs as 3D vectors with an implicit `z` value of `1` for points and `0` for +/// vectors respectively. These methods assume that `Self` contains a valid affine +/// transform. +#[derive(Clone, Copy)] +pub struct Mat3A { + pub x_axis: Vec3A, + pub y_axis: Vec3A, + pub z_axis: Vec3A, +} + +impl Mat3A { + /// A 3x3 matrix with all elements set to `0.0`. + pub const ZERO: Self = Self::from_cols(Vec3A::ZERO, Vec3A::ZERO, Vec3A::ZERO); + + /// A 3x3 identity matrix, where all diagonal elements are `1`, and all off-diagonal elements are `0`. + pub const IDENTITY: Self = Self::from_cols(Vec3A::X, Vec3A::Y, Vec3A::Z); + + /// All NAN:s. + pub const NAN: Self = Self::from_cols(Vec3A::NAN, Vec3A::NAN, Vec3A::NAN); + + #[allow(clippy::too_many_arguments)] + #[inline(always)] + const fn new( + m00: f32, + m01: f32, + m02: f32, + m10: f32, + m11: f32, + m12: f32, + m20: f32, + m21: f32, + m22: f32, + ) -> Self { + Self { + x_axis: Vec3A::new(m00, m01, m02), + y_axis: Vec3A::new(m10, m11, m12), + z_axis: Vec3A::new(m20, m21, m22), + } + } + + /// Creates a 3x3 matrix from two column vectors. + #[inline(always)] + pub const fn from_cols(x_axis: Vec3A, y_axis: Vec3A, z_axis: Vec3A) -> Self { + Self { + x_axis, + y_axis, + z_axis, + } + } + + /// Creates a 3x3 matrix from a `[f32; 9]` array stored in column major order. + /// If your data is stored in row major you will need to `transpose` the returned + /// matrix. + #[inline] + pub const fn from_cols_array(m: &[f32; 9]) -> Self { + Self::new(m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8]) + } + + /// Creates a `[f32; 9]` array storing data in column major order. + /// If you require data in row major order `transpose` the matrix first. + #[inline] + pub fn to_cols_array(&self) -> [f32; 9] { + [ + self.x_axis.x, + self.x_axis.y, + self.x_axis.z, + self.y_axis.x, + self.y_axis.y, + self.y_axis.z, + self.z_axis.x, + self.z_axis.y, + self.z_axis.z, + ] + } + + /// Creates a 3x3 matrix from a `[[f32; 3]; 3]` 3D array stored in column major order. + /// If your data is in row major order you will need to `transpose` the returned + /// matrix. + #[inline] + pub const fn from_cols_array_2d(m: &[[f32; 3]; 3]) -> Self { + Self::from_cols( + Vec3A::from_array(m[0]), + Vec3A::from_array(m[1]), + Vec3A::from_array(m[2]), + ) + } + + /// Creates a `[[f32; 3]; 3]` 3D array storing data in column major order. + /// If you require data in row major order `transpose` the matrix first. + #[inline] + pub fn to_cols_array_2d(&self) -> [[f32; 3]; 3] { + [ + self.x_axis.to_array(), + self.y_axis.to_array(), + self.z_axis.to_array(), + ] + } + + /// Creates a 3x3 matrix with its diagonal set to `diagonal` and all other entries set to 0. + #[doc(alias = "scale")] + #[inline] + pub fn from_diagonal(diagonal: Vec3) -> Self { + Self::new( + diagonal.x, 0.0, 0.0, 0.0, diagonal.y, 0.0, 0.0, 0.0, diagonal.z, + ) + } + + /// Creates a 3x3 matrix from a 4x4 matrix, discarding the 3rd row and column. + pub fn from_mat4(m: Mat4) -> Self { + Self::from_cols(m.x_axis.into(), m.y_axis.into(), m.z_axis.into()) + } + + /// Creates a 3D rotation matrix from the given quaternion. + /// + /// # Panics + /// + /// Will panic if `rotation` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn from_quat(rotation: Quat) -> Self { + glam_assert!(rotation.is_normalized()); + + let x2 = rotation.x + rotation.x; + let y2 = rotation.y + rotation.y; + let z2 = rotation.z + rotation.z; + let xx = rotation.x * x2; + let xy = rotation.x * y2; + let xz = rotation.x * z2; + let yy = rotation.y * y2; + let yz = rotation.y * z2; + let zz = rotation.z * z2; + let wx = rotation.w * x2; + let wy = rotation.w * y2; + let wz = rotation.w * z2; + + Self::from_cols( + Vec3A::new(1.0 - (yy + zz), xy + wz, xz - wy), + Vec3A::new(xy - wz, 1.0 - (xx + zz), yz + wx), + Vec3A::new(xz + wy, yz - wx, 1.0 - (xx + yy)), + ) + } + + /// Creates a 3D rotation matrix from a normalized rotation `axis` and `angle` (in + /// radians). + /// + /// # Panics + /// + /// Will panic if `axis` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn from_axis_angle(axis: Vec3, angle: f32) -> Self { + glam_assert!(axis.is_normalized()); + + let (sin, cos) = angle.sin_cos(); + let (xsin, ysin, zsin) = axis.mul(sin).into(); + let (x, y, z) = axis.into(); + let (x2, y2, z2) = axis.mul(axis).into(); + let omc = 1.0 - cos; + let xyomc = x * y * omc; + let xzomc = x * z * omc; + let yzomc = y * z * omc; + Self::from_cols( + Vec3A::new(x2 * omc + cos, xyomc + zsin, xzomc - ysin), + Vec3A::new(xyomc - zsin, y2 * omc + cos, yzomc + xsin), + Vec3A::new(xzomc + ysin, yzomc - xsin, z2 * omc + cos), + ) + } + + #[inline] + /// Creates a 3D rotation matrix from the given euler rotation sequence and the angles (in + /// radians). + pub fn from_euler(order: EulerRot, a: f32, b: f32, c: f32) -> Self { + let quat = Quat::from_euler(order, a, b, c); + Self::from_quat(quat) + } + + /// Creates a 3D rotation matrix from `angle` (in radians) around the x axis. + #[inline] + pub fn from_rotation_x(angle: f32) -> Self { + let (sina, cosa) = angle.sin_cos(); + Self::from_cols( + Vec3A::X, + Vec3A::new(0.0, cosa, sina), + Vec3A::new(0.0, -sina, cosa), + ) + } + + /// Creates a 3D rotation matrix from `angle` (in radians) around the y axis. + #[inline] + pub fn from_rotation_y(angle: f32) -> Self { + let (sina, cosa) = angle.sin_cos(); + Self::from_cols( + Vec3A::new(cosa, 0.0, -sina), + Vec3A::Y, + Vec3A::new(sina, 0.0, cosa), + ) + } + + /// Creates a 3D rotation matrix from `angle` (in radians) around the z axis. + #[inline] + pub fn from_rotation_z(angle: f32) -> Self { + let (sina, cosa) = angle.sin_cos(); + Self::from_cols( + Vec3A::new(cosa, sina, 0.0), + Vec3A::new(-sina, cosa, 0.0), + Vec3A::Z, + ) + } + + /// Creates an affine transformation matrix from the given 2D `translation`. + /// + /// The resulting matrix can be used to transform 2D points and vectors. See + /// [`Self::transform_point2()`] and [`Self::transform_vector2()`]. + #[inline] + pub fn from_translation(translation: Vec2) -> Self { + Self::from_cols( + Vec3A::X, + Vec3A::Y, + Vec3A::new(translation.x, translation.y, 1.0), + ) + } + + /// Creates an affine transformation matrix from the given 2D rotation `angle` (in + /// radians). + /// + /// The resulting matrix can be used to transform 2D points and vectors. See + /// [`Self::transform_point2()`] and [`Self::transform_vector2()`]. + #[inline] + pub fn from_angle(angle: f32) -> Self { + let (sin, cos) = angle.sin_cos(); + Self::from_cols( + Vec3A::new(cos, sin, 0.0), + Vec3A::new(-sin, cos, 0.0), + Vec3A::Z, + ) + } + + /// Creates an affine transformation matrix from the given 2D `scale`, rotation `angle` (in + /// radians) and `translation`. + /// + /// The resulting matrix can be used to transform 2D points and vectors. See + /// [`Self::transform_point2()`] and [`Self::transform_vector2()`]. + #[inline] + pub fn from_scale_angle_translation(scale: Vec2, angle: f32, translation: Vec2) -> Self { + let (sin, cos) = angle.sin_cos(); + Self::from_cols( + Vec3A::new(cos * scale.x, sin * scale.x, 0.0), + Vec3A::new(-sin * scale.y, cos * scale.y, 0.0), + Vec3A::new(translation.x, translation.y, 1.0), + ) + } + + /// Creates an affine transformation matrix from the given non-uniform 2D `scale`. + /// + /// The resulting matrix can be used to transform 2D points and vectors. See + /// [`Self::transform_point2()`] and [`Self::transform_vector2()`]. + /// + /// # Panics + /// + /// Will panic if all elements of `scale` are zero when `glam_assert` is enabled. + #[inline] + pub fn from_scale(scale: Vec2) -> Self { + // Do not panic as long as any component is non-zero + glam_assert!(scale.cmpne(Vec2::ZERO).any()); + + Self::from_cols( + Vec3A::new(scale.x, 0.0, 0.0), + Vec3A::new(0.0, scale.y, 0.0), + Vec3A::Z, + ) + } + + /// Creates an affine transformation matrix from the given 2x2 matrix. + /// + /// The resulting matrix can be used to transform 2D points and vectors. See + /// [`Self::transform_point2()`] and [`Self::transform_vector2()`]. + #[inline] + pub fn from_mat2(m: Mat2) -> Self { + Self::from_cols((m.x_axis, 0.0).into(), (m.y_axis, 0.0).into(), Vec3A::Z) + } + + /// Creates a 3x3 matrix from the first 9 values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 9 elements long. + #[inline] + pub const fn from_cols_slice(slice: &[f32]) -> Self { + Self::new( + slice[0], slice[1], slice[2], slice[3], slice[4], slice[5], slice[6], slice[7], + slice[8], + ) + } + + /// Writes the columns of `self` to the first 9 elements in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 9 elements long. + #[inline] + pub fn write_cols_to_slice(self, slice: &mut [f32]) { + slice[0] = self.x_axis.x; + slice[1] = self.x_axis.y; + slice[2] = self.x_axis.z; + slice[3] = self.y_axis.x; + slice[4] = self.y_axis.y; + slice[5] = self.y_axis.z; + slice[6] = self.z_axis.x; + slice[7] = self.z_axis.y; + slice[8] = self.z_axis.z; + } + + /// Returns the matrix column for the given `index`. + /// + /// # Panics + /// + /// Panics if `index` is greater than 2. + #[inline] + pub fn col(&self, index: usize) -> Vec3A { + match index { + 0 => self.x_axis, + 1 => self.y_axis, + 2 => self.z_axis, + _ => panic!("index out of bounds"), + } + } + + /// Returns a mutable reference to the matrix column for the given `index`. + /// + /// # Panics + /// + /// Panics if `index` is greater than 2. + #[inline] + pub fn col_mut(&mut self, index: usize) -> &mut Vec3A { + match index { + 0 => &mut self.x_axis, + 1 => &mut self.y_axis, + 2 => &mut self.z_axis, + _ => panic!("index out of bounds"), + } + } + + /// Returns the matrix row for the given `index`. + /// + /// # Panics + /// + /// Panics if `index` is greater than 2. + #[inline] + pub fn row(&self, index: usize) -> Vec3A { + match index { + 0 => Vec3A::new(self.x_axis.x, self.y_axis.x, self.z_axis.x), + 1 => Vec3A::new(self.x_axis.y, self.y_axis.y, self.z_axis.y), + 2 => Vec3A::new(self.x_axis.z, self.y_axis.z, self.z_axis.z), + _ => panic!("index out of bounds"), + } + } + + /// Returns `true` if, and only if, all elements are finite. + /// If any element is either `NaN`, positive or negative infinity, this will return `false`. + #[inline] + pub fn is_finite(&self) -> bool { + self.x_axis.is_finite() && self.y_axis.is_finite() && self.z_axis.is_finite() + } + + /// Returns `true` if any elements are `NaN`. + #[inline] + pub fn is_nan(&self) -> bool { + self.x_axis.is_nan() || self.y_axis.is_nan() || self.z_axis.is_nan() + } + + /// Returns the transpose of `self`. + #[must_use] + #[inline] + pub fn transpose(&self) -> Self { + let tmp0 = i32x4_shuffle::<0, 1, 4, 5>(self.x_axis.0, self.y_axis.0); + let tmp1 = i32x4_shuffle::<2, 3, 6, 7>(self.x_axis.0, self.y_axis.0); + + Self { + x_axis: Vec3A(i32x4_shuffle::<0, 2, 4, 4>(tmp0, self.z_axis.0)), + y_axis: Vec3A(i32x4_shuffle::<1, 3, 5, 5>(tmp0, self.z_axis.0)), + z_axis: Vec3A(i32x4_shuffle::<0, 2, 6, 6>(tmp1, self.z_axis.0)), + } + } + + /// Returns the determinant of `self`. + pub fn determinant(&self) -> f32 { + self.z_axis.dot(self.x_axis.cross(self.y_axis)) + } + + /// Returns the inverse of `self`. + /// + /// If the matrix is not invertible the returned matrix will be invalid. + /// + /// # Panics + /// + /// Will panic if the determinant of `self` is zero when `glam_assert` is enabled. + #[must_use] + pub fn inverse(&self) -> Self { + let tmp0 = self.y_axis.cross(self.z_axis); + let tmp1 = self.z_axis.cross(self.x_axis); + let tmp2 = self.x_axis.cross(self.y_axis); + let det = self.z_axis.dot(tmp2); + glam_assert!(det != 0.0); + let inv_det = Vec3A::splat(det.recip()); + Self::from_cols(tmp0.mul(inv_det), tmp1.mul(inv_det), tmp2.mul(inv_det)).transpose() + } + + /// Transforms the given 2D vector as a point. + /// + /// This is the equivalent of multiplying `rhs` as a 3D vector where `z` is `1`. + /// + /// This method assumes that `self` contains a valid affine transform. + #[inline] + pub fn transform_point2(&self, rhs: Vec2) -> Vec2 { + Mat2::from_cols(self.x_axis.xy(), self.y_axis.xy()) * rhs + self.z_axis.xy() + } + + /// Rotates the given 2D vector. + /// + /// This is the equivalent of multiplying `rhs` as a 3D vector where `z` is `0`. + /// + /// This method assumes that `self` contains a valid affine transform. + #[inline] + pub fn transform_vector2(&self, rhs: Vec2) -> Vec2 { + Mat2::from_cols(self.x_axis.xy(), self.y_axis.xy()) * rhs + } + + /// Transforms a 3D vector. + #[inline] + pub fn mul_vec3(&self, rhs: Vec3) -> Vec3 { + self.mul_vec3a(rhs.into()).into() + } + + /// Transforms a `Vec3A`. + #[inline] + pub fn mul_vec3a(&self, rhs: Vec3A) -> Vec3A { + let mut res = self.x_axis.mul(rhs.xxx()); + res = res.add(self.y_axis.mul(rhs.yyy())); + res = res.add(self.z_axis.mul(rhs.zzz())); + res + } + + /// Multiplies two 3x3 matrices. + #[inline] + pub fn mul_mat3(&self, rhs: &Self) -> Self { + Self::from_cols( + self.mul(rhs.x_axis), + self.mul(rhs.y_axis), + self.mul(rhs.z_axis), + ) + } + + /// Adds two 3x3 matrices. + #[inline] + pub fn add_mat3(&self, rhs: &Self) -> Self { + Self::from_cols( + self.x_axis.add(rhs.x_axis), + self.y_axis.add(rhs.y_axis), + self.z_axis.add(rhs.z_axis), + ) + } + + /// Subtracts two 3x3 matrices. + #[inline] + pub fn sub_mat3(&self, rhs: &Self) -> Self { + Self::from_cols( + self.x_axis.sub(rhs.x_axis), + self.y_axis.sub(rhs.y_axis), + self.z_axis.sub(rhs.z_axis), + ) + } + + /// Multiplies a 3x3 matrix by a scalar. + #[inline] + pub fn mul_scalar(&self, rhs: f32) -> Self { + Self::from_cols( + self.x_axis.mul(rhs), + self.y_axis.mul(rhs), + self.z_axis.mul(rhs), + ) + } + + /// Returns true if the absolute difference of all elements between `self` and `rhs` + /// is less than or equal to `max_abs_diff`. + /// + /// This can be used to compare if two matrices contain similar elements. It works best + /// when comparing with a known value. The `max_abs_diff` that should be used used + /// depends on the values being compared against. + /// + /// For more see + /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/). + #[inline] + pub fn abs_diff_eq(&self, rhs: Self, max_abs_diff: f32) -> bool { + self.x_axis.abs_diff_eq(rhs.x_axis, max_abs_diff) + && self.y_axis.abs_diff_eq(rhs.y_axis, max_abs_diff) + && self.z_axis.abs_diff_eq(rhs.z_axis, max_abs_diff) + } + + #[inline] + pub fn as_dmat3(&self) -> DMat3 { + DMat3::from_cols( + self.x_axis.as_dvec3(), + self.y_axis.as_dvec3(), + self.z_axis.as_dvec3(), + ) + } +} + +impl Default for Mat3A { + #[inline] + fn default() -> Self { + Self::IDENTITY + } +} + +impl Add for Mat3A { + type Output = Self; + #[inline] + fn add(self, rhs: Self) -> Self::Output { + self.add_mat3(&rhs) + } +} + +impl AddAssign for Mat3A { + #[inline] + fn add_assign(&mut self, rhs: Self) { + *self = self.add_mat3(&rhs); + } +} + +impl Sub for Mat3A { + type Output = Self; + #[inline] + fn sub(self, rhs: Self) -> Self::Output { + self.sub_mat3(&rhs) + } +} + +impl SubAssign for Mat3A { + #[inline] + fn sub_assign(&mut self, rhs: Self) { + *self = self.sub_mat3(&rhs); + } +} + +impl Neg for Mat3A { + type Output = Self; + #[inline] + fn neg(self) -> Self::Output { + Self::from_cols(self.x_axis.neg(), self.y_axis.neg(), self.z_axis.neg()) + } +} + +impl Mul for Mat3A { + type Output = Self; + #[inline] + fn mul(self, rhs: Self) -> Self::Output { + self.mul_mat3(&rhs) + } +} + +impl MulAssign for Mat3A { + #[inline] + fn mul_assign(&mut self, rhs: Self) { + *self = self.mul_mat3(&rhs); + } +} + +impl Mul for Mat3A { + type Output = Vec3A; + #[inline] + fn mul(self, rhs: Vec3A) -> Self::Output { + self.mul_vec3a(rhs) + } +} + +impl Mul for f32 { + type Output = Mat3A; + #[inline] + fn mul(self, rhs: Mat3A) -> Self::Output { + rhs.mul_scalar(self) + } +} + +impl Mul for Mat3A { + type Output = Self; + #[inline] + fn mul(self, rhs: f32) -> Self::Output { + self.mul_scalar(rhs) + } +} + +impl MulAssign for Mat3A { + #[inline] + fn mul_assign(&mut self, rhs: f32) { + *self = self.mul_scalar(rhs); + } +} + +impl Mul for Mat3A { + type Output = Vec3; + #[inline] + fn mul(self, rhs: Vec3) -> Vec3 { + self.mul_vec3a(rhs.into()).into() + } +} + +impl From for Mat3A { + #[inline] + fn from(m: Mat3) -> Self { + Self { + x_axis: m.x_axis.into(), + y_axis: m.y_axis.into(), + z_axis: m.z_axis.into(), + } + } +} + +impl<'a> Sum<&'a Self> for Mat3A { + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, |a, &b| Self::add(a, b)) + } +} + +impl<'a> Product<&'a Self> for Mat3A { + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::IDENTITY, |a, &b| Self::mul(a, b)) + } +} + +impl PartialEq for Mat3A { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.x_axis.eq(&rhs.x_axis) && self.y_axis.eq(&rhs.y_axis) && self.z_axis.eq(&rhs.z_axis) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Debug for Mat3A { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct(stringify!(Mat3A)) + .field("x_axis", &self.x_axis) + .field("y_axis", &self.y_axis) + .field("z_axis", &self.z_axis) + .finish() + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Display for Mat3A { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "[{}, {}, {}]", self.x_axis, self.y_axis, self.z_axis) + } +} diff --git a/src/f32/wasm32/mat4.rs b/src/f32/wasm32/mat4.rs new file mode 100644 index 00000000..ce42cc3c --- /dev/null +++ b/src/f32/wasm32/mat4.rs @@ -0,0 +1,1318 @@ +// Generated from mat.rs template. Edit the template, not the generated file. + +use crate::{swizzles::*, DMat4, EulerRot, Mat3, Quat, Vec3, Vec3A, Vec4}; +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::iter::{Product, Sum}; +use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; + +use core::arch::wasm32::*; + +#[cfg(not(feature = "std"))] +use num_traits::Float; + +/// Creates a 4x4 matrix from column vectors. +#[inline(always)] +pub const fn mat4(x_axis: Vec4, y_axis: Vec4, z_axis: Vec4, w_axis: Vec4) -> Mat4 { + Mat4::from_cols(x_axis, y_axis, z_axis, w_axis) +} + +/// A 4x4 column major matrix. +/// +/// This 4x4 matrix type features convenience methods for creating and using affine transforms and +/// perspective projections. If you are primarily dealing with 3D affine transformations +/// considering using [`Affine3A`](crate::Affine3A) which is faster than a 4x4 matrix +/// for some affine operations. +/// +/// Affine transformations including 3D translation, rotation and scale can be created +/// using methods such as [`Self::from_translation()`], [`Self::from_quat()`], +/// [`Self::from_scale()`] and [`Self::from_scale_rotation_translation()`]. +/// +/// Othographic projections can be created using the methods [`Self::orthographic_lh()`] for +/// left-handed coordinate systems and [`Self::orthographic_rh()`] for right-handed +/// systems. The resulting matrix is also an affine transformation. +/// +/// The [`Self::transform_point3()`] and [`Self::transform_vector3()`] convenience methods +/// are provided for performing affine transformations on 3D vectors and points. These +/// multiply 3D inputs as 4D vectors with an implicit `w` value of `1` for points and `0` +/// for vectors respectively. These methods assume that `Self` contains a valid affine +/// transform. +/// +/// Perspective projections can be created using methods such as +/// [`Self::perspective_lh()`], [`Self::perspective_infinite_lh()`] and +/// [`Self::perspective_infinite_reverse_lh()`] for left-handed co-ordinate systems and +/// [`Self::perspective_rh()`], [`Self::perspective_infinite_rh()`] and +/// [`Self::perspective_infinite_reverse_rh()`] for right-handed co-ordinate systems. +/// +/// The resulting perspective project can be use to transform 3D vectors as points with +/// perspective correction using the [`Self::project_point3()`] convenience method. +#[derive(Clone, Copy)] +pub struct Mat4 { + pub x_axis: Vec4, + pub y_axis: Vec4, + pub z_axis: Vec4, + pub w_axis: Vec4, +} + +impl Mat4 { + /// A 4x4 matrix with all elements set to `0.0`. + pub const ZERO: Self = Self::from_cols(Vec4::ZERO, Vec4::ZERO, Vec4::ZERO, Vec4::ZERO); + + /// A 4x4 identity matrix, where all diagonal elements are `1`, and all off-diagonal elements are `0`. + pub const IDENTITY: Self = Self::from_cols(Vec4::X, Vec4::Y, Vec4::Z, Vec4::W); + + /// All NAN:s. + pub const NAN: Self = Self::from_cols(Vec4::NAN, Vec4::NAN, Vec4::NAN, Vec4::NAN); + + #[allow(clippy::too_many_arguments)] + #[inline(always)] + const fn new( + m00: f32, + m01: f32, + m02: f32, + m03: f32, + m10: f32, + m11: f32, + m12: f32, + m13: f32, + m20: f32, + m21: f32, + m22: f32, + m23: f32, + m30: f32, + m31: f32, + m32: f32, + m33: f32, + ) -> Self { + Self { + x_axis: Vec4::new(m00, m01, m02, m03), + y_axis: Vec4::new(m10, m11, m12, m13), + z_axis: Vec4::new(m20, m21, m22, m23), + w_axis: Vec4::new(m30, m31, m32, m33), + } + } + + /// Creates a 4x4 matrix from two column vectors. + #[inline(always)] + pub const fn from_cols(x_axis: Vec4, y_axis: Vec4, z_axis: Vec4, w_axis: Vec4) -> Self { + Self { + x_axis, + y_axis, + z_axis, + w_axis, + } + } + + /// Creates a 4x4 matrix from a `[f32; 16]` array stored in column major order. + /// If your data is stored in row major you will need to `transpose` the returned + /// matrix. + #[inline] + pub const fn from_cols_array(m: &[f32; 16]) -> Self { + Self::new( + m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], m[9], m[10], m[11], m[12], m[13], + m[14], m[15], + ) + } + + /// Creates a `[f32; 16]` array storing data in column major order. + /// If you require data in row major order `transpose` the matrix first. + #[inline] + pub fn to_cols_array(&self) -> [f32; 16] { + [ + self.x_axis.x, + self.x_axis.y, + self.x_axis.z, + self.x_axis.w, + self.y_axis.x, + self.y_axis.y, + self.y_axis.z, + self.y_axis.w, + self.z_axis.x, + self.z_axis.y, + self.z_axis.z, + self.z_axis.w, + self.w_axis.x, + self.w_axis.y, + self.w_axis.z, + self.w_axis.w, + ] + } + + /// Creates a 4x4 matrix from a `[[f32; 4]; 4]` 4D array stored in column major order. + /// If your data is in row major order you will need to `transpose` the returned + /// matrix. + #[inline] + pub const fn from_cols_array_2d(m: &[[f32; 4]; 4]) -> Self { + Self::from_cols( + Vec4::from_array(m[0]), + Vec4::from_array(m[1]), + Vec4::from_array(m[2]), + Vec4::from_array(m[3]), + ) + } + + /// Creates a `[[f32; 4]; 4]` 4D array storing data in column major order. + /// If you require data in row major order `transpose` the matrix first. + #[inline] + pub fn to_cols_array_2d(&self) -> [[f32; 4]; 4] { + [ + self.x_axis.to_array(), + self.y_axis.to_array(), + self.z_axis.to_array(), + self.w_axis.to_array(), + ] + } + + /// Creates a 4x4 matrix with its diagonal set to `diagonal` and all other entries set to 0. + #[doc(alias = "scale")] + #[inline] + pub fn from_diagonal(diagonal: Vec4) -> Self { + Self::new( + diagonal.x, 0.0, 0.0, 0.0, 0.0, diagonal.y, 0.0, 0.0, 0.0, 0.0, diagonal.z, 0.0, 0.0, + 0.0, 0.0, diagonal.w, + ) + } + + fn quat_to_axes(rotation: Quat) -> (Vec4, Vec4, Vec4) { + glam_assert!(rotation.is_normalized()); + + let (x, y, z, w) = rotation.into(); + let x2 = x + x; + let y2 = y + y; + let z2 = z + z; + let xx = x * x2; + let xy = x * y2; + let xz = x * z2; + let yy = y * y2; + let yz = y * z2; + let zz = z * z2; + let wx = w * x2; + let wy = w * y2; + let wz = w * z2; + + let x_axis = Vec4::new(1.0 - (yy + zz), xy + wz, xz - wy, 0.0); + let y_axis = Vec4::new(xy - wz, 1.0 - (xx + zz), yz + wx, 0.0); + let z_axis = Vec4::new(xz + wy, yz - wx, 1.0 - (xx + yy), 0.0); + (x_axis, y_axis, z_axis) + } + + /// Creates an affine transformation matrix from the given 3D `scale`, `rotation` and + /// `translation`. + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + /// + /// # Panics + /// + /// Will panic if `rotation` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn from_scale_rotation_translation(scale: Vec3, rotation: Quat, translation: Vec3) -> Self { + let (x_axis, y_axis, z_axis) = Self::quat_to_axes(rotation); + Self::from_cols( + x_axis.mul(scale.x), + y_axis.mul(scale.y), + z_axis.mul(scale.z), + Vec4::from((translation, 1.0)), + ) + } + + /// Creates an affine transformation matrix from the given 3D `translation`. + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + /// + /// # Panics + /// + /// Will panic if `rotation` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn from_rotation_translation(rotation: Quat, translation: Vec3) -> Self { + let (x_axis, y_axis, z_axis) = Self::quat_to_axes(rotation); + Self::from_cols(x_axis, y_axis, z_axis, Vec4::from((translation, 1.0))) + } + + /// Extracts `scale`, `rotation` and `translation` from `self`. The input matrix is + /// expected to be a 3D affine transformation matrix otherwise the output will be invalid. + /// + /// # Panics + /// + /// Will panic if the determinant of `self` is zero or if the resulting scale vector + /// contains any zero elements when `glam_assert` is enabled. + #[inline] + pub fn to_scale_rotation_translation(&self) -> (Vec3, Quat, Vec3) { + let det = self.determinant(); + glam_assert!(det != 0.0); + + let scale = Vec3::new( + self.x_axis.length() * det.signum(), + self.y_axis.length(), + self.z_axis.length(), + ); + + glam_assert!(scale.cmpne(Vec3::ZERO).all()); + + let inv_scale = scale.recip(); + + let rotation = Quat::from_rotation_axes( + self.x_axis.mul(inv_scale.x).xyz(), + self.y_axis.mul(inv_scale.y).xyz(), + self.z_axis.mul(inv_scale.z).xyz(), + ); + + let translation = self.w_axis.xyz(); + + (scale, rotation, translation) + } + + /// Creates an affine transformation matrix from the given `rotation` quaternion. + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + /// + /// # Panics + /// + /// Will panic if `rotation` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn from_quat(rotation: Quat) -> Self { + let (x_axis, y_axis, z_axis) = Self::quat_to_axes(rotation); + Self::from_cols(x_axis, y_axis, z_axis, Vec4::W) + } + + /// Creates an affine transformation matrix from the given 3x3 linear transformation + /// matrix. + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + #[inline] + pub fn from_mat3(m: Mat3) -> Self { + Self::from_cols( + Vec4::from((m.x_axis, 0.0)), + Vec4::from((m.y_axis, 0.0)), + Vec4::from((m.z_axis, 0.0)), + Vec4::W, + ) + } + + /// Creates an affine transformation matrix from the given 3D `translation`. + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + #[inline] + pub fn from_translation(translation: Vec3) -> Self { + Self::from_cols( + Vec4::X, + Vec4::Y, + Vec4::Z, + Vec4::new(translation.x, translation.y, translation.z, 1.0), + ) + } + + /// Creates an affine transformation matrix containing a 3D rotation around a normalized + /// rotation `axis` of `angle` (in radians). + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + /// + /// # Panics + /// + /// Will panic if `axis` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn from_axis_angle(axis: Vec3, angle: f32) -> Self { + glam_assert!(axis.is_normalized()); + + let (sin, cos) = angle.sin_cos(); + let axis_sin = axis.mul(sin); + let axis_sq = axis.mul(axis); + let omc = 1.0 - cos; + let xyomc = axis.x * axis.y * omc; + let xzomc = axis.x * axis.z * omc; + let yzomc = axis.y * axis.z * omc; + Self::from_cols( + Vec4::new( + axis_sq.x * omc + cos, + xyomc + axis_sin.z, + xzomc - axis_sin.y, + 0.0, + ), + Vec4::new( + xyomc - axis_sin.z, + axis_sq.y * omc + cos, + yzomc + axis_sin.x, + 0.0, + ), + Vec4::new( + xzomc + axis_sin.y, + yzomc - axis_sin.x, + axis_sq.z * omc + cos, + 0.0, + ), + Vec4::W, + ) + } + + #[inline] + /// Creates a affine transformation matrix containing a rotation from the given euler + /// rotation sequence and angles (in radians). + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + pub fn from_euler(order: EulerRot, a: f32, b: f32, c: f32) -> Self { + let quat = Quat::from_euler(order, a, b, c); + Self::from_quat(quat) + } + + /// Creates an affine transformation matrix containing a 3D rotation around the x axis of + /// `angle` (in radians). + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + #[inline] + pub fn from_rotation_x(angle: f32) -> Self { + let (sina, cosa) = angle.sin_cos(); + Self::from_cols( + Vec4::X, + Vec4::new(0.0, cosa, sina, 0.0), + Vec4::new(0.0, -sina, cosa, 0.0), + Vec4::W, + ) + } + + /// Creates an affine transformation matrix containing a 3D rotation around the y axis of + /// `angle` (in radians). + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + #[inline] + pub fn from_rotation_y(angle: f32) -> Self { + let (sina, cosa) = angle.sin_cos(); + Self::from_cols( + Vec4::new(cosa, 0.0, -sina, 0.0), + Vec4::Y, + Vec4::new(sina, 0.0, cosa, 0.0), + Vec4::W, + ) + } + + /// Creates an affine transformation matrix containing a 3D rotation around the z axis of + /// `angle` (in radians). + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + #[inline] + pub fn from_rotation_z(angle: f32) -> Self { + let (sina, cosa) = angle.sin_cos(); + Self::from_cols( + Vec4::new(cosa, sina, 0.0, 0.0), + Vec4::new(-sina, cosa, 0.0, 0.0), + Vec4::Z, + Vec4::W, + ) + } + + /// Creates an affine transformation matrix containing the given 3D non-uniform `scale`. + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + /// + /// # Panics + /// + /// Will panic if all elements of `scale` are zero when `glam_assert` is enabled. + #[inline] + pub fn from_scale(scale: Vec3) -> Self { + // Do not panic as long as any component is non-zero + glam_assert!(scale.cmpne(Vec3::ZERO).any()); + + Self::from_cols( + Vec4::new(scale.x, 0.0, 0.0, 0.0), + Vec4::new(0.0, scale.y, 0.0, 0.0), + Vec4::new(0.0, 0.0, scale.z, 0.0), + Vec4::W, + ) + } + + /// Creates a 4x4 matrix from the first 16 values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 16 elements long. + #[inline] + pub const fn from_cols_slice(slice: &[f32]) -> Self { + Self::new( + slice[0], slice[1], slice[2], slice[3], slice[4], slice[5], slice[6], slice[7], + slice[8], slice[9], slice[10], slice[11], slice[12], slice[13], slice[14], slice[15], + ) + } + + /// Writes the columns of `self` to the first 16 elements in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 16 elements long. + #[inline] + pub fn write_cols_to_slice(self, slice: &mut [f32]) { + slice[0] = self.x_axis.x; + slice[1] = self.x_axis.y; + slice[2] = self.x_axis.z; + slice[3] = self.x_axis.w; + slice[4] = self.y_axis.x; + slice[5] = self.y_axis.y; + slice[6] = self.y_axis.z; + slice[7] = self.y_axis.w; + slice[8] = self.z_axis.x; + slice[9] = self.z_axis.y; + slice[10] = self.z_axis.z; + slice[11] = self.z_axis.w; + slice[12] = self.w_axis.x; + slice[13] = self.w_axis.y; + slice[14] = self.w_axis.z; + slice[15] = self.w_axis.w; + } + + /// Returns the matrix column for the given `index`. + /// + /// # Panics + /// + /// Panics if `index` is greater than 3. + #[inline] + pub fn col(&self, index: usize) -> Vec4 { + match index { + 0 => self.x_axis, + 1 => self.y_axis, + 2 => self.z_axis, + 3 => self.w_axis, + _ => panic!("index out of bounds"), + } + } + + /// Returns a mutable reference to the matrix column for the given `index`. + /// + /// # Panics + /// + /// Panics if `index` is greater than 3. + #[inline] + pub fn col_mut(&mut self, index: usize) -> &mut Vec4 { + match index { + 0 => &mut self.x_axis, + 1 => &mut self.y_axis, + 2 => &mut self.z_axis, + 3 => &mut self.w_axis, + _ => panic!("index out of bounds"), + } + } + + /// Returns the matrix row for the given `index`. + /// + /// # Panics + /// + /// Panics if `index` is greater than 3. + #[inline] + pub fn row(&self, index: usize) -> Vec4 { + match index { + 0 => Vec4::new(self.x_axis.x, self.y_axis.x, self.z_axis.x, self.w_axis.x), + 1 => Vec4::new(self.x_axis.y, self.y_axis.y, self.z_axis.y, self.w_axis.y), + 2 => Vec4::new(self.x_axis.z, self.y_axis.z, self.z_axis.z, self.w_axis.z), + 3 => Vec4::new(self.x_axis.w, self.y_axis.w, self.z_axis.w, self.w_axis.w), + _ => panic!("index out of bounds"), + } + } + + /// Returns `true` if, and only if, all elements are finite. + /// If any element is either `NaN`, positive or negative infinity, this will return `false`. + #[inline] + pub fn is_finite(&self) -> bool { + self.x_axis.is_finite() + && self.y_axis.is_finite() + && self.z_axis.is_finite() + && self.w_axis.is_finite() + } + + /// Returns `true` if any elements are `NaN`. + #[inline] + pub fn is_nan(&self) -> bool { + self.x_axis.is_nan() || self.y_axis.is_nan() || self.z_axis.is_nan() || self.w_axis.is_nan() + } + + /// Returns the transpose of `self`. + #[must_use] + #[inline] + pub fn transpose(&self) -> Self { + // Based on https://github.com/microsoft/DirectXMath `XMMatrixTranspose` + let tmp0 = i32x4_shuffle::<0, 1, 4, 5>(self.x_axis.0, self.y_axis.0); + let tmp1 = i32x4_shuffle::<2, 3, 6, 7>(self.x_axis.0, self.y_axis.0); + let tmp2 = i32x4_shuffle::<0, 1, 4, 5>(self.z_axis.0, self.w_axis.0); + let tmp3 = i32x4_shuffle::<2, 3, 6, 7>(self.z_axis.0, self.w_axis.0); + + Self { + x_axis: Vec4(i32x4_shuffle::<0, 2, 4, 6>(tmp0, tmp2)), + y_axis: Vec4(i32x4_shuffle::<1, 3, 5, 7>(tmp0, tmp2)), + z_axis: Vec4(i32x4_shuffle::<0, 2, 4, 6>(tmp1, tmp3)), + w_axis: Vec4(i32x4_shuffle::<1, 3, 5, 7>(tmp1, tmp3)), + } + } + + /// Returns the determinant of `self`. + pub fn determinant(&self) -> f32 { + // Based on https://github.com/g-truc/glm `glm_mat4_determinant` + let swp2a = i32x4_shuffle::<2, 1, 1, 0>(self.z_axis.0, self.z_axis.0); + let swp3a = i32x4_shuffle::<3, 3, 2, 3>(self.w_axis.0, self.w_axis.0); + let swp2b = i32x4_shuffle::<3, 3, 2, 3>(self.z_axis.0, self.z_axis.0); + let swp3b = i32x4_shuffle::<2, 1, 1, 0>(self.w_axis.0, self.w_axis.0); + let swp2c = i32x4_shuffle::<2, 1, 0, 0>(self.z_axis.0, self.z_axis.0); + let swp3c = i32x4_shuffle::<0, 0, 2, 1>(self.w_axis.0, self.w_axis.0); + + let mula = f32x4_mul(swp2a, swp3a); + let mulb = f32x4_mul(swp2b, swp3b); + let mulc = f32x4_mul(swp2c, swp3c); + let sube = f32x4_sub(mula, mulb); + let subf = f32x4_sub(i32x4_shuffle::<6, 7, 2, 3>(mulc, mulc), mulc); + + let subfaca = i32x4_shuffle::<0, 0, 1, 2>(sube, sube); + let swpfaca = i32x4_shuffle::<1, 0, 0, 0>(self.y_axis.0, self.y_axis.0); + let mulfaca = f32x4_mul(swpfaca, subfaca); + + let subtmpb = i32x4_shuffle::<1, 3, 4, 4>(sube, subf); + let subfacb = i32x4_shuffle::<0, 1, 1, 3>(subtmpb, subtmpb); + let swpfacb = i32x4_shuffle::<2, 2, 1, 1>(self.y_axis.0, self.y_axis.0); + let mulfacb = f32x4_mul(swpfacb, subfacb); + + let subres = f32x4_sub(mulfaca, mulfacb); + let subtmpc = i32x4_shuffle::<2, 2, 4, 5>(sube, subf); + let subfacc = i32x4_shuffle::<0, 2, 3, 3>(subtmpc, subtmpc); + let swpfacc = i32x4_shuffle::<3, 3, 3, 2>(self.y_axis.0, self.y_axis.0); + let mulfacc = f32x4_mul(swpfacc, subfacc); + + let addres = f32x4_add(subres, mulfacc); + let detcof = f32x4_mul(addres, f32x4(1.0, -1.0, 1.0, -1.0)); + + crate::wasm32::dot4(self.x_axis.0, detcof) + } + + /// Returns the inverse of `self`. + /// + /// If the matrix is not invertible the returned matrix will be invalid. + /// + /// # Panics + /// + /// Will panic if the determinant of `self` is zero when `glam_assert` is enabled. + #[must_use] + pub fn inverse(&self) -> Self { + // Based on https://github.com/g-truc/glm `glm_mat4_inverse` + let fac0 = { + let swp0a = i32x4_shuffle::<3, 3, 7, 7>(self.w_axis.0, self.z_axis.0); + let swp0b = i32x4_shuffle::<2, 2, 6, 6>(self.w_axis.0, self.z_axis.0); + + let swp00 = i32x4_shuffle::<2, 2, 6, 6>(self.z_axis.0, self.y_axis.0); + let swp01 = i32x4_shuffle::<0, 0, 4, 6>(swp0a, swp0a); + let swp02 = i32x4_shuffle::<0, 0, 4, 6>(swp0b, swp0b); + let swp03 = i32x4_shuffle::<3, 3, 7, 7>(self.z_axis.0, self.y_axis.0); + + let mul00 = f32x4_mul(swp00, swp01); + let mul01 = f32x4_mul(swp02, swp03); + f32x4_sub(mul00, mul01) + }; + let fac1 = { + let swp0a = i32x4_shuffle::<3, 3, 7, 7>(self.w_axis.0, self.z_axis.0); + let swp0b = i32x4_shuffle::<1, 1, 5, 5>(self.w_axis.0, self.z_axis.0); + + let swp00 = i32x4_shuffle::<1, 1, 5, 5>(self.z_axis.0, self.y_axis.0); + let swp01 = i32x4_shuffle::<0, 0, 4, 6>(swp0a, swp0a); + let swp02 = i32x4_shuffle::<0, 0, 4, 6>(swp0b, swp0b); + let swp03 = i32x4_shuffle::<3, 3, 7, 7>(self.z_axis.0, self.y_axis.0); + + let mul00 = f32x4_mul(swp00, swp01); + let mul01 = f32x4_mul(swp02, swp03); + f32x4_sub(mul00, mul01) + }; + let fac2 = { + let swp0a = i32x4_shuffle::<2, 2, 6, 6>(self.w_axis.0, self.z_axis.0); + let swp0b = i32x4_shuffle::<1, 1, 5, 5>(self.w_axis.0, self.z_axis.0); + + let swp00 = i32x4_shuffle::<1, 1, 5, 5>(self.z_axis.0, self.y_axis.0); + let swp01 = i32x4_shuffle::<0, 0, 4, 6>(swp0a, swp0a); + let swp02 = i32x4_shuffle::<0, 0, 4, 6>(swp0b, swp0b); + let swp03 = i32x4_shuffle::<2, 2, 6, 6>(self.z_axis.0, self.y_axis.0); + + let mul00 = f32x4_mul(swp00, swp01); + let mul01 = f32x4_mul(swp02, swp03); + f32x4_sub(mul00, mul01) + }; + let fac3 = { + let swp0a = i32x4_shuffle::<3, 3, 7, 7>(self.w_axis.0, self.z_axis.0); + let swp0b = i32x4_shuffle::<0, 0, 4, 4>(self.w_axis.0, self.z_axis.0); + + let swp00 = i32x4_shuffle::<0, 0, 4, 4>(self.z_axis.0, self.y_axis.0); + let swp01 = i32x4_shuffle::<0, 0, 4, 6>(swp0a, swp0a); + let swp02 = i32x4_shuffle::<0, 0, 4, 6>(swp0b, swp0b); + let swp03 = i32x4_shuffle::<3, 3, 7, 7>(self.z_axis.0, self.y_axis.0); + + let mul00 = f32x4_mul(swp00, swp01); + let mul01 = f32x4_mul(swp02, swp03); + f32x4_sub(mul00, mul01) + }; + let fac4 = { + let swp0a = i32x4_shuffle::<2, 2, 6, 6>(self.w_axis.0, self.z_axis.0); + let swp0b = i32x4_shuffle::<0, 0, 4, 4>(self.w_axis.0, self.z_axis.0); + + let swp00 = i32x4_shuffle::<0, 0, 4, 4>(self.z_axis.0, self.y_axis.0); + let swp01 = i32x4_shuffle::<0, 0, 4, 6>(swp0a, swp0a); + let swp02 = i32x4_shuffle::<0, 0, 4, 6>(swp0b, swp0b); + let swp03 = i32x4_shuffle::<2, 2, 6, 6>(self.z_axis.0, self.y_axis.0); + + let mul00 = f32x4_mul(swp00, swp01); + let mul01 = f32x4_mul(swp02, swp03); + f32x4_sub(mul00, mul01) + }; + let fac5 = { + let swp0a = i32x4_shuffle::<1, 1, 5, 5>(self.w_axis.0, self.z_axis.0); + let swp0b = i32x4_shuffle::<0, 0, 4, 4>(self.w_axis.0, self.z_axis.0); + + let swp00 = i32x4_shuffle::<0, 0, 4, 4>(self.z_axis.0, self.y_axis.0); + let swp01 = i32x4_shuffle::<0, 0, 4, 6>(swp0a, swp0a); + let swp02 = i32x4_shuffle::<0, 0, 4, 6>(swp0b, swp0b); + let swp03 = i32x4_shuffle::<1, 1, 5, 5>(self.z_axis.0, self.y_axis.0); + + let mul00 = f32x4_mul(swp00, swp01); + let mul01 = f32x4_mul(swp02, swp03); + f32x4_sub(mul00, mul01) + }; + let sign_a = f32x4(-1.0, 1.0, -1.0, 1.0); + let sign_b = f32x4(1.0, -1.0, 1.0, -1.0); + + let temp0 = i32x4_shuffle::<0, 0, 4, 4>(self.y_axis.0, self.x_axis.0); + let vec0 = i32x4_shuffle::<0, 2, 6, 6>(temp0, temp0); + + let temp1 = i32x4_shuffle::<1, 1, 5, 5>(self.y_axis.0, self.x_axis.0); + let vec1 = i32x4_shuffle::<0, 2, 6, 6>(temp1, temp1); + + let temp2 = i32x4_shuffle::<2, 2, 6, 6>(self.y_axis.0, self.x_axis.0); + let vec2 = i32x4_shuffle::<0, 2, 6, 6>(temp2, temp2); + + let temp3 = i32x4_shuffle::<3, 3, 7, 7>(self.y_axis.0, self.x_axis.0); + let vec3 = i32x4_shuffle::<0, 2, 6, 6>(temp3, temp3); + + let mul00 = f32x4_mul(vec1, fac0); + let mul01 = f32x4_mul(vec2, fac1); + let mul02 = f32x4_mul(vec3, fac2); + let sub00 = f32x4_sub(mul00, mul01); + let add00 = f32x4_add(sub00, mul02); + let inv0 = f32x4_mul(sign_b, add00); + + let mul03 = f32x4_mul(vec0, fac0); + let mul04 = f32x4_mul(vec2, fac3); + let mul05 = f32x4_mul(vec3, fac4); + let sub01 = f32x4_sub(mul03, mul04); + let add01 = f32x4_add(sub01, mul05); + let inv1 = f32x4_mul(sign_a, add01); + + let mul06 = f32x4_mul(vec0, fac1); + let mul07 = f32x4_mul(vec1, fac3); + let mul08 = f32x4_mul(vec3, fac5); + let sub02 = f32x4_sub(mul06, mul07); + let add02 = f32x4_add(sub02, mul08); + let inv2 = f32x4_mul(sign_b, add02); + + let mul09 = f32x4_mul(vec0, fac2); + let mul10 = f32x4_mul(vec1, fac4); + let mul11 = f32x4_mul(vec2, fac5); + let sub03 = f32x4_sub(mul09, mul10); + let add03 = f32x4_add(sub03, mul11); + let inv3 = f32x4_mul(sign_a, add03); + + let row0 = i32x4_shuffle::<0, 0, 4, 4>(inv0, inv1); + let row1 = i32x4_shuffle::<0, 0, 4, 4>(inv2, inv3); + let row2 = i32x4_shuffle::<0, 2, 4, 6>(row0, row1); + + let dot0 = crate::wasm32::dot4(self.x_axis.0, row2); + glam_assert!(dot0 != 0.0); + + let rcp0 = f32x4_splat(dot0.recip()); + + Self { + x_axis: Vec4(f32x4_mul(inv0, rcp0)), + y_axis: Vec4(f32x4_mul(inv1, rcp0)), + z_axis: Vec4(f32x4_mul(inv2, rcp0)), + w_axis: Vec4(f32x4_mul(inv3, rcp0)), + } + } + + #[inline] + fn look_to_lh(eye: Vec3, dir: Vec3, up: Vec3) -> Self { + let f = dir.normalize(); + let s = up.cross(f).normalize(); + let u = f.cross(s); + Self::from_cols( + Vec4::new(s.x, u.x, f.x, 0.0), + Vec4::new(s.y, u.y, f.y, 0.0), + Vec4::new(s.z, u.z, f.z, 0.0), + Vec4::new(-s.dot(eye), -u.dot(eye), -f.dot(eye), 1.0), + ) + } + + /// Creates a left-handed view matrix using a camera position, an up direction, and a focal + /// point. + /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=forward`. + /// + /// # Panics + /// + /// Will panic if `up` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn look_at_lh(eye: Vec3, center: Vec3, up: Vec3) -> Self { + glam_assert!(up.is_normalized()); + Self::look_to_lh(eye, center.sub(eye), up) + } + + /// Creates a right-handed view matrix using a camera position, an up direction, and a focal + /// point. + /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=back`. + /// + /// # Panics + /// + /// Will panic if `up` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn look_at_rh(eye: Vec3, center: Vec3, up: Vec3) -> Self { + glam_assert!(up.is_normalized()); + Self::look_to_lh(eye, eye.sub(center), up) + } + + /// Creates a right-handed perspective projection matrix with [-1,1] depth range. + /// This is the same as the OpenGL `gluPerspective` function. + /// See + #[inline] + pub fn perspective_rh_gl( + fov_y_radians: f32, + aspect_ratio: f32, + z_near: f32, + z_far: f32, + ) -> Self { + let inv_length = 1.0 / (z_near - z_far); + let f = 1.0 / (0.5 * fov_y_radians).tan(); + let a = f / aspect_ratio; + let b = (z_near + z_far) * inv_length; + let c = (2.0 * z_near * z_far) * inv_length; + Self::from_cols( + Vec4::new(a, 0.0, 0.0, 0.0), + Vec4::new(0.0, f, 0.0, 0.0), + Vec4::new(0.0, 0.0, b, -1.0), + Vec4::new(0.0, 0.0, c, 0.0), + ) + } + + /// Creates a left-handed perspective projection matrix with `[0,1]` depth range. + /// + /// # Panics + /// + /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is + /// enabled. + #[inline] + pub fn perspective_lh(fov_y_radians: f32, aspect_ratio: f32, z_near: f32, z_far: f32) -> Self { + glam_assert!(z_near > 0.0 && z_far > 0.0); + let (sin_fov, cos_fov) = (0.5 * fov_y_radians).sin_cos(); + let h = cos_fov / sin_fov; + let w = h / aspect_ratio; + let r = z_far / (z_far - z_near); + Self::from_cols( + Vec4::new(w, 0.0, 0.0, 0.0), + Vec4::new(0.0, h, 0.0, 0.0), + Vec4::new(0.0, 0.0, r, 1.0), + Vec4::new(0.0, 0.0, -r * z_near, 0.0), + ) + } + + /// Creates a right-handed perspective projection matrix with `[0,1]` depth range. + /// + /// # Panics + /// + /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is + /// enabled. + #[inline] + pub fn perspective_rh(fov_y_radians: f32, aspect_ratio: f32, z_near: f32, z_far: f32) -> Self { + glam_assert!(z_near > 0.0 && z_far > 0.0); + let (sin_fov, cos_fov) = (0.5 * fov_y_radians).sin_cos(); + let h = cos_fov / sin_fov; + let w = h / aspect_ratio; + let r = z_far / (z_near - z_far); + Self::from_cols( + Vec4::new(w, 0.0, 0.0, 0.0), + Vec4::new(0.0, h, 0.0, 0.0), + Vec4::new(0.0, 0.0, r, -1.0), + Vec4::new(0.0, 0.0, r * z_near, 0.0), + ) + } + + /// Creates an infinite left-handed perspective projection matrix with `[0,1]` depth range. + /// + /// # Panics + /// + /// Will panic if `z_near` is less than or equal to zero when `glam_assert` is enabled. + #[inline] + pub fn perspective_infinite_lh(fov_y_radians: f32, aspect_ratio: f32, z_near: f32) -> Self { + glam_assert!(z_near > 0.0); + let (sin_fov, cos_fov) = (0.5 * fov_y_radians).sin_cos(); + let h = cos_fov / sin_fov; + let w = h / aspect_ratio; + Self::from_cols( + Vec4::new(w, 0.0, 0.0, 0.0), + Vec4::new(0.0, h, 0.0, 0.0), + Vec4::new(0.0, 0.0, 1.0, 1.0), + Vec4::new(0.0, 0.0, -z_near, 0.0), + ) + } + + /// Creates an infinite left-handed perspective projection matrix with `[0,1]` depth range. + /// + /// # Panics + /// + /// Will panic if `z_near` is less than or equal to zero when `glam_assert` is enabled. + #[inline] + pub fn perspective_infinite_reverse_lh( + fov_y_radians: f32, + aspect_ratio: f32, + z_near: f32, + ) -> Self { + glam_assert!(z_near > 0.0); + let (sin_fov, cos_fov) = (0.5 * fov_y_radians).sin_cos(); + let h = cos_fov / sin_fov; + let w = h / aspect_ratio; + Self::from_cols( + Vec4::new(w, 0.0, 0.0, 0.0), + Vec4::new(0.0, h, 0.0, 0.0), + Vec4::new(0.0, 0.0, 0.0, 1.0), + Vec4::new(0.0, 0.0, z_near, 0.0), + ) + } + + /// Creates an infinite right-handed perspective projection matrix with + /// `[0,1]` depth range. + #[inline] + pub fn perspective_infinite_rh(fov_y_radians: f32, aspect_ratio: f32, z_near: f32) -> Self { + glam_assert!(z_near > 0.0); + let f = 1.0 / (0.5 * fov_y_radians).tan(); + Self::from_cols( + Vec4::new(f / aspect_ratio, 0.0, 0.0, 0.0), + Vec4::new(0.0, f, 0.0, 0.0), + Vec4::new(0.0, 0.0, -1.0, -1.0), + Vec4::new(0.0, 0.0, -z_near, 0.0), + ) + } + + /// Creates an infinite reverse right-handed perspective projection matrix + /// with `[0,1]` depth range. + #[inline] + pub fn perspective_infinite_reverse_rh( + fov_y_radians: f32, + aspect_ratio: f32, + z_near: f32, + ) -> Self { + glam_assert!(z_near > 0.0); + let f = 1.0 / (0.5 * fov_y_radians).tan(); + Self::from_cols( + Vec4::new(f / aspect_ratio, 0.0, 0.0, 0.0), + Vec4::new(0.0, f, 0.0, 0.0), + Vec4::new(0.0, 0.0, 0.0, -1.0), + Vec4::new(0.0, 0.0, z_near, 0.0), + ) + } + + /// Creates a right-handed orthographic projection matrix with `[-1,1]` depth + /// range. This is the same as the OpenGL `glOrtho` function in OpenGL. + /// See + /// + #[inline] + pub fn orthographic_rh_gl( + left: f32, + right: f32, + bottom: f32, + top: f32, + near: f32, + far: f32, + ) -> Self { + let a = 2.0 / (right - left); + let b = 2.0 / (top - bottom); + let c = -2.0 / (far - near); + let tx = -(right + left) / (right - left); + let ty = -(top + bottom) / (top - bottom); + let tz = -(far + near) / (far - near); + + Self::from_cols( + Vec4::new(a, 0.0, 0.0, 0.0), + Vec4::new(0.0, b, 0.0, 0.0), + Vec4::new(0.0, 0.0, c, 0.0), + Vec4::new(tx, ty, tz, 1.0), + ) + } + + /// Creates a left-handed orthographic projection matrix with `[0,1]` depth range. + #[inline] + pub fn orthographic_lh( + left: f32, + right: f32, + bottom: f32, + top: f32, + near: f32, + far: f32, + ) -> Self { + let rcp_width = 1.0 / (right - left); + let rcp_height = 1.0 / (top - bottom); + let r = 1.0 / (far - near); + Self::from_cols( + Vec4::new(rcp_width + rcp_width, 0.0, 0.0, 0.0), + Vec4::new(0.0, rcp_height + rcp_height, 0.0, 0.0), + Vec4::new(0.0, 0.0, r, 0.0), + Vec4::new( + -(left + right) * rcp_width, + -(top + bottom) * rcp_height, + -r * near, + 1.0, + ), + ) + } + + /// Creates a right-handed orthographic projection matrix with `[0,1]` depth range. + #[inline] + pub fn orthographic_rh( + left: f32, + right: f32, + bottom: f32, + top: f32, + near: f32, + far: f32, + ) -> Self { + let rcp_width = 1.0 / (right - left); + let rcp_height = 1.0 / (top - bottom); + let r = 1.0 / (near - far); + Self::from_cols( + Vec4::new(rcp_width + rcp_width, 0.0, 0.0, 0.0), + Vec4::new(0.0, rcp_height + rcp_height, 0.0, 0.0), + Vec4::new(0.0, 0.0, r, 0.0), + Vec4::new( + -(left + right) * rcp_width, + -(top + bottom) * rcp_height, + r * near, + 1.0, + ), + ) + } + + /// Transforms the given 3D vector as a point, applying perspective correction. + /// + /// This is the equivalent of multiplying the 3D vector as a 4D vector where `w` is `1.0`. + /// The perspective divide is performed meaning the resulting 3D vector is divided by `w`. + /// + /// This method assumes that `self` contains a projective transform. + #[inline] + pub fn project_point3(&self, rhs: Vec3) -> Vec3 { + let mut res = self.x_axis.mul(rhs.x); + res = self.y_axis.mul(rhs.y).add(res); + res = self.z_axis.mul(rhs.z).add(res); + res = self.w_axis.add(res); + res = res.mul(res.wwww().recip()); + res.xyz() + } + + /// Transforms the given 3D vector as a point. + /// + /// This is the equivalent of multiplying the 3D vector as a 4D vector where `w` is + /// `1.0`. + /// + /// This method assumes that `self` contains a valid affine transform. It does not perform + /// a persective divide, if `self` contains a perspective transform, or if you are unsure, + /// the [`Self::project_point3()`] method should be used instead. + /// + /// # Panics + /// + /// Will panic if the 3rd row of `self` is not `(0, 0, 0, 1)` when `glam_assert` is enabled. + #[inline] + pub fn transform_point3(&self, rhs: Vec3) -> Vec3 { + glam_assert!(self.row(3) == Vec4::W); + let mut res = self.x_axis.mul(rhs.x); + res = self.y_axis.mul(rhs.y).add(res); + res = self.z_axis.mul(rhs.z).add(res); + res = self.w_axis.add(res); + res.xyz() + } + + /// Transforms the give 3D vector as a direction. + /// + /// This is the equivalent of multiplying the 3D vector as a 4D vector where `w` is + /// `0.0`. + /// + /// This method assumes that `self` contains a valid affine transform. + /// + /// # Panics + /// + /// Will panic if the 3rd row of `self` is not `(0, 0, 0, 1)` when `glam_assert` is enabled. + #[inline] + pub fn transform_vector3(&self, rhs: Vec3) -> Vec3 { + glam_assert!(self.row(3) == Vec4::W); + let mut res = self.x_axis.mul(rhs.x); + res = self.y_axis.mul(rhs.y).add(res); + res = self.z_axis.mul(rhs.z).add(res); + res.xyz() + } + + /// Transforms the given `Vec3A` as 3D point. + /// + /// This is the equivalent of multiplying the `Vec3A` as a 4D vector where `w` is `1.0`. + #[inline] + pub fn transform_point3a(&self, rhs: Vec3A) -> Vec3A { + let mut res = self.x_axis.mul(rhs.xxxx()); + res = self.y_axis.mul(rhs.yyyy()).add(res); + res = self.z_axis.mul(rhs.zzzz()).add(res); + res = self.w_axis.add(res); + res.into() + } + + /// Transforms the give `Vec3A` as 3D vector. + /// + /// This is the equivalent of multiplying the `Vec3A` as a 4D vector where `w` is `0.0`. + #[inline] + pub fn transform_vector3a(&self, rhs: Vec3A) -> Vec3A { + let mut res = self.x_axis.mul(rhs.xxxx()); + res = self.y_axis.mul(rhs.yyyy()).add(res); + res = self.z_axis.mul(rhs.zzzz()).add(res); + res.into() + } + + /// Transforms a 4D vector. + #[inline] + pub fn mul_vec4(&self, rhs: Vec4) -> Vec4 { + let mut res = self.x_axis.mul(rhs.xxxx()); + res = res.add(self.y_axis.mul(rhs.yyyy())); + res = res.add(self.z_axis.mul(rhs.zzzz())); + res = res.add(self.w_axis.mul(rhs.wwww())); + res + } + + /// Multiplies two 4x4 matrices. + #[inline] + pub fn mul_mat4(&self, rhs: &Self) -> Self { + Self::from_cols( + self.mul(rhs.x_axis), + self.mul(rhs.y_axis), + self.mul(rhs.z_axis), + self.mul(rhs.w_axis), + ) + } + + /// Adds two 4x4 matrices. + #[inline] + pub fn add_mat4(&self, rhs: &Self) -> Self { + Self::from_cols( + self.x_axis.add(rhs.x_axis), + self.y_axis.add(rhs.y_axis), + self.z_axis.add(rhs.z_axis), + self.w_axis.add(rhs.w_axis), + ) + } + + /// Subtracts two 4x4 matrices. + #[inline] + pub fn sub_mat4(&self, rhs: &Self) -> Self { + Self::from_cols( + self.x_axis.sub(rhs.x_axis), + self.y_axis.sub(rhs.y_axis), + self.z_axis.sub(rhs.z_axis), + self.w_axis.sub(rhs.w_axis), + ) + } + + /// Multiplies a 4x4 matrix by a scalar. + #[inline] + pub fn mul_scalar(&self, rhs: f32) -> Self { + Self::from_cols( + self.x_axis.mul(rhs), + self.y_axis.mul(rhs), + self.z_axis.mul(rhs), + self.w_axis.mul(rhs), + ) + } + + /// Returns true if the absolute difference of all elements between `self` and `rhs` + /// is less than or equal to `max_abs_diff`. + /// + /// This can be used to compare if two matrices contain similar elements. It works best + /// when comparing with a known value. The `max_abs_diff` that should be used used + /// depends on the values being compared against. + /// + /// For more see + /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/). + #[inline] + pub fn abs_diff_eq(&self, rhs: Self, max_abs_diff: f32) -> bool { + self.x_axis.abs_diff_eq(rhs.x_axis, max_abs_diff) + && self.y_axis.abs_diff_eq(rhs.y_axis, max_abs_diff) + && self.z_axis.abs_diff_eq(rhs.z_axis, max_abs_diff) + && self.w_axis.abs_diff_eq(rhs.w_axis, max_abs_diff) + } + + #[inline] + pub fn as_dmat4(&self) -> DMat4 { + DMat4::from_cols( + self.x_axis.as_dvec4(), + self.y_axis.as_dvec4(), + self.z_axis.as_dvec4(), + self.w_axis.as_dvec4(), + ) + } +} + +impl Default for Mat4 { + #[inline] + fn default() -> Self { + Self::IDENTITY + } +} + +impl Add for Mat4 { + type Output = Self; + #[inline] + fn add(self, rhs: Self) -> Self::Output { + self.add_mat4(&rhs) + } +} + +impl AddAssign for Mat4 { + #[inline] + fn add_assign(&mut self, rhs: Self) { + *self = self.add_mat4(&rhs); + } +} + +impl Sub for Mat4 { + type Output = Self; + #[inline] + fn sub(self, rhs: Self) -> Self::Output { + self.sub_mat4(&rhs) + } +} + +impl SubAssign for Mat4 { + #[inline] + fn sub_assign(&mut self, rhs: Self) { + *self = self.sub_mat4(&rhs); + } +} + +impl Neg for Mat4 { + type Output = Self; + #[inline] + fn neg(self) -> Self::Output { + Self::from_cols( + self.x_axis.neg(), + self.y_axis.neg(), + self.z_axis.neg(), + self.w_axis.neg(), + ) + } +} + +impl Mul for Mat4 { + type Output = Self; + #[inline] + fn mul(self, rhs: Self) -> Self::Output { + self.mul_mat4(&rhs) + } +} + +impl MulAssign for Mat4 { + #[inline] + fn mul_assign(&mut self, rhs: Self) { + *self = self.mul_mat4(&rhs); + } +} + +impl Mul for Mat4 { + type Output = Vec4; + #[inline] + fn mul(self, rhs: Vec4) -> Self::Output { + self.mul_vec4(rhs) + } +} + +impl Mul for f32 { + type Output = Mat4; + #[inline] + fn mul(self, rhs: Mat4) -> Self::Output { + rhs.mul_scalar(self) + } +} + +impl Mul for Mat4 { + type Output = Self; + #[inline] + fn mul(self, rhs: f32) -> Self::Output { + self.mul_scalar(rhs) + } +} + +impl MulAssign for Mat4 { + #[inline] + fn mul_assign(&mut self, rhs: f32) { + *self = self.mul_scalar(rhs); + } +} + +impl<'a> Sum<&'a Self> for Mat4 { + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, |a, &b| Self::add(a, b)) + } +} + +impl<'a> Product<&'a Self> for Mat4 { + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::IDENTITY, |a, &b| Self::mul(a, b)) + } +} + +impl PartialEq for Mat4 { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.x_axis.eq(&rhs.x_axis) + && self.y_axis.eq(&rhs.y_axis) + && self.z_axis.eq(&rhs.z_axis) + && self.w_axis.eq(&rhs.w_axis) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsRef<[f32; 16]> for Mat4 { + #[inline] + fn as_ref(&self) -> &[f32; 16] { + unsafe { &*(self as *const Self as *const [f32; 16]) } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsMut<[f32; 16]> for Mat4 { + #[inline] + fn as_mut(&mut self) -> &mut [f32; 16] { + unsafe { &mut *(self as *mut Self as *mut [f32; 16]) } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Debug for Mat4 { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct(stringify!(Mat4)) + .field("x_axis", &self.x_axis) + .field("y_axis", &self.y_axis) + .field("z_axis", &self.z_axis) + .field("w_axis", &self.w_axis) + .finish() + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Display for Mat4 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "[{}, {}, {}, {}]", + self.x_axis, self.y_axis, self.z_axis, self.w_axis + ) + } +} diff --git a/src/f32/wasm32/quat.rs b/src/f32/wasm32/quat.rs new file mode 100644 index 00000000..f3ff59d5 --- /dev/null +++ b/src/f32/wasm32/quat.rs @@ -0,0 +1,901 @@ +// Generated from quat.rs template. Edit the template, not the generated file. + +use crate::{ + euler::{EulerFromQuaternion, EulerRot, EulerToQuaternion}, + DQuat, FloatEx, Mat3, Mat4, Vec2, Vec3, Vec3A, Vec4, +}; + +#[cfg(not(feature = "std"))] +use num_traits::Float; + +use core::arch::wasm32::*; + +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::iter::{Product, Sum}; +use core::ops::{Add, Deref, Div, Mul, MulAssign, Neg, Sub}; + +/// Creates a quaternion from `x`, `y`, `z` and `w` values. +/// +/// This should generally not be called manually unless you know what you are doing. Use +/// one of the other constructors instead such as `identity` or `from_axis_angle`. +#[inline] +pub const fn quat(x: f32, y: f32, z: f32, w: f32) -> Quat { + Quat::from_xyzw(x, y, z, w) +} + +/// A quaternion representing an orientation. +/// +/// This quaternion is intended to be of unit length but may denormalize due to +/// floating point "error creep" which can occur when successive quaternion +/// operations are applied. +/// +/// This type is 16 byte aligned. +#[derive(Clone, Copy)] +#[repr(transparent)] +pub struct Quat(pub(crate) v128); + +impl Quat { + /// All zeros. + const ZERO: Self = Self::from_array([0.0; 4]); + + /// The identity quaternion. Corresponds to no rotation. + pub const IDENTITY: Self = Self::from_xyzw(0.0, 0.0, 0.0, 1.0); + + /// All NANs. + pub const NAN: Self = Self::from_array([f32::NAN; 4]); + + /// Creates a new rotation quaternion. + /// + /// This should generally not be called manually unless you know what you are doing. + /// Use one of the other constructors instead such as `identity` or `from_axis_angle`. + /// + /// `from_xyzw` is mostly used by unit tests and `serde` deserialization. + /// + /// # Preconditions + /// + /// This function does not check if the input is normalized, it is up to the user to + /// provide normalized input or to normalized the resulting quaternion. + #[inline(always)] + pub const fn from_xyzw(x: f32, y: f32, z: f32, w: f32) -> Self { + Self(f32x4(x, y, z, w)) + } + + /// Creates a rotation quaternion from an array. + /// + /// # Preconditions + /// + /// This function does not check if the input is normalized, it is up to the user to + /// provide normalized input or to normalized the resulting quaternion. + #[inline] + pub const fn from_array(a: [f32; 4]) -> Self { + Self::from_xyzw(a[0], a[1], a[2], a[3]) + } + + /// Creates a new rotation quaternion from a 4D vector. + /// + /// # Preconditions + /// + /// This function does not check if the input is normalized, it is up to the user to + /// provide normalized input or to normalized the resulting quaternion. + #[inline] + pub fn from_vec4(v: Vec4) -> Self { + Self(v.0) + } + + /// Creates a rotation quaternion from a slice. + /// + /// # Preconditions + /// + /// This function does not check if the input is normalized, it is up to the user to + /// provide normalized input or to normalized the resulting quaternion. + /// + /// # Panics + /// + /// Panics if `slice` length is less than 4. + #[inline] + pub fn from_slice(slice: &[f32]) -> Self { + Self::from_xyzw(slice[0], slice[1], slice[2], slice[3]) + } + + /// Writes the quaternion to an unaligned slice. + /// + /// # Panics + /// + /// Panics if `slice` length is less than 4. + #[inline] + pub fn write_to_slice(self, slice: &mut [f32]) { + slice[0] = self.x; + slice[1] = self.y; + slice[2] = self.z; + slice[3] = self.w; + } + + /// Create a quaternion for a normalized rotation `axis` and `angle` (in radians). + /// The axis must be normalized (unit-length). + /// + /// # Panics + /// + /// Will panic if `axis` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn from_axis_angle(axis: Vec3, angle: f32) -> Self { + glam_assert!(axis.is_normalized()); + let (s, c) = (angle * 0.5).sin_cos(); + let v = axis * s; + Self::from_xyzw(v.x, v.y, v.z, c) + } + + /// Create a quaternion that rotates `v.length()` radians around `v.normalize()`. + /// + /// `from_scaled_axis(Vec3::ZERO)` results in the identity quaternion. + #[inline] + pub fn from_scaled_axis(v: Vec3) -> Self { + let length = v.length(); + if length == 0.0 { + Self::IDENTITY + } else { + Self::from_axis_angle(v / length, length) + } + } + + /// Creates a quaternion from the `angle` (in radians) around the x axis. + #[inline] + pub fn from_rotation_x(angle: f32) -> Self { + let (s, c) = (angle * 0.5).sin_cos(); + Self::from_xyzw(s, 0.0, 0.0, c) + } + + /// Creates a quaternion from the `angle` (in radians) around the y axis. + #[inline] + pub fn from_rotation_y(angle: f32) -> Self { + let (s, c) = (angle * 0.5).sin_cos(); + Self::from_xyzw(0.0, s, 0.0, c) + } + + /// Creates a quaternion from the `angle` (in radians) around the z axis. + #[inline] + pub fn from_rotation_z(angle: f32) -> Self { + let (s, c) = (angle * 0.5).sin_cos(); + Self::from_xyzw(0.0, 0.0, s, c) + } + + #[inline] + /// Creates a quaternion from the given Euler rotation sequence and the angles (in radians). + pub fn from_euler(euler: EulerRot, a: f32, b: f32, c: f32) -> Self { + euler.new_quat(a, b, c) + } + + /// From the columns of a 3x3 rotation matrix. + #[inline] + pub(crate) fn from_rotation_axes(x_axis: Vec3, y_axis: Vec3, z_axis: Vec3) -> Self { + // Based on https://github.com/microsoft/DirectXMath `XM$quaternionRotationMatrix` + // TODO: sse2 version + let (m00, m01, m02) = x_axis.into(); + let (m10, m11, m12) = y_axis.into(); + let (m20, m21, m22) = z_axis.into(); + if m22 <= 0.0 { + // x^2 + y^2 >= z^2 + w^2 + let dif10 = m11 - m00; + let omm22 = 1.0 - m22; + if dif10 <= 0.0 { + // x^2 >= y^2 + let four_xsq = omm22 - dif10; + let inv4x = 0.5 / four_xsq.sqrt(); + Self::from_xyzw( + four_xsq * inv4x, + (m01 + m10) * inv4x, + (m02 + m20) * inv4x, + (m12 - m21) * inv4x, + ) + } else { + // y^2 >= x^2 + let four_ysq = omm22 + dif10; + let inv4y = 0.5 / four_ysq.sqrt(); + Self::from_xyzw( + (m01 + m10) * inv4y, + four_ysq * inv4y, + (m12 + m21) * inv4y, + (m20 - m02) * inv4y, + ) + } + } else { + // z^2 + w^2 >= x^2 + y^2 + let sum10 = m11 + m00; + let opm22 = 1.0 + m22; + if sum10 <= 0.0 { + // z^2 >= w^2 + let four_zsq = opm22 - sum10; + let inv4z = 0.5 / four_zsq.sqrt(); + Self::from_xyzw( + (m02 + m20) * inv4z, + (m12 + m21) * inv4z, + four_zsq * inv4z, + (m01 - m10) * inv4z, + ) + } else { + // w^2 >= z^2 + let four_wsq = opm22 + sum10; + let inv4w = 0.5 / four_wsq.sqrt(); + Self::from_xyzw( + (m12 - m21) * inv4w, + (m20 - m02) * inv4w, + (m01 - m10) * inv4w, + four_wsq * inv4w, + ) + } + } + } + + /// Creates a quaternion from a 3x3 rotation matrix. + #[inline] + pub fn from_mat3(mat: &Mat3) -> Self { + Self::from_rotation_axes(mat.x_axis, mat.y_axis, mat.z_axis) + } + + /// Creates a quaternion from a 3x3 rotation matrix inside a homogeneous 4x4 matrix. + #[inline] + pub fn from_mat4(mat: &Mat4) -> Self { + Self::from_rotation_axes( + mat.x_axis.truncate(), + mat.y_axis.truncate(), + mat.z_axis.truncate(), + ) + } + + /// Gets the minimal rotation for transforming `from` to `to`. The rotation is in the + /// plane spanned by the two vectors. Will rotate at most 180 degrees. + /// + /// The input vectors must be normalized (unit-length). + /// + /// `from_rotation_arc(from, to) * from ≈ to`. + /// + /// For near-singular cases (from≈to and from≈-to) the current implementation + /// is only accurate to about 0.001 (for `f32`). + /// + /// # Panics + /// + /// Will panic if `from` or `to` are not normalized when `glam_assert` is enabled. + pub fn from_rotation_arc(from: Vec3, to: Vec3) -> Self { + glam_assert!(from.is_normalized()); + glam_assert!(to.is_normalized()); + + const ONE_MINUS_EPS: f32 = 1.0 - 2.0 * core::f32::EPSILON; + let dot = from.dot(to); + if dot > ONE_MINUS_EPS { + // 0° singulary: from ≈ to + Self::IDENTITY + } else if dot < -ONE_MINUS_EPS { + // 180° singulary: from ≈ -to + use core::f32::consts::PI; // half a turn = 𝛕/2 = 180° + Self::from_axis_angle(from.any_orthonormal_vector(), PI) + } else { + let c = from.cross(to); + Self::from_xyzw(c.x, c.y, c.z, 1.0 + dot).normalize() + } + } + + /// Gets the minimal rotation for transforming `from` to either `to` or `-to`. This means + /// that the resulting quaternion will rotate `from` so that it is colinear with `to`. + /// + /// The rotation is in the plane spanned by the two vectors. Will rotate at most 90 + /// degrees. + /// + /// The input vectors must be normalized (unit-length). + /// + /// `to.dot(from_rotation_arc_colinear(from, to) * from).abs() ≈ 1`. + /// + /// # Panics + /// + /// Will panic if `from` or `to` are not normalized when `glam_assert` is enabled. + #[inline] + pub fn from_rotation_arc_colinear(from: Vec3, to: Vec3) -> Self { + if from.dot(to) < 0.0 { + Self::from_rotation_arc(from, -to) + } else { + Self::from_rotation_arc(from, to) + } + } + + /// Gets the minimal rotation for transforming `from` to `to`. The resulting rotation is + /// around the z axis. Will rotate at most 180 degrees. + /// + /// The input vectors must be normalized (unit-length). + /// + /// `from_rotation_arc_2d(from, to) * from ≈ to`. + /// + /// For near-singular cases (from≈to and from≈-to) the current implementation + /// is only accurate to about 0.001 (for `f32`). + /// + /// # Panics + /// + /// Will panic if `from` or `to` are not normalized when `glam_assert` is enabled. + pub fn from_rotation_arc_2d(from: Vec2, to: Vec2) -> Self { + glam_assert!(from.is_normalized()); + glam_assert!(to.is_normalized()); + + const ONE_MINUS_EPSILON: f32 = 1.0 - 2.0 * core::f32::EPSILON; + let dot = from.dot(to); + if dot > ONE_MINUS_EPSILON { + // 0° singulary: from ≈ to + Self::IDENTITY + } else if dot < -ONE_MINUS_EPSILON { + // 180° singulary: from ≈ -to + const COS_FRAC_PI_2: f32 = 0.0; + const SIN_FRAC_PI_2: f32 = 1.0; + // rotation around z by PI radians + Self::from_xyzw(0.0, 0.0, SIN_FRAC_PI_2, COS_FRAC_PI_2) + } else { + // vector3 cross where z=0 + let z = from.x * to.y - to.x * from.y; + let w = 1.0 + dot; + // calculate length with x=0 and y=0 to normalize + let len_rcp = 1.0 / (z * z + w * w).sqrt(); + Self::from_xyzw(0.0, 0.0, z * len_rcp, w * len_rcp) + } + } + + /// Returns the rotation axis and angle (in radians) of `self`. + #[inline] + pub fn to_axis_angle(self) -> (Vec3, f32) { + const EPSILON: f32 = 1.0e-8; + const EPSILON_SQUARED: f32 = EPSILON * EPSILON; + let w = self.w; + let angle = w.acos_approx() * 2.0; + let scale_sq = f32::max(1.0 - w * w, 0.0); + if scale_sq >= EPSILON_SQUARED { + ( + Vec3::new(self.x, self.y, self.z) * scale_sq.sqrt().recip(), + angle, + ) + } else { + (Vec3::X, angle) + } + } + + /// Returns the rotation axis scaled by the rotation in radians. + #[inline] + pub fn to_scaled_axis(self) -> Vec3 { + let (axis, angle) = self.to_axis_angle(); + axis * angle + } + + /// Returns the rotation angles for the given euler rotation sequence. + #[inline] + pub fn to_euler(self, euler: EulerRot) -> (f32, f32, f32) { + euler.convert_quat(self) + } + + /// `[x, y, z, w]` + #[inline] + pub fn to_array(&self) -> [f32; 4] { + [self.x, self.y, self.z, self.w] + } + + /// Returns the vector part of the quaternion. + #[inline] + pub fn xyz(self) -> Vec3 { + Vec3::new(self.x, self.y, self.z) + } + + /// Returns the quaternion conjugate of `self`. For a unit quaternion the + /// conjugate is also the inverse. + #[must_use] + #[inline] + pub fn conjugate(self) -> Self { + const SIGN: v128 = const_f32x4!([-1.0, -1.0, -1.0, 1.0]); + Self(f32x4_mul(self.0, SIGN)) + } + + /// Returns the inverse of a normalized quaternion. + /// + /// Typically quaternion inverse returns the conjugate of a normalized quaternion. + /// Because `self` is assumed to already be unit length this method *does not* normalize + /// before returning the conjugate. + /// + /// # Panics + /// + /// Will panic if `self` is not normalized when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn inverse(self) -> Self { + glam_assert!(self.is_normalized()); + self.conjugate() + } + + /// Computes the dot product of `self` and `rhs`. The dot product is + /// equal to the cosine of the angle between two quaternion rotations. + #[inline] + pub fn dot(self, rhs: Self) -> f32 { + Vec4::from(self).dot(Vec4::from(rhs)) + } + + /// Computes the length of `self`. + #[doc(alias = "magnitude")] + #[inline] + pub fn length(self) -> f32 { + Vec4::from(self).length() + } + + /// Computes the squared length of `self`. + /// + /// This is generally faster than `length()` as it avoids a square + /// root operation. + #[doc(alias = "magnitude2")] + #[inline] + pub fn length_squared(self) -> f32 { + Vec4::from(self).length_squared() + } + + /// Computes `1.0 / length()`. + /// + /// For valid results, `self` must _not_ be of length zero. + #[inline] + pub fn length_recip(self) -> f32 { + Vec4::from(self).length_recip() + } + + /// Returns `self` normalized to length 1.0. + /// + /// For valid results, `self` must _not_ be of length zero. + /// + /// Panics + /// + /// Will panic if `self` is zero length when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn normalize(self) -> Self { + Self::from_vec4(Vec4::from(self).normalize()) + } + + /// Returns `true` if, and only if, all elements are finite. + /// If any element is either `NaN`, positive or negative infinity, this will return `false`. + #[inline] + pub fn is_finite(self) -> bool { + Vec4::from(self).is_finite() + } + + #[inline] + pub fn is_nan(self) -> bool { + Vec4::from(self).is_nan() + } + + /// Returns whether `self` of length `1.0` or not. + /// + /// Uses a precision threshold of `1e-6`. + #[inline] + pub fn is_normalized(self) -> bool { + Vec4::from(self).is_normalized() + } + + #[inline] + pub fn is_near_identity(self) -> bool { + // Based on https://github.com/nfrechette/rtm `rtm::quat_near_identity` + let threshold_angle = 0.002_847_144_6; + // Because of floating point precision, we cannot represent very small rotations. + // The closest f32 to 1.0 that is not 1.0 itself yields: + // 0.99999994.acos() * 2.0 = 0.000690533954 rad + // + // An error threshold of 1.e-6 is used by default. + // (1.0 - 1.e-6).acos() * 2.0 = 0.00284714461 rad + // (1.0 - 1.e-7).acos() * 2.0 = 0.00097656250 rad + // + // We don't really care about the angle value itself, only if it's close to 0. + // This will happen whenever quat.w is close to 1.0. + // If the quat.w is close to -1.0, the angle will be near 2*PI which is close to + // a negative 0 rotation. By forcing quat.w to be positive, we'll end up with + // the shortest path. + let positive_w_angle = self.w.abs().acos_approx() * 2.0; + positive_w_angle < threshold_angle + } + + /// Returns the angle (in radians) for the minimal rotation + /// for transforming this quaternion into another. + /// + /// Both quaternions must be normalized. + /// + /// # Panics + /// + /// Will panic if `self` or `rhs` are not normalized when `glam_assert` is enabled. + #[inline] + pub fn angle_between(self, rhs: Self) -> f32 { + glam_assert!(self.is_normalized() && rhs.is_normalized()); + self.dot(rhs).abs().acos_approx() * 2.0 + } + + /// Returns true if the absolute difference of all elements between `self` and `rhs` + /// is less than or equal to `max_abs_diff`. + /// + /// This can be used to compare if two quaternions contain similar elements. It works + /// best when comparing with a known value. The `max_abs_diff` that should be used used + /// depends on the values being compared against. + /// + /// For more see + /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/). + #[inline] + pub fn abs_diff_eq(self, rhs: Self, max_abs_diff: f32) -> bool { + Vec4::from(self).abs_diff_eq(Vec4::from(rhs), max_abs_diff) + } + + /// Performs a linear interpolation between `self` and `rhs` based on + /// the value `s`. + /// + /// When `s` is `0.0`, the result will be equal to `self`. When `s` + /// is `1.0`, the result will be equal to `rhs`. + /// + /// # Panics + /// + /// Will panic if `self` or `end` are not normalized when `glam_assert` is enabled. + #[inline] + #[doc(alias = "mix")] + pub fn lerp(self, end: Self, s: f32) -> Self { + glam_assert!(self.is_normalized()); + glam_assert!(end.is_normalized()); + + const NEG_ZERO: v128 = const_f32x4!([-0.0; 4]); + let start = self.0; + let end = end.0; + let dot = crate::wasm32::dot4_into_v128(start, end); + // Calculate the bias, if the dot product is positive or zero, there is no bias + // but if it is negative, we want to flip the 'end' rotation XYZW components + let bias = v128_and(dot, NEG_ZERO); + let interpolated = f32x4_add( + f32x4_mul(f32x4_sub(v128_xor(end, bias), start), f32x4_splat(s)), + start, + ); + Quat(interpolated).normalize() + } + + /// Performs a spherical linear interpolation between `self` and `end` + /// based on the value `s`. + /// + /// When `s` is `0.0`, the result will be equal to `self`. When `s` + /// is `1.0`, the result will be equal to `end`. + /// + /// # Panics + /// + /// Will panic if `self` or `end` are not normalized when `glam_assert` is enabled. + #[inline] + pub fn slerp(self, mut end: Self, s: f32) -> Self { + // http://number-none.com/product/Understanding%20Slerp,%20Then%20Not%20Using%20It/ + glam_assert!(self.is_normalized()); + glam_assert!(end.is_normalized()); + + const DOT_THRESHOLD: f32 = 0.9995; + + // Note that a rotation can be represented by two quaternions: `q` and + // `-q`. The slerp path between `q` and `end` will be different from the + // path between `-q` and `end`. One path will take the long way around and + // one will take the short way. In order to correct for this, the `dot` + // product between `self` and `end` should be positive. If the `dot` + // product is negative, slerp between `self` and `-end`. + let mut dot = self.dot(end); + if dot < 0.0 { + end = -end; + dot = -dot; + } + + if dot > DOT_THRESHOLD { + // assumes lerp returns a normalized quaternion + self.lerp(end, s) + } else { + let theta = dot.acos_approx(); + + // TODO: v128_sin is broken + // let x = 1.0 - s; + // let y = s; + // let z = 1.0; + // let w = 0.0; + // let tmp = f32x4_mul(f32x4_splat(theta), f32x4(x, y, z, w)); + // let tmp = v128_sin(tmp); + let x = (theta * (1.0 - s)).sin(); + let y = (theta * s).sin(); + let z = theta.sin(); + let w = 0.0; + let tmp = f32x4(x, y, z, w); + + let scale1 = i32x4_shuffle::<0, 0, 4, 4>(tmp, tmp); + let scale2 = i32x4_shuffle::<1, 1, 5, 5>(tmp, tmp); + let theta_sin = i32x4_shuffle::<2, 2, 6, 6>(tmp, tmp); + + Self(f32x4_div( + f32x4_add(f32x4_mul(self.0, scale1), f32x4_mul(end.0, scale2)), + theta_sin, + )) + } + } + + /// Multiplies a quaternion and a 3D vector, returning the rotated vector. + /// + /// # Panics + /// + /// Will panic if `self` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn mul_vec3(self, rhs: Vec3) -> Vec3 { + glam_assert!(self.is_normalized()); + + self.mul_vec3a(rhs.into()).into() + } + + /// Multiplies two quaternions. If they each represent a rotation, the result will + /// represent the combined rotation. + /// + /// Note that due to floating point rounding the result may not be perfectly normalized. + /// + /// # Panics + /// + /// Will panic if `self` or `rhs` are not normalized when `glam_assert` is enabled. + #[inline] + pub fn mul_quat(self, rhs: Self) -> Self { + glam_assert!(self.is_normalized()); + glam_assert!(rhs.is_normalized()); + + let lhs = self.0; + let rhs = rhs.0; + + const CONTROL_WZYX: v128 = const_f32x4!([1.0, -1.0, 1.0, -1.0]); + const CONTROL_ZWXY: v128 = const_f32x4!([1.0, 1.0, -1.0, -1.0]); + const CONTROL_YXWZ: v128 = const_f32x4!([-1.0, 1.0, 1.0, -1.0]); + + let r_xxxx = i32x4_shuffle::<0, 0, 4, 4>(lhs, lhs); + let r_yyyy = i32x4_shuffle::<1, 1, 5, 5>(lhs, lhs); + let r_zzzz = i32x4_shuffle::<2, 2, 6, 6>(lhs, lhs); + let r_wwww = i32x4_shuffle::<3, 3, 7, 7>(lhs, lhs); + + let lxrw_lyrw_lzrw_lwrw = f32x4_mul(r_wwww, rhs); + let l_wzyx = i32x4_shuffle::<3, 2, 5, 4>(rhs, rhs); + + let lwrx_lzrx_lyrx_lxrx = f32x4_mul(r_xxxx, l_wzyx); + let l_zwxy = i32x4_shuffle::<1, 0, 7, 6>(l_wzyx, l_wzyx); + + let lwrx_nlzrx_lyrx_nlxrx = f32x4_mul(lwrx_lzrx_lyrx_lxrx, CONTROL_WZYX); + + let lzry_lwry_lxry_lyry = f32x4_mul(r_yyyy, l_zwxy); + let l_yxwz = i32x4_shuffle::<3, 2, 5, 4>(l_zwxy, l_zwxy); + + let lzry_lwry_nlxry_nlyry = f32x4_mul(lzry_lwry_lxry_lyry, CONTROL_ZWXY); + + let lyrz_lxrz_lwrz_lzrz = f32x4_mul(r_zzzz, l_yxwz); + let result0 = f32x4_add(lxrw_lyrw_lzrw_lwrw, lwrx_nlzrx_lyrx_nlxrx); + + let nlyrz_lxrz_lwrz_wlzrz = f32x4_mul(lyrz_lxrz_lwrz_lzrz, CONTROL_YXWZ); + let result1 = f32x4_add(lzry_lwry_nlxry_nlyry, nlyrz_lxrz_lwrz_wlzrz); + + Self(f32x4_add(result0, result1)) + } + + /// Creates a quaternion from a 3x3 rotation matrix inside a 3D affine transform. + #[inline] + pub fn from_affine3(a: &crate::Affine3A) -> Self { + #[allow(clippy::useless_conversion)] + Self::from_rotation_axes( + a.matrix3.x_axis.into(), + a.matrix3.y_axis.into(), + a.matrix3.z_axis.into(), + ) + } + + /// Multiplies a quaternion and a 3D vector, returning the rotated vector. + #[inline] + pub fn mul_vec3a(self, rhs: Vec3A) -> Vec3A { + const TWO: v128 = const_f32x4!([2.0; 4]); + let w = i32x4_shuffle::<3, 3, 7, 7>(self.0, self.0); + let b = self.0; + let b2 = crate::wasm32::dot3_into_v128(b, b); + Vec3A(f32x4_add( + f32x4_add( + f32x4_mul(rhs.0, f32x4_sub(f32x4_mul(w, w), b2)), + f32x4_mul(b, f32x4_mul(crate::wasm32::dot3_into_v128(rhs.0, b), TWO)), + ), + f32x4_mul(Vec3A(b).cross(rhs).into(), f32x4_mul(w, TWO)), + )) + } + + #[inline] + pub fn as_f64(self) -> DQuat { + DQuat::from_xyzw(self.x as f64, self.y as f64, self.z as f64, self.w as f64) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Debug for Quat { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_tuple(stringify!(Quat)) + .field(&self.x) + .field(&self.y) + .field(&self.z) + .field(&self.w) + .finish() + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Display for Quat { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(fmt, "[{}, {}, {}, {}]", self.x, self.y, self.z, self.w) + } +} + +impl Add for Quat { + type Output = Self; + /// Adds two quaternions. + /// + /// The sum is not guaranteed to be normalized. + /// + /// Note that addition is not the same as combining the rotations represented by the + /// two quaternions! That corresponds to multiplication. + #[inline] + fn add(self, rhs: Self) -> Self { + Self::from_vec4(Vec4::from(self) + Vec4::from(rhs)) + } +} + +impl Sub for Quat { + type Output = Self; + /// Subtracts the `rhs` quaternion from `self`. + /// + /// The difference is not guaranteed to be normalized. + #[inline] + fn sub(self, rhs: Self) -> Self { + Self::from_vec4(Vec4::from(self) - Vec4::from(rhs)) + } +} + +impl Mul for Quat { + type Output = Self; + /// Multiplies a quaternion by a scalar value. + /// + /// The product is not guaranteed to be normalized. + #[inline] + fn mul(self, rhs: f32) -> Self { + Self::from_vec4(Vec4::from(self) * rhs) + } +} + +impl Div for Quat { + type Output = Self; + /// Divides a quaternion by a scalar value. + /// The quotient is not guaranteed to be normalized. + #[inline] + fn div(self, rhs: f32) -> Self { + Self::from_vec4(Vec4::from(self) / rhs) + } +} + +impl Mul for Quat { + type Output = Self; + /// Multiplies two quaternions. If they each represent a rotation, the result will + /// represent the combined rotation. + /// + /// Note that due to floating point rounding the result may not be perfectly + /// normalized. + /// + /// # Panics + /// + /// Will panic if `self` or `rhs` are not normalized when `glam_assert` is enabled. + #[inline] + fn mul(self, rhs: Self) -> Self { + self.mul_quat(rhs) + } +} + +impl MulAssign for Quat { + /// Multiplies two quaternions. If they each represent a rotation, the result will + /// represent the combined rotation. + /// + /// Note that due to floating point rounding the result may not be perfectly + /// normalized. + /// + /// # Panics + /// + /// Will panic if `self` or `rhs` are not normalized when `glam_assert` is enabled. + #[inline] + fn mul_assign(&mut self, rhs: Self) { + *self = self.mul_quat(rhs); + } +} + +impl Mul for Quat { + type Output = Vec3; + /// Multiplies a quaternion and a 3D vector, returning the rotated vector. + /// + /// # Panics + /// + /// Will panic if `self` is not normalized when `glam_assert` is enabled. + #[inline] + fn mul(self, rhs: Vec3) -> Self::Output { + self.mul_vec3(rhs) + } +} + +impl Neg for Quat { + type Output = Self; + #[inline] + fn neg(self) -> Self { + self * -1.0 + } +} + +impl Default for Quat { + #[inline] + fn default() -> Self { + Self::IDENTITY + } +} + +impl PartialEq for Quat { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + Vec4::from(*self).eq(&Vec4::from(*rhs)) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsRef<[f32; 4]> for Quat { + #[inline] + fn as_ref(&self) -> &[f32; 4] { + unsafe { &*(self as *const Self as *const [f32; 4]) } + } +} + +impl<'a> Sum<&'a Self> for Quat { + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, |a, &b| Self::add(a, b)) + } +} + +impl<'a> Product<&'a Self> for Quat { + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::IDENTITY, |a, &b| Self::mul(a, b)) + } +} + +impl Mul for Quat { + type Output = Vec3A; + #[inline] + fn mul(self, rhs: Vec3A) -> Self::Output { + self.mul_vec3a(rhs) + } +} + +impl From for Vec4 { + #[inline] + fn from(q: Quat) -> Self { + Self(q.0) + } +} + +impl From for (f32, f32, f32, f32) { + #[inline] + fn from(q: Quat) -> Self { + Vec4::from(q).into() + } +} + +impl From for [f32; 4] { + #[inline] + fn from(q: Quat) -> Self { + Vec4::from(q).into() + } +} + +impl From for v128 { + // TODO: write test + #[inline] + fn from(q: Quat) -> Self { + q.0 + } +} + +impl Deref for Quat { + type Target = crate::deref::XYZW; + #[inline] + fn deref(&self) -> &Self::Target { + unsafe { &*(self as *const Self).cast() } + } +} diff --git a/src/f32/wasm32/vec3a.rs b/src/f32/wasm32/vec3a.rs new file mode 100644 index 00000000..fb9f9aea --- /dev/null +++ b/src/f32/wasm32/vec3a.rs @@ -0,0 +1,1066 @@ +// Generated from vec.rs template. Edit the template, not the generated file. + +use crate::{BVec3A, Vec2, Vec3, Vec4}; + +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::iter::{Product, Sum}; +use core::{f32, ops::*}; + +use core::arch::wasm32::*; + +#[cfg(not(feature = "std"))] +use num_traits::Float; + +union UnionCast { + a: [f32; 4], + v: Vec3A, +} + +/// Creates a 3-dimensional vector. +#[inline(always)] +pub const fn vec3a(x: f32, y: f32, z: f32) -> Vec3A { + Vec3A::new(x, y, z) +} + +/// A 3-dimensional vector with SIMD support. +/// +/// This type is 16 byte aligned. A SIMD vector type is used for storage on supported platforms for +/// better performance than the `Vec3` type. +/// +/// It is possible to convert between `Vec3` and `Vec3A` types using `From` trait implementations. +#[derive(Clone, Copy)] +#[repr(transparent)] +pub struct Vec3A(pub(crate) v128); + +impl Vec3A { + /// All zeroes. + pub const ZERO: Self = Self::splat(0.0); + + /// All ones. + pub const ONE: Self = Self::splat(1.0); + + /// All negative ones. + pub const NEG_ONE: Self = Self::splat(-1.0); + + /// All NAN. + pub const NAN: Self = Self::splat(f32::NAN); + + /// `[1.0, 0.0, 0.0]`: a unit-length vector pointing along the positive X axis. + pub const X: Self = Self::from_array([1.0, 0.0, 0.0]); + + /// `[0.0, 1.0, 0.0]`: a unit-length vector pointing along the positive Y axis. + pub const Y: Self = Self::from_array([0.0, 1.0, 0.0]); + + /// `[0.0, 0.0, 1.0]`: a unit-length vector pointing along the positive Z axis. + pub const Z: Self = Self::from_array([0.0, 0.0, 1.0]); + + /// The unit axes. + pub const AXES: [Self; 3] = [Self::X, Self::Y, Self::Z]; + + /// Creates a new vector. + #[inline(always)] + pub const fn new(x: f32, y: f32, z: f32) -> Self { + Self(f32x4(x, y, z, z)) + } + + /// Creates a vector with all elements set to `v`. + #[inline] + pub const fn splat(v: f32) -> Self { + unsafe { UnionCast { a: [v; 4] }.v } + } + + /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use + /// for each element of `self`. + /// + /// A true element in the mask uses the corresponding element from `if_true`, and false + /// uses the element from `if_false`. + #[inline] + pub fn select(mask: BVec3A, if_true: Self, if_false: Self) -> Self { + Self(v128_bitselect(if_true.0, if_false.0, mask.0)) + } + + /// Creates a new vector from an array. + #[inline] + pub const fn from_array(a: [f32; 3]) -> Self { + Self::new(a[0], a[1], a[2]) + } + + /// `[x, y, z]` + #[inline] + pub const fn to_array(&self) -> [f32; 3] { + unsafe { *(self as *const Vec3A as *const [f32; 3]) } + } + + /// Creates a vector from the first N values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than N elements long. + #[inline] + pub const fn from_slice(slice: &[f32]) -> Self { + Self::new(slice[0], slice[1], slice[2]) + } + + /// Writes the elements of `self` to the first 3 elements in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than N elements long. + #[inline] + pub fn write_to_slice(self, slice: &mut [f32]) { + slice[0] = self.x; + slice[1] = self.y; + slice[2] = self.z; + } + + /// Internal method for creating a 3D vector from a 4D vector, discarding `w`. + #[allow(dead_code)] + #[inline] + pub(crate) fn from_vec4(v: Vec4) -> Self { + Self(v.0) + } + + /// Creates a 4D vector from `self` and the given `w` value. + #[inline] + pub fn extend(self, w: f32) -> Vec4 { + Vec4::new(self.x, self.y, self.z, w) + } + + /// Creates a 2D vector from the `x` and `y` elements of `self`, discarding `z`. + /// + /// Truncation may also be performed by using `self.xy()` or `Vec2::from()`. + #[inline] + pub fn truncate(self) -> Vec2 { + use crate::swizzles::Vec3Swizzles; + self.xy() + } + + /// Computes the dot product of `self` and `rhs`. + #[inline] + pub fn dot(self, rhs: Self) -> f32 { + crate::wasm32::dot3(self.0, rhs.0) + } + + /// Computes the cross product of `self` and `rhs`. + #[inline] + pub fn cross(self, rhs: Self) -> Self { + let lhszxy = i32x4_shuffle::<2, 0, 1, 1>(self.0, self.0); + let rhszxy = i32x4_shuffle::<2, 0, 1, 1>(rhs.0, rhs.0); + let lhszxy_rhs = f32x4_mul(lhszxy, rhs.0); + let rhszxy_lhs = f32x4_mul(rhszxy, self.0); + let sub = f32x4_sub(lhszxy_rhs, rhszxy_lhs); + Self(i32x4_shuffle::<2, 0, 1, 1>(sub, sub)) + } + + /// Returns a vector containing the minimum values for each element of `self` and `rhs`. + /// + /// In other words this computes `[self.x.min(rhs.x), self.y.min(rhs.y), ..]`. + #[inline] + pub fn min(self, rhs: Self) -> Self { + Self(f32x4_pmin(self.0, rhs.0)) + } + + /// Returns a vector containing the maximum values for each element of `self` and `rhs`. + /// + /// In other words this computes `[self.x.max(rhs.x), self.y.max(rhs.y), ..]`. + #[inline] + pub fn max(self, rhs: Self) -> Self { + Self(f32x4_pmax(self.0, rhs.0)) + } + + /// Component-wise clamping of values, similar to [`f32::clamp`]. + /// + /// Each element in `min` must be less-or-equal to the corresponding element in `max`. + /// + /// # Panics + /// + /// Will panic if `min` is greater than `max` when `glam_assert` is enabled. + #[inline] + pub fn clamp(self, min: Self, max: Self) -> Self { + glam_assert!(min.cmple(max).all(), "clamp: expected min <= max"); + self.max(min).min(max) + } + + /// Returns the horizontal minimum of `self`. + /// + /// In other words this computes `min(x, y, ..)`. + #[inline] + pub fn min_element(self) -> f32 { + let v = self.0; + let v = f32x4_pmin(v, i32x4_shuffle::<2, 2, 1, 1>(v, v)); + let v = f32x4_pmin(v, i32x4_shuffle::<1, 0, 0, 0>(v, v)); + f32x4_extract_lane::<0>(v) + } + + /// Returns the horizontal maximum of `self`. + /// + /// In other words this computes `max(x, y, ..)`. + #[inline] + pub fn max_element(self) -> f32 { + let v = self.0; + let v = f32x4_pmax(v, i32x4_shuffle::<2, 2, 0, 0>(v, v)); + let v = f32x4_pmax(v, i32x4_shuffle::<1, 0, 0, 0>(v, v)); + f32x4_extract_lane::<0>(v) + } + + /// Returns a vector mask containing the result of a `==` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words, this computes `[self.x == rhs.x, self.y == rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpeq(self, rhs: Self) -> BVec3A { + BVec3A(f32x4_eq(self.0, rhs.0)) + } + + /// Returns a vector mask containing the result of a `!=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x != rhs.x, self.y != rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpne(self, rhs: Self) -> BVec3A { + BVec3A(f32x4_ne(self.0, rhs.0)) + } + + /// Returns a vector mask containing the result of a `>=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x >= rhs.x, self.y >= rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpge(self, rhs: Self) -> BVec3A { + BVec3A(f32x4_ge(self.0, rhs.0)) + } + + /// Returns a vector mask containing the result of a `>` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x > rhs.x, self.y > rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpgt(self, rhs: Self) -> BVec3A { + BVec3A(f32x4_gt(self.0, rhs.0)) + } + + /// Returns a vector mask containing the result of a `<=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x <= rhs.x, self.y <= rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmple(self, rhs: Self) -> BVec3A { + BVec3A(f32x4_le(self.0, rhs.0)) + } + + /// Returns a vector mask containing the result of a `<` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x < rhs.x, self.y < rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmplt(self, rhs: Self) -> BVec3A { + BVec3A(f32x4_lt(self.0, rhs.0)) + } + + /// Returns a vector containing the absolute value of each element of `self`. + #[inline] + pub fn abs(self) -> Self { + Self(f32x4_abs(self.0)) + } + + /// Returns a vector with elements representing the sign of `self`. + /// + /// - `1.0` if the number is positive, `+0.0` or `INFINITY` + /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` + /// - `NAN` if the number is `NAN` + #[inline] + pub fn signum(self) -> Self { + let mask = self.cmpge(Self::ZERO); + let result = Self::select(mask, Self::ONE, Self::NEG_ONE); + let mask = self.is_nan_mask(); + Self::select(mask, self, result) + } + + /// Returns `true` if, and only if, all elements are finite. If any element is either + /// `NaN`, positive or negative infinity, this will return `false`. + #[inline] + pub fn is_finite(self) -> bool { + self.x.is_finite() && self.y.is_finite() && self.z.is_finite() + } + + /// Returns `true` if any elements are `NaN`. + #[inline] + pub fn is_nan(self) -> bool { + self.is_nan_mask().any() + } + + /// Performs `is_nan` on each element of self, returning a vector mask of the results. + /// + /// In other words, this computes `[x.is_nan(), y.is_nan(), z.is_nan(), w.is_nan()]`. + #[inline] + pub fn is_nan_mask(self) -> BVec3A { + BVec3A(f32x4_ne(self.0, self.0)) + } + + /// Computes the length of `self`. + #[doc(alias = "magnitude")] + #[inline] + pub fn length(self) -> f32 { + let dot = crate::wasm32::dot3_in_x(self.0, self.0); + f32x4_extract_lane::<0>(f32x4_sqrt(dot)) + } + + /// Computes the squared length of `self`. + /// + /// This is faster than `length()` as it avoids a square root operation. + #[doc(alias = "magnitude2")] + #[inline] + pub fn length_squared(self) -> f32 { + self.dot(self) + } + + /// Computes `1.0 / length()`. + /// + /// For valid results, `self` must _not_ be of length zero. + #[inline] + pub fn length_recip(self) -> f32 { + let dot = crate::wasm32::dot3_in_x(self.0, self.0); + f32x4_extract_lane::<0>(f32x4_div(Self::ONE.0, f32x4_sqrt(dot))) + } + + /// Computes the Euclidean distance between two points in space. + #[inline] + pub fn distance(self, rhs: Self) -> f32 { + (self - rhs).length() + } + + /// Compute the squared euclidean distance between two points in space. + #[inline] + pub fn distance_squared(self, rhs: Self) -> f32 { + (self - rhs).length_squared() + } + + /// Returns `self` normalized to length 1.0. + /// + /// For valid results, `self` must _not_ be of length zero, nor very close to zero. + /// + /// See also [`Self::try_normalize`] and [`Self::normalize_or_zero`]. + /// + /// Panics + /// + /// Will panic if `self` is zero length when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn normalize(self) -> Self { + let length = f32x4_sqrt(crate::wasm32::dot3_into_v128(self.0, self.0)); + #[allow(clippy::let_and_return)] + let normalized = Self(f32x4_div(self.0, length)); + glam_assert!(normalized.is_finite()); + normalized + } + + /// Returns `self` normalized to length 1.0 if possible, else returns `None`. + /// + /// In particular, if the input is zero (or very close to zero), or non-finite, + /// the result of this operation will be `None`. + /// + /// See also [`Self::normalize_or_zero`]. + #[must_use] + #[inline] + pub fn try_normalize(self) -> Option { + let rcp = self.length_recip(); + if rcp.is_finite() && rcp > 0.0 { + Some(self * rcp) + } else { + None + } + } + + /// Returns `self` normalized to length 1.0 if possible, else returns zero. + /// + /// In particular, if the input is zero (or very close to zero), or non-finite, + /// the result of this operation will be zero. + /// + /// See also [`Self::try_normalize`]. + #[must_use] + #[inline] + pub fn normalize_or_zero(self) -> Self { + let rcp = self.length_recip(); + if rcp.is_finite() && rcp > 0.0 { + self * rcp + } else { + Self::ZERO + } + } + + /// Returns whether `self` is length `1.0` or not. + /// + /// Uses a precision threshold of `1e-6`. + #[inline] + pub fn is_normalized(self) -> bool { + // TODO: do something with epsilon + (self.length_squared() - 1.0).abs() <= 1e-4 + } + + /// Returns the vector projection of `self` onto `rhs`. + /// + /// `rhs` must be of non-zero length. + /// + /// # Panics + /// + /// Will panic if `rhs` is zero length when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn project_onto(self, rhs: Self) -> Self { + let other_len_sq_rcp = rhs.dot(rhs).recip(); + glam_assert!(other_len_sq_rcp.is_finite()); + rhs * self.dot(rhs) * other_len_sq_rcp + } + + /// Returns the vector rejection of `self` from `rhs`. + /// + /// The vector rejection is the vector perpendicular to the projection of `self` onto + /// `rhs`, in rhs words the result of `self - self.project_onto(rhs)`. + /// + /// `rhs` must be of non-zero length. + /// + /// # Panics + /// + /// Will panic if `rhs` has a length of zero when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn reject_from(self, rhs: Self) -> Self { + self - self.project_onto(rhs) + } + + /// Returns the vector projection of `self` onto `rhs`. + /// + /// `rhs` must be normalized. + /// + /// # Panics + /// + /// Will panic if `rhs` is not normalized when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn project_onto_normalized(self, rhs: Self) -> Self { + glam_assert!(rhs.is_normalized()); + rhs * self.dot(rhs) + } + + /// Returns the vector rejection of `self` from `rhs`. + /// + /// The vector rejection is the vector perpendicular to the projection of `self` onto + /// `rhs`, in rhs words the result of `self - self.project_onto(rhs)`. + /// + /// `rhs` must be normalized. + /// + /// # Panics + /// + /// Will panic if `rhs` is not normalized when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn reject_from_normalized(self, rhs: Self) -> Self { + self - self.project_onto_normalized(rhs) + } + + /// Returns a vector containing the nearest integer to a number for each element of `self`. + /// Round half-way cases away from 0.0. + #[inline] + pub fn round(self) -> Self { + Self(f32x4_nearest(self.0)) + } + + /// Returns a vector containing the largest integer less than or equal to a number for each + /// element of `self`. + #[inline] + pub fn floor(self) -> Self { + Self(f32x4_floor(self.0)) + } + + /// Returns a vector containing the smallest integer greater than or equal to a number for + /// each element of `self`. + #[inline] + pub fn ceil(self) -> Self { + Self(f32x4_ceil(self.0)) + } + + /// Returns a vector containing the fractional part of the vector, e.g. `self - + /// self.floor()`. + /// + /// Note that this is fast but not precise for large numbers. + #[inline] + pub fn fract(self) -> Self { + self - self.floor() + } + + /// Returns a vector containing `e^self` (the exponential function) for each element of + /// `self`. + #[inline] + pub fn exp(self) -> Self { + Self::new(self.x.exp(), self.y.exp(), self.z.exp()) + } + + /// Returns a vector containing each element of `self` raised to the power of `n`. + #[inline] + pub fn powf(self, n: f32) -> Self { + Self::new(self.x.powf(n), self.y.powf(n), self.z.powf(n)) + } + + /// Returns a vector containing the reciprocal `1.0/n` of each element of `self`. + #[inline] + pub fn recip(self) -> Self { + Self(f32x4_div(Self::ONE.0, self.0)) + } + + /// Performs a linear interpolation between `self` and `rhs` based on the value `s`. + /// + /// When `s` is `0.0`, the result will be equal to `self`. When `s` is `1.0`, the result + /// will be equal to `rhs`. When `s` is outside of range `[0, 1]`, the result is linearly + /// extrapolated. + #[doc(alias = "mix")] + #[inline] + pub fn lerp(self, rhs: Self, s: f32) -> Self { + self + ((rhs - self) * s) + } + + /// Returns true if the absolute difference of all elements between `self` and `rhs` is + /// less than or equal to `max_abs_diff`. + /// + /// This can be used to compare if two vectors contain similar elements. It works best when + /// comparing with a known value. The `max_abs_diff` that should be used used depends on + /// the values being compared against. + /// + /// For more see + /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/). + #[inline] + pub fn abs_diff_eq(self, rhs: Self, max_abs_diff: f32) -> bool { + self.sub(rhs).abs().cmple(Self::splat(max_abs_diff)).all() + } + + /// Returns a vector with a length no less than `min` and no more than `max` + /// + /// # Panics + /// + /// Will panic if `min` is greater than `max` when `glam_assert` is enabled. + #[inline] + pub fn clamp_length(self, min: f32, max: f32) -> Self { + glam_assert!(min <= max); + let length_sq = self.length_squared(); + if length_sq < min * min { + self * (length_sq.sqrt().recip() * min) + } else if length_sq > max * max { + self * (length_sq.sqrt().recip() * max) + } else { + self + } + } + + /// Returns a vector with a length no more than `max` + pub fn clamp_length_max(self, max: f32) -> Self { + let length_sq = self.length_squared(); + if length_sq > max * max { + self * (length_sq.sqrt().recip() * max) + } else { + self + } + } + + /// Returns a vector with a length no less than `min` + pub fn clamp_length_min(self, min: f32) -> Self { + let length_sq = self.length_squared(); + if length_sq < min * min { + self * (length_sq.sqrt().recip() * min) + } else { + self + } + } + + /// Fused multiply-add. Computes `(self * a) + b` element-wise with only one rounding + /// error, yielding a more accurate result than an unfused multiply-add. + /// + /// Using `mul_add` *may* be more performant than an unfused multiply-add if the target + /// architecture has a dedicated fma CPU instruction. However, this is not always true, + /// and will be heavily dependant on designing algorithms with specific target hardware in + /// mind. + #[inline] + pub fn mul_add(self, a: Self, b: Self) -> Self { + Self::new( + self.x.mul_add(a.x, b.x), + self.y.mul_add(a.y, b.y), + self.z.mul_add(a.z, b.z), + ) + } + + /// Returns the angle (in radians) between two vectors. + /// + /// The input vectors do not need to be unit length however they must be non-zero. + #[inline] + pub fn angle_between(self, rhs: Self) -> f32 { + use crate::FloatEx; + self.dot(rhs) + .div(self.length_squared().mul(rhs.length_squared()).sqrt()) + .acos_approx() + } + + /// Returns some vector that is orthogonal to the given one. + /// + /// The input vector must be finite and non-zero. + /// + /// The output vector is not necessarily unit-length. + /// For that use [`Self::any_orthonormal_vector`] instead. + #[inline] + pub fn any_orthogonal_vector(&self) -> Self { + // This can probably be optimized + if self.x.abs() > self.y.abs() { + Self::new(-self.z, 0.0, self.x) // self.cross(Self::Y) + } else { + Self::new(0.0, self.z, -self.y) // self.cross(Self::X) + } + } + + /// Returns any unit-length vector that is orthogonal to the given one. + /// The input vector must be finite and non-zero. + /// + /// # Panics + /// + /// Will panic if `self` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn any_orthonormal_vector(&self) -> Self { + glam_assert!(self.is_normalized()); + // From https://graphics.pixar.com/library/OrthonormalB/paper.pdf + #[cfg(feature = "std")] + let sign = (1.0_f32).copysign(self.z); + #[cfg(not(feature = "std"))] + let sign = self.z.signum(); + let a = -1.0 / (sign + self.z); + let b = self.x * self.y * a; + Self::new(b, sign + self.y * self.y * a, -self.y) + } + + /// Given a unit-length vector return two other vectors that together form an orthonormal + /// basis. That is, all three vectors are orthogonal to each other and are normalized. + /// + /// # Panics + /// + /// Will panic if `self` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn any_orthonormal_pair(&self) -> (Self, Self) { + glam_assert!(self.is_normalized()); + // From https://graphics.pixar.com/library/OrthonormalB/paper.pdf + #[cfg(feature = "std")] + let sign = (1.0_f32).copysign(self.z); + #[cfg(not(feature = "std"))] + let sign = self.z.signum(); + let a = -1.0 / (sign + self.z); + let b = self.x * self.y * a; + ( + Self::new(1.0 + sign * self.x * self.x * a, sign * b, -sign * self.x), + Self::new(b, sign + self.y * self.y * a, -self.y), + ) + } + + /// Casts all elements of `self` to `f64`. + #[inline] + pub fn as_dvec3(&self) -> crate::DVec3 { + crate::DVec3::new(self.x as f64, self.y as f64, self.z as f64) + } + + /// Casts all elements of `self` to `i32`. + #[inline] + pub fn as_ivec3(&self) -> crate::IVec3 { + crate::IVec3::new(self.x as i32, self.y as i32, self.z as i32) + } + + /// Casts all elements of `self` to `u32`. + #[inline] + pub fn as_uvec3(&self) -> crate::UVec3 { + crate::UVec3::new(self.x as u32, self.y as u32, self.z as u32) + } +} + +impl Default for Vec3A { + #[inline(always)] + fn default() -> Self { + Self::ZERO + } +} + +impl PartialEq for Vec3A { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.cmpeq(*rhs).all() + } +} + +impl Div for Vec3A { + type Output = Self; + #[inline] + fn div(self, rhs: Self) -> Self { + Self(f32x4_div(self.0, rhs.0)) + } +} + +impl DivAssign for Vec3A { + #[inline] + fn div_assign(&mut self, rhs: Self) { + self.0 = f32x4_div(self.0, rhs.0); + } +} + +impl Div for Vec3A { + type Output = Self; + #[inline] + fn div(self, rhs: f32) -> Self { + Self(f32x4_div(self.0, f32x4_splat(rhs))) + } +} + +impl DivAssign for Vec3A { + #[inline] + fn div_assign(&mut self, rhs: f32) { + self.0 = f32x4_div(self.0, f32x4_splat(rhs)) + } +} + +impl Div for f32 { + type Output = Vec3A; + #[inline] + fn div(self, rhs: Vec3A) -> Vec3A { + Vec3A(f32x4_div(f32x4_splat(self), rhs.0)) + } +} + +impl Mul for Vec3A { + type Output = Self; + #[inline] + fn mul(self, rhs: Self) -> Self { + Self(f32x4_mul(self.0, rhs.0)) + } +} + +impl MulAssign for Vec3A { + #[inline] + fn mul_assign(&mut self, rhs: Self) { + self.0 = f32x4_mul(self.0, rhs.0); + } +} + +impl Mul for Vec3A { + type Output = Self; + #[inline] + fn mul(self, rhs: f32) -> Self { + Self(f32x4_mul(self.0, f32x4_splat(rhs))) + } +} + +impl MulAssign for Vec3A { + #[inline] + fn mul_assign(&mut self, rhs: f32) { + self.0 = f32x4_mul(self.0, f32x4_splat(rhs)) + } +} + +impl Mul for f32 { + type Output = Vec3A; + #[inline] + fn mul(self, rhs: Vec3A) -> Vec3A { + Vec3A(f32x4_mul(f32x4_splat(self), rhs.0)) + } +} + +impl Add for Vec3A { + type Output = Self; + #[inline] + fn add(self, rhs: Self) -> Self { + Self(f32x4_add(self.0, rhs.0)) + } +} + +impl AddAssign for Vec3A { + #[inline] + fn add_assign(&mut self, rhs: Self) { + self.0 = f32x4_add(self.0, rhs.0); + } +} + +impl Add for Vec3A { + type Output = Self; + #[inline] + fn add(self, rhs: f32) -> Self { + Self(f32x4_add(self.0, f32x4_splat(rhs))) + } +} + +impl AddAssign for Vec3A { + #[inline] + fn add_assign(&mut self, rhs: f32) { + self.0 = f32x4_add(self.0, f32x4_splat(rhs)) + } +} + +impl Add for f32 { + type Output = Vec3A; + #[inline] + fn add(self, rhs: Vec3A) -> Vec3A { + Vec3A(f32x4_add(f32x4_splat(self), rhs.0)) + } +} + +impl Sub for Vec3A { + type Output = Self; + #[inline] + fn sub(self, rhs: Self) -> Self { + Self(f32x4_sub(self.0, rhs.0)) + } +} + +impl SubAssign for Vec3A { + #[inline] + fn sub_assign(&mut self, rhs: Vec3A) { + self.0 = f32x4_sub(self.0, rhs.0); + } +} + +impl Sub for Vec3A { + type Output = Self; + #[inline] + fn sub(self, rhs: f32) -> Self { + Self(f32x4_sub(self.0, f32x4_splat(rhs))) + } +} + +impl SubAssign for Vec3A { + #[inline] + fn sub_assign(&mut self, rhs: f32) { + self.0 = f32x4_sub(self.0, f32x4_splat(rhs)) + } +} + +impl Sub for f32 { + type Output = Vec3A; + #[inline] + fn sub(self, rhs: Vec3A) -> Vec3A { + Vec3A(f32x4_sub(f32x4_splat(self), rhs.0)) + } +} + +impl Rem for Vec3A { + type Output = Self; + #[inline] + fn rem(self, rhs: Self) -> Self { + let n = f32x4_floor(f32x4_div(self.0, rhs.0)); + Self(f32x4_sub(self.0, f32x4_mul(n, rhs.0))) + } +} + +impl RemAssign for Vec3A { + #[inline] + fn rem_assign(&mut self, rhs: Self) { + *self = self.rem(rhs); + } +} + +impl Rem for Vec3A { + type Output = Self; + #[inline] + fn rem(self, rhs: f32) -> Self { + self.rem(Self::splat(rhs)) + } +} + +impl RemAssign for Vec3A { + #[inline] + fn rem_assign(&mut self, rhs: f32) { + *self = self.rem(Self::splat(rhs)); + } +} + +impl Rem for f32 { + type Output = Vec3A; + #[inline] + fn rem(self, rhs: Vec3A) -> Vec3A { + Vec3A::splat(self).rem(rhs) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsRef<[f32; 3]> for Vec3A { + #[inline] + fn as_ref(&self) -> &[f32; 3] { + unsafe { &*(self as *const Vec3A as *const [f32; 3]) } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsMut<[f32; 3]> for Vec3A { + #[inline] + fn as_mut(&mut self) -> &mut [f32; 3] { + unsafe { &mut *(self as *mut Vec3A as *mut [f32; 3]) } + } +} + +impl<'a> Sum<&'a Self> for Vec3A { + #[inline] + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, |a, &b| Self::add(a, b)) + } +} + +impl<'a> Product<&'a Self> for Vec3A { + #[inline] + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ONE, |a, &b| Self::mul(a, b)) + } +} + +impl Neg for Vec3A { + type Output = Self; + #[inline] + fn neg(self) -> Self { + Self(f32x4_neg(self.0)) + } +} + +impl Index for Vec3A { + type Output = f32; + #[inline] + fn index(&self, index: usize) -> &Self::Output { + match index { + 0 => &self.x, + 1 => &self.y, + 2 => &self.z, + _ => panic!("index out of bounds"), + } + } +} + +impl IndexMut for Vec3A { + #[inline] + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + match index { + 0 => &mut self.x, + 1 => &mut self.y, + 2 => &mut self.z, + _ => panic!("index out of bounds"), + } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Display for Vec3A { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "[{}, {}, {}]", self.x, self.y, self.z) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Debug for Vec3A { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_tuple(stringify!(Vec3A)) + .field(&self.x) + .field(&self.y) + .field(&self.z) + .finish() + } +} + +impl From for v128 { + #[inline] + fn from(t: Vec3A) -> Self { + t.0 + } +} + +impl From for Vec3A { + #[inline] + fn from(t: v128) -> Self { + Self(t) + } +} + +impl From<[f32; 3]> for Vec3A { + #[inline] + fn from(a: [f32; 3]) -> Self { + Self::new(a[0], a[1], a[2]) + } +} + +impl From for [f32; 3] { + #[inline] + fn from(v: Vec3A) -> Self { + // TODO: can probably simplify this? + use core::mem::MaybeUninit; + let mut out: MaybeUninit = MaybeUninit::uninit(); + unsafe { + v128_store(out.as_mut_ptr(), v.0); + *(&out.assume_init() as *const v128 as *const [f32; 3]) + } + } +} + +impl From<(f32, f32, f32)> for Vec3A { + #[inline] + fn from(t: (f32, f32, f32)) -> Self { + Self::new(t.0, t.1, t.2) + } +} + +impl From for (f32, f32, f32) { + #[inline] + fn from(v: Vec3A) -> Self { + // TODO: can probably simplify this + use core::mem::MaybeUninit; + let mut out: MaybeUninit = MaybeUninit::uninit(); + unsafe { + v128_store(out.as_mut_ptr(), v.0); + *(&out.assume_init() as *const v128 as *const Self) + } + } +} + +impl From for Vec3A { + #[inline] + fn from(v: Vec3) -> Self { + Self::new(v.x, v.y, v.z) + } +} + +impl From for Vec3A { + /// Creates a `Vec3A` from the `x`, `y` and `z` elements of `self` discarding `w`. + /// + /// On architectures where SIMD is supported such as SSE2 on `x86_64` this conversion is a noop. + #[inline] + fn from(v: Vec4) -> Self { + Self(v.0) + } +} + +impl From<(Vec2, f32)> for Vec3A { + #[inline] + fn from((v, z): (Vec2, f32)) -> Self { + Self::new(v.x, v.y, z) + } +} + +impl Deref for Vec3A { + type Target = crate::deref::XYZ; + #[inline] + fn deref(&self) -> &Self::Target { + unsafe { &*(self as *const Self).cast() } + } +} + +impl DerefMut for Vec3A { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { &mut *(self as *mut Self).cast() } + } +} diff --git a/src/f32/wasm32/vec4.rs b/src/f32/wasm32/vec4.rs new file mode 100644 index 00000000..e2f662c7 --- /dev/null +++ b/src/f32/wasm32/vec4.rs @@ -0,0 +1,1004 @@ +// Generated from vec.rs template. Edit the template, not the generated file. + +use crate::{BVec4A, Vec2, Vec3, Vec3A}; + +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::iter::{Product, Sum}; +use core::{f32, ops::*}; + +use core::arch::wasm32::*; + +#[cfg(not(feature = "std"))] +use num_traits::Float; + +union UnionCast { + a: [f32; 4], + v: Vec4, +} + +/// Creates a 4-dimensional vector. +#[inline(always)] +pub const fn vec4(x: f32, y: f32, z: f32, w: f32) -> Vec4 { + Vec4::new(x, y, z, w) +} + +/// A 4-dimensional vector with SIMD support. +/// +/// This type uses 16 byte aligned SIMD vector type for storage. +#[derive(Clone, Copy)] +#[repr(transparent)] +pub struct Vec4(pub(crate) v128); + +impl Vec4 { + /// All zeroes. + pub const ZERO: Self = Self::splat(0.0); + + /// All ones. + pub const ONE: Self = Self::splat(1.0); + + /// All negative ones. + pub const NEG_ONE: Self = Self::splat(-1.0); + + /// All NAN. + pub const NAN: Self = Self::splat(f32::NAN); + + /// `[1.0, 0.0, 0.0, 0.0]`: a unit-length vector pointing along the positive X axis. + pub const X: Self = Self::from_array([1.0, 0.0, 0.0, 0.0]); + + /// `[0.0, 1.0, 0.0, 0.0]`: a unit-length vector pointing along the positive Y axis. + pub const Y: Self = Self::from_array([0.0, 1.0, 0.0, 0.0]); + + /// `[0.0, 0.0, 1.0, 0.0]`: a unit-length vector pointing along the positive Z axis. + pub const Z: Self = Self::from_array([0.0, 0.0, 1.0, 0.0]); + + /// `[0.0, 0.0, 0.0, 1.0]`: a unit-length vector pointing along the positive W axis. + pub const W: Self = Self::from_array([0.0, 0.0, 0.0, 1.0]); + + /// The unit axes. + pub const AXES: [Self; 4] = [Self::X, Self::Y, Self::Z, Self::W]; + + /// Creates a new vector. + #[inline(always)] + pub const fn new(x: f32, y: f32, z: f32, w: f32) -> Self { + Self(f32x4(x, y, z, w)) + } + + /// Creates a vector with all elements set to `v`. + #[inline] + pub const fn splat(v: f32) -> Self { + unsafe { UnionCast { a: [v; 4] }.v } + } + + /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use + /// for each element of `self`. + /// + /// A true element in the mask uses the corresponding element from `if_true`, and false + /// uses the element from `if_false`. + #[inline] + pub fn select(mask: BVec4A, if_true: Self, if_false: Self) -> Self { + Self(v128_bitselect(if_true.0, if_false.0, mask.0)) + } + + /// Creates a new vector from an array. + #[inline] + pub const fn from_array(a: [f32; 4]) -> Self { + Self::new(a[0], a[1], a[2], a[3]) + } + + /// `[x, y, z, w]` + #[inline] + pub const fn to_array(&self) -> [f32; 4] { + unsafe { *(self as *const Vec4 as *const [f32; 4]) } + } + + /// Creates a vector from the first N values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than N elements long. + #[inline] + pub const fn from_slice(slice: &[f32]) -> Self { + Self::new(slice[0], slice[1], slice[2], slice[3]) + } + + /// Writes the elements of `self` to the first 4 elements in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than N elements long. + #[inline] + pub fn write_to_slice(self, slice: &mut [f32]) { + slice[0] = self.x; + slice[1] = self.y; + slice[2] = self.z; + slice[3] = self.w; + } + + /// Creates a 2D vector from the `x`, `y` and `z` elements of `self`, discarding `w`. + /// + /// Truncation to `Vec3` may also be performed by using `self.xyz()` or `Vec3::from()`. + /// + /// To truncate to `Vec3A` use `Vec3A::from()`. + #[inline] + pub fn truncate(self) -> Vec3 { + use crate::swizzles::Vec4Swizzles; + self.xyz() + } + + /// Computes the dot product of `self` and `rhs`. + #[inline] + pub fn dot(self, rhs: Self) -> f32 { + crate::wasm32::dot4(self.0, rhs.0) + } + + /// Returns a vector containing the minimum values for each element of `self` and `rhs`. + /// + /// In other words this computes `[self.x.min(rhs.x), self.y.min(rhs.y), ..]`. + #[inline] + pub fn min(self, rhs: Self) -> Self { + Self(f32x4_pmin(self.0, rhs.0)) + } + + /// Returns a vector containing the maximum values for each element of `self` and `rhs`. + /// + /// In other words this computes `[self.x.max(rhs.x), self.y.max(rhs.y), ..]`. + #[inline] + pub fn max(self, rhs: Self) -> Self { + Self(f32x4_pmax(self.0, rhs.0)) + } + + /// Component-wise clamping of values, similar to [`f32::clamp`]. + /// + /// Each element in `min` must be less-or-equal to the corresponding element in `max`. + /// + /// # Panics + /// + /// Will panic if `min` is greater than `max` when `glam_assert` is enabled. + #[inline] + pub fn clamp(self, min: Self, max: Self) -> Self { + glam_assert!(min.cmple(max).all(), "clamp: expected min <= max"); + self.max(min).min(max) + } + + /// Returns the horizontal minimum of `self`. + /// + /// In other words this computes `min(x, y, ..)`. + #[inline] + pub fn min_element(self) -> f32 { + let v = self.0; + let v = f32x4_pmin(v, i32x4_shuffle::<2, 3, 0, 0>(v, v)); + let v = f32x4_pmin(v, i32x4_shuffle::<1, 0, 0, 0>(v, v)); + f32x4_extract_lane::<0>(v) + } + + /// Returns the horizontal maximum of `self`. + /// + /// In other words this computes `max(x, y, ..)`. + #[inline] + pub fn max_element(self) -> f32 { + let v = self.0; + let v = f32x4_pmax(v, i32x4_shuffle::<2, 3, 0, 0>(v, v)); + let v = f32x4_pmax(v, i32x4_shuffle::<1, 0, 0, 0>(v, v)); + f32x4_extract_lane::<0>(v) + } + + /// Returns a vector mask containing the result of a `==` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words, this computes `[self.x == rhs.x, self.y == rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpeq(self, rhs: Self) -> BVec4A { + BVec4A(f32x4_eq(self.0, rhs.0)) + } + + /// Returns a vector mask containing the result of a `!=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x != rhs.x, self.y != rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpne(self, rhs: Self) -> BVec4A { + BVec4A(f32x4_ne(self.0, rhs.0)) + } + + /// Returns a vector mask containing the result of a `>=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x >= rhs.x, self.y >= rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpge(self, rhs: Self) -> BVec4A { + BVec4A(f32x4_ge(self.0, rhs.0)) + } + + /// Returns a vector mask containing the result of a `>` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x > rhs.x, self.y > rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpgt(self, rhs: Self) -> BVec4A { + BVec4A(f32x4_gt(self.0, rhs.0)) + } + + /// Returns a vector mask containing the result of a `<=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x <= rhs.x, self.y <= rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmple(self, rhs: Self) -> BVec4A { + BVec4A(f32x4_le(self.0, rhs.0)) + } + + /// Returns a vector mask containing the result of a `<` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x < rhs.x, self.y < rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmplt(self, rhs: Self) -> BVec4A { + BVec4A(f32x4_lt(self.0, rhs.0)) + } + + /// Returns a vector containing the absolute value of each element of `self`. + #[inline] + pub fn abs(self) -> Self { + Self(f32x4_abs(self.0)) + } + + /// Returns a vector with elements representing the sign of `self`. + /// + /// - `1.0` if the number is positive, `+0.0` or `INFINITY` + /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` + /// - `NAN` if the number is `NAN` + #[inline] + pub fn signum(self) -> Self { + let mask = self.cmpge(Self::ZERO); + let result = Self::select(mask, Self::ONE, Self::NEG_ONE); + let mask = self.is_nan_mask(); + Self::select(mask, self, result) + } + + /// Returns `true` if, and only if, all elements are finite. If any element is either + /// `NaN`, positive or negative infinity, this will return `false`. + #[inline] + pub fn is_finite(self) -> bool { + self.x.is_finite() && self.y.is_finite() && self.z.is_finite() && self.w.is_finite() + } + + /// Returns `true` if any elements are `NaN`. + #[inline] + pub fn is_nan(self) -> bool { + self.is_nan_mask().any() + } + + /// Performs `is_nan` on each element of self, returning a vector mask of the results. + /// + /// In other words, this computes `[x.is_nan(), y.is_nan(), z.is_nan(), w.is_nan()]`. + #[inline] + pub fn is_nan_mask(self) -> BVec4A { + BVec4A(f32x4_ne(self.0, self.0)) + } + + /// Computes the length of `self`. + #[doc(alias = "magnitude")] + #[inline] + pub fn length(self) -> f32 { + let dot = crate::wasm32::dot4_in_x(self.0, self.0); + f32x4_extract_lane::<0>(f32x4_sqrt(dot)) + } + + /// Computes the squared length of `self`. + /// + /// This is faster than `length()` as it avoids a square root operation. + #[doc(alias = "magnitude2")] + #[inline] + pub fn length_squared(self) -> f32 { + self.dot(self) + } + + /// Computes `1.0 / length()`. + /// + /// For valid results, `self` must _not_ be of length zero. + #[inline] + pub fn length_recip(self) -> f32 { + let dot = crate::wasm32::dot4_in_x(self.0, self.0); + f32x4_extract_lane::<0>(f32x4_div(Self::ONE.0, f32x4_sqrt(dot))) + } + + /// Computes the Euclidean distance between two points in space. + #[inline] + pub fn distance(self, rhs: Self) -> f32 { + (self - rhs).length() + } + + /// Compute the squared euclidean distance between two points in space. + #[inline] + pub fn distance_squared(self, rhs: Self) -> f32 { + (self - rhs).length_squared() + } + + /// Returns `self` normalized to length 1.0. + /// + /// For valid results, `self` must _not_ be of length zero, nor very close to zero. + /// + /// See also [`Self::try_normalize`] and [`Self::normalize_or_zero`]. + /// + /// Panics + /// + /// Will panic if `self` is zero length when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn normalize(self) -> Self { + let length = f32x4_sqrt(crate::wasm32::dot4_into_v128(self.0, self.0)); + #[allow(clippy::let_and_return)] + let normalized = Self(f32x4_div(self.0, length)); + glam_assert!(normalized.is_finite()); + normalized + } + + /// Returns `self` normalized to length 1.0 if possible, else returns `None`. + /// + /// In particular, if the input is zero (or very close to zero), or non-finite, + /// the result of this operation will be `None`. + /// + /// See also [`Self::normalize_or_zero`]. + #[must_use] + #[inline] + pub fn try_normalize(self) -> Option { + let rcp = self.length_recip(); + if rcp.is_finite() && rcp > 0.0 { + Some(self * rcp) + } else { + None + } + } + + /// Returns `self` normalized to length 1.0 if possible, else returns zero. + /// + /// In particular, if the input is zero (or very close to zero), or non-finite, + /// the result of this operation will be zero. + /// + /// See also [`Self::try_normalize`]. + #[must_use] + #[inline] + pub fn normalize_or_zero(self) -> Self { + let rcp = self.length_recip(); + if rcp.is_finite() && rcp > 0.0 { + self * rcp + } else { + Self::ZERO + } + } + + /// Returns whether `self` is length `1.0` or not. + /// + /// Uses a precision threshold of `1e-6`. + #[inline] + pub fn is_normalized(self) -> bool { + // TODO: do something with epsilon + (self.length_squared() - 1.0).abs() <= 1e-4 + } + + /// Returns the vector projection of `self` onto `rhs`. + /// + /// `rhs` must be of non-zero length. + /// + /// # Panics + /// + /// Will panic if `rhs` is zero length when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn project_onto(self, rhs: Self) -> Self { + let other_len_sq_rcp = rhs.dot(rhs).recip(); + glam_assert!(other_len_sq_rcp.is_finite()); + rhs * self.dot(rhs) * other_len_sq_rcp + } + + /// Returns the vector rejection of `self` from `rhs`. + /// + /// The vector rejection is the vector perpendicular to the projection of `self` onto + /// `rhs`, in rhs words the result of `self - self.project_onto(rhs)`. + /// + /// `rhs` must be of non-zero length. + /// + /// # Panics + /// + /// Will panic if `rhs` has a length of zero when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn reject_from(self, rhs: Self) -> Self { + self - self.project_onto(rhs) + } + + /// Returns the vector projection of `self` onto `rhs`. + /// + /// `rhs` must be normalized. + /// + /// # Panics + /// + /// Will panic if `rhs` is not normalized when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn project_onto_normalized(self, rhs: Self) -> Self { + glam_assert!(rhs.is_normalized()); + rhs * self.dot(rhs) + } + + /// Returns the vector rejection of `self` from `rhs`. + /// + /// The vector rejection is the vector perpendicular to the projection of `self` onto + /// `rhs`, in rhs words the result of `self - self.project_onto(rhs)`. + /// + /// `rhs` must be normalized. + /// + /// # Panics + /// + /// Will panic if `rhs` is not normalized when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn reject_from_normalized(self, rhs: Self) -> Self { + self - self.project_onto_normalized(rhs) + } + + /// Returns a vector containing the nearest integer to a number for each element of `self`. + /// Round half-way cases away from 0.0. + #[inline] + pub fn round(self) -> Self { + Self(f32x4_nearest(self.0)) + } + + /// Returns a vector containing the largest integer less than or equal to a number for each + /// element of `self`. + #[inline] + pub fn floor(self) -> Self { + Self(f32x4_floor(self.0)) + } + + /// Returns a vector containing the smallest integer greater than or equal to a number for + /// each element of `self`. + #[inline] + pub fn ceil(self) -> Self { + Self(f32x4_ceil(self.0)) + } + + /// Returns a vector containing the fractional part of the vector, e.g. `self - + /// self.floor()`. + /// + /// Note that this is fast but not precise for large numbers. + #[inline] + pub fn fract(self) -> Self { + self - self.floor() + } + + /// Returns a vector containing `e^self` (the exponential function) for each element of + /// `self`. + #[inline] + pub fn exp(self) -> Self { + Self::new(self.x.exp(), self.y.exp(), self.z.exp(), self.w.exp()) + } + + /// Returns a vector containing each element of `self` raised to the power of `n`. + #[inline] + pub fn powf(self, n: f32) -> Self { + Self::new( + self.x.powf(n), + self.y.powf(n), + self.z.powf(n), + self.w.powf(n), + ) + } + + /// Returns a vector containing the reciprocal `1.0/n` of each element of `self`. + #[inline] + pub fn recip(self) -> Self { + Self(f32x4_div(Self::ONE.0, self.0)) + } + + /// Performs a linear interpolation between `self` and `rhs` based on the value `s`. + /// + /// When `s` is `0.0`, the result will be equal to `self`. When `s` is `1.0`, the result + /// will be equal to `rhs`. When `s` is outside of range `[0, 1]`, the result is linearly + /// extrapolated. + #[doc(alias = "mix")] + #[inline] + pub fn lerp(self, rhs: Self, s: f32) -> Self { + self + ((rhs - self) * s) + } + + /// Returns true if the absolute difference of all elements between `self` and `rhs` is + /// less than or equal to `max_abs_diff`. + /// + /// This can be used to compare if two vectors contain similar elements. It works best when + /// comparing with a known value. The `max_abs_diff` that should be used used depends on + /// the values being compared against. + /// + /// For more see + /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/). + #[inline] + pub fn abs_diff_eq(self, rhs: Self, max_abs_diff: f32) -> bool { + self.sub(rhs).abs().cmple(Self::splat(max_abs_diff)).all() + } + + /// Returns a vector with a length no less than `min` and no more than `max` + /// + /// # Panics + /// + /// Will panic if `min` is greater than `max` when `glam_assert` is enabled. + #[inline] + pub fn clamp_length(self, min: f32, max: f32) -> Self { + glam_assert!(min <= max); + let length_sq = self.length_squared(); + if length_sq < min * min { + self * (length_sq.sqrt().recip() * min) + } else if length_sq > max * max { + self * (length_sq.sqrt().recip() * max) + } else { + self + } + } + + /// Returns a vector with a length no more than `max` + pub fn clamp_length_max(self, max: f32) -> Self { + let length_sq = self.length_squared(); + if length_sq > max * max { + self * (length_sq.sqrt().recip() * max) + } else { + self + } + } + + /// Returns a vector with a length no less than `min` + pub fn clamp_length_min(self, min: f32) -> Self { + let length_sq = self.length_squared(); + if length_sq < min * min { + self * (length_sq.sqrt().recip() * min) + } else { + self + } + } + + /// Fused multiply-add. Computes `(self * a) + b` element-wise with only one rounding + /// error, yielding a more accurate result than an unfused multiply-add. + /// + /// Using `mul_add` *may* be more performant than an unfused multiply-add if the target + /// architecture has a dedicated fma CPU instruction. However, this is not always true, + /// and will be heavily dependant on designing algorithms with specific target hardware in + /// mind. + #[inline] + pub fn mul_add(self, a: Self, b: Self) -> Self { + Self::new( + self.x.mul_add(a.x, b.x), + self.y.mul_add(a.y, b.y), + self.z.mul_add(a.z, b.z), + self.w.mul_add(a.w, b.w), + ) + } + + /// Casts all elements of `self` to `f64`. + #[inline] + pub fn as_dvec4(&self) -> crate::DVec4 { + crate::DVec4::new(self.x as f64, self.y as f64, self.z as f64, self.w as f64) + } + + /// Casts all elements of `self` to `i32`. + #[inline] + pub fn as_ivec4(&self) -> crate::IVec4 { + crate::IVec4::new(self.x as i32, self.y as i32, self.z as i32, self.w as i32) + } + + /// Casts all elements of `self` to `u32`. + #[inline] + pub fn as_uvec4(&self) -> crate::UVec4 { + crate::UVec4::new(self.x as u32, self.y as u32, self.z as u32, self.w as u32) + } +} + +impl Default for Vec4 { + #[inline(always)] + fn default() -> Self { + Self::ZERO + } +} + +impl PartialEq for Vec4 { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.cmpeq(*rhs).all() + } +} + +impl Div for Vec4 { + type Output = Self; + #[inline] + fn div(self, rhs: Self) -> Self { + Self(f32x4_div(self.0, rhs.0)) + } +} + +impl DivAssign for Vec4 { + #[inline] + fn div_assign(&mut self, rhs: Self) { + self.0 = f32x4_div(self.0, rhs.0); + } +} + +impl Div for Vec4 { + type Output = Self; + #[inline] + fn div(self, rhs: f32) -> Self { + Self(f32x4_div(self.0, f32x4_splat(rhs))) + } +} + +impl DivAssign for Vec4 { + #[inline] + fn div_assign(&mut self, rhs: f32) { + self.0 = f32x4_div(self.0, f32x4_splat(rhs)) + } +} + +impl Div for f32 { + type Output = Vec4; + #[inline] + fn div(self, rhs: Vec4) -> Vec4 { + Vec4(f32x4_div(f32x4_splat(self), rhs.0)) + } +} + +impl Mul for Vec4 { + type Output = Self; + #[inline] + fn mul(self, rhs: Self) -> Self { + Self(f32x4_mul(self.0, rhs.0)) + } +} + +impl MulAssign for Vec4 { + #[inline] + fn mul_assign(&mut self, rhs: Self) { + self.0 = f32x4_mul(self.0, rhs.0); + } +} + +impl Mul for Vec4 { + type Output = Self; + #[inline] + fn mul(self, rhs: f32) -> Self { + Self(f32x4_mul(self.0, f32x4_splat(rhs))) + } +} + +impl MulAssign for Vec4 { + #[inline] + fn mul_assign(&mut self, rhs: f32) { + self.0 = f32x4_mul(self.0, f32x4_splat(rhs)) + } +} + +impl Mul for f32 { + type Output = Vec4; + #[inline] + fn mul(self, rhs: Vec4) -> Vec4 { + Vec4(f32x4_mul(f32x4_splat(self), rhs.0)) + } +} + +impl Add for Vec4 { + type Output = Self; + #[inline] + fn add(self, rhs: Self) -> Self { + Self(f32x4_add(self.0, rhs.0)) + } +} + +impl AddAssign for Vec4 { + #[inline] + fn add_assign(&mut self, rhs: Self) { + self.0 = f32x4_add(self.0, rhs.0); + } +} + +impl Add for Vec4 { + type Output = Self; + #[inline] + fn add(self, rhs: f32) -> Self { + Self(f32x4_add(self.0, f32x4_splat(rhs))) + } +} + +impl AddAssign for Vec4 { + #[inline] + fn add_assign(&mut self, rhs: f32) { + self.0 = f32x4_add(self.0, f32x4_splat(rhs)) + } +} + +impl Add for f32 { + type Output = Vec4; + #[inline] + fn add(self, rhs: Vec4) -> Vec4 { + Vec4(f32x4_add(f32x4_splat(self), rhs.0)) + } +} + +impl Sub for Vec4 { + type Output = Self; + #[inline] + fn sub(self, rhs: Self) -> Self { + Self(f32x4_sub(self.0, rhs.0)) + } +} + +impl SubAssign for Vec4 { + #[inline] + fn sub_assign(&mut self, rhs: Vec4) { + self.0 = f32x4_sub(self.0, rhs.0); + } +} + +impl Sub for Vec4 { + type Output = Self; + #[inline] + fn sub(self, rhs: f32) -> Self { + Self(f32x4_sub(self.0, f32x4_splat(rhs))) + } +} + +impl SubAssign for Vec4 { + #[inline] + fn sub_assign(&mut self, rhs: f32) { + self.0 = f32x4_sub(self.0, f32x4_splat(rhs)) + } +} + +impl Sub for f32 { + type Output = Vec4; + #[inline] + fn sub(self, rhs: Vec4) -> Vec4 { + Vec4(f32x4_sub(f32x4_splat(self), rhs.0)) + } +} + +impl Rem for Vec4 { + type Output = Self; + #[inline] + fn rem(self, rhs: Self) -> Self { + let n = f32x4_floor(f32x4_div(self.0, rhs.0)); + Self(f32x4_sub(self.0, f32x4_mul(n, rhs.0))) + } +} + +impl RemAssign for Vec4 { + #[inline] + fn rem_assign(&mut self, rhs: Self) { + *self = self.rem(rhs); + } +} + +impl Rem for Vec4 { + type Output = Self; + #[inline] + fn rem(self, rhs: f32) -> Self { + self.rem(Self::splat(rhs)) + } +} + +impl RemAssign for Vec4 { + #[inline] + fn rem_assign(&mut self, rhs: f32) { + *self = self.rem(Self::splat(rhs)); + } +} + +impl Rem for f32 { + type Output = Vec4; + #[inline] + fn rem(self, rhs: Vec4) -> Vec4 { + Vec4::splat(self).rem(rhs) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsRef<[f32; 4]> for Vec4 { + #[inline] + fn as_ref(&self) -> &[f32; 4] { + unsafe { &*(self as *const Vec4 as *const [f32; 4]) } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsMut<[f32; 4]> for Vec4 { + #[inline] + fn as_mut(&mut self) -> &mut [f32; 4] { + unsafe { &mut *(self as *mut Vec4 as *mut [f32; 4]) } + } +} + +impl<'a> Sum<&'a Self> for Vec4 { + #[inline] + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, |a, &b| Self::add(a, b)) + } +} + +impl<'a> Product<&'a Self> for Vec4 { + #[inline] + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ONE, |a, &b| Self::mul(a, b)) + } +} + +impl Neg for Vec4 { + type Output = Self; + #[inline] + fn neg(self) -> Self { + Self(f32x4_neg(self.0)) + } +} + +impl Index for Vec4 { + type Output = f32; + #[inline] + fn index(&self, index: usize) -> &Self::Output { + match index { + 0 => &self.x, + 1 => &self.y, + 2 => &self.z, + 3 => &self.w, + _ => panic!("index out of bounds"), + } + } +} + +impl IndexMut for Vec4 { + #[inline] + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + match index { + 0 => &mut self.x, + 1 => &mut self.y, + 2 => &mut self.z, + 3 => &mut self.w, + _ => panic!("index out of bounds"), + } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Display for Vec4 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "[{}, {}, {}, {}]", self.x, self.y, self.z, self.w) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Debug for Vec4 { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_tuple(stringify!(Vec4)) + .field(&self.x) + .field(&self.y) + .field(&self.z) + .field(&self.w) + .finish() + } +} + +impl From for v128 { + #[inline] + fn from(t: Vec4) -> Self { + t.0 + } +} + +impl From for Vec4 { + #[inline] + fn from(t: v128) -> Self { + Self(t) + } +} + +impl From<[f32; 4]> for Vec4 { + #[inline] + fn from(a: [f32; 4]) -> Self { + Self::new(a[0], a[1], a[2], a[3]) + } +} + +impl From for [f32; 4] { + #[inline] + fn from(v: Vec4) -> Self { + // TODO: can probably simplify this? + use core::mem::MaybeUninit; + let mut out: MaybeUninit = MaybeUninit::uninit(); + unsafe { + v128_store(out.as_mut_ptr(), v.0); + *(&out.assume_init() as *const v128 as *const [f32; 4]) + } + } +} + +impl From<(f32, f32, f32, f32)> for Vec4 { + #[inline] + fn from(t: (f32, f32, f32, f32)) -> Self { + Self::new(t.0, t.1, t.2, t.3) + } +} + +impl From for (f32, f32, f32, f32) { + #[inline] + fn from(v: Vec4) -> Self { + // TODO: can probably simplify this + use core::mem::MaybeUninit; + let mut out: MaybeUninit = MaybeUninit::uninit(); + unsafe { + v128_store(out.as_mut_ptr(), v.0); + *(&out.assume_init() as *const v128 as *const Self) + } + } +} + +impl From<(Vec3A, f32)> for Vec4 { + #[inline] + fn from((v, w): (Vec3A, f32)) -> Self { + v.extend(w) + } +} + +impl From<(f32, Vec3A)> for Vec4 { + #[inline] + fn from((x, v): (f32, Vec3A)) -> Self { + Self::new(x, v.x, v.y, v.z) + } +} + +impl From<(Vec3, f32)> for Vec4 { + #[inline] + fn from((v, w): (Vec3, f32)) -> Self { + Self::new(v.x, v.y, v.z, w) + } +} + +impl From<(f32, Vec3)> for Vec4 { + #[inline] + fn from((x, v): (f32, Vec3)) -> Self { + Self::new(x, v.x, v.y, v.z) + } +} + +impl From<(Vec2, f32, f32)> for Vec4 { + #[inline] + fn from((v, z, w): (Vec2, f32, f32)) -> Self { + Self::new(v.x, v.y, z, w) + } +} + +impl From<(Vec2, Vec2)> for Vec4 { + #[inline] + fn from((v, u): (Vec2, Vec2)) -> Self { + Self::new(v.x, v.y, u.x, u.y) + } +} + +impl Deref for Vec4 { + type Target = crate::deref::XYZW; + #[inline] + fn deref(&self) -> &Self::Target { + unsafe { &*(self as *const Self).cast() } + } +} + +impl DerefMut for Vec4 { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { &mut *(self as *mut Self).cast() } + } +} diff --git a/src/f64.rs b/src/f64.rs new file mode 100644 index 00000000..aea4ab35 --- /dev/null +++ b/src/f64.rs @@ -0,0 +1,89 @@ +mod daffine2; +mod daffine3; +mod dmat2; +mod dmat3; +mod dmat4; +mod dquat; +mod dvec2; +mod dvec3; +mod dvec4; + +pub use daffine2::DAffine2; +pub use daffine3::DAffine3; +pub use dmat2::{dmat2, DMat2}; +pub use dmat3::{dmat3, DMat3}; +pub use dmat4::{dmat4, DMat4}; +pub use dquat::{dquat, DQuat}; +pub use dvec2::{dvec2, DVec2}; +pub use dvec3::{dvec3, DVec3}; +pub use dvec4::{dvec4, DVec4}; + +mod const_test_daffine2 { + const_assert_eq!( + core::mem::align_of::(), + core::mem::align_of::() + ); + const_assert_eq!(48, core::mem::size_of::()); +} + +mod const_test_dmat2 { + const_assert_eq!( + core::mem::align_of::(), + core::mem::align_of::() + ); + const_assert_eq!(32, core::mem::size_of::()); +} + +mod const_test_dmat3 { + const_assert_eq!( + core::mem::align_of::(), + core::mem::align_of::() + ); + const_assert_eq!(72, core::mem::size_of::()); +} + +mod const_test_dmat4 { + const_assert_eq!( + core::mem::align_of::(), + core::mem::align_of::() + ); + const_assert_eq!(128, core::mem::size_of::()); +} + +mod const_test_dquat { + const_assert_eq!( + core::mem::align_of::(), + core::mem::align_of::() + ); + const_assert_eq!(32, core::mem::size_of::()); +} + +mod const_test_dvec2 { + #[cfg(not(feature = "cuda"))] + const_assert_eq!( + core::mem::align_of::(), + core::mem::align_of::() + ); + #[cfg(feature = "cuda")] + const_assert_eq!(16, core::mem::align_of::()); + const_assert_eq!(16, core::mem::size_of::()); +} + +mod const_test_dvec3 { + const_assert_eq!( + core::mem::align_of::(), + core::mem::align_of::() + ); + const_assert_eq!(24, core::mem::size_of::()); +} + +mod const_test_dvec4 { + #[cfg(not(feature = "cuda"))] + const_assert_eq!( + core::mem::align_of::(), + core::mem::align_of::() + ); + #[cfg(feature = "cuda")] + const_assert_eq!(16, core::mem::align_of::()); + const_assert_eq!(32, core::mem::size_of::()); +} diff --git a/src/f64/daffine2.rs b/src/f64/daffine2.rs new file mode 100644 index 00000000..71e7ca2e --- /dev/null +++ b/src/f64/daffine2.rs @@ -0,0 +1,406 @@ +// Generated from affine.rs template. Edit the template, not the generated file. + +use crate::{DMat2, DMat3, DVec2}; +use core::ops::{Add, Deref, DerefMut, Mul, Sub}; + +/// A 2D affine transform, which can represent translation, rotation, scaling and shear. +#[derive(Copy, Clone)] +#[repr(C)] +pub struct DAffine2 { + pub matrix2: DMat2, + pub translation: DVec2, +} + +impl DAffine2 { + /// The degenerate zero transform. + /// + /// This transforms any finite vector and point to zero. + /// The zero transform is non-invertible. + pub const ZERO: Self = Self { + matrix2: DMat2::ZERO, + translation: DVec2::ZERO, + }; + + /// The identity transform. + /// + /// Multiplying a vector with this returns the same vector. + pub const IDENTITY: Self = Self { + matrix2: DMat2::IDENTITY, + translation: DVec2::ZERO, + }; + + /// All NAN:s. + pub const NAN: Self = Self { + matrix2: DMat2::NAN, + translation: DVec2::NAN, + }; + + /// Creates an affine transform from three column vectors. + #[inline(always)] + pub const fn from_cols(x_axis: DVec2, y_axis: DVec2, z_axis: DVec2) -> Self { + Self { + matrix2: DMat2::from_cols(x_axis, y_axis), + translation: z_axis, + } + } + + /// Creates an affine transform from a `[f64; 6]` array stored in column major order. + /// If your data is stored in row major you will need to `transpose` the returned + /// matrix. + #[inline] + pub fn from_cols_array(m: &[f64; 6]) -> Self { + Self { + matrix2: DMat2::from_cols_slice(&m[0..4]), + translation: DVec2::from_slice(&m[4..6]), + } + } + + /// Creates a `[f64; 6]` array storing data in column major order. + /// If you require data in row major order `transpose` the matrix first. + #[inline] + pub fn to_cols_array(&self) -> [f64; 6] { + let x = &self.matrix2.x_axis; + let y = &self.matrix2.y_axis; + let z = &self.translation; + [x.x, x.y, y.x, y.y, z.x, z.y] + } + + /// Creates an affine transform from a `[[f64; 2]; 3]` + /// 2D array stored in column major order. + /// If your data is in row major order you will need to `transpose` the returned + /// matrix. + #[inline] + pub fn from_cols_array_2d(m: &[[f64; 2]; 3]) -> Self { + Self { + matrix2: DMat2::from_cols(m[0].into(), m[1].into()), + translation: m[2].into(), + } + } + + /// Creates a `[[f64; 2]; 3]` 2D array storing data in + /// column major order. + /// If you require data in row major order `transpose` the matrix first. + #[inline] + pub fn to_cols_array_2d(&self) -> [[f64; 2]; 3] { + [ + self.matrix2.x_axis.into(), + self.matrix2.y_axis.into(), + self.translation.into(), + ] + } + + /// Creates an affine transform from the first 6 values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 6 elements long. + #[inline] + pub fn from_cols_slice(slice: &[f64]) -> Self { + Self { + matrix2: DMat2::from_cols_slice(&slice[0..4]), + translation: DVec2::from_slice(&slice[4..6]), + } + } + + /// Writes the columns of `self` to the first 6 elements in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 6 elements long. + #[inline] + pub fn write_cols_to_slice(self, slice: &mut [f64]) { + self.matrix2.write_cols_to_slice(&mut slice[0..4]); + self.translation.write_to_slice(&mut slice[4..6]); + } + + /// Creates an affine transform that changes scale. + /// Note that if any scale is zero the transform will be non-invertible. + #[inline] + pub fn from_scale(scale: DVec2) -> Self { + Self { + matrix2: DMat2::from_diagonal(scale), + translation: DVec2::ZERO, + } + } + + /// Creates an affine transform from the given rotation `angle`. + #[inline] + pub fn from_angle(angle: f64) -> Self { + Self { + matrix2: DMat2::from_angle(angle), + translation: DVec2::ZERO, + } + } + + /// Creates an affine transformation from the given 2D `translation`. + #[inline] + pub fn from_translation(translation: DVec2) -> Self { + Self { + matrix2: DMat2::IDENTITY, + translation, + } + } + + /// Creates an affine transform from a 2x2 matrix (expressing scale, shear and rotation) + #[inline] + pub fn from_mat2(matrix2: DMat2) -> Self { + Self { + matrix2, + translation: DVec2::ZERO, + } + } + + /// Creates an affine transform from a 2x2 matrix (expressing scale, shear and rotation) and a + /// translation vector. + /// + /// Equivalent to + /// `DAffine2::from_translation(translation) * DAffine2::from_mat2(mat2)` + #[inline] + pub fn from_mat2_translation(matrix2: DMat2, translation: DVec2) -> Self { + Self { + matrix2, + translation, + } + } + + /// Creates an affine transform from the given 2D `scale`, rotation `angle` (in radians) and + /// `translation`. + /// + /// Equivalent to `DAffine2::from_translation(translation) * + /// DAffine2::from_angle(angle) * DAffine2::from_scale(scale)` + #[inline] + pub fn from_scale_angle_translation(scale: DVec2, angle: f64, translation: DVec2) -> Self { + let rotation = DMat2::from_angle(angle); + Self { + matrix2: DMat2::from_cols(rotation.x_axis * scale.x, rotation.y_axis * scale.y), + translation, + } + } + + /// Creates an affine transform from the given 2D rotation `angle` (in radians) and + /// `translation`. + /// + /// Equivalent to `DAffine2::from_translation(translation) * DAffine2::from_angle(angle)` + #[inline] + pub fn from_angle_translation(angle: f64, translation: DVec2) -> Self { + Self { + matrix2: DMat2::from_angle(angle), + translation, + } + } + + /// The given `DMat3` must be an affine transform, + #[inline] + pub fn from_mat3(m: DMat3) -> Self { + use crate::swizzles::Vec3Swizzles; + Self { + matrix2: DMat2::from_cols(m.x_axis.xy(), m.y_axis.xy()), + translation: m.z_axis.xy(), + } + } + + /// Transforms the given 2D point, applying shear, scale, rotation and translation. + #[inline] + pub fn transform_point2(&self, rhs: DVec2) -> DVec2 { + self.matrix2 * rhs + self.translation + } + + /// Transforms the given 2D vector, applying shear, scale and rotation (but NOT + /// translation). + /// + /// To also apply translation, use [`Self::transform_point2`] instead. + #[inline] + pub fn transform_vector2(&self, rhs: DVec2) -> DVec2 { + self.matrix2 * rhs + } + + /// Returns `true` if, and only if, all elements are finite. + /// + /// If any element is either `NaN`, positive or negative infinity, this will return + /// `false`. + #[inline] + pub fn is_finite(&self) -> bool { + self.matrix2.is_finite() && self.translation.is_finite() + } + + /// Returns `true` if any elements are `NaN`. + #[inline] + pub fn is_nan(&self) -> bool { + self.matrix2.is_nan() || self.translation.is_nan() + } + + /// Returns true if the absolute difference of all elements between `self` and `rhs` + /// is less than or equal to `max_abs_diff`. + /// + /// This can be used to compare if two 3x4 matrices contain similar elements. It works + /// best when comparing with a known value. The `max_abs_diff` that should be used used + /// depends on the values being compared against. + /// + /// For more see + /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/). + #[inline] + pub fn abs_diff_eq(&self, rhs: Self, max_abs_diff: f64) -> bool { + self.matrix2.abs_diff_eq(rhs.matrix2, max_abs_diff) + && self.translation.abs_diff_eq(rhs.translation, max_abs_diff) + } + + /// Return the inverse of this transform. + /// + /// Note that if the transform is not invertible the result will be invalid. + #[must_use] + #[inline] + pub fn inverse(&self) -> Self { + let matrix2 = self.matrix2.inverse(); + // transform negative translation by the matrix inverse: + let translation = -(matrix2 * self.translation); + + Self { + matrix2, + translation, + } + } +} + +impl Default for DAffine2 { + #[inline(always)] + fn default() -> Self { + Self::IDENTITY + } +} + +impl Deref for DAffine2 { + type Target = crate::deref::Columns3; + #[inline(always)] + fn deref(&self) -> &Self::Target { + unsafe { &*(self as *const Self as *const Self::Target) } + } +} + +impl DerefMut for DAffine2 { + #[inline(always)] + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { &mut *(self as *mut Self as *mut Self::Target) } + } +} + +impl PartialEq for DAffine2 { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.matrix2.eq(&rhs.matrix2) && self.translation.eq(&rhs.translation) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl core::fmt::Debug for DAffine2 { + fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + fmt.debug_struct(stringify!(DAffine2)) + .field("matrix2", &self.matrix2) + .field("translation", &self.translation) + .finish() + } +} + +#[cfg(not(target_arch = "spirv"))] +impl core::fmt::Display for DAffine2 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!( + f, + "[{}, {}, {}]", + self.matrix2.x_axis, self.matrix2.y_axis, self.translation + ) + } +} + +impl<'a> core::iter::Product<&'a Self> for DAffine2 { + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::IDENTITY, |a, &b| a * b) + } +} + +impl Mul for DAffine2 { + type Output = DAffine2; + + #[inline] + fn mul(self, rhs: DAffine2) -> Self::Output { + Self { + matrix2: self.matrix2 * rhs.matrix2, + translation: self.matrix2 * rhs.translation + self.translation, + } + } +} + +impl Mul for f64 { + type Output = DAffine2; + #[inline] + fn mul(self, rhs: DAffine2) -> Self::Output { + DAffine2 { + matrix2: self * rhs.matrix2, + translation: self * rhs.translation, + } + } +} + +impl Mul for DAffine2 { + type Output = Self; + #[inline] + fn mul(self, rhs: f64) -> Self::Output { + Self { + matrix2: self.matrix2 * rhs, + translation: self.translation * rhs, + } + } +} + +impl Add for DAffine2 { + type Output = Self; + #[inline] + fn add(self, rhs: Self) -> Self::Output { + Self { + matrix2: self.matrix2 + rhs.matrix2, + translation: self.translation + rhs.translation, + } + } +} + +impl Sub for DAffine2 { + type Output = Self; + #[inline] + fn sub(self, rhs: Self) -> Self::Output { + Self { + matrix2: self.matrix2 - rhs.matrix2, + translation: self.translation - rhs.translation, + } + } +} + +impl From for DMat3 { + #[inline] + fn from(m: DAffine2) -> DMat3 { + Self::from_cols( + m.matrix2.x_axis.extend(0.0), + m.matrix2.y_axis.extend(0.0), + m.translation.extend(1.0), + ) + } +} + +impl Mul for DAffine2 { + type Output = DMat3; + + #[inline] + fn mul(self, rhs: DMat3) -> Self::Output { + DMat3::from(self) * rhs + } +} + +impl Mul for DMat3 { + type Output = DMat3; + + #[inline] + fn mul(self, rhs: DAffine2) -> Self::Output { + self * DMat3::from(rhs) + } +} diff --git a/src/f64/daffine3.rs b/src/f64/daffine3.rs new file mode 100644 index 00000000..c9a7384f --- /dev/null +++ b/src/f64/daffine3.rs @@ -0,0 +1,555 @@ +// Generated from affine.rs template. Edit the template, not the generated file. + +use crate::{DMat3, DMat4, DQuat, DVec3}; +use core::ops::{Add, Deref, DerefMut, Mul, Sub}; + +/// A 3D affine transform, which can represent translation, rotation, scaling and shear. +#[derive(Copy, Clone)] +#[repr(C)] +pub struct DAffine3 { + pub matrix3: DMat3, + pub translation: DVec3, +} + +impl DAffine3 { + /// The degenerate zero transform. + /// + /// This transforms any finite vector and point to zero. + /// The zero transform is non-invertible. + pub const ZERO: Self = Self { + matrix3: DMat3::ZERO, + translation: DVec3::ZERO, + }; + + /// The identity transform. + /// + /// Multiplying a vector with this returns the same vector. + pub const IDENTITY: Self = Self { + matrix3: DMat3::IDENTITY, + translation: DVec3::ZERO, + }; + + /// All NAN:s. + pub const NAN: Self = Self { + matrix3: DMat3::NAN, + translation: DVec3::NAN, + }; + + /// Creates an affine transform from three column vectors. + #[inline(always)] + pub const fn from_cols(x_axis: DVec3, y_axis: DVec3, z_axis: DVec3, w_axis: DVec3) -> Self { + Self { + matrix3: DMat3::from_cols(x_axis, y_axis, z_axis), + translation: w_axis, + } + } + + /// Creates an affine transform from a `[f64; 12]` array stored in column major order. + /// If your data is stored in row major you will need to `transpose` the returned + /// matrix. + #[inline] + pub fn from_cols_array(m: &[f64; 12]) -> Self { + Self { + matrix3: DMat3::from_cols_slice(&m[0..9]), + translation: DVec3::from_slice(&m[9..12]), + } + } + + /// Creates a `[f64; 12]` array storing data in column major order. + /// If you require data in row major order `transpose` the matrix first. + #[inline] + pub fn to_cols_array(&self) -> [f64; 12] { + let x = &self.matrix3.x_axis; + let y = &self.matrix3.y_axis; + let z = &self.matrix3.z_axis; + let w = &self.translation; + [x.x, x.y, x.z, y.x, y.y, y.z, z.x, z.y, z.z, w.x, w.y, w.z] + } + + /// Creates an affine transform from a `[[f64; 3]; 4]` + /// 3D array stored in column major order. + /// If your data is in row major order you will need to `transpose` the returned + /// matrix. + #[inline] + pub fn from_cols_array_2d(m: &[[f64; 3]; 4]) -> Self { + Self { + matrix3: DMat3::from_cols(m[0].into(), m[1].into(), m[2].into()), + translation: m[3].into(), + } + } + + /// Creates a `[[f64; 3]; 4]` 3D array storing data in + /// column major order. + /// If you require data in row major order `transpose` the matrix first. + #[inline] + pub fn to_cols_array_2d(&self) -> [[f64; 3]; 4] { + [ + self.matrix3.x_axis.into(), + self.matrix3.y_axis.into(), + self.matrix3.z_axis.into(), + self.translation.into(), + ] + } + + /// Creates an affine transform from the first 12 values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 12 elements long. + #[inline] + pub fn from_cols_slice(slice: &[f64]) -> Self { + Self { + matrix3: DMat3::from_cols_slice(&slice[0..9]), + translation: DVec3::from_slice(&slice[9..12]), + } + } + + /// Writes the columns of `self` to the first 12 elements in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 12 elements long. + #[inline] + pub fn write_cols_to_slice(self, slice: &mut [f64]) { + self.matrix3.write_cols_to_slice(&mut slice[0..9]); + self.translation.write_to_slice(&mut slice[9..12]); + } + + /// Creates an affine transform that changes scale. + /// Note that if any scale is zero the transform will be non-invertible. + #[inline] + pub fn from_scale(scale: DVec3) -> Self { + Self { + matrix3: DMat3::from_diagonal(scale), + translation: DVec3::ZERO, + } + } + /// Creates an affine transform from the given `rotation` quaternion. + #[inline] + pub fn from_quat(rotation: DQuat) -> Self { + Self { + matrix3: DMat3::from_quat(rotation), + translation: DVec3::ZERO, + } + } + + /// Creates an affine transform containing a 3D rotation around a normalized + /// rotation `axis` of `angle` (in radians). + #[inline] + pub fn from_axis_angle(axis: DVec3, angle: f64) -> Self { + Self { + matrix3: DMat3::from_axis_angle(axis, angle), + translation: DVec3::ZERO, + } + } + + /// Creates an affine transform containing a 3D rotation around the x axis of + /// `angle` (in radians). + #[inline] + pub fn from_rotation_x(angle: f64) -> Self { + Self { + matrix3: DMat3::from_rotation_x(angle), + translation: DVec3::ZERO, + } + } + + /// Creates an affine transform containing a 3D rotation around the y axis of + /// `angle` (in radians). + #[inline] + pub fn from_rotation_y(angle: f64) -> Self { + Self { + matrix3: DMat3::from_rotation_y(angle), + translation: DVec3::ZERO, + } + } + + /// Creates an affine transform containing a 3D rotation around the z axis of + /// `angle` (in radians). + #[inline] + pub fn from_rotation_z(angle: f64) -> Self { + Self { + matrix3: DMat3::from_rotation_z(angle), + translation: DVec3::ZERO, + } + } + + /// Creates an affine transformation from the given 3D `translation`. + #[inline] + pub fn from_translation(translation: DVec3) -> Self { + #[allow(clippy::useless_conversion)] + Self { + matrix3: DMat3::IDENTITY, + translation: translation.into(), + } + } + + /// Creates an affine transform from a 3x3 matrix (expressing scale, shear and + /// rotation) + #[inline] + pub fn from_mat3(mat3: DMat3) -> Self { + #[allow(clippy::useless_conversion)] + Self { + matrix3: mat3.into(), + translation: DVec3::ZERO, + } + } + + /// Creates an affine transform from a 3x3 matrix (expressing scale, shear and rotation) + /// and a translation vector. + /// + /// Equivalent to `DAffine3::from_translation(translation) * DAffine3::from_mat3(mat3)` + #[inline] + pub fn from_mat3_translation(mat3: DMat3, translation: DVec3) -> Self { + #[allow(clippy::useless_conversion)] + Self { + matrix3: mat3.into(), + translation: translation.into(), + } + } + + /// Creates an affine transform from the given 3D `scale`, `rotation` and + /// `translation`. + /// + /// Equivalent to `DAffine3::from_translation(translation) * + /// DAffine3::from_quat(rotation) * DAffine3::from_scale(scale)` + #[inline] + pub fn from_scale_rotation_translation( + scale: DVec3, + rotation: DQuat, + translation: DVec3, + ) -> Self { + let rotation = DMat3::from_quat(rotation); + #[allow(clippy::useless_conversion)] + Self { + matrix3: DMat3::from_cols( + rotation.x_axis * scale.x, + rotation.y_axis * scale.y, + rotation.z_axis * scale.z, + ), + translation: translation.into(), + } + } + + /// Creates an affine transform from the given 3D `rotation` and `translation`. + /// + /// Equivalent to `DAffine3::from_translation(translation) * DAffine3::from_quat(rotation)` + #[inline] + pub fn from_rotation_translation(rotation: DQuat, translation: DVec3) -> Self { + #[allow(clippy::useless_conversion)] + Self { + matrix3: DMat3::from_quat(rotation), + translation: translation.into(), + } + } + + /// The given `DMat4` must be an affine transform, + /// i.e. contain no perspective transform. + #[inline] + pub fn from_mat4(m: DMat4) -> Self { + Self { + matrix3: DMat3::from_cols( + DVec3::from_vec4(m.x_axis), + DVec3::from_vec4(m.y_axis), + DVec3::from_vec4(m.z_axis), + ), + translation: DVec3::from_vec4(m.w_axis), + } + } + + /// Extracts `scale`, `rotation` and `translation` from `self`. + /// + /// The transform is expected to be non-degenerate and without shearing, or the output + /// will be invalid. + /// + /// # Panics + /// + /// Will panic if the determinant `self.matrix3` is zero or if the resulting scale + /// vector contains any zero elements when `glam_assert` is enabled. + #[inline] + pub fn to_scale_rotation_translation(&self) -> (DVec3, DQuat, DVec3) { + #[cfg(not(feature = "std"))] + use num_traits::Float; + + // TODO: migrate to core module + let det = self.matrix3.determinant(); + glam_assert!(det != 0.0); + + let scale = DVec3::new( + self.matrix3.x_axis.length() * det.signum(), + self.matrix3.y_axis.length(), + self.matrix3.z_axis.length(), + ); + + glam_assert!(scale.cmpne(DVec3::ZERO).all()); + + let inv_scale = scale.recip(); + + #[allow(clippy::useless_conversion)] + let rotation = DQuat::from_mat3(&DMat3::from_cols( + (self.matrix3.x_axis * inv_scale.x).into(), + (self.matrix3.y_axis * inv_scale.y).into(), + (self.matrix3.z_axis * inv_scale.z).into(), + )); + + #[allow(clippy::useless_conversion)] + (scale, rotation, self.translation.into()) + } + + #[inline] + fn look_to_lh(eye: DVec3, dir: DVec3, up: DVec3) -> Self { + let f = dir.normalize(); + let s = up.cross(f).normalize(); + let u = f.cross(s); + Self { + matrix3: DMat3::from_cols( + DVec3::new(s.x, u.x, f.x), + DVec3::new(s.y, u.y, f.y), + DVec3::new(s.z, u.z, f.z), + ), + translation: DVec3::new(-s.dot(eye), -u.dot(eye), -f.dot(eye)), + } + } + + /// Creates a left-handed view transform using a camera position, an up direction, and + /// a focal point. + /// + /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=forward`. + /// + /// # Panics + /// + /// Will panic if `up` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn look_at_lh(eye: DVec3, center: DVec3, up: DVec3) -> Self { + glam_assert!(up.is_normalized()); + Self::look_to_lh(eye, center - eye, up) + } + + /// Creates a right-handed view transform using a camera position, an up direction, and + /// a focal point. + /// + /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=back`. + /// + /// # Panics + /// + /// Will panic if `up` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn look_at_rh(eye: DVec3, center: DVec3, up: DVec3) -> Self { + glam_assert!(up.is_normalized()); + Self::look_to_lh(eye, eye - center, up) + } + + /// Transforms the given 3D points, applying shear, scale, rotation and translation. + #[inline] + pub fn transform_point3(&self, rhs: DVec3) -> DVec3 { + #[allow(clippy::useless_conversion)] + ((self.matrix3.x_axis * rhs.x) + + (self.matrix3.y_axis * rhs.y) + + (self.matrix3.z_axis * rhs.z) + + self.translation) + .into() + } + + /// Transforms the given 3D vector, applying shear, scale and rotation (but NOT + /// translation). + /// + /// To also apply translation, use [`Self::transform_point3`] instead. + #[inline] + pub fn transform_vector3(&self, rhs: DVec3) -> DVec3 { + #[allow(clippy::useless_conversion)] + ((self.matrix3.x_axis * rhs.x) + + (self.matrix3.y_axis * rhs.y) + + (self.matrix3.z_axis * rhs.z)) + .into() + } + + /// Returns `true` if, and only if, all elements are finite. + /// + /// If any element is either `NaN`, positive or negative infinity, this will return + /// `false`. + #[inline] + pub fn is_finite(&self) -> bool { + self.matrix3.is_finite() && self.translation.is_finite() + } + + /// Returns `true` if any elements are `NaN`. + #[inline] + pub fn is_nan(&self) -> bool { + self.matrix3.is_nan() || self.translation.is_nan() + } + + /// Returns true if the absolute difference of all elements between `self` and `rhs` + /// is less than or equal to `max_abs_diff`. + /// + /// This can be used to compare if two 3x4 matrices contain similar elements. It works + /// best when comparing with a known value. The `max_abs_diff` that should be used used + /// depends on the values being compared against. + /// + /// For more see + /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/). + #[inline] + pub fn abs_diff_eq(&self, rhs: Self, max_abs_diff: f64) -> bool { + self.matrix3.abs_diff_eq(rhs.matrix3, max_abs_diff) + && self.translation.abs_diff_eq(rhs.translation, max_abs_diff) + } + + /// Return the inverse of this transform. + /// + /// Note that if the transform is not invertible the result will be invalid. + #[must_use] + #[inline] + pub fn inverse(&self) -> Self { + let matrix3 = self.matrix3.inverse(); + // transform negative translation by the matrix inverse: + let translation = -(matrix3 * self.translation); + + Self { + matrix3, + translation, + } + } +} + +impl Default for DAffine3 { + #[inline(always)] + fn default() -> Self { + Self::IDENTITY + } +} + +impl Deref for DAffine3 { + type Target = crate::deref::Columns4; + #[inline(always)] + fn deref(&self) -> &Self::Target { + unsafe { &*(self as *const Self as *const Self::Target) } + } +} + +impl DerefMut for DAffine3 { + #[inline(always)] + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { &mut *(self as *mut Self as *mut Self::Target) } + } +} + +impl PartialEq for DAffine3 { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.matrix3.eq(&rhs.matrix3) && self.translation.eq(&rhs.translation) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl core::fmt::Debug for DAffine3 { + fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + fmt.debug_struct(stringify!(DAffine3)) + .field("matrix3", &self.matrix3) + .field("translation", &self.translation) + .finish() + } +} + +#[cfg(not(target_arch = "spirv"))] +impl core::fmt::Display for DAffine3 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!( + f, + "[{}, {}, {}, {}]", + self.matrix3.x_axis, self.matrix3.y_axis, self.matrix3.z_axis, self.translation + ) + } +} + +impl<'a> core::iter::Product<&'a Self> for DAffine3 { + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::IDENTITY, |a, &b| a * b) + } +} + +impl Mul for DAffine3 { + type Output = DAffine3; + + #[inline] + fn mul(self, rhs: DAffine3) -> Self::Output { + Self { + matrix3: self.matrix3 * rhs.matrix3, + translation: self.matrix3 * rhs.translation + self.translation, + } + } +} + +impl Mul for f64 { + type Output = DAffine3; + #[inline] + fn mul(self, rhs: DAffine3) -> Self::Output { + DAffine3 { + matrix3: self * rhs.matrix3, + translation: self * rhs.translation, + } + } +} + +impl Mul for DAffine3 { + type Output = Self; + #[inline] + fn mul(self, rhs: f64) -> Self::Output { + Self { + matrix3: self.matrix3 * rhs, + translation: self.translation * rhs, + } + } +} + +impl Add for DAffine3 { + type Output = Self; + #[inline] + fn add(self, rhs: Self) -> Self::Output { + Self { + matrix3: self.matrix3 + rhs.matrix3, + translation: self.translation + rhs.translation, + } + } +} + +impl Sub for DAffine3 { + type Output = Self; + #[inline] + fn sub(self, rhs: Self) -> Self::Output { + Self { + matrix3: self.matrix3 - rhs.matrix3, + translation: self.translation - rhs.translation, + } + } +} + +impl From for DMat4 { + #[inline] + fn from(m: DAffine3) -> DMat4 { + DMat4::from_cols( + m.matrix3.x_axis.extend(0.0), + m.matrix3.y_axis.extend(0.0), + m.matrix3.z_axis.extend(0.0), + m.translation.extend(1.0), + ) + } +} + +impl Mul for DAffine3 { + type Output = DMat4; + + #[inline] + fn mul(self, rhs: DMat4) -> Self::Output { + DMat4::from(self) * rhs + } +} + +impl Mul for DMat4 { + type Output = DMat4; + + #[inline] + fn mul(self, rhs: DAffine3) -> Self::Output { + self * DMat4::from(rhs) + } +} diff --git a/src/f64/dmat2.rs b/src/f64/dmat2.rs new file mode 100644 index 00000000..008e0e80 --- /dev/null +++ b/src/f64/dmat2.rs @@ -0,0 +1,427 @@ +// Generated from mat.rs template. Edit the template, not the generated file. + +use crate::{swizzles::*, DMat3, DVec2, Mat2}; +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::iter::{Product, Sum}; +use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; + +#[cfg(not(feature = "std"))] +use num_traits::Float; + +/// Creates a 2x2 matrix from column vectors. +#[inline(always)] +pub const fn dmat2(x_axis: DVec2, y_axis: DVec2) -> DMat2 { + DMat2::from_cols(x_axis, y_axis) +} + +/// A 2x2 column major matrix. +#[derive(Clone, Copy)] +#[cfg_attr(feature = "cuda", repr(align(16)))] +pub struct DMat2 { + pub x_axis: DVec2, + pub y_axis: DVec2, +} + +impl DMat2 { + /// A 2x2 matrix with all elements set to `0.0`. + pub const ZERO: Self = Self::from_cols(DVec2::ZERO, DVec2::ZERO); + + /// A 2x2 identity matrix, where all diagonal elements are `1`, and all off-diagonal elements are `0`. + pub const IDENTITY: Self = Self::from_cols(DVec2::X, DVec2::Y); + + /// All NAN:s. + pub const NAN: Self = Self::from_cols(DVec2::NAN, DVec2::NAN); + + #[allow(clippy::too_many_arguments)] + #[inline(always)] + const fn new(m00: f64, m01: f64, m10: f64, m11: f64) -> Self { + Self { + x_axis: DVec2::new(m00, m01), + y_axis: DVec2::new(m10, m11), + } + } + + /// Creates a 2x2 matrix from two column vectors. + #[inline(always)] + pub const fn from_cols(x_axis: DVec2, y_axis: DVec2) -> Self { + Self { x_axis, y_axis } + } + + /// Creates a 2x2 matrix from a `[f64; 4]` array stored in column major order. + /// If your data is stored in row major you will need to `transpose` the returned + /// matrix. + #[inline] + pub const fn from_cols_array(m: &[f64; 4]) -> Self { + Self::new(m[0], m[1], m[2], m[3]) + } + + /// Creates a `[f64; 4]` array storing data in column major order. + /// If you require data in row major order `transpose` the matrix first. + #[inline] + pub fn to_cols_array(&self) -> [f64; 4] { + [self.x_axis.x, self.x_axis.y, self.y_axis.x, self.y_axis.y] + } + + /// Creates a 2x2 matrix from a `[[f64; 2]; 2]` 2D array stored in column major order. + /// If your data is in row major order you will need to `transpose` the returned + /// matrix. + #[inline] + pub const fn from_cols_array_2d(m: &[[f64; 2]; 2]) -> Self { + Self::from_cols(DVec2::from_array(m[0]), DVec2::from_array(m[1])) + } + + /// Creates a `[[f64; 2]; 2]` 2D array storing data in column major order. + /// If you require data in row major order `transpose` the matrix first. + #[inline] + pub fn to_cols_array_2d(&self) -> [[f64; 2]; 2] { + [self.x_axis.to_array(), self.y_axis.to_array()] + } + + /// Creates a 2x2 matrix with its diagonal set to `diagonal` and all other entries set to 0. + #[doc(alias = "scale")] + #[inline] + pub fn from_diagonal(diagonal: DVec2) -> Self { + Self::new(diagonal.x, 0.0, 0.0, diagonal.y) + } + + /// Creates a 2x2 matrix containing the combining non-uniform `scale` and rotation of + /// `angle` (in radians). + #[inline] + pub fn from_scale_angle(scale: DVec2, angle: f64) -> Self { + let (sin, cos) = angle.sin_cos(); + Self::new(cos * scale.x, sin * scale.x, -sin * scale.y, cos * scale.y) + } + + /// Creates a 2x2 matrix containing a rotation of `angle` (in radians). + #[inline] + pub fn from_angle(angle: f64) -> Self { + let (sin, cos) = angle.sin_cos(); + Self::new(cos, sin, -sin, cos) + } + + /// Creates a 2x2 matrix from a 3x3 matrix, discarding the 2nd row and column. + #[inline] + pub fn from_mat3(m: DMat3) -> Self { + Self::from_cols(m.x_axis.xy(), m.y_axis.xy()) + } + + /// Creates a 2x2 matrix from the first 4 values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 4 elements long. + #[inline] + pub const fn from_cols_slice(slice: &[f64]) -> Self { + Self::new(slice[0], slice[1], slice[2], slice[3]) + } + + /// Writes the columns of `self` to the first 4 elements in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 4 elements long. + #[inline] + pub fn write_cols_to_slice(self, slice: &mut [f64]) { + slice[0] = self.x_axis.x; + slice[1] = self.x_axis.y; + slice[2] = self.y_axis.x; + slice[3] = self.y_axis.y; + } + + /// Returns the matrix column for the given `index`. + /// + /// # Panics + /// + /// Panics if `index` is greater than 1. + #[inline] + pub fn col(&self, index: usize) -> DVec2 { + match index { + 0 => self.x_axis, + 1 => self.y_axis, + _ => panic!("index out of bounds"), + } + } + + /// Returns a mutable reference to the matrix column for the given `index`. + /// + /// # Panics + /// + /// Panics if `index` is greater than 1. + #[inline] + pub fn col_mut(&mut self, index: usize) -> &mut DVec2 { + match index { + 0 => &mut self.x_axis, + 1 => &mut self.y_axis, + _ => panic!("index out of bounds"), + } + } + + /// Returns the matrix row for the given `index`. + /// + /// # Panics + /// + /// Panics if `index` is greater than 1. + #[inline] + pub fn row(&self, index: usize) -> DVec2 { + match index { + 0 => DVec2::new(self.x_axis.x, self.y_axis.x), + 1 => DVec2::new(self.x_axis.y, self.y_axis.y), + _ => panic!("index out of bounds"), + } + } + + /// Returns `true` if, and only if, all elements are finite. + /// If any element is either `NaN`, positive or negative infinity, this will return `false`. + #[inline] + pub fn is_finite(&self) -> bool { + self.x_axis.is_finite() && self.y_axis.is_finite() + } + + /// Returns `true` if any elements are `NaN`. + #[inline] + pub fn is_nan(&self) -> bool { + self.x_axis.is_nan() || self.y_axis.is_nan() + } + + /// Returns the transpose of `self`. + #[must_use] + #[inline] + pub fn transpose(&self) -> Self { + Self { + x_axis: DVec2::new(self.x_axis.x, self.y_axis.x), + y_axis: DVec2::new(self.x_axis.y, self.y_axis.y), + } + } + + /// Returns the determinant of `self`. + #[inline] + pub fn determinant(&self) -> f64 { + self.x_axis.x * self.y_axis.y - self.x_axis.y * self.y_axis.x + } + + /// Returns the inverse of `self`. + /// + /// If the matrix is not invertible the returned matrix will be invalid. + /// + /// # Panics + /// + /// Will panic if the determinant of `self` is zero when `glam_assert` is enabled. + #[must_use] + pub fn inverse(&self) -> Self { + let inv_det = { + let det = self.determinant(); + glam_assert!(det != 0.0); + det.recip() + }; + Self::new( + self.y_axis.y * inv_det, + self.x_axis.y * -inv_det, + self.y_axis.x * -inv_det, + self.x_axis.x * inv_det, + ) + } + + /// Transforms a 2D vector. + #[inline] + pub fn mul_vec2(&self, rhs: DVec2) -> DVec2 { + #[allow(clippy::suspicious_operation_groupings)] + DVec2::new( + (self.x_axis.x * rhs.x) + (self.y_axis.x * rhs.y), + (self.x_axis.y * rhs.x) + (self.y_axis.y * rhs.y), + ) + } + + /// Multiplies two 2x2 matrices. + #[inline] + pub fn mul_mat2(&self, rhs: &Self) -> Self { + Self::from_cols(self.mul(rhs.x_axis), self.mul(rhs.y_axis)) + } + + /// Adds two 2x2 matrices. + #[inline] + pub fn add_mat2(&self, rhs: &Self) -> Self { + Self::from_cols(self.x_axis.add(rhs.x_axis), self.y_axis.add(rhs.y_axis)) + } + + /// Subtracts two 2x2 matrices. + #[inline] + pub fn sub_mat2(&self, rhs: &Self) -> Self { + Self::from_cols(self.x_axis.sub(rhs.x_axis), self.y_axis.sub(rhs.y_axis)) + } + + /// Multiplies a 2x2 matrix by a scalar. + #[inline] + pub fn mul_scalar(&self, rhs: f64) -> Self { + Self::from_cols(self.x_axis.mul(rhs), self.y_axis.mul(rhs)) + } + + /// Returns true if the absolute difference of all elements between `self` and `rhs` + /// is less than or equal to `max_abs_diff`. + /// + /// This can be used to compare if two matrices contain similar elements. It works best + /// when comparing with a known value. The `max_abs_diff` that should be used used + /// depends on the values being compared against. + /// + /// For more see + /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/). + #[inline] + pub fn abs_diff_eq(&self, rhs: Self, max_abs_diff: f64) -> bool { + self.x_axis.abs_diff_eq(rhs.x_axis, max_abs_diff) + && self.y_axis.abs_diff_eq(rhs.y_axis, max_abs_diff) + } + + #[inline] + pub fn as_mat2(&self) -> Mat2 { + Mat2::from_cols(self.x_axis.as_vec2(), self.y_axis.as_vec2()) + } +} + +impl Default for DMat2 { + #[inline] + fn default() -> Self { + Self::IDENTITY + } +} + +impl Add for DMat2 { + type Output = Self; + #[inline] + fn add(self, rhs: Self) -> Self::Output { + self.add_mat2(&rhs) + } +} + +impl AddAssign for DMat2 { + #[inline] + fn add_assign(&mut self, rhs: Self) { + *self = self.add_mat2(&rhs); + } +} + +impl Sub for DMat2 { + type Output = Self; + #[inline] + fn sub(self, rhs: Self) -> Self::Output { + self.sub_mat2(&rhs) + } +} + +impl SubAssign for DMat2 { + #[inline] + fn sub_assign(&mut self, rhs: Self) { + *self = self.sub_mat2(&rhs); + } +} + +impl Neg for DMat2 { + type Output = Self; + #[inline] + fn neg(self) -> Self::Output { + Self::from_cols(self.x_axis.neg(), self.y_axis.neg()) + } +} + +impl Mul for DMat2 { + type Output = Self; + #[inline] + fn mul(self, rhs: Self) -> Self::Output { + self.mul_mat2(&rhs) + } +} + +impl MulAssign for DMat2 { + #[inline] + fn mul_assign(&mut self, rhs: Self) { + *self = self.mul_mat2(&rhs); + } +} + +impl Mul for DMat2 { + type Output = DVec2; + #[inline] + fn mul(self, rhs: DVec2) -> Self::Output { + self.mul_vec2(rhs) + } +} + +impl Mul for f64 { + type Output = DMat2; + #[inline] + fn mul(self, rhs: DMat2) -> Self::Output { + rhs.mul_scalar(self) + } +} + +impl Mul for DMat2 { + type Output = Self; + #[inline] + fn mul(self, rhs: f64) -> Self::Output { + self.mul_scalar(rhs) + } +} + +impl MulAssign for DMat2 { + #[inline] + fn mul_assign(&mut self, rhs: f64) { + *self = self.mul_scalar(rhs); + } +} + +impl<'a> Sum<&'a Self> for DMat2 { + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, |a, &b| Self::add(a, b)) + } +} + +impl<'a> Product<&'a Self> for DMat2 { + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::IDENTITY, |a, &b| Self::mul(a, b)) + } +} + +impl PartialEq for DMat2 { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.x_axis.eq(&rhs.x_axis) && self.y_axis.eq(&rhs.y_axis) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsRef<[f64; 4]> for DMat2 { + #[inline] + fn as_ref(&self) -> &[f64; 4] { + unsafe { &*(self as *const Self as *const [f64; 4]) } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsMut<[f64; 4]> for DMat2 { + #[inline] + fn as_mut(&mut self) -> &mut [f64; 4] { + unsafe { &mut *(self as *mut Self as *mut [f64; 4]) } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Debug for DMat2 { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct(stringify!(DMat2)) + .field("x_axis", &self.x_axis) + .field("y_axis", &self.y_axis) + .finish() + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Display for DMat2 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "[{}, {}]", self.x_axis, self.y_axis) + } +} diff --git a/src/f64/dmat3.rs b/src/f64/dmat3.rs new file mode 100644 index 00000000..2458f5e6 --- /dev/null +++ b/src/f64/dmat3.rs @@ -0,0 +1,684 @@ +// Generated from mat.rs template. Edit the template, not the generated file. + +use crate::{swizzles::*, DMat2, DMat4, DQuat, DVec2, DVec3, EulerRot, Mat3}; +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::iter::{Product, Sum}; +use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; + +#[cfg(not(feature = "std"))] +use num_traits::Float; + +/// Creates a 3x3 matrix from column vectors. +#[inline(always)] +pub const fn dmat3(x_axis: DVec3, y_axis: DVec3, z_axis: DVec3) -> DMat3 { + DMat3::from_cols(x_axis, y_axis, z_axis) +} + +/// A 3x3 column major matrix. +/// +/// This 3x3 matrix type features convenience methods for creating and using linear and +/// affine transformations. If you are primarily dealing with 2D affine transformations the +/// [`DAffine2`](crate::DAffine2) type is much faster and more space efficient than +/// using a 3x3 matrix. +/// +/// Linear transformations including 3D rotation and scale can be created using methods +/// such as [`Self::from_diagonal()`], [`Self::from_quat()`], [`Self::from_axis_angle()`], +/// [`Self::from_rotation_x()`], [`Self::from_rotation_y()`], or +/// [`Self::from_rotation_z()`]. +/// +/// The resulting matrices can be use to transform 3D vectors using regular vector +/// multiplication. +/// +/// Affine transformations including 2D translation, rotation and scale can be created +/// using methods such as [`Self::from_translation()`], [`Self::from_angle()`], +/// [`Self::from_scale()`] and [`Self::from_scale_angle_translation()`]. +/// +/// The [`Self::transform_point2()`] and [`Self::transform_vector2()`] convenience methods +/// are provided for performing affine transforms on 2D vectors and points. These multiply +/// 2D inputs as 3D vectors with an implicit `z` value of `1` for points and `0` for +/// vectors respectively. These methods assume that `Self` contains a valid affine +/// transform. +#[derive(Clone, Copy)] +pub struct DMat3 { + pub x_axis: DVec3, + pub y_axis: DVec3, + pub z_axis: DVec3, +} + +impl DMat3 { + /// A 3x3 matrix with all elements set to `0.0`. + pub const ZERO: Self = Self::from_cols(DVec3::ZERO, DVec3::ZERO, DVec3::ZERO); + + /// A 3x3 identity matrix, where all diagonal elements are `1`, and all off-diagonal elements are `0`. + pub const IDENTITY: Self = Self::from_cols(DVec3::X, DVec3::Y, DVec3::Z); + + /// All NAN:s. + pub const NAN: Self = Self::from_cols(DVec3::NAN, DVec3::NAN, DVec3::NAN); + + #[allow(clippy::too_many_arguments)] + #[inline(always)] + const fn new( + m00: f64, + m01: f64, + m02: f64, + m10: f64, + m11: f64, + m12: f64, + m20: f64, + m21: f64, + m22: f64, + ) -> Self { + Self { + x_axis: DVec3::new(m00, m01, m02), + y_axis: DVec3::new(m10, m11, m12), + z_axis: DVec3::new(m20, m21, m22), + } + } + + /// Creates a 3x3 matrix from two column vectors. + #[inline(always)] + pub const fn from_cols(x_axis: DVec3, y_axis: DVec3, z_axis: DVec3) -> Self { + Self { + x_axis, + y_axis, + z_axis, + } + } + + /// Creates a 3x3 matrix from a `[f64; 9]` array stored in column major order. + /// If your data is stored in row major you will need to `transpose` the returned + /// matrix. + #[inline] + pub const fn from_cols_array(m: &[f64; 9]) -> Self { + Self::new(m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8]) + } + + /// Creates a `[f64; 9]` array storing data in column major order. + /// If you require data in row major order `transpose` the matrix first. + #[inline] + pub fn to_cols_array(&self) -> [f64; 9] { + [ + self.x_axis.x, + self.x_axis.y, + self.x_axis.z, + self.y_axis.x, + self.y_axis.y, + self.y_axis.z, + self.z_axis.x, + self.z_axis.y, + self.z_axis.z, + ] + } + + /// Creates a 3x3 matrix from a `[[f64; 3]; 3]` 3D array stored in column major order. + /// If your data is in row major order you will need to `transpose` the returned + /// matrix. + #[inline] + pub const fn from_cols_array_2d(m: &[[f64; 3]; 3]) -> Self { + Self::from_cols( + DVec3::from_array(m[0]), + DVec3::from_array(m[1]), + DVec3::from_array(m[2]), + ) + } + + /// Creates a `[[f64; 3]; 3]` 3D array storing data in column major order. + /// If you require data in row major order `transpose` the matrix first. + #[inline] + pub fn to_cols_array_2d(&self) -> [[f64; 3]; 3] { + [ + self.x_axis.to_array(), + self.y_axis.to_array(), + self.z_axis.to_array(), + ] + } + + /// Creates a 3x3 matrix with its diagonal set to `diagonal` and all other entries set to 0. + #[doc(alias = "scale")] + #[inline] + pub fn from_diagonal(diagonal: DVec3) -> Self { + Self::new( + diagonal.x, 0.0, 0.0, 0.0, diagonal.y, 0.0, 0.0, 0.0, diagonal.z, + ) + } + + /// Creates a 3x3 matrix from a 4x4 matrix, discarding the 3rd row and column. + pub fn from_mat4(m: DMat4) -> Self { + Self::from_cols(m.x_axis.xyz(), m.y_axis.xyz(), m.z_axis.xyz()) + } + + /// Creates a 3D rotation matrix from the given quaternion. + /// + /// # Panics + /// + /// Will panic if `rotation` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn from_quat(rotation: DQuat) -> Self { + glam_assert!(rotation.is_normalized()); + + let x2 = rotation.x + rotation.x; + let y2 = rotation.y + rotation.y; + let z2 = rotation.z + rotation.z; + let xx = rotation.x * x2; + let xy = rotation.x * y2; + let xz = rotation.x * z2; + let yy = rotation.y * y2; + let yz = rotation.y * z2; + let zz = rotation.z * z2; + let wx = rotation.w * x2; + let wy = rotation.w * y2; + let wz = rotation.w * z2; + + Self::from_cols( + DVec3::new(1.0 - (yy + zz), xy + wz, xz - wy), + DVec3::new(xy - wz, 1.0 - (xx + zz), yz + wx), + DVec3::new(xz + wy, yz - wx, 1.0 - (xx + yy)), + ) + } + + /// Creates a 3D rotation matrix from a normalized rotation `axis` and `angle` (in + /// radians). + /// + /// # Panics + /// + /// Will panic if `axis` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn from_axis_angle(axis: DVec3, angle: f64) -> Self { + glam_assert!(axis.is_normalized()); + + let (sin, cos) = angle.sin_cos(); + let (xsin, ysin, zsin) = axis.mul(sin).into(); + let (x, y, z) = axis.into(); + let (x2, y2, z2) = axis.mul(axis).into(); + let omc = 1.0 - cos; + let xyomc = x * y * omc; + let xzomc = x * z * omc; + let yzomc = y * z * omc; + Self::from_cols( + DVec3::new(x2 * omc + cos, xyomc + zsin, xzomc - ysin), + DVec3::new(xyomc - zsin, y2 * omc + cos, yzomc + xsin), + DVec3::new(xzomc + ysin, yzomc - xsin, z2 * omc + cos), + ) + } + + #[inline] + /// Creates a 3D rotation matrix from the given euler rotation sequence and the angles (in + /// radians). + pub fn from_euler(order: EulerRot, a: f64, b: f64, c: f64) -> Self { + let quat = DQuat::from_euler(order, a, b, c); + Self::from_quat(quat) + } + + /// Creates a 3D rotation matrix from `angle` (in radians) around the x axis. + #[inline] + pub fn from_rotation_x(angle: f64) -> Self { + let (sina, cosa) = angle.sin_cos(); + Self::from_cols( + DVec3::X, + DVec3::new(0.0, cosa, sina), + DVec3::new(0.0, -sina, cosa), + ) + } + + /// Creates a 3D rotation matrix from `angle` (in radians) around the y axis. + #[inline] + pub fn from_rotation_y(angle: f64) -> Self { + let (sina, cosa) = angle.sin_cos(); + Self::from_cols( + DVec3::new(cosa, 0.0, -sina), + DVec3::Y, + DVec3::new(sina, 0.0, cosa), + ) + } + + /// Creates a 3D rotation matrix from `angle` (in radians) around the z axis. + #[inline] + pub fn from_rotation_z(angle: f64) -> Self { + let (sina, cosa) = angle.sin_cos(); + Self::from_cols( + DVec3::new(cosa, sina, 0.0), + DVec3::new(-sina, cosa, 0.0), + DVec3::Z, + ) + } + + /// Creates an affine transformation matrix from the given 2D `translation`. + /// + /// The resulting matrix can be used to transform 2D points and vectors. See + /// [`Self::transform_point2()`] and [`Self::transform_vector2()`]. + #[inline] + pub fn from_translation(translation: DVec2) -> Self { + Self::from_cols( + DVec3::X, + DVec3::Y, + DVec3::new(translation.x, translation.y, 1.0), + ) + } + + /// Creates an affine transformation matrix from the given 2D rotation `angle` (in + /// radians). + /// + /// The resulting matrix can be used to transform 2D points and vectors. See + /// [`Self::transform_point2()`] and [`Self::transform_vector2()`]. + #[inline] + pub fn from_angle(angle: f64) -> Self { + let (sin, cos) = angle.sin_cos(); + Self::from_cols( + DVec3::new(cos, sin, 0.0), + DVec3::new(-sin, cos, 0.0), + DVec3::Z, + ) + } + + /// Creates an affine transformation matrix from the given 2D `scale`, rotation `angle` (in + /// radians) and `translation`. + /// + /// The resulting matrix can be used to transform 2D points and vectors. See + /// [`Self::transform_point2()`] and [`Self::transform_vector2()`]. + #[inline] + pub fn from_scale_angle_translation(scale: DVec2, angle: f64, translation: DVec2) -> Self { + let (sin, cos) = angle.sin_cos(); + Self::from_cols( + DVec3::new(cos * scale.x, sin * scale.x, 0.0), + DVec3::new(-sin * scale.y, cos * scale.y, 0.0), + DVec3::new(translation.x, translation.y, 1.0), + ) + } + + /// Creates an affine transformation matrix from the given non-uniform 2D `scale`. + /// + /// The resulting matrix can be used to transform 2D points and vectors. See + /// [`Self::transform_point2()`] and [`Self::transform_vector2()`]. + /// + /// # Panics + /// + /// Will panic if all elements of `scale` are zero when `glam_assert` is enabled. + #[inline] + pub fn from_scale(scale: DVec2) -> Self { + // Do not panic as long as any component is non-zero + glam_assert!(scale.cmpne(DVec2::ZERO).any()); + + Self::from_cols( + DVec3::new(scale.x, 0.0, 0.0), + DVec3::new(0.0, scale.y, 0.0), + DVec3::Z, + ) + } + + /// Creates an affine transformation matrix from the given 2x2 matrix. + /// + /// The resulting matrix can be used to transform 2D points and vectors. See + /// [`Self::transform_point2()`] and [`Self::transform_vector2()`]. + #[inline] + pub fn from_mat2(m: DMat2) -> Self { + Self::from_cols((m.x_axis, 0.0).into(), (m.y_axis, 0.0).into(), DVec3::Z) + } + + /// Creates a 3x3 matrix from the first 9 values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 9 elements long. + #[inline] + pub const fn from_cols_slice(slice: &[f64]) -> Self { + Self::new( + slice[0], slice[1], slice[2], slice[3], slice[4], slice[5], slice[6], slice[7], + slice[8], + ) + } + + /// Writes the columns of `self` to the first 9 elements in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 9 elements long. + #[inline] + pub fn write_cols_to_slice(self, slice: &mut [f64]) { + slice[0] = self.x_axis.x; + slice[1] = self.x_axis.y; + slice[2] = self.x_axis.z; + slice[3] = self.y_axis.x; + slice[4] = self.y_axis.y; + slice[5] = self.y_axis.z; + slice[6] = self.z_axis.x; + slice[7] = self.z_axis.y; + slice[8] = self.z_axis.z; + } + + /// Returns the matrix column for the given `index`. + /// + /// # Panics + /// + /// Panics if `index` is greater than 2. + #[inline] + pub fn col(&self, index: usize) -> DVec3 { + match index { + 0 => self.x_axis, + 1 => self.y_axis, + 2 => self.z_axis, + _ => panic!("index out of bounds"), + } + } + + /// Returns a mutable reference to the matrix column for the given `index`. + /// + /// # Panics + /// + /// Panics if `index` is greater than 2. + #[inline] + pub fn col_mut(&mut self, index: usize) -> &mut DVec3 { + match index { + 0 => &mut self.x_axis, + 1 => &mut self.y_axis, + 2 => &mut self.z_axis, + _ => panic!("index out of bounds"), + } + } + + /// Returns the matrix row for the given `index`. + /// + /// # Panics + /// + /// Panics if `index` is greater than 2. + #[inline] + pub fn row(&self, index: usize) -> DVec3 { + match index { + 0 => DVec3::new(self.x_axis.x, self.y_axis.x, self.z_axis.x), + 1 => DVec3::new(self.x_axis.y, self.y_axis.y, self.z_axis.y), + 2 => DVec3::new(self.x_axis.z, self.y_axis.z, self.z_axis.z), + _ => panic!("index out of bounds"), + } + } + + /// Returns `true` if, and only if, all elements are finite. + /// If any element is either `NaN`, positive or negative infinity, this will return `false`. + #[inline] + pub fn is_finite(&self) -> bool { + self.x_axis.is_finite() && self.y_axis.is_finite() && self.z_axis.is_finite() + } + + /// Returns `true` if any elements are `NaN`. + #[inline] + pub fn is_nan(&self) -> bool { + self.x_axis.is_nan() || self.y_axis.is_nan() || self.z_axis.is_nan() + } + + /// Returns the transpose of `self`. + #[must_use] + #[inline] + pub fn transpose(&self) -> Self { + Self { + x_axis: DVec3::new(self.x_axis.x, self.y_axis.x, self.z_axis.x), + y_axis: DVec3::new(self.x_axis.y, self.y_axis.y, self.z_axis.y), + z_axis: DVec3::new(self.x_axis.z, self.y_axis.z, self.z_axis.z), + } + } + + /// Returns the determinant of `self`. + pub fn determinant(&self) -> f64 { + self.z_axis.dot(self.x_axis.cross(self.y_axis)) + } + + /// Returns the inverse of `self`. + /// + /// If the matrix is not invertible the returned matrix will be invalid. + /// + /// # Panics + /// + /// Will panic if the determinant of `self` is zero when `glam_assert` is enabled. + #[must_use] + pub fn inverse(&self) -> Self { + let tmp0 = self.y_axis.cross(self.z_axis); + let tmp1 = self.z_axis.cross(self.x_axis); + let tmp2 = self.x_axis.cross(self.y_axis); + let det = self.z_axis.dot(tmp2); + glam_assert!(det != 0.0); + let inv_det = DVec3::splat(det.recip()); + Self::from_cols(tmp0.mul(inv_det), tmp1.mul(inv_det), tmp2.mul(inv_det)).transpose() + } + + /// Transforms the given 2D vector as a point. + /// + /// This is the equivalent of multiplying `rhs` as a 3D vector where `z` is `1`. + /// + /// This method assumes that `self` contains a valid affine transform. + #[inline] + pub fn transform_point2(&self, rhs: DVec2) -> DVec2 { + DMat2::from_cols(self.x_axis.xy(), self.y_axis.xy()) * rhs + self.z_axis.xy() + } + + /// Rotates the given 2D vector. + /// + /// This is the equivalent of multiplying `rhs` as a 3D vector where `z` is `0`. + /// + /// This method assumes that `self` contains a valid affine transform. + #[inline] + pub fn transform_vector2(&self, rhs: DVec2) -> DVec2 { + DMat2::from_cols(self.x_axis.xy(), self.y_axis.xy()) * rhs + } + + /// Transforms a 3D vector. + #[inline] + pub fn mul_vec3(&self, rhs: DVec3) -> DVec3 { + let mut res = self.x_axis.mul(rhs.x); + res = res.add(self.y_axis.mul(rhs.y)); + res = res.add(self.z_axis.mul(rhs.z)); + res + } + + /// Multiplies two 3x3 matrices. + #[inline] + pub fn mul_mat3(&self, rhs: &Self) -> Self { + Self::from_cols( + self.mul(rhs.x_axis), + self.mul(rhs.y_axis), + self.mul(rhs.z_axis), + ) + } + + /// Adds two 3x3 matrices. + #[inline] + pub fn add_mat3(&self, rhs: &Self) -> Self { + Self::from_cols( + self.x_axis.add(rhs.x_axis), + self.y_axis.add(rhs.y_axis), + self.z_axis.add(rhs.z_axis), + ) + } + + /// Subtracts two 3x3 matrices. + #[inline] + pub fn sub_mat3(&self, rhs: &Self) -> Self { + Self::from_cols( + self.x_axis.sub(rhs.x_axis), + self.y_axis.sub(rhs.y_axis), + self.z_axis.sub(rhs.z_axis), + ) + } + + /// Multiplies a 3x3 matrix by a scalar. + #[inline] + pub fn mul_scalar(&self, rhs: f64) -> Self { + Self::from_cols( + self.x_axis.mul(rhs), + self.y_axis.mul(rhs), + self.z_axis.mul(rhs), + ) + } + + /// Returns true if the absolute difference of all elements between `self` and `rhs` + /// is less than or equal to `max_abs_diff`. + /// + /// This can be used to compare if two matrices contain similar elements. It works best + /// when comparing with a known value. The `max_abs_diff` that should be used used + /// depends on the values being compared against. + /// + /// For more see + /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/). + #[inline] + pub fn abs_diff_eq(&self, rhs: Self, max_abs_diff: f64) -> bool { + self.x_axis.abs_diff_eq(rhs.x_axis, max_abs_diff) + && self.y_axis.abs_diff_eq(rhs.y_axis, max_abs_diff) + && self.z_axis.abs_diff_eq(rhs.z_axis, max_abs_diff) + } + + #[inline] + pub fn as_mat3(&self) -> Mat3 { + Mat3::from_cols( + self.x_axis.as_vec3(), + self.y_axis.as_vec3(), + self.z_axis.as_vec3(), + ) + } +} + +impl Default for DMat3 { + #[inline] + fn default() -> Self { + Self::IDENTITY + } +} + +impl Add for DMat3 { + type Output = Self; + #[inline] + fn add(self, rhs: Self) -> Self::Output { + self.add_mat3(&rhs) + } +} + +impl AddAssign for DMat3 { + #[inline] + fn add_assign(&mut self, rhs: Self) { + *self = self.add_mat3(&rhs); + } +} + +impl Sub for DMat3 { + type Output = Self; + #[inline] + fn sub(self, rhs: Self) -> Self::Output { + self.sub_mat3(&rhs) + } +} + +impl SubAssign for DMat3 { + #[inline] + fn sub_assign(&mut self, rhs: Self) { + *self = self.sub_mat3(&rhs); + } +} + +impl Neg for DMat3 { + type Output = Self; + #[inline] + fn neg(self) -> Self::Output { + Self::from_cols(self.x_axis.neg(), self.y_axis.neg(), self.z_axis.neg()) + } +} + +impl Mul for DMat3 { + type Output = Self; + #[inline] + fn mul(self, rhs: Self) -> Self::Output { + self.mul_mat3(&rhs) + } +} + +impl MulAssign for DMat3 { + #[inline] + fn mul_assign(&mut self, rhs: Self) { + *self = self.mul_mat3(&rhs); + } +} + +impl Mul for DMat3 { + type Output = DVec3; + #[inline] + fn mul(self, rhs: DVec3) -> Self::Output { + self.mul_vec3(rhs) + } +} + +impl Mul for f64 { + type Output = DMat3; + #[inline] + fn mul(self, rhs: DMat3) -> Self::Output { + rhs.mul_scalar(self) + } +} + +impl Mul for DMat3 { + type Output = Self; + #[inline] + fn mul(self, rhs: f64) -> Self::Output { + self.mul_scalar(rhs) + } +} + +impl MulAssign for DMat3 { + #[inline] + fn mul_assign(&mut self, rhs: f64) { + *self = self.mul_scalar(rhs); + } +} + +impl<'a> Sum<&'a Self> for DMat3 { + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, |a, &b| Self::add(a, b)) + } +} + +impl<'a> Product<&'a Self> for DMat3 { + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::IDENTITY, |a, &b| Self::mul(a, b)) + } +} + +impl PartialEq for DMat3 { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.x_axis.eq(&rhs.x_axis) && self.y_axis.eq(&rhs.y_axis) && self.z_axis.eq(&rhs.z_axis) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsRef<[f64; 9]> for DMat3 { + #[inline] + fn as_ref(&self) -> &[f64; 9] { + unsafe { &*(self as *const Self as *const [f64; 9]) } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsMut<[f64; 9]> for DMat3 { + #[inline] + fn as_mut(&mut self) -> &mut [f64; 9] { + unsafe { &mut *(self as *mut Self as *mut [f64; 9]) } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Debug for DMat3 { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct(stringify!(DMat3)) + .field("x_axis", &self.x_axis) + .field("y_axis", &self.y_axis) + .field("z_axis", &self.z_axis) + .finish() + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Display for DMat3 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "[{}, {}, {}]", self.x_axis, self.y_axis, self.z_axis) + } +} diff --git a/src/f64/dmat4.rs b/src/f64/dmat4.rs new file mode 100644 index 00000000..082021c4 --- /dev/null +++ b/src/f64/dmat4.rs @@ -0,0 +1,1208 @@ +// Generated from mat.rs template. Edit the template, not the generated file. + +use crate::{swizzles::*, DMat3, DQuat, DVec3, DVec4, EulerRot, Mat4}; +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::iter::{Product, Sum}; +use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; + +#[cfg(not(feature = "std"))] +use num_traits::Float; + +/// Creates a 4x4 matrix from column vectors. +#[inline(always)] +pub const fn dmat4(x_axis: DVec4, y_axis: DVec4, z_axis: DVec4, w_axis: DVec4) -> DMat4 { + DMat4::from_cols(x_axis, y_axis, z_axis, w_axis) +} + +/// A 4x4 column major matrix. +/// +/// This 4x4 matrix type features convenience methods for creating and using affine transforms and +/// perspective projections. If you are primarily dealing with 3D affine transformations +/// considering using [`DAffine3`](crate::DAffine3) which is faster than a 4x4 matrix +/// for some affine operations. +/// +/// Affine transformations including 3D translation, rotation and scale can be created +/// using methods such as [`Self::from_translation()`], [`Self::from_quat()`], +/// [`Self::from_scale()`] and [`Self::from_scale_rotation_translation()`]. +/// +/// Othographic projections can be created using the methods [`Self::orthographic_lh()`] for +/// left-handed coordinate systems and [`Self::orthographic_rh()`] for right-handed +/// systems. The resulting matrix is also an affine transformation. +/// +/// The [`Self::transform_point3()`] and [`Self::transform_vector3()`] convenience methods +/// are provided for performing affine transformations on 3D vectors and points. These +/// multiply 3D inputs as 4D vectors with an implicit `w` value of `1` for points and `0` +/// for vectors respectively. These methods assume that `Self` contains a valid affine +/// transform. +/// +/// Perspective projections can be created using methods such as +/// [`Self::perspective_lh()`], [`Self::perspective_infinite_lh()`] and +/// [`Self::perspective_infinite_reverse_lh()`] for left-handed co-ordinate systems and +/// [`Self::perspective_rh()`], [`Self::perspective_infinite_rh()`] and +/// [`Self::perspective_infinite_reverse_rh()`] for right-handed co-ordinate systems. +/// +/// The resulting perspective project can be use to transform 3D vectors as points with +/// perspective correction using the [`Self::project_point3()`] convenience method. +#[derive(Clone, Copy)] +#[cfg_attr(feature = "cuda", repr(align(16)))] +pub struct DMat4 { + pub x_axis: DVec4, + pub y_axis: DVec4, + pub z_axis: DVec4, + pub w_axis: DVec4, +} + +impl DMat4 { + /// A 4x4 matrix with all elements set to `0.0`. + pub const ZERO: Self = Self::from_cols(DVec4::ZERO, DVec4::ZERO, DVec4::ZERO, DVec4::ZERO); + + /// A 4x4 identity matrix, where all diagonal elements are `1`, and all off-diagonal elements are `0`. + pub const IDENTITY: Self = Self::from_cols(DVec4::X, DVec4::Y, DVec4::Z, DVec4::W); + + /// All NAN:s. + pub const NAN: Self = Self::from_cols(DVec4::NAN, DVec4::NAN, DVec4::NAN, DVec4::NAN); + + #[allow(clippy::too_many_arguments)] + #[inline(always)] + const fn new( + m00: f64, + m01: f64, + m02: f64, + m03: f64, + m10: f64, + m11: f64, + m12: f64, + m13: f64, + m20: f64, + m21: f64, + m22: f64, + m23: f64, + m30: f64, + m31: f64, + m32: f64, + m33: f64, + ) -> Self { + Self { + x_axis: DVec4::new(m00, m01, m02, m03), + y_axis: DVec4::new(m10, m11, m12, m13), + z_axis: DVec4::new(m20, m21, m22, m23), + w_axis: DVec4::new(m30, m31, m32, m33), + } + } + + /// Creates a 4x4 matrix from two column vectors. + #[inline(always)] + pub const fn from_cols(x_axis: DVec4, y_axis: DVec4, z_axis: DVec4, w_axis: DVec4) -> Self { + Self { + x_axis, + y_axis, + z_axis, + w_axis, + } + } + + /// Creates a 4x4 matrix from a `[f64; 16]` array stored in column major order. + /// If your data is stored in row major you will need to `transpose` the returned + /// matrix. + #[inline] + pub const fn from_cols_array(m: &[f64; 16]) -> Self { + Self::new( + m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], m[9], m[10], m[11], m[12], m[13], + m[14], m[15], + ) + } + + /// Creates a `[f64; 16]` array storing data in column major order. + /// If you require data in row major order `transpose` the matrix first. + #[inline] + pub fn to_cols_array(&self) -> [f64; 16] { + [ + self.x_axis.x, + self.x_axis.y, + self.x_axis.z, + self.x_axis.w, + self.y_axis.x, + self.y_axis.y, + self.y_axis.z, + self.y_axis.w, + self.z_axis.x, + self.z_axis.y, + self.z_axis.z, + self.z_axis.w, + self.w_axis.x, + self.w_axis.y, + self.w_axis.z, + self.w_axis.w, + ] + } + + /// Creates a 4x4 matrix from a `[[f64; 4]; 4]` 4D array stored in column major order. + /// If your data is in row major order you will need to `transpose` the returned + /// matrix. + #[inline] + pub const fn from_cols_array_2d(m: &[[f64; 4]; 4]) -> Self { + Self::from_cols( + DVec4::from_array(m[0]), + DVec4::from_array(m[1]), + DVec4::from_array(m[2]), + DVec4::from_array(m[3]), + ) + } + + /// Creates a `[[f64; 4]; 4]` 4D array storing data in column major order. + /// If you require data in row major order `transpose` the matrix first. + #[inline] + pub fn to_cols_array_2d(&self) -> [[f64; 4]; 4] { + [ + self.x_axis.to_array(), + self.y_axis.to_array(), + self.z_axis.to_array(), + self.w_axis.to_array(), + ] + } + + /// Creates a 4x4 matrix with its diagonal set to `diagonal` and all other entries set to 0. + #[doc(alias = "scale")] + #[inline] + pub fn from_diagonal(diagonal: DVec4) -> Self { + Self::new( + diagonal.x, 0.0, 0.0, 0.0, 0.0, diagonal.y, 0.0, 0.0, 0.0, 0.0, diagonal.z, 0.0, 0.0, + 0.0, 0.0, diagonal.w, + ) + } + + fn quat_to_axes(rotation: DQuat) -> (DVec4, DVec4, DVec4) { + glam_assert!(rotation.is_normalized()); + + let (x, y, z, w) = rotation.into(); + let x2 = x + x; + let y2 = y + y; + let z2 = z + z; + let xx = x * x2; + let xy = x * y2; + let xz = x * z2; + let yy = y * y2; + let yz = y * z2; + let zz = z * z2; + let wx = w * x2; + let wy = w * y2; + let wz = w * z2; + + let x_axis = DVec4::new(1.0 - (yy + zz), xy + wz, xz - wy, 0.0); + let y_axis = DVec4::new(xy - wz, 1.0 - (xx + zz), yz + wx, 0.0); + let z_axis = DVec4::new(xz + wy, yz - wx, 1.0 - (xx + yy), 0.0); + (x_axis, y_axis, z_axis) + } + + /// Creates an affine transformation matrix from the given 3D `scale`, `rotation` and + /// `translation`. + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + /// + /// # Panics + /// + /// Will panic if `rotation` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn from_scale_rotation_translation( + scale: DVec3, + rotation: DQuat, + translation: DVec3, + ) -> Self { + let (x_axis, y_axis, z_axis) = Self::quat_to_axes(rotation); + Self::from_cols( + x_axis.mul(scale.x), + y_axis.mul(scale.y), + z_axis.mul(scale.z), + DVec4::from((translation, 1.0)), + ) + } + + /// Creates an affine transformation matrix from the given 3D `translation`. + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + /// + /// # Panics + /// + /// Will panic if `rotation` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn from_rotation_translation(rotation: DQuat, translation: DVec3) -> Self { + let (x_axis, y_axis, z_axis) = Self::quat_to_axes(rotation); + Self::from_cols(x_axis, y_axis, z_axis, DVec4::from((translation, 1.0))) + } + + /// Extracts `scale`, `rotation` and `translation` from `self`. The input matrix is + /// expected to be a 3D affine transformation matrix otherwise the output will be invalid. + /// + /// # Panics + /// + /// Will panic if the determinant of `self` is zero or if the resulting scale vector + /// contains any zero elements when `glam_assert` is enabled. + #[inline] + pub fn to_scale_rotation_translation(&self) -> (DVec3, DQuat, DVec3) { + let det = self.determinant(); + glam_assert!(det != 0.0); + + let scale = DVec3::new( + self.x_axis.length() * det.signum(), + self.y_axis.length(), + self.z_axis.length(), + ); + + glam_assert!(scale.cmpne(DVec3::ZERO).all()); + + let inv_scale = scale.recip(); + + let rotation = DQuat::from_rotation_axes( + self.x_axis.mul(inv_scale.x).xyz(), + self.y_axis.mul(inv_scale.y).xyz(), + self.z_axis.mul(inv_scale.z).xyz(), + ); + + let translation = self.w_axis.xyz(); + + (scale, rotation, translation) + } + + /// Creates an affine transformation matrix from the given `rotation` quaternion. + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + /// + /// # Panics + /// + /// Will panic if `rotation` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn from_quat(rotation: DQuat) -> Self { + let (x_axis, y_axis, z_axis) = Self::quat_to_axes(rotation); + Self::from_cols(x_axis, y_axis, z_axis, DVec4::W) + } + + /// Creates an affine transformation matrix from the given 3x3 linear transformation + /// matrix. + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + #[inline] + pub fn from_mat3(m: DMat3) -> Self { + Self::from_cols( + DVec4::from((m.x_axis, 0.0)), + DVec4::from((m.y_axis, 0.0)), + DVec4::from((m.z_axis, 0.0)), + DVec4::W, + ) + } + + /// Creates an affine transformation matrix from the given 3D `translation`. + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + #[inline] + pub fn from_translation(translation: DVec3) -> Self { + Self::from_cols( + DVec4::X, + DVec4::Y, + DVec4::Z, + DVec4::new(translation.x, translation.y, translation.z, 1.0), + ) + } + + /// Creates an affine transformation matrix containing a 3D rotation around a normalized + /// rotation `axis` of `angle` (in radians). + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + /// + /// # Panics + /// + /// Will panic if `axis` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn from_axis_angle(axis: DVec3, angle: f64) -> Self { + glam_assert!(axis.is_normalized()); + + let (sin, cos) = angle.sin_cos(); + let axis_sin = axis.mul(sin); + let axis_sq = axis.mul(axis); + let omc = 1.0 - cos; + let xyomc = axis.x * axis.y * omc; + let xzomc = axis.x * axis.z * omc; + let yzomc = axis.y * axis.z * omc; + Self::from_cols( + DVec4::new( + axis_sq.x * omc + cos, + xyomc + axis_sin.z, + xzomc - axis_sin.y, + 0.0, + ), + DVec4::new( + xyomc - axis_sin.z, + axis_sq.y * omc + cos, + yzomc + axis_sin.x, + 0.0, + ), + DVec4::new( + xzomc + axis_sin.y, + yzomc - axis_sin.x, + axis_sq.z * omc + cos, + 0.0, + ), + DVec4::W, + ) + } + + #[inline] + /// Creates a affine transformation matrix containing a rotation from the given euler + /// rotation sequence and angles (in radians). + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + pub fn from_euler(order: EulerRot, a: f64, b: f64, c: f64) -> Self { + let quat = DQuat::from_euler(order, a, b, c); + Self::from_quat(quat) + } + + /// Creates an affine transformation matrix containing a 3D rotation around the x axis of + /// `angle` (in radians). + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + #[inline] + pub fn from_rotation_x(angle: f64) -> Self { + let (sina, cosa) = angle.sin_cos(); + Self::from_cols( + DVec4::X, + DVec4::new(0.0, cosa, sina, 0.0), + DVec4::new(0.0, -sina, cosa, 0.0), + DVec4::W, + ) + } + + /// Creates an affine transformation matrix containing a 3D rotation around the y axis of + /// `angle` (in radians). + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + #[inline] + pub fn from_rotation_y(angle: f64) -> Self { + let (sina, cosa) = angle.sin_cos(); + Self::from_cols( + DVec4::new(cosa, 0.0, -sina, 0.0), + DVec4::Y, + DVec4::new(sina, 0.0, cosa, 0.0), + DVec4::W, + ) + } + + /// Creates an affine transformation matrix containing a 3D rotation around the z axis of + /// `angle` (in radians). + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + #[inline] + pub fn from_rotation_z(angle: f64) -> Self { + let (sina, cosa) = angle.sin_cos(); + Self::from_cols( + DVec4::new(cosa, sina, 0.0, 0.0), + DVec4::new(-sina, cosa, 0.0, 0.0), + DVec4::Z, + DVec4::W, + ) + } + + /// Creates an affine transformation matrix containing the given 3D non-uniform `scale`. + /// + /// The resulting matrix can be used to transform 3D points and vectors. See + /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. + /// + /// # Panics + /// + /// Will panic if all elements of `scale` are zero when `glam_assert` is enabled. + #[inline] + pub fn from_scale(scale: DVec3) -> Self { + // Do not panic as long as any component is non-zero + glam_assert!(scale.cmpne(DVec3::ZERO).any()); + + Self::from_cols( + DVec4::new(scale.x, 0.0, 0.0, 0.0), + DVec4::new(0.0, scale.y, 0.0, 0.0), + DVec4::new(0.0, 0.0, scale.z, 0.0), + DVec4::W, + ) + } + + /// Creates a 4x4 matrix from the first 16 values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 16 elements long. + #[inline] + pub const fn from_cols_slice(slice: &[f64]) -> Self { + Self::new( + slice[0], slice[1], slice[2], slice[3], slice[4], slice[5], slice[6], slice[7], + slice[8], slice[9], slice[10], slice[11], slice[12], slice[13], slice[14], slice[15], + ) + } + + /// Writes the columns of `self` to the first 16 elements in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 16 elements long. + #[inline] + pub fn write_cols_to_slice(self, slice: &mut [f64]) { + slice[0] = self.x_axis.x; + slice[1] = self.x_axis.y; + slice[2] = self.x_axis.z; + slice[3] = self.x_axis.w; + slice[4] = self.y_axis.x; + slice[5] = self.y_axis.y; + slice[6] = self.y_axis.z; + slice[7] = self.y_axis.w; + slice[8] = self.z_axis.x; + slice[9] = self.z_axis.y; + slice[10] = self.z_axis.z; + slice[11] = self.z_axis.w; + slice[12] = self.w_axis.x; + slice[13] = self.w_axis.y; + slice[14] = self.w_axis.z; + slice[15] = self.w_axis.w; + } + + /// Returns the matrix column for the given `index`. + /// + /// # Panics + /// + /// Panics if `index` is greater than 3. + #[inline] + pub fn col(&self, index: usize) -> DVec4 { + match index { + 0 => self.x_axis, + 1 => self.y_axis, + 2 => self.z_axis, + 3 => self.w_axis, + _ => panic!("index out of bounds"), + } + } + + /// Returns a mutable reference to the matrix column for the given `index`. + /// + /// # Panics + /// + /// Panics if `index` is greater than 3. + #[inline] + pub fn col_mut(&mut self, index: usize) -> &mut DVec4 { + match index { + 0 => &mut self.x_axis, + 1 => &mut self.y_axis, + 2 => &mut self.z_axis, + 3 => &mut self.w_axis, + _ => panic!("index out of bounds"), + } + } + + /// Returns the matrix row for the given `index`. + /// + /// # Panics + /// + /// Panics if `index` is greater than 3. + #[inline] + pub fn row(&self, index: usize) -> DVec4 { + match index { + 0 => DVec4::new(self.x_axis.x, self.y_axis.x, self.z_axis.x, self.w_axis.x), + 1 => DVec4::new(self.x_axis.y, self.y_axis.y, self.z_axis.y, self.w_axis.y), + 2 => DVec4::new(self.x_axis.z, self.y_axis.z, self.z_axis.z, self.w_axis.z), + 3 => DVec4::new(self.x_axis.w, self.y_axis.w, self.z_axis.w, self.w_axis.w), + _ => panic!("index out of bounds"), + } + } + + /// Returns `true` if, and only if, all elements are finite. + /// If any element is either `NaN`, positive or negative infinity, this will return `false`. + #[inline] + pub fn is_finite(&self) -> bool { + self.x_axis.is_finite() + && self.y_axis.is_finite() + && self.z_axis.is_finite() + && self.w_axis.is_finite() + } + + /// Returns `true` if any elements are `NaN`. + #[inline] + pub fn is_nan(&self) -> bool { + self.x_axis.is_nan() || self.y_axis.is_nan() || self.z_axis.is_nan() || self.w_axis.is_nan() + } + + /// Returns the transpose of `self`. + #[must_use] + #[inline] + pub fn transpose(&self) -> Self { + Self { + x_axis: DVec4::new(self.x_axis.x, self.y_axis.x, self.z_axis.x, self.w_axis.x), + y_axis: DVec4::new(self.x_axis.y, self.y_axis.y, self.z_axis.y, self.w_axis.y), + z_axis: DVec4::new(self.x_axis.z, self.y_axis.z, self.z_axis.z, self.w_axis.z), + w_axis: DVec4::new(self.x_axis.w, self.y_axis.w, self.z_axis.w, self.w_axis.w), + } + } + + /// Returns the determinant of `self`. + pub fn determinant(&self) -> f64 { + let (m00, m01, m02, m03) = self.x_axis.into(); + let (m10, m11, m12, m13) = self.y_axis.into(); + let (m20, m21, m22, m23) = self.z_axis.into(); + let (m30, m31, m32, m33) = self.w_axis.into(); + + 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) + } + + /// Returns the inverse of `self`. + /// + /// If the matrix is not invertible the returned matrix will be invalid. + /// + /// # Panics + /// + /// Will panic if the determinant of `self` is zero when `glam_assert` is enabled. + #[must_use] + pub fn inverse(&self) -> Self { + let (m00, m01, m02, m03) = self.x_axis.into(); + let (m10, m11, m12, m13) = self.y_axis.into(); + let (m20, m21, m22, m23) = self.z_axis.into(); + let (m30, m31, m32, m33) = self.w_axis.into(); + + let coef00 = m22 * m33 - m32 * m23; + let coef02 = m12 * m33 - m32 * m13; + let coef03 = m12 * m23 - m22 * m13; + + let coef04 = m21 * m33 - m31 * m23; + let coef06 = m11 * m33 - m31 * m13; + let coef07 = m11 * m23 - m21 * m13; + + let coef08 = m21 * m32 - m31 * m22; + let coef10 = m11 * m32 - m31 * m12; + let coef11 = m11 * m22 - m21 * m12; + + let coef12 = m20 * m33 - m30 * m23; + let coef14 = m10 * m33 - m30 * m13; + let coef15 = m10 * m23 - m20 * m13; + + let coef16 = m20 * m32 - m30 * m22; + let coef18 = m10 * m32 - m30 * m12; + let coef19 = m10 * m22 - m20 * m12; + + let coef20 = m20 * m31 - m30 * m21; + let coef22 = m10 * m31 - m30 * m11; + let coef23 = m10 * m21 - m20 * m11; + + let fac0 = DVec4::new(coef00, coef00, coef02, coef03); + let fac1 = DVec4::new(coef04, coef04, coef06, coef07); + let fac2 = DVec4::new(coef08, coef08, coef10, coef11); + let fac3 = DVec4::new(coef12, coef12, coef14, coef15); + let fac4 = DVec4::new(coef16, coef16, coef18, coef19); + let fac5 = DVec4::new(coef20, coef20, coef22, coef23); + + let vec0 = DVec4::new(m10, m00, m00, m00); + let vec1 = DVec4::new(m11, m01, m01, m01); + let vec2 = DVec4::new(m12, m02, m02, m02); + let vec3 = DVec4::new(m13, m03, m03, m03); + + let inv0 = vec1.mul(fac0).sub(vec2.mul(fac1)).add(vec3.mul(fac2)); + let inv1 = vec0.mul(fac0).sub(vec2.mul(fac3)).add(vec3.mul(fac4)); + let inv2 = vec0.mul(fac1).sub(vec1.mul(fac3)).add(vec3.mul(fac5)); + let inv3 = vec0.mul(fac2).sub(vec1.mul(fac4)).add(vec2.mul(fac5)); + + let sign_a = DVec4::new(1.0, -1.0, 1.0, -1.0); + let sign_b = DVec4::new(-1.0, 1.0, -1.0, 1.0); + + let inverse = Self::from_cols( + inv0.mul(sign_a), + inv1.mul(sign_b), + inv2.mul(sign_a), + inv3.mul(sign_b), + ); + + let col0 = DVec4::new( + inverse.x_axis.x, + inverse.y_axis.x, + inverse.z_axis.x, + inverse.w_axis.x, + ); + + let dot0 = self.x_axis.mul(col0); + let dot1 = dot0.x + dot0.y + dot0.z + dot0.w; + + glam_assert!(dot1 != 0.0); + + let rcp_det = dot1.recip(); + inverse.mul(rcp_det) + } + + #[inline] + fn look_to_lh(eye: DVec3, dir: DVec3, up: DVec3) -> Self { + let f = dir.normalize(); + let s = up.cross(f).normalize(); + let u = f.cross(s); + Self::from_cols( + DVec4::new(s.x, u.x, f.x, 0.0), + DVec4::new(s.y, u.y, f.y, 0.0), + DVec4::new(s.z, u.z, f.z, 0.0), + DVec4::new(-s.dot(eye), -u.dot(eye), -f.dot(eye), 1.0), + ) + } + + /// Creates a left-handed view matrix using a camera position, an up direction, and a focal + /// point. + /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=forward`. + /// + /// # Panics + /// + /// Will panic if `up` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn look_at_lh(eye: DVec3, center: DVec3, up: DVec3) -> Self { + glam_assert!(up.is_normalized()); + Self::look_to_lh(eye, center.sub(eye), up) + } + + /// Creates a right-handed view matrix using a camera position, an up direction, and a focal + /// point. + /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=back`. + /// + /// # Panics + /// + /// Will panic if `up` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn look_at_rh(eye: DVec3, center: DVec3, up: DVec3) -> Self { + glam_assert!(up.is_normalized()); + Self::look_to_lh(eye, eye.sub(center), up) + } + + /// Creates a right-handed perspective projection matrix with [-1,1] depth range. + /// This is the same as the OpenGL `gluPerspective` function. + /// See + #[inline] + pub fn perspective_rh_gl( + fov_y_radians: f64, + aspect_ratio: f64, + z_near: f64, + z_far: f64, + ) -> Self { + let inv_length = 1.0 / (z_near - z_far); + let f = 1.0 / (0.5 * fov_y_radians).tan(); + let a = f / aspect_ratio; + let b = (z_near + z_far) * inv_length; + let c = (2.0 * z_near * z_far) * inv_length; + Self::from_cols( + DVec4::new(a, 0.0, 0.0, 0.0), + DVec4::new(0.0, f, 0.0, 0.0), + DVec4::new(0.0, 0.0, b, -1.0), + DVec4::new(0.0, 0.0, c, 0.0), + ) + } + + /// Creates a left-handed perspective projection matrix with `[0,1]` depth range. + /// + /// # Panics + /// + /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is + /// enabled. + #[inline] + pub fn perspective_lh(fov_y_radians: f64, aspect_ratio: f64, z_near: f64, z_far: f64) -> Self { + glam_assert!(z_near > 0.0 && z_far > 0.0); + let (sin_fov, cos_fov) = (0.5 * fov_y_radians).sin_cos(); + let h = cos_fov / sin_fov; + let w = h / aspect_ratio; + let r = z_far / (z_far - z_near); + Self::from_cols( + DVec4::new(w, 0.0, 0.0, 0.0), + DVec4::new(0.0, h, 0.0, 0.0), + DVec4::new(0.0, 0.0, r, 1.0), + DVec4::new(0.0, 0.0, -r * z_near, 0.0), + ) + } + + /// Creates a right-handed perspective projection matrix with `[0,1]` depth range. + /// + /// # Panics + /// + /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is + /// enabled. + #[inline] + pub fn perspective_rh(fov_y_radians: f64, aspect_ratio: f64, z_near: f64, z_far: f64) -> Self { + glam_assert!(z_near > 0.0 && z_far > 0.0); + let (sin_fov, cos_fov) = (0.5 * fov_y_radians).sin_cos(); + let h = cos_fov / sin_fov; + let w = h / aspect_ratio; + let r = z_far / (z_near - z_far); + Self::from_cols( + DVec4::new(w, 0.0, 0.0, 0.0), + DVec4::new(0.0, h, 0.0, 0.0), + DVec4::new(0.0, 0.0, r, -1.0), + DVec4::new(0.0, 0.0, r * z_near, 0.0), + ) + } + + /// Creates an infinite left-handed perspective projection matrix with `[0,1]` depth range. + /// + /// # Panics + /// + /// Will panic if `z_near` is less than or equal to zero when `glam_assert` is enabled. + #[inline] + pub fn perspective_infinite_lh(fov_y_radians: f64, aspect_ratio: f64, z_near: f64) -> Self { + glam_assert!(z_near > 0.0); + let (sin_fov, cos_fov) = (0.5 * fov_y_radians).sin_cos(); + let h = cos_fov / sin_fov; + let w = h / aspect_ratio; + Self::from_cols( + DVec4::new(w, 0.0, 0.0, 0.0), + DVec4::new(0.0, h, 0.0, 0.0), + DVec4::new(0.0, 0.0, 1.0, 1.0), + DVec4::new(0.0, 0.0, -z_near, 0.0), + ) + } + + /// Creates an infinite left-handed perspective projection matrix with `[0,1]` depth range. + /// + /// # Panics + /// + /// Will panic if `z_near` is less than or equal to zero when `glam_assert` is enabled. + #[inline] + pub fn perspective_infinite_reverse_lh( + fov_y_radians: f64, + aspect_ratio: f64, + z_near: f64, + ) -> Self { + glam_assert!(z_near > 0.0); + let (sin_fov, cos_fov) = (0.5 * fov_y_radians).sin_cos(); + let h = cos_fov / sin_fov; + let w = h / aspect_ratio; + Self::from_cols( + DVec4::new(w, 0.0, 0.0, 0.0), + DVec4::new(0.0, h, 0.0, 0.0), + DVec4::new(0.0, 0.0, 0.0, 1.0), + DVec4::new(0.0, 0.0, z_near, 0.0), + ) + } + + /// Creates an infinite right-handed perspective projection matrix with + /// `[0,1]` depth range. + #[inline] + pub fn perspective_infinite_rh(fov_y_radians: f64, aspect_ratio: f64, z_near: f64) -> Self { + glam_assert!(z_near > 0.0); + let f = 1.0 / (0.5 * fov_y_radians).tan(); + Self::from_cols( + DVec4::new(f / aspect_ratio, 0.0, 0.0, 0.0), + DVec4::new(0.0, f, 0.0, 0.0), + DVec4::new(0.0, 0.0, -1.0, -1.0), + DVec4::new(0.0, 0.0, -z_near, 0.0), + ) + } + + /// Creates an infinite reverse right-handed perspective projection matrix + /// with `[0,1]` depth range. + #[inline] + pub fn perspective_infinite_reverse_rh( + fov_y_radians: f64, + aspect_ratio: f64, + z_near: f64, + ) -> Self { + glam_assert!(z_near > 0.0); + let f = 1.0 / (0.5 * fov_y_radians).tan(); + Self::from_cols( + DVec4::new(f / aspect_ratio, 0.0, 0.0, 0.0), + DVec4::new(0.0, f, 0.0, 0.0), + DVec4::new(0.0, 0.0, 0.0, -1.0), + DVec4::new(0.0, 0.0, z_near, 0.0), + ) + } + + /// Creates a right-handed orthographic projection matrix with `[-1,1]` depth + /// range. This is the same as the OpenGL `glOrtho` function in OpenGL. + /// See + /// + #[inline] + pub fn orthographic_rh_gl( + left: f64, + right: f64, + bottom: f64, + top: f64, + near: f64, + far: f64, + ) -> Self { + let a = 2.0 / (right - left); + let b = 2.0 / (top - bottom); + let c = -2.0 / (far - near); + let tx = -(right + left) / (right - left); + let ty = -(top + bottom) / (top - bottom); + let tz = -(far + near) / (far - near); + + Self::from_cols( + DVec4::new(a, 0.0, 0.0, 0.0), + DVec4::new(0.0, b, 0.0, 0.0), + DVec4::new(0.0, 0.0, c, 0.0), + DVec4::new(tx, ty, tz, 1.0), + ) + } + + /// Creates a left-handed orthographic projection matrix with `[0,1]` depth range. + #[inline] + pub fn orthographic_lh( + left: f64, + right: f64, + bottom: f64, + top: f64, + near: f64, + far: f64, + ) -> Self { + let rcp_width = 1.0 / (right - left); + let rcp_height = 1.0 / (top - bottom); + let r = 1.0 / (far - near); + Self::from_cols( + DVec4::new(rcp_width + rcp_width, 0.0, 0.0, 0.0), + DVec4::new(0.0, rcp_height + rcp_height, 0.0, 0.0), + DVec4::new(0.0, 0.0, r, 0.0), + DVec4::new( + -(left + right) * rcp_width, + -(top + bottom) * rcp_height, + -r * near, + 1.0, + ), + ) + } + + /// Creates a right-handed orthographic projection matrix with `[0,1]` depth range. + #[inline] + pub fn orthographic_rh( + left: f64, + right: f64, + bottom: f64, + top: f64, + near: f64, + far: f64, + ) -> Self { + let rcp_width = 1.0 / (right - left); + let rcp_height = 1.0 / (top - bottom); + let r = 1.0 / (near - far); + Self::from_cols( + DVec4::new(rcp_width + rcp_width, 0.0, 0.0, 0.0), + DVec4::new(0.0, rcp_height + rcp_height, 0.0, 0.0), + DVec4::new(0.0, 0.0, r, 0.0), + DVec4::new( + -(left + right) * rcp_width, + -(top + bottom) * rcp_height, + r * near, + 1.0, + ), + ) + } + + /// Transforms the given 3D vector as a point, applying perspective correction. + /// + /// This is the equivalent of multiplying the 3D vector as a 4D vector where `w` is `1.0`. + /// The perspective divide is performed meaning the resulting 3D vector is divided by `w`. + /// + /// This method assumes that `self` contains a projective transform. + #[inline] + pub fn project_point3(&self, rhs: DVec3) -> DVec3 { + let mut res = self.x_axis.mul(rhs.x); + res = self.y_axis.mul(rhs.y).add(res); + res = self.z_axis.mul(rhs.z).add(res); + res = self.w_axis.add(res); + res = res.mul(res.wwww().recip()); + res.xyz() + } + + /// Transforms the given 3D vector as a point. + /// + /// This is the equivalent of multiplying the 3D vector as a 4D vector where `w` is + /// `1.0`. + /// + /// This method assumes that `self` contains a valid affine transform. It does not perform + /// a persective divide, if `self` contains a perspective transform, or if you are unsure, + /// the [`Self::project_point3()`] method should be used instead. + /// + /// # Panics + /// + /// Will panic if the 3rd row of `self` is not `(0, 0, 0, 1)` when `glam_assert` is enabled. + #[inline] + pub fn transform_point3(&self, rhs: DVec3) -> DVec3 { + glam_assert!(self.row(3) == DVec4::W); + let mut res = self.x_axis.mul(rhs.x); + res = self.y_axis.mul(rhs.y).add(res); + res = self.z_axis.mul(rhs.z).add(res); + res = self.w_axis.add(res); + res.xyz() + } + + /// Transforms the give 3D vector as a direction. + /// + /// This is the equivalent of multiplying the 3D vector as a 4D vector where `w` is + /// `0.0`. + /// + /// This method assumes that `self` contains a valid affine transform. + /// + /// # Panics + /// + /// Will panic if the 3rd row of `self` is not `(0, 0, 0, 1)` when `glam_assert` is enabled. + #[inline] + pub fn transform_vector3(&self, rhs: DVec3) -> DVec3 { + glam_assert!(self.row(3) == DVec4::W); + let mut res = self.x_axis.mul(rhs.x); + res = self.y_axis.mul(rhs.y).add(res); + res = self.z_axis.mul(rhs.z).add(res); + res.xyz() + } + + /// Transforms a 4D vector. + #[inline] + pub fn mul_vec4(&self, rhs: DVec4) -> DVec4 { + let mut res = self.x_axis.mul(rhs.x); + res = res.add(self.y_axis.mul(rhs.y)); + res = res.add(self.z_axis.mul(rhs.z)); + res = res.add(self.w_axis.mul(rhs.w)); + res + } + + /// Multiplies two 4x4 matrices. + #[inline] + pub fn mul_mat4(&self, rhs: &Self) -> Self { + Self::from_cols( + self.mul(rhs.x_axis), + self.mul(rhs.y_axis), + self.mul(rhs.z_axis), + self.mul(rhs.w_axis), + ) + } + + /// Adds two 4x4 matrices. + #[inline] + pub fn add_mat4(&self, rhs: &Self) -> Self { + Self::from_cols( + self.x_axis.add(rhs.x_axis), + self.y_axis.add(rhs.y_axis), + self.z_axis.add(rhs.z_axis), + self.w_axis.add(rhs.w_axis), + ) + } + + /// Subtracts two 4x4 matrices. + #[inline] + pub fn sub_mat4(&self, rhs: &Self) -> Self { + Self::from_cols( + self.x_axis.sub(rhs.x_axis), + self.y_axis.sub(rhs.y_axis), + self.z_axis.sub(rhs.z_axis), + self.w_axis.sub(rhs.w_axis), + ) + } + + /// Multiplies a 4x4 matrix by a scalar. + #[inline] + pub fn mul_scalar(&self, rhs: f64) -> Self { + Self::from_cols( + self.x_axis.mul(rhs), + self.y_axis.mul(rhs), + self.z_axis.mul(rhs), + self.w_axis.mul(rhs), + ) + } + + /// Returns true if the absolute difference of all elements between `self` and `rhs` + /// is less than or equal to `max_abs_diff`. + /// + /// This can be used to compare if two matrices contain similar elements. It works best + /// when comparing with a known value. The `max_abs_diff` that should be used used + /// depends on the values being compared against. + /// + /// For more see + /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/). + #[inline] + pub fn abs_diff_eq(&self, rhs: Self, max_abs_diff: f64) -> bool { + self.x_axis.abs_diff_eq(rhs.x_axis, max_abs_diff) + && self.y_axis.abs_diff_eq(rhs.y_axis, max_abs_diff) + && self.z_axis.abs_diff_eq(rhs.z_axis, max_abs_diff) + && self.w_axis.abs_diff_eq(rhs.w_axis, max_abs_diff) + } + + #[inline] + pub fn as_mat4(&self) -> Mat4 { + Mat4::from_cols( + self.x_axis.as_vec4(), + self.y_axis.as_vec4(), + self.z_axis.as_vec4(), + self.w_axis.as_vec4(), + ) + } +} + +impl Default for DMat4 { + #[inline] + fn default() -> Self { + Self::IDENTITY + } +} + +impl Add for DMat4 { + type Output = Self; + #[inline] + fn add(self, rhs: Self) -> Self::Output { + self.add_mat4(&rhs) + } +} + +impl AddAssign for DMat4 { + #[inline] + fn add_assign(&mut self, rhs: Self) { + *self = self.add_mat4(&rhs); + } +} + +impl Sub for DMat4 { + type Output = Self; + #[inline] + fn sub(self, rhs: Self) -> Self::Output { + self.sub_mat4(&rhs) + } +} + +impl SubAssign for DMat4 { + #[inline] + fn sub_assign(&mut self, rhs: Self) { + *self = self.sub_mat4(&rhs); + } +} + +impl Neg for DMat4 { + type Output = Self; + #[inline] + fn neg(self) -> Self::Output { + Self::from_cols( + self.x_axis.neg(), + self.y_axis.neg(), + self.z_axis.neg(), + self.w_axis.neg(), + ) + } +} + +impl Mul for DMat4 { + type Output = Self; + #[inline] + fn mul(self, rhs: Self) -> Self::Output { + self.mul_mat4(&rhs) + } +} + +impl MulAssign for DMat4 { + #[inline] + fn mul_assign(&mut self, rhs: Self) { + *self = self.mul_mat4(&rhs); + } +} + +impl Mul for DMat4 { + type Output = DVec4; + #[inline] + fn mul(self, rhs: DVec4) -> Self::Output { + self.mul_vec4(rhs) + } +} + +impl Mul for f64 { + type Output = DMat4; + #[inline] + fn mul(self, rhs: DMat4) -> Self::Output { + rhs.mul_scalar(self) + } +} + +impl Mul for DMat4 { + type Output = Self; + #[inline] + fn mul(self, rhs: f64) -> Self::Output { + self.mul_scalar(rhs) + } +} + +impl MulAssign for DMat4 { + #[inline] + fn mul_assign(&mut self, rhs: f64) { + *self = self.mul_scalar(rhs); + } +} + +impl<'a> Sum<&'a Self> for DMat4 { + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, |a, &b| Self::add(a, b)) + } +} + +impl<'a> Product<&'a Self> for DMat4 { + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::IDENTITY, |a, &b| Self::mul(a, b)) + } +} + +impl PartialEq for DMat4 { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.x_axis.eq(&rhs.x_axis) + && self.y_axis.eq(&rhs.y_axis) + && self.z_axis.eq(&rhs.z_axis) + && self.w_axis.eq(&rhs.w_axis) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsRef<[f64; 16]> for DMat4 { + #[inline] + fn as_ref(&self) -> &[f64; 16] { + unsafe { &*(self as *const Self as *const [f64; 16]) } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsMut<[f64; 16]> for DMat4 { + #[inline] + fn as_mut(&mut self) -> &mut [f64; 16] { + unsafe { &mut *(self as *mut Self as *mut [f64; 16]) } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Debug for DMat4 { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct(stringify!(DMat4)) + .field("x_axis", &self.x_axis) + .field("y_axis", &self.y_axis) + .field("z_axis", &self.z_axis) + .field("w_axis", &self.w_axis) + .finish() + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Display for DMat4 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "[{}, {}, {}, {}]", + self.x_axis, self.y_axis, self.z_axis, self.w_axis + ) + } +} diff --git a/src/f64/dquat.rs b/src/f64/dquat.rs new file mode 100644 index 00000000..2915f46c --- /dev/null +++ b/src/f64/dquat.rs @@ -0,0 +1,836 @@ +// Generated from quat.rs template. Edit the template, not the generated file. + +use crate::{ + euler::{EulerFromQuaternion, EulerRot, EulerToQuaternion}, + DMat3, DMat4, DVec2, DVec3, DVec4, FloatEx, Quat, +}; + +#[cfg(not(feature = "std"))] +use num_traits::Float; + +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::iter::{Product, Sum}; +use core::ops::{Add, Deref, Div, Mul, MulAssign, Neg, Sub}; + +/// Creates a quaternion from `x`, `y`, `z` and `w` values. +/// +/// This should generally not be called manually unless you know what you are doing. Use +/// one of the other constructors instead such as `identity` or `from_axis_angle`. +#[inline] +pub const fn dquat(x: f64, y: f64, z: f64, w: f64) -> DQuat { + DQuat::from_xyzw(x, y, z, w) +} + +/// A quaternion representing an orientation. +/// +/// This quaternion is intended to be of unit length but may denormalize due to +/// floating point "error creep" which can occur when successive quaternion +/// operations are applied. +#[derive(Clone, Copy)] +pub struct DQuat { + x: f64, + y: f64, + z: f64, + w: f64, +} + +impl DQuat { + /// All zeros. + const ZERO: Self = Self::from_array([0.0; 4]); + + /// The identity quaternion. Corresponds to no rotation. + pub const IDENTITY: Self = Self::from_xyzw(0.0, 0.0, 0.0, 1.0); + + /// All NANs. + pub const NAN: Self = Self::from_array([f64::NAN; 4]); + + /// Creates a new rotation quaternion. + /// + /// This should generally not be called manually unless you know what you are doing. + /// Use one of the other constructors instead such as `identity` or `from_axis_angle`. + /// + /// `from_xyzw` is mostly used by unit tests and `serde` deserialization. + /// + /// # Preconditions + /// + /// This function does not check if the input is normalized, it is up to the user to + /// provide normalized input or to normalized the resulting quaternion. + #[inline(always)] + pub const fn from_xyzw(x: f64, y: f64, z: f64, w: f64) -> Self { + Self { x, y, z, w } + } + + /// Creates a rotation quaternion from an array. + /// + /// # Preconditions + /// + /// This function does not check if the input is normalized, it is up to the user to + /// provide normalized input or to normalized the resulting quaternion. + #[inline] + pub const fn from_array(a: [f64; 4]) -> Self { + Self::from_xyzw(a[0], a[1], a[2], a[3]) + } + + /// Creates a new rotation quaternion from a 4D vector. + /// + /// # Preconditions + /// + /// This function does not check if the input is normalized, it is up to the user to + /// provide normalized input or to normalized the resulting quaternion. + #[inline] + pub fn from_vec4(v: DVec4) -> Self { + Self { + x: v.x, + y: v.y, + z: v.z, + w: v.w, + } + } + + /// Creates a rotation quaternion from a slice. + /// + /// # Preconditions + /// + /// This function does not check if the input is normalized, it is up to the user to + /// provide normalized input or to normalized the resulting quaternion. + /// + /// # Panics + /// + /// Panics if `slice` length is less than 4. + #[inline] + pub fn from_slice(slice: &[f64]) -> Self { + Self::from_xyzw(slice[0], slice[1], slice[2], slice[3]) + } + + /// Writes the quaternion to an unaligned slice. + /// + /// # Panics + /// + /// Panics if `slice` length is less than 4. + #[inline] + pub fn write_to_slice(self, slice: &mut [f64]) { + slice[0] = self.x; + slice[1] = self.y; + slice[2] = self.z; + slice[3] = self.w; + } + + /// Create a quaternion for a normalized rotation `axis` and `angle` (in radians). + /// The axis must be normalized (unit-length). + /// + /// # Panics + /// + /// Will panic if `axis` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn from_axis_angle(axis: DVec3, angle: f64) -> Self { + glam_assert!(axis.is_normalized()); + let (s, c) = (angle * 0.5).sin_cos(); + let v = axis * s; + Self::from_xyzw(v.x, v.y, v.z, c) + } + + /// Create a quaternion that rotates `v.length()` radians around `v.normalize()`. + /// + /// `from_scaled_axis(Vec3::ZERO)` results in the identity quaternion. + #[inline] + pub fn from_scaled_axis(v: DVec3) -> Self { + let length = v.length(); + if length == 0.0 { + Self::IDENTITY + } else { + Self::from_axis_angle(v / length, length) + } + } + + /// Creates a quaternion from the `angle` (in radians) around the x axis. + #[inline] + pub fn from_rotation_x(angle: f64) -> Self { + let (s, c) = (angle * 0.5).sin_cos(); + Self::from_xyzw(s, 0.0, 0.0, c) + } + + /// Creates a quaternion from the `angle` (in radians) around the y axis. + #[inline] + pub fn from_rotation_y(angle: f64) -> Self { + let (s, c) = (angle * 0.5).sin_cos(); + Self::from_xyzw(0.0, s, 0.0, c) + } + + /// Creates a quaternion from the `angle` (in radians) around the z axis. + #[inline] + pub fn from_rotation_z(angle: f64) -> Self { + let (s, c) = (angle * 0.5).sin_cos(); + Self::from_xyzw(0.0, 0.0, s, c) + } + + #[inline] + /// Creates a quaternion from the given Euler rotation sequence and the angles (in radians). + pub fn from_euler(euler: EulerRot, a: f64, b: f64, c: f64) -> Self { + euler.new_quat(a, b, c) + } + + /// From the columns of a 3x3 rotation matrix. + #[inline] + pub(crate) fn from_rotation_axes(x_axis: DVec3, y_axis: DVec3, z_axis: DVec3) -> Self { + // Based on https://github.com/microsoft/DirectXMath `XM$quaternionRotationMatrix` + // TODO: sse2 version + let (m00, m01, m02) = x_axis.into(); + let (m10, m11, m12) = y_axis.into(); + let (m20, m21, m22) = z_axis.into(); + if m22 <= 0.0 { + // x^2 + y^2 >= z^2 + w^2 + let dif10 = m11 - m00; + let omm22 = 1.0 - m22; + if dif10 <= 0.0 { + // x^2 >= y^2 + let four_xsq = omm22 - dif10; + let inv4x = 0.5 / four_xsq.sqrt(); + Self::from_xyzw( + four_xsq * inv4x, + (m01 + m10) * inv4x, + (m02 + m20) * inv4x, + (m12 - m21) * inv4x, + ) + } else { + // y^2 >= x^2 + let four_ysq = omm22 + dif10; + let inv4y = 0.5 / four_ysq.sqrt(); + Self::from_xyzw( + (m01 + m10) * inv4y, + four_ysq * inv4y, + (m12 + m21) * inv4y, + (m20 - m02) * inv4y, + ) + } + } else { + // z^2 + w^2 >= x^2 + y^2 + let sum10 = m11 + m00; + let opm22 = 1.0 + m22; + if sum10 <= 0.0 { + // z^2 >= w^2 + let four_zsq = opm22 - sum10; + let inv4z = 0.5 / four_zsq.sqrt(); + Self::from_xyzw( + (m02 + m20) * inv4z, + (m12 + m21) * inv4z, + four_zsq * inv4z, + (m01 - m10) * inv4z, + ) + } else { + // w^2 >= z^2 + let four_wsq = opm22 + sum10; + let inv4w = 0.5 / four_wsq.sqrt(); + Self::from_xyzw( + (m12 - m21) * inv4w, + (m20 - m02) * inv4w, + (m01 - m10) * inv4w, + four_wsq * inv4w, + ) + } + } + } + + /// Creates a quaternion from a 3x3 rotation matrix. + #[inline] + pub fn from_mat3(mat: &DMat3) -> Self { + Self::from_rotation_axes(mat.x_axis, mat.y_axis, mat.z_axis) + } + + /// Creates a quaternion from a 3x3 rotation matrix inside a homogeneous 4x4 matrix. + #[inline] + pub fn from_mat4(mat: &DMat4) -> Self { + Self::from_rotation_axes( + mat.x_axis.truncate(), + mat.y_axis.truncate(), + mat.z_axis.truncate(), + ) + } + + /// Gets the minimal rotation for transforming `from` to `to`. The rotation is in the + /// plane spanned by the two vectors. Will rotate at most 180 degrees. + /// + /// The input vectors must be normalized (unit-length). + /// + /// `from_rotation_arc(from, to) * from ≈ to`. + /// + /// For near-singular cases (from≈to and from≈-to) the current implementation + /// is only accurate to about 0.001 (for `f32`). + /// + /// # Panics + /// + /// Will panic if `from` or `to` are not normalized when `glam_assert` is enabled. + pub fn from_rotation_arc(from: DVec3, to: DVec3) -> Self { + glam_assert!(from.is_normalized()); + glam_assert!(to.is_normalized()); + + const ONE_MINUS_EPS: f64 = 1.0 - 2.0 * core::f64::EPSILON; + let dot = from.dot(to); + if dot > ONE_MINUS_EPS { + // 0° singulary: from ≈ to + Self::IDENTITY + } else if dot < -ONE_MINUS_EPS { + // 180° singulary: from ≈ -to + use core::f64::consts::PI; // half a turn = 𝛕/2 = 180° + Self::from_axis_angle(from.any_orthonormal_vector(), PI) + } else { + let c = from.cross(to); + Self::from_xyzw(c.x, c.y, c.z, 1.0 + dot).normalize() + } + } + + /// Gets the minimal rotation for transforming `from` to either `to` or `-to`. This means + /// that the resulting quaternion will rotate `from` so that it is colinear with `to`. + /// + /// The rotation is in the plane spanned by the two vectors. Will rotate at most 90 + /// degrees. + /// + /// The input vectors must be normalized (unit-length). + /// + /// `to.dot(from_rotation_arc_colinear(from, to) * from).abs() ≈ 1`. + /// + /// # Panics + /// + /// Will panic if `from` or `to` are not normalized when `glam_assert` is enabled. + #[inline] + pub fn from_rotation_arc_colinear(from: DVec3, to: DVec3) -> Self { + if from.dot(to) < 0.0 { + Self::from_rotation_arc(from, -to) + } else { + Self::from_rotation_arc(from, to) + } + } + + /// Gets the minimal rotation for transforming `from` to `to`. The resulting rotation is + /// around the z axis. Will rotate at most 180 degrees. + /// + /// The input vectors must be normalized (unit-length). + /// + /// `from_rotation_arc_2d(from, to) * from ≈ to`. + /// + /// For near-singular cases (from≈to and from≈-to) the current implementation + /// is only accurate to about 0.001 (for `f32`). + /// + /// # Panics + /// + /// Will panic if `from` or `to` are not normalized when `glam_assert` is enabled. + pub fn from_rotation_arc_2d(from: DVec2, to: DVec2) -> Self { + glam_assert!(from.is_normalized()); + glam_assert!(to.is_normalized()); + + const ONE_MINUS_EPSILON: f64 = 1.0 - 2.0 * core::f64::EPSILON; + let dot = from.dot(to); + if dot > ONE_MINUS_EPSILON { + // 0° singulary: from ≈ to + Self::IDENTITY + } else if dot < -ONE_MINUS_EPSILON { + // 180° singulary: from ≈ -to + const COS_FRAC_PI_2: f64 = 0.0; + const SIN_FRAC_PI_2: f64 = 1.0; + // rotation around z by PI radians + Self::from_xyzw(0.0, 0.0, SIN_FRAC_PI_2, COS_FRAC_PI_2) + } else { + // vector3 cross where z=0 + let z = from.x * to.y - to.x * from.y; + let w = 1.0 + dot; + // calculate length with x=0 and y=0 to normalize + let len_rcp = 1.0 / (z * z + w * w).sqrt(); + Self::from_xyzw(0.0, 0.0, z * len_rcp, w * len_rcp) + } + } + + /// Returns the rotation axis and angle (in radians) of `self`. + #[inline] + pub fn to_axis_angle(self) -> (DVec3, f64) { + const EPSILON: f64 = 1.0e-8; + const EPSILON_SQUARED: f64 = EPSILON * EPSILON; + let w = self.w; + let angle = w.acos_approx() * 2.0; + let scale_sq = f64::max(1.0 - w * w, 0.0); + if scale_sq >= EPSILON_SQUARED { + ( + DVec3::new(self.x, self.y, self.z) * scale_sq.sqrt().recip(), + angle, + ) + } else { + (DVec3::X, angle) + } + } + + /// Returns the rotation axis scaled by the rotation in radians. + #[inline] + pub fn to_scaled_axis(self) -> DVec3 { + let (axis, angle) = self.to_axis_angle(); + axis * angle + } + + /// Returns the rotation angles for the given euler rotation sequence. + #[inline] + pub fn to_euler(self, euler: EulerRot) -> (f64, f64, f64) { + euler.convert_quat(self) + } + + /// `[x, y, z, w]` + #[inline] + pub fn to_array(&self) -> [f64; 4] { + [self.x, self.y, self.z, self.w] + } + + /// Returns the vector part of the quaternion. + #[inline] + pub fn xyz(self) -> DVec3 { + DVec3::new(self.x, self.y, self.z) + } + + /// Returns the quaternion conjugate of `self`. For a unit quaternion the + /// conjugate is also the inverse. + #[must_use] + #[inline] + pub fn conjugate(self) -> Self { + Self { + x: -self.x, + y: -self.y, + z: -self.z, + w: self.w, + } + } + + /// Returns the inverse of a normalized quaternion. + /// + /// Typically quaternion inverse returns the conjugate of a normalized quaternion. + /// Because `self` is assumed to already be unit length this method *does not* normalize + /// before returning the conjugate. + /// + /// # Panics + /// + /// Will panic if `self` is not normalized when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn inverse(self) -> Self { + glam_assert!(self.is_normalized()); + self.conjugate() + } + + /// Computes the dot product of `self` and `rhs`. The dot product is + /// equal to the cosine of the angle between two quaternion rotations. + #[inline] + pub fn dot(self, rhs: Self) -> f64 { + DVec4::from(self).dot(DVec4::from(rhs)) + } + + /// Computes the length of `self`. + #[doc(alias = "magnitude")] + #[inline] + pub fn length(self) -> f64 { + DVec4::from(self).length() + } + + /// Computes the squared length of `self`. + /// + /// This is generally faster than `length()` as it avoids a square + /// root operation. + #[doc(alias = "magnitude2")] + #[inline] + pub fn length_squared(self) -> f64 { + DVec4::from(self).length_squared() + } + + /// Computes `1.0 / length()`. + /// + /// For valid results, `self` must _not_ be of length zero. + #[inline] + pub fn length_recip(self) -> f64 { + DVec4::from(self).length_recip() + } + + /// Returns `self` normalized to length 1.0. + /// + /// For valid results, `self` must _not_ be of length zero. + /// + /// Panics + /// + /// Will panic if `self` is zero length when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn normalize(self) -> Self { + Self::from_vec4(DVec4::from(self).normalize()) + } + + /// Returns `true` if, and only if, all elements are finite. + /// If any element is either `NaN`, positive or negative infinity, this will return `false`. + #[inline] + pub fn is_finite(self) -> bool { + DVec4::from(self).is_finite() + } + + #[inline] + pub fn is_nan(self) -> bool { + DVec4::from(self).is_nan() + } + + /// Returns whether `self` of length `1.0` or not. + /// + /// Uses a precision threshold of `1e-6`. + #[inline] + pub fn is_normalized(self) -> bool { + DVec4::from(self).is_normalized() + } + + #[inline] + pub fn is_near_identity(self) -> bool { + // Based on https://github.com/nfrechette/rtm `rtm::quat_near_identity` + let threshold_angle = 0.002_847_144_6; + // Because of floating point precision, we cannot represent very small rotations. + // The closest f32 to 1.0 that is not 1.0 itself yields: + // 0.99999994.acos() * 2.0 = 0.000690533954 rad + // + // An error threshold of 1.e-6 is used by default. + // (1.0 - 1.e-6).acos() * 2.0 = 0.00284714461 rad + // (1.0 - 1.e-7).acos() * 2.0 = 0.00097656250 rad + // + // We don't really care about the angle value itself, only if it's close to 0. + // This will happen whenever quat.w is close to 1.0. + // If the quat.w is close to -1.0, the angle will be near 2*PI which is close to + // a negative 0 rotation. By forcing quat.w to be positive, we'll end up with + // the shortest path. + let positive_w_angle = self.w.abs().acos_approx() * 2.0; + positive_w_angle < threshold_angle + } + + /// Returns the angle (in radians) for the minimal rotation + /// for transforming this quaternion into another. + /// + /// Both quaternions must be normalized. + /// + /// # Panics + /// + /// Will panic if `self` or `rhs` are not normalized when `glam_assert` is enabled. + #[inline] + pub fn angle_between(self, rhs: Self) -> f64 { + glam_assert!(self.is_normalized() && rhs.is_normalized()); + self.dot(rhs).abs().acos_approx() * 2.0 + } + + /// Returns true if the absolute difference of all elements between `self` and `rhs` + /// is less than or equal to `max_abs_diff`. + /// + /// This can be used to compare if two quaternions contain similar elements. It works + /// best when comparing with a known value. The `max_abs_diff` that should be used used + /// depends on the values being compared against. + /// + /// For more see + /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/). + #[inline] + pub fn abs_diff_eq(self, rhs: Self, max_abs_diff: f64) -> bool { + DVec4::from(self).abs_diff_eq(DVec4::from(rhs), max_abs_diff) + } + + /// Performs a linear interpolation between `self` and `rhs` based on + /// the value `s`. + /// + /// When `s` is `0.0`, the result will be equal to `self`. When `s` + /// is `1.0`, the result will be equal to `rhs`. + /// + /// # Panics + /// + /// Will panic if `self` or `end` are not normalized when `glam_assert` is enabled. + #[inline] + #[doc(alias = "mix")] + pub fn lerp(self, end: Self, s: f64) -> Self { + glam_assert!(self.is_normalized()); + glam_assert!(end.is_normalized()); + + let start = self; + let dot = start.dot(end); + let bias = if dot >= 0.0 { 1.0 } else { -1.0 }; + let interpolated = start.add(end.mul(bias).sub(start).mul(s)); + interpolated.normalize() + } + + /// Performs a spherical linear interpolation between `self` and `end` + /// based on the value `s`. + /// + /// When `s` is `0.0`, the result will be equal to `self`. When `s` + /// is `1.0`, the result will be equal to `end`. + /// + /// # Panics + /// + /// Will panic if `self` or `end` are not normalized when `glam_assert` is enabled. + #[inline] + pub fn slerp(self, mut end: Self, s: f64) -> Self { + // http://number-none.com/product/Understanding%20Slerp,%20Then%20Not%20Using%20It/ + glam_assert!(self.is_normalized()); + glam_assert!(end.is_normalized()); + + const DOT_THRESHOLD: f64 = 0.9995; + + // Note that a rotation can be represented by two quaternions: `q` and + // `-q`. The slerp path between `q` and `end` will be different from the + // path between `-q` and `end`. One path will take the long way around and + // one will take the short way. In order to correct for this, the `dot` + // product between `self` and `end` should be positive. If the `dot` + // product is negative, slerp between `self` and `-end`. + let mut dot = self.dot(end); + if dot < 0.0 { + end = -end; + dot = -dot; + } + + if dot > DOT_THRESHOLD { + // assumes lerp returns a normalized quaternion + self.lerp(end, s) + } else { + let theta = dot.acos_approx(); + + let scale1 = (theta * (1.0 - s)).sin(); + let scale2 = (theta * s).sin(); + let theta_sin = theta.sin(); + + self.mul(scale1).add(end.mul(scale2)).mul(theta_sin.recip()) + } + } + + /// Multiplies a quaternion and a 3D vector, returning the rotated vector. + /// + /// # Panics + /// + /// Will panic if `self` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn mul_vec3(self, rhs: DVec3) -> DVec3 { + glam_assert!(self.is_normalized()); + + let w = self.w; + let b = DVec3::new(self.x, self.y, self.z); + let b2 = b.dot(b); + rhs.mul(w * w - b2) + .add(b.mul(rhs.dot(b) * 2.0)) + .add(b.cross(rhs).mul(w * 2.0)) + } + + /// Multiplies two quaternions. If they each represent a rotation, the result will + /// represent the combined rotation. + /// + /// Note that due to floating point rounding the result may not be perfectly normalized. + /// + /// # Panics + /// + /// Will panic if `self` or `rhs` are not normalized when `glam_assert` is enabled. + #[inline] + pub fn mul_quat(self, rhs: Self) -> Self { + glam_assert!(self.is_normalized()); + glam_assert!(rhs.is_normalized()); + + let (x0, y0, z0, w0) = self.into(); + let (x1, y1, z1, w1) = rhs.into(); + Self::from_xyzw( + w0 * x1 + x0 * w1 + y0 * z1 - z0 * y1, + w0 * y1 - x0 * z1 + y0 * w1 + z0 * x1, + w0 * z1 + x0 * y1 - y0 * x1 + z0 * w1, + w0 * w1 - x0 * x1 - y0 * y1 - z0 * z1, + ) + } + + /// Creates a quaternion from a 3x3 rotation matrix inside a 3D affine transform. + #[inline] + pub fn from_affine3(a: &crate::DAffine3) -> Self { + #[allow(clippy::useless_conversion)] + Self::from_rotation_axes( + a.matrix3.x_axis.into(), + a.matrix3.y_axis.into(), + a.matrix3.z_axis.into(), + ) + } + + #[inline] + pub fn as_f32(self) -> Quat { + Quat::from_xyzw(self.x as f32, self.y as f32, self.z as f32, self.w as f32) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Debug for DQuat { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_tuple(stringify!(DQuat)) + .field(&self.x) + .field(&self.y) + .field(&self.z) + .field(&self.w) + .finish() + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Display for DQuat { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(fmt, "[{}, {}, {}, {}]", self.x, self.y, self.z, self.w) + } +} + +impl Add for DQuat { + type Output = Self; + /// Adds two quaternions. + /// + /// The sum is not guaranteed to be normalized. + /// + /// Note that addition is not the same as combining the rotations represented by the + /// two quaternions! That corresponds to multiplication. + #[inline] + fn add(self, rhs: Self) -> Self { + Self::from_vec4(DVec4::from(self) + DVec4::from(rhs)) + } +} + +impl Sub for DQuat { + type Output = Self; + /// Subtracts the `rhs` quaternion from `self`. + /// + /// The difference is not guaranteed to be normalized. + #[inline] + fn sub(self, rhs: Self) -> Self { + Self::from_vec4(DVec4::from(self) - DVec4::from(rhs)) + } +} + +impl Mul for DQuat { + type Output = Self; + /// Multiplies a quaternion by a scalar value. + /// + /// The product is not guaranteed to be normalized. + #[inline] + fn mul(self, rhs: f64) -> Self { + Self::from_vec4(DVec4::from(self) * rhs) + } +} + +impl Div for DQuat { + type Output = Self; + /// Divides a quaternion by a scalar value. + /// The quotient is not guaranteed to be normalized. + #[inline] + fn div(self, rhs: f64) -> Self { + Self::from_vec4(DVec4::from(self) / rhs) + } +} + +impl Mul for DQuat { + type Output = Self; + /// Multiplies two quaternions. If they each represent a rotation, the result will + /// represent the combined rotation. + /// + /// Note that due to floating point rounding the result may not be perfectly + /// normalized. + /// + /// # Panics + /// + /// Will panic if `self` or `rhs` are not normalized when `glam_assert` is enabled. + #[inline] + fn mul(self, rhs: Self) -> Self { + self.mul_quat(rhs) + } +} + +impl MulAssign for DQuat { + /// Multiplies two quaternions. If they each represent a rotation, the result will + /// represent the combined rotation. + /// + /// Note that due to floating point rounding the result may not be perfectly + /// normalized. + /// + /// # Panics + /// + /// Will panic if `self` or `rhs` are not normalized when `glam_assert` is enabled. + #[inline] + fn mul_assign(&mut self, rhs: Self) { + *self = self.mul_quat(rhs); + } +} + +impl Mul for DQuat { + type Output = DVec3; + /// Multiplies a quaternion and a 3D vector, returning the rotated vector. + /// + /// # Panics + /// + /// Will panic if `self` is not normalized when `glam_assert` is enabled. + #[inline] + fn mul(self, rhs: DVec3) -> Self::Output { + self.mul_vec3(rhs) + } +} + +impl Neg for DQuat { + type Output = Self; + #[inline] + fn neg(self) -> Self { + self * -1.0 + } +} + +impl Default for DQuat { + #[inline] + fn default() -> Self { + Self::IDENTITY + } +} + +impl PartialEq for DQuat { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + DVec4::from(*self).eq(&DVec4::from(*rhs)) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsRef<[f64; 4]> for DQuat { + #[inline] + fn as_ref(&self) -> &[f64; 4] { + unsafe { &*(self as *const Self as *const [f64; 4]) } + } +} + +impl<'a> Sum<&'a Self> for DQuat { + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, |a, &b| Self::add(a, b)) + } +} + +impl<'a> Product<&'a Self> for DQuat { + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::IDENTITY, |a, &b| Self::mul(a, b)) + } +} + +impl From for DVec4 { + #[inline] + fn from(q: DQuat) -> Self { + Self::new(q.x, q.y, q.z, q.w) + } +} + +impl From for (f64, f64, f64, f64) { + #[inline] + fn from(q: DQuat) -> Self { + (q.x, q.y, q.z, q.w) + } +} + +impl From for [f64; 4] { + #[inline] + fn from(q: DQuat) -> Self { + [q.x, q.y, q.z, q.w] + } +} + +impl Deref for DQuat { + type Target = crate::deref::XYZW; + #[inline] + fn deref(&self) -> &Self::Target { + unsafe { &*(self as *const Self).cast() } + } +} diff --git a/src/f64/dvec2.rs b/src/f64/dvec2.rs new file mode 100644 index 00000000..6e98ca8e --- /dev/null +++ b/src/f64/dvec2.rs @@ -0,0 +1,1010 @@ +// Generated from vec.rs template. Edit the template, not the generated file. + +use crate::{BVec2, DVec3}; + +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::iter::{Product, Sum}; +use core::{f32, ops::*}; + +#[cfg(not(feature = "std"))] +use num_traits::Float; + +/// Creates a 2-dimensional vector. +#[inline(always)] +pub const fn dvec2(x: f64, y: f64) -> DVec2 { + DVec2::new(x, y) +} + +/// A 2-dimensional vector. +#[derive(Clone, Copy)] +#[cfg_attr(feature = "cuda", repr(C, align(16)))] +pub struct DVec2 { + pub x: f64, + pub y: f64, +} + +impl DVec2 { + /// All zeroes. + pub const ZERO: Self = Self::splat(0.0); + + /// All ones. + pub const ONE: Self = Self::splat(1.0); + + /// All negative ones. + pub const NEG_ONE: Self = Self::splat(-1.0); + + /// All NAN. + pub const NAN: Self = Self::splat(f64::NAN); + + /// `[1.0, 0.0]`: a unit-length vector pointing along the positive X axis. + pub const X: Self = Self::from_array([1.0, 0.0]); + + /// `[0.0, 1.0]`: a unit-length vector pointing along the positive Y axis. + pub const Y: Self = Self::from_array([0.0, 1.0]); + + /// The unit axes. + pub const AXES: [Self; 2] = [Self::X, Self::Y]; + + /// Creates a new vector. + #[inline(always)] + pub const fn new(x: f64, y: f64) -> Self { + Self { x, y } + } + + /// Creates a vector with all elements set to `v`. + #[inline] + pub const fn splat(v: f64) -> Self { + Self { x: v, y: v } + } + + /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use + /// for each element of `self`. + /// + /// A true element in the mask uses the corresponding element from `if_true`, and false + /// uses the element from `if_false`. + #[inline] + pub fn select(mask: BVec2, if_true: Self, if_false: Self) -> Self { + Self { + x: if mask.x { if_true.x } else { if_false.x }, + y: if mask.y { if_true.y } else { if_false.y }, + } + } + + /// Creates a new vector from an array. + #[inline] + pub const fn from_array(a: [f64; 2]) -> Self { + Self::new(a[0], a[1]) + } + + /// `[x, y]` + #[inline] + pub const fn to_array(&self) -> [f64; 2] { + [self.x, self.y] + } + + /// Creates a vector from the first N values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than N elements long. + #[inline] + pub const fn from_slice(slice: &[f64]) -> Self { + Self::new(slice[0], slice[1]) + } + + /// Writes the elements of `self` to the first 2 elements in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than N elements long. + #[inline] + pub fn write_to_slice(self, slice: &mut [f64]) { + slice[0] = self.x; + slice[1] = self.y; + } + + /// Creates a 3D vector from `self` and the given `z` value. + #[inline] + pub const fn extend(self, z: f64) -> DVec3 { + DVec3::new(self.x, self.y, z) + } + + /// Computes the dot product of `self` and `rhs`. + #[inline] + pub fn dot(self, rhs: Self) -> f64 { + (self.x * rhs.x) + (self.y * rhs.y) + } + + /// Returns a vector containing the minimum values for each element of `self` and `rhs`. + /// + /// In other words this computes `[self.x.min(rhs.x), self.y.min(rhs.y), ..]`. + #[inline] + pub fn min(self, rhs: Self) -> Self { + Self { + x: self.x.min(rhs.x), + y: self.y.min(rhs.y), + } + } + + /// Returns a vector containing the maximum values for each element of `self` and `rhs`. + /// + /// In other words this computes `[self.x.max(rhs.x), self.y.max(rhs.y), ..]`. + #[inline] + pub fn max(self, rhs: Self) -> Self { + Self { + x: self.x.max(rhs.x), + y: self.y.max(rhs.y), + } + } + + /// Component-wise clamping of values, similar to [`f32::clamp`]. + /// + /// Each element in `min` must be less-or-equal to the corresponding element in `max`. + /// + /// # Panics + /// + /// Will panic if `min` is greater than `max` when `glam_assert` is enabled. + #[inline] + pub fn clamp(self, min: Self, max: Self) -> Self { + glam_assert!(min.cmple(max).all(), "clamp: expected min <= max"); + self.max(min).min(max) + } + + /// Returns the horizontal minimum of `self`. + /// + /// In other words this computes `min(x, y, ..)`. + #[inline] + pub fn min_element(self) -> f64 { + self.x.min(self.y) + } + + /// Returns the horizontal maximum of `self`. + /// + /// In other words this computes `max(x, y, ..)`. + #[inline] + pub fn max_element(self) -> f64 { + self.x.max(self.y) + } + + /// Returns a vector mask containing the result of a `==` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words, this computes `[self.x == rhs.x, self.y == rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpeq(self, rhs: Self) -> BVec2 { + BVec2::new(self.x.eq(&rhs.x), self.y.eq(&rhs.y)) + } + + /// Returns a vector mask containing the result of a `!=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x != rhs.x, self.y != rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpne(self, rhs: Self) -> BVec2 { + BVec2::new(self.x.ne(&rhs.x), self.y.ne(&rhs.y)) + } + + /// Returns a vector mask containing the result of a `>=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x >= rhs.x, self.y >= rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpge(self, rhs: Self) -> BVec2 { + BVec2::new(self.x.ge(&rhs.x), self.y.ge(&rhs.y)) + } + + /// Returns a vector mask containing the result of a `>` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x > rhs.x, self.y > rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpgt(self, rhs: Self) -> BVec2 { + BVec2::new(self.x.gt(&rhs.x), self.y.gt(&rhs.y)) + } + + /// Returns a vector mask containing the result of a `<=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x <= rhs.x, self.y <= rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmple(self, rhs: Self) -> BVec2 { + BVec2::new(self.x.le(&rhs.x), self.y.le(&rhs.y)) + } + + /// Returns a vector mask containing the result of a `<` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x < rhs.x, self.y < rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmplt(self, rhs: Self) -> BVec2 { + BVec2::new(self.x.lt(&rhs.x), self.y.lt(&rhs.y)) + } + + /// Returns a vector containing the absolute value of each element of `self`. + #[inline] + pub fn abs(self) -> Self { + Self { + x: self.x.abs(), + y: self.y.abs(), + } + } + + /// Returns a vector with elements representing the sign of `self`. + /// + /// - `1.0` if the number is positive, `+0.0` or `INFINITY` + /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` + /// - `NAN` if the number is `NAN` + #[inline] + pub fn signum(self) -> Self { + Self { + x: self.x.signum(), + y: self.y.signum(), + } + } + + /// Returns `true` if, and only if, all elements are finite. If any element is either + /// `NaN`, positive or negative infinity, this will return `false`. + #[inline] + pub fn is_finite(self) -> bool { + self.x.is_finite() && self.y.is_finite() + } + + /// Returns `true` if any elements are `NaN`. + #[inline] + pub fn is_nan(self) -> bool { + self.x.is_nan() || self.y.is_nan() + } + + /// Performs `is_nan` on each element of self, returning a vector mask of the results. + /// + /// In other words, this computes `[x.is_nan(), y.is_nan(), z.is_nan(), w.is_nan()]`. + #[inline] + pub fn is_nan_mask(self) -> BVec2 { + BVec2::new(self.x.is_nan(), self.y.is_nan()) + } + + /// Computes the length of `self`. + #[doc(alias = "magnitude")] + #[inline] + pub fn length(self) -> f64 { + self.dot(self).sqrt() + } + + /// Computes the squared length of `self`. + /// + /// This is faster than `length()` as it avoids a square root operation. + #[doc(alias = "magnitude2")] + #[inline] + pub fn length_squared(self) -> f64 { + self.dot(self) + } + + /// Computes `1.0 / length()`. + /// + /// For valid results, `self` must _not_ be of length zero. + #[inline] + pub fn length_recip(self) -> f64 { + self.length().recip() + } + + /// Computes the Euclidean distance between two points in space. + #[inline] + pub fn distance(self, rhs: Self) -> f64 { + (self - rhs).length() + } + + /// Compute the squared euclidean distance between two points in space. + #[inline] + pub fn distance_squared(self, rhs: Self) -> f64 { + (self - rhs).length_squared() + } + + /// Returns `self` normalized to length 1.0. + /// + /// For valid results, `self` must _not_ be of length zero, nor very close to zero. + /// + /// See also [`Self::try_normalize`] and [`Self::normalize_or_zero`]. + /// + /// Panics + /// + /// Will panic if `self` is zero length when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn normalize(self) -> Self { + #[allow(clippy::let_and_return)] + let normalized = self.mul(self.length_recip()); + glam_assert!(normalized.is_finite()); + normalized + } + + /// Returns `self` normalized to length 1.0 if possible, else returns `None`. + /// + /// In particular, if the input is zero (or very close to zero), or non-finite, + /// the result of this operation will be `None`. + /// + /// See also [`Self::normalize_or_zero`]. + #[must_use] + #[inline] + pub fn try_normalize(self) -> Option { + let rcp = self.length_recip(); + if rcp.is_finite() && rcp > 0.0 { + Some(self * rcp) + } else { + None + } + } + + /// Returns `self` normalized to length 1.0 if possible, else returns zero. + /// + /// In particular, if the input is zero (or very close to zero), or non-finite, + /// the result of this operation will be zero. + /// + /// See also [`Self::try_normalize`]. + #[must_use] + #[inline] + pub fn normalize_or_zero(self) -> Self { + let rcp = self.length_recip(); + if rcp.is_finite() && rcp > 0.0 { + self * rcp + } else { + Self::ZERO + } + } + + /// Returns whether `self` is length `1.0` or not. + /// + /// Uses a precision threshold of `1e-6`. + #[inline] + pub fn is_normalized(self) -> bool { + // TODO: do something with epsilon + (self.length_squared() - 1.0).abs() <= 1e-4 + } + + /// Returns the vector projection of `self` onto `rhs`. + /// + /// `rhs` must be of non-zero length. + /// + /// # Panics + /// + /// Will panic if `rhs` is zero length when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn project_onto(self, rhs: Self) -> Self { + let other_len_sq_rcp = rhs.dot(rhs).recip(); + glam_assert!(other_len_sq_rcp.is_finite()); + rhs * self.dot(rhs) * other_len_sq_rcp + } + + /// Returns the vector rejection of `self` from `rhs`. + /// + /// The vector rejection is the vector perpendicular to the projection of `self` onto + /// `rhs`, in rhs words the result of `self - self.project_onto(rhs)`. + /// + /// `rhs` must be of non-zero length. + /// + /// # Panics + /// + /// Will panic if `rhs` has a length of zero when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn reject_from(self, rhs: Self) -> Self { + self - self.project_onto(rhs) + } + + /// Returns the vector projection of `self` onto `rhs`. + /// + /// `rhs` must be normalized. + /// + /// # Panics + /// + /// Will panic if `rhs` is not normalized when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn project_onto_normalized(self, rhs: Self) -> Self { + glam_assert!(rhs.is_normalized()); + rhs * self.dot(rhs) + } + + /// Returns the vector rejection of `self` from `rhs`. + /// + /// The vector rejection is the vector perpendicular to the projection of `self` onto + /// `rhs`, in rhs words the result of `self - self.project_onto(rhs)`. + /// + /// `rhs` must be normalized. + /// + /// # Panics + /// + /// Will panic if `rhs` is not normalized when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn reject_from_normalized(self, rhs: Self) -> Self { + self - self.project_onto_normalized(rhs) + } + + /// Returns a vector containing the nearest integer to a number for each element of `self`. + /// Round half-way cases away from 0.0. + #[inline] + pub fn round(self) -> Self { + Self { + x: self.x.round(), + y: self.y.round(), + } + } + + /// Returns a vector containing the largest integer less than or equal to a number for each + /// element of `self`. + #[inline] + pub fn floor(self) -> Self { + Self { + x: self.x.floor(), + y: self.y.floor(), + } + } + + /// Returns a vector containing the smallest integer greater than or equal to a number for + /// each element of `self`. + #[inline] + pub fn ceil(self) -> Self { + Self { + x: self.x.ceil(), + y: self.y.ceil(), + } + } + + /// Returns a vector containing the fractional part of the vector, e.g. `self - + /// self.floor()`. + /// + /// Note that this is fast but not precise for large numbers. + #[inline] + pub fn fract(self) -> Self { + self - self.floor() + } + + /// Returns a vector containing `e^self` (the exponential function) for each element of + /// `self`. + #[inline] + pub fn exp(self) -> Self { + Self::new(self.x.exp(), self.y.exp()) + } + + /// Returns a vector containing each element of `self` raised to the power of `n`. + #[inline] + pub fn powf(self, n: f64) -> Self { + Self::new(self.x.powf(n), self.y.powf(n)) + } + + /// Returns a vector containing the reciprocal `1.0/n` of each element of `self`. + #[inline] + pub fn recip(self) -> Self { + Self { + x: self.x.recip(), + y: self.y.recip(), + } + } + + /// Performs a linear interpolation between `self` and `rhs` based on the value `s`. + /// + /// When `s` is `0.0`, the result will be equal to `self`. When `s` is `1.0`, the result + /// will be equal to `rhs`. When `s` is outside of range `[0, 1]`, the result is linearly + /// extrapolated. + #[doc(alias = "mix")] + #[inline] + pub fn lerp(self, rhs: Self, s: f64) -> Self { + self + ((rhs - self) * s) + } + + /// Returns true if the absolute difference of all elements between `self` and `rhs` is + /// less than or equal to `max_abs_diff`. + /// + /// This can be used to compare if two vectors contain similar elements. It works best when + /// comparing with a known value. The `max_abs_diff` that should be used used depends on + /// the values being compared against. + /// + /// For more see + /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/). + #[inline] + pub fn abs_diff_eq(self, rhs: Self, max_abs_diff: f64) -> bool { + self.sub(rhs).abs().cmple(Self::splat(max_abs_diff)).all() + } + + /// Returns a vector with a length no less than `min` and no more than `max` + /// + /// # Panics + /// + /// Will panic if `min` is greater than `max` when `glam_assert` is enabled. + #[inline] + pub fn clamp_length(self, min: f64, max: f64) -> Self { + glam_assert!(min <= max); + let length_sq = self.length_squared(); + if length_sq < min * min { + self * (length_sq.sqrt().recip() * min) + } else if length_sq > max * max { + self * (length_sq.sqrt().recip() * max) + } else { + self + } + } + + /// Returns a vector with a length no more than `max` + pub fn clamp_length_max(self, max: f64) -> Self { + let length_sq = self.length_squared(); + if length_sq > max * max { + self * (length_sq.sqrt().recip() * max) + } else { + self + } + } + + /// Returns a vector with a length no less than `min` + pub fn clamp_length_min(self, min: f64) -> Self { + let length_sq = self.length_squared(); + if length_sq < min * min { + self * (length_sq.sqrt().recip() * min) + } else { + self + } + } + + /// Fused multiply-add. Computes `(self * a) + b` element-wise with only one rounding + /// error, yielding a more accurate result than an unfused multiply-add. + /// + /// Using `mul_add` *may* be more performant than an unfused multiply-add if the target + /// architecture has a dedicated fma CPU instruction. However, this is not always true, + /// and will be heavily dependant on designing algorithms with specific target hardware in + /// mind. + #[inline] + pub fn mul_add(self, a: Self, b: Self) -> Self { + Self::new(self.x.mul_add(a.x, b.x), self.y.mul_add(a.y, b.y)) + } + + /// Creates a 2D vector containing `[angle.cos(), angle.sin()]`. This can be used in + /// conjunction with the `rotate` method, e.g. `Vec2::from_angle(PI).rotate(Vec2::Y)` will + /// create the vector [-1, 0] and rotate `Vec2::Y` around it returning `-Vec2::Y`. + #[inline] + pub fn from_angle(angle: f64) -> Self { + let (sin, cos) = angle.sin_cos(); + Self { x: cos, y: sin } + } + + /// Returns the angle (in radians) between `self` and `rhs`. + /// + /// The input vectors do not need to be unit length however they must be non-zero. + #[inline] + pub fn angle_between(self, rhs: Self) -> f64 { + use crate::FloatEx; + let angle = + (self.dot(rhs) / (self.length_squared() * rhs.length_squared()).sqrt()).acos_approx(); + + angle * self.perp_dot(rhs).signum() + } + + /// Returns a vector that is equal to `self` rotated by 90 degrees. + #[inline] + pub fn perp(self) -> Self { + Self { + x: -self.y, + y: self.x, + } + } + + /// The perpendicular dot product of `self` and `rhs`. + /// Also known as the wedge product, 2D cross product, and determinant. + #[doc(alias = "wedge")] + #[doc(alias = "cross")] + #[doc(alias = "determinant")] + #[inline] + pub fn perp_dot(self, rhs: Self) -> f64 { + (self.x * rhs.y) - (self.y * rhs.x) + } + + /// Returns `rhs` rotated by the angle of `self`. If `self` is normalized, + /// then this just rotation. This is what you usually want. Otherwise, + /// it will be like a rotation with a multiplication by `self`'s length. + #[must_use] + #[inline] + pub fn rotate(self, rhs: Self) -> Self { + Self { + x: self.x * rhs.x - self.y * rhs.y, + y: self.y * rhs.x + self.x * rhs.y, + } + } + + /// Casts all elements of `self` to `f32`. + #[inline] + pub fn as_vec2(&self) -> crate::Vec2 { + crate::Vec2::new(self.x as f32, self.y as f32) + } + + /// Casts all elements of `self` to `i32`. + #[inline] + pub fn as_ivec2(&self) -> crate::IVec2 { + crate::IVec2::new(self.x as i32, self.y as i32) + } + + /// Casts all elements of `self` to `u32`. + #[inline] + pub fn as_uvec2(&self) -> crate::UVec2 { + crate::UVec2::new(self.x as u32, self.y as u32) + } +} + +impl Default for DVec2 { + #[inline(always)] + fn default() -> Self { + Self::ZERO + } +} + +impl PartialEq for DVec2 { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.cmpeq(*rhs).all() + } +} + +impl Div for DVec2 { + type Output = Self; + #[inline] + fn div(self, rhs: Self) -> Self { + Self { + x: self.x.div(rhs.x), + y: self.y.div(rhs.y), + } + } +} + +impl DivAssign for DVec2 { + #[inline] + fn div_assign(&mut self, rhs: Self) { + self.x.div_assign(rhs.x); + self.y.div_assign(rhs.y); + } +} + +impl Div for DVec2 { + type Output = Self; + #[inline] + fn div(self, rhs: f64) -> Self { + Self { + x: self.x.div(rhs), + y: self.y.div(rhs), + } + } +} + +impl DivAssign for DVec2 { + #[inline] + fn div_assign(&mut self, rhs: f64) { + self.x.div_assign(rhs); + self.y.div_assign(rhs); + } +} + +impl Div for f64 { + type Output = DVec2; + #[inline] + fn div(self, rhs: DVec2) -> DVec2 { + DVec2 { + x: self.div(rhs.x), + y: self.div(rhs.y), + } + } +} + +impl Mul for DVec2 { + type Output = Self; + #[inline] + fn mul(self, rhs: Self) -> Self { + Self { + x: self.x.mul(rhs.x), + y: self.y.mul(rhs.y), + } + } +} + +impl MulAssign for DVec2 { + #[inline] + fn mul_assign(&mut self, rhs: Self) { + self.x.mul_assign(rhs.x); + self.y.mul_assign(rhs.y); + } +} + +impl Mul for DVec2 { + type Output = Self; + #[inline] + fn mul(self, rhs: f64) -> Self { + Self { + x: self.x.mul(rhs), + y: self.y.mul(rhs), + } + } +} + +impl MulAssign for DVec2 { + #[inline] + fn mul_assign(&mut self, rhs: f64) { + self.x.mul_assign(rhs); + self.y.mul_assign(rhs); + } +} + +impl Mul for f64 { + type Output = DVec2; + #[inline] + fn mul(self, rhs: DVec2) -> DVec2 { + DVec2 { + x: self.mul(rhs.x), + y: self.mul(rhs.y), + } + } +} + +impl Add for DVec2 { + type Output = Self; + #[inline] + fn add(self, rhs: Self) -> Self { + Self { + x: self.x.add(rhs.x), + y: self.y.add(rhs.y), + } + } +} + +impl AddAssign for DVec2 { + #[inline] + fn add_assign(&mut self, rhs: Self) { + self.x.add_assign(rhs.x); + self.y.add_assign(rhs.y); + } +} + +impl Add for DVec2 { + type Output = Self; + #[inline] + fn add(self, rhs: f64) -> Self { + Self { + x: self.x.add(rhs), + y: self.y.add(rhs), + } + } +} + +impl AddAssign for DVec2 { + #[inline] + fn add_assign(&mut self, rhs: f64) { + self.x.add_assign(rhs); + self.y.add_assign(rhs); + } +} + +impl Add for f64 { + type Output = DVec2; + #[inline] + fn add(self, rhs: DVec2) -> DVec2 { + DVec2 { + x: self.add(rhs.x), + y: self.add(rhs.y), + } + } +} + +impl Sub for DVec2 { + type Output = Self; + #[inline] + fn sub(self, rhs: Self) -> Self { + Self { + x: self.x.sub(rhs.x), + y: self.y.sub(rhs.y), + } + } +} + +impl SubAssign for DVec2 { + #[inline] + fn sub_assign(&mut self, rhs: DVec2) { + self.x.sub_assign(rhs.x); + self.y.sub_assign(rhs.y); + } +} + +impl Sub for DVec2 { + type Output = Self; + #[inline] + fn sub(self, rhs: f64) -> Self { + Self { + x: self.x.sub(rhs), + y: self.y.sub(rhs), + } + } +} + +impl SubAssign for DVec2 { + #[inline] + fn sub_assign(&mut self, rhs: f64) { + self.x.sub_assign(rhs); + self.y.sub_assign(rhs); + } +} + +impl Sub for f64 { + type Output = DVec2; + #[inline] + fn sub(self, rhs: DVec2) -> DVec2 { + DVec2 { + x: self.sub(rhs.x), + y: self.sub(rhs.y), + } + } +} + +impl Rem for DVec2 { + type Output = Self; + #[inline] + fn rem(self, rhs: Self) -> Self { + Self { + x: self.x.rem(rhs.x), + y: self.y.rem(rhs.y), + } + } +} + +impl RemAssign for DVec2 { + #[inline] + fn rem_assign(&mut self, rhs: Self) { + self.x.rem_assign(rhs.x); + self.y.rem_assign(rhs.y); + } +} + +impl Rem for DVec2 { + type Output = Self; + #[inline] + fn rem(self, rhs: f64) -> Self { + Self { + x: self.x.rem(rhs), + y: self.y.rem(rhs), + } + } +} + +impl RemAssign for DVec2 { + #[inline] + fn rem_assign(&mut self, rhs: f64) { + self.x.rem_assign(rhs); + self.y.rem_assign(rhs); + } +} + +impl Rem for f64 { + type Output = DVec2; + #[inline] + fn rem(self, rhs: DVec2) -> DVec2 { + DVec2 { + x: self.rem(rhs.x), + y: self.rem(rhs.y), + } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsRef<[f64; 2]> for DVec2 { + #[inline] + fn as_ref(&self) -> &[f64; 2] { + unsafe { &*(self as *const DVec2 as *const [f64; 2]) } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsMut<[f64; 2]> for DVec2 { + #[inline] + fn as_mut(&mut self) -> &mut [f64; 2] { + unsafe { &mut *(self as *mut DVec2 as *mut [f64; 2]) } + } +} + +impl<'a> Sum<&'a Self> for DVec2 { + #[inline] + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, |a, &b| Self::add(a, b)) + } +} + +impl<'a> Product<&'a Self> for DVec2 { + #[inline] + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ONE, |a, &b| Self::mul(a, b)) + } +} + +impl Neg for DVec2 { + type Output = Self; + #[inline] + fn neg(self) -> Self { + Self { + x: self.x.neg(), + y: self.y.neg(), + } + } +} + +impl Index for DVec2 { + type Output = f64; + #[inline] + fn index(&self, index: usize) -> &Self::Output { + match index { + 0 => &self.x, + 1 => &self.y, + _ => panic!("index out of bounds"), + } + } +} + +impl IndexMut for DVec2 { + #[inline] + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + match index { + 0 => &mut self.x, + 1 => &mut self.y, + _ => panic!("index out of bounds"), + } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Display for DVec2 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "[{}, {}]", self.x, self.y) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Debug for DVec2 { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_tuple(stringify!(DVec2)) + .field(&self.x) + .field(&self.y) + .finish() + } +} + +impl From<[f64; 2]> for DVec2 { + #[inline] + fn from(a: [f64; 2]) -> Self { + Self::new(a[0], a[1]) + } +} + +impl From for [f64; 2] { + #[inline] + fn from(v: DVec2) -> Self { + [v.x, v.y] + } +} + +impl From<(f64, f64)> for DVec2 { + #[inline] + fn from(t: (f64, f64)) -> Self { + Self::new(t.0, t.1) + } +} + +impl From for (f64, f64) { + #[inline] + fn from(v: DVec2) -> Self { + (v.x, v.y) + } +} diff --git a/src/f64/dvec3.rs b/src/f64/dvec3.rs new file mode 100644 index 00000000..ce406124 --- /dev/null +++ b/src/f64/dvec3.rs @@ -0,0 +1,1115 @@ +// Generated from vec.rs template. Edit the template, not the generated file. + +use crate::{BVec3, DVec2, DVec4}; + +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::iter::{Product, Sum}; +use core::{f32, ops::*}; + +#[cfg(not(feature = "std"))] +use num_traits::Float; + +/// Creates a 3-dimensional vector. +#[inline(always)] +pub const fn dvec3(x: f64, y: f64, z: f64) -> DVec3 { + DVec3::new(x, y, z) +} + +/// A 3-dimensional vector. +#[derive(Clone, Copy)] +pub struct DVec3 { + pub x: f64, + pub y: f64, + pub z: f64, +} + +impl DVec3 { + /// All zeroes. + pub const ZERO: Self = Self::splat(0.0); + + /// All ones. + pub const ONE: Self = Self::splat(1.0); + + /// All negative ones. + pub const NEG_ONE: Self = Self::splat(-1.0); + + /// All NAN. + pub const NAN: Self = Self::splat(f64::NAN); + + /// `[1.0, 0.0, 0.0]`: a unit-length vector pointing along the positive X axis. + pub const X: Self = Self::from_array([1.0, 0.0, 0.0]); + + /// `[0.0, 1.0, 0.0]`: a unit-length vector pointing along the positive Y axis. + pub const Y: Self = Self::from_array([0.0, 1.0, 0.0]); + + /// `[0.0, 0.0, 1.0]`: a unit-length vector pointing along the positive Z axis. + pub const Z: Self = Self::from_array([0.0, 0.0, 1.0]); + + /// The unit axes. + pub const AXES: [Self; 3] = [Self::X, Self::Y, Self::Z]; + + /// Creates a new vector. + #[inline(always)] + pub const fn new(x: f64, y: f64, z: f64) -> Self { + Self { x, y, z } + } + + /// Creates a vector with all elements set to `v`. + #[inline] + pub const fn splat(v: f64) -> Self { + Self { x: v, y: v, z: v } + } + + /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use + /// for each element of `self`. + /// + /// A true element in the mask uses the corresponding element from `if_true`, and false + /// uses the element from `if_false`. + #[inline] + pub fn select(mask: BVec3, if_true: Self, if_false: Self) -> Self { + Self { + x: if mask.x { if_true.x } else { if_false.x }, + y: if mask.y { if_true.y } else { if_false.y }, + z: if mask.z { if_true.z } else { if_false.z }, + } + } + + /// Creates a new vector from an array. + #[inline] + pub const fn from_array(a: [f64; 3]) -> Self { + Self::new(a[0], a[1], a[2]) + } + + /// `[x, y, z]` + #[inline] + pub const fn to_array(&self) -> [f64; 3] { + [self.x, self.y, self.z] + } + + /// Creates a vector from the first N values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than N elements long. + #[inline] + pub const fn from_slice(slice: &[f64]) -> Self { + Self::new(slice[0], slice[1], slice[2]) + } + + /// Writes the elements of `self` to the first 3 elements in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than N elements long. + #[inline] + pub fn write_to_slice(self, slice: &mut [f64]) { + slice[0] = self.x; + slice[1] = self.y; + slice[2] = self.z; + } + + /// Internal method for creating a 3D vector from a 4D vector, discarding `w`. + #[allow(dead_code)] + #[inline] + pub(crate) fn from_vec4(v: DVec4) -> Self { + Self { + x: v.x, + y: v.y, + z: v.z, + } + } + + /// Creates a 4D vector from `self` and the given `w` value. + #[inline] + pub fn extend(self, w: f64) -> DVec4 { + DVec4::new(self.x, self.y, self.z, w) + } + + /// Creates a 2D vector from the `x` and `y` elements of `self`, discarding `z`. + /// + /// Truncation may also be performed by using `self.xy()` or `DVec2::from()`. + #[inline] + pub fn truncate(self) -> DVec2 { + use crate::swizzles::Vec3Swizzles; + self.xy() + } + + /// Computes the dot product of `self` and `rhs`. + #[inline] + pub fn dot(self, rhs: Self) -> f64 { + (self.x * rhs.x) + (self.y * rhs.y) + (self.z * rhs.z) + } + + /// Computes the cross product of `self` and `rhs`. + #[inline] + pub fn cross(self, rhs: Self) -> Self { + Self { + x: self.y * rhs.z - rhs.y * self.z, + y: self.z * rhs.x - rhs.z * self.x, + z: self.x * rhs.y - rhs.x * self.y, + } + } + + /// Returns a vector containing the minimum values for each element of `self` and `rhs`. + /// + /// In other words this computes `[self.x.min(rhs.x), self.y.min(rhs.y), ..]`. + #[inline] + pub fn min(self, rhs: Self) -> Self { + Self { + x: self.x.min(rhs.x), + y: self.y.min(rhs.y), + z: self.z.min(rhs.z), + } + } + + /// Returns a vector containing the maximum values for each element of `self` and `rhs`. + /// + /// In other words this computes `[self.x.max(rhs.x), self.y.max(rhs.y), ..]`. + #[inline] + pub fn max(self, rhs: Self) -> Self { + Self { + x: self.x.max(rhs.x), + y: self.y.max(rhs.y), + z: self.z.max(rhs.z), + } + } + + /// Component-wise clamping of values, similar to [`f32::clamp`]. + /// + /// Each element in `min` must be less-or-equal to the corresponding element in `max`. + /// + /// # Panics + /// + /// Will panic if `min` is greater than `max` when `glam_assert` is enabled. + #[inline] + pub fn clamp(self, min: Self, max: Self) -> Self { + glam_assert!(min.cmple(max).all(), "clamp: expected min <= max"); + self.max(min).min(max) + } + + /// Returns the horizontal minimum of `self`. + /// + /// In other words this computes `min(x, y, ..)`. + #[inline] + pub fn min_element(self) -> f64 { + self.x.min(self.y.min(self.z)) + } + + /// Returns the horizontal maximum of `self`. + /// + /// In other words this computes `max(x, y, ..)`. + #[inline] + pub fn max_element(self) -> f64 { + self.x.max(self.y.max(self.z)) + } + + /// Returns a vector mask containing the result of a `==` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words, this computes `[self.x == rhs.x, self.y == rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpeq(self, rhs: Self) -> BVec3 { + BVec3::new(self.x.eq(&rhs.x), self.y.eq(&rhs.y), self.z.eq(&rhs.z)) + } + + /// Returns a vector mask containing the result of a `!=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x != rhs.x, self.y != rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpne(self, rhs: Self) -> BVec3 { + BVec3::new(self.x.ne(&rhs.x), self.y.ne(&rhs.y), self.z.ne(&rhs.z)) + } + + /// Returns a vector mask containing the result of a `>=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x >= rhs.x, self.y >= rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpge(self, rhs: Self) -> BVec3 { + BVec3::new(self.x.ge(&rhs.x), self.y.ge(&rhs.y), self.z.ge(&rhs.z)) + } + + /// Returns a vector mask containing the result of a `>` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x > rhs.x, self.y > rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpgt(self, rhs: Self) -> BVec3 { + BVec3::new(self.x.gt(&rhs.x), self.y.gt(&rhs.y), self.z.gt(&rhs.z)) + } + + /// Returns a vector mask containing the result of a `<=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x <= rhs.x, self.y <= rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmple(self, rhs: Self) -> BVec3 { + BVec3::new(self.x.le(&rhs.x), self.y.le(&rhs.y), self.z.le(&rhs.z)) + } + + /// Returns a vector mask containing the result of a `<` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x < rhs.x, self.y < rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmplt(self, rhs: Self) -> BVec3 { + BVec3::new(self.x.lt(&rhs.x), self.y.lt(&rhs.y), self.z.lt(&rhs.z)) + } + + /// Returns a vector containing the absolute value of each element of `self`. + #[inline] + pub fn abs(self) -> Self { + Self { + x: self.x.abs(), + y: self.y.abs(), + z: self.z.abs(), + } + } + + /// Returns a vector with elements representing the sign of `self`. + /// + /// - `1.0` if the number is positive, `+0.0` or `INFINITY` + /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` + /// - `NAN` if the number is `NAN` + #[inline] + pub fn signum(self) -> Self { + Self { + x: self.x.signum(), + y: self.y.signum(), + z: self.z.signum(), + } + } + + /// Returns `true` if, and only if, all elements are finite. If any element is either + /// `NaN`, positive or negative infinity, this will return `false`. + #[inline] + pub fn is_finite(self) -> bool { + self.x.is_finite() && self.y.is_finite() && self.z.is_finite() + } + + /// Returns `true` if any elements are `NaN`. + #[inline] + pub fn is_nan(self) -> bool { + self.x.is_nan() || self.y.is_nan() || self.z.is_nan() + } + + /// Performs `is_nan` on each element of self, returning a vector mask of the results. + /// + /// In other words, this computes `[x.is_nan(), y.is_nan(), z.is_nan(), w.is_nan()]`. + #[inline] + pub fn is_nan_mask(self) -> BVec3 { + BVec3::new(self.x.is_nan(), self.y.is_nan(), self.z.is_nan()) + } + + /// Computes the length of `self`. + #[doc(alias = "magnitude")] + #[inline] + pub fn length(self) -> f64 { + self.dot(self).sqrt() + } + + /// Computes the squared length of `self`. + /// + /// This is faster than `length()` as it avoids a square root operation. + #[doc(alias = "magnitude2")] + #[inline] + pub fn length_squared(self) -> f64 { + self.dot(self) + } + + /// Computes `1.0 / length()`. + /// + /// For valid results, `self` must _not_ be of length zero. + #[inline] + pub fn length_recip(self) -> f64 { + self.length().recip() + } + + /// Computes the Euclidean distance between two points in space. + #[inline] + pub fn distance(self, rhs: Self) -> f64 { + (self - rhs).length() + } + + /// Compute the squared euclidean distance between two points in space. + #[inline] + pub fn distance_squared(self, rhs: Self) -> f64 { + (self - rhs).length_squared() + } + + /// Returns `self` normalized to length 1.0. + /// + /// For valid results, `self` must _not_ be of length zero, nor very close to zero. + /// + /// See also [`Self::try_normalize`] and [`Self::normalize_or_zero`]. + /// + /// Panics + /// + /// Will panic if `self` is zero length when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn normalize(self) -> Self { + #[allow(clippy::let_and_return)] + let normalized = self.mul(self.length_recip()); + glam_assert!(normalized.is_finite()); + normalized + } + + /// Returns `self` normalized to length 1.0 if possible, else returns `None`. + /// + /// In particular, if the input is zero (or very close to zero), or non-finite, + /// the result of this operation will be `None`. + /// + /// See also [`Self::normalize_or_zero`]. + #[must_use] + #[inline] + pub fn try_normalize(self) -> Option { + let rcp = self.length_recip(); + if rcp.is_finite() && rcp > 0.0 { + Some(self * rcp) + } else { + None + } + } + + /// Returns `self` normalized to length 1.0 if possible, else returns zero. + /// + /// In particular, if the input is zero (or very close to zero), or non-finite, + /// the result of this operation will be zero. + /// + /// See also [`Self::try_normalize`]. + #[must_use] + #[inline] + pub fn normalize_or_zero(self) -> Self { + let rcp = self.length_recip(); + if rcp.is_finite() && rcp > 0.0 { + self * rcp + } else { + Self::ZERO + } + } + + /// Returns whether `self` is length `1.0` or not. + /// + /// Uses a precision threshold of `1e-6`. + #[inline] + pub fn is_normalized(self) -> bool { + // TODO: do something with epsilon + (self.length_squared() - 1.0).abs() <= 1e-4 + } + + /// Returns the vector projection of `self` onto `rhs`. + /// + /// `rhs` must be of non-zero length. + /// + /// # Panics + /// + /// Will panic if `rhs` is zero length when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn project_onto(self, rhs: Self) -> Self { + let other_len_sq_rcp = rhs.dot(rhs).recip(); + glam_assert!(other_len_sq_rcp.is_finite()); + rhs * self.dot(rhs) * other_len_sq_rcp + } + + /// Returns the vector rejection of `self` from `rhs`. + /// + /// The vector rejection is the vector perpendicular to the projection of `self` onto + /// `rhs`, in rhs words the result of `self - self.project_onto(rhs)`. + /// + /// `rhs` must be of non-zero length. + /// + /// # Panics + /// + /// Will panic if `rhs` has a length of zero when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn reject_from(self, rhs: Self) -> Self { + self - self.project_onto(rhs) + } + + /// Returns the vector projection of `self` onto `rhs`. + /// + /// `rhs` must be normalized. + /// + /// # Panics + /// + /// Will panic if `rhs` is not normalized when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn project_onto_normalized(self, rhs: Self) -> Self { + glam_assert!(rhs.is_normalized()); + rhs * self.dot(rhs) + } + + /// Returns the vector rejection of `self` from `rhs`. + /// + /// The vector rejection is the vector perpendicular to the projection of `self` onto + /// `rhs`, in rhs words the result of `self - self.project_onto(rhs)`. + /// + /// `rhs` must be normalized. + /// + /// # Panics + /// + /// Will panic if `rhs` is not normalized when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn reject_from_normalized(self, rhs: Self) -> Self { + self - self.project_onto_normalized(rhs) + } + + /// Returns a vector containing the nearest integer to a number for each element of `self`. + /// Round half-way cases away from 0.0. + #[inline] + pub fn round(self) -> Self { + Self { + x: self.x.round(), + y: self.y.round(), + z: self.z.round(), + } + } + + /// Returns a vector containing the largest integer less than or equal to a number for each + /// element of `self`. + #[inline] + pub fn floor(self) -> Self { + Self { + x: self.x.floor(), + y: self.y.floor(), + z: self.z.floor(), + } + } + + /// Returns a vector containing the smallest integer greater than or equal to a number for + /// each element of `self`. + #[inline] + pub fn ceil(self) -> Self { + Self { + x: self.x.ceil(), + y: self.y.ceil(), + z: self.z.ceil(), + } + } + + /// Returns a vector containing the fractional part of the vector, e.g. `self - + /// self.floor()`. + /// + /// Note that this is fast but not precise for large numbers. + #[inline] + pub fn fract(self) -> Self { + self - self.floor() + } + + /// Returns a vector containing `e^self` (the exponential function) for each element of + /// `self`. + #[inline] + pub fn exp(self) -> Self { + Self::new(self.x.exp(), self.y.exp(), self.z.exp()) + } + + /// Returns a vector containing each element of `self` raised to the power of `n`. + #[inline] + pub fn powf(self, n: f64) -> Self { + Self::new(self.x.powf(n), self.y.powf(n), self.z.powf(n)) + } + + /// Returns a vector containing the reciprocal `1.0/n` of each element of `self`. + #[inline] + pub fn recip(self) -> Self { + Self { + x: self.x.recip(), + y: self.y.recip(), + z: self.z.recip(), + } + } + + /// Performs a linear interpolation between `self` and `rhs` based on the value `s`. + /// + /// When `s` is `0.0`, the result will be equal to `self`. When `s` is `1.0`, the result + /// will be equal to `rhs`. When `s` is outside of range `[0, 1]`, the result is linearly + /// extrapolated. + #[doc(alias = "mix")] + #[inline] + pub fn lerp(self, rhs: Self, s: f64) -> Self { + self + ((rhs - self) * s) + } + + /// Returns true if the absolute difference of all elements between `self` and `rhs` is + /// less than or equal to `max_abs_diff`. + /// + /// This can be used to compare if two vectors contain similar elements. It works best when + /// comparing with a known value. The `max_abs_diff` that should be used used depends on + /// the values being compared against. + /// + /// For more see + /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/). + #[inline] + pub fn abs_diff_eq(self, rhs: Self, max_abs_diff: f64) -> bool { + self.sub(rhs).abs().cmple(Self::splat(max_abs_diff)).all() + } + + /// Returns a vector with a length no less than `min` and no more than `max` + /// + /// # Panics + /// + /// Will panic if `min` is greater than `max` when `glam_assert` is enabled. + #[inline] + pub fn clamp_length(self, min: f64, max: f64) -> Self { + glam_assert!(min <= max); + let length_sq = self.length_squared(); + if length_sq < min * min { + self * (length_sq.sqrt().recip() * min) + } else if length_sq > max * max { + self * (length_sq.sqrt().recip() * max) + } else { + self + } + } + + /// Returns a vector with a length no more than `max` + pub fn clamp_length_max(self, max: f64) -> Self { + let length_sq = self.length_squared(); + if length_sq > max * max { + self * (length_sq.sqrt().recip() * max) + } else { + self + } + } + + /// Returns a vector with a length no less than `min` + pub fn clamp_length_min(self, min: f64) -> Self { + let length_sq = self.length_squared(); + if length_sq < min * min { + self * (length_sq.sqrt().recip() * min) + } else { + self + } + } + + /// Fused multiply-add. Computes `(self * a) + b` element-wise with only one rounding + /// error, yielding a more accurate result than an unfused multiply-add. + /// + /// Using `mul_add` *may* be more performant than an unfused multiply-add if the target + /// architecture has a dedicated fma CPU instruction. However, this is not always true, + /// and will be heavily dependant on designing algorithms with specific target hardware in + /// mind. + #[inline] + pub fn mul_add(self, a: Self, b: Self) -> Self { + Self::new( + self.x.mul_add(a.x, b.x), + self.y.mul_add(a.y, b.y), + self.z.mul_add(a.z, b.z), + ) + } + + /// Returns the angle (in radians) between two vectors. + /// + /// The input vectors do not need to be unit length however they must be non-zero. + #[inline] + pub fn angle_between(self, rhs: Self) -> f64 { + use crate::FloatEx; + self.dot(rhs) + .div(self.length_squared().mul(rhs.length_squared()).sqrt()) + .acos_approx() + } + + /// Returns some vector that is orthogonal to the given one. + /// + /// The input vector must be finite and non-zero. + /// + /// The output vector is not necessarily unit-length. + /// For that use [`Self::any_orthonormal_vector`] instead. + #[inline] + pub fn any_orthogonal_vector(&self) -> Self { + // This can probably be optimized + if self.x.abs() > self.y.abs() { + Self::new(-self.z, 0.0, self.x) // self.cross(Self::Y) + } else { + Self::new(0.0, self.z, -self.y) // self.cross(Self::X) + } + } + + /// Returns any unit-length vector that is orthogonal to the given one. + /// The input vector must be finite and non-zero. + /// + /// # Panics + /// + /// Will panic if `self` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn any_orthonormal_vector(&self) -> Self { + glam_assert!(self.is_normalized()); + // From https://graphics.pixar.com/library/OrthonormalB/paper.pdf + #[cfg(feature = "std")] + let sign = (1.0_f64).copysign(self.z); + #[cfg(not(feature = "std"))] + let sign = self.z.signum(); + let a = -1.0 / (sign + self.z); + let b = self.x * self.y * a; + Self::new(b, sign + self.y * self.y * a, -self.y) + } + + /// Given a unit-length vector return two other vectors that together form an orthonormal + /// basis. That is, all three vectors are orthogonal to each other and are normalized. + /// + /// # Panics + /// + /// Will panic if `self` is not normalized when `glam_assert` is enabled. + #[inline] + pub fn any_orthonormal_pair(&self) -> (Self, Self) { + glam_assert!(self.is_normalized()); + // From https://graphics.pixar.com/library/OrthonormalB/paper.pdf + #[cfg(feature = "std")] + let sign = (1.0_f64).copysign(self.z); + #[cfg(not(feature = "std"))] + let sign = self.z.signum(); + let a = -1.0 / (sign + self.z); + let b = self.x * self.y * a; + ( + Self::new(1.0 + sign * self.x * self.x * a, sign * b, -sign * self.x), + Self::new(b, sign + self.y * self.y * a, -self.y), + ) + } + + /// Casts all elements of `self` to `f32`. + #[inline] + pub fn as_vec3(&self) -> crate::Vec3 { + crate::Vec3::new(self.x as f32, self.y as f32, self.z as f32) + } + + /// Casts all elements of `self` to `f32`. + #[inline] + pub fn as_vec3a(&self) -> crate::Vec3A { + crate::Vec3A::new(self.x as f32, self.y as f32, self.z as f32) + } + + /// Casts all elements of `self` to `i32`. + #[inline] + pub fn as_ivec3(&self) -> crate::IVec3 { + crate::IVec3::new(self.x as i32, self.y as i32, self.z as i32) + } + + /// Casts all elements of `self` to `u32`. + #[inline] + pub fn as_uvec3(&self) -> crate::UVec3 { + crate::UVec3::new(self.x as u32, self.y as u32, self.z as u32) + } +} + +impl Default for DVec3 { + #[inline(always)] + fn default() -> Self { + Self::ZERO + } +} + +impl PartialEq for DVec3 { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.cmpeq(*rhs).all() + } +} + +impl Div for DVec3 { + type Output = Self; + #[inline] + fn div(self, rhs: Self) -> Self { + Self { + x: self.x.div(rhs.x), + y: self.y.div(rhs.y), + z: self.z.div(rhs.z), + } + } +} + +impl DivAssign for DVec3 { + #[inline] + fn div_assign(&mut self, rhs: Self) { + self.x.div_assign(rhs.x); + self.y.div_assign(rhs.y); + self.z.div_assign(rhs.z); + } +} + +impl Div for DVec3 { + type Output = Self; + #[inline] + fn div(self, rhs: f64) -> Self { + Self { + x: self.x.div(rhs), + y: self.y.div(rhs), + z: self.z.div(rhs), + } + } +} + +impl DivAssign for DVec3 { + #[inline] + fn div_assign(&mut self, rhs: f64) { + self.x.div_assign(rhs); + self.y.div_assign(rhs); + self.z.div_assign(rhs); + } +} + +impl Div for f64 { + type Output = DVec3; + #[inline] + fn div(self, rhs: DVec3) -> DVec3 { + DVec3 { + x: self.div(rhs.x), + y: self.div(rhs.y), + z: self.div(rhs.z), + } + } +} + +impl Mul for DVec3 { + type Output = Self; + #[inline] + fn mul(self, rhs: Self) -> Self { + Self { + x: self.x.mul(rhs.x), + y: self.y.mul(rhs.y), + z: self.z.mul(rhs.z), + } + } +} + +impl MulAssign for DVec3 { + #[inline] + fn mul_assign(&mut self, rhs: Self) { + self.x.mul_assign(rhs.x); + self.y.mul_assign(rhs.y); + self.z.mul_assign(rhs.z); + } +} + +impl Mul for DVec3 { + type Output = Self; + #[inline] + fn mul(self, rhs: f64) -> Self { + Self { + x: self.x.mul(rhs), + y: self.y.mul(rhs), + z: self.z.mul(rhs), + } + } +} + +impl MulAssign for DVec3 { + #[inline] + fn mul_assign(&mut self, rhs: f64) { + self.x.mul_assign(rhs); + self.y.mul_assign(rhs); + self.z.mul_assign(rhs); + } +} + +impl Mul for f64 { + type Output = DVec3; + #[inline] + fn mul(self, rhs: DVec3) -> DVec3 { + DVec3 { + x: self.mul(rhs.x), + y: self.mul(rhs.y), + z: self.mul(rhs.z), + } + } +} + +impl Add for DVec3 { + type Output = Self; + #[inline] + fn add(self, rhs: Self) -> Self { + Self { + x: self.x.add(rhs.x), + y: self.y.add(rhs.y), + z: self.z.add(rhs.z), + } + } +} + +impl AddAssign for DVec3 { + #[inline] + fn add_assign(&mut self, rhs: Self) { + self.x.add_assign(rhs.x); + self.y.add_assign(rhs.y); + self.z.add_assign(rhs.z); + } +} + +impl Add for DVec3 { + type Output = Self; + #[inline] + fn add(self, rhs: f64) -> Self { + Self { + x: self.x.add(rhs), + y: self.y.add(rhs), + z: self.z.add(rhs), + } + } +} + +impl AddAssign for DVec3 { + #[inline] + fn add_assign(&mut self, rhs: f64) { + self.x.add_assign(rhs); + self.y.add_assign(rhs); + self.z.add_assign(rhs); + } +} + +impl Add for f64 { + type Output = DVec3; + #[inline] + fn add(self, rhs: DVec3) -> DVec3 { + DVec3 { + x: self.add(rhs.x), + y: self.add(rhs.y), + z: self.add(rhs.z), + } + } +} + +impl Sub for DVec3 { + type Output = Self; + #[inline] + fn sub(self, rhs: Self) -> Self { + Self { + x: self.x.sub(rhs.x), + y: self.y.sub(rhs.y), + z: self.z.sub(rhs.z), + } + } +} + +impl SubAssign for DVec3 { + #[inline] + fn sub_assign(&mut self, rhs: DVec3) { + self.x.sub_assign(rhs.x); + self.y.sub_assign(rhs.y); + self.z.sub_assign(rhs.z); + } +} + +impl Sub for DVec3 { + type Output = Self; + #[inline] + fn sub(self, rhs: f64) -> Self { + Self { + x: self.x.sub(rhs), + y: self.y.sub(rhs), + z: self.z.sub(rhs), + } + } +} + +impl SubAssign for DVec3 { + #[inline] + fn sub_assign(&mut self, rhs: f64) { + self.x.sub_assign(rhs); + self.y.sub_assign(rhs); + self.z.sub_assign(rhs); + } +} + +impl Sub for f64 { + type Output = DVec3; + #[inline] + fn sub(self, rhs: DVec3) -> DVec3 { + DVec3 { + x: self.sub(rhs.x), + y: self.sub(rhs.y), + z: self.sub(rhs.z), + } + } +} + +impl Rem for DVec3 { + type Output = Self; + #[inline] + fn rem(self, rhs: Self) -> Self { + Self { + x: self.x.rem(rhs.x), + y: self.y.rem(rhs.y), + z: self.z.rem(rhs.z), + } + } +} + +impl RemAssign for DVec3 { + #[inline] + fn rem_assign(&mut self, rhs: Self) { + self.x.rem_assign(rhs.x); + self.y.rem_assign(rhs.y); + self.z.rem_assign(rhs.z); + } +} + +impl Rem for DVec3 { + type Output = Self; + #[inline] + fn rem(self, rhs: f64) -> Self { + Self { + x: self.x.rem(rhs), + y: self.y.rem(rhs), + z: self.z.rem(rhs), + } + } +} + +impl RemAssign for DVec3 { + #[inline] + fn rem_assign(&mut self, rhs: f64) { + self.x.rem_assign(rhs); + self.y.rem_assign(rhs); + self.z.rem_assign(rhs); + } +} + +impl Rem for f64 { + type Output = DVec3; + #[inline] + fn rem(self, rhs: DVec3) -> DVec3 { + DVec3 { + x: self.rem(rhs.x), + y: self.rem(rhs.y), + z: self.rem(rhs.z), + } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsRef<[f64; 3]> for DVec3 { + #[inline] + fn as_ref(&self) -> &[f64; 3] { + unsafe { &*(self as *const DVec3 as *const [f64; 3]) } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsMut<[f64; 3]> for DVec3 { + #[inline] + fn as_mut(&mut self) -> &mut [f64; 3] { + unsafe { &mut *(self as *mut DVec3 as *mut [f64; 3]) } + } +} + +impl<'a> Sum<&'a Self> for DVec3 { + #[inline] + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, |a, &b| Self::add(a, b)) + } +} + +impl<'a> Product<&'a Self> for DVec3 { + #[inline] + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ONE, |a, &b| Self::mul(a, b)) + } +} + +impl Neg for DVec3 { + type Output = Self; + #[inline] + fn neg(self) -> Self { + Self { + x: self.x.neg(), + y: self.y.neg(), + z: self.z.neg(), + } + } +} + +impl Index for DVec3 { + type Output = f64; + #[inline] + fn index(&self, index: usize) -> &Self::Output { + match index { + 0 => &self.x, + 1 => &self.y, + 2 => &self.z, + _ => panic!("index out of bounds"), + } + } +} + +impl IndexMut for DVec3 { + #[inline] + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + match index { + 0 => &mut self.x, + 1 => &mut self.y, + 2 => &mut self.z, + _ => panic!("index out of bounds"), + } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Display for DVec3 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "[{}, {}, {}]", self.x, self.y, self.z) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Debug for DVec3 { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_tuple(stringify!(DVec3)) + .field(&self.x) + .field(&self.y) + .field(&self.z) + .finish() + } +} + +impl From<[f64; 3]> for DVec3 { + #[inline] + fn from(a: [f64; 3]) -> Self { + Self::new(a[0], a[1], a[2]) + } +} + +impl From for [f64; 3] { + #[inline] + fn from(v: DVec3) -> Self { + [v.x, v.y, v.z] + } +} + +impl From<(f64, f64, f64)> for DVec3 { + #[inline] + fn from(t: (f64, f64, f64)) -> Self { + Self::new(t.0, t.1, t.2) + } +} + +impl From for (f64, f64, f64) { + #[inline] + fn from(v: DVec3) -> Self { + (v.x, v.y, v.z) + } +} + +impl From<(DVec2, f64)> for DVec3 { + #[inline] + fn from((v, z): (DVec2, f64)) -> Self { + Self::new(v.x, v.y, z) + } +} diff --git a/src/f64/dvec4.rs b/src/f64/dvec4.rs new file mode 100644 index 00000000..c01c60e3 --- /dev/null +++ b/src/f64/dvec4.rs @@ -0,0 +1,1128 @@ +// Generated from vec.rs template. Edit the template, not the generated file. + +use crate::{BVec4, DVec2, DVec3}; + +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::iter::{Product, Sum}; +use core::{f32, ops::*}; + +#[cfg(not(feature = "std"))] +use num_traits::Float; + +/// Creates a 4-dimensional vector. +#[inline(always)] +pub const fn dvec4(x: f64, y: f64, z: f64, w: f64) -> DVec4 { + DVec4::new(x, y, z, w) +} + +/// A 4-dimensional vector. +#[derive(Clone, Copy)] +#[cfg_attr(feature = "cuda", repr(C, align(16)))] +pub struct DVec4 { + pub x: f64, + pub y: f64, + pub z: f64, + pub w: f64, +} + +impl DVec4 { + /// All zeroes. + pub const ZERO: Self = Self::splat(0.0); + + /// All ones. + pub const ONE: Self = Self::splat(1.0); + + /// All negative ones. + pub const NEG_ONE: Self = Self::splat(-1.0); + + /// All NAN. + pub const NAN: Self = Self::splat(f64::NAN); + + /// `[1.0, 0.0, 0.0, 0.0]`: a unit-length vector pointing along the positive X axis. + pub const X: Self = Self::from_array([1.0, 0.0, 0.0, 0.0]); + + /// `[0.0, 1.0, 0.0, 0.0]`: a unit-length vector pointing along the positive Y axis. + pub const Y: Self = Self::from_array([0.0, 1.0, 0.0, 0.0]); + + /// `[0.0, 0.0, 1.0, 0.0]`: a unit-length vector pointing along the positive Z axis. + pub const Z: Self = Self::from_array([0.0, 0.0, 1.0, 0.0]); + + /// `[0.0, 0.0, 0.0, 1.0]`: a unit-length vector pointing along the positive W axis. + pub const W: Self = Self::from_array([0.0, 0.0, 0.0, 1.0]); + + /// The unit axes. + pub const AXES: [Self; 4] = [Self::X, Self::Y, Self::Z, Self::W]; + + /// Creates a new vector. + #[inline(always)] + pub const fn new(x: f64, y: f64, z: f64, w: f64) -> Self { + Self { x, y, z, w } + } + + /// Creates a vector with all elements set to `v`. + #[inline] + pub const fn splat(v: f64) -> Self { + Self { + x: v, + + y: v, + + z: v, + + w: v, + } + } + + /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use + /// for each element of `self`. + /// + /// A true element in the mask uses the corresponding element from `if_true`, and false + /// uses the element from `if_false`. + #[inline] + pub fn select(mask: BVec4, if_true: Self, if_false: Self) -> Self { + Self { + x: if mask.x { if_true.x } else { if_false.x }, + y: if mask.y { if_true.y } else { if_false.y }, + z: if mask.z { if_true.z } else { if_false.z }, + w: if mask.w { if_true.w } else { if_false.w }, + } + } + + /// Creates a new vector from an array. + #[inline] + pub const fn from_array(a: [f64; 4]) -> Self { + Self::new(a[0], a[1], a[2], a[3]) + } + + /// `[x, y, z, w]` + #[inline] + pub const fn to_array(&self) -> [f64; 4] { + [self.x, self.y, self.z, self.w] + } + + /// Creates a vector from the first N values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than N elements long. + #[inline] + pub const fn from_slice(slice: &[f64]) -> Self { + Self::new(slice[0], slice[1], slice[2], slice[3]) + } + + /// Writes the elements of `self` to the first 4 elements in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than N elements long. + #[inline] + pub fn write_to_slice(self, slice: &mut [f64]) { + slice[0] = self.x; + slice[1] = self.y; + slice[2] = self.z; + slice[3] = self.w; + } + + /// Creates a 2D vector from the `x`, `y` and `z` elements of `self`, discarding `w`. + /// + /// Truncation to `DVec3` may also be performed by using `self.xyz()` or `DVec3::from()`. + #[inline] + pub fn truncate(self) -> DVec3 { + use crate::swizzles::Vec4Swizzles; + self.xyz() + } + + /// Computes the dot product of `self` and `rhs`. + #[inline] + pub fn dot(self, rhs: Self) -> f64 { + (self.x * rhs.x) + (self.y * rhs.y) + (self.z * rhs.z) + (self.w * rhs.w) + } + + /// Returns a vector containing the minimum values for each element of `self` and `rhs`. + /// + /// In other words this computes `[self.x.min(rhs.x), self.y.min(rhs.y), ..]`. + #[inline] + pub fn min(self, rhs: Self) -> Self { + Self { + x: self.x.min(rhs.x), + y: self.y.min(rhs.y), + z: self.z.min(rhs.z), + w: self.w.min(rhs.w), + } + } + + /// Returns a vector containing the maximum values for each element of `self` and `rhs`. + /// + /// In other words this computes `[self.x.max(rhs.x), self.y.max(rhs.y), ..]`. + #[inline] + pub fn max(self, rhs: Self) -> Self { + Self { + x: self.x.max(rhs.x), + y: self.y.max(rhs.y), + z: self.z.max(rhs.z), + w: self.w.max(rhs.w), + } + } + + /// Component-wise clamping of values, similar to [`f32::clamp`]. + /// + /// Each element in `min` must be less-or-equal to the corresponding element in `max`. + /// + /// # Panics + /// + /// Will panic if `min` is greater than `max` when `glam_assert` is enabled. + #[inline] + pub fn clamp(self, min: Self, max: Self) -> Self { + glam_assert!(min.cmple(max).all(), "clamp: expected min <= max"); + self.max(min).min(max) + } + + /// Returns the horizontal minimum of `self`. + /// + /// In other words this computes `min(x, y, ..)`. + #[inline] + pub fn min_element(self) -> f64 { + self.x.min(self.y.min(self.z.min(self.w))) + } + + /// Returns the horizontal maximum of `self`. + /// + /// In other words this computes `max(x, y, ..)`. + #[inline] + pub fn max_element(self) -> f64 { + self.x.max(self.y.max(self.z.max(self.w))) + } + + /// Returns a vector mask containing the result of a `==` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words, this computes `[self.x == rhs.x, self.y == rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpeq(self, rhs: Self) -> BVec4 { + BVec4::new( + self.x.eq(&rhs.x), + self.y.eq(&rhs.y), + self.z.eq(&rhs.z), + self.w.eq(&rhs.w), + ) + } + + /// Returns a vector mask containing the result of a `!=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x != rhs.x, self.y != rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpne(self, rhs: Self) -> BVec4 { + BVec4::new( + self.x.ne(&rhs.x), + self.y.ne(&rhs.y), + self.z.ne(&rhs.z), + self.w.ne(&rhs.w), + ) + } + + /// Returns a vector mask containing the result of a `>=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x >= rhs.x, self.y >= rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpge(self, rhs: Self) -> BVec4 { + BVec4::new( + self.x.ge(&rhs.x), + self.y.ge(&rhs.y), + self.z.ge(&rhs.z), + self.w.ge(&rhs.w), + ) + } + + /// Returns a vector mask containing the result of a `>` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x > rhs.x, self.y > rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpgt(self, rhs: Self) -> BVec4 { + BVec4::new( + self.x.gt(&rhs.x), + self.y.gt(&rhs.y), + self.z.gt(&rhs.z), + self.w.gt(&rhs.w), + ) + } + + /// Returns a vector mask containing the result of a `<=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x <= rhs.x, self.y <= rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmple(self, rhs: Self) -> BVec4 { + BVec4::new( + self.x.le(&rhs.x), + self.y.le(&rhs.y), + self.z.le(&rhs.z), + self.w.le(&rhs.w), + ) + } + + /// Returns a vector mask containing the result of a `<` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x < rhs.x, self.y < rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmplt(self, rhs: Self) -> BVec4 { + BVec4::new( + self.x.lt(&rhs.x), + self.y.lt(&rhs.y), + self.z.lt(&rhs.z), + self.w.lt(&rhs.w), + ) + } + + /// Returns a vector containing the absolute value of each element of `self`. + #[inline] + pub fn abs(self) -> Self { + Self { + x: self.x.abs(), + y: self.y.abs(), + z: self.z.abs(), + w: self.w.abs(), + } + } + + /// Returns a vector with elements representing the sign of `self`. + /// + /// - `1.0` if the number is positive, `+0.0` or `INFINITY` + /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` + /// - `NAN` if the number is `NAN` + #[inline] + pub fn signum(self) -> Self { + Self { + x: self.x.signum(), + y: self.y.signum(), + z: self.z.signum(), + w: self.w.signum(), + } + } + + /// Returns `true` if, and only if, all elements are finite. If any element is either + /// `NaN`, positive or negative infinity, this will return `false`. + #[inline] + pub fn is_finite(self) -> bool { + self.x.is_finite() && self.y.is_finite() && self.z.is_finite() && self.w.is_finite() + } + + /// Returns `true` if any elements are `NaN`. + #[inline] + pub fn is_nan(self) -> bool { + self.x.is_nan() || self.y.is_nan() || self.z.is_nan() || self.w.is_nan() + } + + /// Performs `is_nan` on each element of self, returning a vector mask of the results. + /// + /// In other words, this computes `[x.is_nan(), y.is_nan(), z.is_nan(), w.is_nan()]`. + #[inline] + pub fn is_nan_mask(self) -> BVec4 { + BVec4::new( + self.x.is_nan(), + self.y.is_nan(), + self.z.is_nan(), + self.w.is_nan(), + ) + } + + /// Computes the length of `self`. + #[doc(alias = "magnitude")] + #[inline] + pub fn length(self) -> f64 { + self.dot(self).sqrt() + } + + /// Computes the squared length of `self`. + /// + /// This is faster than `length()` as it avoids a square root operation. + #[doc(alias = "magnitude2")] + #[inline] + pub fn length_squared(self) -> f64 { + self.dot(self) + } + + /// Computes `1.0 / length()`. + /// + /// For valid results, `self` must _not_ be of length zero. + #[inline] + pub fn length_recip(self) -> f64 { + self.length().recip() + } + + /// Computes the Euclidean distance between two points in space. + #[inline] + pub fn distance(self, rhs: Self) -> f64 { + (self - rhs).length() + } + + /// Compute the squared euclidean distance between two points in space. + #[inline] + pub fn distance_squared(self, rhs: Self) -> f64 { + (self - rhs).length_squared() + } + + /// Returns `self` normalized to length 1.0. + /// + /// For valid results, `self` must _not_ be of length zero, nor very close to zero. + /// + /// See also [`Self::try_normalize`] and [`Self::normalize_or_zero`]. + /// + /// Panics + /// + /// Will panic if `self` is zero length when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn normalize(self) -> Self { + #[allow(clippy::let_and_return)] + let normalized = self.mul(self.length_recip()); + glam_assert!(normalized.is_finite()); + normalized + } + + /// Returns `self` normalized to length 1.0 if possible, else returns `None`. + /// + /// In particular, if the input is zero (or very close to zero), or non-finite, + /// the result of this operation will be `None`. + /// + /// See also [`Self::normalize_or_zero`]. + #[must_use] + #[inline] + pub fn try_normalize(self) -> Option { + let rcp = self.length_recip(); + if rcp.is_finite() && rcp > 0.0 { + Some(self * rcp) + } else { + None + } + } + + /// Returns `self` normalized to length 1.0 if possible, else returns zero. + /// + /// In particular, if the input is zero (or very close to zero), or non-finite, + /// the result of this operation will be zero. + /// + /// See also [`Self::try_normalize`]. + #[must_use] + #[inline] + pub fn normalize_or_zero(self) -> Self { + let rcp = self.length_recip(); + if rcp.is_finite() && rcp > 0.0 { + self * rcp + } else { + Self::ZERO + } + } + + /// Returns whether `self` is length `1.0` or not. + /// + /// Uses a precision threshold of `1e-6`. + #[inline] + pub fn is_normalized(self) -> bool { + // TODO: do something with epsilon + (self.length_squared() - 1.0).abs() <= 1e-4 + } + + /// Returns the vector projection of `self` onto `rhs`. + /// + /// `rhs` must be of non-zero length. + /// + /// # Panics + /// + /// Will panic if `rhs` is zero length when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn project_onto(self, rhs: Self) -> Self { + let other_len_sq_rcp = rhs.dot(rhs).recip(); + glam_assert!(other_len_sq_rcp.is_finite()); + rhs * self.dot(rhs) * other_len_sq_rcp + } + + /// Returns the vector rejection of `self` from `rhs`. + /// + /// The vector rejection is the vector perpendicular to the projection of `self` onto + /// `rhs`, in rhs words the result of `self - self.project_onto(rhs)`. + /// + /// `rhs` must be of non-zero length. + /// + /// # Panics + /// + /// Will panic if `rhs` has a length of zero when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn reject_from(self, rhs: Self) -> Self { + self - self.project_onto(rhs) + } + + /// Returns the vector projection of `self` onto `rhs`. + /// + /// `rhs` must be normalized. + /// + /// # Panics + /// + /// Will panic if `rhs` is not normalized when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn project_onto_normalized(self, rhs: Self) -> Self { + glam_assert!(rhs.is_normalized()); + rhs * self.dot(rhs) + } + + /// Returns the vector rejection of `self` from `rhs`. + /// + /// The vector rejection is the vector perpendicular to the projection of `self` onto + /// `rhs`, in rhs words the result of `self - self.project_onto(rhs)`. + /// + /// `rhs` must be normalized. + /// + /// # Panics + /// + /// Will panic if `rhs` is not normalized when `glam_assert` is enabled. + #[must_use] + #[inline] + pub fn reject_from_normalized(self, rhs: Self) -> Self { + self - self.project_onto_normalized(rhs) + } + + /// Returns a vector containing the nearest integer to a number for each element of `self`. + /// Round half-way cases away from 0.0. + #[inline] + pub fn round(self) -> Self { + Self { + x: self.x.round(), + y: self.y.round(), + z: self.z.round(), + w: self.w.round(), + } + } + + /// Returns a vector containing the largest integer less than or equal to a number for each + /// element of `self`. + #[inline] + pub fn floor(self) -> Self { + Self { + x: self.x.floor(), + y: self.y.floor(), + z: self.z.floor(), + w: self.w.floor(), + } + } + + /// Returns a vector containing the smallest integer greater than or equal to a number for + /// each element of `self`. + #[inline] + pub fn ceil(self) -> Self { + Self { + x: self.x.ceil(), + y: self.y.ceil(), + z: self.z.ceil(), + w: self.w.ceil(), + } + } + + /// Returns a vector containing the fractional part of the vector, e.g. `self - + /// self.floor()`. + /// + /// Note that this is fast but not precise for large numbers. + #[inline] + pub fn fract(self) -> Self { + self - self.floor() + } + + /// Returns a vector containing `e^self` (the exponential function) for each element of + /// `self`. + #[inline] + pub fn exp(self) -> Self { + Self::new(self.x.exp(), self.y.exp(), self.z.exp(), self.w.exp()) + } + + /// Returns a vector containing each element of `self` raised to the power of `n`. + #[inline] + pub fn powf(self, n: f64) -> Self { + Self::new( + self.x.powf(n), + self.y.powf(n), + self.z.powf(n), + self.w.powf(n), + ) + } + + /// Returns a vector containing the reciprocal `1.0/n` of each element of `self`. + #[inline] + pub fn recip(self) -> Self { + Self { + x: self.x.recip(), + y: self.y.recip(), + z: self.z.recip(), + w: self.w.recip(), + } + } + + /// Performs a linear interpolation between `self` and `rhs` based on the value `s`. + /// + /// When `s` is `0.0`, the result will be equal to `self`. When `s` is `1.0`, the result + /// will be equal to `rhs`. When `s` is outside of range `[0, 1]`, the result is linearly + /// extrapolated. + #[doc(alias = "mix")] + #[inline] + pub fn lerp(self, rhs: Self, s: f64) -> Self { + self + ((rhs - self) * s) + } + + /// Returns true if the absolute difference of all elements between `self` and `rhs` is + /// less than or equal to `max_abs_diff`. + /// + /// This can be used to compare if two vectors contain similar elements. It works best when + /// comparing with a known value. The `max_abs_diff` that should be used used depends on + /// the values being compared against. + /// + /// For more see + /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/). + #[inline] + pub fn abs_diff_eq(self, rhs: Self, max_abs_diff: f64) -> bool { + self.sub(rhs).abs().cmple(Self::splat(max_abs_diff)).all() + } + + /// Returns a vector with a length no less than `min` and no more than `max` + /// + /// # Panics + /// + /// Will panic if `min` is greater than `max` when `glam_assert` is enabled. + #[inline] + pub fn clamp_length(self, min: f64, max: f64) -> Self { + glam_assert!(min <= max); + let length_sq = self.length_squared(); + if length_sq < min * min { + self * (length_sq.sqrt().recip() * min) + } else if length_sq > max * max { + self * (length_sq.sqrt().recip() * max) + } else { + self + } + } + + /// Returns a vector with a length no more than `max` + pub fn clamp_length_max(self, max: f64) -> Self { + let length_sq = self.length_squared(); + if length_sq > max * max { + self * (length_sq.sqrt().recip() * max) + } else { + self + } + } + + /// Returns a vector with a length no less than `min` + pub fn clamp_length_min(self, min: f64) -> Self { + let length_sq = self.length_squared(); + if length_sq < min * min { + self * (length_sq.sqrt().recip() * min) + } else { + self + } + } + + /// Fused multiply-add. Computes `(self * a) + b` element-wise with only one rounding + /// error, yielding a more accurate result than an unfused multiply-add. + /// + /// Using `mul_add` *may* be more performant than an unfused multiply-add if the target + /// architecture has a dedicated fma CPU instruction. However, this is not always true, + /// and will be heavily dependant on designing algorithms with specific target hardware in + /// mind. + #[inline] + pub fn mul_add(self, a: Self, b: Self) -> Self { + Self::new( + self.x.mul_add(a.x, b.x), + self.y.mul_add(a.y, b.y), + self.z.mul_add(a.z, b.z), + self.w.mul_add(a.w, b.w), + ) + } + + /// Casts all elements of `self` to `f32`. + #[inline] + pub fn as_vec4(&self) -> crate::Vec4 { + crate::Vec4::new(self.x as f32, self.y as f32, self.z as f32, self.w as f32) + } + + /// Casts all elements of `self` to `i32`. + #[inline] + pub fn as_ivec4(&self) -> crate::IVec4 { + crate::IVec4::new(self.x as i32, self.y as i32, self.z as i32, self.w as i32) + } + + /// Casts all elements of `self` to `u32`. + #[inline] + pub fn as_uvec4(&self) -> crate::UVec4 { + crate::UVec4::new(self.x as u32, self.y as u32, self.z as u32, self.w as u32) + } +} + +impl Default for DVec4 { + #[inline(always)] + fn default() -> Self { + Self::ZERO + } +} + +impl PartialEq for DVec4 { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.cmpeq(*rhs).all() + } +} + +impl Div for DVec4 { + type Output = Self; + #[inline] + fn div(self, rhs: Self) -> Self { + Self { + x: self.x.div(rhs.x), + y: self.y.div(rhs.y), + z: self.z.div(rhs.z), + w: self.w.div(rhs.w), + } + } +} + +impl DivAssign for DVec4 { + #[inline] + fn div_assign(&mut self, rhs: Self) { + self.x.div_assign(rhs.x); + self.y.div_assign(rhs.y); + self.z.div_assign(rhs.z); + self.w.div_assign(rhs.w); + } +} + +impl Div for DVec4 { + type Output = Self; + #[inline] + fn div(self, rhs: f64) -> Self { + Self { + x: self.x.div(rhs), + y: self.y.div(rhs), + z: self.z.div(rhs), + w: self.w.div(rhs), + } + } +} + +impl DivAssign for DVec4 { + #[inline] + fn div_assign(&mut self, rhs: f64) { + self.x.div_assign(rhs); + self.y.div_assign(rhs); + self.z.div_assign(rhs); + self.w.div_assign(rhs); + } +} + +impl Div for f64 { + type Output = DVec4; + #[inline] + fn div(self, rhs: DVec4) -> DVec4 { + DVec4 { + x: self.div(rhs.x), + y: self.div(rhs.y), + z: self.div(rhs.z), + w: self.div(rhs.w), + } + } +} + +impl Mul for DVec4 { + type Output = Self; + #[inline] + fn mul(self, rhs: Self) -> Self { + Self { + x: self.x.mul(rhs.x), + y: self.y.mul(rhs.y), + z: self.z.mul(rhs.z), + w: self.w.mul(rhs.w), + } + } +} + +impl MulAssign for DVec4 { + #[inline] + fn mul_assign(&mut self, rhs: Self) { + self.x.mul_assign(rhs.x); + self.y.mul_assign(rhs.y); + self.z.mul_assign(rhs.z); + self.w.mul_assign(rhs.w); + } +} + +impl Mul for DVec4 { + type Output = Self; + #[inline] + fn mul(self, rhs: f64) -> Self { + Self { + x: self.x.mul(rhs), + y: self.y.mul(rhs), + z: self.z.mul(rhs), + w: self.w.mul(rhs), + } + } +} + +impl MulAssign for DVec4 { + #[inline] + fn mul_assign(&mut self, rhs: f64) { + self.x.mul_assign(rhs); + self.y.mul_assign(rhs); + self.z.mul_assign(rhs); + self.w.mul_assign(rhs); + } +} + +impl Mul for f64 { + type Output = DVec4; + #[inline] + fn mul(self, rhs: DVec4) -> DVec4 { + DVec4 { + x: self.mul(rhs.x), + y: self.mul(rhs.y), + z: self.mul(rhs.z), + w: self.mul(rhs.w), + } + } +} + +impl Add for DVec4 { + type Output = Self; + #[inline] + fn add(self, rhs: Self) -> Self { + Self { + x: self.x.add(rhs.x), + y: self.y.add(rhs.y), + z: self.z.add(rhs.z), + w: self.w.add(rhs.w), + } + } +} + +impl AddAssign for DVec4 { + #[inline] + fn add_assign(&mut self, rhs: Self) { + self.x.add_assign(rhs.x); + self.y.add_assign(rhs.y); + self.z.add_assign(rhs.z); + self.w.add_assign(rhs.w); + } +} + +impl Add for DVec4 { + type Output = Self; + #[inline] + fn add(self, rhs: f64) -> Self { + Self { + x: self.x.add(rhs), + y: self.y.add(rhs), + z: self.z.add(rhs), + w: self.w.add(rhs), + } + } +} + +impl AddAssign for DVec4 { + #[inline] + fn add_assign(&mut self, rhs: f64) { + self.x.add_assign(rhs); + self.y.add_assign(rhs); + self.z.add_assign(rhs); + self.w.add_assign(rhs); + } +} + +impl Add for f64 { + type Output = DVec4; + #[inline] + fn add(self, rhs: DVec4) -> DVec4 { + DVec4 { + x: self.add(rhs.x), + y: self.add(rhs.y), + z: self.add(rhs.z), + w: self.add(rhs.w), + } + } +} + +impl Sub for DVec4 { + type Output = Self; + #[inline] + fn sub(self, rhs: Self) -> Self { + Self { + x: self.x.sub(rhs.x), + y: self.y.sub(rhs.y), + z: self.z.sub(rhs.z), + w: self.w.sub(rhs.w), + } + } +} + +impl SubAssign for DVec4 { + #[inline] + fn sub_assign(&mut self, rhs: DVec4) { + self.x.sub_assign(rhs.x); + self.y.sub_assign(rhs.y); + self.z.sub_assign(rhs.z); + self.w.sub_assign(rhs.w); + } +} + +impl Sub for DVec4 { + type Output = Self; + #[inline] + fn sub(self, rhs: f64) -> Self { + Self { + x: self.x.sub(rhs), + y: self.y.sub(rhs), + z: self.z.sub(rhs), + w: self.w.sub(rhs), + } + } +} + +impl SubAssign for DVec4 { + #[inline] + fn sub_assign(&mut self, rhs: f64) { + self.x.sub_assign(rhs); + self.y.sub_assign(rhs); + self.z.sub_assign(rhs); + self.w.sub_assign(rhs); + } +} + +impl Sub for f64 { + type Output = DVec4; + #[inline] + fn sub(self, rhs: DVec4) -> DVec4 { + DVec4 { + x: self.sub(rhs.x), + y: self.sub(rhs.y), + z: self.sub(rhs.z), + w: self.sub(rhs.w), + } + } +} + +impl Rem for DVec4 { + type Output = Self; + #[inline] + fn rem(self, rhs: Self) -> Self { + Self { + x: self.x.rem(rhs.x), + y: self.y.rem(rhs.y), + z: self.z.rem(rhs.z), + w: self.w.rem(rhs.w), + } + } +} + +impl RemAssign for DVec4 { + #[inline] + fn rem_assign(&mut self, rhs: Self) { + self.x.rem_assign(rhs.x); + self.y.rem_assign(rhs.y); + self.z.rem_assign(rhs.z); + self.w.rem_assign(rhs.w); + } +} + +impl Rem for DVec4 { + type Output = Self; + #[inline] + fn rem(self, rhs: f64) -> Self { + Self { + x: self.x.rem(rhs), + y: self.y.rem(rhs), + z: self.z.rem(rhs), + w: self.w.rem(rhs), + } + } +} + +impl RemAssign for DVec4 { + #[inline] + fn rem_assign(&mut self, rhs: f64) { + self.x.rem_assign(rhs); + self.y.rem_assign(rhs); + self.z.rem_assign(rhs); + self.w.rem_assign(rhs); + } +} + +impl Rem for f64 { + type Output = DVec4; + #[inline] + fn rem(self, rhs: DVec4) -> DVec4 { + DVec4 { + x: self.rem(rhs.x), + y: self.rem(rhs.y), + z: self.rem(rhs.z), + w: self.rem(rhs.w), + } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsRef<[f64; 4]> for DVec4 { + #[inline] + fn as_ref(&self) -> &[f64; 4] { + unsafe { &*(self as *const DVec4 as *const [f64; 4]) } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsMut<[f64; 4]> for DVec4 { + #[inline] + fn as_mut(&mut self) -> &mut [f64; 4] { + unsafe { &mut *(self as *mut DVec4 as *mut [f64; 4]) } + } +} + +impl<'a> Sum<&'a Self> for DVec4 { + #[inline] + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, |a, &b| Self::add(a, b)) + } +} + +impl<'a> Product<&'a Self> for DVec4 { + #[inline] + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ONE, |a, &b| Self::mul(a, b)) + } +} + +impl Neg for DVec4 { + type Output = Self; + #[inline] + fn neg(self) -> Self { + Self { + x: self.x.neg(), + y: self.y.neg(), + z: self.z.neg(), + w: self.w.neg(), + } + } +} + +impl Index for DVec4 { + type Output = f64; + #[inline] + fn index(&self, index: usize) -> &Self::Output { + match index { + 0 => &self.x, + 1 => &self.y, + 2 => &self.z, + 3 => &self.w, + _ => panic!("index out of bounds"), + } + } +} + +impl IndexMut for DVec4 { + #[inline] + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + match index { + 0 => &mut self.x, + 1 => &mut self.y, + 2 => &mut self.z, + 3 => &mut self.w, + _ => panic!("index out of bounds"), + } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Display for DVec4 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "[{}, {}, {}, {}]", self.x, self.y, self.z, self.w) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Debug for DVec4 { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_tuple(stringify!(DVec4)) + .field(&self.x) + .field(&self.y) + .field(&self.z) + .field(&self.w) + .finish() + } +} + +impl From<[f64; 4]> for DVec4 { + #[inline] + fn from(a: [f64; 4]) -> Self { + Self::new(a[0], a[1], a[2], a[3]) + } +} + +impl From for [f64; 4] { + #[inline] + fn from(v: DVec4) -> Self { + [v.x, v.y, v.z, v.w] + } +} + +impl From<(f64, f64, f64, f64)> for DVec4 { + #[inline] + fn from(t: (f64, f64, f64, f64)) -> Self { + Self::new(t.0, t.1, t.2, t.3) + } +} + +impl From for (f64, f64, f64, f64) { + #[inline] + fn from(v: DVec4) -> Self { + (v.x, v.y, v.z, v.w) + } +} + +impl From<(DVec3, f64)> for DVec4 { + #[inline] + fn from((v, w): (DVec3, f64)) -> Self { + Self::new(v.x, v.y, v.z, w) + } +} + +impl From<(f64, DVec3)> for DVec4 { + #[inline] + fn from((x, v): (f64, DVec3)) -> Self { + Self::new(x, v.x, v.y, v.z) + } +} + +impl From<(DVec2, f64, f64)> for DVec4 { + #[inline] + fn from((v, z, w): (DVec2, f64, f64)) -> Self { + Self::new(v.x, v.y, z, w) + } +} + +impl From<(DVec2, DVec2)> for DVec4 { + #[inline] + fn from((v, u): (DVec2, DVec2)) -> Self { + Self::new(v.x, v.y, u.x, u.y) + } +} diff --git a/src/float_ex.rs b/src/float_ex.rs new file mode 100644 index 00000000..742670de --- /dev/null +++ b/src/float_ex.rs @@ -0,0 +1,50 @@ +#[cfg(not(feature = "std"))] +use num_traits::Float; + +pub(crate) trait FloatEx { + /// Returns a very close approximation of `self.clamp(-1.0, 1.0).acos()`. + fn acos_approx(self) -> Self; +} + +impl FloatEx for f32 { + #[inline(always)] + fn acos_approx(self) -> Self { + // Based on https://github.com/microsoft/DirectXMath `XMScalarAcos` + // Clamp input to [-1,1]. + let nonnegative = self >= 0.0; + let x = self.abs(); + let mut omx = 1.0 - x; + if omx < 0.0 { + omx = 0.0; + } + let root = omx.sqrt(); + + // 7-degree minimax approximation + #[allow(clippy::approx_constant)] + let mut result = ((((((-0.001_262_491_1 * x + 0.006_670_09) * x - 0.017_088_126) * x + + 0.030_891_88) + * x + - 0.050_174_303) + * x + + 0.088_978_99) + * x + - 0.214_598_8) + * x + + 1.570_796_3; + result *= root; + + // acos(x) = pi - acos(-x) when x < 0 + if nonnegative { + result + } else { + core::f32::consts::PI - result + } + } +} + +impl FloatEx for f64 { + #[inline(always)] + fn acos_approx(self) -> Self { + f64::acos(self.max(-1.0).min(1.0)) + } +} diff --git a/src/i32.rs b/src/i32.rs new file mode 100644 index 00000000..d50a1e53 --- /dev/null +++ b/src/i32.rs @@ -0,0 +1,37 @@ +mod ivec2; +mod ivec3; +mod ivec4; + +pub use ivec2::{ivec2, IVec2}; +pub use ivec3::{ivec3, IVec3}; +pub use ivec4::{ivec4, IVec4}; + +mod const_test_ivec2 { + #[cfg(not(feature = "cuda"))] + const_assert_eq!( + core::mem::align_of::(), + core::mem::align_of::() + ); + #[cfg(feature = "cuda")] + const_assert_eq!(8, core::mem::align_of::()); + const_assert_eq!(8, core::mem::size_of::()); +} + +mod const_test_ivec3 { + const_assert_eq!( + core::mem::align_of::(), + core::mem::align_of::() + ); + const_assert_eq!(12, core::mem::size_of::()); +} + +mod const_test_ivec4 { + #[cfg(not(feature = "cuda"))] + const_assert_eq!( + core::mem::align_of::(), + core::mem::align_of::() + ); + #[cfg(feature = "cuda")] + const_assert_eq!(16, core::mem::align_of::()); + const_assert_eq!(16, core::mem::size_of::()); +} diff --git a/src/i32/ivec2.rs b/src/i32/ivec2.rs new file mode 100644 index 00000000..edeb3af0 --- /dev/null +++ b/src/i32/ivec2.rs @@ -0,0 +1,931 @@ +// Generated from vec.rs template. Edit the template, not the generated file. + +use crate::{BVec2, IVec3}; + +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::iter::{Product, Sum}; +use core::{f32, ops::*}; + +/// Creates a 2-dimensional vector. +#[inline(always)] +pub const fn ivec2(x: i32, y: i32) -> IVec2 { + IVec2::new(x, y) +} + +/// A 2-dimensional vector. +#[derive(Clone, Copy)] +#[cfg_attr(feature = "cuda", repr(C, align(8)))] +pub struct IVec2 { + pub x: i32, + pub y: i32, +} + +impl IVec2 { + /// All zeroes. + pub const ZERO: Self = Self::splat(0); + + /// All ones. + pub const ONE: Self = Self::splat(1); + + /// All negative ones. + pub const NEG_ONE: Self = Self::splat(-1); + + /// `[1, 0]`: a unit-length vector pointing along the positive X axis. + pub const X: Self = Self::from_array([1, 0]); + + /// `[0, 1]`: a unit-length vector pointing along the positive Y axis. + pub const Y: Self = Self::from_array([0, 1]); + + /// The unit axes. + pub const AXES: [Self; 2] = [Self::X, Self::Y]; + + /// Creates a new vector. + #[inline(always)] + pub const fn new(x: i32, y: i32) -> Self { + Self { x, y } + } + + /// Creates a vector with all elements set to `v`. + #[inline] + pub const fn splat(v: i32) -> Self { + Self { x: v, y: v } + } + + /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use + /// for each element of `self`. + /// + /// A true element in the mask uses the corresponding element from `if_true`, and false + /// uses the element from `if_false`. + #[inline] + pub fn select(mask: BVec2, if_true: Self, if_false: Self) -> Self { + Self { + x: if mask.x { if_true.x } else { if_false.x }, + y: if mask.y { if_true.y } else { if_false.y }, + } + } + + /// Creates a new vector from an array. + #[inline] + pub const fn from_array(a: [i32; 2]) -> Self { + Self::new(a[0], a[1]) + } + + /// `[x, y]` + #[inline] + pub const fn to_array(&self) -> [i32; 2] { + [self.x, self.y] + } + + /// Creates a vector from the first N values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than N elements long. + #[inline] + pub const fn from_slice(slice: &[i32]) -> Self { + Self::new(slice[0], slice[1]) + } + + /// Writes the elements of `self` to the first 2 elements in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than N elements long. + #[inline] + pub fn write_to_slice(self, slice: &mut [i32]) { + slice[0] = self.x; + slice[1] = self.y; + } + + /// Creates a 3D vector from `self` and the given `z` value. + #[inline] + pub const fn extend(self, z: i32) -> IVec3 { + IVec3::new(self.x, self.y, z) + } + + /// Computes the dot product of `self` and `rhs`. + #[inline] + pub fn dot(self, rhs: Self) -> i32 { + (self.x * rhs.x) + (self.y * rhs.y) + } + + /// Returns a vector containing the minimum values for each element of `self` and `rhs`. + /// + /// In other words this computes `[self.x.min(rhs.x), self.y.min(rhs.y), ..]`. + #[inline] + pub fn min(self, rhs: Self) -> Self { + Self { + x: self.x.min(rhs.x), + y: self.y.min(rhs.y), + } + } + + /// Returns a vector containing the maximum values for each element of `self` and `rhs`. + /// + /// In other words this computes `[self.x.max(rhs.x), self.y.max(rhs.y), ..]`. + #[inline] + pub fn max(self, rhs: Self) -> Self { + Self { + x: self.x.max(rhs.x), + y: self.y.max(rhs.y), + } + } + + /// Component-wise clamping of values, similar to [`f32::clamp`]. + /// + /// Each element in `min` must be less-or-equal to the corresponding element in `max`. + /// + /// # Panics + /// + /// Will panic if `min` is greater than `max` when `glam_assert` is enabled. + #[inline] + pub fn clamp(self, min: Self, max: Self) -> Self { + glam_assert!(min.cmple(max).all(), "clamp: expected min <= max"); + self.max(min).min(max) + } + + /// Returns the horizontal minimum of `self`. + /// + /// In other words this computes `min(x, y, ..)`. + #[inline] + pub fn min_element(self) -> i32 { + self.x.min(self.y) + } + + /// Returns the horizontal maximum of `self`. + /// + /// In other words this computes `max(x, y, ..)`. + #[inline] + pub fn max_element(self) -> i32 { + self.x.max(self.y) + } + + /// Returns a vector mask containing the result of a `==` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words, this computes `[self.x == rhs.x, self.y == rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpeq(self, rhs: Self) -> BVec2 { + BVec2::new(self.x.eq(&rhs.x), self.y.eq(&rhs.y)) + } + + /// Returns a vector mask containing the result of a `!=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x != rhs.x, self.y != rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpne(self, rhs: Self) -> BVec2 { + BVec2::new(self.x.ne(&rhs.x), self.y.ne(&rhs.y)) + } + + /// Returns a vector mask containing the result of a `>=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x >= rhs.x, self.y >= rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpge(self, rhs: Self) -> BVec2 { + BVec2::new(self.x.ge(&rhs.x), self.y.ge(&rhs.y)) + } + + /// Returns a vector mask containing the result of a `>` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x > rhs.x, self.y > rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpgt(self, rhs: Self) -> BVec2 { + BVec2::new(self.x.gt(&rhs.x), self.y.gt(&rhs.y)) + } + + /// Returns a vector mask containing the result of a `<=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x <= rhs.x, self.y <= rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmple(self, rhs: Self) -> BVec2 { + BVec2::new(self.x.le(&rhs.x), self.y.le(&rhs.y)) + } + + /// Returns a vector mask containing the result of a `<` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x < rhs.x, self.y < rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmplt(self, rhs: Self) -> BVec2 { + BVec2::new(self.x.lt(&rhs.x), self.y.lt(&rhs.y)) + } + + /// Returns a vector containing the absolute value of each element of `self`. + #[inline] + pub fn abs(self) -> Self { + Self { + x: self.x.abs(), + y: self.y.abs(), + } + } + + /// Returns a vector with elements representing the sign of `self`. + /// + /// - `1.0` if the number is positive, `+0.0` or `INFINITY` + /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` + /// - `NAN` if the number is `NAN` + #[inline] + pub fn signum(self) -> Self { + Self { + x: self.x.signum(), + y: self.y.signum(), + } + } + + /// Returns a vector that is equal to `self` rotated by 90 degrees. + #[inline] + pub fn perp(self) -> Self { + Self { + x: -self.y, + y: self.x, + } + } + + /// The perpendicular dot product of `self` and `rhs`. + /// Also known as the wedge product, 2D cross product, and determinant. + #[doc(alias = "wedge")] + #[doc(alias = "cross")] + #[doc(alias = "determinant")] + #[inline] + pub fn perp_dot(self, rhs: Self) -> i32 { + (self.x * rhs.y) - (self.y * rhs.x) + } + + /// Returns `rhs` rotated by the angle of `self`. If `self` is normalized, + /// then this just rotation. This is what you usually want. Otherwise, + /// it will be like a rotation with a multiplication by `self`'s length. + #[must_use] + #[inline] + pub fn rotate(self, rhs: Self) -> Self { + Self { + x: self.x * rhs.x - self.y * rhs.y, + y: self.y * rhs.x + self.x * rhs.y, + } + } + + /// Casts all elements of `self` to `f32`. + #[inline] + pub fn as_vec2(&self) -> crate::Vec2 { + crate::Vec2::new(self.x as f32, self.y as f32) + } + + /// Casts all elements of `self` to `f64`. + #[inline] + pub fn as_dvec2(&self) -> crate::DVec2 { + crate::DVec2::new(self.x as f64, self.y as f64) + } + + /// Casts all elements of `self` to `u32`. + #[inline] + pub fn as_uvec2(&self) -> crate::UVec2 { + crate::UVec2::new(self.x as u32, self.y as u32) + } +} + +impl Default for IVec2 { + #[inline(always)] + fn default() -> Self { + Self::ZERO + } +} + +impl PartialEq for IVec2 { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.cmpeq(*rhs).all() + } +} + +impl Div for IVec2 { + type Output = Self; + #[inline] + fn div(self, rhs: Self) -> Self { + Self { + x: self.x.div(rhs.x), + y: self.y.div(rhs.y), + } + } +} + +impl DivAssign for IVec2 { + #[inline] + fn div_assign(&mut self, rhs: Self) { + self.x.div_assign(rhs.x); + self.y.div_assign(rhs.y); + } +} + +impl Div for IVec2 { + type Output = Self; + #[inline] + fn div(self, rhs: i32) -> Self { + Self { + x: self.x.div(rhs), + y: self.y.div(rhs), + } + } +} + +impl DivAssign for IVec2 { + #[inline] + fn div_assign(&mut self, rhs: i32) { + self.x.div_assign(rhs); + self.y.div_assign(rhs); + } +} + +impl Div for i32 { + type Output = IVec2; + #[inline] + fn div(self, rhs: IVec2) -> IVec2 { + IVec2 { + x: self.div(rhs.x), + y: self.div(rhs.y), + } + } +} + +impl Mul for IVec2 { + type Output = Self; + #[inline] + fn mul(self, rhs: Self) -> Self { + Self { + x: self.x.mul(rhs.x), + y: self.y.mul(rhs.y), + } + } +} + +impl MulAssign for IVec2 { + #[inline] + fn mul_assign(&mut self, rhs: Self) { + self.x.mul_assign(rhs.x); + self.y.mul_assign(rhs.y); + } +} + +impl Mul for IVec2 { + type Output = Self; + #[inline] + fn mul(self, rhs: i32) -> Self { + Self { + x: self.x.mul(rhs), + y: self.y.mul(rhs), + } + } +} + +impl MulAssign for IVec2 { + #[inline] + fn mul_assign(&mut self, rhs: i32) { + self.x.mul_assign(rhs); + self.y.mul_assign(rhs); + } +} + +impl Mul for i32 { + type Output = IVec2; + #[inline] + fn mul(self, rhs: IVec2) -> IVec2 { + IVec2 { + x: self.mul(rhs.x), + y: self.mul(rhs.y), + } + } +} + +impl Add for IVec2 { + type Output = Self; + #[inline] + fn add(self, rhs: Self) -> Self { + Self { + x: self.x.add(rhs.x), + y: self.y.add(rhs.y), + } + } +} + +impl AddAssign for IVec2 { + #[inline] + fn add_assign(&mut self, rhs: Self) { + self.x.add_assign(rhs.x); + self.y.add_assign(rhs.y); + } +} + +impl Add for IVec2 { + type Output = Self; + #[inline] + fn add(self, rhs: i32) -> Self { + Self { + x: self.x.add(rhs), + y: self.y.add(rhs), + } + } +} + +impl AddAssign for IVec2 { + #[inline] + fn add_assign(&mut self, rhs: i32) { + self.x.add_assign(rhs); + self.y.add_assign(rhs); + } +} + +impl Add for i32 { + type Output = IVec2; + #[inline] + fn add(self, rhs: IVec2) -> IVec2 { + IVec2 { + x: self.add(rhs.x), + y: self.add(rhs.y), + } + } +} + +impl Sub for IVec2 { + type Output = Self; + #[inline] + fn sub(self, rhs: Self) -> Self { + Self { + x: self.x.sub(rhs.x), + y: self.y.sub(rhs.y), + } + } +} + +impl SubAssign for IVec2 { + #[inline] + fn sub_assign(&mut self, rhs: IVec2) { + self.x.sub_assign(rhs.x); + self.y.sub_assign(rhs.y); + } +} + +impl Sub for IVec2 { + type Output = Self; + #[inline] + fn sub(self, rhs: i32) -> Self { + Self { + x: self.x.sub(rhs), + y: self.y.sub(rhs), + } + } +} + +impl SubAssign for IVec2 { + #[inline] + fn sub_assign(&mut self, rhs: i32) { + self.x.sub_assign(rhs); + self.y.sub_assign(rhs); + } +} + +impl Sub for i32 { + type Output = IVec2; + #[inline] + fn sub(self, rhs: IVec2) -> IVec2 { + IVec2 { + x: self.sub(rhs.x), + y: self.sub(rhs.y), + } + } +} + +impl Rem for IVec2 { + type Output = Self; + #[inline] + fn rem(self, rhs: Self) -> Self { + Self { + x: self.x.rem(rhs.x), + y: self.y.rem(rhs.y), + } + } +} + +impl RemAssign for IVec2 { + #[inline] + fn rem_assign(&mut self, rhs: Self) { + self.x.rem_assign(rhs.x); + self.y.rem_assign(rhs.y); + } +} + +impl Rem for IVec2 { + type Output = Self; + #[inline] + fn rem(self, rhs: i32) -> Self { + Self { + x: self.x.rem(rhs), + y: self.y.rem(rhs), + } + } +} + +impl RemAssign for IVec2 { + #[inline] + fn rem_assign(&mut self, rhs: i32) { + self.x.rem_assign(rhs); + self.y.rem_assign(rhs); + } +} + +impl Rem for i32 { + type Output = IVec2; + #[inline] + fn rem(self, rhs: IVec2) -> IVec2 { + IVec2 { + x: self.rem(rhs.x), + y: self.rem(rhs.y), + } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsRef<[i32; 2]> for IVec2 { + #[inline] + fn as_ref(&self) -> &[i32; 2] { + unsafe { &*(self as *const IVec2 as *const [i32; 2]) } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsMut<[i32; 2]> for IVec2 { + #[inline] + fn as_mut(&mut self) -> &mut [i32; 2] { + unsafe { &mut *(self as *mut IVec2 as *mut [i32; 2]) } + } +} + +impl<'a> Sum<&'a Self> for IVec2 { + #[inline] + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, |a, &b| Self::add(a, b)) + } +} + +impl<'a> Product<&'a Self> for IVec2 { + #[inline] + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ONE, |a, &b| Self::mul(a, b)) + } +} + +impl Neg for IVec2 { + type Output = Self; + #[inline] + fn neg(self) -> Self { + Self { + x: self.x.neg(), + y: self.y.neg(), + } + } +} + +impl Eq for IVec2 {} + +#[cfg(not(target_arch = "spirv"))] +impl core::hash::Hash for IVec2 { + fn hash(&self, state: &mut H) { + let inner: &[i32; 2] = self.as_ref(); + inner.hash(state); + } +} + +impl Not for IVec2 { + type Output = Self; + #[inline] + fn not(self) -> Self::Output { + Self { + x: self.x.not(), + y: self.y.not(), + } + } +} + +impl BitAnd for IVec2 { + type Output = Self; + #[inline] + fn bitand(self, rhs: Self) -> Self::Output { + Self { + x: self.x.bitand(rhs.x), + y: self.y.bitand(rhs.y), + } + } +} + +impl BitOr for IVec2 { + type Output = Self; + #[inline] + fn bitor(self, rhs: Self) -> Self::Output { + Self { + x: self.x.bitor(rhs.x), + y: self.y.bitor(rhs.y), + } + } +} + +impl BitXor for IVec2 { + type Output = Self; + #[inline] + fn bitxor(self, rhs: Self) -> Self::Output { + Self { + x: self.x.bitxor(rhs.x), + y: self.y.bitxor(rhs.y), + } + } +} + +impl BitAnd for IVec2 { + type Output = Self; + #[inline] + fn bitand(self, rhs: i32) -> Self::Output { + Self { + x: self.x.bitand(rhs), + y: self.y.bitand(rhs), + } + } +} + +impl BitOr for IVec2 { + type Output = Self; + #[inline] + fn bitor(self, rhs: i32) -> Self::Output { + Self { + x: self.x.bitor(rhs), + y: self.y.bitor(rhs), + } + } +} + +impl BitXor for IVec2 { + type Output = Self; + #[inline] + fn bitxor(self, rhs: i32) -> Self::Output { + Self { + x: self.x.bitxor(rhs), + y: self.y.bitxor(rhs), + } + } +} + +impl Shl for IVec2 { + type Output = Self; + #[inline] + fn shl(self, rhs: i8) -> Self::Output { + Self { + x: self.x.shl(rhs), + y: self.y.shl(rhs), + } + } +} + +impl Shr for IVec2 { + type Output = Self; + #[inline] + fn shr(self, rhs: i8) -> Self::Output { + Self { + x: self.x.shr(rhs), + y: self.y.shr(rhs), + } + } +} + +impl Shl for IVec2 { + type Output = Self; + #[inline] + fn shl(self, rhs: i16) -> Self::Output { + Self { + x: self.x.shl(rhs), + y: self.y.shl(rhs), + } + } +} + +impl Shr for IVec2 { + type Output = Self; + #[inline] + fn shr(self, rhs: i16) -> Self::Output { + Self { + x: self.x.shr(rhs), + y: self.y.shr(rhs), + } + } +} + +impl Shl for IVec2 { + type Output = Self; + #[inline] + fn shl(self, rhs: i32) -> Self::Output { + Self { + x: self.x.shl(rhs), + y: self.y.shl(rhs), + } + } +} + +impl Shr for IVec2 { + type Output = Self; + #[inline] + fn shr(self, rhs: i32) -> Self::Output { + Self { + x: self.x.shr(rhs), + y: self.y.shr(rhs), + } + } +} + +impl Shl for IVec2 { + type Output = Self; + #[inline] + fn shl(self, rhs: u8) -> Self::Output { + Self { + x: self.x.shl(rhs), + y: self.y.shl(rhs), + } + } +} + +impl Shr for IVec2 { + type Output = Self; + #[inline] + fn shr(self, rhs: u8) -> Self::Output { + Self { + x: self.x.shr(rhs), + y: self.y.shr(rhs), + } + } +} + +impl Shl for IVec2 { + type Output = Self; + #[inline] + fn shl(self, rhs: u16) -> Self::Output { + Self { + x: self.x.shl(rhs), + y: self.y.shl(rhs), + } + } +} + +impl Shr for IVec2 { + type Output = Self; + #[inline] + fn shr(self, rhs: u16) -> Self::Output { + Self { + x: self.x.shr(rhs), + y: self.y.shr(rhs), + } + } +} + +impl Shl for IVec2 { + type Output = Self; + #[inline] + fn shl(self, rhs: u32) -> Self::Output { + Self { + x: self.x.shl(rhs), + y: self.y.shl(rhs), + } + } +} + +impl Shr for IVec2 { + type Output = Self; + #[inline] + fn shr(self, rhs: u32) -> Self::Output { + Self { + x: self.x.shr(rhs), + y: self.y.shr(rhs), + } + } +} + +impl Shl for IVec2 { + type Output = Self; + #[inline] + fn shl(self, rhs: crate::IVec2) -> Self::Output { + Self { + x: self.x.shl(rhs.x), + y: self.y.shl(rhs.y), + } + } +} + +impl Shr for IVec2 { + type Output = Self; + #[inline] + fn shr(self, rhs: crate::IVec2) -> Self::Output { + Self { + x: self.x.shr(rhs.x), + y: self.y.shr(rhs.y), + } + } +} + +impl Shl for IVec2 { + type Output = Self; + #[inline] + fn shl(self, rhs: crate::UVec2) -> Self::Output { + Self { + x: self.x.shl(rhs.x), + y: self.y.shl(rhs.y), + } + } +} + +impl Shr for IVec2 { + type Output = Self; + #[inline] + fn shr(self, rhs: crate::UVec2) -> Self::Output { + Self { + x: self.x.shr(rhs.x), + y: self.y.shr(rhs.y), + } + } +} + +impl Index for IVec2 { + type Output = i32; + #[inline] + fn index(&self, index: usize) -> &Self::Output { + match index { + 0 => &self.x, + 1 => &self.y, + _ => panic!("index out of bounds"), + } + } +} + +impl IndexMut for IVec2 { + #[inline] + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + match index { + 0 => &mut self.x, + 1 => &mut self.y, + _ => panic!("index out of bounds"), + } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Display for IVec2 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "[{}, {}]", self.x, self.y) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Debug for IVec2 { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_tuple(stringify!(IVec2)) + .field(&self.x) + .field(&self.y) + .finish() + } +} + +impl From<[i32; 2]> for IVec2 { + #[inline] + fn from(a: [i32; 2]) -> Self { + Self::new(a[0], a[1]) + } +} + +impl From for [i32; 2] { + #[inline] + fn from(v: IVec2) -> Self { + [v.x, v.y] + } +} + +impl From<(i32, i32)> for IVec2 { + #[inline] + fn from(t: (i32, i32)) -> Self { + Self::new(t.0, t.1) + } +} + +impl From for (i32, i32) { + #[inline] + fn from(v: IVec2) -> Self { + (v.x, v.y) + } +} diff --git a/src/i32/ivec3.rs b/src/i32/ivec3.rs new file mode 100644 index 00000000..5bdf2cd4 --- /dev/null +++ b/src/i32/ivec3.rs @@ -0,0 +1,1004 @@ +// Generated from vec.rs template. Edit the template, not the generated file. + +use crate::{BVec3, IVec2, IVec4}; + +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::iter::{Product, Sum}; +use core::{f32, ops::*}; + +/// Creates a 3-dimensional vector. +#[inline(always)] +pub const fn ivec3(x: i32, y: i32, z: i32) -> IVec3 { + IVec3::new(x, y, z) +} + +/// A 3-dimensional vector. +#[derive(Clone, Copy)] +pub struct IVec3 { + pub x: i32, + pub y: i32, + pub z: i32, +} + +impl IVec3 { + /// All zeroes. + pub const ZERO: Self = Self::splat(0); + + /// All ones. + pub const ONE: Self = Self::splat(1); + + /// All negative ones. + pub const NEG_ONE: Self = Self::splat(-1); + + /// `[1, 0, 0]`: a unit-length vector pointing along the positive X axis. + pub const X: Self = Self::from_array([1, 0, 0]); + + /// `[0, 1, 0]`: a unit-length vector pointing along the positive Y axis. + pub const Y: Self = Self::from_array([0, 1, 0]); + + /// `[0, 0, 1]`: a unit-length vector pointing along the positive Z axis. + pub const Z: Self = Self::from_array([0, 0, 1]); + + /// The unit axes. + pub const AXES: [Self; 3] = [Self::X, Self::Y, Self::Z]; + + /// Creates a new vector. + #[inline(always)] + pub const fn new(x: i32, y: i32, z: i32) -> Self { + Self { x, y, z } + } + + /// Creates a vector with all elements set to `v`. + #[inline] + pub const fn splat(v: i32) -> Self { + Self { x: v, y: v, z: v } + } + + /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use + /// for each element of `self`. + /// + /// A true element in the mask uses the corresponding element from `if_true`, and false + /// uses the element from `if_false`. + #[inline] + pub fn select(mask: BVec3, if_true: Self, if_false: Self) -> Self { + Self { + x: if mask.x { if_true.x } else { if_false.x }, + y: if mask.y { if_true.y } else { if_false.y }, + z: if mask.z { if_true.z } else { if_false.z }, + } + } + + /// Creates a new vector from an array. + #[inline] + pub const fn from_array(a: [i32; 3]) -> Self { + Self::new(a[0], a[1], a[2]) + } + + /// `[x, y, z]` + #[inline] + pub const fn to_array(&self) -> [i32; 3] { + [self.x, self.y, self.z] + } + + /// Creates a vector from the first N values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than N elements long. + #[inline] + pub const fn from_slice(slice: &[i32]) -> Self { + Self::new(slice[0], slice[1], slice[2]) + } + + /// Writes the elements of `self` to the first 3 elements in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than N elements long. + #[inline] + pub fn write_to_slice(self, slice: &mut [i32]) { + slice[0] = self.x; + slice[1] = self.y; + slice[2] = self.z; + } + + /// Internal method for creating a 3D vector from a 4D vector, discarding `w`. + #[allow(dead_code)] + #[inline] + pub(crate) fn from_vec4(v: IVec4) -> Self { + Self { + x: v.x, + y: v.y, + z: v.z, + } + } + + /// Creates a 4D vector from `self` and the given `w` value. + #[inline] + pub fn extend(self, w: i32) -> IVec4 { + IVec4::new(self.x, self.y, self.z, w) + } + + /// Creates a 2D vector from the `x` and `y` elements of `self`, discarding `z`. + /// + /// Truncation may also be performed by using `self.xy()` or `IVec2::from()`. + #[inline] + pub fn truncate(self) -> IVec2 { + use crate::swizzles::Vec3Swizzles; + self.xy() + } + + /// Computes the dot product of `self` and `rhs`. + #[inline] + pub fn dot(self, rhs: Self) -> i32 { + (self.x * rhs.x) + (self.y * rhs.y) + (self.z * rhs.z) + } + + /// Computes the cross product of `self` and `rhs`. + #[inline] + pub fn cross(self, rhs: Self) -> Self { + Self { + x: self.y * rhs.z - rhs.y * self.z, + y: self.z * rhs.x - rhs.z * self.x, + z: self.x * rhs.y - rhs.x * self.y, + } + } + + /// Returns a vector containing the minimum values for each element of `self` and `rhs`. + /// + /// In other words this computes `[self.x.min(rhs.x), self.y.min(rhs.y), ..]`. + #[inline] + pub fn min(self, rhs: Self) -> Self { + Self { + x: self.x.min(rhs.x), + y: self.y.min(rhs.y), + z: self.z.min(rhs.z), + } + } + + /// Returns a vector containing the maximum values for each element of `self` and `rhs`. + /// + /// In other words this computes `[self.x.max(rhs.x), self.y.max(rhs.y), ..]`. + #[inline] + pub fn max(self, rhs: Self) -> Self { + Self { + x: self.x.max(rhs.x), + y: self.y.max(rhs.y), + z: self.z.max(rhs.z), + } + } + + /// Component-wise clamping of values, similar to [`f32::clamp`]. + /// + /// Each element in `min` must be less-or-equal to the corresponding element in `max`. + /// + /// # Panics + /// + /// Will panic if `min` is greater than `max` when `glam_assert` is enabled. + #[inline] + pub fn clamp(self, min: Self, max: Self) -> Self { + glam_assert!(min.cmple(max).all(), "clamp: expected min <= max"); + self.max(min).min(max) + } + + /// Returns the horizontal minimum of `self`. + /// + /// In other words this computes `min(x, y, ..)`. + #[inline] + pub fn min_element(self) -> i32 { + self.x.min(self.y.min(self.z)) + } + + /// Returns the horizontal maximum of `self`. + /// + /// In other words this computes `max(x, y, ..)`. + #[inline] + pub fn max_element(self) -> i32 { + self.x.max(self.y.max(self.z)) + } + + /// Returns a vector mask containing the result of a `==` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words, this computes `[self.x == rhs.x, self.y == rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpeq(self, rhs: Self) -> BVec3 { + BVec3::new(self.x.eq(&rhs.x), self.y.eq(&rhs.y), self.z.eq(&rhs.z)) + } + + /// Returns a vector mask containing the result of a `!=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x != rhs.x, self.y != rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpne(self, rhs: Self) -> BVec3 { + BVec3::new(self.x.ne(&rhs.x), self.y.ne(&rhs.y), self.z.ne(&rhs.z)) + } + + /// Returns a vector mask containing the result of a `>=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x >= rhs.x, self.y >= rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpge(self, rhs: Self) -> BVec3 { + BVec3::new(self.x.ge(&rhs.x), self.y.ge(&rhs.y), self.z.ge(&rhs.z)) + } + + /// Returns a vector mask containing the result of a `>` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x > rhs.x, self.y > rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpgt(self, rhs: Self) -> BVec3 { + BVec3::new(self.x.gt(&rhs.x), self.y.gt(&rhs.y), self.z.gt(&rhs.z)) + } + + /// Returns a vector mask containing the result of a `<=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x <= rhs.x, self.y <= rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmple(self, rhs: Self) -> BVec3 { + BVec3::new(self.x.le(&rhs.x), self.y.le(&rhs.y), self.z.le(&rhs.z)) + } + + /// Returns a vector mask containing the result of a `<` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x < rhs.x, self.y < rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmplt(self, rhs: Self) -> BVec3 { + BVec3::new(self.x.lt(&rhs.x), self.y.lt(&rhs.y), self.z.lt(&rhs.z)) + } + + /// Returns a vector containing the absolute value of each element of `self`. + #[inline] + pub fn abs(self) -> Self { + Self { + x: self.x.abs(), + y: self.y.abs(), + z: self.z.abs(), + } + } + + /// Returns a vector with elements representing the sign of `self`. + /// + /// - `1.0` if the number is positive, `+0.0` or `INFINITY` + /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` + /// - `NAN` if the number is `NAN` + #[inline] + pub fn signum(self) -> Self { + Self { + x: self.x.signum(), + y: self.y.signum(), + z: self.z.signum(), + } + } + + /// Casts all elements of `self` to `f32`. + #[inline] + pub fn as_vec3(&self) -> crate::Vec3 { + crate::Vec3::new(self.x as f32, self.y as f32, self.z as f32) + } + + /// Casts all elements of `self` to `f32`. + #[inline] + pub fn as_vec3a(&self) -> crate::Vec3A { + crate::Vec3A::new(self.x as f32, self.y as f32, self.z as f32) + } + + /// Casts all elements of `self` to `f64`. + #[inline] + pub fn as_dvec3(&self) -> crate::DVec3 { + crate::DVec3::new(self.x as f64, self.y as f64, self.z as f64) + } + + /// Casts all elements of `self` to `u32`. + #[inline] + pub fn as_uvec3(&self) -> crate::UVec3 { + crate::UVec3::new(self.x as u32, self.y as u32, self.z as u32) + } +} + +impl Default for IVec3 { + #[inline(always)] + fn default() -> Self { + Self::ZERO + } +} + +impl PartialEq for IVec3 { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.cmpeq(*rhs).all() + } +} + +impl Div for IVec3 { + type Output = Self; + #[inline] + fn div(self, rhs: Self) -> Self { + Self { + x: self.x.div(rhs.x), + y: self.y.div(rhs.y), + z: self.z.div(rhs.z), + } + } +} + +impl DivAssign for IVec3 { + #[inline] + fn div_assign(&mut self, rhs: Self) { + self.x.div_assign(rhs.x); + self.y.div_assign(rhs.y); + self.z.div_assign(rhs.z); + } +} + +impl Div for IVec3 { + type Output = Self; + #[inline] + fn div(self, rhs: i32) -> Self { + Self { + x: self.x.div(rhs), + y: self.y.div(rhs), + z: self.z.div(rhs), + } + } +} + +impl DivAssign for IVec3 { + #[inline] + fn div_assign(&mut self, rhs: i32) { + self.x.div_assign(rhs); + self.y.div_assign(rhs); + self.z.div_assign(rhs); + } +} + +impl Div for i32 { + type Output = IVec3; + #[inline] + fn div(self, rhs: IVec3) -> IVec3 { + IVec3 { + x: self.div(rhs.x), + y: self.div(rhs.y), + z: self.div(rhs.z), + } + } +} + +impl Mul for IVec3 { + type Output = Self; + #[inline] + fn mul(self, rhs: Self) -> Self { + Self { + x: self.x.mul(rhs.x), + y: self.y.mul(rhs.y), + z: self.z.mul(rhs.z), + } + } +} + +impl MulAssign for IVec3 { + #[inline] + fn mul_assign(&mut self, rhs: Self) { + self.x.mul_assign(rhs.x); + self.y.mul_assign(rhs.y); + self.z.mul_assign(rhs.z); + } +} + +impl Mul for IVec3 { + type Output = Self; + #[inline] + fn mul(self, rhs: i32) -> Self { + Self { + x: self.x.mul(rhs), + y: self.y.mul(rhs), + z: self.z.mul(rhs), + } + } +} + +impl MulAssign for IVec3 { + #[inline] + fn mul_assign(&mut self, rhs: i32) { + self.x.mul_assign(rhs); + self.y.mul_assign(rhs); + self.z.mul_assign(rhs); + } +} + +impl Mul for i32 { + type Output = IVec3; + #[inline] + fn mul(self, rhs: IVec3) -> IVec3 { + IVec3 { + x: self.mul(rhs.x), + y: self.mul(rhs.y), + z: self.mul(rhs.z), + } + } +} + +impl Add for IVec3 { + type Output = Self; + #[inline] + fn add(self, rhs: Self) -> Self { + Self { + x: self.x.add(rhs.x), + y: self.y.add(rhs.y), + z: self.z.add(rhs.z), + } + } +} + +impl AddAssign for IVec3 { + #[inline] + fn add_assign(&mut self, rhs: Self) { + self.x.add_assign(rhs.x); + self.y.add_assign(rhs.y); + self.z.add_assign(rhs.z); + } +} + +impl Add for IVec3 { + type Output = Self; + #[inline] + fn add(self, rhs: i32) -> Self { + Self { + x: self.x.add(rhs), + y: self.y.add(rhs), + z: self.z.add(rhs), + } + } +} + +impl AddAssign for IVec3 { + #[inline] + fn add_assign(&mut self, rhs: i32) { + self.x.add_assign(rhs); + self.y.add_assign(rhs); + self.z.add_assign(rhs); + } +} + +impl Add for i32 { + type Output = IVec3; + #[inline] + fn add(self, rhs: IVec3) -> IVec3 { + IVec3 { + x: self.add(rhs.x), + y: self.add(rhs.y), + z: self.add(rhs.z), + } + } +} + +impl Sub for IVec3 { + type Output = Self; + #[inline] + fn sub(self, rhs: Self) -> Self { + Self { + x: self.x.sub(rhs.x), + y: self.y.sub(rhs.y), + z: self.z.sub(rhs.z), + } + } +} + +impl SubAssign for IVec3 { + #[inline] + fn sub_assign(&mut self, rhs: IVec3) { + self.x.sub_assign(rhs.x); + self.y.sub_assign(rhs.y); + self.z.sub_assign(rhs.z); + } +} + +impl Sub for IVec3 { + type Output = Self; + #[inline] + fn sub(self, rhs: i32) -> Self { + Self { + x: self.x.sub(rhs), + y: self.y.sub(rhs), + z: self.z.sub(rhs), + } + } +} + +impl SubAssign for IVec3 { + #[inline] + fn sub_assign(&mut self, rhs: i32) { + self.x.sub_assign(rhs); + self.y.sub_assign(rhs); + self.z.sub_assign(rhs); + } +} + +impl Sub for i32 { + type Output = IVec3; + #[inline] + fn sub(self, rhs: IVec3) -> IVec3 { + IVec3 { + x: self.sub(rhs.x), + y: self.sub(rhs.y), + z: self.sub(rhs.z), + } + } +} + +impl Rem for IVec3 { + type Output = Self; + #[inline] + fn rem(self, rhs: Self) -> Self { + Self { + x: self.x.rem(rhs.x), + y: self.y.rem(rhs.y), + z: self.z.rem(rhs.z), + } + } +} + +impl RemAssign for IVec3 { + #[inline] + fn rem_assign(&mut self, rhs: Self) { + self.x.rem_assign(rhs.x); + self.y.rem_assign(rhs.y); + self.z.rem_assign(rhs.z); + } +} + +impl Rem for IVec3 { + type Output = Self; + #[inline] + fn rem(self, rhs: i32) -> Self { + Self { + x: self.x.rem(rhs), + y: self.y.rem(rhs), + z: self.z.rem(rhs), + } + } +} + +impl RemAssign for IVec3 { + #[inline] + fn rem_assign(&mut self, rhs: i32) { + self.x.rem_assign(rhs); + self.y.rem_assign(rhs); + self.z.rem_assign(rhs); + } +} + +impl Rem for i32 { + type Output = IVec3; + #[inline] + fn rem(self, rhs: IVec3) -> IVec3 { + IVec3 { + x: self.rem(rhs.x), + y: self.rem(rhs.y), + z: self.rem(rhs.z), + } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsRef<[i32; 3]> for IVec3 { + #[inline] + fn as_ref(&self) -> &[i32; 3] { + unsafe { &*(self as *const IVec3 as *const [i32; 3]) } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsMut<[i32; 3]> for IVec3 { + #[inline] + fn as_mut(&mut self) -> &mut [i32; 3] { + unsafe { &mut *(self as *mut IVec3 as *mut [i32; 3]) } + } +} + +impl<'a> Sum<&'a Self> for IVec3 { + #[inline] + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, |a, &b| Self::add(a, b)) + } +} + +impl<'a> Product<&'a Self> for IVec3 { + #[inline] + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ONE, |a, &b| Self::mul(a, b)) + } +} + +impl Neg for IVec3 { + type Output = Self; + #[inline] + fn neg(self) -> Self { + Self { + x: self.x.neg(), + y: self.y.neg(), + z: self.z.neg(), + } + } +} + +impl Eq for IVec3 {} + +#[cfg(not(target_arch = "spirv"))] +impl core::hash::Hash for IVec3 { + fn hash(&self, state: &mut H) { + let inner: &[i32; 3] = self.as_ref(); + inner.hash(state); + } +} + +impl Not for IVec3 { + type Output = Self; + #[inline] + fn not(self) -> Self::Output { + Self { + x: self.x.not(), + y: self.y.not(), + z: self.z.not(), + } + } +} + +impl BitAnd for IVec3 { + type Output = Self; + #[inline] + fn bitand(self, rhs: Self) -> Self::Output { + Self { + x: self.x.bitand(rhs.x), + y: self.y.bitand(rhs.y), + z: self.z.bitand(rhs.z), + } + } +} + +impl BitOr for IVec3 { + type Output = Self; + #[inline] + fn bitor(self, rhs: Self) -> Self::Output { + Self { + x: self.x.bitor(rhs.x), + y: self.y.bitor(rhs.y), + z: self.z.bitor(rhs.z), + } + } +} + +impl BitXor for IVec3 { + type Output = Self; + #[inline] + fn bitxor(self, rhs: Self) -> Self::Output { + Self { + x: self.x.bitxor(rhs.x), + y: self.y.bitxor(rhs.y), + z: self.z.bitxor(rhs.z), + } + } +} + +impl BitAnd for IVec3 { + type Output = Self; + #[inline] + fn bitand(self, rhs: i32) -> Self::Output { + Self { + x: self.x.bitand(rhs), + y: self.y.bitand(rhs), + z: self.z.bitand(rhs), + } + } +} + +impl BitOr for IVec3 { + type Output = Self; + #[inline] + fn bitor(self, rhs: i32) -> Self::Output { + Self { + x: self.x.bitor(rhs), + y: self.y.bitor(rhs), + z: self.z.bitor(rhs), + } + } +} + +impl BitXor for IVec3 { + type Output = Self; + #[inline] + fn bitxor(self, rhs: i32) -> Self::Output { + Self { + x: self.x.bitxor(rhs), + y: self.y.bitxor(rhs), + z: self.z.bitxor(rhs), + } + } +} + +impl Shl for IVec3 { + type Output = Self; + #[inline] + fn shl(self, rhs: i8) -> Self::Output { + Self { + x: self.x.shl(rhs), + y: self.y.shl(rhs), + z: self.z.shl(rhs), + } + } +} + +impl Shr for IVec3 { + type Output = Self; + #[inline] + fn shr(self, rhs: i8) -> Self::Output { + Self { + x: self.x.shr(rhs), + y: self.y.shr(rhs), + z: self.z.shr(rhs), + } + } +} + +impl Shl for IVec3 { + type Output = Self; + #[inline] + fn shl(self, rhs: i16) -> Self::Output { + Self { + x: self.x.shl(rhs), + y: self.y.shl(rhs), + z: self.z.shl(rhs), + } + } +} + +impl Shr for IVec3 { + type Output = Self; + #[inline] + fn shr(self, rhs: i16) -> Self::Output { + Self { + x: self.x.shr(rhs), + y: self.y.shr(rhs), + z: self.z.shr(rhs), + } + } +} + +impl Shl for IVec3 { + type Output = Self; + #[inline] + fn shl(self, rhs: i32) -> Self::Output { + Self { + x: self.x.shl(rhs), + y: self.y.shl(rhs), + z: self.z.shl(rhs), + } + } +} + +impl Shr for IVec3 { + type Output = Self; + #[inline] + fn shr(self, rhs: i32) -> Self::Output { + Self { + x: self.x.shr(rhs), + y: self.y.shr(rhs), + z: self.z.shr(rhs), + } + } +} + +impl Shl for IVec3 { + type Output = Self; + #[inline] + fn shl(self, rhs: u8) -> Self::Output { + Self { + x: self.x.shl(rhs), + y: self.y.shl(rhs), + z: self.z.shl(rhs), + } + } +} + +impl Shr for IVec3 { + type Output = Self; + #[inline] + fn shr(self, rhs: u8) -> Self::Output { + Self { + x: self.x.shr(rhs), + y: self.y.shr(rhs), + z: self.z.shr(rhs), + } + } +} + +impl Shl for IVec3 { + type Output = Self; + #[inline] + fn shl(self, rhs: u16) -> Self::Output { + Self { + x: self.x.shl(rhs), + y: self.y.shl(rhs), + z: self.z.shl(rhs), + } + } +} + +impl Shr for IVec3 { + type Output = Self; + #[inline] + fn shr(self, rhs: u16) -> Self::Output { + Self { + x: self.x.shr(rhs), + y: self.y.shr(rhs), + z: self.z.shr(rhs), + } + } +} + +impl Shl for IVec3 { + type Output = Self; + #[inline] + fn shl(self, rhs: u32) -> Self::Output { + Self { + x: self.x.shl(rhs), + y: self.y.shl(rhs), + z: self.z.shl(rhs), + } + } +} + +impl Shr for IVec3 { + type Output = Self; + #[inline] + fn shr(self, rhs: u32) -> Self::Output { + Self { + x: self.x.shr(rhs), + y: self.y.shr(rhs), + z: self.z.shr(rhs), + } + } +} + +impl Shl for IVec3 { + type Output = Self; + #[inline] + fn shl(self, rhs: crate::IVec3) -> Self::Output { + Self { + x: self.x.shl(rhs.x), + y: self.y.shl(rhs.y), + z: self.z.shl(rhs.z), + } + } +} + +impl Shr for IVec3 { + type Output = Self; + #[inline] + fn shr(self, rhs: crate::IVec3) -> Self::Output { + Self { + x: self.x.shr(rhs.x), + y: self.y.shr(rhs.y), + z: self.z.shr(rhs.z), + } + } +} + +impl Shl for IVec3 { + type Output = Self; + #[inline] + fn shl(self, rhs: crate::UVec3) -> Self::Output { + Self { + x: self.x.shl(rhs.x), + y: self.y.shl(rhs.y), + z: self.z.shl(rhs.z), + } + } +} + +impl Shr for IVec3 { + type Output = Self; + #[inline] + fn shr(self, rhs: crate::UVec3) -> Self::Output { + Self { + x: self.x.shr(rhs.x), + y: self.y.shr(rhs.y), + z: self.z.shr(rhs.z), + } + } +} + +impl Index for IVec3 { + type Output = i32; + #[inline] + fn index(&self, index: usize) -> &Self::Output { + match index { + 0 => &self.x, + 1 => &self.y, + 2 => &self.z, + _ => panic!("index out of bounds"), + } + } +} + +impl IndexMut for IVec3 { + #[inline] + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + match index { + 0 => &mut self.x, + 1 => &mut self.y, + 2 => &mut self.z, + _ => panic!("index out of bounds"), + } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Display for IVec3 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "[{}, {}, {}]", self.x, self.y, self.z) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Debug for IVec3 { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_tuple(stringify!(IVec3)) + .field(&self.x) + .field(&self.y) + .field(&self.z) + .finish() + } +} + +impl From<[i32; 3]> for IVec3 { + #[inline] + fn from(a: [i32; 3]) -> Self { + Self::new(a[0], a[1], a[2]) + } +} + +impl From for [i32; 3] { + #[inline] + fn from(v: IVec3) -> Self { + [v.x, v.y, v.z] + } +} + +impl From<(i32, i32, i32)> for IVec3 { + #[inline] + fn from(t: (i32, i32, i32)) -> Self { + Self::new(t.0, t.1, t.2) + } +} + +impl From for (i32, i32, i32) { + #[inline] + fn from(v: IVec3) -> Self { + (v.x, v.y, v.z) + } +} + +impl From<(IVec2, i32)> for IVec3 { + #[inline] + fn from((v, z): (IVec2, i32)) -> Self { + Self::new(v.x, v.y, z) + } +} diff --git a/src/i32/ivec4.rs b/src/i32/ivec4.rs new file mode 100644 index 00000000..a2aa2c8a --- /dev/null +++ b/src/i32/ivec4.rs @@ -0,0 +1,1093 @@ +// Generated from vec.rs template. Edit the template, not the generated file. + +use crate::{BVec4, IVec2, IVec3}; + +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::iter::{Product, Sum}; +use core::{f32, ops::*}; + +/// Creates a 4-dimensional vector. +#[inline(always)] +pub const fn ivec4(x: i32, y: i32, z: i32, w: i32) -> IVec4 { + IVec4::new(x, y, z, w) +} + +/// A 4-dimensional vector. +#[derive(Clone, Copy)] +#[cfg_attr(feature = "cuda", repr(C, align(16)))] +pub struct IVec4 { + pub x: i32, + pub y: i32, + pub z: i32, + pub w: i32, +} + +impl IVec4 { + /// All zeroes. + pub const ZERO: Self = Self::splat(0); + + /// All ones. + pub const ONE: Self = Self::splat(1); + + /// All negative ones. + pub const NEG_ONE: Self = Self::splat(-1); + + /// `[1, 0, 0, 0]`: a unit-length vector pointing along the positive X axis. + pub const X: Self = Self::from_array([1, 0, 0, 0]); + + /// `[0, 1, 0, 0]`: a unit-length vector pointing along the positive Y axis. + pub const Y: Self = Self::from_array([0, 1, 0, 0]); + + /// `[0, 0, 1, 0]`: a unit-length vector pointing along the positive Z axis. + pub const Z: Self = Self::from_array([0, 0, 1, 0]); + + /// `[0, 0, 0, 1]`: a unit-length vector pointing along the positive W axis. + pub const W: Self = Self::from_array([0, 0, 0, 1]); + + /// The unit axes. + pub const AXES: [Self; 4] = [Self::X, Self::Y, Self::Z, Self::W]; + + /// Creates a new vector. + #[inline(always)] + pub const fn new(x: i32, y: i32, z: i32, w: i32) -> Self { + Self { x, y, z, w } + } + + /// Creates a vector with all elements set to `v`. + #[inline] + pub const fn splat(v: i32) -> Self { + Self { + x: v, + + y: v, + + z: v, + + w: v, + } + } + + /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use + /// for each element of `self`. + /// + /// A true element in the mask uses the corresponding element from `if_true`, and false + /// uses the element from `if_false`. + #[inline] + pub fn select(mask: BVec4, if_true: Self, if_false: Self) -> Self { + Self { + x: if mask.x { if_true.x } else { if_false.x }, + y: if mask.y { if_true.y } else { if_false.y }, + z: if mask.z { if_true.z } else { if_false.z }, + w: if mask.w { if_true.w } else { if_false.w }, + } + } + + /// Creates a new vector from an array. + #[inline] + pub const fn from_array(a: [i32; 4]) -> Self { + Self::new(a[0], a[1], a[2], a[3]) + } + + /// `[x, y, z, w]` + #[inline] + pub const fn to_array(&self) -> [i32; 4] { + [self.x, self.y, self.z, self.w] + } + + /// Creates a vector from the first N values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than N elements long. + #[inline] + pub const fn from_slice(slice: &[i32]) -> Self { + Self::new(slice[0], slice[1], slice[2], slice[3]) + } + + /// Writes the elements of `self` to the first 4 elements in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than N elements long. + #[inline] + pub fn write_to_slice(self, slice: &mut [i32]) { + slice[0] = self.x; + slice[1] = self.y; + slice[2] = self.z; + slice[3] = self.w; + } + + /// Creates a 2D vector from the `x`, `y` and `z` elements of `self`, discarding `w`. + /// + /// Truncation to `IVec3` may also be performed by using `self.xyz()` or `IVec3::from()`. + #[inline] + pub fn truncate(self) -> IVec3 { + use crate::swizzles::Vec4Swizzles; + self.xyz() + } + + /// Computes the dot product of `self` and `rhs`. + #[inline] + pub fn dot(self, rhs: Self) -> i32 { + (self.x * rhs.x) + (self.y * rhs.y) + (self.z * rhs.z) + (self.w * rhs.w) + } + + /// Returns a vector containing the minimum values for each element of `self` and `rhs`. + /// + /// In other words this computes `[self.x.min(rhs.x), self.y.min(rhs.y), ..]`. + #[inline] + pub fn min(self, rhs: Self) -> Self { + Self { + x: self.x.min(rhs.x), + y: self.y.min(rhs.y), + z: self.z.min(rhs.z), + w: self.w.min(rhs.w), + } + } + + /// Returns a vector containing the maximum values for each element of `self` and `rhs`. + /// + /// In other words this computes `[self.x.max(rhs.x), self.y.max(rhs.y), ..]`. + #[inline] + pub fn max(self, rhs: Self) -> Self { + Self { + x: self.x.max(rhs.x), + y: self.y.max(rhs.y), + z: self.z.max(rhs.z), + w: self.w.max(rhs.w), + } + } + + /// Component-wise clamping of values, similar to [`f32::clamp`]. + /// + /// Each element in `min` must be less-or-equal to the corresponding element in `max`. + /// + /// # Panics + /// + /// Will panic if `min` is greater than `max` when `glam_assert` is enabled. + #[inline] + pub fn clamp(self, min: Self, max: Self) -> Self { + glam_assert!(min.cmple(max).all(), "clamp: expected min <= max"); + self.max(min).min(max) + } + + /// Returns the horizontal minimum of `self`. + /// + /// In other words this computes `min(x, y, ..)`. + #[inline] + pub fn min_element(self) -> i32 { + self.x.min(self.y.min(self.z.min(self.w))) + } + + /// Returns the horizontal maximum of `self`. + /// + /// In other words this computes `max(x, y, ..)`. + #[inline] + pub fn max_element(self) -> i32 { + self.x.max(self.y.max(self.z.max(self.w))) + } + + /// Returns a vector mask containing the result of a `==` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words, this computes `[self.x == rhs.x, self.y == rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpeq(self, rhs: Self) -> BVec4 { + BVec4::new( + self.x.eq(&rhs.x), + self.y.eq(&rhs.y), + self.z.eq(&rhs.z), + self.w.eq(&rhs.w), + ) + } + + /// Returns a vector mask containing the result of a `!=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x != rhs.x, self.y != rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpne(self, rhs: Self) -> BVec4 { + BVec4::new( + self.x.ne(&rhs.x), + self.y.ne(&rhs.y), + self.z.ne(&rhs.z), + self.w.ne(&rhs.w), + ) + } + + /// Returns a vector mask containing the result of a `>=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x >= rhs.x, self.y >= rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpge(self, rhs: Self) -> BVec4 { + BVec4::new( + self.x.ge(&rhs.x), + self.y.ge(&rhs.y), + self.z.ge(&rhs.z), + self.w.ge(&rhs.w), + ) + } + + /// Returns a vector mask containing the result of a `>` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x > rhs.x, self.y > rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpgt(self, rhs: Self) -> BVec4 { + BVec4::new( + self.x.gt(&rhs.x), + self.y.gt(&rhs.y), + self.z.gt(&rhs.z), + self.w.gt(&rhs.w), + ) + } + + /// Returns a vector mask containing the result of a `<=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x <= rhs.x, self.y <= rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmple(self, rhs: Self) -> BVec4 { + BVec4::new( + self.x.le(&rhs.x), + self.y.le(&rhs.y), + self.z.le(&rhs.z), + self.w.le(&rhs.w), + ) + } + + /// Returns a vector mask containing the result of a `<` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x < rhs.x, self.y < rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmplt(self, rhs: Self) -> BVec4 { + BVec4::new( + self.x.lt(&rhs.x), + self.y.lt(&rhs.y), + self.z.lt(&rhs.z), + self.w.lt(&rhs.w), + ) + } + + /// Returns a vector containing the absolute value of each element of `self`. + #[inline] + pub fn abs(self) -> Self { + Self { + x: self.x.abs(), + y: self.y.abs(), + z: self.z.abs(), + w: self.w.abs(), + } + } + + /// Returns a vector with elements representing the sign of `self`. + /// + /// - `1.0` if the number is positive, `+0.0` or `INFINITY` + /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` + /// - `NAN` if the number is `NAN` + #[inline] + pub fn signum(self) -> Self { + Self { + x: self.x.signum(), + y: self.y.signum(), + z: self.z.signum(), + w: self.w.signum(), + } + } + + /// Casts all elements of `self` to `f32`. + #[inline] + pub fn as_vec4(&self) -> crate::Vec4 { + crate::Vec4::new(self.x as f32, self.y as f32, self.z as f32, self.w as f32) + } + + /// Casts all elements of `self` to `f64`. + #[inline] + pub fn as_dvec4(&self) -> crate::DVec4 { + crate::DVec4::new(self.x as f64, self.y as f64, self.z as f64, self.w as f64) + } + + /// Casts all elements of `self` to `u32`. + #[inline] + pub fn as_uvec4(&self) -> crate::UVec4 { + crate::UVec4::new(self.x as u32, self.y as u32, self.z as u32, self.w as u32) + } +} + +impl Default for IVec4 { + #[inline(always)] + fn default() -> Self { + Self::ZERO + } +} + +impl PartialEq for IVec4 { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.cmpeq(*rhs).all() + } +} + +impl Div for IVec4 { + type Output = Self; + #[inline] + fn div(self, rhs: Self) -> Self { + Self { + x: self.x.div(rhs.x), + y: self.y.div(rhs.y), + z: self.z.div(rhs.z), + w: self.w.div(rhs.w), + } + } +} + +impl DivAssign for IVec4 { + #[inline] + fn div_assign(&mut self, rhs: Self) { + self.x.div_assign(rhs.x); + self.y.div_assign(rhs.y); + self.z.div_assign(rhs.z); + self.w.div_assign(rhs.w); + } +} + +impl Div for IVec4 { + type Output = Self; + #[inline] + fn div(self, rhs: i32) -> Self { + Self { + x: self.x.div(rhs), + y: self.y.div(rhs), + z: self.z.div(rhs), + w: self.w.div(rhs), + } + } +} + +impl DivAssign for IVec4 { + #[inline] + fn div_assign(&mut self, rhs: i32) { + self.x.div_assign(rhs); + self.y.div_assign(rhs); + self.z.div_assign(rhs); + self.w.div_assign(rhs); + } +} + +impl Div for i32 { + type Output = IVec4; + #[inline] + fn div(self, rhs: IVec4) -> IVec4 { + IVec4 { + x: self.div(rhs.x), + y: self.div(rhs.y), + z: self.div(rhs.z), + w: self.div(rhs.w), + } + } +} + +impl Mul for IVec4 { + type Output = Self; + #[inline] + fn mul(self, rhs: Self) -> Self { + Self { + x: self.x.mul(rhs.x), + y: self.y.mul(rhs.y), + z: self.z.mul(rhs.z), + w: self.w.mul(rhs.w), + } + } +} + +impl MulAssign for IVec4 { + #[inline] + fn mul_assign(&mut self, rhs: Self) { + self.x.mul_assign(rhs.x); + self.y.mul_assign(rhs.y); + self.z.mul_assign(rhs.z); + self.w.mul_assign(rhs.w); + } +} + +impl Mul for IVec4 { + type Output = Self; + #[inline] + fn mul(self, rhs: i32) -> Self { + Self { + x: self.x.mul(rhs), + y: self.y.mul(rhs), + z: self.z.mul(rhs), + w: self.w.mul(rhs), + } + } +} + +impl MulAssign for IVec4 { + #[inline] + fn mul_assign(&mut self, rhs: i32) { + self.x.mul_assign(rhs); + self.y.mul_assign(rhs); + self.z.mul_assign(rhs); + self.w.mul_assign(rhs); + } +} + +impl Mul for i32 { + type Output = IVec4; + #[inline] + fn mul(self, rhs: IVec4) -> IVec4 { + IVec4 { + x: self.mul(rhs.x), + y: self.mul(rhs.y), + z: self.mul(rhs.z), + w: self.mul(rhs.w), + } + } +} + +impl Add for IVec4 { + type Output = Self; + #[inline] + fn add(self, rhs: Self) -> Self { + Self { + x: self.x.add(rhs.x), + y: self.y.add(rhs.y), + z: self.z.add(rhs.z), + w: self.w.add(rhs.w), + } + } +} + +impl AddAssign for IVec4 { + #[inline] + fn add_assign(&mut self, rhs: Self) { + self.x.add_assign(rhs.x); + self.y.add_assign(rhs.y); + self.z.add_assign(rhs.z); + self.w.add_assign(rhs.w); + } +} + +impl Add for IVec4 { + type Output = Self; + #[inline] + fn add(self, rhs: i32) -> Self { + Self { + x: self.x.add(rhs), + y: self.y.add(rhs), + z: self.z.add(rhs), + w: self.w.add(rhs), + } + } +} + +impl AddAssign for IVec4 { + #[inline] + fn add_assign(&mut self, rhs: i32) { + self.x.add_assign(rhs); + self.y.add_assign(rhs); + self.z.add_assign(rhs); + self.w.add_assign(rhs); + } +} + +impl Add for i32 { + type Output = IVec4; + #[inline] + fn add(self, rhs: IVec4) -> IVec4 { + IVec4 { + x: self.add(rhs.x), + y: self.add(rhs.y), + z: self.add(rhs.z), + w: self.add(rhs.w), + } + } +} + +impl Sub for IVec4 { + type Output = Self; + #[inline] + fn sub(self, rhs: Self) -> Self { + Self { + x: self.x.sub(rhs.x), + y: self.y.sub(rhs.y), + z: self.z.sub(rhs.z), + w: self.w.sub(rhs.w), + } + } +} + +impl SubAssign for IVec4 { + #[inline] + fn sub_assign(&mut self, rhs: IVec4) { + self.x.sub_assign(rhs.x); + self.y.sub_assign(rhs.y); + self.z.sub_assign(rhs.z); + self.w.sub_assign(rhs.w); + } +} + +impl Sub for IVec4 { + type Output = Self; + #[inline] + fn sub(self, rhs: i32) -> Self { + Self { + x: self.x.sub(rhs), + y: self.y.sub(rhs), + z: self.z.sub(rhs), + w: self.w.sub(rhs), + } + } +} + +impl SubAssign for IVec4 { + #[inline] + fn sub_assign(&mut self, rhs: i32) { + self.x.sub_assign(rhs); + self.y.sub_assign(rhs); + self.z.sub_assign(rhs); + self.w.sub_assign(rhs); + } +} + +impl Sub for i32 { + type Output = IVec4; + #[inline] + fn sub(self, rhs: IVec4) -> IVec4 { + IVec4 { + x: self.sub(rhs.x), + y: self.sub(rhs.y), + z: self.sub(rhs.z), + w: self.sub(rhs.w), + } + } +} + +impl Rem for IVec4 { + type Output = Self; + #[inline] + fn rem(self, rhs: Self) -> Self { + Self { + x: self.x.rem(rhs.x), + y: self.y.rem(rhs.y), + z: self.z.rem(rhs.z), + w: self.w.rem(rhs.w), + } + } +} + +impl RemAssign for IVec4 { + #[inline] + fn rem_assign(&mut self, rhs: Self) { + self.x.rem_assign(rhs.x); + self.y.rem_assign(rhs.y); + self.z.rem_assign(rhs.z); + self.w.rem_assign(rhs.w); + } +} + +impl Rem for IVec4 { + type Output = Self; + #[inline] + fn rem(self, rhs: i32) -> Self { + Self { + x: self.x.rem(rhs), + y: self.y.rem(rhs), + z: self.z.rem(rhs), + w: self.w.rem(rhs), + } + } +} + +impl RemAssign for IVec4 { + #[inline] + fn rem_assign(&mut self, rhs: i32) { + self.x.rem_assign(rhs); + self.y.rem_assign(rhs); + self.z.rem_assign(rhs); + self.w.rem_assign(rhs); + } +} + +impl Rem for i32 { + type Output = IVec4; + #[inline] + fn rem(self, rhs: IVec4) -> IVec4 { + IVec4 { + x: self.rem(rhs.x), + y: self.rem(rhs.y), + z: self.rem(rhs.z), + w: self.rem(rhs.w), + } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsRef<[i32; 4]> for IVec4 { + #[inline] + fn as_ref(&self) -> &[i32; 4] { + unsafe { &*(self as *const IVec4 as *const [i32; 4]) } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsMut<[i32; 4]> for IVec4 { + #[inline] + fn as_mut(&mut self) -> &mut [i32; 4] { + unsafe { &mut *(self as *mut IVec4 as *mut [i32; 4]) } + } +} + +impl<'a> Sum<&'a Self> for IVec4 { + #[inline] + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, |a, &b| Self::add(a, b)) + } +} + +impl<'a> Product<&'a Self> for IVec4 { + #[inline] + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ONE, |a, &b| Self::mul(a, b)) + } +} + +impl Neg for IVec4 { + type Output = Self; + #[inline] + fn neg(self) -> Self { + Self { + x: self.x.neg(), + y: self.y.neg(), + z: self.z.neg(), + w: self.w.neg(), + } + } +} + +impl Eq for IVec4 {} + +#[cfg(not(target_arch = "spirv"))] +impl core::hash::Hash for IVec4 { + fn hash(&self, state: &mut H) { + let inner: &[i32; 4] = self.as_ref(); + inner.hash(state); + } +} + +impl Not for IVec4 { + type Output = Self; + #[inline] + fn not(self) -> Self::Output { + Self { + x: self.x.not(), + y: self.y.not(), + z: self.z.not(), + w: self.w.not(), + } + } +} + +impl BitAnd for IVec4 { + type Output = Self; + #[inline] + fn bitand(self, rhs: Self) -> Self::Output { + Self { + x: self.x.bitand(rhs.x), + y: self.y.bitand(rhs.y), + z: self.z.bitand(rhs.z), + w: self.w.bitand(rhs.w), + } + } +} + +impl BitOr for IVec4 { + type Output = Self; + #[inline] + fn bitor(self, rhs: Self) -> Self::Output { + Self { + x: self.x.bitor(rhs.x), + y: self.y.bitor(rhs.y), + z: self.z.bitor(rhs.z), + w: self.w.bitor(rhs.w), + } + } +} + +impl BitXor for IVec4 { + type Output = Self; + #[inline] + fn bitxor(self, rhs: Self) -> Self::Output { + Self { + x: self.x.bitxor(rhs.x), + y: self.y.bitxor(rhs.y), + z: self.z.bitxor(rhs.z), + w: self.w.bitxor(rhs.w), + } + } +} + +impl BitAnd for IVec4 { + type Output = Self; + #[inline] + fn bitand(self, rhs: i32) -> Self::Output { + Self { + x: self.x.bitand(rhs), + y: self.y.bitand(rhs), + z: self.z.bitand(rhs), + w: self.w.bitand(rhs), + } + } +} + +impl BitOr for IVec4 { + type Output = Self; + #[inline] + fn bitor(self, rhs: i32) -> Self::Output { + Self { + x: self.x.bitor(rhs), + y: self.y.bitor(rhs), + z: self.z.bitor(rhs), + w: self.w.bitor(rhs), + } + } +} + +impl BitXor for IVec4 { + type Output = Self; + #[inline] + fn bitxor(self, rhs: i32) -> Self::Output { + Self { + x: self.x.bitxor(rhs), + y: self.y.bitxor(rhs), + z: self.z.bitxor(rhs), + w: self.w.bitxor(rhs), + } + } +} + +impl Shl for IVec4 { + type Output = Self; + #[inline] + fn shl(self, rhs: i8) -> Self::Output { + Self { + x: self.x.shl(rhs), + y: self.y.shl(rhs), + z: self.z.shl(rhs), + w: self.w.shl(rhs), + } + } +} + +impl Shr for IVec4 { + type Output = Self; + #[inline] + fn shr(self, rhs: i8) -> Self::Output { + Self { + x: self.x.shr(rhs), + y: self.y.shr(rhs), + z: self.z.shr(rhs), + w: self.w.shr(rhs), + } + } +} + +impl Shl for IVec4 { + type Output = Self; + #[inline] + fn shl(self, rhs: i16) -> Self::Output { + Self { + x: self.x.shl(rhs), + y: self.y.shl(rhs), + z: self.z.shl(rhs), + w: self.w.shl(rhs), + } + } +} + +impl Shr for IVec4 { + type Output = Self; + #[inline] + fn shr(self, rhs: i16) -> Self::Output { + Self { + x: self.x.shr(rhs), + y: self.y.shr(rhs), + z: self.z.shr(rhs), + w: self.w.shr(rhs), + } + } +} + +impl Shl for IVec4 { + type Output = Self; + #[inline] + fn shl(self, rhs: i32) -> Self::Output { + Self { + x: self.x.shl(rhs), + y: self.y.shl(rhs), + z: self.z.shl(rhs), + w: self.w.shl(rhs), + } + } +} + +impl Shr for IVec4 { + type Output = Self; + #[inline] + fn shr(self, rhs: i32) -> Self::Output { + Self { + x: self.x.shr(rhs), + y: self.y.shr(rhs), + z: self.z.shr(rhs), + w: self.w.shr(rhs), + } + } +} + +impl Shl for IVec4 { + type Output = Self; + #[inline] + fn shl(self, rhs: u8) -> Self::Output { + Self { + x: self.x.shl(rhs), + y: self.y.shl(rhs), + z: self.z.shl(rhs), + w: self.w.shl(rhs), + } + } +} + +impl Shr for IVec4 { + type Output = Self; + #[inline] + fn shr(self, rhs: u8) -> Self::Output { + Self { + x: self.x.shr(rhs), + y: self.y.shr(rhs), + z: self.z.shr(rhs), + w: self.w.shr(rhs), + } + } +} + +impl Shl for IVec4 { + type Output = Self; + #[inline] + fn shl(self, rhs: u16) -> Self::Output { + Self { + x: self.x.shl(rhs), + y: self.y.shl(rhs), + z: self.z.shl(rhs), + w: self.w.shl(rhs), + } + } +} + +impl Shr for IVec4 { + type Output = Self; + #[inline] + fn shr(self, rhs: u16) -> Self::Output { + Self { + x: self.x.shr(rhs), + y: self.y.shr(rhs), + z: self.z.shr(rhs), + w: self.w.shr(rhs), + } + } +} + +impl Shl for IVec4 { + type Output = Self; + #[inline] + fn shl(self, rhs: u32) -> Self::Output { + Self { + x: self.x.shl(rhs), + y: self.y.shl(rhs), + z: self.z.shl(rhs), + w: self.w.shl(rhs), + } + } +} + +impl Shr for IVec4 { + type Output = Self; + #[inline] + fn shr(self, rhs: u32) -> Self::Output { + Self { + x: self.x.shr(rhs), + y: self.y.shr(rhs), + z: self.z.shr(rhs), + w: self.w.shr(rhs), + } + } +} + +impl Shl for IVec4 { + type Output = Self; + #[inline] + fn shl(self, rhs: crate::IVec4) -> Self::Output { + Self { + x: self.x.shl(rhs.x), + y: self.y.shl(rhs.y), + z: self.z.shl(rhs.z), + w: self.w.shl(rhs.w), + } + } +} + +impl Shr for IVec4 { + type Output = Self; + #[inline] + fn shr(self, rhs: crate::IVec4) -> Self::Output { + Self { + x: self.x.shr(rhs.x), + y: self.y.shr(rhs.y), + z: self.z.shr(rhs.z), + w: self.w.shr(rhs.w), + } + } +} + +impl Shl for IVec4 { + type Output = Self; + #[inline] + fn shl(self, rhs: crate::UVec4) -> Self::Output { + Self { + x: self.x.shl(rhs.x), + y: self.y.shl(rhs.y), + z: self.z.shl(rhs.z), + w: self.w.shl(rhs.w), + } + } +} + +impl Shr for IVec4 { + type Output = Self; + #[inline] + fn shr(self, rhs: crate::UVec4) -> Self::Output { + Self { + x: self.x.shr(rhs.x), + y: self.y.shr(rhs.y), + z: self.z.shr(rhs.z), + w: self.w.shr(rhs.w), + } + } +} + +impl Index for IVec4 { + type Output = i32; + #[inline] + fn index(&self, index: usize) -> &Self::Output { + match index { + 0 => &self.x, + 1 => &self.y, + 2 => &self.z, + 3 => &self.w, + _ => panic!("index out of bounds"), + } + } +} + +impl IndexMut for IVec4 { + #[inline] + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + match index { + 0 => &mut self.x, + 1 => &mut self.y, + 2 => &mut self.z, + 3 => &mut self.w, + _ => panic!("index out of bounds"), + } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Display for IVec4 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "[{}, {}, {}, {}]", self.x, self.y, self.z, self.w) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Debug for IVec4 { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_tuple(stringify!(IVec4)) + .field(&self.x) + .field(&self.y) + .field(&self.z) + .field(&self.w) + .finish() + } +} + +impl From<[i32; 4]> for IVec4 { + #[inline] + fn from(a: [i32; 4]) -> Self { + Self::new(a[0], a[1], a[2], a[3]) + } +} + +impl From for [i32; 4] { + #[inline] + fn from(v: IVec4) -> Self { + [v.x, v.y, v.z, v.w] + } +} + +impl From<(i32, i32, i32, i32)> for IVec4 { + #[inline] + fn from(t: (i32, i32, i32, i32)) -> Self { + Self::new(t.0, t.1, t.2, t.3) + } +} + +impl From for (i32, i32, i32, i32) { + #[inline] + fn from(v: IVec4) -> Self { + (v.x, v.y, v.z, v.w) + } +} + +impl From<(IVec3, i32)> for IVec4 { + #[inline] + fn from((v, w): (IVec3, i32)) -> Self { + Self::new(v.x, v.y, v.z, w) + } +} + +impl From<(i32, IVec3)> for IVec4 { + #[inline] + fn from((x, v): (i32, IVec3)) -> Self { + Self::new(x, v.x, v.y, v.z) + } +} + +impl From<(IVec2, i32, i32)> for IVec4 { + #[inline] + fn from((v, z, w): (IVec2, i32, i32)) -> Self { + Self::new(v.x, v.y, z, w) + } +} + +impl From<(IVec2, IVec2)> for IVec4 { + #[inline] + fn from((v, u): (IVec2, IVec2)) -> Self { + Self::new(v.x, v.y, u.x, u.y) + } +} diff --git a/src/lib.rs b/src/lib.rs index 336f7b58..620daa09 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -229,7 +229,7 @@ and benchmarks. ## Minimum Supported Rust Version (MSRV) -The minimum supported Rust version is `1.52.1`. +The minimum supported Rust version is `1.58.1`. */ #![doc(html_root_url = "https://docs.rs/glam/0.20.5")] @@ -249,95 +249,51 @@ The minimum supported Rust version is `1.52.1`. #[macro_use] mod macros; -#[macro_use] -mod mat; - -#[macro_use] -mod vec; - #[doc(hidden)] pub mod cast; -mod affine2; -mod affine3; -mod core; +mod align16; +mod deref; mod euler; mod features; -mod mat2; -mod mat3; -mod mat4; -mod quat; -mod vec2; -mod vec3; -mod vec4; -mod vec_mask; +mod float_ex; #[cfg(target_arch = "spirv")] mod spirv; -#[cfg(feature = "transform-types")] -mod transform; +#[cfg(all(target_feature = "sse2", not(feature = "scalar-math")))] +mod sse2; -#[doc(hidden)] -pub use self::core::storage::{XY, XYZ, XYZW}; +#[cfg(all(target_feature = "sse2", not(feature = "scalar-math")))] +use align16::Align16; + +#[cfg(all(target_feature = "simd128", not(feature = "scalar-math")))] +mod wasm32; + +use float_ex::FloatEx; /** `bool` vector mask types. */ -pub mod bool { - pub use super::vec_mask::{BVec2, BVec3, BVec3A, BVec4, BVec4A}; -} +pub mod bool; pub use self::bool::*; /** `f32` vector, quaternion and matrix types. */ -pub mod f32 { - pub use super::affine2::Affine2; - pub use super::affine3::Affine3A; - pub use super::mat2::{mat2, Mat2}; - pub use super::mat3::{mat3, mat3a, Mat3, Mat3A}; - pub use super::mat4::{mat4, Mat4}; - pub use super::quat::{quat, Quat}; - pub use super::vec2::{vec2, Vec2}; - pub use super::vec3::{vec3, vec3a, Vec3, Vec3A}; - pub use super::vec4::{vec4, Vec4}; - - #[cfg(feature = "transform-types")] - #[allow(deprecated)] - pub use super::transform::{TransformRT, TransformSRT}; -} +pub mod f32; pub use self::f32::*; /** `f64` vector, quaternion and matrix types. */ -pub mod f64 { - pub use super::affine2::DAffine2; - pub use super::affine3::DAffine3; - pub use super::mat2::{dmat2, DMat2}; - pub use super::mat3::{dmat3, DMat3}; - pub use super::mat4::{dmat4, DMat4}; - pub use super::quat::{dquat, DQuat}; - pub use super::vec2::{dvec2, DVec2}; - pub use super::vec3::{dvec3, DVec3}; - pub use super::vec4::{dvec4, DVec4}; -} +pub mod f64; pub use self::f64::*; /** `i32` vector types. */ -pub mod i32 { - pub use super::vec2::{ivec2, IVec2}; - pub use super::vec3::{ivec3, IVec3}; - pub use super::vec4::{ivec4, IVec4}; -} +pub mod i32; pub use self::i32::*; /** `u32` vector types. */ -pub mod u32 { - pub use super::vec2::{uvec2, UVec2}; - pub use super::vec3::{uvec3, UVec3}; - pub use super::vec4::{uvec4, UVec4}; -} +pub mod u32; pub use self::u32::*; /** Traits adding swizzle methods to all vector types. */ pub mod swizzles; - pub use self::swizzles::{Vec2Swizzles, Vec3Swizzles, Vec4Swizzles}; /** Rotation Helper */ diff --git a/src/macros.rs b/src/macros.rs index b2d7954c..3c8e4222 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -18,10 +18,7 @@ macro_rules! const_assert { // FIXME: everything is align 16 on spirv - ignore for now #[cfg(not(target_arch = "spirv"))] #[allow(unknown_lints, clippy::eq_op)] - const _: [(); 0 - !{ - const ASSERT: bool = $x; - ASSERT - } as usize] = []; + const _: () = assert!($x); }; } @@ -63,11 +60,11 @@ macro_rules! const_f32x4 { /// const ONE: Vec2 = const_vec2!([1.0; 2]); /// const X: Vec2 = const_vec2!([1.0, 0.0]); /// ``` +#[deprecated(since = "0.21.0", note = "use Vec2::from_array() instead.")] #[macro_export] macro_rules! const_vec2 { ($fx2:expr) => {{ - let fx2 = $fx2; - unsafe { $crate::cast::Vec2Cast { fx2 }.v2 } + Vec2::from_array($fx2) }}; } @@ -78,11 +75,11 @@ macro_rules! const_vec2 { /// const ONE: Vec3 = const_vec3!([1.0; 3]); /// const X: Vec3 = const_vec3!([1.0, 0.0, 0.0]); /// ``` +#[deprecated(since = "0.21.0", note = "use Vec3::from_array() instead.")] #[macro_export] macro_rules! const_vec3 { ($fx3:expr) => {{ - let fx3 = $fx3; - unsafe { $crate::cast::Vec3Cast { fx3 }.v3 } + Vec3::from_array($fx3) }}; } @@ -93,16 +90,11 @@ macro_rules! const_vec3 { /// const ONE: Vec3A = const_vec3a!([1.0; 3]); /// const X: Vec3A = const_vec3a!([1.0, 0.0, 0.0]); /// ``` +#[deprecated(since = "0.21.0", note = "use Vec3A::from_array() instead.")] #[macro_export] macro_rules! const_vec3a { ($fx3:expr) => {{ - let fx3 = $fx3; - unsafe { - $crate::cast::Vec4Cast { - fx4: [fx3[0], fx3[1], fx3[2], 0.0], - } - .v3a - } + Vec3A::from_array($fx3) }}; } @@ -113,11 +105,11 @@ macro_rules! const_vec3a { /// const ONE: Vec4 = const_vec4!([1.0; 4]); /// const X: Vec4 = const_vec4!([1.0, 0.0, 0.0, 0.0]); /// ``` +#[deprecated(since = "0.21.0", note = "use Vec4::from_array() instead.")] #[macro_export] macro_rules! const_vec4 { ($fx4:expr) => {{ - let fx4 = $fx4; - unsafe { $crate::cast::Vec4Cast { fx4 }.v4 } + Vec4::from_array($fx4) }}; } @@ -128,26 +120,17 @@ macro_rules! const_vec4 { /// const ZERO: Mat2 = const_mat2!([0.0; 4]); /// const IDENTITY: Mat2 = const_mat2!([1.0, 0.0], [0.0, 1.0]); /// ``` +#[deprecated( + since = "0.21.0", + note = "use Mat2::from_cols(), Mat2::from_cols_array() or Mat2::from_cols_array_2d() instead." +)] #[macro_export] macro_rules! const_mat2 { ($col0:expr, $col1:expr) => {{ - let col0 = $col0; - let col1 = $col1; - unsafe { - $crate::cast::Mat2Cast { - v2x2: [$crate::const_vec2!(col0), $crate::const_vec2!(col1)], - } - .m2 - } + Mat2::from_cols_array_2d(&[$col0, $col1]) }}; ($fx4:expr) => {{ - let fx4 = $fx4; - unsafe { - $crate::const_mat2!( - $crate::cast::Vec4Cast { fx4 }.fx2x2[0], - $crate::cast::Vec4Cast { fx4 }.fx2x2[1] - ) - } + Mat2::from_cols_array(&$fx4) }}; } @@ -158,32 +141,17 @@ macro_rules! const_mat2 { /// const ZERO: Mat3 = const_mat3!([0.0; 9]); /// const IDENTITY: Mat3 = const_mat3!([1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]); /// ``` +#[deprecated( + since = "0.21.0", + note = "use Mat3::from_cols(), Mat3::from_cols_array() or Mat3::from_cols_array_2d() instead." +)] #[macro_export] macro_rules! const_mat3 { ($col0:expr, $col1:expr, $col2:expr) => {{ - let col0 = $col0; - let col1 = $col1; - let col2 = $col2; - unsafe { - $crate::cast::Mat3Cast { - v3x3: [ - $crate::const_vec3!(col0), - $crate::const_vec3!(col1), - $crate::const_vec3!(col2), - ], - } - .m3 - } + Mat3::from_cols_array_2d(&[$col0, $col1, $col2]) }}; ($fx9:expr) => {{ - let fx9 = $fx9; - unsafe { - $crate::const_mat3!( - $crate::cast::F32x9Cast { fx9 }.fx3x3[0], - $crate::cast::F32x9Cast { fx9 }.fx3x3[1], - $crate::cast::F32x9Cast { fx9 }.fx3x3[2] - ) - } + Mat3::from_cols_array(&$fx9) }}; } @@ -194,32 +162,17 @@ macro_rules! const_mat3 { /// const ZERO: Mat3A = const_mat3a!([0.0; 9]); /// const IDENTITY: Mat3A = const_mat3a!([1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]); /// ``` +#[deprecated( + since = "0.21.0", + note = "use Mat3A::from_cols(), Mat3A::from_cols_array() or Mat3A::from_cols_array_2d() instead." +)] #[macro_export] macro_rules! const_mat3a { ($col0:expr, $col1:expr, $col2:expr) => {{ - let col0 = $col0; - let col1 = $col1; - let col2 = $col2; - unsafe { - $crate::cast::Mat3ACast { - v3x3: [ - $crate::const_vec3a!(col0), - $crate::const_vec3a!(col1), - $crate::const_vec3a!(col2), - ], - } - .m3 - } + Mat3A::from_cols_array_2d(&[$col0, $col1, $col2]) }}; ($fx9:expr) => {{ - let fx9 = $fx9; - unsafe { - $crate::const_mat3a!( - $crate::cast::F32x9Cast { fx9 }.fx3x3[0], - $crate::cast::F32x9Cast { fx9 }.fx3x3[1], - $crate::cast::F32x9Cast { fx9 }.fx3x3[2] - ) - } + Mat3A::from_cols_array(&$fx9) }}; } @@ -235,35 +188,17 @@ macro_rules! const_mat3a { /// [0.0, 0.0, 0.0, 1.0] /// ); /// ``` +#[deprecated( + since = "0.21.0", + note = "use Mat4::from_cols(), Mat4::from_cols_array() or Mat4::from_cols_array_2d() instead." +)] #[macro_export] macro_rules! const_mat4 { ($col0:expr, $col1:expr, $col2:expr, $col3:expr) => {{ - let col0 = $col0; - let col1 = $col1; - let col2 = $col2; - let col3 = $col3; - unsafe { - $crate::cast::Mat4Cast { - v4x4: [ - $crate::const_vec4!(col0), - $crate::const_vec4!(col1), - $crate::const_vec4!(col2), - $crate::const_vec4!(col3), - ], - } - .m4 - } + Mat4::from_cols_array_2d(&[$col0, $col1, $col2, $col3]) }}; ($fx16:expr) => {{ - let fx16 = $fx16; - unsafe { - $crate::const_mat4!( - $crate::cast::F32x16Cast { fx16 }.fx4x4[0], - $crate::cast::F32x16Cast { fx16 }.fx4x4[1], - $crate::cast::F32x16Cast { fx16 }.fx4x4[2], - $crate::cast::F32x16Cast { fx16 }.fx4x4[3] - ) - } + Mat4::from_cols_array(&$fx16) }}; } @@ -274,11 +209,14 @@ macro_rules! const_mat4 { /// use glam::{const_quat, Quat}; /// const IDENTITY: Quat = const_quat!([0.0, 0.0, 0.0, 1.0]); /// ``` +#[deprecated( + since = "0.21.0", + note = "use Quat::from_xyzw() or Quat::from_array() instead." +)] #[macro_export] macro_rules! const_quat { ($fx4:expr) => {{ - let fx4 = $fx4; - unsafe { $crate::cast::Vec4Cast { fx4 }.q } + Quat::from_array($fx4) }}; } @@ -289,11 +227,11 @@ macro_rules! const_quat { /// const ONE: DVec2 = const_dvec2!([1.0; 2]); /// const X: DVec2 = const_dvec2!([1.0, 0.0]); /// ``` +#[deprecated(since = "0.21.0", note = "use DVec2::from_array() instead.")] #[macro_export] macro_rules! const_dvec2 { ($fx2:expr) => {{ - let fx2 = $fx2; - unsafe { $crate::cast::DVec2Cast { fx2 }.v2 } + DVec2::from_array($fx2) }}; } @@ -304,11 +242,11 @@ macro_rules! const_dvec2 { /// const ONE: DVec3 = const_dvec3!([1.0; 3]); /// const X: DVec3 = const_dvec3!([1.0, 0.0, 0.0]); /// ``` +#[deprecated(since = "0.21.0", note = "use DVec3::from_array() instead.")] #[macro_export] macro_rules! const_dvec3 { ($fx3:expr) => {{ - let fx3 = $fx3; - unsafe { $crate::cast::DVec3Cast { fx3 }.v3 } + DVec3::from_array($fx3) }}; } @@ -319,11 +257,11 @@ macro_rules! const_dvec3 { /// const ONE: DVec4 = const_dvec4!([1.0; 4]); /// const X: DVec4 = const_dvec4!([1.0, 0.0, 0.0, 0.0]); /// ``` +#[deprecated(since = "0.21.0", note = "use DVec4::from_array() instead.")] #[macro_export] macro_rules! const_dvec4 { ($fx4:expr) => {{ - let fx4 = $fx4; - unsafe { $crate::cast::DVec4Cast { fx4 }.v4 } + DVec4::from_array($fx4) }}; } @@ -334,26 +272,17 @@ macro_rules! const_dvec4 { /// const ZERO: DMat2 = const_dmat2!([0.0; 4]); /// const IDENTITY: DMat2 = const_dmat2!([1.0, 0.0], [0.0, 1.0]); /// ``` +#[deprecated( + since = "0.21.0", + note = "use DMat2::from_cols(), DMat2::from_cols_array() or DMat2::from_cols_array_2d() instead." +)] #[macro_export] macro_rules! const_dmat2 { ($col0:expr, $col1:expr) => {{ - let col0 = $col0; - let col1 = $col1; - unsafe { - $crate::cast::DMat2Cast { - v2x2: [$crate::const_dvec2!(col0), $crate::const_dvec2!(col1)], - } - .m2 - } + DMat2::from_cols_array_2d(&[$col0, $col1]) }}; ($fx4:expr) => {{ - let fx4 = $fx4; - unsafe { - $crate::const_dmat2!( - $crate::cast::DVec4Cast { fx4 }.fx2x2[0], - $crate::cast::DVec4Cast { fx4 }.fx2x2[1] - ) - } + DMat2::from_cols_array(&$fx4) }}; } @@ -365,32 +294,17 @@ macro_rules! const_dmat2 { /// const ZERO: DMat3 = const_dmat3!([0.0; 9]); /// const IDENTITY: DMat3 = const_dmat3!([1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]); /// ``` +#[deprecated( + since = "0.21.0", + note = "use DMat3::from_cols(), DMat3::from_cols_array() or DMat3::from_cols_array_2d() instead." +)] #[macro_export] macro_rules! const_dmat3 { ($col0:expr, $col1:expr, $col2:expr) => {{ - let col0 = $col0; - let col1 = $col1; - let col2 = $col2; - unsafe { - $crate::cast::DMat3Cast { - v3x3: [ - $crate::const_dvec3!(col0), - $crate::const_dvec3!(col1), - $crate::const_dvec3!(col2), - ], - } - .m3 - } + DMat3::from_cols_array_2d(&[$col0, $col1, $col2]) }}; ($fx9:expr) => {{ - let fx9 = $fx9; - unsafe { - $crate::const_dmat3!( - $crate::cast::F64x9Cast { fx9 }.fx3x3[0], - $crate::cast::F64x9Cast { fx9 }.fx3x3[1], - $crate::cast::F64x9Cast { fx9 }.fx3x3[2] - ) - } + DMat3::from_cols_array(&$fx9) }}; } @@ -406,35 +320,17 @@ macro_rules! const_dmat3 { /// [0.0, 0.0, 0.0, 1.0] /// ); /// ``` +#[deprecated( + since = "0.21.0", + note = "use DMat4::from_cols(), DMat4::from_cols_array() or DMat4::from_cols_array_2d() instead." +)] #[macro_export] macro_rules! const_dmat4 { ($col0:expr, $col1:expr, $col2:expr, $col3:expr) => {{ - let col0 = $col0; - let col1 = $col1; - let col2 = $col2; - let col3 = $col3; - unsafe { - $crate::cast::DMat4Cast { - v4x4: [ - $crate::const_dvec4!(col0), - $crate::const_dvec4!(col1), - $crate::const_dvec4!(col2), - $crate::const_dvec4!(col3), - ], - } - .m4 - } + DMat4::from_cols_array_2d(&[$col0, $col1, $col2, $col3]) }}; ($fx16:expr) => {{ - let fx16 = $fx16; - unsafe { - $crate::const_dmat4!( - $crate::cast::F64x16Cast { fx16 }.fx4x4[0], - $crate::cast::F64x16Cast { fx16 }.fx4x4[1], - $crate::cast::F64x16Cast { fx16 }.fx4x4[2], - $crate::cast::F64x16Cast { fx16 }.fx4x4[3] - ) - } + DMat4::from_cols_array(&$fx16) }}; } @@ -445,11 +341,14 @@ macro_rules! const_dmat4 { /// use glam::{const_dquat, DQuat}; /// const IDENTITY: DQuat = const_dquat!([0.0, 0.0, 0.0, 1.0]); /// ``` +#[deprecated( + since = "0.21.0", + note = "use DQuat::from_xyzw() or DQuat::from_array() instead." +)] #[macro_export] macro_rules! const_dquat { ($fx4:expr) => {{ - let fx4 = $fx4; - unsafe { $crate::cast::DVec4Cast { fx4 }.q } + DQuat::from_array($fx4) }}; } @@ -460,11 +359,11 @@ macro_rules! const_dquat { /// const ONE: IVec2 = const_ivec2!([1; 2]); /// const X: IVec2 = const_ivec2!([1, 0]); /// ``` +#[deprecated(since = "0.21.0", note = "use IVec2::from_array() instead.")] #[macro_export] macro_rules! const_ivec2 { ($ix2:expr) => {{ - let ix2 = $ix2; - unsafe { $crate::cast::IVec2Cast { ix2 }.v2 } + IVec2::from_array($ix2) }}; } @@ -475,11 +374,11 @@ macro_rules! const_ivec2 { /// const ONE: IVec3 = const_ivec3!([1; 3]); /// const X: IVec3 = const_ivec3!([1, 0, 0]); /// ``` +#[deprecated(since = "0.21.0", note = "use IVec3::from_array() instead.")] #[macro_export] macro_rules! const_ivec3 { ($ix3:expr) => {{ - let ix3 = $ix3; - unsafe { $crate::cast::IVec3Cast { ix3 }.v3 } + IVec3::from_array($ix3) }}; } @@ -490,11 +389,11 @@ macro_rules! const_ivec3 { /// const ONE: IVec4 = const_ivec4!([1; 4]); /// const X: IVec4 = const_ivec4!([1, 0, 0, 0]); /// ``` +#[deprecated(since = "0.21.0", note = "use IVec4::from_array() instead.")] #[macro_export] macro_rules! const_ivec4 { ($ix4:expr) => {{ - let ix4 = $ix4; - unsafe { $crate::cast::IVec4Cast { ix4 }.v4 } + IVec4::from_array($ix4) }}; } @@ -505,11 +404,11 @@ macro_rules! const_ivec4 { /// const ONE: UVec2 = const_uvec2!([1; 2]); /// const X: UVec2 = const_uvec2!([1, 0]); /// ``` +#[deprecated(since = "0.21.0", note = "use UVec2::from_array() instead.")] #[macro_export] macro_rules! const_uvec2 { ($ux2:expr) => {{ - let ux2 = $ux2; - unsafe { $crate::cast::UVec2Cast { ux2 }.v2 } + UVec2::from_array($ux2) }}; } @@ -520,11 +419,11 @@ macro_rules! const_uvec2 { /// const ONE: UVec3 = const_uvec3!([1; 3]); /// const X: UVec3 = const_uvec3!([1, 0, 0]); /// ``` +#[deprecated(since = "0.21.0", note = "use UVec3::from_array() instead.")] #[macro_export] macro_rules! const_uvec3 { ($ux3:expr) => {{ - let ux3 = $ux3; - unsafe { $crate::cast::UVec3Cast { ux3 }.v3 } + UVec3::from_array($ux3) }}; } @@ -535,10 +434,10 @@ macro_rules! const_uvec3 { /// const ONE: UVec4 = const_uvec4!([1; 4]); /// const X: UVec4 = const_uvec4!([1, 0, 0, 0]); /// ``` +#[deprecated(since = "0.21.0", note = "use UVec4::from_array() instead.")] #[macro_export] macro_rules! const_uvec4 { ($ux4:expr) => {{ - let ux4 = $ux4; - unsafe { $crate::cast::UVec4Cast { ux4 }.v4 } + UVec4::from_array($ux4) }}; } diff --git a/src/mat.rs b/src/mat.rs deleted file mode 100644 index b97e8edc..00000000 --- a/src/mat.rs +++ /dev/null @@ -1,114 +0,0 @@ -// Adds common vector trait implementations. -// The traits here should be supported for all types of $t and all sizes of vector. -macro_rules! impl_matn_common_traits { - ($t:ty, $matn:ident, $vecn:ident) => { - impl Default for $matn { - #[inline(always)] - fn default() -> Self { - Self::IDENTITY - } - } - - impl Add<$matn> for $matn { - type Output = Self; - #[inline(always)] - fn add(self, other: Self) -> Self::Output { - Self(self.0.add_matrix(&other.0)) - } - } - - impl AddAssign<$matn> for $matn { - #[inline(always)] - fn add_assign(&mut self, other: Self) { - self.0 = self.0.add_matrix(&other.0); - } - } - - impl Sub<$matn> for $matn { - type Output = Self; - #[inline(always)] - fn sub(self, other: Self) -> Self::Output { - Self(self.0.sub_matrix(&other.0)) - } - } - - impl SubAssign<$matn> for $matn { - #[inline(always)] - fn sub_assign(&mut self, other: Self) { - self.0 = self.0.sub_matrix(&other.0); - } - } - - impl Neg for $matn { - type Output = Self; - #[inline(always)] - fn neg(self) -> Self::Output { - Self(self.0.neg_matrix()) - } - } - - impl Mul<$matn> for $matn { - type Output = Self; - #[inline(always)] - fn mul(self, other: Self) -> Self::Output { - Self(self.0.mul_matrix(&other.0)) - } - } - - impl MulAssign<$matn> for $matn { - #[inline(always)] - fn mul_assign(&mut self, other: Self) { - self.0 = self.0.mul_matrix(&other.0); - } - } - - impl Mul<$vecn> for $matn { - type Output = $vecn; - #[inline(always)] - fn mul(self, other: $vecn) -> Self::Output { - $vecn(self.0.mul_vector(other.0)) - } - } - - impl Mul<$matn> for $t { - type Output = $matn; - #[inline(always)] - fn mul(self, other: $matn) -> Self::Output { - $matn(other.0.mul_scalar(self)) - } - } - - impl Mul<$t> for $matn { - type Output = Self; - #[inline(always)] - fn mul(self, other: $t) -> Self::Output { - Self(self.0.mul_scalar(other)) - } - } - - impl MulAssign<$t> for $matn { - #[inline(always)] - fn mul_assign(&mut self, other: $t) { - self.0 = self.0.mul_scalar(other); - } - } - - impl<'a> Sum<&'a Self> for $matn { - fn sum(iter: I) -> Self - where - I: Iterator, - { - iter.fold(Self::ZERO, |a, &b| Self::add(a, b)) - } - } - - impl<'a> Product<&'a Self> for $matn { - fn product(iter: I) -> Self - where - I: Iterator, - { - iter.fold(Self::IDENTITY, |a, &b| Self::mul(a, b)) - } - } - }; -} diff --git a/src/mat2.rs b/src/mat2.rs deleted file mode 100644 index 36ced761..00000000 --- a/src/mat2.rs +++ /dev/null @@ -1,398 +0,0 @@ -use crate::core::{ - storage::{Columns2, XY}, - traits::matrix::{FloatMatrix2x2, Matrix2x2, MatrixConst}, -}; -use crate::{DMat3, DVec2, Mat3, Vec2}; -#[cfg(not(target_arch = "spirv"))] -use core::fmt; -use core::iter::{Product, Sum}; -use core::ops::{Add, AddAssign, Deref, DerefMut, Mul, MulAssign, Neg, Sub, SubAssign}; - -#[cfg(all( - target_arch = "x86", - target_feature = "sse2", - not(feature = "scalar-math") -))] -use core::arch::x86::*; -#[cfg(all( - target_arch = "x86_64", - target_feature = "sse2", - not(feature = "scalar-math") -))] -use core::arch::x86_64::*; - -#[cfg(target_feature = "simd128")] -use core::arch::wasm32::v128; - -macro_rules! impl_mat2_methods { - ($t:ty, $vec2:ident, $mat3:ident, $inner:ident) => { - /// A 2x2 matrix with all elements set to `0.0`. - pub const ZERO: Self = Self($inner::ZERO); - - /// A 2x2 identity matrix, where all diagonal elements are `1`, and all off-diagonal elements are `0`. - pub const IDENTITY: Self = Self($inner::IDENTITY); - - /// All NAN:s. - pub const NAN: Self = Self(<$inner as crate::core::traits::scalar::NanConstEx>::NAN); - - /// Creates a 2x2 matrix from two column vectors. - #[inline(always)] - pub fn from_cols(x_axis: $vec2, y_axis: $vec2) -> Self { - Self($inner::from_cols(x_axis.0, y_axis.0)) - } - - /// Creates a 2x2 matrix from a `[S; 4]` array stored in column major order. - /// If your data is stored in row major you will need to `transpose` the returned - /// matrix. - #[inline(always)] - pub fn from_cols_array(m: &[$t; 4]) -> Self { - Self($inner::from_cols_array(m)) - } - - /// Creates a `[S; 4]` array storing data in column major order. - /// If you require data in row major order `transpose` the matrix first. - #[inline(always)] - pub fn to_cols_array(&self) -> [$t; 4] { - self.0.to_cols_array() - } - - /// Creates a 2x2 matrix from a `[[S; 2]; 2]` 2D array stored in column major order. - /// If your data is in row major order you will need to `transpose` the returned - /// matrix. - #[inline(always)] - pub fn from_cols_array_2d(m: &[[$t; 2]; 2]) -> Self { - Self($inner::from_cols_array_2d(m)) - } - - /// Creates a `[[S; 2]; 2]` 2D array storing data in column major order. - /// If you require data in row major order `transpose` the matrix first. - #[inline(always)] - pub fn to_cols_array_2d(&self) -> [[$t; 2]; 2] { - self.0.to_cols_array_2d() - } - - /// Creates a 2x2 matrix with its diagonal set to `diagonal` and all other entries set to 0. - #[doc(alias = "scale")] - #[inline(always)] - pub fn from_diagonal(diagonal: $vec2) -> Self { - Self($inner::from_diagonal(diagonal.0)) - } - - /// Creates a 2x2 matrix containing the combining non-uniform `scale` and rotation of - /// `angle` (in radians). - #[inline(always)] - pub fn from_scale_angle(scale: $vec2, angle: $t) -> Self { - Self($inner::from_scale_angle(scale.0, angle)) - } - - /// Creates a 2x2 matrix containing a rotation of `angle` (in radians). - #[inline(always)] - pub fn from_angle(angle: $t) -> Self { - Self($inner::from_angle(angle)) - } - - /// Creates a 2x2 matrix from a 3x3 matrix, discarding the 2nd row and column. - #[inline(always)] - pub fn from_mat3(m: $mat3) -> Self { - Self::from_cols($vec2(m.x_axis.0.into()), $vec2(m.y_axis.0.into())) - } - - /// Creates a 2x2 matrix from the first 4 values in `slice`. - /// - /// # Panics - /// - /// Panics if `slice` is less than 4 elements long. - #[inline(always)] - pub fn from_cols_slice(slice: &[$t]) -> Self { - Self(Matrix2x2::from_cols_slice(slice)) - } - - /// Writes the columns of `self` to the first 4 elements in `slice`. - /// - /// # Panics - /// - /// Panics if `slice` is less than 4 elements long. - #[inline(always)] - pub fn write_cols_to_slice(self, slice: &mut [$t]) { - Matrix2x2::write_cols_to_slice(&self.0, slice) - } - - /// Returns the matrix column for the given `index`. - /// - /// # Panics - /// - /// Panics if `index` is greater than 1. - #[inline] - pub fn col(&self, index: usize) -> $vec2 { - match index { - 0 => self.x_axis, - 1 => self.y_axis, - _ => panic!("index out of bounds"), - } - } - - /// Returns a mutable reference to the matrix column for the given `index`. - /// - /// # Panics - /// - /// Panics if `index` is greater than 1. - #[inline] - pub fn col_mut(&mut self, index: usize) -> &mut $vec2 { - match index { - 0 => &mut self.x_axis, - 1 => &mut self.y_axis, - _ => panic!("index out of bounds"), - } - } - - /// Returns the matrix row for the given `index`. - /// - /// # Panics - /// - /// Panics if `index` is greater than 1. - #[inline] - pub fn row(&self, index: usize) -> $vec2 { - match index { - 0 => $vec2::new(self.x_axis.x, self.y_axis.x), - 1 => $vec2::new(self.x_axis.y, self.y_axis.y), - _ => panic!("index out of bounds"), - } - } - - /// Returns `true` if, and only if, all elements are finite. - /// If any element is either `NaN`, positive or negative infinity, this will return `false`. - #[inline] - pub fn is_finite(&self) -> bool { - // TODO - self.x_axis.is_finite() && self.y_axis.is_finite() - } - - /// Returns `true` if any elements are `NaN`. - #[inline] - pub fn is_nan(&self) -> bool { - self.x_axis.is_nan() || self.y_axis.is_nan() - } - - /// Returns the transpose of `self`. - #[must_use] - #[inline(always)] - pub fn transpose(&self) -> Self { - Self(self.0.transpose()) - } - - /// Returns the determinant of `self`. - #[inline(always)] - pub fn determinant(&self) -> $t { - self.0.determinant() - } - - /// Returns the inverse of `self`. - /// - /// If the matrix is not invertible the returned matrix will be invalid. - /// - /// # Panics - /// - /// Will panic if the determinant of `self` is zero when `glam_assert` is enabled. - #[must_use] - #[inline(always)] - pub fn inverse(&self) -> Self { - Self(self.0.inverse()) - } - - /// Transforms a 2D vector. - #[inline(always)] - pub fn mul_vec2(&self, other: $vec2) -> $vec2 { - $vec2(self.0.mul_vector(other.0)) - } - - /// Multiplies two 2x2 matrices. - #[inline(always)] - pub fn mul_mat2(&self, other: &Self) -> Self { - Self(self.0.mul_matrix(&other.0)) - } - - /// Adds two 2x2 matrices. - #[inline(always)] - pub fn add_mat2(&self, other: &Self) -> Self { - Self(self.0.add_matrix(&other.0)) - } - - /// Subtracts two 2x2 matrices. - #[inline(always)] - pub fn sub_mat2(&self, other: &Self) -> Self { - Self(self.0.sub_matrix(&other.0)) - } - - /// Multiplies a 2x2 matrix by a scalar. - #[inline(always)] - pub fn mul_scalar(&self, other: $t) -> Self { - Self(self.0.mul_scalar(other)) - } - - /// Returns true if the absolute difference of all elements between `self` and `other` - /// is less than or equal to `max_abs_diff`. - /// - /// This can be used to compare if two matrices contain similar elements. It works best - /// when comparing with a known value. The `max_abs_diff` that should be used used - /// depends on the values being compared against. - /// - /// For more see - /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/). - #[inline(always)] - pub fn abs_diff_eq(&self, other: &Self, max_abs_diff: $t) -> bool { - self.0.abs_diff_eq(&other.0, max_abs_diff) - } - }; -} - -macro_rules! impl_mat2_traits { - ($t:ty, $new:ident, $mat2:ident, $vec2:ident) => { - /// Creates a 2x2 matrix from two column vectors. - #[inline(always)] - pub fn $new(x_axis: $vec2, y_axis: $vec2) -> $mat2 { - $mat2::from_cols(x_axis, y_axis) - } - - impl_matn_common_traits!($t, $mat2, $vec2); - - impl PartialEq for $mat2 { - #[inline] - fn eq(&self, other: &Self) -> bool { - self.x_axis.eq(&other.x_axis) && self.y_axis.eq(&other.y_axis) - } - } - - #[cfg(not(target_arch = "spirv"))] - impl AsRef<[$t; 4]> for $mat2 { - #[inline(always)] - fn as_ref(&self) -> &[$t; 4] { - unsafe { &*(self as *const Self as *const [$t; 4]) } - } - } - - #[cfg(not(target_arch = "spirv"))] - impl AsMut<[$t; 4]> for $mat2 { - #[inline(always)] - fn as_mut(&mut self) -> &mut [$t; 4] { - unsafe { &mut *(self as *mut Self as *mut [$t; 4]) } - } - } - - impl Deref for $mat2 { - type Target = Columns2<$vec2>; - #[inline(always)] - fn deref(&self) -> &Self::Target { - unsafe { &*(self as *const Self as *const Self::Target) } - } - } - - impl DerefMut for $mat2 { - #[inline(always)] - fn deref_mut(&mut self) -> &mut Self::Target { - unsafe { &mut *(self as *mut Self as *mut Self::Target) } - } - } - - #[cfg(not(target_arch = "spirv"))] - impl fmt::Debug for $mat2 { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_struct(stringify!($mat2)) - .field("x_axis", &self.x_axis) - .field("y_axis", &self.y_axis) - .finish() - } - } - - #[cfg(not(target_arch = "spirv"))] - impl fmt::Display for $mat2 { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "[{}, {}]", self.x_axis, self.y_axis) - } - } - }; -} - -#[cfg(all(target_feature = "sse2", not(feature = "scalar-math")))] -type InnerF32 = __m128; - -#[cfg(all(target_feature = "simd128", not(feature = "scalar-math")))] -type InnerF32 = v128; - -#[cfg(any( - not(any(target_feature = "sse2", target_feature = "simd128")), - feature = "scalar-math" -))] -type InnerF32 = crate::core::storage::Columns2>; - -/// A 2x2 column major matrix. -#[derive(Clone, Copy)] -#[cfg_attr( - not(any( - feature = "scalar-math", - target_arch = "spirv", - target_feature = "sse2", - target_feature = "simd128" - )), - repr(C, align(16)) -)] -#[cfg_attr(feature = "cuda", repr(C, align(8)))] -#[cfg_attr( - all( - any( - feature = "scalar-math", - target_arch = "spirv", - target_feature = "sse2", - target_feature = "simd128" - ), - not(feature = "cuda"), - ), - repr(transparent) -)] -pub struct Mat2(pub(crate) InnerF32); - -impl Mat2 { - impl_mat2_methods!(f32, Vec2, Mat3, InnerF32); - - #[inline(always)] - pub fn as_dmat2(&self) -> DMat2 { - DMat2::from_cols(self.x_axis.as_dvec2(), self.y_axis.as_dvec2()) - } -} -impl_mat2_traits!(f32, mat2, Mat2, Vec2); - -type InnerF64 = crate::core::storage::Columns2>; - -/// A 2x2 column major matrix. -#[derive(Clone, Copy)] -#[cfg_attr(feature = "cuda", repr(C, align(16)))] -#[cfg_attr(not(feature = "cuda"), repr(transparent))] -pub struct DMat2(pub(crate) InnerF64); - -impl DMat2 { - impl_mat2_methods!(f64, DVec2, DMat3, InnerF64); - - #[inline(always)] - pub fn as_mat2(&self) -> Mat2 { - Mat2::from_cols(self.x_axis.as_vec2(), self.y_axis.as_vec2()) - } -} -impl_mat2_traits!(f64, dmat2, DMat2, DVec2); - -mod const_test_mat2 { - #[cfg(any(feature = "scalar-math", target_arch = "spirv"))] - const_assert_eq!( - core::mem::align_of::(), - core::mem::align_of::() - ); - #[cfg(not(any(feature = "scalar-math", target_arch = "spirv")))] - const_assert_eq!(16, core::mem::align_of::()); - const_assert_eq!(16, core::mem::size_of::()); -} - -mod const_test_dmat2 { - const_assert_eq!( - core::mem::align_of::(), - core::mem::align_of::() - ); - const_assert_eq!(32, core::mem::size_of::()); -} diff --git a/src/mat3.rs b/src/mat3.rs deleted file mode 100644 index 564832a8..00000000 --- a/src/mat3.rs +++ /dev/null @@ -1,596 +0,0 @@ -use crate::core::{ - storage::{Columns3, XYZ}, - traits::matrix::{FloatMatrix3x3, Matrix3x3, MatrixConst}, -}; -use crate::{DMat2, DMat4, DQuat, DVec2, DVec3, EulerRot, Mat2, Mat4, Quat, Vec2, Vec3, Vec3A}; -#[cfg(not(target_arch = "spirv"))] -use core::fmt; -use core::iter::{Product, Sum}; -use core::ops::{Add, AddAssign, Deref, DerefMut, Mul, MulAssign, Neg, Sub, SubAssign}; - -#[cfg(all( - target_arch = "x86", - target_feature = "sse2", - not(feature = "scalar-math") -))] -use core::arch::x86::*; -#[cfg(all( - target_arch = "x86_64", - target_feature = "sse2", - not(feature = "scalar-math") -))] -use core::arch::x86_64::*; - -#[cfg(target_feature = "simd128")] -use core::arch::wasm32::v128; - -macro_rules! define_mat3_struct { - ($mat3:ident, $inner:ident) => { - /// A 3x3 column major matrix. - /// - /// This 3x3 matrix type features convenience methods for creating and using linear and - /// affine transformations. If you are primarily dealing with 2D affine transformations the - /// [`Affine2`](crate::Affine2) type is much faster and more space efficient than using a - /// 3x3 matrix. - /// - /// Linear transformations including 3D rotation and scale can be created using methods - /// such as [`Self::from_diagonal()`], [`Self::from_quat()`], [`Self::from_axis_angle()`], - /// [`Self::from_rotation_x()`], [`Self::from_rotation_y()`], or - /// [`Self::from_rotation_z()`]. - /// - /// The resulting matrices can be use to transform 3D vectors using regular vector - /// multiplication. - /// - /// Affine transformations including 2D translation, rotation and scale can be created - /// using methods such as [`Self::from_translation()`], [`Self::from_angle()`], - /// [`Self::from_scale()`] and [`Self::from_scale_angle_translation()`]. - /// - /// The [`Self::transform_point2()`] and [`Self::transform_vector2()`] convenience methods - /// are provided for performing affine transforms on 2D vectors and points. These multiply - /// 2D inputs as 3D vectors with an implicit `z` value of `1` for points and `0` for - /// vectors respectively. These methods assume that `Self` contains a valid affine - /// transform. - #[derive(Clone, Copy)] - #[cfg_attr(not(target_arch = "spirv"), repr(C))] - pub struct $mat3(pub(crate) $inner); - }; -} - -macro_rules! impl_mat3_methods { - ($t:ty, $vec3:ident, $vec3a:ident, $vec2:ident, $quat:ident, $mat2:ident, $mat4:ident, $inner:ident) => { - /// A 3x3 matrix with all elements set to `0.0`. - pub const ZERO: Self = Self($inner::ZERO); - - /// A 3x3 identity matrix, where all diagonal elements are `1`, and all off-diagonal - /// elements are `0`. - pub const IDENTITY: Self = Self($inner::IDENTITY); - - /// All NAN:s. - pub const NAN: Self = Self(<$inner as crate::core::traits::scalar::NanConstEx>::NAN); - - /// Creates a 3x3 matrix from three column vectors. - #[inline(always)] - pub fn from_cols(x_axis: $vec3a, y_axis: $vec3a, z_axis: $vec3a) -> Self { - Self(Matrix3x3::from_cols(x_axis.0, y_axis.0, z_axis.0)) - } - - /// Creates a 3x3 matrix from a `[S; 9]` array stored in column major order. - /// If your data is stored in row major you will need to `transpose` the returned - /// matrix. - #[inline(always)] - pub fn from_cols_array(m: &[$t; 9]) -> Self { - Self(Matrix3x3::from_cols_array(m)) - } - - /// Creates a `[S; 9]` array storing data in column major order. - /// If you require data in row major order `transpose` the matrix first. - #[inline(always)] - pub fn to_cols_array(&self) -> [$t; 9] { - self.0.to_cols_array() - } - - /// Creates a 3x3 matrix from a `[[S; 3]; 3]` 2D array stored in column major order. - /// If your data is in row major order you will need to `transpose` the returned - /// matrix. - #[inline(always)] - pub fn from_cols_array_2d(m: &[[$t; 3]; 3]) -> Self { - Self(Matrix3x3::from_cols_array_2d(m)) - } - - /// Creates a `[[S; 3]; 3]` 2D array storing data in column major order. - /// If you require data in row major order `transpose` the matrix first. - #[inline(always)] - pub fn to_cols_array_2d(&self) -> [[$t; 3]; 3] { - self.0.to_cols_array_2d() - } - - /// Creates a 3x3 matrix with its diagonal set to `diagonal` and all other entries set to 0. - /// The resulting matrix is a 3D scale transfom. - #[doc(alias = "scale")] - #[inline(always)] - pub fn from_diagonal(diagonal: $vec3) -> Self { - Self($inner::from_diagonal(diagonal.0)) - } - - /// Creates a 3x3 matrix from a 4x4 matrix, discarding the 3rd row and column. - pub fn from_mat4(m: $mat4) -> Self { - Self::from_cols( - $vec3a(m.x_axis.0.into()), - $vec3a(m.y_axis.0.into()), - $vec3a(m.z_axis.0.into()), - ) - } - - /// Creates a 3D rotation matrix from the given quaternion. - /// - /// # Panics - /// - /// Will panic if `rotation` is not normalized when `glam_assert` is enabled. - #[inline(always)] - pub fn from_quat(rotation: $quat) -> Self { - // TODO: SIMD? - Self($inner::from_quaternion(rotation.0.into())) - } - - /// Creates a 3D rotation matrix from a normalized rotation `axis` and `angle` (in - /// radians). - /// - /// # Panics - /// - /// Will panic if `axis` is not normalized when `glam_assert` is enabled. - #[inline(always)] - pub fn from_axis_angle(axis: $vec3, angle: $t) -> Self { - Self(FloatMatrix3x3::from_axis_angle(axis.0, angle)) - } - - #[inline(always)] - /// Creates a 3D rotation matrix from the given euler rotation sequence and the angles (in - /// radians). - pub fn from_euler(order: EulerRot, a: $t, b: $t, c: $t) -> Self { - let quat = $quat::from_euler(order, a, b, c); - Self::from_quat(quat) - } - - /// Creates a 3D rotation matrix from `angle` (in radians) around the x axis. - #[inline(always)] - pub fn from_rotation_x(angle: $t) -> Self { - Self($inner::from_rotation_x(angle)) - } - - /// Creates a 3D rotation matrix from `angle` (in radians) around the y axis. - #[inline(always)] - pub fn from_rotation_y(angle: $t) -> Self { - Self($inner::from_rotation_y(angle)) - } - - /// Creates a 3D rotation matrix from `angle` (in radians) around the z axis. - #[inline(always)] - pub fn from_rotation_z(angle: $t) -> Self { - Self($inner::from_rotation_z(angle)) - } - - /// Creates an affine transformation matrix from the given 2D `translation`. - /// - /// The resulting matrix can be used to transform 2D points and vectors. See - /// [`Self::transform_point2()`] and [`Self::transform_vector2()`]. - #[inline(always)] - pub fn from_translation(translation: $vec2) -> Self { - Self(Matrix3x3::from_translation(translation.0)) - } - - /// Creates an affine transformation matrix from the given 2D rotation `angle` (in - /// radians). - /// - /// The resulting matrix can be used to transform 2D points and vectors. See - /// [`Self::transform_point2()`] and [`Self::transform_vector2()`]. - #[inline(always)] - pub fn from_angle(angle: $t) -> Self { - Self(FloatMatrix3x3::from_angle(angle)) - } - - /// Creates an affine transformation matrix from the given 2D `scale`, rotation `angle` (in - /// radians) and `translation`. - /// - /// The resulting matrix can be used to transform 2D points and vectors. See - /// [`Self::transform_point2()`] and [`Self::transform_vector2()`]. - #[inline(always)] - pub fn from_scale_angle_translation(scale: $vec2, angle: $t, translation: $vec2) -> Self { - Self(FloatMatrix3x3::from_scale_angle_translation( - scale.0, - angle, - translation.0, - )) - } - - /// Creates an affine transformation matrix from the given non-uniform 2D `scale`. - /// - /// The resulting matrix can be used to transform 2D points and vectors. See - /// [`Self::transform_point2()`] and [`Self::transform_vector2()`]. - /// - /// # Panics - /// - /// Will panic if all elements of `scale` are zero when `glam_assert` is enabled. - #[inline(always)] - pub fn from_scale(scale: $vec2) -> Self { - Self(Matrix3x3::from_scale(scale.0)) - } - - /// Creates an affine transformation matrix from the given 2x2 matrix. - /// - /// The resulting matrix can be used to transform 2D points and vectors. See - /// [`Self::transform_point2()`] and [`Self::transform_vector2()`]. - #[inline(always)] - pub fn from_mat2(m: $mat2) -> Self { - Self::from_cols((m.x_axis, 0.0).into(), (m.y_axis, 0.0).into(), $vec3a::Z) - } - - /// Creates a 3x3 matrix from the first 9 values in `slice`. - /// - /// # Panics - /// - /// Panics if `slice` is less than 9 elements long. - #[inline(always)] - pub fn from_cols_slice(slice: &[$t]) -> Self { - Self(Matrix3x3::from_cols_slice(slice)) - } - - /// Writes the columns of `self` to the first 9 elements in `slice`. - /// - /// # Panics - /// - /// Panics if `slice` is less than 9 elements long. - #[inline(always)] - pub fn write_cols_to_slice(self, slice: &mut [$t]) { - Matrix3x3::write_cols_to_slice(&self.0, slice) - } - - /// Returns the matrix column for the given `index`. - /// - /// # Panics - /// - /// Panics if `index` is greater than 2. - #[inline] - pub fn col(&self, index: usize) -> $vec3a { - match index { - 0 => self.x_axis, - 1 => self.y_axis, - 2 => self.z_axis, - _ => panic!("index out of bounds"), - } - } - - /// Returns a mutable reference to the matrix column for the given `index`. - /// - /// # Panics - /// - /// Panics if `index` is greater than 2. - #[inline] - pub fn col_mut(&mut self, index: usize) -> &mut $vec3a { - match index { - 0 => &mut self.x_axis, - 1 => &mut self.y_axis, - 2 => &mut self.z_axis, - _ => panic!("index out of bounds"), - } - } - - /// Returns the matrix row for the given `index`. - /// - /// # Panics - /// - /// Panics if `index` is greater than 2. - #[inline] - pub fn row(&self, index: usize) -> $vec3a { - match index { - 0 => $vec3a::new(self.x_axis.x, self.y_axis.x, self.z_axis.x), - 1 => $vec3a::new(self.x_axis.y, self.y_axis.y, self.z_axis.y), - 2 => $vec3a::new(self.x_axis.z, self.y_axis.z, self.z_axis.z), - _ => panic!("index out of bounds"), - } - } - - /// Returns `true` if, and only if, all elements are finite. - /// If any element is either `NaN`, positive or negative infinity, this will return `false`. - #[inline] - pub fn is_finite(&self) -> bool { - self.x_axis.is_finite() && self.y_axis.is_finite() && self.z_axis.is_finite() - } - - /// Returns `true` if any elements are `NaN`. - #[inline] - pub fn is_nan(&self) -> bool { - self.x_axis.is_nan() || self.y_axis.is_nan() || self.z_axis.is_nan() - } - - /// Returns the transpose of `self`. - #[must_use] - #[inline(always)] - pub fn transpose(&self) -> Self { - Self(self.0.transpose()) - } - - /// Returns the determinant of `self`. - #[inline(always)] - pub fn determinant(&self) -> $t { - self.0.determinant() - } - - /// Returns the inverse of `self`. - /// - /// If the matrix is not invertible the returned matrix will be invalid. - /// - /// # Panics - /// - /// Will panic if the determinant of `self` is zero when `glam_assert` is enabled. - #[must_use] - #[inline(always)] - pub fn inverse(&self) -> Self { - Self(self.0.inverse()) - } - - /// Transforms a 3D vector. - #[inline(always)] - pub fn mul_vec3(&self, other: $vec3) -> $vec3 { - $vec3(self.0.mul_vector(other.0.into()).into()) - } - - /// Multiplies two 3x3 matrices. - #[inline] - pub fn mul_mat3(&self, other: &Self) -> Self { - Self(self.0.mul_matrix(&other.0)) - } - - /// Adds two 3x3 matrices. - #[inline(always)] - pub fn add_mat3(&self, other: &Self) -> Self { - Self(self.0.add_matrix(&other.0)) - } - - /// Subtracts two 3x3 matrices. - #[inline(always)] - pub fn sub_mat3(&self, other: &Self) -> Self { - Self(self.0.sub_matrix(&other.0)) - } - - /// Multiplies a 3x3 matrix by a scalar. - #[inline(always)] - pub fn mul_scalar(&self, other: $t) -> Self { - Self(self.0.mul_scalar(other)) - } - - /// Transforms the given 2D vector as a point. - /// - /// This is the equivalent of multiplying `other` as a 3D vector where `z` is `1`. - /// - /// This method assumes that `self` contains a valid affine transform. - #[inline(always)] - pub fn transform_point2(&self, other: $vec2) -> $vec2 { - $mat2::from_cols($vec2(self.x_axis.0.into()), $vec2(self.y_axis.0.into())) * other - + $vec2(self.z_axis.0.into()) - } - - /// Rotates the given 2D vector. - /// - /// This is the equivalent of multiplying `other` as a 3D vector where `z` is `0`. - /// - /// This method assumes that `self` contains a valid affine transform. - #[inline(always)] - pub fn transform_vector2(&self, other: $vec2) -> $vec2 { - $mat2::from_cols($vec2(self.x_axis.0.into()), $vec2(self.y_axis.0.into())) * other - } - - /// Returns true if the absolute difference of all elements between `self` and `other` - /// is less than or equal to `max_abs_diff`. - /// - /// This can be used to compare if two matrices contain similar elements. It works best - /// when comparing with a known value. The `max_abs_diff` that should be used used - /// depends on the values being compared against. - /// - /// For more see - /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/). - #[inline(always)] - pub fn abs_diff_eq(&self, other: Self, max_abs_diff: $t) -> bool { - self.0.abs_diff_eq(&other.0, max_abs_diff) - } - }; -} - -macro_rules! impl_mat3_traits { - ($t:ty, $new:ident, $mat3:ident, $vec3:ident, $vec3a:ident) => { - /// Creates a 3x3 matrix from three column vectors. - #[inline(always)] - pub fn $new(x_axis: $vec3a, y_axis: $vec3a, z_axis: $vec3a) -> $mat3 { - $mat3::from_cols(x_axis, y_axis, z_axis) - } - - impl_matn_common_traits!($t, $mat3, $vec3a); - - impl PartialEq for $mat3 { - #[inline] - fn eq(&self, other: &Self) -> bool { - self.x_axis.eq(&other.x_axis) - && self.y_axis.eq(&other.y_axis) - && self.z_axis.eq(&other.z_axis) - } - } - - impl Deref for $mat3 { - type Target = Columns3<$vec3a>; - #[inline(always)] - fn deref(&self) -> &Self::Target { - unsafe { &*(self as *const Self as *const Self::Target) } - } - } - - impl DerefMut for $mat3 { - #[inline(always)] - fn deref_mut(&mut self) -> &mut Self::Target { - unsafe { &mut *(self as *mut Self as *mut Self::Target) } - } - } - - #[cfg(not(target_arch = "spirv"))] - impl fmt::Display for $mat3 { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "[{}, {}, {}]", self.x_axis, self.y_axis, self.z_axis) - } - } - - #[cfg(not(target_arch = "spirv"))] - impl fmt::Debug for $mat3 { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_struct("$mat3") - .field("x_axis", &self.x_axis) - .field("y_axis", &self.y_axis) - .field("z_axis", &self.z_axis) - .finish() - } - } - }; -} - -macro_rules! impl_mat3_traits_unsafe { - ($t:ty, $mat3:ident) => { - #[cfg(not(target_arch = "spirv"))] - impl AsRef<[$t; 9]> for $mat3 { - #[inline(always)] - fn as_ref(&self) -> &[$t; 9] { - unsafe { &*(self as *const Self as *const [$t; 9]) } - } - } - - #[cfg(not(target_arch = "spirv"))] - impl AsMut<[$t; 9]> for $mat3 { - #[inline(always)] - fn as_mut(&mut self) -> &mut [$t; 9] { - unsafe { &mut *(self as *mut Self as *mut [$t; 9]) } - } - } - }; -} - -type InnerF32 = Columns3>; -define_mat3_struct!(Mat3, InnerF32); - -impl Mat3 { - impl_mat3_methods!(f32, Vec3, Vec3, Vec2, Quat, Mat2, Mat4, InnerF32); - - /// Transforms a `Vec3A`. - #[inline] - pub fn mul_vec3a(&self, other: Vec3A) -> Vec3A { - self.mul_vec3(other.into()).into() - } - - #[inline(always)] - pub fn as_dmat3(&self) -> DMat3 { - DMat3::from_cols( - self.x_axis.as_dvec3(), - self.y_axis.as_dvec3(), - self.z_axis.as_dvec3(), - ) - } -} -impl_mat3_traits!(f32, mat3, Mat3, Vec3, Vec3); -impl_mat3_traits_unsafe!(f32, Mat3); - -impl Mul for Mat3 { - type Output = Vec3A; - #[inline(always)] - fn mul(self, other: Vec3A) -> Vec3A { - self.mul_vec3a(other) - } -} - -#[cfg(all(target_feature = "sse2", not(feature = "scalar-math")))] -type InnerF32A = Columns3<__m128>; - -#[cfg(all(target_feature = "simd128", not(feature = "scalar-math")))] -type InnerF32A = Columns3; - -#[cfg(any( - not(any(target_feature = "sse2", target_feature = "simd128")), - feature = "scalar-math" -))] -type InnerF32A = Columns3; -define_mat3_struct!(Mat3A, InnerF32A); - -impl Mat3A { - impl_mat3_methods!(f32, Vec3, Vec3A, Vec2, Quat, Mat2, Mat4, InnerF32A); - - /// Transforms a `Vec3A`. - #[inline] - pub fn mul_vec3a(&self, other: Vec3A) -> Vec3A { - Vec3A(self.0.mul_vector(other.0)) - } - - #[inline(always)] - pub fn as_dmat3(&self) -> DMat3 { - DMat3::from_cols( - self.x_axis.as_dvec3(), - self.y_axis.as_dvec3(), - self.z_axis.as_dvec3(), - ) - } -} -impl_mat3_traits!(f32, mat3a, Mat3A, Vec3, Vec3A); - -impl Mul for Mat3A { - type Output = Vec3; - #[inline(always)] - fn mul(self, other: Vec3) -> Vec3 { - self.mul_vec3(other) - } -} - -impl From for Mat3A { - #[inline(always)] - fn from(m: Mat3) -> Self { - Self(m.0.into()) - } -} - -impl From for Mat3 { - #[inline(always)] - fn from(m: Mat3A) -> Self { - Self(m.0.into()) - } -} - -type InnerF64 = Columns3>; -define_mat3_struct!(DMat3, InnerF64); - -impl DMat3 { - impl_mat3_methods!(f64, DVec3, DVec3, DVec2, DQuat, DMat2, DMat4, InnerF64); - - #[inline(always)] - pub fn as_mat3(&self) -> Mat3 { - Mat3::from_cols( - self.x_axis.as_vec3(), - self.y_axis.as_vec3(), - self.z_axis.as_vec3(), - ) - } -} -impl_mat3_traits!(f64, dmat3, DMat3, DVec3, DVec3); -impl_mat3_traits_unsafe!(f64, DMat3); - -mod const_test_mat3 { - const_assert_eq!( - core::mem::align_of::(), - core::mem::align_of::() - ); - const_assert_eq!(36, core::mem::size_of::()); -} - -mod const_test_mat3a { - const_assert_eq!(16, core::mem::align_of::()); - const_assert_eq!(48, core::mem::size_of::()); -} - -mod const_test_dmat3 { - const_assert_eq!( - core::mem::align_of::(), - core::mem::align_of::() - ); - const_assert_eq!(72, core::mem::size_of::()); -} diff --git a/src/mat4.rs b/src/mat4.rs deleted file mode 100644 index fab1b738..00000000 --- a/src/mat4.rs +++ /dev/null @@ -1,890 +0,0 @@ -use crate::core::{ - storage::{Columns4, XYZW}, - traits::{ - matrix::{FloatMatrix4x4, Matrix4x4, MatrixConst}, - projection::ProjectionMatrix, - }, -}; -use crate::{DMat3, DQuat, DVec3, DVec4, EulerRot, Mat3, Quat, Vec3, Vec3A, Vec4}; - -#[cfg(all( - target_feature = "sse2", - not(feature = "scalar-math"), - target_arch = "x86" -))] -use core::arch::x86::*; -#[cfg(all( - target_feature = "sse2", - not(feature = "scalar-math"), - target_arch = "x86_64" -))] -use core::arch::x86_64::*; - -#[cfg(target_feature = "simd128")] -use core::arch::wasm32::v128; - -#[cfg(not(target_arch = "spirv"))] -use core::fmt; -use core::iter::{Product, Sum}; -use core::ops::{Add, AddAssign, Deref, DerefMut, Mul, MulAssign, Neg, Sub, SubAssign}; - -//macro_rules! define_mat4_struct { -// ($mat4:ident, $inner:ident) => { -// /// A 4x4 column major matrix. -// /// -// /// This 4x4 matrix type features convenience methods for creating and using affine -// /// transforms and perspective projections. -// /// -// /// Affine transformations including 3D translation, rotation and scale can be created -// /// using methods such as [`Self::from_translation()`], [`Self::from_quat()`], -// /// [`Self::from_scale()`] and [`Self::from_scale_rotation_translation()`]. -// /// -// /// Othographic projections can be created using the methods [`Self::orthographic_lh()`] for -// /// left-handed coordinate systems and [`Self::orthographic_rh()`] for right-handed -// /// systems. The resulting matrix is also an affine transformation. -// /// -// /// The [`Self::transform_point3()`] and [`Self::transform_vector3()`] convenience methods -// /// are provided for performing affine transformations on 3D vectors and points. These -// /// multiply 3D inputs as 4D vectors with an implicit `w` value of `1` for points and `0` -// /// for vectors respectively. These methods assume that `Self` contains a valid affine -// /// transform. -// /// -// /// Perspective projections can be created using methods such as -// /// [`Self::perspective_lh()`], [`Self::perspective_infinite_lh()`] and -// /// [`Self::perspective_infinite_reverse_lh()`] for left-handed co-ordinate systems and -// /// [`Self::perspective_rh()`], [`Self::perspective_infinite_rh()`] and -// /// [`Self::perspective_infinite_reverse_rh()`] for right-handed co-ordinate systems. -// /// -// /// The resulting perspective project can be use to transform 3D vectors as points with -// /// perspective correction using the [`Self::project_point3()`] convenience method. -// #[derive(Clone, Copy)] -// #[repr(transparent)] -// pub struct $mat4(pub(crate) $inner); -// }; -//} - -macro_rules! impl_mat4_methods { - ($t:ident, $vec4:ident, $vec3:ident, $mat3:ident, $quat:ident, $inner:ident) => { - /// A 4x4 matrix with all elements set to `0.0`. - pub const ZERO: Self = Self($inner::ZERO); - - /// A 4x4 identity matrix, where all diagonal elements are `1`, and all off-diagonal elements are `0`. - pub const IDENTITY: Self = Self($inner::IDENTITY); - - /// All NAN:s. - pub const NAN: Self = Self(<$inner as crate::core::traits::scalar::NanConstEx>::NAN); - - /// Creates a 4x4 matrix from four column vectors. - #[inline(always)] - pub fn from_cols(x_axis: $vec4, y_axis: $vec4, z_axis: $vec4, w_axis: $vec4) -> Self { - Self($inner::from_cols(x_axis.0, y_axis.0, z_axis.0, w_axis.0)) - } - - /// Creates a 4x4 matrix from a `[S; 16]` array stored in column major order. - /// If your data is stored in row major you will need to `transpose` the returned - /// matrix. - #[inline(always)] - pub fn from_cols_array(m: &[$t; 16]) -> Self { - Self($inner::from_cols_array(m)) - } - - /// Creates a `[S; 16]` array storing data in column major order. - /// If you require data in row major order `transpose` the matrix first. - #[inline(always)] - pub fn to_cols_array(&self) -> [$t; 16] { - self.0.to_cols_array() - } - - /// Creates a 4x4 matrix from a `[[S; 4]; 4]` 2D array stored in column major order. - /// If your data is in row major order you will need to `transpose` the returned - /// matrix. - #[inline(always)] - pub fn from_cols_array_2d(m: &[[$t; 4]; 4]) -> Self { - Self($inner::from_cols_array_2d(m)) - } - - /// Creates a `[[S; 4]; 4]` 2D array storing data in column major order. - /// If you require data in row major order `transpose` the matrix first. - #[inline(always)] - pub fn to_cols_array_2d(&self) -> [[$t; 4]; 4] { - self.0.to_cols_array_2d() - } - - /// Creates a 4x4 matrix with its diagonal set to `diagonal` and all other entries set to 0. - #[doc(alias = "scale")] - #[inline(always)] - pub fn from_diagonal(diagonal: $vec4) -> Self { - Self($inner::from_diagonal(diagonal.0.into())) - } - - /// Creates an affine transformation matrix from the given 3D `scale`, `rotation` and - /// `translation`. - /// - /// The resulting matrix can be used to transform 3D points and vectors. See - /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. - /// - /// # Panics - /// - /// Will panic if `rotation` is not normalized when `glam_assert` is enabled. - #[inline(always)] - pub fn from_scale_rotation_translation( - scale: $vec3, - rotation: $quat, - translation: $vec3, - ) -> Self { - Self($inner::from_scale_quaternion_translation( - scale.0, - rotation.0, - translation.0, - )) - } - - /// Creates an affine transformation matrix from the given 3D `translation`. - /// - /// The resulting matrix can be used to transform 3D points and vectors. See - /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. - /// - /// # Panics - /// - /// Will panic if `rotation` is not normalized when `glam_assert` is enabled. - #[inline(always)] - pub fn from_rotation_translation(rotation: $quat, translation: $vec3) -> Self { - Self($inner::from_quaternion_translation( - rotation.0, - translation.0, - )) - } - - /// Extracts `scale`, `rotation` and `translation` from `self`. The input matrix is - /// expected to be a 3D affine transformation matrix otherwise the output will be invalid. - /// - /// # Panics - /// - /// Will panic if the determinant of `self` is zero or if the resulting scale vector - /// contains any zero elements when `glam_assert` is enabled. - #[inline(always)] - pub fn to_scale_rotation_translation(&self) -> ($vec3, $quat, $vec3) { - let (scale, rotation, translation) = self.0.to_scale_quaternion_translation(); - ($vec3(scale), $quat(rotation), $vec3(translation)) - } - - /// Creates an affine transformation matrix from the given `rotation` quaternion. - /// - /// The resulting matrix can be used to transform 3D points and vectors. See - /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. - /// - /// # Panics - /// - /// Will panic if `rotation` is not normalized when `glam_assert` is enabled. - #[inline(always)] - pub fn from_quat(rotation: $quat) -> Self { - Self($inner::from_quaternion(rotation.0)) - } - - /// Creates an affine transformation matrix from the given 3x3 linear transformation - /// matrix. - /// - /// The resulting matrix can be used to transform 3D points and vectors. See - /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. - #[inline(always)] - pub fn from_mat3(m: $mat3) -> Self { - Self::from_cols( - (m.x_axis, 0.0).into(), - (m.y_axis, 0.0).into(), - (m.z_axis, 0.0).into(), - $vec4::W, - ) - } - - /// Creates an affine transformation matrix from the given 3D `translation`. - /// - /// The resulting matrix can be used to transform 3D points and vectors. See - /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. - #[inline(always)] - pub fn from_translation(translation: $vec3) -> Self { - Self($inner::from_translation(translation.0)) - } - - /// Creates an affine transformation matrix containing a 3D rotation around a normalized - /// rotation `axis` of `angle` (in radians). - /// - /// The resulting matrix can be used to transform 3D points and vectors. See - /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. - /// - /// # Panics - /// - /// Will panic if `axis` is not normalized when `glam_assert` is enabled. - #[inline(always)] - pub fn from_axis_angle(axis: $vec3, angle: $t) -> Self { - Self($inner::from_axis_angle(axis.0, angle)) - } - - #[inline(always)] - /// Creates a affine transformation matrix containing a rotation from the given euler - /// rotation sequence and angles (in radians). - /// - /// The resulting matrix can be used to transform 3D points and vectors. See - /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. - pub fn from_euler(order: EulerRot, a: $t, b: $t, c: $t) -> Self { - let quat = $quat::from_euler(order, a, b, c); - Self::from_quat(quat) - } - - /// Creates an affine transformation matrix containing a 3D rotation around the x axis of - /// `angle` (in radians). - /// - /// The resulting matrix can be used to transform 3D points and vectors. See - /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. - #[inline(always)] - pub fn from_rotation_x(angle: $t) -> Self { - Self($inner::from_rotation_x(angle)) - } - - /// Creates an affine transformation matrix containing a 3D rotation around the y axis of - /// `angle` (in radians). - /// - /// The resulting matrix can be used to transform 3D points and vectors. See - /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. - #[inline(always)] - pub fn from_rotation_y(angle: $t) -> Self { - Self($inner::from_rotation_y(angle)) - } - - /// Creates an affine transformation matrix containing a 3D rotation around the z axis of - /// `angle` (in radians). - /// - /// The resulting matrix can be used to transform 3D points and vectors. See - /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. - #[inline(always)] - pub fn from_rotation_z(angle: $t) -> Self { - Self($inner::from_rotation_z(angle)) - } - - /// Creates an affine transformation matrix containing the given 3D non-uniform `scale`. - /// - /// The resulting matrix can be used to transform 3D points and vectors. See - /// [`Self::transform_point3()`] and [`Self::transform_vector3()`]. - /// - /// # Panics - /// - /// Will panic if all elements of `scale` are zero when `glam_assert` is enabled. - #[inline(always)] - pub fn from_scale(scale: $vec3) -> Self { - Self($inner::from_scale(scale.0)) - } - - /// Creates a 4x4 matrix from the first 16 values in `slice`. - /// - /// # Panics - /// - /// Panics if `slice` is less than 16 elements long. - #[inline(always)] - pub fn from_cols_slice(slice: &[$t]) -> Self { - Self(Matrix4x4::from_cols_slice(slice)) - } - - /// Writes the columns of `self` to the first 16 elements in `slice`. - /// - /// # Panics - /// - /// Panics if `slice` is less than 16 elements long. - #[inline(always)] - pub fn write_cols_to_slice(self, slice: &mut [$t]) { - Matrix4x4::write_cols_to_slice(&self.0, slice) - } - - /// Returns the matrix column for the given `index`. - /// - /// # Panics - /// - /// Panics if `index` is greater than 3. - #[inline] - pub fn col(&self, index: usize) -> $vec4 { - match index { - 0 => self.x_axis, - 1 => self.y_axis, - 2 => self.z_axis, - 3 => self.w_axis, - _ => panic!("index out of bounds"), - } - } - - /// Returns a mutable reference to the matrix column for the given `index`. - /// - /// # Panics - /// - /// Panics if `index` is greater than 3. - #[inline] - pub fn col_mut(&mut self, index: usize) -> &mut $vec4 { - match index { - 0 => &mut self.x_axis, - 1 => &mut self.y_axis, - 2 => &mut self.z_axis, - 3 => &mut self.w_axis, - _ => panic!("index out of bounds"), - } - } - - /// Returns the matrix row for the given `index`. - /// - /// # Panics - /// - /// Panics if `index` is greater than 3. - #[inline] - pub fn row(&self, index: usize) -> $vec4 { - match index { - 0 => $vec4::new(self.x_axis.x, self.y_axis.x, self.z_axis.x, self.w_axis.x), - 1 => $vec4::new(self.x_axis.y, self.y_axis.y, self.z_axis.y, self.w_axis.y), - 2 => $vec4::new(self.x_axis.z, self.y_axis.z, self.z_axis.z, self.w_axis.z), - 3 => $vec4::new(self.x_axis.w, self.y_axis.w, self.z_axis.w, self.w_axis.w), - _ => panic!("index out of bounds"), - } - } - - /// Returns `true` if, and only if, all elements are finite. - /// If any element is either `NaN`, positive or negative infinity, this will return `false`. - #[inline] - pub fn is_finite(&self) -> bool { - self.x_axis.is_finite() - && self.y_axis.is_finite() - && self.z_axis.is_finite() - && self.w_axis.is_finite() - } - - /// Returns `true` if any elements are `NaN`. - #[inline] - pub fn is_nan(&self) -> bool { - self.x_axis.is_nan() - || self.y_axis.is_nan() - || self.z_axis.is_nan() - || self.w_axis.is_nan() - } - - /// Returns the transpose of `self`. - #[must_use] - #[inline(always)] - pub fn transpose(&self) -> Self { - Self(self.0.transpose()) - } - - /// Returns the determinant of `self`. - #[inline(always)] - pub fn determinant(&self) -> $t { - self.0.determinant() - } - - /// Returns the inverse of `self`. - /// - /// If the matrix is not invertible the returned matrix will be invalid. - /// - /// # Panics - /// - /// Will panic if the determinant of `self` is zero when `glam_assert` is enabled. - #[must_use] - #[inline(always)] - pub fn inverse(&self) -> Self { - Self(self.0.inverse()) - } - - /// Creates a left-handed view matrix using a camera position, an up direction, and a focal - /// point. - /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=forward`. - /// - /// # Panics - /// - /// Will panic if `up` is not normalized when `glam_assert` is enabled. - #[inline(always)] - pub fn look_at_lh(eye: $vec3, center: $vec3, up: $vec3) -> Self { - Self($inner::look_at_lh(eye.0, center.0, up.0)) - } - - /// Creates a right-handed view matrix using a camera position, an up direction, and a focal - /// point. - /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=back`. - /// - /// # Panics - /// - /// Will panic if `up` is not normalized when `glam_assert` is enabled. - #[inline(always)] - pub fn look_at_rh(eye: $vec3, center: $vec3, up: $vec3) -> Self { - Self($inner::look_at_rh(eye.0, center.0, up.0)) - } - - /// Creates a right-handed perspective projection matrix with [-1,1] depth range. - /// This is the same as the OpenGL `gluPerspective` function. - /// See - #[inline(always)] - pub fn perspective_rh_gl( - fov_y_radians: $t, - aspect_ratio: $t, - z_near: $t, - z_far: $t, - ) -> Self { - Self($inner::perspective_rh_gl( - fov_y_radians, - aspect_ratio, - z_near, - z_far, - )) - } - - /// Creates a left-handed perspective projection matrix with `[0,1]` depth range. - /// - /// # Panics - /// - /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is - /// enabled. - #[inline(always)] - pub fn perspective_lh(fov_y_radians: $t, aspect_ratio: $t, z_near: $t, z_far: $t) -> Self { - Self($inner::perspective_lh( - fov_y_radians, - aspect_ratio, - z_near, - z_far, - )) - } - - /// Creates a right-handed perspective projection matrix with `[0,1]` depth range. - /// - /// # Panics - /// - /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is - /// enabled. - #[inline(always)] - pub fn perspective_rh(fov_y_radians: $t, aspect_ratio: $t, z_near: $t, z_far: $t) -> Self { - Self($inner::perspective_rh( - fov_y_radians, - aspect_ratio, - z_near, - z_far, - )) - } - - /// Creates an infinite left-handed perspective projection matrix with `[0,1]` depth range. - /// - /// # Panics - /// - /// Will panic if `z_near` is less than or equal to zero when `glam_assert` is enabled. - #[inline(always)] - pub fn perspective_infinite_lh(fov_y_radians: $t, aspect_ratio: $t, z_near: $t) -> Self { - Self($inner::perspective_infinite_lh( - fov_y_radians, - aspect_ratio, - z_near, - )) - } - - /// Creates an infinite left-handed perspective projection matrix with `[0,1]` depth range. - /// - /// # Panics - /// - /// Will panic if `z_near` is less than or equal to zero when `glam_assert` is enabled. - #[inline(always)] - pub fn perspective_infinite_reverse_lh( - fov_y_radians: $t, - aspect_ratio: $t, - z_near: $t, - ) -> Self { - Self($inner::perspective_infinite_reverse_lh( - fov_y_radians, - aspect_ratio, - z_near, - )) - } - - /// Creates an infinite right-handed perspective projection matrix with - /// `[0,1]` depth range. - #[inline(always)] - pub fn perspective_infinite_rh(fov_y_radians: $t, aspect_ratio: $t, z_near: $t) -> Self { - Self($inner::perspective_infinite_rh( - fov_y_radians, - aspect_ratio, - z_near, - )) - } - - /// Creates an infinite reverse right-handed perspective projection matrix - /// with `[0,1]` depth range. - #[inline(always)] - pub fn perspective_infinite_reverse_rh( - fov_y_radians: $t, - aspect_ratio: $t, - z_near: $t, - ) -> Self { - Self($inner::perspective_infinite_reverse_rh( - fov_y_radians, - aspect_ratio, - z_near, - )) - } - - /// Creates a right-handed orthographic projection matrix with `[-1,1]` depth - /// range. This is the same as the OpenGL `glOrtho` function in OpenGL. - /// See - /// - #[inline(always)] - pub fn orthographic_rh_gl( - left: $t, - right: $t, - bottom: $t, - top: $t, - near: $t, - far: $t, - ) -> Self { - Self($inner::orthographic_rh_gl( - left, right, bottom, top, near, far, - )) - } - - /// Creates a left-handed orthographic projection matrix with `[0,1]` depth range. - #[inline(always)] - pub fn orthographic_lh( - left: $t, - right: $t, - bottom: $t, - top: $t, - near: $t, - far: $t, - ) -> Self { - Self($inner::orthographic_lh(left, right, bottom, top, near, far)) - } - - /// Creates a right-handed orthographic projection matrix with `[0,1]` depth range. - #[inline(always)] - pub fn orthographic_rh( - left: $t, - right: $t, - bottom: $t, - top: $t, - near: $t, - far: $t, - ) -> Self { - Self($inner::orthographic_rh(left, right, bottom, top, near, far)) - } - - /// Transforms a 4D vector. - #[inline(always)] - pub fn mul_vec4(&self, other: $vec4) -> $vec4 { - $vec4(self.0.mul_vector(other.0)) - } - - /// Multiplies two 4x4 matrices. - #[inline(always)] - pub fn mul_mat4(&self, other: &Self) -> Self { - Self(self.0.mul_matrix(&other.0)) - } - - /// Adds two 4x4 matrices. - #[inline(always)] - pub fn add_mat4(&self, other: &Self) -> Self { - Self(self.0.add_matrix(&other.0)) - } - - /// Subtracts two 4x4 matrices. - #[inline(always)] - pub fn sub_mat4(&self, other: &Self) -> Self { - Self(self.0.sub_matrix(&other.0)) - } - - /// Multiplies this matrix by a scalar value. - #[inline(always)] - pub fn mul_scalar(&self, other: $t) -> Self { - Self(self.0.mul_scalar(other)) - } - - /// Transforms the given 3D vector as a point, applying perspective correction. - /// - /// This is the equivalent of multiplying the 3D vector as a 4D vector where `w` is `1.0`. - /// The perspective divide is performed meaning the resulting 3D vector is divided by `w`. - /// - /// This method assumes that `self` contains a projective transform. - #[inline] - pub fn project_point3(&self, other: $vec3) -> $vec3 { - $vec3(self.0.project_point3(other.0)) - } - - /// Transforms the given 3D vector as a point. - /// - /// This is the equivalent of multiplying the 3D vector as a 4D vector where `w` is - /// `1.0`. - /// - /// This method assumes that `self` contains a valid affine transform. It does not perform - /// a persective divide, if `self` contains a perspective transform, or if you are unsure, - /// the [`Self::project_point3()`] method should be used instead. - /// - /// # Panics - /// - /// Will panic if the 3rd row of `self` is not `(0, 0, 0, 1)` when `glam_assert` is enabled. - #[inline] - pub fn transform_point3(&self, other: $vec3) -> $vec3 { - glam_assert!(self.row(3) == $vec4::W); - $vec3(self.0.transform_point3(other.0)) - } - - /// Transforms the give 3D vector as a direction. - /// - /// This is the equivalent of multiplying the 3D vector as a 4D vector where `w` is - /// `0.0`. - /// - /// This method assumes that `self` contains a valid affine transform. - /// - /// # Panics - /// - /// Will panic if the 3rd row of `self` is not `(0, 0, 0, 1)` when `glam_assert` is enabled. - #[inline] - pub fn transform_vector3(&self, other: $vec3) -> $vec3 { - glam_assert!(self.row(3) == $vec4::W); - $vec3(self.0.transform_vector3(other.0)) - } - - /// Returns true if the absolute difference of all elements between `self` and `other` - /// is less than or equal to `max_abs_diff`. - /// - /// This can be used to compare if two 4x4 matrices contain similar elements. It works - /// best when comparing with a known value. The `max_abs_diff` that should be used used - /// depends on the values being compared against. - /// - /// For more see - /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/). - #[inline(always)] - pub fn abs_diff_eq(&self, other: Self, max_abs_diff: $t) -> bool { - self.0.abs_diff_eq(&other.0, max_abs_diff) - } - }; -} - -macro_rules! impl_mat4_traits { - ($t:ty, $new:ident, $mat4:ident, $vec4:ident) => { - /// Creates a 4x4 matrix from four column vectors. - #[inline(always)] - pub fn $new(x_axis: $vec4, y_axis: $vec4, z_axis: $vec4, w_axis: $vec4) -> $mat4 { - $mat4::from_cols(x_axis, y_axis, z_axis, w_axis) - } - - impl_matn_common_traits!($t, $mat4, $vec4); - - impl Deref for $mat4 { - type Target = Columns4<$vec4>; - #[inline(always)] - fn deref(&self) -> &Self::Target { - unsafe { &*(self as *const Self as *const Self::Target) } - } - } - - impl DerefMut for $mat4 { - #[inline(always)] - fn deref_mut(&mut self) -> &mut Self::Target { - unsafe { &mut *(self as *mut Self as *mut Self::Target) } - } - } - - impl PartialEq for $mat4 { - #[inline] - fn eq(&self, other: &Self) -> bool { - self.x_axis.eq(&other.x_axis) - && self.y_axis.eq(&other.y_axis) - && self.z_axis.eq(&other.z_axis) - && self.w_axis.eq(&other.w_axis) - } - } - - #[cfg(not(target_arch = "spirv"))] - impl AsRef<[$t; 16]> for $mat4 { - #[inline] - fn as_ref(&self) -> &[$t; 16] { - unsafe { &*(self as *const Self as *const [$t; 16]) } - } - } - - #[cfg(not(target_arch = "spirv"))] - impl AsMut<[$t; 16]> for $mat4 { - #[inline] - fn as_mut(&mut self) -> &mut [$t; 16] { - unsafe { &mut *(self as *mut Self as *mut [$t; 16]) } - } - } - - #[cfg(not(target_arch = "spirv"))] - impl fmt::Debug for $mat4 { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_struct(stringify!($mat4)) - .field("x_axis", &self.x_axis) - .field("y_axis", &self.y_axis) - .field("z_axis", &self.z_axis) - .field("w_axis", &self.w_axis) - .finish() - } - } - - #[cfg(not(target_arch = "spirv"))] - impl fmt::Display for $mat4 { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "[{}, {}, {}, {}]", - self.x_axis, self.y_axis, self.z_axis, self.w_axis - ) - } - } - }; -} - -#[cfg(all(target_feature = "sse2", not(feature = "scalar-math")))] -type InnerF32 = Columns4<__m128>; - -#[cfg(all(target_feature = "simd128", not(feature = "scalar-math")))] -type InnerF32 = Columns4; - -#[cfg(any( - not(any(target_feature = "sse2", target_feature = "simd128")), - feature = "scalar-math" -))] -type InnerF32 = Columns4>; - -/// A 4x4 column major matrix. -/// -/// This 4x4 matrix type features convenience methods for creating and using affine transforms and -/// perspective projections. If you are primarily dealing with 3D affine transformations -/// considering using [`Affine3A`](crate::Affine3A) which is faster than a 4x4 matrix for some -/// affine operations. -/// -/// Affine transformations including 3D translation, rotation and scale can be created -/// using methods such as [`Self::from_translation()`], [`Self::from_quat()`], -/// [`Self::from_scale()`] and [`Self::from_scale_rotation_translation()`]. -/// -/// Othographic projections can be created using the methods [`Self::orthographic_lh()`] for -/// left-handed coordinate systems and [`Self::orthographic_rh()`] for right-handed -/// systems. The resulting matrix is also an affine transformation. -/// -/// The [`Self::transform_point3()`] and [`Self::transform_vector3()`] convenience methods -/// are provided for performing affine transformations on 3D vectors and points. These -/// multiply 3D inputs as 4D vectors with an implicit `w` value of `1` for points and `0` -/// for vectors respectively. These methods assume that `Self` contains a valid affine -/// transform. -/// -/// Perspective projections can be created using methods such as -/// [`Self::perspective_lh()`], [`Self::perspective_infinite_lh()`] and -/// [`Self::perspective_infinite_reverse_lh()`] for left-handed co-ordinate systems and -/// [`Self::perspective_rh()`], [`Self::perspective_infinite_rh()`] and -/// [`Self::perspective_infinite_reverse_rh()`] for right-handed co-ordinate systems. -/// -/// The resulting perspective project can be use to transform 3D vectors as points with -/// perspective correction using the [`Self::project_point3()`] convenience method. -#[derive(Clone, Copy)] -#[cfg_attr( - any( - not(any(feature = "scalar-math", target_arch = "spirv")), - feature = "cuda" - ), - repr(C, align(16)) -)] -#[cfg_attr( - all( - any(feature = "scalar-math", target_arch = "spirv"), - not(feature = "cuda"), - ), - repr(transparent) -)] -pub struct Mat4(pub(crate) InnerF32); -// define_mat4_struct!(Mat4, InnerF32); - -impl Mat4 { - impl_mat4_methods!(f32, Vec4, Vec3, Mat3, Quat, InnerF32); - - /// Transforms the given `Vec3A` as 3D point. - /// - /// This is the equivalent of multiplying the `Vec3A` as a 4D vector where `w` is `1.0`. - #[inline(always)] - pub fn transform_point3a(&self, other: Vec3A) -> Vec3A { - #[allow(clippy::useless_conversion)] - Vec3A(self.0.transform_float4_as_point3(other.0.into()).into()) - } - - /// Transforms the give `Vec3A` as 3D vector. - /// - /// This is the equivalent of multiplying the `Vec3A` as a 4D vector where `w` is `0.0`. - #[inline(always)] - pub fn transform_vector3a(&self, other: Vec3A) -> Vec3A { - #[allow(clippy::useless_conversion)] - Vec3A(self.0.transform_float4_as_vector3(other.0.into()).into()) - } - - #[inline(always)] - pub fn as_dmat4(&self) -> DMat4 { - DMat4::from_cols( - self.x_axis.as_dvec4(), - self.y_axis.as_dvec4(), - self.z_axis.as_dvec4(), - self.w_axis.as_dvec4(), - ) - } -} -impl_mat4_traits!(f32, mat4, Mat4, Vec4); - -type InnerF64 = Columns4>; - -/// A 4x4 column major matrix. -/// -/// This 4x4 matrix type features convenience methods for creating and using affine transforms and -/// perspective projections. If you are primarily dealing with 3D affine transformations -/// considering using [`DAffine3`](crate::DAffine3) which is faster than a 4x4 matrix for some -/// affine operations. -/// -/// Affine transformations including 3D translation, rotation and scale can be created -/// using methods such as [`Self::from_translation()`], [`Self::from_quat()`], -/// [`Self::from_scale()`] and [`Self::from_scale_rotation_translation()`]. -/// -/// Othographic projections can be created using the methods [`Self::orthographic_lh()`] for -/// left-handed coordinate systems and [`Self::orthographic_rh()`] for right-handed -/// systems. The resulting matrix is also an affine transformation. -/// -/// The [`Self::transform_point3()`] and [`Self::transform_vector3()`] convenience methods -/// are provided for performing affine transformations on 3D vectors and points. These -/// multiply 3D inputs as 4D vectors with an implicit `w` value of `1` for points and `0` -/// for vectors respectively. These methods assume that `Self` contains a valid affine -/// transform. -/// -/// Perspective projections can be created using methods such as -/// [`Self::perspective_lh()`], [`Self::perspective_infinite_lh()`] and -/// [`Self::perspective_infinite_reverse_lh()`] for left-handed co-ordinate systems and -/// [`Self::perspective_rh()`], [`Self::perspective_infinite_rh()`] and -/// [`Self::perspective_infinite_reverse_rh()`] for right-handed co-ordinate systems. -/// -/// The resulting perspective project can be use to transform 3D vectors as points with -/// perspective correction using the [`Self::project_point3()`] convenience method. -#[derive(Clone, Copy)] -#[cfg_attr(not(feature = "cuda"), repr(transparent))] -#[cfg_attr(feature = "cuda", repr(C, align(16)))] -pub struct DMat4(pub(crate) InnerF64); -// define_mat4_struct!(DMat4, InnerF64); - -impl DMat4 { - impl_mat4_methods!(f64, DVec4, DVec3, DMat3, DQuat, InnerF64); - - #[inline(always)] - pub fn as_mat4(&self) -> Mat4 { - Mat4::from_cols( - self.x_axis.as_vec4(), - self.y_axis.as_vec4(), - self.z_axis.as_vec4(), - self.w_axis.as_vec4(), - ) - } -} -impl_mat4_traits!(f64, dmat4, DMat4, DVec4); - -mod const_test_mat4 { - const_assert_eq!( - core::mem::align_of::(), - core::mem::align_of::() - ); - const_assert_eq!(64, core::mem::size_of::()); -} - -mod const_test_dmat4 { - const_assert_eq!( - core::mem::align_of::(), - core::mem::align_of::() - ); - const_assert_eq!(128, core::mem::size_of::()); -} diff --git a/src/quat.rs b/src/quat.rs deleted file mode 100644 index e0fa1b25..00000000 --- a/src/quat.rs +++ /dev/null @@ -1,818 +0,0 @@ -use crate::core::traits::{ - quaternion::Quaternion, - vector::{FloatVector4, MaskVector4, Vector, Vector4, Vector4Const}, -}; -use crate::euler::{EulerFromQuaternion, EulerRot, EulerToQuaternion}; -use crate::{DMat3, DMat4, DVec2, DVec3, DVec4}; -use crate::{Mat3, Mat4, Vec2, Vec3, Vec3A, Vec4}; - -#[cfg(not(feature = "std"))] -use num_traits::Float; - -#[cfg(all( - target_arch = "x86", - target_feature = "sse2", - not(feature = "scalar-math") -))] -use core::arch::x86::*; -#[cfg(all( - target_arch = "x86_64", - target_feature = "sse2", - not(feature = "scalar-math") -))] -use core::arch::x86_64::*; - -#[cfg(all(target_feature = "simd128", not(feature = "scalar-math")))] -use core::arch::wasm32::v128; - -#[cfg(not(target_arch = "spirv"))] -use core::fmt; -use core::iter::{Product, Sum}; -use core::ops::{Add, Deref, Div, Mul, MulAssign, Neg, Sub}; - -macro_rules! impl_quat_methods { - ($t:ident, $quat:ident, $vec2:ident, $vec3:ident, $vec4:ident, $mat3:ident, $mat4:ident, $inner:ident) => { - /// The identity quaternion. Corresponds to no rotation. - pub const IDENTITY: Self = Self($inner::W); - - /// All NAN:s. - pub const NAN: Self = Self(<$inner as crate::core::traits::scalar::NanConstEx>::NAN); - - /// Creates a new rotation quaternion. - /// - /// This should generally not be called manually unless you know what you are doing. - /// Use one of the other constructors instead such as `identity` or `from_axis_angle`. - /// - /// `from_xyzw` is mostly used by unit tests and `serde` deserialization. - /// - /// # Preconditions - /// - /// This function does not check if the input is normalized, it is up to the user to - /// provide normalized input or to normalized the resulting quaternion. - #[inline(always)] - pub fn from_xyzw(x: $t, y: $t, z: $t, w: $t) -> Self { - Self(Vector4::new(x, y, z, w)) - } - - /// Creates a rotation quaternion from an array. - /// - /// # Preconditions - /// - /// This function does not check if the input is normalized, it is up to the user to - /// provide normalized input or to normalized the resulting quaternion. - #[inline(always)] - pub fn from_array(a: [$t; 4]) -> Self { - let q = Vector4::from_array(a); - Self(q) - } - - /// Creates a new rotation quaternion from a 4D vector. - /// - /// # Preconditions - /// - /// This function does not check if the input is normalized, it is up to the user to - /// provide normalized input or to normalized the resulting quaternion. - #[inline(always)] - pub fn from_vec4(v: $vec4) -> Self { - Self(v.0) - } - - /// Creates a rotation quaternion from a slice. - /// - /// # Preconditions - /// - /// This function does not check if the input is normalized, it is up to the user to - /// provide normalized input or to normalized the resulting quaternion. - /// - /// # Panics - /// - /// Panics if `slice` length is less than 4. - #[inline(always)] - pub fn from_slice(slice: &[$t]) -> Self { - Self(Vector4::from_slice_unaligned(slice)) - } - - /// Writes the quaternion to an unaligned slice. - /// - /// # Panics - /// - /// Panics if `slice` length is less than 4. - #[inline(always)] - pub fn write_to_slice(self, slice: &mut [$t]) { - Vector4::write_to_slice_unaligned(self.0, slice) - } - - /// Create a quaternion for a normalized rotation `axis` and `angle` (in radians). - /// The axis must be normalized (unit-length). - /// - /// # Panics - /// - /// Will panic if `axis` is not normalized when `glam_assert` is enabled. - #[inline(always)] - pub fn from_axis_angle(axis: $vec3, angle: $t) -> Self { - Self($inner::from_axis_angle(axis.0, angle)) - } - - /// Create a quaternion that rotates `v.length()` radians around `v.normalize()`. - /// - /// `from_scaled_axis(Vec3::ZERO)` results in the identity quaternion. - #[inline(always)] - pub fn from_scaled_axis(v: $vec3) -> Self { - // Self($inner::from_scaled_axis(v.0)) - let length = v.length(); - if length == 0.0 { - Self::IDENTITY - } else { - Self::from_axis_angle(v / length, length) - } - } - - /// Creates a quaternion from the `angle` (in radians) around the x axis. - #[inline(always)] - pub fn from_rotation_x(angle: $t) -> Self { - Self($inner::from_rotation_x(angle)) - } - - /// Creates a quaternion from the `angle` (in radians) around the y axis. - #[inline(always)] - pub fn from_rotation_y(angle: $t) -> Self { - Self($inner::from_rotation_y(angle)) - } - - /// Creates a quaternion from the `angle` (in radians) around the z axis. - #[inline(always)] - pub fn from_rotation_z(angle: $t) -> Self { - Self($inner::from_rotation_z(angle)) - } - - #[inline(always)] - /// Creates a quaternion from the given euler rotation sequence and the angles (in radians). - pub fn from_euler(euler: EulerRot, a: $t, b: $t, c: $t) -> Self { - euler.new_quat(a, b, c) - } - - /// Creates a quaternion from a 3x3 rotation matrix. - #[inline] - pub fn from_mat3(mat: &$mat3) -> Self { - Self(Quaternion::from_rotation_axes( - mat.x_axis.0, - mat.y_axis.0, - mat.z_axis.0, - )) - } - - /// Creates a quaternion from a 3x3 rotation matrix inside a homogeneous 4x4 matrix. - #[inline] - pub fn from_mat4(mat: &$mat4) -> Self { - Self(Quaternion::from_rotation_axes( - mat.x_axis.0.into(), - mat.y_axis.0.into(), - mat.z_axis.0.into(), - )) - } - - /// Gets the minimal rotation for transforming `from` to `to`. The rotation is in the - /// plane spanned by the two vectors. Will rotate at most 180 degrees. - /// - /// The input vectors must be normalized (unit-length). - /// - /// `from_rotation_arc(from, to) * from ≈ to`. - /// - /// For near-singular cases (from≈to and from≈-to) the current implementation - /// is only accurate to about 0.001 (for `f32`). - /// - /// # Panics - /// - /// Will panic if `from` or `to` are not normalized when `glam_assert` is enabled. - pub fn from_rotation_arc(from: $vec3, to: $vec3) -> Self { - glam_assert!(from.is_normalized()); - glam_assert!(to.is_normalized()); - - const ONE_MINUS_EPS: $t = 1.0 - 2.0 * core::$t::EPSILON; - let dot = from.dot(to); - if dot > ONE_MINUS_EPS { - // 0° singulary: from ≈ to - Self::IDENTITY - } else if dot < -ONE_MINUS_EPS { - // 180° singulary: from ≈ -to - use core::$t::consts::PI; // half a turn = 𝛕/2 = 180° - Self::from_axis_angle(from.any_orthonormal_vector(), PI) - } else { - let c = from.cross(to); - Self::from_xyzw(c.x, c.y, c.z, 1.0 + dot).normalize() - } - } - - /// Gets the minimal rotation for transforming `from` to either `to` or `-to`. This means - /// that the resulting quaternion will rotate `from` so that it is colinear with `to`. - /// - /// The rotation is in the plane spanned by the two vectors. Will rotate at most 90 - /// degrees. - /// - /// The input vectors must be normalized (unit-length). - /// - /// `to.dot(from_rotation_arc_colinear(from, to) * from).abs() ≈ 1`. - /// - /// # Panics - /// - /// Will panic if `from` or `to` are not normalized when `glam_assert` is enabled. - pub fn from_rotation_arc_colinear(from: $vec3, to: $vec3) -> Self { - if from.dot(to) < 0.0 { - Self::from_rotation_arc(from, -to) - } else { - Self::from_rotation_arc(from, to) - } - } - - /// Gets the minimal rotation for transforming `from` to `to`. The resulting rotation is - /// around the z axis. Will rotate at most 180 degrees. - /// - /// The input vectors must be normalized (unit-length). - /// - /// `from_rotation_arc_2d(from, to) * from ≈ to`. - /// - /// For near-singular cases (from≈to and from≈-to) the current implementation - /// is only accurate to about 0.001 (for `f32`). - /// - /// # Panics - /// - /// Will panic if `from` or `to` are not normalized when `glam_assert` is enabled. - pub fn from_rotation_arc_2d(from: $vec2, to: $vec2) -> Self { - glam_assert!(from.is_normalized()); - glam_assert!(to.is_normalized()); - - const ONE_MINUS_EPSILON: $t = 1.0 - 2.0 * core::$t::EPSILON; - let dot = from.dot(to); - if dot > ONE_MINUS_EPSILON { - // 0° singulary: from ≈ to - Self::IDENTITY - } else if dot < -ONE_MINUS_EPSILON { - // 180° singulary: from ≈ -to - const COS_FRAC_PI_2: $t = 0.0; - const SIN_FRAC_PI_2: $t = 1.0; - // rotation around z by PI radians - Self::from_xyzw(0.0, 0.0, SIN_FRAC_PI_2, COS_FRAC_PI_2) - } else { - // vector3 cross where z=0 - let z = from.x * to.y - to.x * from.y; - let w = 1.0 + dot; - // calculate length with x=0 and y=0 to normalize - let len_rcp = 1.0 / (z * z + w * w).sqrt(); - Self::from_xyzw(0.0, 0.0, z * len_rcp, w * len_rcp) - } - } - - /// Returns the rotation axis and angle (in radians) of `self`. - #[inline(always)] - pub fn to_axis_angle(self) -> ($vec3, $t) { - let (axis, angle) = self.0.to_axis_angle(); - ($vec3(axis), angle) - } - - /// Returns the rotation axis scaled by the rotation in radians. - #[inline(always)] - pub fn to_scaled_axis(self) -> $vec3 { - let (axis, angle) = self.0.to_axis_angle(); - $vec3(axis) * angle - } - - /// Returns the rotation angles for the given euler rotation sequence. - #[inline(always)] - pub fn to_euler(self, euler: EulerRot) -> ($t, $t, $t) { - euler.convert_quat(self) - } - - /// `[x, y, z, w]` - #[inline(always)] - pub fn to_array(&self) -> [$t; 4] { - [self.x, self.y, self.z, self.w] - } - - /// Returns the vector part of the quaternion. - #[inline(always)] - pub fn xyz(self) -> $vec3 { - $vec3::new(self.x, self.y, self.z) - } - - /// Returns the quaternion conjugate of `self`. For a unit quaternion the - /// conjugate is also the inverse. - #[must_use] - #[inline(always)] - pub fn conjugate(self) -> Self { - Self(self.0.conjugate()) - } - - /// Returns the inverse of a normalized quaternion. - /// - /// Typically quaternion inverse returns the conjugate of a normalized quaternion. - /// Because `self` is assumed to already be unit length this method *does not* normalize - /// before returning the conjugate. - /// - /// # Panics - /// - /// Will panic if `self` is not normalized when `glam_assert` is enabled. - #[must_use] - #[inline(always)] - pub fn inverse(self) -> Self { - glam_assert!(self.is_normalized()); - self.conjugate() - } - - /// Computes the dot product of `self` and `other`. The dot product is - /// equal to the the cosine of the angle between two quaternion rotations. - #[inline(always)] - pub fn dot(self, other: Self) -> $t { - Vector4::dot(self.0, other.0) - } - - /// Computes the length of `self`. - #[doc(alias = "magnitude")] - #[inline(always)] - pub fn length(self) -> $t { - FloatVector4::length(self.0) - } - - /// Computes the squared length of `self`. - /// - /// This is generally faster than `length()` as it avoids a square - /// root operation. - #[doc(alias = "magnitude2")] - #[inline(always)] - pub fn length_squared(self) -> $t { - FloatVector4::length_squared(self.0) - } - - /// Computes `1.0 / length()`. - /// - /// For valid results, `self` must _not_ be of length zero. - #[inline(always)] - pub fn length_recip(self) -> $t { - FloatVector4::length_recip(self.0) - } - - /// Returns `self` normalized to length 1.0. - /// - /// For valid results, `self` must _not_ be of length zero. - /// - /// Panics - /// - /// Will panic if `self` is zero length when `glam_assert` is enabled. - #[must_use] - #[inline(always)] - pub fn normalize(self) -> Self { - Self(FloatVector4::normalize(self.0)) - } - - /// Returns `true` if, and only if, all elements are finite. - /// If any element is either `NaN`, positive or negative infinity, this will return `false`. - #[inline(always)] - pub fn is_finite(self) -> bool { - FloatVector4::is_finite(self.0) - } - - #[inline(always)] - pub fn is_nan(self) -> bool { - FloatVector4::is_nan(self.0) - } - - /// Returns whether `self` of length `1.0` or not. - /// - /// Uses a precision threshold of `1e-6`. - #[inline(always)] - pub fn is_normalized(self) -> bool { - FloatVector4::is_normalized(self.0) - } - - #[inline(always)] - pub fn is_near_identity(self) -> bool { - self.0.is_near_identity() - } - - /// Returns the angle (in radians) for the minimal rotation - /// for transforming this quaternion into another. - /// - /// Both quaternions must be normalized. - /// - /// # Panics - /// - /// Will panic if `self` or `other` are not normalized when `glam_assert` is enabled. - pub fn angle_between(self, other: Self) -> $t { - glam_assert!(self.is_normalized() && other.is_normalized()); - use crate::core::traits::scalar::FloatEx; - self.dot(other).abs().acos_approx() * 2.0 - } - - /// Returns true if the absolute difference of all elements between `self` and `other` - /// is less than or equal to `max_abs_diff`. - /// - /// This can be used to compare if two quaternions contain similar elements. It works - /// best when comparing with a known value. The `max_abs_diff` that should be used used - /// depends on the values being compared against. - /// - /// For more see - /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/). - #[inline(always)] - pub fn abs_diff_eq(self, other: Self, max_abs_diff: $t) -> bool { - FloatVector4::abs_diff_eq(self.0, other.0, max_abs_diff) - } - - /// Performs a linear interpolation between `self` and `other` based on - /// the value `s`. - /// - /// When `s` is `0.0`, the result will be equal to `self`. When `s` - /// is `1.0`, the result will be equal to `other`. - /// - /// # Panics - /// - /// Will panic if `self` or `end` are not normalized when `glam_assert` is enabled. - #[inline(always)] - #[doc(alias = "mix")] - pub fn lerp(self, end: Self, s: $t) -> Self { - Self(self.0.lerp(end.0, s)) - } - - /// Performs a spherical linear interpolation between `self` and `end` - /// based on the value `s`. - /// - /// When `s` is `0.0`, the result will be equal to `self`. When `s` - /// is `1.0`, the result will be equal to `end`. - /// - /// # Panics - /// - /// Will panic if `self` or `end` are not normalized when `glam_assert` is enabled. - #[inline(always)] - pub fn slerp(self, end: Self, s: $t) -> Self { - Self(self.0.slerp(end.0, s)) - } - - /// Multiplies a quaternion and a 3D vector, returning the rotated vector. - /// - /// # Panics - /// - /// Will panic if `self` is not normalized when `glam_assert` is enabled. - #[inline(always)] - pub fn mul_vec3(self, other: $vec3) -> $vec3 { - $vec3(self.0.mul_vector3(other.0)) - } - - /// Multiplies two quaternions. If they each represent a rotation, the result will - /// represent the combined rotation. - /// - /// Note that due to floating point rounding the result may not be perfectly normalized. - /// - /// # Panics - /// - /// Will panic if `self` or `other` are not normalized when `glam_assert` is enabled. - #[inline(always)] - pub fn mul_quat(self, other: Self) -> Self { - Self(self.0.mul_quaternion(other.0)) - } - }; -} - -macro_rules! impl_quat_traits { - ($t:ty, $new:ident, $quat:ident, $vec3:ident, $vec4:ident, $inner:ident) => { - /// Creates a quaternion from `x`, `y`, `z` and `w` values. - /// - /// This should generally not be called manually unless you know what you are doing. Use - /// one of the other constructors instead such as `identity` or `from_axis_angle`. - #[inline] - pub fn $new(x: $t, y: $t, z: $t, w: $t) -> $quat { - $quat::from_xyzw(x, y, z, w) - } - - #[cfg(not(target_arch = "spirv"))] - impl fmt::Debug for $quat { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_tuple(stringify!($quat)) - .field(&self.x) - .field(&self.y) - .field(&self.z) - .field(&self.w) - .finish() - } - } - - #[cfg(not(target_arch = "spirv"))] - impl fmt::Display for $quat { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(fmt, "[{}, {}, {}, {}]", self.x, self.y, self.z, self.w) - } - } - - impl Add<$quat> for $quat { - type Output = Self; - /// Adds two quaternions. - /// - /// The sum is not guaranteed to be normalized. - /// - /// Note that addition is not the same as combining the rotations represented by the - /// two quaternions! That corresponds to multiplication. - #[inline] - fn add(self, other: Self) -> Self { - Self(self.0.add(other.0)) - } - } - - impl Sub<$quat> for $quat { - type Output = Self; - /// Subtracts the other quaternion from self. - /// - /// The difference is not guaranteed to be normalized. - #[inline] - fn sub(self, other: Self) -> Self { - Self(self.0.sub(other.0)) - } - } - - impl Mul<$t> for $quat { - type Output = Self; - /// Multiplies a quaternion by a scalar value. - /// - /// The product is not guaranteed to be normalized. - #[inline] - fn mul(self, other: $t) -> Self { - Self(self.0.scale(other)) - } - } - - impl Div<$t> for $quat { - type Output = Self; - /// Divides a quaternion by a scalar value. - /// The quotient is not guaranteed to be normalized. - #[inline] - fn div(self, other: $t) -> Self { - Self(self.0.scale(other.recip())) - } - } - - impl Mul<$quat> for $quat { - type Output = Self; - /// Multiplies two quaternions. If they each represent a rotation, the result will - /// represent the combined rotation. - /// - /// Note that due to floating point rounding the result may not be perfectly - /// normalized. - /// - /// # Panics - /// - /// Will panic if `self` or `other` are not normalized when `glam_assert` is enabled. - #[inline] - fn mul(self, other: Self) -> Self { - Self(self.0.mul_quaternion(other.0)) - } - } - - impl MulAssign<$quat> for $quat { - /// Multiplies two quaternions. If they each represent a rotation, the result will - /// represent the combined rotation. - /// - /// Note that due to floating point rounding the result may not be perfectly - /// normalized. - /// - /// # Panics - /// - /// Will panic if `self` or `other` are not normalized when `glam_assert` is enabled. - #[inline] - fn mul_assign(&mut self, other: Self) { - self.0 = self.0.mul_quaternion(other.0); - } - } - - impl Mul<$vec3> for $quat { - type Output = $vec3; - /// Multiplies a quaternion and a 3D vector, returning the rotated vector. - /// - /// # Panics - /// - /// Will panic if `self` is not normalized when `glam_assert` is enabled. - #[inline] - fn mul(self, other: $vec3) -> Self::Output { - $vec3(self.0.mul_vector3(other.0)) - } - } - - impl Neg for $quat { - type Output = Self; - #[inline] - fn neg(self) -> Self { - Self(self.0.scale(-1.0)) - } - } - - impl Default for $quat { - #[inline] - fn default() -> Self { - Self::IDENTITY - } - } - - impl PartialEq for $quat { - #[inline] - fn eq(&self, other: &Self) -> bool { - MaskVector4::all(self.0.cmpeq(other.0)) - } - } - - #[cfg(not(target_arch = "spirv"))] - impl AsRef<[$t; 4]> for $quat { - #[inline(always)] - fn as_ref(&self) -> &[$t; 4] { - unsafe { &*(self as *const Self as *const [$t; 4]) } - } - } - - #[cfg(not(target_arch = "spirv"))] - impl AsMut<[$t; 4]> for $quat { - #[inline(always)] - fn as_mut(&mut self) -> &mut [$t; 4] { - unsafe { &mut *(self as *mut Self as *mut [$t; 4]) } - } - } - - impl From<$quat> for $vec4 { - #[inline(always)] - fn from(q: $quat) -> Self { - $vec4(q.0) - } - } - - impl From<$quat> for ($t, $t, $t, $t) { - #[inline(always)] - fn from(q: $quat) -> Self { - Vector4::into_tuple(q.0) - } - } - - impl From<$quat> for [$t; 4] { - #[inline(always)] - fn from(q: $quat) -> Self { - Vector4::into_array(q.0) - } - } - - impl From<$quat> for $inner { - // TODO: write test - #[inline(always)] - fn from(q: $quat) -> Self { - q.0 - } - } - - impl Deref for $quat { - type Target = crate::XYZW<$t>; - #[inline(always)] - fn deref(&self) -> &Self::Target { - self.0.as_ref_xyzw() - } - } - - impl<'a> Sum<&'a Self> for $quat { - fn sum(iter: I) -> Self - where - I: Iterator, - { - use crate::core::traits::vector::VectorConst; - iter.fold(Self($inner::ZERO), |a, &b| Self::add(a, b)) - } - } - - impl<'a> Product<&'a Self> for $quat { - fn product(iter: I) -> Self - where - I: Iterator, - { - iter.fold(Self::IDENTITY, |a, &b| Self::mul(a, b)) - } - } - }; -} - -#[cfg(all(target_feature = "sse2", not(feature = "scalar-math")))] -type InnerF32 = __m128; - -#[cfg(all(target_feature = "simd128", not(feature = "scalar-math")))] -type InnerF32 = v128; - -#[cfg(any( - not(any(target_feature = "sse2", target_feature = "simd128")), - feature = "scalar-math" -))] -type InnerF32 = crate::XYZW; - -/// A quaternion representing an orientation. -/// -/// This quaternion is intended to be of unit length but may denormalize due to -/// floating point "error creep" which can occur when successive quaternion -/// operations are applied. -/// -/// This type is 16 byte aligned. -#[derive(Clone, Copy)] -#[cfg_attr( - not(any( - feature = "scalar-math", - target_arch = "spirv", - target_feature = "sse2", - target_feature = "simd128" - )), - repr(C, align(16)) -)] -#[cfg_attr( - any( - feature = "scalar-math", - target_arch = "spirv", - target_feature = "sse2", - target_feature = "simd128" - ), - repr(transparent) -)] -pub struct Quat(pub(crate) InnerF32); - -impl Quat { - impl_quat_methods!(f32, Quat, Vec2, Vec3, Vec4, Mat3, Mat4, InnerF32); - - /// Multiplies a quaternion and a 3D vector, returning the rotated vector. - #[inline(always)] - pub fn mul_vec3a(self, other: Vec3A) -> Vec3A { - #[allow(clippy::useless_conversion)] - Vec3A(self.0.mul_float4_as_vector3(other.0.into()).into()) - } - - #[inline(always)] - pub fn as_f64(self) -> DQuat { - DQuat::from_xyzw(self.x as f64, self.y as f64, self.z as f64, self.w as f64) - } - - /// Creates a quaternion from a 3x3 rotation matrix inside a 3D affine transform. - #[inline] - pub fn from_affine3(mat: &crate::Affine3A) -> Self { - Self(Quaternion::from_rotation_axes( - mat.x_axis.0.into(), - mat.y_axis.0.into(), - mat.z_axis.0.into(), - )) - } -} -impl_quat_traits!(f32, quat, Quat, Vec3, Vec4, InnerF32); - -impl Mul for Quat { - type Output = Vec3A; - #[inline(always)] - fn mul(self, other: Vec3A) -> Self::Output { - self.mul_vec3a(other) - } -} - -type InnerF64 = crate::XYZW; - -/// A quaternion representing an orientation. -/// -/// This quaternion is intended to be of unit length but may denormalize due to -/// floating point "error creep" which can occur when successive quaternion -/// operations are applied. -#[derive(Clone, Copy)] -#[repr(transparent)] -pub struct DQuat(pub(crate) InnerF64); - -impl DQuat { - impl_quat_methods!(f64, DQuat, DVec2, DVec3, DVec4, DMat3, DMat4, InnerF64); - - #[inline(always)] - pub fn as_f32(self) -> Quat { - Quat::from_xyzw(self.x as f32, self.y as f32, self.z as f32, self.w as f32) - } - - /// Creates a quaternion from a 3x3 rotation matrix inside a 3D affine transform. - #[inline] - pub fn from_affine3(mat: &crate::DAffine3) -> Self { - Self(Quaternion::from_rotation_axes( - mat.x_axis.0, - mat.y_axis.0, - mat.z_axis.0, - )) - } -} -impl_quat_traits!(f64, dquat, DQuat, DVec3, DVec4, InnerF64); - -#[cfg(any(feature = "scalar-math", target_arch = "spirv"))] -mod const_test_quat { - const_assert_eq!( - core::mem::align_of::(), - core::mem::align_of::() - ); - const_assert_eq!(16, core::mem::size_of::()); -} - -#[cfg(not(any(feature = "scalar-math", target_arch = "spirv")))] -mod const_test_quat { - const_assert_eq!(16, core::mem::align_of::()); - const_assert_eq!(16, core::mem::size_of::()); -} - -mod const_test_dquat { - const_assert_eq!( - core::mem::align_of::(), - core::mem::align_of::() - ); - const_assert_eq!(32, core::mem::size_of::()); -} diff --git a/src/core/sse2/float.rs b/src/sse2.rs similarity index 66% rename from src/core/sse2/float.rs rename to src/sse2.rs index 9c3ac8e7..a7bf4bcf 100644 --- a/src/core/sse2/float.rs +++ b/src/sse2.rs @@ -27,23 +27,46 @@ const PS_ONE: __m128 = const_f32x4!([1.0; 4]); const PS_TWO_PI: __m128 = const_f32x4!([core::f32::consts::TAU; 4]); const PS_RECIPROCAL_TWO_PI: __m128 = const_f32x4!([0.159_154_94; 4]); +/// Calculates the vector 3 dot product and returns answer in x lane of __m128. +#[inline(always)] +pub(crate) unsafe fn dot3_in_x(lhs: __m128, rhs: __m128) -> __m128 { + let x2_y2_z2_w2 = _mm_mul_ps(lhs, rhs); + let y2_0_0_0 = _mm_shuffle_ps(x2_y2_z2_w2, x2_y2_z2_w2, 0b00_00_00_01); + let z2_0_0_0 = _mm_shuffle_ps(x2_y2_z2_w2, x2_y2_z2_w2, 0b00_00_00_10); + let x2y2_0_0_0 = _mm_add_ss(x2_y2_z2_w2, y2_0_0_0); + _mm_add_ss(x2y2_0_0_0, z2_0_0_0) +} + +/// Calculates the vector 4 dot product and returns answer in x lane of __m128. +#[inline(always)] +pub(crate) unsafe fn dot4_in_x(lhs: __m128, rhs: __m128) -> __m128 { + let x2_y2_z2_w2 = _mm_mul_ps(lhs, rhs); + let z2_w2_0_0 = _mm_shuffle_ps(x2_y2_z2_w2, x2_y2_z2_w2, 0b00_00_11_10); + let x2z2_y2w2_0_0 = _mm_add_ps(x2_y2_z2_w2, z2_w2_0_0); + let y2w2_0_0_0 = _mm_shuffle_ps(x2z2_y2w2_0_0, x2z2_y2w2_0_0, 0b00_00_00_01); + _mm_add_ps(x2z2_y2w2_0_0, y2w2_0_0_0) +} + #[inline] -pub(crate) unsafe fn m128_abs(v: __m128) -> __m128 { - _mm_and_ps(v, _mm_castsi128_ps(_mm_set1_epi32(0x7f_ff_ff_ff))) +pub(crate) unsafe fn dot3(lhs: __m128, rhs: __m128) -> f32 { + _mm_cvtss_f32(dot3_in_x(lhs, rhs)) } #[inline] -pub(crate) unsafe fn m128_round(v: __m128) -> __m128 { - // Based on https://github.com/microsoft/DirectXMath `XMVectorRound` - let sign = _mm_and_ps(v, PS_SIGN_MASK); - let s_magic = _mm_or_ps(PS_NO_FRACTION, sign); - let r1 = _mm_add_ps(v, s_magic); - let r1 = _mm_sub_ps(r1, s_magic); - let r2 = _mm_and_ps(v, PS_INV_SIGN_MASK); - let mask = _mm_cmple_ps(r2, PS_NO_FRACTION); - let r2 = _mm_andnot_ps(mask, v); - let r1 = _mm_and_ps(r1, mask); - _mm_xor_ps(r1, r2) +pub(crate) unsafe fn dot3_into_m128(lhs: __m128, rhs: __m128) -> __m128 { + let dot_in_x = dot3_in_x(lhs, rhs); + _mm_shuffle_ps(dot_in_x, dot_in_x, 0b00_00_00_00) +} + +#[inline] +pub(crate) unsafe fn dot4(lhs: __m128, rhs: __m128) -> f32 { + _mm_cvtss_f32(dot4_in_x(lhs, rhs)) +} + +#[inline] +pub(crate) unsafe fn dot4_into_m128(lhs: __m128, rhs: __m128) -> __m128 { + let dot_in_x = dot4_in_x(lhs, rhs); + _mm_shuffle_ps(dot_in_x, dot_in_x, 0b00_00_00_00) } #[inline] @@ -86,6 +109,11 @@ pub(crate) unsafe fn m128_ceil(v: __m128) -> __m128 { _mm_or_ps(result, _mm_castsi128_ps(test)) } +#[inline] +pub(crate) unsafe fn m128_abs(v: __m128) -> __m128 { + _mm_and_ps(v, _mm_castsi128_ps(_mm_set1_epi32(0x7f_ff_ff_ff))) +} + #[inline(always)] pub(crate) unsafe fn m128_mul_add(a: __m128, b: __m128, c: __m128) -> __m128 { // Only enable fused multiply-adds here if "fast-math" is enabled and the @@ -106,6 +134,20 @@ pub(crate) unsafe fn m128_neg_mul_sub(a: __m128, b: __m128, c: __m128) -> __m128 _mm_sub_ps(c, _mm_mul_ps(a, b)) } +#[inline] +pub(crate) unsafe fn m128_round(v: __m128) -> __m128 { + // Based on https://github.com/microsoft/DirectXMath `XMVectorRound` + let sign = _mm_and_ps(v, PS_SIGN_MASK); + let s_magic = _mm_or_ps(PS_NO_FRACTION, sign); + let r1 = _mm_add_ps(v, s_magic); + let r1 = _mm_sub_ps(r1, s_magic); + let r2 = _mm_and_ps(v, PS_INV_SIGN_MASK); + let mask = _mm_cmple_ps(r2, PS_NO_FRACTION); + let r2 = _mm_andnot_ps(mask, v); + let r1 = _mm_and_ps(r1, mask); + _mm_xor_ps(r1, r2) +} + /// Returns a vector whose components are the corresponding components of Angles modulo 2PI. #[inline] pub(crate) unsafe fn m128_mod_angles(angles: __m128) -> __m128 { @@ -164,109 +206,17 @@ pub(crate) unsafe fn m128_sin(v: __m128) -> __m128 { result } -// Based on http://gruntthepeon.free.fr/ssemath/sse_mathfun.h -// #[cfg(target_feature = "sse2")] -// unsafe fn sin_cos_sse2(x: __m128) -> (__m128, __m128) { -// let mut sign_bit_sin = x; -// // take the absolute value -// let mut x = _mm_and_ps(x, PS_INV_SIGN_MASK.m128); -// // extract the sign bit (upper one) -// sign_bit_sin = _mm_and_ps(sign_bit_sin, PS_SIGN_MASK.m128); - -// // scale by 4/Pi -// let mut y = _mm_mul_ps(x, PS_CEPHES_FOPI.m128); - -// // store the integer part of y in emm2 -// let mut emm2 = _mm_cvttps_epi32(y); - -// // j=(j+1) & (~1) (see the cephes sources) -// emm2 = _mm_add_epi32(emm2, PI32_1.m128i); -// emm2 = _mm_and_si128(emm2, PI32_INV_1.m128i); -// y = _mm_cvtepi32_ps(emm2); - -// let mut emm4 = emm2; - -// /* get the swap sign flag for the sine */ -// let mut emm0 = _mm_and_si128(emm2, PI32_4.m128i); -// emm0 = _mm_slli_epi32(emm0, 29); -// let swap_sign_bit_sin = _mm_castsi128_ps(emm0); - -// /* get the polynom selection mask for the sine*/ -// emm2 = _mm_and_si128(emm2, PI32_2.m128i); -// emm2 = _mm_cmpeq_epi32(emm2, _mm_setzero_si128()); -// let poly_mask = _mm_castsi128_ps(emm2); - -// /* The magic pass: "Extended precision modular arithmetic" -// x = ((x - y * DP1) - y * DP2) - y * DP3; */ -// let mut xmm1 = PS_MINUS_CEPHES_DP1.m128; -// let mut xmm2 = PS_MINUS_CEPHES_DP2.m128; -// let mut xmm3 = PS_MINUS_CEPHES_DP3.m128; -// xmm1 = _mm_mul_ps(y, xmm1); -// xmm2 = _mm_mul_ps(y, xmm2); -// xmm3 = _mm_mul_ps(y, xmm3); -// x = _mm_add_ps(x, xmm1); -// x = _mm_add_ps(x, xmm2); -// x = _mm_add_ps(x, xmm3); - -// emm4 = _mm_sub_epi32(emm4, PI32_2.m128i); -// emm4 = _mm_andnot_si128(emm4, PI32_4.m128i); -// emm4 = _mm_slli_epi32(emm4, 29); -// let sign_bit_cos = _mm_castsi128_ps(emm4); - -// sign_bit_sin = _mm_xor_ps(sign_bit_sin, swap_sign_bit_sin); - -// // Evaluate the first polynom (0 <= x <= Pi/4) -// let z = _mm_mul_ps(x, x); -// y = PS_COSCOF_P0.m128; - -// y = _mm_mul_ps(y, z); -// y = _mm_add_ps(y, PS_COSCOF_P1.m128); -// y = _mm_mul_ps(y, z); -// y = _mm_add_ps(y, PS_COSCOF_P2.m128); -// y = _mm_mul_ps(y, z); -// y = _mm_mul_ps(y, z); -// let tmp = _mm_mul_ps(z, PS_0_5.m128); -// y = _mm_sub_ps(y, tmp); -// y = _mm_add_ps(y, PS_1_0.m128); - -// // Evaluate the second polynom (Pi/4 <= x <= 0) -// let mut y2 = PS_SINCOF_P0.m128; -// y2 = _mm_mul_ps(y2, z); -// y2 = _mm_add_ps(y2, PS_SINCOF_P1.m128); -// y2 = _mm_mul_ps(y2, z); -// y2 = _mm_add_ps(y2, PS_SINCOF_P2.m128); -// y2 = _mm_mul_ps(y2, z); -// y2 = _mm_mul_ps(y2, x); -// y2 = _mm_add_ps(y2, x); - -// // select the correct result from the two polynoms -// xmm3 = poly_mask; -// let ysin2 = _mm_and_ps(xmm3, y2); -// let ysin1 = _mm_andnot_ps(xmm3, y); -// y2 = _mm_sub_ps(y2, ysin2); -// y = _mm_sub_ps(y, ysin1); - -// xmm1 = _mm_add_ps(ysin1, ysin2); -// xmm2 = _mm_add_ps(y, y2); - -// // update the sign -// ( -// _mm_xor_ps(xmm1, sign_bit_sin), -// _mm_xor_ps(xmm2, sign_bit_cos), -// ) -// } - #[test] fn test_sse2_m128_sin() { - use crate::core::traits::vector::*; + use crate::Vec4; use core::f32::consts::PI; fn test_sse2_m128_sin_angle(a: f32) { let v = unsafe { m128_sin(_mm_set_ps1(a)) }; - let v = v.as_ref_xyzw(); + let v = Vec4(v); let a_sin = a.sin(); // dbg!((a, a_sin, v)); - assert!(v.abs_diff_eq(Vector::splat(a_sin), 1e-6)); + assert!(v.abs_diff_eq(Vec4::splat(a_sin), 1e-6)); } let mut a = -PI; diff --git a/src/swizzles/dvec2_impl_scalar.rs b/src/swizzles/dvec2_impl_scalar.rs index 1cb65e98..3c42e20d 100644 --- a/src/swizzles/dvec2_impl_scalar.rs +++ b/src/swizzles/dvec2_impl_scalar.rs @@ -1,118 +1,196 @@ -// Generated by swizzlegen. Do not edit. +// Generated from swizzle_impl.rs template. Edit the template, not the generated file. + +#![allow(clippy::useless_conversion)] use super::Vec2Swizzles; use crate::{DVec2, DVec3, DVec4}; impl Vec2Swizzles for DVec2 { type Vec3 = DVec3; + type Vec4 = DVec4; + #[inline] + fn xx(self) -> DVec2 { + DVec2 { + x: self.x, + y: self.x, + } + } + + #[inline] + fn xy(self) -> DVec2 { + DVec2 { + x: self.x, + y: self.y, + } + } + + #[inline] + fn yx(self) -> DVec2 { + DVec2 { + x: self.y, + y: self.x, + } + } + + #[inline] + fn yy(self) -> DVec2 { + DVec2 { + x: self.y, + y: self.y, + } + } + + #[inline] + fn xxx(self) -> DVec3 { + DVec3 { + x: self.x, + y: self.x, + z: self.x, + } + } + + #[inline] + fn xxy(self) -> DVec3 { + DVec3 { + x: self.x, + y: self.x, + z: self.y, + } + } + + #[inline] + fn xyx(self) -> DVec3 { + DVec3 { + x: self.x, + y: self.y, + z: self.x, + } + } + + #[inline] + fn xyy(self) -> DVec3 { + DVec3 { + x: self.x, + y: self.y, + z: self.y, + } + } + + #[inline] + fn yxx(self) -> DVec3 { + DVec3 { + x: self.y, + y: self.x, + z: self.x, + } + } + + #[inline] + fn yxy(self) -> DVec3 { + DVec3 { + x: self.y, + y: self.x, + z: self.y, + } + } + + #[inline] + fn yyx(self) -> DVec3 { + DVec3 { + x: self.y, + y: self.y, + z: self.x, + } + } + + #[inline] + fn yyy(self) -> DVec3 { + DVec3 { + x: self.y, + y: self.y, + z: self.y, + } + } + #[inline] fn xxxx(self) -> DVec4 { DVec4::new(self.x, self.x, self.x, self.x) } + #[inline] fn xxxy(self) -> DVec4 { DVec4::new(self.x, self.x, self.x, self.y) } + #[inline] fn xxyx(self) -> DVec4 { DVec4::new(self.x, self.x, self.y, self.x) } + #[inline] fn xxyy(self) -> DVec4 { DVec4::new(self.x, self.x, self.y, self.y) } + #[inline] fn xyxx(self) -> DVec4 { DVec4::new(self.x, self.y, self.x, self.x) } + #[inline] fn xyxy(self) -> DVec4 { DVec4::new(self.x, self.y, self.x, self.y) } + #[inline] fn xyyx(self) -> DVec4 { DVec4::new(self.x, self.y, self.y, self.x) } + #[inline] fn xyyy(self) -> DVec4 { DVec4::new(self.x, self.y, self.y, self.y) } + #[inline] fn yxxx(self) -> DVec4 { DVec4::new(self.y, self.x, self.x, self.x) } + #[inline] fn yxxy(self) -> DVec4 { DVec4::new(self.y, self.x, self.x, self.y) } + #[inline] fn yxyx(self) -> DVec4 { DVec4::new(self.y, self.x, self.y, self.x) } + #[inline] fn yxyy(self) -> DVec4 { DVec4::new(self.y, self.x, self.y, self.y) } + #[inline] fn yyxx(self) -> DVec4 { DVec4::new(self.y, self.y, self.x, self.x) } + #[inline] fn yyxy(self) -> DVec4 { DVec4::new(self.y, self.y, self.x, self.y) } + #[inline] fn yyyx(self) -> DVec4 { DVec4::new(self.y, self.y, self.y, self.x) } + #[inline] fn yyyy(self) -> DVec4 { DVec4::new(self.y, self.y, self.y, self.y) } - #[inline] - fn xxx(self) -> DVec3 { - DVec3::new(self.x, self.x, self.x) - } - #[inline] - fn xxy(self) -> DVec3 { - DVec3::new(self.x, self.x, self.y) - } - #[inline] - fn xyx(self) -> DVec3 { - DVec3::new(self.x, self.y, self.x) - } - #[inline] - fn xyy(self) -> DVec3 { - DVec3::new(self.x, self.y, self.y) - } - #[inline] - fn yxx(self) -> DVec3 { - DVec3::new(self.y, self.x, self.x) - } - #[inline] - fn yxy(self) -> DVec3 { - DVec3::new(self.y, self.x, self.y) - } - #[inline] - fn yyx(self) -> DVec3 { - DVec3::new(self.y, self.y, self.x) - } - #[inline] - fn yyy(self) -> DVec3 { - DVec3::new(self.y, self.y, self.y) - } - #[inline] - fn xx(self) -> Self { - Self::new(self.x, self.x) - } - #[inline] - fn yx(self) -> Self { - Self::new(self.y, self.x) - } - #[inline] - fn yy(self) -> Self { - Self::new(self.y, self.y) - } } diff --git a/src/swizzles/dvec3_impl_scalar.rs b/src/swizzles/dvec3_impl_scalar.rs index 53fab097..2d82b8a9 100644 --- a/src/swizzles/dvec3_impl_scalar.rs +++ b/src/swizzles/dvec3_impl_scalar.rs @@ -1,474 +1,732 @@ -// Generated by swizzlegen. Do not edit. +// Generated from swizzle_impl.rs template. Edit the template, not the generated file. + +#![allow(clippy::useless_conversion)] use super::Vec3Swizzles; use crate::{DVec2, DVec3, DVec4}; impl Vec3Swizzles for DVec3 { type Vec2 = DVec2; + type Vec4 = DVec4; + #[inline] + fn xx(self) -> DVec2 { + DVec2 { + x: self.x, + y: self.x, + } + } + + #[inline] + fn xy(self) -> DVec2 { + DVec2 { + x: self.x, + y: self.y, + } + } + + #[inline] + fn xz(self) -> DVec2 { + DVec2 { + x: self.x, + y: self.z, + } + } + + #[inline] + fn yx(self) -> DVec2 { + DVec2 { + x: self.y, + y: self.x, + } + } + + #[inline] + fn yy(self) -> DVec2 { + DVec2 { + x: self.y, + y: self.y, + } + } + + #[inline] + fn yz(self) -> DVec2 { + DVec2 { + x: self.y, + y: self.z, + } + } + + #[inline] + fn zx(self) -> DVec2 { + DVec2 { + x: self.z, + y: self.x, + } + } + + #[inline] + fn zy(self) -> DVec2 { + DVec2 { + x: self.z, + y: self.y, + } + } + + #[inline] + fn zz(self) -> DVec2 { + DVec2 { + x: self.z, + y: self.z, + } + } + + #[inline] + fn xxx(self) -> DVec3 { + DVec3 { + x: self.x, + y: self.x, + z: self.x, + } + } + + #[inline] + fn xxy(self) -> DVec3 { + DVec3 { + x: self.x, + y: self.x, + z: self.y, + } + } + + #[inline] + fn xxz(self) -> DVec3 { + DVec3 { + x: self.x, + y: self.x, + z: self.z, + } + } + + #[inline] + fn xyx(self) -> DVec3 { + DVec3 { + x: self.x, + y: self.y, + z: self.x, + } + } + + #[inline] + fn xyy(self) -> DVec3 { + DVec3 { + x: self.x, + y: self.y, + z: self.y, + } + } + + #[inline] + fn xyz(self) -> DVec3 { + DVec3 { + x: self.x, + y: self.y, + z: self.z, + } + } + + #[inline] + fn xzx(self) -> DVec3 { + DVec3 { + x: self.x, + y: self.z, + z: self.x, + } + } + + #[inline] + fn xzy(self) -> DVec3 { + DVec3 { + x: self.x, + y: self.z, + z: self.y, + } + } + + #[inline] + fn xzz(self) -> DVec3 { + DVec3 { + x: self.x, + y: self.z, + z: self.z, + } + } + + #[inline] + fn yxx(self) -> DVec3 { + DVec3 { + x: self.y, + y: self.x, + z: self.x, + } + } + + #[inline] + fn yxy(self) -> DVec3 { + DVec3 { + x: self.y, + y: self.x, + z: self.y, + } + } + + #[inline] + fn yxz(self) -> DVec3 { + DVec3 { + x: self.y, + y: self.x, + z: self.z, + } + } + + #[inline] + fn yyx(self) -> DVec3 { + DVec3 { + x: self.y, + y: self.y, + z: self.x, + } + } + + #[inline] + fn yyy(self) -> DVec3 { + DVec3 { + x: self.y, + y: self.y, + z: self.y, + } + } + + #[inline] + fn yyz(self) -> DVec3 { + DVec3 { + x: self.y, + y: self.y, + z: self.z, + } + } + + #[inline] + fn yzx(self) -> DVec3 { + DVec3 { + x: self.y, + y: self.z, + z: self.x, + } + } + + #[inline] + fn yzy(self) -> DVec3 { + DVec3 { + x: self.y, + y: self.z, + z: self.y, + } + } + + #[inline] + fn yzz(self) -> DVec3 { + DVec3 { + x: self.y, + y: self.z, + z: self.z, + } + } + + #[inline] + fn zxx(self) -> DVec3 { + DVec3 { + x: self.z, + y: self.x, + z: self.x, + } + } + + #[inline] + fn zxy(self) -> DVec3 { + DVec3 { + x: self.z, + y: self.x, + z: self.y, + } + } + + #[inline] + fn zxz(self) -> DVec3 { + DVec3 { + x: self.z, + y: self.x, + z: self.z, + } + } + + #[inline] + fn zyx(self) -> DVec3 { + DVec3 { + x: self.z, + y: self.y, + z: self.x, + } + } + + #[inline] + fn zyy(self) -> DVec3 { + DVec3 { + x: self.z, + y: self.y, + z: self.y, + } + } + + #[inline] + fn zyz(self) -> DVec3 { + DVec3 { + x: self.z, + y: self.y, + z: self.z, + } + } + + #[inline] + fn zzx(self) -> DVec3 { + DVec3 { + x: self.z, + y: self.z, + z: self.x, + } + } + + #[inline] + fn zzy(self) -> DVec3 { + DVec3 { + x: self.z, + y: self.z, + z: self.y, + } + } + + #[inline] + fn zzz(self) -> DVec3 { + DVec3 { + x: self.z, + y: self.z, + z: self.z, + } + } + #[inline] fn xxxx(self) -> DVec4 { DVec4::new(self.x, self.x, self.x, self.x) } + #[inline] fn xxxy(self) -> DVec4 { DVec4::new(self.x, self.x, self.x, self.y) } + #[inline] fn xxxz(self) -> DVec4 { DVec4::new(self.x, self.x, self.x, self.z) } + #[inline] fn xxyx(self) -> DVec4 { DVec4::new(self.x, self.x, self.y, self.x) } + #[inline] fn xxyy(self) -> DVec4 { DVec4::new(self.x, self.x, self.y, self.y) } + #[inline] fn xxyz(self) -> DVec4 { DVec4::new(self.x, self.x, self.y, self.z) } + #[inline] fn xxzx(self) -> DVec4 { DVec4::new(self.x, self.x, self.z, self.x) } + #[inline] fn xxzy(self) -> DVec4 { DVec4::new(self.x, self.x, self.z, self.y) } + #[inline] fn xxzz(self) -> DVec4 { DVec4::new(self.x, self.x, self.z, self.z) } + #[inline] fn xyxx(self) -> DVec4 { DVec4::new(self.x, self.y, self.x, self.x) } + #[inline] fn xyxy(self) -> DVec4 { DVec4::new(self.x, self.y, self.x, self.y) } + #[inline] fn xyxz(self) -> DVec4 { DVec4::new(self.x, self.y, self.x, self.z) } + #[inline] fn xyyx(self) -> DVec4 { DVec4::new(self.x, self.y, self.y, self.x) } + #[inline] fn xyyy(self) -> DVec4 { DVec4::new(self.x, self.y, self.y, self.y) } + #[inline] fn xyyz(self) -> DVec4 { DVec4::new(self.x, self.y, self.y, self.z) } + #[inline] fn xyzx(self) -> DVec4 { DVec4::new(self.x, self.y, self.z, self.x) } + #[inline] fn xyzy(self) -> DVec4 { DVec4::new(self.x, self.y, self.z, self.y) } + #[inline] fn xyzz(self) -> DVec4 { DVec4::new(self.x, self.y, self.z, self.z) } + #[inline] fn xzxx(self) -> DVec4 { DVec4::new(self.x, self.z, self.x, self.x) } + #[inline] fn xzxy(self) -> DVec4 { DVec4::new(self.x, self.z, self.x, self.y) } + #[inline] fn xzxz(self) -> DVec4 { DVec4::new(self.x, self.z, self.x, self.z) } + #[inline] fn xzyx(self) -> DVec4 { DVec4::new(self.x, self.z, self.y, self.x) } + #[inline] fn xzyy(self) -> DVec4 { DVec4::new(self.x, self.z, self.y, self.y) } + #[inline] fn xzyz(self) -> DVec4 { DVec4::new(self.x, self.z, self.y, self.z) } + #[inline] fn xzzx(self) -> DVec4 { DVec4::new(self.x, self.z, self.z, self.x) } + #[inline] fn xzzy(self) -> DVec4 { DVec4::new(self.x, self.z, self.z, self.y) } + #[inline] fn xzzz(self) -> DVec4 { DVec4::new(self.x, self.z, self.z, self.z) } + #[inline] fn yxxx(self) -> DVec4 { DVec4::new(self.y, self.x, self.x, self.x) } + #[inline] fn yxxy(self) -> DVec4 { DVec4::new(self.y, self.x, self.x, self.y) } + #[inline] fn yxxz(self) -> DVec4 { DVec4::new(self.y, self.x, self.x, self.z) } + #[inline] fn yxyx(self) -> DVec4 { DVec4::new(self.y, self.x, self.y, self.x) } + #[inline] fn yxyy(self) -> DVec4 { DVec4::new(self.y, self.x, self.y, self.y) } + #[inline] fn yxyz(self) -> DVec4 { DVec4::new(self.y, self.x, self.y, self.z) } + #[inline] fn yxzx(self) -> DVec4 { DVec4::new(self.y, self.x, self.z, self.x) } + #[inline] fn yxzy(self) -> DVec4 { DVec4::new(self.y, self.x, self.z, self.y) } + #[inline] fn yxzz(self) -> DVec4 { DVec4::new(self.y, self.x, self.z, self.z) } + #[inline] fn yyxx(self) -> DVec4 { DVec4::new(self.y, self.y, self.x, self.x) } + #[inline] fn yyxy(self) -> DVec4 { DVec4::new(self.y, self.y, self.x, self.y) } + #[inline] fn yyxz(self) -> DVec4 { DVec4::new(self.y, self.y, self.x, self.z) } + #[inline] fn yyyx(self) -> DVec4 { DVec4::new(self.y, self.y, self.y, self.x) } + #[inline] fn yyyy(self) -> DVec4 { DVec4::new(self.y, self.y, self.y, self.y) } + #[inline] fn yyyz(self) -> DVec4 { DVec4::new(self.y, self.y, self.y, self.z) } + #[inline] fn yyzx(self) -> DVec4 { DVec4::new(self.y, self.y, self.z, self.x) } + #[inline] fn yyzy(self) -> DVec4 { DVec4::new(self.y, self.y, self.z, self.y) } + #[inline] fn yyzz(self) -> DVec4 { DVec4::new(self.y, self.y, self.z, self.z) } + #[inline] fn yzxx(self) -> DVec4 { DVec4::new(self.y, self.z, self.x, self.x) } + #[inline] fn yzxy(self) -> DVec4 { DVec4::new(self.y, self.z, self.x, self.y) } + #[inline] fn yzxz(self) -> DVec4 { DVec4::new(self.y, self.z, self.x, self.z) } + #[inline] fn yzyx(self) -> DVec4 { DVec4::new(self.y, self.z, self.y, self.x) } + #[inline] fn yzyy(self) -> DVec4 { DVec4::new(self.y, self.z, self.y, self.y) } + #[inline] fn yzyz(self) -> DVec4 { DVec4::new(self.y, self.z, self.y, self.z) } + #[inline] fn yzzx(self) -> DVec4 { DVec4::new(self.y, self.z, self.z, self.x) } + #[inline] fn yzzy(self) -> DVec4 { DVec4::new(self.y, self.z, self.z, self.y) } + #[inline] fn yzzz(self) -> DVec4 { DVec4::new(self.y, self.z, self.z, self.z) } + #[inline] fn zxxx(self) -> DVec4 { DVec4::new(self.z, self.x, self.x, self.x) } + #[inline] fn zxxy(self) -> DVec4 { DVec4::new(self.z, self.x, self.x, self.y) } + #[inline] fn zxxz(self) -> DVec4 { DVec4::new(self.z, self.x, self.x, self.z) } + #[inline] fn zxyx(self) -> DVec4 { DVec4::new(self.z, self.x, self.y, self.x) } + #[inline] fn zxyy(self) -> DVec4 { DVec4::new(self.z, self.x, self.y, self.y) } + #[inline] fn zxyz(self) -> DVec4 { DVec4::new(self.z, self.x, self.y, self.z) } + #[inline] fn zxzx(self) -> DVec4 { DVec4::new(self.z, self.x, self.z, self.x) } + #[inline] fn zxzy(self) -> DVec4 { DVec4::new(self.z, self.x, self.z, self.y) } + #[inline] fn zxzz(self) -> DVec4 { DVec4::new(self.z, self.x, self.z, self.z) } + #[inline] fn zyxx(self) -> DVec4 { DVec4::new(self.z, self.y, self.x, self.x) } + #[inline] fn zyxy(self) -> DVec4 { DVec4::new(self.z, self.y, self.x, self.y) } + #[inline] fn zyxz(self) -> DVec4 { DVec4::new(self.z, self.y, self.x, self.z) } + #[inline] fn zyyx(self) -> DVec4 { DVec4::new(self.z, self.y, self.y, self.x) } + #[inline] fn zyyy(self) -> DVec4 { DVec4::new(self.z, self.y, self.y, self.y) } + #[inline] fn zyyz(self) -> DVec4 { DVec4::new(self.z, self.y, self.y, self.z) } + #[inline] fn zyzx(self) -> DVec4 { DVec4::new(self.z, self.y, self.z, self.x) } + #[inline] fn zyzy(self) -> DVec4 { DVec4::new(self.z, self.y, self.z, self.y) } + #[inline] fn zyzz(self) -> DVec4 { DVec4::new(self.z, self.y, self.z, self.z) } + #[inline] fn zzxx(self) -> DVec4 { DVec4::new(self.z, self.z, self.x, self.x) } + #[inline] fn zzxy(self) -> DVec4 { DVec4::new(self.z, self.z, self.x, self.y) } + #[inline] fn zzxz(self) -> DVec4 { DVec4::new(self.z, self.z, self.x, self.z) } + #[inline] fn zzyx(self) -> DVec4 { DVec4::new(self.z, self.z, self.y, self.x) } + #[inline] fn zzyy(self) -> DVec4 { DVec4::new(self.z, self.z, self.y, self.y) } + #[inline] fn zzyz(self) -> DVec4 { DVec4::new(self.z, self.z, self.y, self.z) } + #[inline] fn zzzx(self) -> DVec4 { DVec4::new(self.z, self.z, self.z, self.x) } + #[inline] fn zzzy(self) -> DVec4 { DVec4::new(self.z, self.z, self.z, self.y) } + #[inline] fn zzzz(self) -> DVec4 { DVec4::new(self.z, self.z, self.z, self.z) } - #[inline] - fn xxx(self) -> Self { - Self::new(self.x, self.x, self.x) - } - #[inline] - fn xxy(self) -> Self { - Self::new(self.x, self.x, self.y) - } - #[inline] - fn xxz(self) -> Self { - Self::new(self.x, self.x, self.z) - } - #[inline] - fn xyx(self) -> Self { - Self::new(self.x, self.y, self.x) - } - #[inline] - fn xyy(self) -> Self { - Self::new(self.x, self.y, self.y) - } - #[inline] - fn xzx(self) -> Self { - Self::new(self.x, self.z, self.x) - } - #[inline] - fn xzy(self) -> Self { - Self::new(self.x, self.z, self.y) - } - #[inline] - fn xzz(self) -> Self { - Self::new(self.x, self.z, self.z) - } - #[inline] - fn yxx(self) -> Self { - Self::new(self.y, self.x, self.x) - } - #[inline] - fn yxy(self) -> Self { - Self::new(self.y, self.x, self.y) - } - #[inline] - fn yxz(self) -> Self { - Self::new(self.y, self.x, self.z) - } - #[inline] - fn yyx(self) -> Self { - Self::new(self.y, self.y, self.x) - } - #[inline] - fn yyy(self) -> Self { - Self::new(self.y, self.y, self.y) - } - #[inline] - fn yyz(self) -> Self { - Self::new(self.y, self.y, self.z) - } - #[inline] - fn yzx(self) -> Self { - Self::new(self.y, self.z, self.x) - } - #[inline] - fn yzy(self) -> Self { - Self::new(self.y, self.z, self.y) - } - #[inline] - fn yzz(self) -> Self { - Self::new(self.y, self.z, self.z) - } - #[inline] - fn zxx(self) -> Self { - Self::new(self.z, self.x, self.x) - } - #[inline] - fn zxy(self) -> Self { - Self::new(self.z, self.x, self.y) - } - #[inline] - fn zxz(self) -> Self { - Self::new(self.z, self.x, self.z) - } - #[inline] - fn zyx(self) -> Self { - Self::new(self.z, self.y, self.x) - } - #[inline] - fn zyy(self) -> Self { - Self::new(self.z, self.y, self.y) - } - #[inline] - fn zyz(self) -> Self { - Self::new(self.z, self.y, self.z) - } - #[inline] - fn zzx(self) -> Self { - Self::new(self.z, self.z, self.x) - } - #[inline] - fn zzy(self) -> Self { - Self::new(self.z, self.z, self.y) - } - #[inline] - fn zzz(self) -> Self { - Self::new(self.z, self.z, self.z) - } - #[inline] - fn xx(self) -> DVec2 { - DVec2::new(self.x, self.x) - } - #[inline] - fn xy(self) -> DVec2 { - DVec2::new(self.x, self.y) - } - #[inline] - fn xz(self) -> DVec2 { - DVec2::new(self.x, self.z) - } - #[inline] - fn yx(self) -> DVec2 { - DVec2::new(self.y, self.x) - } - #[inline] - fn yy(self) -> DVec2 { - DVec2::new(self.y, self.y) - } - #[inline] - fn yz(self) -> DVec2 { - DVec2::new(self.y, self.z) - } - #[inline] - fn zx(self) -> DVec2 { - DVec2::new(self.z, self.x) - } - #[inline] - fn zy(self) -> DVec2 { - DVec2::new(self.z, self.y) - } - #[inline] - fn zz(self) -> DVec2 { - DVec2::new(self.z, self.z) - } } diff --git a/src/swizzles/dvec4_impl_scalar.rs b/src/swizzles/dvec4_impl_scalar.rs index 4b6740be..fa191b0b 100644 --- a/src/swizzles/dvec4_impl_scalar.rs +++ b/src/swizzles/dvec4_impl_scalar.rs @@ -1,1350 +1,1996 @@ -// Generated by swizzlegen. Do not edit. +// Generated from swizzle_impl.rs template. Edit the template, not the generated file. + +#![allow(clippy::useless_conversion)] use super::Vec4Swizzles; use crate::{DVec2, DVec3, DVec4}; impl Vec4Swizzles for DVec4 { type Vec2 = DVec2; + type Vec3 = DVec3; #[inline] - fn xxxx(self) -> DVec4 { - DVec4::new(self.x, self.x, self.x, self.x) + fn xx(self) -> DVec2 { + DVec2 { + x: self.x, + y: self.x, + } } + #[inline] - fn xxxy(self) -> DVec4 { - DVec4::new(self.x, self.x, self.x, self.y) + fn xy(self) -> DVec2 { + DVec2 { + x: self.x, + y: self.y, + } } + #[inline] - fn xxxz(self) -> DVec4 { - DVec4::new(self.x, self.x, self.x, self.z) + fn xz(self) -> DVec2 { + DVec2 { + x: self.x, + y: self.z, + } } + #[inline] - fn xxxw(self) -> DVec4 { - DVec4::new(self.x, self.x, self.x, self.w) + fn xw(self) -> DVec2 { + DVec2 { + x: self.x, + y: self.w, + } } + #[inline] - fn xxyx(self) -> DVec4 { - DVec4::new(self.x, self.x, self.y, self.x) + fn yx(self) -> DVec2 { + DVec2 { + x: self.y, + y: self.x, + } } + #[inline] - fn xxyy(self) -> DVec4 { - DVec4::new(self.x, self.x, self.y, self.y) + fn yy(self) -> DVec2 { + DVec2 { + x: self.y, + y: self.y, + } } + #[inline] - fn xxyz(self) -> DVec4 { - DVec4::new(self.x, self.x, self.y, self.z) + fn yz(self) -> DVec2 { + DVec2 { + x: self.y, + y: self.z, + } } + #[inline] - fn xxyw(self) -> DVec4 { - DVec4::new(self.x, self.x, self.y, self.w) + fn yw(self) -> DVec2 { + DVec2 { + x: self.y, + y: self.w, + } } + #[inline] - fn xxzx(self) -> DVec4 { - DVec4::new(self.x, self.x, self.z, self.x) + fn zx(self) -> DVec2 { + DVec2 { + x: self.z, + y: self.x, + } } + #[inline] - fn xxzy(self) -> DVec4 { - DVec4::new(self.x, self.x, self.z, self.y) + fn zy(self) -> DVec2 { + DVec2 { + x: self.z, + y: self.y, + } } + #[inline] - fn xxzz(self) -> DVec4 { - DVec4::new(self.x, self.x, self.z, self.z) + fn zz(self) -> DVec2 { + DVec2 { + x: self.z, + y: self.z, + } } + #[inline] - fn xxzw(self) -> DVec4 { - DVec4::new(self.x, self.x, self.z, self.w) + fn zw(self) -> DVec2 { + DVec2 { + x: self.z, + y: self.w, + } } + #[inline] - fn xxwx(self) -> DVec4 { - DVec4::new(self.x, self.x, self.w, self.x) + fn wx(self) -> DVec2 { + DVec2 { + x: self.w, + y: self.x, + } } + #[inline] - fn xxwy(self) -> DVec4 { - DVec4::new(self.x, self.x, self.w, self.y) + fn wy(self) -> DVec2 { + DVec2 { + x: self.w, + y: self.y, + } } + #[inline] - fn xxwz(self) -> DVec4 { - DVec4::new(self.x, self.x, self.w, self.z) + fn wz(self) -> DVec2 { + DVec2 { + x: self.w, + y: self.z, + } } + #[inline] - fn xxww(self) -> DVec4 { - DVec4::new(self.x, self.x, self.w, self.w) + fn ww(self) -> DVec2 { + DVec2 { + x: self.w, + y: self.w, + } } + #[inline] - fn xyxx(self) -> DVec4 { - DVec4::new(self.x, self.y, self.x, self.x) + fn xxx(self) -> DVec3 { + DVec3 { + x: self.x, + y: self.x, + z: self.x, + } } + #[inline] - fn xyxy(self) -> DVec4 { - DVec4::new(self.x, self.y, self.x, self.y) + fn xxy(self) -> DVec3 { + DVec3 { + x: self.x, + y: self.x, + z: self.y, + } } + #[inline] - fn xyxz(self) -> DVec4 { - DVec4::new(self.x, self.y, self.x, self.z) + fn xxz(self) -> DVec3 { + DVec3 { + x: self.x, + y: self.x, + z: self.z, + } } + #[inline] - fn xyxw(self) -> DVec4 { - DVec4::new(self.x, self.y, self.x, self.w) + fn xxw(self) -> DVec3 { + DVec3 { + x: self.x, + y: self.x, + z: self.w, + } } + #[inline] - fn xyyx(self) -> DVec4 { - DVec4::new(self.x, self.y, self.y, self.x) + fn xyx(self) -> DVec3 { + DVec3 { + x: self.x, + y: self.y, + z: self.x, + } } + #[inline] - fn xyyy(self) -> DVec4 { - DVec4::new(self.x, self.y, self.y, self.y) + fn xyy(self) -> DVec3 { + DVec3 { + x: self.x, + y: self.y, + z: self.y, + } } + #[inline] - fn xyyz(self) -> DVec4 { - DVec4::new(self.x, self.y, self.y, self.z) + fn xyz(self) -> DVec3 { + DVec3 { + x: self.x, + y: self.y, + z: self.z, + } } + #[inline] - fn xyyw(self) -> DVec4 { - DVec4::new(self.x, self.y, self.y, self.w) + fn xyw(self) -> DVec3 { + DVec3 { + x: self.x, + y: self.y, + z: self.w, + } } + #[inline] - fn xyzx(self) -> DVec4 { - DVec4::new(self.x, self.y, self.z, self.x) + fn xzx(self) -> DVec3 { + DVec3 { + x: self.x, + y: self.z, + z: self.x, + } } + #[inline] - fn xyzy(self) -> DVec4 { - DVec4::new(self.x, self.y, self.z, self.y) + fn xzy(self) -> DVec3 { + DVec3 { + x: self.x, + y: self.z, + z: self.y, + } } + #[inline] - fn xyzz(self) -> DVec4 { - DVec4::new(self.x, self.y, self.z, self.z) + fn xzz(self) -> DVec3 { + DVec3 { + x: self.x, + y: self.z, + z: self.z, + } } + #[inline] - fn xywx(self) -> DVec4 { - DVec4::new(self.x, self.y, self.w, self.x) + fn xzw(self) -> DVec3 { + DVec3 { + x: self.x, + y: self.z, + z: self.w, + } } + #[inline] - fn xywy(self) -> DVec4 { - DVec4::new(self.x, self.y, self.w, self.y) + fn xwx(self) -> DVec3 { + DVec3 { + x: self.x, + y: self.w, + z: self.x, + } } + #[inline] - fn xywz(self) -> DVec4 { - DVec4::new(self.x, self.y, self.w, self.z) + fn xwy(self) -> DVec3 { + DVec3 { + x: self.x, + y: self.w, + z: self.y, + } } + #[inline] - fn xyww(self) -> DVec4 { - DVec4::new(self.x, self.y, self.w, self.w) + fn xwz(self) -> DVec3 { + DVec3 { + x: self.x, + y: self.w, + z: self.z, + } } + #[inline] - fn xzxx(self) -> DVec4 { - DVec4::new(self.x, self.z, self.x, self.x) + fn xww(self) -> DVec3 { + DVec3 { + x: self.x, + y: self.w, + z: self.w, + } } + #[inline] - fn xzxy(self) -> DVec4 { - DVec4::new(self.x, self.z, self.x, self.y) + fn yxx(self) -> DVec3 { + DVec3 { + x: self.y, + y: self.x, + z: self.x, + } } + #[inline] - fn xzxz(self) -> DVec4 { - DVec4::new(self.x, self.z, self.x, self.z) + fn yxy(self) -> DVec3 { + DVec3 { + x: self.y, + y: self.x, + z: self.y, + } } + #[inline] - fn xzxw(self) -> DVec4 { - DVec4::new(self.x, self.z, self.x, self.w) + fn yxz(self) -> DVec3 { + DVec3 { + x: self.y, + y: self.x, + z: self.z, + } } + #[inline] - fn xzyx(self) -> DVec4 { - DVec4::new(self.x, self.z, self.y, self.x) + fn yxw(self) -> DVec3 { + DVec3 { + x: self.y, + y: self.x, + z: self.w, + } } + #[inline] - fn xzyy(self) -> DVec4 { - DVec4::new(self.x, self.z, self.y, self.y) + fn yyx(self) -> DVec3 { + DVec3 { + x: self.y, + y: self.y, + z: self.x, + } } + #[inline] - fn xzyz(self) -> DVec4 { - DVec4::new(self.x, self.z, self.y, self.z) + fn yyy(self) -> DVec3 { + DVec3 { + x: self.y, + y: self.y, + z: self.y, + } } + #[inline] - fn xzyw(self) -> DVec4 { - DVec4::new(self.x, self.z, self.y, self.w) + fn yyz(self) -> DVec3 { + DVec3 { + x: self.y, + y: self.y, + z: self.z, + } } + #[inline] - fn xzzx(self) -> DVec4 { - DVec4::new(self.x, self.z, self.z, self.x) + fn yyw(self) -> DVec3 { + DVec3 { + x: self.y, + y: self.y, + z: self.w, + } } + #[inline] - fn xzzy(self) -> DVec4 { - DVec4::new(self.x, self.z, self.z, self.y) + fn yzx(self) -> DVec3 { + DVec3 { + x: self.y, + y: self.z, + z: self.x, + } } + #[inline] - fn xzzz(self) -> DVec4 { - DVec4::new(self.x, self.z, self.z, self.z) + fn yzy(self) -> DVec3 { + DVec3 { + x: self.y, + y: self.z, + z: self.y, + } } + #[inline] - fn xzzw(self) -> DVec4 { - DVec4::new(self.x, self.z, self.z, self.w) + fn yzz(self) -> DVec3 { + DVec3 { + x: self.y, + y: self.z, + z: self.z, + } } + #[inline] - fn xzwx(self) -> DVec4 { - DVec4::new(self.x, self.z, self.w, self.x) + fn yzw(self) -> DVec3 { + DVec3 { + x: self.y, + y: self.z, + z: self.w, + } } + #[inline] - fn xzwy(self) -> DVec4 { - DVec4::new(self.x, self.z, self.w, self.y) + fn ywx(self) -> DVec3 { + DVec3 { + x: self.y, + y: self.w, + z: self.x, + } } + #[inline] - fn xzwz(self) -> DVec4 { - DVec4::new(self.x, self.z, self.w, self.z) + fn ywy(self) -> DVec3 { + DVec3 { + x: self.y, + y: self.w, + z: self.y, + } } + #[inline] - fn xzww(self) -> DVec4 { - DVec4::new(self.x, self.z, self.w, self.w) + fn ywz(self) -> DVec3 { + DVec3 { + x: self.y, + y: self.w, + z: self.z, + } } + #[inline] - fn xwxx(self) -> DVec4 { - DVec4::new(self.x, self.w, self.x, self.x) + fn yww(self) -> DVec3 { + DVec3 { + x: self.y, + y: self.w, + z: self.w, + } } + #[inline] - fn xwxy(self) -> DVec4 { - DVec4::new(self.x, self.w, self.x, self.y) + fn zxx(self) -> DVec3 { + DVec3 { + x: self.z, + y: self.x, + z: self.x, + } } + #[inline] - fn xwxz(self) -> DVec4 { - DVec4::new(self.x, self.w, self.x, self.z) + fn zxy(self) -> DVec3 { + DVec3 { + x: self.z, + y: self.x, + z: self.y, + } } + #[inline] - fn xwxw(self) -> DVec4 { - DVec4::new(self.x, self.w, self.x, self.w) + fn zxz(self) -> DVec3 { + DVec3 { + x: self.z, + y: self.x, + z: self.z, + } } + #[inline] - fn xwyx(self) -> DVec4 { - DVec4::new(self.x, self.w, self.y, self.x) + fn zxw(self) -> DVec3 { + DVec3 { + x: self.z, + y: self.x, + z: self.w, + } } + #[inline] - fn xwyy(self) -> DVec4 { - DVec4::new(self.x, self.w, self.y, self.y) + fn zyx(self) -> DVec3 { + DVec3 { + x: self.z, + y: self.y, + z: self.x, + } } + #[inline] - fn xwyz(self) -> DVec4 { - DVec4::new(self.x, self.w, self.y, self.z) + fn zyy(self) -> DVec3 { + DVec3 { + x: self.z, + y: self.y, + z: self.y, + } } + #[inline] - fn xwyw(self) -> DVec4 { - DVec4::new(self.x, self.w, self.y, self.w) + fn zyz(self) -> DVec3 { + DVec3 { + x: self.z, + y: self.y, + z: self.z, + } } + #[inline] - fn xwzx(self) -> DVec4 { - DVec4::new(self.x, self.w, self.z, self.x) + fn zyw(self) -> DVec3 { + DVec3 { + x: self.z, + y: self.y, + z: self.w, + } } + #[inline] - fn xwzy(self) -> DVec4 { - DVec4::new(self.x, self.w, self.z, self.y) + fn zzx(self) -> DVec3 { + DVec3 { + x: self.z, + y: self.z, + z: self.x, + } } + #[inline] - fn xwzz(self) -> DVec4 { - DVec4::new(self.x, self.w, self.z, self.z) + fn zzy(self) -> DVec3 { + DVec3 { + x: self.z, + y: self.z, + z: self.y, + } } + #[inline] - fn xwzw(self) -> DVec4 { - DVec4::new(self.x, self.w, self.z, self.w) + fn zzz(self) -> DVec3 { + DVec3 { + x: self.z, + y: self.z, + z: self.z, + } } + #[inline] - fn xwwx(self) -> DVec4 { - DVec4::new(self.x, self.w, self.w, self.x) + fn zzw(self) -> DVec3 { + DVec3 { + x: self.z, + y: self.z, + z: self.w, + } } + #[inline] - fn xwwy(self) -> DVec4 { - DVec4::new(self.x, self.w, self.w, self.y) + fn zwx(self) -> DVec3 { + DVec3 { + x: self.z, + y: self.w, + z: self.x, + } } + #[inline] - fn xwwz(self) -> DVec4 { - DVec4::new(self.x, self.w, self.w, self.z) + fn zwy(self) -> DVec3 { + DVec3 { + x: self.z, + y: self.w, + z: self.y, + } } + #[inline] - fn xwww(self) -> DVec4 { - DVec4::new(self.x, self.w, self.w, self.w) + fn zwz(self) -> DVec3 { + DVec3 { + x: self.z, + y: self.w, + z: self.z, + } } + #[inline] - fn yxxx(self) -> DVec4 { - DVec4::new(self.y, self.x, self.x, self.x) + fn zww(self) -> DVec3 { + DVec3 { + x: self.z, + y: self.w, + z: self.w, + } } + #[inline] - fn yxxy(self) -> DVec4 { - DVec4::new(self.y, self.x, self.x, self.y) + fn wxx(self) -> DVec3 { + DVec3 { + x: self.w, + y: self.x, + z: self.x, + } } + #[inline] - fn yxxz(self) -> DVec4 { - DVec4::new(self.y, self.x, self.x, self.z) + fn wxy(self) -> DVec3 { + DVec3 { + x: self.w, + y: self.x, + z: self.y, + } } + #[inline] - fn yxxw(self) -> DVec4 { - DVec4::new(self.y, self.x, self.x, self.w) + fn wxz(self) -> DVec3 { + DVec3 { + x: self.w, + y: self.x, + z: self.z, + } } + #[inline] - fn yxyx(self) -> DVec4 { - DVec4::new(self.y, self.x, self.y, self.x) + fn wxw(self) -> DVec3 { + DVec3 { + x: self.w, + y: self.x, + z: self.w, + } } + #[inline] - fn yxyy(self) -> DVec4 { - DVec4::new(self.y, self.x, self.y, self.y) + fn wyx(self) -> DVec3 { + DVec3 { + x: self.w, + y: self.y, + z: self.x, + } } + #[inline] - fn yxyz(self) -> DVec4 { - DVec4::new(self.y, self.x, self.y, self.z) + fn wyy(self) -> DVec3 { + DVec3 { + x: self.w, + y: self.y, + z: self.y, + } } + #[inline] - fn yxyw(self) -> DVec4 { - DVec4::new(self.y, self.x, self.y, self.w) + fn wyz(self) -> DVec3 { + DVec3 { + x: self.w, + y: self.y, + z: self.z, + } } + #[inline] - fn yxzx(self) -> DVec4 { - DVec4::new(self.y, self.x, self.z, self.x) + fn wyw(self) -> DVec3 { + DVec3 { + x: self.w, + y: self.y, + z: self.w, + } } + #[inline] - fn yxzy(self) -> DVec4 { - DVec4::new(self.y, self.x, self.z, self.y) + fn wzx(self) -> DVec3 { + DVec3 { + x: self.w, + y: self.z, + z: self.x, + } } + #[inline] - fn yxzz(self) -> DVec4 { - DVec4::new(self.y, self.x, self.z, self.z) + fn wzy(self) -> DVec3 { + DVec3 { + x: self.w, + y: self.z, + z: self.y, + } } + #[inline] - fn yxzw(self) -> DVec4 { - DVec4::new(self.y, self.x, self.z, self.w) + fn wzz(self) -> DVec3 { + DVec3 { + x: self.w, + y: self.z, + z: self.z, + } } + #[inline] - fn yxwx(self) -> DVec4 { - DVec4::new(self.y, self.x, self.w, self.x) + fn wzw(self) -> DVec3 { + DVec3 { + x: self.w, + y: self.z, + z: self.w, + } } + #[inline] - fn yxwy(self) -> DVec4 { - DVec4::new(self.y, self.x, self.w, self.y) + fn wwx(self) -> DVec3 { + DVec3 { + x: self.w, + y: self.w, + z: self.x, + } } + #[inline] - fn yxwz(self) -> DVec4 { - DVec4::new(self.y, self.x, self.w, self.z) + fn wwy(self) -> DVec3 { + DVec3 { + x: self.w, + y: self.w, + z: self.y, + } } + #[inline] - fn yxww(self) -> DVec4 { - DVec4::new(self.y, self.x, self.w, self.w) + fn wwz(self) -> DVec3 { + DVec3 { + x: self.w, + y: self.w, + z: self.z, + } } + #[inline] - fn yyxx(self) -> DVec4 { - DVec4::new(self.y, self.y, self.x, self.x) + fn www(self) -> DVec3 { + DVec3 { + x: self.w, + y: self.w, + z: self.w, + } } + #[inline] - fn yyxy(self) -> DVec4 { - DVec4::new(self.y, self.y, self.x, self.y) + fn xxxx(self) -> DVec4 { + DVec4::new(self.x, self.x, self.x, self.x) } + #[inline] - fn yyxz(self) -> DVec4 { - DVec4::new(self.y, self.y, self.x, self.z) + fn xxxy(self) -> DVec4 { + DVec4::new(self.x, self.x, self.x, self.y) } + #[inline] - fn yyxw(self) -> DVec4 { - DVec4::new(self.y, self.y, self.x, self.w) + fn xxxz(self) -> DVec4 { + DVec4::new(self.x, self.x, self.x, self.z) } + #[inline] - fn yyyx(self) -> DVec4 { - DVec4::new(self.y, self.y, self.y, self.x) + fn xxxw(self) -> DVec4 { + DVec4::new(self.x, self.x, self.x, self.w) } + #[inline] - fn yyyy(self) -> DVec4 { - DVec4::new(self.y, self.y, self.y, self.y) + fn xxyx(self) -> DVec4 { + DVec4::new(self.x, self.x, self.y, self.x) } + #[inline] - fn yyyz(self) -> DVec4 { - DVec4::new(self.y, self.y, self.y, self.z) + fn xxyy(self) -> DVec4 { + DVec4::new(self.x, self.x, self.y, self.y) } + #[inline] - fn yyyw(self) -> DVec4 { - DVec4::new(self.y, self.y, self.y, self.w) + fn xxyz(self) -> DVec4 { + DVec4::new(self.x, self.x, self.y, self.z) } + #[inline] - fn yyzx(self) -> DVec4 { - DVec4::new(self.y, self.y, self.z, self.x) + fn xxyw(self) -> DVec4 { + DVec4::new(self.x, self.x, self.y, self.w) } + #[inline] - fn yyzy(self) -> DVec4 { - DVec4::new(self.y, self.y, self.z, self.y) + fn xxzx(self) -> DVec4 { + DVec4::new(self.x, self.x, self.z, self.x) } + #[inline] - fn yyzz(self) -> DVec4 { - DVec4::new(self.y, self.y, self.z, self.z) + fn xxzy(self) -> DVec4 { + DVec4::new(self.x, self.x, self.z, self.y) } + #[inline] - fn yyzw(self) -> DVec4 { - DVec4::new(self.y, self.y, self.z, self.w) + fn xxzz(self) -> DVec4 { + DVec4::new(self.x, self.x, self.z, self.z) } + #[inline] - fn yywx(self) -> DVec4 { - DVec4::new(self.y, self.y, self.w, self.x) + fn xxzw(self) -> DVec4 { + DVec4::new(self.x, self.x, self.z, self.w) } + #[inline] - fn yywy(self) -> DVec4 { - DVec4::new(self.y, self.y, self.w, self.y) + fn xxwx(self) -> DVec4 { + DVec4::new(self.x, self.x, self.w, self.x) } + #[inline] - fn yywz(self) -> DVec4 { - DVec4::new(self.y, self.y, self.w, self.z) + fn xxwy(self) -> DVec4 { + DVec4::new(self.x, self.x, self.w, self.y) } + #[inline] - fn yyww(self) -> DVec4 { - DVec4::new(self.y, self.y, self.w, self.w) + fn xxwz(self) -> DVec4 { + DVec4::new(self.x, self.x, self.w, self.z) } + #[inline] - fn yzxx(self) -> DVec4 { - DVec4::new(self.y, self.z, self.x, self.x) + fn xxww(self) -> DVec4 { + DVec4::new(self.x, self.x, self.w, self.w) } + #[inline] - fn yzxy(self) -> DVec4 { - DVec4::new(self.y, self.z, self.x, self.y) + fn xyxx(self) -> DVec4 { + DVec4::new(self.x, self.y, self.x, self.x) } + #[inline] - fn yzxz(self) -> DVec4 { - DVec4::new(self.y, self.z, self.x, self.z) + fn xyxy(self) -> DVec4 { + DVec4::new(self.x, self.y, self.x, self.y) } + #[inline] - fn yzxw(self) -> DVec4 { - DVec4::new(self.y, self.z, self.x, self.w) + fn xyxz(self) -> DVec4 { + DVec4::new(self.x, self.y, self.x, self.z) } + #[inline] - fn yzyx(self) -> DVec4 { - DVec4::new(self.y, self.z, self.y, self.x) + fn xyxw(self) -> DVec4 { + DVec4::new(self.x, self.y, self.x, self.w) } + #[inline] - fn yzyy(self) -> DVec4 { - DVec4::new(self.y, self.z, self.y, self.y) + fn xyyx(self) -> DVec4 { + DVec4::new(self.x, self.y, self.y, self.x) } + #[inline] - fn yzyz(self) -> DVec4 { - DVec4::new(self.y, self.z, self.y, self.z) + fn xyyy(self) -> DVec4 { + DVec4::new(self.x, self.y, self.y, self.y) } + #[inline] - fn yzyw(self) -> DVec4 { - DVec4::new(self.y, self.z, self.y, self.w) + fn xyyz(self) -> DVec4 { + DVec4::new(self.x, self.y, self.y, self.z) } + #[inline] - fn yzzx(self) -> DVec4 { - DVec4::new(self.y, self.z, self.z, self.x) + fn xyyw(self) -> DVec4 { + DVec4::new(self.x, self.y, self.y, self.w) } + #[inline] - fn yzzy(self) -> DVec4 { - DVec4::new(self.y, self.z, self.z, self.y) + fn xyzx(self) -> DVec4 { + DVec4::new(self.x, self.y, self.z, self.x) } + #[inline] - fn yzzz(self) -> DVec4 { - DVec4::new(self.y, self.z, self.z, self.z) + fn xyzy(self) -> DVec4 { + DVec4::new(self.x, self.y, self.z, self.y) } + #[inline] - fn yzzw(self) -> DVec4 { - DVec4::new(self.y, self.z, self.z, self.w) + fn xyzz(self) -> DVec4 { + DVec4::new(self.x, self.y, self.z, self.z) } + #[inline] - fn yzwx(self) -> DVec4 { - DVec4::new(self.y, self.z, self.w, self.x) + fn xyzw(self) -> DVec4 { + DVec4::new(self.x, self.y, self.z, self.w) } + #[inline] - fn yzwy(self) -> DVec4 { - DVec4::new(self.y, self.z, self.w, self.y) + fn xywx(self) -> DVec4 { + DVec4::new(self.x, self.y, self.w, self.x) } + #[inline] - fn yzwz(self) -> DVec4 { - DVec4::new(self.y, self.z, self.w, self.z) + fn xywy(self) -> DVec4 { + DVec4::new(self.x, self.y, self.w, self.y) } + #[inline] - fn yzww(self) -> DVec4 { - DVec4::new(self.y, self.z, self.w, self.w) + fn xywz(self) -> DVec4 { + DVec4::new(self.x, self.y, self.w, self.z) } + #[inline] - fn ywxx(self) -> DVec4 { - DVec4::new(self.y, self.w, self.x, self.x) + fn xyww(self) -> DVec4 { + DVec4::new(self.x, self.y, self.w, self.w) } + #[inline] - fn ywxy(self) -> DVec4 { - DVec4::new(self.y, self.w, self.x, self.y) + fn xzxx(self) -> DVec4 { + DVec4::new(self.x, self.z, self.x, self.x) } + #[inline] - fn ywxz(self) -> DVec4 { - DVec4::new(self.y, self.w, self.x, self.z) + fn xzxy(self) -> DVec4 { + DVec4::new(self.x, self.z, self.x, self.y) } + #[inline] - fn ywxw(self) -> DVec4 { - DVec4::new(self.y, self.w, self.x, self.w) + fn xzxz(self) -> DVec4 { + DVec4::new(self.x, self.z, self.x, self.z) } + #[inline] - fn ywyx(self) -> DVec4 { - DVec4::new(self.y, self.w, self.y, self.x) + fn xzxw(self) -> DVec4 { + DVec4::new(self.x, self.z, self.x, self.w) } + #[inline] - fn ywyy(self) -> DVec4 { - DVec4::new(self.y, self.w, self.y, self.y) + fn xzyx(self) -> DVec4 { + DVec4::new(self.x, self.z, self.y, self.x) } + #[inline] - fn ywyz(self) -> DVec4 { - DVec4::new(self.y, self.w, self.y, self.z) + fn xzyy(self) -> DVec4 { + DVec4::new(self.x, self.z, self.y, self.y) } + #[inline] - fn ywyw(self) -> DVec4 { - DVec4::new(self.y, self.w, self.y, self.w) + fn xzyz(self) -> DVec4 { + DVec4::new(self.x, self.z, self.y, self.z) } + #[inline] - fn ywzx(self) -> DVec4 { - DVec4::new(self.y, self.w, self.z, self.x) + fn xzyw(self) -> DVec4 { + DVec4::new(self.x, self.z, self.y, self.w) } + #[inline] - fn ywzy(self) -> DVec4 { - DVec4::new(self.y, self.w, self.z, self.y) + fn xzzx(self) -> DVec4 { + DVec4::new(self.x, self.z, self.z, self.x) } + #[inline] - fn ywzz(self) -> DVec4 { - DVec4::new(self.y, self.w, self.z, self.z) + fn xzzy(self) -> DVec4 { + DVec4::new(self.x, self.z, self.z, self.y) } + #[inline] - fn ywzw(self) -> DVec4 { - DVec4::new(self.y, self.w, self.z, self.w) + fn xzzz(self) -> DVec4 { + DVec4::new(self.x, self.z, self.z, self.z) } + #[inline] - fn ywwx(self) -> DVec4 { - DVec4::new(self.y, self.w, self.w, self.x) + fn xzzw(self) -> DVec4 { + DVec4::new(self.x, self.z, self.z, self.w) } + #[inline] - fn ywwy(self) -> DVec4 { - DVec4::new(self.y, self.w, self.w, self.y) + fn xzwx(self) -> DVec4 { + DVec4::new(self.x, self.z, self.w, self.x) } + #[inline] - fn ywwz(self) -> DVec4 { - DVec4::new(self.y, self.w, self.w, self.z) + fn xzwy(self) -> DVec4 { + DVec4::new(self.x, self.z, self.w, self.y) } + #[inline] - fn ywww(self) -> DVec4 { - DVec4::new(self.y, self.w, self.w, self.w) + fn xzwz(self) -> DVec4 { + DVec4::new(self.x, self.z, self.w, self.z) } + #[inline] - fn zxxx(self) -> DVec4 { - DVec4::new(self.z, self.x, self.x, self.x) + fn xzww(self) -> DVec4 { + DVec4::new(self.x, self.z, self.w, self.w) } + #[inline] - fn zxxy(self) -> DVec4 { - DVec4::new(self.z, self.x, self.x, self.y) + fn xwxx(self) -> DVec4 { + DVec4::new(self.x, self.w, self.x, self.x) } + #[inline] - fn zxxz(self) -> DVec4 { - DVec4::new(self.z, self.x, self.x, self.z) + fn xwxy(self) -> DVec4 { + DVec4::new(self.x, self.w, self.x, self.y) } + #[inline] - fn zxxw(self) -> DVec4 { - DVec4::new(self.z, self.x, self.x, self.w) + fn xwxz(self) -> DVec4 { + DVec4::new(self.x, self.w, self.x, self.z) } + #[inline] - fn zxyx(self) -> DVec4 { - DVec4::new(self.z, self.x, self.y, self.x) + fn xwxw(self) -> DVec4 { + DVec4::new(self.x, self.w, self.x, self.w) } + #[inline] - fn zxyy(self) -> DVec4 { - DVec4::new(self.z, self.x, self.y, self.y) + fn xwyx(self) -> DVec4 { + DVec4::new(self.x, self.w, self.y, self.x) } + #[inline] - fn zxyz(self) -> DVec4 { - DVec4::new(self.z, self.x, self.y, self.z) + fn xwyy(self) -> DVec4 { + DVec4::new(self.x, self.w, self.y, self.y) } + #[inline] - fn zxyw(self) -> DVec4 { - DVec4::new(self.z, self.x, self.y, self.w) + fn xwyz(self) -> DVec4 { + DVec4::new(self.x, self.w, self.y, self.z) } + #[inline] - fn zxzx(self) -> DVec4 { - DVec4::new(self.z, self.x, self.z, self.x) + fn xwyw(self) -> DVec4 { + DVec4::new(self.x, self.w, self.y, self.w) } + #[inline] - fn zxzy(self) -> DVec4 { - DVec4::new(self.z, self.x, self.z, self.y) + fn xwzx(self) -> DVec4 { + DVec4::new(self.x, self.w, self.z, self.x) } + #[inline] - fn zxzz(self) -> DVec4 { - DVec4::new(self.z, self.x, self.z, self.z) + fn xwzy(self) -> DVec4 { + DVec4::new(self.x, self.w, self.z, self.y) } + #[inline] - fn zxzw(self) -> DVec4 { - DVec4::new(self.z, self.x, self.z, self.w) + fn xwzz(self) -> DVec4 { + DVec4::new(self.x, self.w, self.z, self.z) } + #[inline] - fn zxwx(self) -> DVec4 { - DVec4::new(self.z, self.x, self.w, self.x) + fn xwzw(self) -> DVec4 { + DVec4::new(self.x, self.w, self.z, self.w) } + #[inline] - fn zxwy(self) -> DVec4 { - DVec4::new(self.z, self.x, self.w, self.y) + fn xwwx(self) -> DVec4 { + DVec4::new(self.x, self.w, self.w, self.x) } + #[inline] - fn zxwz(self) -> DVec4 { - DVec4::new(self.z, self.x, self.w, self.z) + fn xwwy(self) -> DVec4 { + DVec4::new(self.x, self.w, self.w, self.y) } + #[inline] - fn zxww(self) -> DVec4 { - DVec4::new(self.z, self.x, self.w, self.w) + fn xwwz(self) -> DVec4 { + DVec4::new(self.x, self.w, self.w, self.z) } + #[inline] - fn zyxx(self) -> DVec4 { - DVec4::new(self.z, self.y, self.x, self.x) + fn xwww(self) -> DVec4 { + DVec4::new(self.x, self.w, self.w, self.w) } + #[inline] - fn zyxy(self) -> DVec4 { - DVec4::new(self.z, self.y, self.x, self.y) + fn yxxx(self) -> DVec4 { + DVec4::new(self.y, self.x, self.x, self.x) } + #[inline] - fn zyxz(self) -> DVec4 { - DVec4::new(self.z, self.y, self.x, self.z) + fn yxxy(self) -> DVec4 { + DVec4::new(self.y, self.x, self.x, self.y) } + #[inline] - fn zyxw(self) -> DVec4 { - DVec4::new(self.z, self.y, self.x, self.w) + fn yxxz(self) -> DVec4 { + DVec4::new(self.y, self.x, self.x, self.z) } + #[inline] - fn zyyx(self) -> DVec4 { - DVec4::new(self.z, self.y, self.y, self.x) + fn yxxw(self) -> DVec4 { + DVec4::new(self.y, self.x, self.x, self.w) } + #[inline] - fn zyyy(self) -> DVec4 { - DVec4::new(self.z, self.y, self.y, self.y) + fn yxyx(self) -> DVec4 { + DVec4::new(self.y, self.x, self.y, self.x) } + #[inline] - fn zyyz(self) -> DVec4 { - DVec4::new(self.z, self.y, self.y, self.z) + fn yxyy(self) -> DVec4 { + DVec4::new(self.y, self.x, self.y, self.y) } + #[inline] - fn zyyw(self) -> DVec4 { - DVec4::new(self.z, self.y, self.y, self.w) + fn yxyz(self) -> DVec4 { + DVec4::new(self.y, self.x, self.y, self.z) } + #[inline] - fn zyzx(self) -> DVec4 { - DVec4::new(self.z, self.y, self.z, self.x) + fn yxyw(self) -> DVec4 { + DVec4::new(self.y, self.x, self.y, self.w) } + #[inline] - fn zyzy(self) -> DVec4 { - DVec4::new(self.z, self.y, self.z, self.y) + fn yxzx(self) -> DVec4 { + DVec4::new(self.y, self.x, self.z, self.x) } + #[inline] - fn zyzz(self) -> DVec4 { - DVec4::new(self.z, self.y, self.z, self.z) + fn yxzy(self) -> DVec4 { + DVec4::new(self.y, self.x, self.z, self.y) } + #[inline] - fn zyzw(self) -> DVec4 { - DVec4::new(self.z, self.y, self.z, self.w) + fn yxzz(self) -> DVec4 { + DVec4::new(self.y, self.x, self.z, self.z) } + #[inline] - fn zywx(self) -> DVec4 { - DVec4::new(self.z, self.y, self.w, self.x) + fn yxzw(self) -> DVec4 { + DVec4::new(self.y, self.x, self.z, self.w) } + #[inline] - fn zywy(self) -> DVec4 { - DVec4::new(self.z, self.y, self.w, self.y) + fn yxwx(self) -> DVec4 { + DVec4::new(self.y, self.x, self.w, self.x) } + #[inline] - fn zywz(self) -> DVec4 { - DVec4::new(self.z, self.y, self.w, self.z) + fn yxwy(self) -> DVec4 { + DVec4::new(self.y, self.x, self.w, self.y) } + #[inline] - fn zyww(self) -> DVec4 { - DVec4::new(self.z, self.y, self.w, self.w) + fn yxwz(self) -> DVec4 { + DVec4::new(self.y, self.x, self.w, self.z) } + #[inline] - fn zzxx(self) -> DVec4 { - DVec4::new(self.z, self.z, self.x, self.x) + fn yxww(self) -> DVec4 { + DVec4::new(self.y, self.x, self.w, self.w) } + #[inline] - fn zzxy(self) -> DVec4 { - DVec4::new(self.z, self.z, self.x, self.y) + fn yyxx(self) -> DVec4 { + DVec4::new(self.y, self.y, self.x, self.x) } + #[inline] - fn zzxz(self) -> DVec4 { - DVec4::new(self.z, self.z, self.x, self.z) + fn yyxy(self) -> DVec4 { + DVec4::new(self.y, self.y, self.x, self.y) } + #[inline] - fn zzxw(self) -> DVec4 { - DVec4::new(self.z, self.z, self.x, self.w) + fn yyxz(self) -> DVec4 { + DVec4::new(self.y, self.y, self.x, self.z) } + #[inline] - fn zzyx(self) -> DVec4 { - DVec4::new(self.z, self.z, self.y, self.x) + fn yyxw(self) -> DVec4 { + DVec4::new(self.y, self.y, self.x, self.w) } + #[inline] - fn zzyy(self) -> DVec4 { - DVec4::new(self.z, self.z, self.y, self.y) + fn yyyx(self) -> DVec4 { + DVec4::new(self.y, self.y, self.y, self.x) } + #[inline] - fn zzyz(self) -> DVec4 { - DVec4::new(self.z, self.z, self.y, self.z) + fn yyyy(self) -> DVec4 { + DVec4::new(self.y, self.y, self.y, self.y) } + #[inline] - fn zzyw(self) -> DVec4 { - DVec4::new(self.z, self.z, self.y, self.w) + fn yyyz(self) -> DVec4 { + DVec4::new(self.y, self.y, self.y, self.z) } + #[inline] - fn zzzx(self) -> DVec4 { - DVec4::new(self.z, self.z, self.z, self.x) + fn yyyw(self) -> DVec4 { + DVec4::new(self.y, self.y, self.y, self.w) } + #[inline] - fn zzzy(self) -> DVec4 { - DVec4::new(self.z, self.z, self.z, self.y) + fn yyzx(self) -> DVec4 { + DVec4::new(self.y, self.y, self.z, self.x) } + #[inline] - fn zzzz(self) -> DVec4 { - DVec4::new(self.z, self.z, self.z, self.z) + fn yyzy(self) -> DVec4 { + DVec4::new(self.y, self.y, self.z, self.y) } + #[inline] - fn zzzw(self) -> DVec4 { - DVec4::new(self.z, self.z, self.z, self.w) + fn yyzz(self) -> DVec4 { + DVec4::new(self.y, self.y, self.z, self.z) } + #[inline] - fn zzwx(self) -> DVec4 { - DVec4::new(self.z, self.z, self.w, self.x) + fn yyzw(self) -> DVec4 { + DVec4::new(self.y, self.y, self.z, self.w) } + #[inline] - fn zzwy(self) -> DVec4 { - DVec4::new(self.z, self.z, self.w, self.y) + fn yywx(self) -> DVec4 { + DVec4::new(self.y, self.y, self.w, self.x) } + #[inline] - fn zzwz(self) -> DVec4 { - DVec4::new(self.z, self.z, self.w, self.z) + fn yywy(self) -> DVec4 { + DVec4::new(self.y, self.y, self.w, self.y) } + #[inline] - fn zzww(self) -> DVec4 { - DVec4::new(self.z, self.z, self.w, self.w) + fn yywz(self) -> DVec4 { + DVec4::new(self.y, self.y, self.w, self.z) } + #[inline] - fn zwxx(self) -> DVec4 { - DVec4::new(self.z, self.w, self.x, self.x) + fn yyww(self) -> DVec4 { + DVec4::new(self.y, self.y, self.w, self.w) } + #[inline] - fn zwxy(self) -> DVec4 { - DVec4::new(self.z, self.w, self.x, self.y) + fn yzxx(self) -> DVec4 { + DVec4::new(self.y, self.z, self.x, self.x) } + #[inline] - fn zwxz(self) -> DVec4 { - DVec4::new(self.z, self.w, self.x, self.z) + fn yzxy(self) -> DVec4 { + DVec4::new(self.y, self.z, self.x, self.y) } + #[inline] - fn zwxw(self) -> DVec4 { - DVec4::new(self.z, self.w, self.x, self.w) + fn yzxz(self) -> DVec4 { + DVec4::new(self.y, self.z, self.x, self.z) } + #[inline] - fn zwyx(self) -> DVec4 { - DVec4::new(self.z, self.w, self.y, self.x) + fn yzxw(self) -> DVec4 { + DVec4::new(self.y, self.z, self.x, self.w) } + #[inline] - fn zwyy(self) -> DVec4 { - DVec4::new(self.z, self.w, self.y, self.y) + fn yzyx(self) -> DVec4 { + DVec4::new(self.y, self.z, self.y, self.x) } + #[inline] - fn zwyz(self) -> DVec4 { - DVec4::new(self.z, self.w, self.y, self.z) + fn yzyy(self) -> DVec4 { + DVec4::new(self.y, self.z, self.y, self.y) } + #[inline] - fn zwyw(self) -> DVec4 { - DVec4::new(self.z, self.w, self.y, self.w) + fn yzyz(self) -> DVec4 { + DVec4::new(self.y, self.z, self.y, self.z) } + #[inline] - fn zwzx(self) -> DVec4 { - DVec4::new(self.z, self.w, self.z, self.x) + fn yzyw(self) -> DVec4 { + DVec4::new(self.y, self.z, self.y, self.w) } + #[inline] - fn zwzy(self) -> DVec4 { - DVec4::new(self.z, self.w, self.z, self.y) + fn yzzx(self) -> DVec4 { + DVec4::new(self.y, self.z, self.z, self.x) } + #[inline] - fn zwzz(self) -> DVec4 { - DVec4::new(self.z, self.w, self.z, self.z) + fn yzzy(self) -> DVec4 { + DVec4::new(self.y, self.z, self.z, self.y) } + #[inline] - fn zwzw(self) -> DVec4 { - DVec4::new(self.z, self.w, self.z, self.w) + fn yzzz(self) -> DVec4 { + DVec4::new(self.y, self.z, self.z, self.z) } + #[inline] - fn zwwx(self) -> DVec4 { - DVec4::new(self.z, self.w, self.w, self.x) + fn yzzw(self) -> DVec4 { + DVec4::new(self.y, self.z, self.z, self.w) } + #[inline] - fn zwwy(self) -> DVec4 { - DVec4::new(self.z, self.w, self.w, self.y) + fn yzwx(self) -> DVec4 { + DVec4::new(self.y, self.z, self.w, self.x) } + #[inline] - fn zwwz(self) -> DVec4 { - DVec4::new(self.z, self.w, self.w, self.z) + fn yzwy(self) -> DVec4 { + DVec4::new(self.y, self.z, self.w, self.y) } + #[inline] - fn zwww(self) -> DVec4 { - DVec4::new(self.z, self.w, self.w, self.w) + fn yzwz(self) -> DVec4 { + DVec4::new(self.y, self.z, self.w, self.z) } + #[inline] - fn wxxx(self) -> DVec4 { - DVec4::new(self.w, self.x, self.x, self.x) + fn yzww(self) -> DVec4 { + DVec4::new(self.y, self.z, self.w, self.w) } + #[inline] - fn wxxy(self) -> DVec4 { - DVec4::new(self.w, self.x, self.x, self.y) + fn ywxx(self) -> DVec4 { + DVec4::new(self.y, self.w, self.x, self.x) } + #[inline] - fn wxxz(self) -> DVec4 { - DVec4::new(self.w, self.x, self.x, self.z) + fn ywxy(self) -> DVec4 { + DVec4::new(self.y, self.w, self.x, self.y) } + #[inline] - fn wxxw(self) -> DVec4 { - DVec4::new(self.w, self.x, self.x, self.w) + fn ywxz(self) -> DVec4 { + DVec4::new(self.y, self.w, self.x, self.z) } + #[inline] - fn wxyx(self) -> DVec4 { - DVec4::new(self.w, self.x, self.y, self.x) + fn ywxw(self) -> DVec4 { + DVec4::new(self.y, self.w, self.x, self.w) } + #[inline] - fn wxyy(self) -> DVec4 { - DVec4::new(self.w, self.x, self.y, self.y) + fn ywyx(self) -> DVec4 { + DVec4::new(self.y, self.w, self.y, self.x) } + #[inline] - fn wxyz(self) -> DVec4 { - DVec4::new(self.w, self.x, self.y, self.z) + fn ywyy(self) -> DVec4 { + DVec4::new(self.y, self.w, self.y, self.y) } + #[inline] - fn wxyw(self) -> DVec4 { - DVec4::new(self.w, self.x, self.y, self.w) + fn ywyz(self) -> DVec4 { + DVec4::new(self.y, self.w, self.y, self.z) } + #[inline] - fn wxzx(self) -> DVec4 { - DVec4::new(self.w, self.x, self.z, self.x) + fn ywyw(self) -> DVec4 { + DVec4::new(self.y, self.w, self.y, self.w) } + #[inline] - fn wxzy(self) -> DVec4 { - DVec4::new(self.w, self.x, self.z, self.y) + fn ywzx(self) -> DVec4 { + DVec4::new(self.y, self.w, self.z, self.x) } + #[inline] - fn wxzz(self) -> DVec4 { - DVec4::new(self.w, self.x, self.z, self.z) + fn ywzy(self) -> DVec4 { + DVec4::new(self.y, self.w, self.z, self.y) } + #[inline] - fn wxzw(self) -> DVec4 { - DVec4::new(self.w, self.x, self.z, self.w) + fn ywzz(self) -> DVec4 { + DVec4::new(self.y, self.w, self.z, self.z) } + #[inline] - fn wxwx(self) -> DVec4 { - DVec4::new(self.w, self.x, self.w, self.x) + fn ywzw(self) -> DVec4 { + DVec4::new(self.y, self.w, self.z, self.w) } + #[inline] - fn wxwy(self) -> DVec4 { - DVec4::new(self.w, self.x, self.w, self.y) + fn ywwx(self) -> DVec4 { + DVec4::new(self.y, self.w, self.w, self.x) } + #[inline] - fn wxwz(self) -> DVec4 { - DVec4::new(self.w, self.x, self.w, self.z) + fn ywwy(self) -> DVec4 { + DVec4::new(self.y, self.w, self.w, self.y) } + #[inline] - fn wxww(self) -> DVec4 { - DVec4::new(self.w, self.x, self.w, self.w) + fn ywwz(self) -> DVec4 { + DVec4::new(self.y, self.w, self.w, self.z) } + #[inline] - fn wyxx(self) -> DVec4 { - DVec4::new(self.w, self.y, self.x, self.x) + fn ywww(self) -> DVec4 { + DVec4::new(self.y, self.w, self.w, self.w) } + #[inline] - fn wyxy(self) -> DVec4 { - DVec4::new(self.w, self.y, self.x, self.y) + fn zxxx(self) -> DVec4 { + DVec4::new(self.z, self.x, self.x, self.x) } + #[inline] - fn wyxz(self) -> DVec4 { - DVec4::new(self.w, self.y, self.x, self.z) + fn zxxy(self) -> DVec4 { + DVec4::new(self.z, self.x, self.x, self.y) } + #[inline] - fn wyxw(self) -> DVec4 { - DVec4::new(self.w, self.y, self.x, self.w) + fn zxxz(self) -> DVec4 { + DVec4::new(self.z, self.x, self.x, self.z) } + #[inline] - fn wyyx(self) -> DVec4 { - DVec4::new(self.w, self.y, self.y, self.x) + fn zxxw(self) -> DVec4 { + DVec4::new(self.z, self.x, self.x, self.w) } + #[inline] - fn wyyy(self) -> DVec4 { - DVec4::new(self.w, self.y, self.y, self.y) + fn zxyx(self) -> DVec4 { + DVec4::new(self.z, self.x, self.y, self.x) } + #[inline] - fn wyyz(self) -> DVec4 { - DVec4::new(self.w, self.y, self.y, self.z) + fn zxyy(self) -> DVec4 { + DVec4::new(self.z, self.x, self.y, self.y) } + #[inline] - fn wyyw(self) -> DVec4 { - DVec4::new(self.w, self.y, self.y, self.w) + fn zxyz(self) -> DVec4 { + DVec4::new(self.z, self.x, self.y, self.z) } + #[inline] - fn wyzx(self) -> DVec4 { - DVec4::new(self.w, self.y, self.z, self.x) + fn zxyw(self) -> DVec4 { + DVec4::new(self.z, self.x, self.y, self.w) } + #[inline] - fn wyzy(self) -> DVec4 { - DVec4::new(self.w, self.y, self.z, self.y) + fn zxzx(self) -> DVec4 { + DVec4::new(self.z, self.x, self.z, self.x) + } + + #[inline] + fn zxzy(self) -> DVec4 { + DVec4::new(self.z, self.x, self.z, self.y) } + #[inline] - fn wyzz(self) -> DVec4 { - DVec4::new(self.w, self.y, self.z, self.z) + fn zxzz(self) -> DVec4 { + DVec4::new(self.z, self.x, self.z, self.z) } + #[inline] - fn wyzw(self) -> DVec4 { - DVec4::new(self.w, self.y, self.z, self.w) + fn zxzw(self) -> DVec4 { + DVec4::new(self.z, self.x, self.z, self.w) } + #[inline] - fn wywx(self) -> DVec4 { - DVec4::new(self.w, self.y, self.w, self.x) + fn zxwx(self) -> DVec4 { + DVec4::new(self.z, self.x, self.w, self.x) } + #[inline] - fn wywy(self) -> DVec4 { - DVec4::new(self.w, self.y, self.w, self.y) + fn zxwy(self) -> DVec4 { + DVec4::new(self.z, self.x, self.w, self.y) } + #[inline] - fn wywz(self) -> DVec4 { - DVec4::new(self.w, self.y, self.w, self.z) + fn zxwz(self) -> DVec4 { + DVec4::new(self.z, self.x, self.w, self.z) } + #[inline] - fn wyww(self) -> DVec4 { - DVec4::new(self.w, self.y, self.w, self.w) + fn zxww(self) -> DVec4 { + DVec4::new(self.z, self.x, self.w, self.w) } + #[inline] - fn wzxx(self) -> DVec4 { - DVec4::new(self.w, self.z, self.x, self.x) + fn zyxx(self) -> DVec4 { + DVec4::new(self.z, self.y, self.x, self.x) } + #[inline] - fn wzxy(self) -> DVec4 { - DVec4::new(self.w, self.z, self.x, self.y) + fn zyxy(self) -> DVec4 { + DVec4::new(self.z, self.y, self.x, self.y) } + #[inline] - fn wzxz(self) -> DVec4 { - DVec4::new(self.w, self.z, self.x, self.z) + fn zyxz(self) -> DVec4 { + DVec4::new(self.z, self.y, self.x, self.z) } + #[inline] - fn wzxw(self) -> DVec4 { - DVec4::new(self.w, self.z, self.x, self.w) + fn zyxw(self) -> DVec4 { + DVec4::new(self.z, self.y, self.x, self.w) } + #[inline] - fn wzyx(self) -> DVec4 { - DVec4::new(self.w, self.z, self.y, self.x) + fn zyyx(self) -> DVec4 { + DVec4::new(self.z, self.y, self.y, self.x) } + #[inline] - fn wzyy(self) -> DVec4 { - DVec4::new(self.w, self.z, self.y, self.y) + fn zyyy(self) -> DVec4 { + DVec4::new(self.z, self.y, self.y, self.y) } + #[inline] - fn wzyz(self) -> DVec4 { - DVec4::new(self.w, self.z, self.y, self.z) + fn zyyz(self) -> DVec4 { + DVec4::new(self.z, self.y, self.y, self.z) } + #[inline] - fn wzyw(self) -> DVec4 { - DVec4::new(self.w, self.z, self.y, self.w) + fn zyyw(self) -> DVec4 { + DVec4::new(self.z, self.y, self.y, self.w) } + #[inline] - fn wzzx(self) -> DVec4 { - DVec4::new(self.w, self.z, self.z, self.x) + fn zyzx(self) -> DVec4 { + DVec4::new(self.z, self.y, self.z, self.x) } + #[inline] - fn wzzy(self) -> DVec4 { - DVec4::new(self.w, self.z, self.z, self.y) + fn zyzy(self) -> DVec4 { + DVec4::new(self.z, self.y, self.z, self.y) } + #[inline] - fn wzzz(self) -> DVec4 { - DVec4::new(self.w, self.z, self.z, self.z) + fn zyzz(self) -> DVec4 { + DVec4::new(self.z, self.y, self.z, self.z) } + #[inline] - fn wzzw(self) -> DVec4 { - DVec4::new(self.w, self.z, self.z, self.w) + fn zyzw(self) -> DVec4 { + DVec4::new(self.z, self.y, self.z, self.w) } + #[inline] - fn wzwx(self) -> DVec4 { - DVec4::new(self.w, self.z, self.w, self.x) + fn zywx(self) -> DVec4 { + DVec4::new(self.z, self.y, self.w, self.x) } + #[inline] - fn wzwy(self) -> DVec4 { - DVec4::new(self.w, self.z, self.w, self.y) + fn zywy(self) -> DVec4 { + DVec4::new(self.z, self.y, self.w, self.y) } + #[inline] - fn wzwz(self) -> DVec4 { - DVec4::new(self.w, self.z, self.w, self.z) + fn zywz(self) -> DVec4 { + DVec4::new(self.z, self.y, self.w, self.z) } + #[inline] - fn wzww(self) -> DVec4 { - DVec4::new(self.w, self.z, self.w, self.w) + fn zyww(self) -> DVec4 { + DVec4::new(self.z, self.y, self.w, self.w) } + #[inline] - fn wwxx(self) -> DVec4 { - DVec4::new(self.w, self.w, self.x, self.x) + fn zzxx(self) -> DVec4 { + DVec4::new(self.z, self.z, self.x, self.x) } + #[inline] - fn wwxy(self) -> DVec4 { - DVec4::new(self.w, self.w, self.x, self.y) + fn zzxy(self) -> DVec4 { + DVec4::new(self.z, self.z, self.x, self.y) } + #[inline] - fn wwxz(self) -> DVec4 { - DVec4::new(self.w, self.w, self.x, self.z) + fn zzxz(self) -> DVec4 { + DVec4::new(self.z, self.z, self.x, self.z) } + #[inline] - fn wwxw(self) -> DVec4 { - DVec4::new(self.w, self.w, self.x, self.w) + fn zzxw(self) -> DVec4 { + DVec4::new(self.z, self.z, self.x, self.w) } + #[inline] - fn wwyx(self) -> DVec4 { - DVec4::new(self.w, self.w, self.y, self.x) + fn zzyx(self) -> DVec4 { + DVec4::new(self.z, self.z, self.y, self.x) } + #[inline] - fn wwyy(self) -> DVec4 { - DVec4::new(self.w, self.w, self.y, self.y) + fn zzyy(self) -> DVec4 { + DVec4::new(self.z, self.z, self.y, self.y) } + #[inline] - fn wwyz(self) -> DVec4 { - DVec4::new(self.w, self.w, self.y, self.z) + fn zzyz(self) -> DVec4 { + DVec4::new(self.z, self.z, self.y, self.z) } + #[inline] - fn wwyw(self) -> DVec4 { - DVec4::new(self.w, self.w, self.y, self.w) + fn zzyw(self) -> DVec4 { + DVec4::new(self.z, self.z, self.y, self.w) } + #[inline] - fn wwzx(self) -> DVec4 { - DVec4::new(self.w, self.w, self.z, self.x) + fn zzzx(self) -> DVec4 { + DVec4::new(self.z, self.z, self.z, self.x) } + #[inline] - fn wwzy(self) -> DVec4 { - DVec4::new(self.w, self.w, self.z, self.y) + fn zzzy(self) -> DVec4 { + DVec4::new(self.z, self.z, self.z, self.y) } + #[inline] - fn wwzz(self) -> DVec4 { - DVec4::new(self.w, self.w, self.z, self.z) + fn zzzz(self) -> DVec4 { + DVec4::new(self.z, self.z, self.z, self.z) } + #[inline] - fn wwzw(self) -> DVec4 { - DVec4::new(self.w, self.w, self.z, self.w) + fn zzzw(self) -> DVec4 { + DVec4::new(self.z, self.z, self.z, self.w) } + #[inline] - fn wwwx(self) -> DVec4 { - DVec4::new(self.w, self.w, self.w, self.x) + fn zzwx(self) -> DVec4 { + DVec4::new(self.z, self.z, self.w, self.x) } + #[inline] - fn wwwy(self) -> DVec4 { - DVec4::new(self.w, self.w, self.w, self.y) + fn zzwy(self) -> DVec4 { + DVec4::new(self.z, self.z, self.w, self.y) } + #[inline] - fn wwwz(self) -> DVec4 { - DVec4::new(self.w, self.w, self.w, self.z) + fn zzwz(self) -> DVec4 { + DVec4::new(self.z, self.z, self.w, self.z) } + #[inline] - fn wwww(self) -> DVec4 { - DVec4::new(self.w, self.w, self.w, self.w) + fn zzww(self) -> DVec4 { + DVec4::new(self.z, self.z, self.w, self.w) } + #[inline] - fn xxx(self) -> DVec3 { - DVec3::new(self.x, self.x, self.x) + fn zwxx(self) -> DVec4 { + DVec4::new(self.z, self.w, self.x, self.x) } + #[inline] - fn xxy(self) -> DVec3 { - DVec3::new(self.x, self.x, self.y) + fn zwxy(self) -> DVec4 { + DVec4::new(self.z, self.w, self.x, self.y) } + #[inline] - fn xxz(self) -> DVec3 { - DVec3::new(self.x, self.x, self.z) + fn zwxz(self) -> DVec4 { + DVec4::new(self.z, self.w, self.x, self.z) } + #[inline] - fn xxw(self) -> DVec3 { - DVec3::new(self.x, self.x, self.w) + fn zwxw(self) -> DVec4 { + DVec4::new(self.z, self.w, self.x, self.w) } + #[inline] - fn xyx(self) -> DVec3 { - DVec3::new(self.x, self.y, self.x) + fn zwyx(self) -> DVec4 { + DVec4::new(self.z, self.w, self.y, self.x) } + #[inline] - fn xyy(self) -> DVec3 { - DVec3::new(self.x, self.y, self.y) + fn zwyy(self) -> DVec4 { + DVec4::new(self.z, self.w, self.y, self.y) } + #[inline] - fn xyz(self) -> DVec3 { - DVec3::new(self.x, self.y, self.z) + fn zwyz(self) -> DVec4 { + DVec4::new(self.z, self.w, self.y, self.z) } + #[inline] - fn xyw(self) -> DVec3 { - DVec3::new(self.x, self.y, self.w) + fn zwyw(self) -> DVec4 { + DVec4::new(self.z, self.w, self.y, self.w) } + #[inline] - fn xzx(self) -> DVec3 { - DVec3::new(self.x, self.z, self.x) + fn zwzx(self) -> DVec4 { + DVec4::new(self.z, self.w, self.z, self.x) } + #[inline] - fn xzy(self) -> DVec3 { - DVec3::new(self.x, self.z, self.y) + fn zwzy(self) -> DVec4 { + DVec4::new(self.z, self.w, self.z, self.y) } + #[inline] - fn xzz(self) -> DVec3 { - DVec3::new(self.x, self.z, self.z) + fn zwzz(self) -> DVec4 { + DVec4::new(self.z, self.w, self.z, self.z) } + #[inline] - fn xzw(self) -> DVec3 { - DVec3::new(self.x, self.z, self.w) + fn zwzw(self) -> DVec4 { + DVec4::new(self.z, self.w, self.z, self.w) } + #[inline] - fn xwx(self) -> DVec3 { - DVec3::new(self.x, self.w, self.x) + fn zwwx(self) -> DVec4 { + DVec4::new(self.z, self.w, self.w, self.x) } + #[inline] - fn xwy(self) -> DVec3 { - DVec3::new(self.x, self.w, self.y) + fn zwwy(self) -> DVec4 { + DVec4::new(self.z, self.w, self.w, self.y) } + #[inline] - fn xwz(self) -> DVec3 { - DVec3::new(self.x, self.w, self.z) + fn zwwz(self) -> DVec4 { + DVec4::new(self.z, self.w, self.w, self.z) } + #[inline] - fn xww(self) -> DVec3 { - DVec3::new(self.x, self.w, self.w) + fn zwww(self) -> DVec4 { + DVec4::new(self.z, self.w, self.w, self.w) } + #[inline] - fn yxx(self) -> DVec3 { - DVec3::new(self.y, self.x, self.x) + fn wxxx(self) -> DVec4 { + DVec4::new(self.w, self.x, self.x, self.x) } + #[inline] - fn yxy(self) -> DVec3 { - DVec3::new(self.y, self.x, self.y) + fn wxxy(self) -> DVec4 { + DVec4::new(self.w, self.x, self.x, self.y) } + #[inline] - fn yxz(self) -> DVec3 { - DVec3::new(self.y, self.x, self.z) + fn wxxz(self) -> DVec4 { + DVec4::new(self.w, self.x, self.x, self.z) } + #[inline] - fn yxw(self) -> DVec3 { - DVec3::new(self.y, self.x, self.w) + fn wxxw(self) -> DVec4 { + DVec4::new(self.w, self.x, self.x, self.w) } + #[inline] - fn yyx(self) -> DVec3 { - DVec3::new(self.y, self.y, self.x) + fn wxyx(self) -> DVec4 { + DVec4::new(self.w, self.x, self.y, self.x) } + #[inline] - fn yyy(self) -> DVec3 { - DVec3::new(self.y, self.y, self.y) + fn wxyy(self) -> DVec4 { + DVec4::new(self.w, self.x, self.y, self.y) } + #[inline] - fn yyz(self) -> DVec3 { - DVec3::new(self.y, self.y, self.z) + fn wxyz(self) -> DVec4 { + DVec4::new(self.w, self.x, self.y, self.z) } + #[inline] - fn yyw(self) -> DVec3 { - DVec3::new(self.y, self.y, self.w) + fn wxyw(self) -> DVec4 { + DVec4::new(self.w, self.x, self.y, self.w) } + #[inline] - fn yzx(self) -> DVec3 { - DVec3::new(self.y, self.z, self.x) + fn wxzx(self) -> DVec4 { + DVec4::new(self.w, self.x, self.z, self.x) } + #[inline] - fn yzy(self) -> DVec3 { - DVec3::new(self.y, self.z, self.y) + fn wxzy(self) -> DVec4 { + DVec4::new(self.w, self.x, self.z, self.y) } + #[inline] - fn yzz(self) -> DVec3 { - DVec3::new(self.y, self.z, self.z) + fn wxzz(self) -> DVec4 { + DVec4::new(self.w, self.x, self.z, self.z) } + #[inline] - fn yzw(self) -> DVec3 { - DVec3::new(self.y, self.z, self.w) + fn wxzw(self) -> DVec4 { + DVec4::new(self.w, self.x, self.z, self.w) } + #[inline] - fn ywx(self) -> DVec3 { - DVec3::new(self.y, self.w, self.x) + fn wxwx(self) -> DVec4 { + DVec4::new(self.w, self.x, self.w, self.x) } + #[inline] - fn ywy(self) -> DVec3 { - DVec3::new(self.y, self.w, self.y) + fn wxwy(self) -> DVec4 { + DVec4::new(self.w, self.x, self.w, self.y) } + #[inline] - fn ywz(self) -> DVec3 { - DVec3::new(self.y, self.w, self.z) + fn wxwz(self) -> DVec4 { + DVec4::new(self.w, self.x, self.w, self.z) } + #[inline] - fn yww(self) -> DVec3 { - DVec3::new(self.y, self.w, self.w) + fn wxww(self) -> DVec4 { + DVec4::new(self.w, self.x, self.w, self.w) } + #[inline] - fn zxx(self) -> DVec3 { - DVec3::new(self.z, self.x, self.x) + fn wyxx(self) -> DVec4 { + DVec4::new(self.w, self.y, self.x, self.x) } + #[inline] - fn zxy(self) -> DVec3 { - DVec3::new(self.z, self.x, self.y) + fn wyxy(self) -> DVec4 { + DVec4::new(self.w, self.y, self.x, self.y) } + #[inline] - fn zxz(self) -> DVec3 { - DVec3::new(self.z, self.x, self.z) + fn wyxz(self) -> DVec4 { + DVec4::new(self.w, self.y, self.x, self.z) } + #[inline] - fn zxw(self) -> DVec3 { - DVec3::new(self.z, self.x, self.w) + fn wyxw(self) -> DVec4 { + DVec4::new(self.w, self.y, self.x, self.w) } + #[inline] - fn zyx(self) -> DVec3 { - DVec3::new(self.z, self.y, self.x) + fn wyyx(self) -> DVec4 { + DVec4::new(self.w, self.y, self.y, self.x) } + #[inline] - fn zyy(self) -> DVec3 { - DVec3::new(self.z, self.y, self.y) + fn wyyy(self) -> DVec4 { + DVec4::new(self.w, self.y, self.y, self.y) } + #[inline] - fn zyz(self) -> DVec3 { - DVec3::new(self.z, self.y, self.z) + fn wyyz(self) -> DVec4 { + DVec4::new(self.w, self.y, self.y, self.z) } + #[inline] - fn zyw(self) -> DVec3 { - DVec3::new(self.z, self.y, self.w) + fn wyyw(self) -> DVec4 { + DVec4::new(self.w, self.y, self.y, self.w) } + #[inline] - fn zzx(self) -> DVec3 { - DVec3::new(self.z, self.z, self.x) + fn wyzx(self) -> DVec4 { + DVec4::new(self.w, self.y, self.z, self.x) } + #[inline] - fn zzy(self) -> DVec3 { - DVec3::new(self.z, self.z, self.y) + fn wyzy(self) -> DVec4 { + DVec4::new(self.w, self.y, self.z, self.y) } + #[inline] - fn zzz(self) -> DVec3 { - DVec3::new(self.z, self.z, self.z) + fn wyzz(self) -> DVec4 { + DVec4::new(self.w, self.y, self.z, self.z) } + #[inline] - fn zzw(self) -> DVec3 { - DVec3::new(self.z, self.z, self.w) + fn wyzw(self) -> DVec4 { + DVec4::new(self.w, self.y, self.z, self.w) } + #[inline] - fn zwx(self) -> DVec3 { - DVec3::new(self.z, self.w, self.x) + fn wywx(self) -> DVec4 { + DVec4::new(self.w, self.y, self.w, self.x) } + #[inline] - fn zwy(self) -> DVec3 { - DVec3::new(self.z, self.w, self.y) + fn wywy(self) -> DVec4 { + DVec4::new(self.w, self.y, self.w, self.y) } + #[inline] - fn zwz(self) -> DVec3 { - DVec3::new(self.z, self.w, self.z) + fn wywz(self) -> DVec4 { + DVec4::new(self.w, self.y, self.w, self.z) } + #[inline] - fn zww(self) -> DVec3 { - DVec3::new(self.z, self.w, self.w) + fn wyww(self) -> DVec4 { + DVec4::new(self.w, self.y, self.w, self.w) } + #[inline] - fn wxx(self) -> DVec3 { - DVec3::new(self.w, self.x, self.x) + fn wzxx(self) -> DVec4 { + DVec4::new(self.w, self.z, self.x, self.x) } + #[inline] - fn wxy(self) -> DVec3 { - DVec3::new(self.w, self.x, self.y) + fn wzxy(self) -> DVec4 { + DVec4::new(self.w, self.z, self.x, self.y) } + #[inline] - fn wxz(self) -> DVec3 { - DVec3::new(self.w, self.x, self.z) + fn wzxz(self) -> DVec4 { + DVec4::new(self.w, self.z, self.x, self.z) } + #[inline] - fn wxw(self) -> DVec3 { - DVec3::new(self.w, self.x, self.w) + fn wzxw(self) -> DVec4 { + DVec4::new(self.w, self.z, self.x, self.w) } + #[inline] - fn wyx(self) -> DVec3 { - DVec3::new(self.w, self.y, self.x) + fn wzyx(self) -> DVec4 { + DVec4::new(self.w, self.z, self.y, self.x) } + #[inline] - fn wyy(self) -> DVec3 { - DVec3::new(self.w, self.y, self.y) + fn wzyy(self) -> DVec4 { + DVec4::new(self.w, self.z, self.y, self.y) } + #[inline] - fn wyz(self) -> DVec3 { - DVec3::new(self.w, self.y, self.z) + fn wzyz(self) -> DVec4 { + DVec4::new(self.w, self.z, self.y, self.z) } + #[inline] - fn wyw(self) -> DVec3 { - DVec3::new(self.w, self.y, self.w) + fn wzyw(self) -> DVec4 { + DVec4::new(self.w, self.z, self.y, self.w) } + #[inline] - fn wzx(self) -> DVec3 { - DVec3::new(self.w, self.z, self.x) + fn wzzx(self) -> DVec4 { + DVec4::new(self.w, self.z, self.z, self.x) } + #[inline] - fn wzy(self) -> DVec3 { - DVec3::new(self.w, self.z, self.y) + fn wzzy(self) -> DVec4 { + DVec4::new(self.w, self.z, self.z, self.y) } + #[inline] - fn wzz(self) -> DVec3 { - DVec3::new(self.w, self.z, self.z) + fn wzzz(self) -> DVec4 { + DVec4::new(self.w, self.z, self.z, self.z) } + #[inline] - fn wzw(self) -> DVec3 { - DVec3::new(self.w, self.z, self.w) + fn wzzw(self) -> DVec4 { + DVec4::new(self.w, self.z, self.z, self.w) } + #[inline] - fn wwx(self) -> DVec3 { - DVec3::new(self.w, self.w, self.x) + fn wzwx(self) -> DVec4 { + DVec4::new(self.w, self.z, self.w, self.x) } + #[inline] - fn wwy(self) -> DVec3 { - DVec3::new(self.w, self.w, self.y) + fn wzwy(self) -> DVec4 { + DVec4::new(self.w, self.z, self.w, self.y) } + #[inline] - fn wwz(self) -> DVec3 { - DVec3::new(self.w, self.w, self.z) + fn wzwz(self) -> DVec4 { + DVec4::new(self.w, self.z, self.w, self.z) } + #[inline] - fn www(self) -> DVec3 { - DVec3::new(self.w, self.w, self.w) + fn wzww(self) -> DVec4 { + DVec4::new(self.w, self.z, self.w, self.w) } + #[inline] - fn xx(self) -> DVec2 { - DVec2::new(self.x, self.x) + fn wwxx(self) -> DVec4 { + DVec4::new(self.w, self.w, self.x, self.x) } + #[inline] - fn xy(self) -> DVec2 { - DVec2::new(self.x, self.y) + fn wwxy(self) -> DVec4 { + DVec4::new(self.w, self.w, self.x, self.y) } + #[inline] - fn xz(self) -> DVec2 { - DVec2::new(self.x, self.z) + fn wwxz(self) -> DVec4 { + DVec4::new(self.w, self.w, self.x, self.z) } + #[inline] - fn xw(self) -> DVec2 { - DVec2::new(self.x, self.w) + fn wwxw(self) -> DVec4 { + DVec4::new(self.w, self.w, self.x, self.w) } + #[inline] - fn yx(self) -> DVec2 { - DVec2::new(self.y, self.x) + fn wwyx(self) -> DVec4 { + DVec4::new(self.w, self.w, self.y, self.x) } + #[inline] - fn yy(self) -> DVec2 { - DVec2::new(self.y, self.y) + fn wwyy(self) -> DVec4 { + DVec4::new(self.w, self.w, self.y, self.y) } + #[inline] - fn yz(self) -> DVec2 { - DVec2::new(self.y, self.z) + fn wwyz(self) -> DVec4 { + DVec4::new(self.w, self.w, self.y, self.z) } + #[inline] - fn yw(self) -> DVec2 { - DVec2::new(self.y, self.w) + fn wwyw(self) -> DVec4 { + DVec4::new(self.w, self.w, self.y, self.w) } + #[inline] - fn zx(self) -> DVec2 { - DVec2::new(self.z, self.x) + fn wwzx(self) -> DVec4 { + DVec4::new(self.w, self.w, self.z, self.x) } + #[inline] - fn zy(self) -> DVec2 { - DVec2::new(self.z, self.y) + fn wwzy(self) -> DVec4 { + DVec4::new(self.w, self.w, self.z, self.y) } + #[inline] - fn zz(self) -> DVec2 { - DVec2::new(self.z, self.z) + fn wwzz(self) -> DVec4 { + DVec4::new(self.w, self.w, self.z, self.z) } + #[inline] - fn zw(self) -> DVec2 { - DVec2::new(self.z, self.w) + fn wwzw(self) -> DVec4 { + DVec4::new(self.w, self.w, self.z, self.w) } + #[inline] - fn wx(self) -> DVec2 { - DVec2::new(self.w, self.x) + fn wwwx(self) -> DVec4 { + DVec4::new(self.w, self.w, self.w, self.x) } + #[inline] - fn wy(self) -> DVec2 { - DVec2::new(self.w, self.y) + fn wwwy(self) -> DVec4 { + DVec4::new(self.w, self.w, self.w, self.y) } + #[inline] - fn wz(self) -> DVec2 { - DVec2::new(self.w, self.z) + fn wwwz(self) -> DVec4 { + DVec4::new(self.w, self.w, self.w, self.z) } + #[inline] - fn ww(self) -> DVec2 { - DVec2::new(self.w, self.w) + fn wwww(self) -> DVec4 { + DVec4::new(self.w, self.w, self.w, self.w) } } diff --git a/src/swizzles/ivec2_impl_scalar.rs b/src/swizzles/ivec2_impl_scalar.rs index 26702c87..5076e595 100644 --- a/src/swizzles/ivec2_impl_scalar.rs +++ b/src/swizzles/ivec2_impl_scalar.rs @@ -1,118 +1,196 @@ -// Generated by swizzlegen. Do not edit. +// Generated from swizzle_impl.rs template. Edit the template, not the generated file. + +#![allow(clippy::useless_conversion)] use super::Vec2Swizzles; use crate::{IVec2, IVec3, IVec4}; impl Vec2Swizzles for IVec2 { type Vec3 = IVec3; + type Vec4 = IVec4; + #[inline] + fn xx(self) -> IVec2 { + IVec2 { + x: self.x, + y: self.x, + } + } + + #[inline] + fn xy(self) -> IVec2 { + IVec2 { + x: self.x, + y: self.y, + } + } + + #[inline] + fn yx(self) -> IVec2 { + IVec2 { + x: self.y, + y: self.x, + } + } + + #[inline] + fn yy(self) -> IVec2 { + IVec2 { + x: self.y, + y: self.y, + } + } + + #[inline] + fn xxx(self) -> IVec3 { + IVec3 { + x: self.x, + y: self.x, + z: self.x, + } + } + + #[inline] + fn xxy(self) -> IVec3 { + IVec3 { + x: self.x, + y: self.x, + z: self.y, + } + } + + #[inline] + fn xyx(self) -> IVec3 { + IVec3 { + x: self.x, + y: self.y, + z: self.x, + } + } + + #[inline] + fn xyy(self) -> IVec3 { + IVec3 { + x: self.x, + y: self.y, + z: self.y, + } + } + + #[inline] + fn yxx(self) -> IVec3 { + IVec3 { + x: self.y, + y: self.x, + z: self.x, + } + } + + #[inline] + fn yxy(self) -> IVec3 { + IVec3 { + x: self.y, + y: self.x, + z: self.y, + } + } + + #[inline] + fn yyx(self) -> IVec3 { + IVec3 { + x: self.y, + y: self.y, + z: self.x, + } + } + + #[inline] + fn yyy(self) -> IVec3 { + IVec3 { + x: self.y, + y: self.y, + z: self.y, + } + } + #[inline] fn xxxx(self) -> IVec4 { IVec4::new(self.x, self.x, self.x, self.x) } + #[inline] fn xxxy(self) -> IVec4 { IVec4::new(self.x, self.x, self.x, self.y) } + #[inline] fn xxyx(self) -> IVec4 { IVec4::new(self.x, self.x, self.y, self.x) } + #[inline] fn xxyy(self) -> IVec4 { IVec4::new(self.x, self.x, self.y, self.y) } + #[inline] fn xyxx(self) -> IVec4 { IVec4::new(self.x, self.y, self.x, self.x) } + #[inline] fn xyxy(self) -> IVec4 { IVec4::new(self.x, self.y, self.x, self.y) } + #[inline] fn xyyx(self) -> IVec4 { IVec4::new(self.x, self.y, self.y, self.x) } + #[inline] fn xyyy(self) -> IVec4 { IVec4::new(self.x, self.y, self.y, self.y) } + #[inline] fn yxxx(self) -> IVec4 { IVec4::new(self.y, self.x, self.x, self.x) } + #[inline] fn yxxy(self) -> IVec4 { IVec4::new(self.y, self.x, self.x, self.y) } + #[inline] fn yxyx(self) -> IVec4 { IVec4::new(self.y, self.x, self.y, self.x) } + #[inline] fn yxyy(self) -> IVec4 { IVec4::new(self.y, self.x, self.y, self.y) } + #[inline] fn yyxx(self) -> IVec4 { IVec4::new(self.y, self.y, self.x, self.x) } + #[inline] fn yyxy(self) -> IVec4 { IVec4::new(self.y, self.y, self.x, self.y) } + #[inline] fn yyyx(self) -> IVec4 { IVec4::new(self.y, self.y, self.y, self.x) } + #[inline] fn yyyy(self) -> IVec4 { IVec4::new(self.y, self.y, self.y, self.y) } - #[inline] - fn xxx(self) -> IVec3 { - IVec3::new(self.x, self.x, self.x) - } - #[inline] - fn xxy(self) -> IVec3 { - IVec3::new(self.x, self.x, self.y) - } - #[inline] - fn xyx(self) -> IVec3 { - IVec3::new(self.x, self.y, self.x) - } - #[inline] - fn xyy(self) -> IVec3 { - IVec3::new(self.x, self.y, self.y) - } - #[inline] - fn yxx(self) -> IVec3 { - IVec3::new(self.y, self.x, self.x) - } - #[inline] - fn yxy(self) -> IVec3 { - IVec3::new(self.y, self.x, self.y) - } - #[inline] - fn yyx(self) -> IVec3 { - IVec3::new(self.y, self.y, self.x) - } - #[inline] - fn yyy(self) -> IVec3 { - IVec3::new(self.y, self.y, self.y) - } - #[inline] - fn xx(self) -> Self { - Self::new(self.x, self.x) - } - #[inline] - fn yx(self) -> Self { - Self::new(self.y, self.x) - } - #[inline] - fn yy(self) -> Self { - Self::new(self.y, self.y) - } } diff --git a/src/swizzles/ivec3_impl_scalar.rs b/src/swizzles/ivec3_impl_scalar.rs index 799e5d83..53aed4c0 100644 --- a/src/swizzles/ivec3_impl_scalar.rs +++ b/src/swizzles/ivec3_impl_scalar.rs @@ -1,474 +1,732 @@ -// Generated by swizzlegen. Do not edit. +// Generated from swizzle_impl.rs template. Edit the template, not the generated file. + +#![allow(clippy::useless_conversion)] use super::Vec3Swizzles; use crate::{IVec2, IVec3, IVec4}; impl Vec3Swizzles for IVec3 { type Vec2 = IVec2; + type Vec4 = IVec4; + #[inline] + fn xx(self) -> IVec2 { + IVec2 { + x: self.x, + y: self.x, + } + } + + #[inline] + fn xy(self) -> IVec2 { + IVec2 { + x: self.x, + y: self.y, + } + } + + #[inline] + fn xz(self) -> IVec2 { + IVec2 { + x: self.x, + y: self.z, + } + } + + #[inline] + fn yx(self) -> IVec2 { + IVec2 { + x: self.y, + y: self.x, + } + } + + #[inline] + fn yy(self) -> IVec2 { + IVec2 { + x: self.y, + y: self.y, + } + } + + #[inline] + fn yz(self) -> IVec2 { + IVec2 { + x: self.y, + y: self.z, + } + } + + #[inline] + fn zx(self) -> IVec2 { + IVec2 { + x: self.z, + y: self.x, + } + } + + #[inline] + fn zy(self) -> IVec2 { + IVec2 { + x: self.z, + y: self.y, + } + } + + #[inline] + fn zz(self) -> IVec2 { + IVec2 { + x: self.z, + y: self.z, + } + } + + #[inline] + fn xxx(self) -> IVec3 { + IVec3 { + x: self.x, + y: self.x, + z: self.x, + } + } + + #[inline] + fn xxy(self) -> IVec3 { + IVec3 { + x: self.x, + y: self.x, + z: self.y, + } + } + + #[inline] + fn xxz(self) -> IVec3 { + IVec3 { + x: self.x, + y: self.x, + z: self.z, + } + } + + #[inline] + fn xyx(self) -> IVec3 { + IVec3 { + x: self.x, + y: self.y, + z: self.x, + } + } + + #[inline] + fn xyy(self) -> IVec3 { + IVec3 { + x: self.x, + y: self.y, + z: self.y, + } + } + + #[inline] + fn xyz(self) -> IVec3 { + IVec3 { + x: self.x, + y: self.y, + z: self.z, + } + } + + #[inline] + fn xzx(self) -> IVec3 { + IVec3 { + x: self.x, + y: self.z, + z: self.x, + } + } + + #[inline] + fn xzy(self) -> IVec3 { + IVec3 { + x: self.x, + y: self.z, + z: self.y, + } + } + + #[inline] + fn xzz(self) -> IVec3 { + IVec3 { + x: self.x, + y: self.z, + z: self.z, + } + } + + #[inline] + fn yxx(self) -> IVec3 { + IVec3 { + x: self.y, + y: self.x, + z: self.x, + } + } + + #[inline] + fn yxy(self) -> IVec3 { + IVec3 { + x: self.y, + y: self.x, + z: self.y, + } + } + + #[inline] + fn yxz(self) -> IVec3 { + IVec3 { + x: self.y, + y: self.x, + z: self.z, + } + } + + #[inline] + fn yyx(self) -> IVec3 { + IVec3 { + x: self.y, + y: self.y, + z: self.x, + } + } + + #[inline] + fn yyy(self) -> IVec3 { + IVec3 { + x: self.y, + y: self.y, + z: self.y, + } + } + + #[inline] + fn yyz(self) -> IVec3 { + IVec3 { + x: self.y, + y: self.y, + z: self.z, + } + } + + #[inline] + fn yzx(self) -> IVec3 { + IVec3 { + x: self.y, + y: self.z, + z: self.x, + } + } + + #[inline] + fn yzy(self) -> IVec3 { + IVec3 { + x: self.y, + y: self.z, + z: self.y, + } + } + + #[inline] + fn yzz(self) -> IVec3 { + IVec3 { + x: self.y, + y: self.z, + z: self.z, + } + } + + #[inline] + fn zxx(self) -> IVec3 { + IVec3 { + x: self.z, + y: self.x, + z: self.x, + } + } + + #[inline] + fn zxy(self) -> IVec3 { + IVec3 { + x: self.z, + y: self.x, + z: self.y, + } + } + + #[inline] + fn zxz(self) -> IVec3 { + IVec3 { + x: self.z, + y: self.x, + z: self.z, + } + } + + #[inline] + fn zyx(self) -> IVec3 { + IVec3 { + x: self.z, + y: self.y, + z: self.x, + } + } + + #[inline] + fn zyy(self) -> IVec3 { + IVec3 { + x: self.z, + y: self.y, + z: self.y, + } + } + + #[inline] + fn zyz(self) -> IVec3 { + IVec3 { + x: self.z, + y: self.y, + z: self.z, + } + } + + #[inline] + fn zzx(self) -> IVec3 { + IVec3 { + x: self.z, + y: self.z, + z: self.x, + } + } + + #[inline] + fn zzy(self) -> IVec3 { + IVec3 { + x: self.z, + y: self.z, + z: self.y, + } + } + + #[inline] + fn zzz(self) -> IVec3 { + IVec3 { + x: self.z, + y: self.z, + z: self.z, + } + } + #[inline] fn xxxx(self) -> IVec4 { IVec4::new(self.x, self.x, self.x, self.x) } + #[inline] fn xxxy(self) -> IVec4 { IVec4::new(self.x, self.x, self.x, self.y) } + #[inline] fn xxxz(self) -> IVec4 { IVec4::new(self.x, self.x, self.x, self.z) } + #[inline] fn xxyx(self) -> IVec4 { IVec4::new(self.x, self.x, self.y, self.x) } + #[inline] fn xxyy(self) -> IVec4 { IVec4::new(self.x, self.x, self.y, self.y) } + #[inline] fn xxyz(self) -> IVec4 { IVec4::new(self.x, self.x, self.y, self.z) } + #[inline] fn xxzx(self) -> IVec4 { IVec4::new(self.x, self.x, self.z, self.x) } + #[inline] fn xxzy(self) -> IVec4 { IVec4::new(self.x, self.x, self.z, self.y) } + #[inline] fn xxzz(self) -> IVec4 { IVec4::new(self.x, self.x, self.z, self.z) } + #[inline] fn xyxx(self) -> IVec4 { IVec4::new(self.x, self.y, self.x, self.x) } + #[inline] fn xyxy(self) -> IVec4 { IVec4::new(self.x, self.y, self.x, self.y) } + #[inline] fn xyxz(self) -> IVec4 { IVec4::new(self.x, self.y, self.x, self.z) } + #[inline] fn xyyx(self) -> IVec4 { IVec4::new(self.x, self.y, self.y, self.x) } + #[inline] fn xyyy(self) -> IVec4 { IVec4::new(self.x, self.y, self.y, self.y) } + #[inline] fn xyyz(self) -> IVec4 { IVec4::new(self.x, self.y, self.y, self.z) } + #[inline] fn xyzx(self) -> IVec4 { IVec4::new(self.x, self.y, self.z, self.x) } + #[inline] fn xyzy(self) -> IVec4 { IVec4::new(self.x, self.y, self.z, self.y) } + #[inline] fn xyzz(self) -> IVec4 { IVec4::new(self.x, self.y, self.z, self.z) } + #[inline] fn xzxx(self) -> IVec4 { IVec4::new(self.x, self.z, self.x, self.x) } + #[inline] fn xzxy(self) -> IVec4 { IVec4::new(self.x, self.z, self.x, self.y) } + #[inline] fn xzxz(self) -> IVec4 { IVec4::new(self.x, self.z, self.x, self.z) } + #[inline] fn xzyx(self) -> IVec4 { IVec4::new(self.x, self.z, self.y, self.x) } + #[inline] fn xzyy(self) -> IVec4 { IVec4::new(self.x, self.z, self.y, self.y) } + #[inline] fn xzyz(self) -> IVec4 { IVec4::new(self.x, self.z, self.y, self.z) } + #[inline] fn xzzx(self) -> IVec4 { IVec4::new(self.x, self.z, self.z, self.x) } + #[inline] fn xzzy(self) -> IVec4 { IVec4::new(self.x, self.z, self.z, self.y) } + #[inline] fn xzzz(self) -> IVec4 { IVec4::new(self.x, self.z, self.z, self.z) } + #[inline] fn yxxx(self) -> IVec4 { IVec4::new(self.y, self.x, self.x, self.x) } + #[inline] fn yxxy(self) -> IVec4 { IVec4::new(self.y, self.x, self.x, self.y) } + #[inline] fn yxxz(self) -> IVec4 { IVec4::new(self.y, self.x, self.x, self.z) } + #[inline] fn yxyx(self) -> IVec4 { IVec4::new(self.y, self.x, self.y, self.x) } + #[inline] fn yxyy(self) -> IVec4 { IVec4::new(self.y, self.x, self.y, self.y) } + #[inline] fn yxyz(self) -> IVec4 { IVec4::new(self.y, self.x, self.y, self.z) } + #[inline] fn yxzx(self) -> IVec4 { IVec4::new(self.y, self.x, self.z, self.x) } + #[inline] fn yxzy(self) -> IVec4 { IVec4::new(self.y, self.x, self.z, self.y) } + #[inline] fn yxzz(self) -> IVec4 { IVec4::new(self.y, self.x, self.z, self.z) } + #[inline] fn yyxx(self) -> IVec4 { IVec4::new(self.y, self.y, self.x, self.x) } + #[inline] fn yyxy(self) -> IVec4 { IVec4::new(self.y, self.y, self.x, self.y) } + #[inline] fn yyxz(self) -> IVec4 { IVec4::new(self.y, self.y, self.x, self.z) } + #[inline] fn yyyx(self) -> IVec4 { IVec4::new(self.y, self.y, self.y, self.x) } + #[inline] fn yyyy(self) -> IVec4 { IVec4::new(self.y, self.y, self.y, self.y) } + #[inline] fn yyyz(self) -> IVec4 { IVec4::new(self.y, self.y, self.y, self.z) } + #[inline] fn yyzx(self) -> IVec4 { IVec4::new(self.y, self.y, self.z, self.x) } + #[inline] fn yyzy(self) -> IVec4 { IVec4::new(self.y, self.y, self.z, self.y) } + #[inline] fn yyzz(self) -> IVec4 { IVec4::new(self.y, self.y, self.z, self.z) } + #[inline] fn yzxx(self) -> IVec4 { IVec4::new(self.y, self.z, self.x, self.x) } + #[inline] fn yzxy(self) -> IVec4 { IVec4::new(self.y, self.z, self.x, self.y) } + #[inline] fn yzxz(self) -> IVec4 { IVec4::new(self.y, self.z, self.x, self.z) } + #[inline] fn yzyx(self) -> IVec4 { IVec4::new(self.y, self.z, self.y, self.x) } + #[inline] fn yzyy(self) -> IVec4 { IVec4::new(self.y, self.z, self.y, self.y) } + #[inline] fn yzyz(self) -> IVec4 { IVec4::new(self.y, self.z, self.y, self.z) } + #[inline] fn yzzx(self) -> IVec4 { IVec4::new(self.y, self.z, self.z, self.x) } + #[inline] fn yzzy(self) -> IVec4 { IVec4::new(self.y, self.z, self.z, self.y) } + #[inline] fn yzzz(self) -> IVec4 { IVec4::new(self.y, self.z, self.z, self.z) } + #[inline] fn zxxx(self) -> IVec4 { IVec4::new(self.z, self.x, self.x, self.x) } + #[inline] fn zxxy(self) -> IVec4 { IVec4::new(self.z, self.x, self.x, self.y) } + #[inline] fn zxxz(self) -> IVec4 { IVec4::new(self.z, self.x, self.x, self.z) } + #[inline] fn zxyx(self) -> IVec4 { IVec4::new(self.z, self.x, self.y, self.x) } + #[inline] fn zxyy(self) -> IVec4 { IVec4::new(self.z, self.x, self.y, self.y) } + #[inline] fn zxyz(self) -> IVec4 { IVec4::new(self.z, self.x, self.y, self.z) } + #[inline] fn zxzx(self) -> IVec4 { IVec4::new(self.z, self.x, self.z, self.x) } + #[inline] fn zxzy(self) -> IVec4 { IVec4::new(self.z, self.x, self.z, self.y) } + #[inline] fn zxzz(self) -> IVec4 { IVec4::new(self.z, self.x, self.z, self.z) } + #[inline] fn zyxx(self) -> IVec4 { IVec4::new(self.z, self.y, self.x, self.x) } + #[inline] fn zyxy(self) -> IVec4 { IVec4::new(self.z, self.y, self.x, self.y) } + #[inline] fn zyxz(self) -> IVec4 { IVec4::new(self.z, self.y, self.x, self.z) } + #[inline] fn zyyx(self) -> IVec4 { IVec4::new(self.z, self.y, self.y, self.x) } + #[inline] fn zyyy(self) -> IVec4 { IVec4::new(self.z, self.y, self.y, self.y) } + #[inline] fn zyyz(self) -> IVec4 { IVec4::new(self.z, self.y, self.y, self.z) } + #[inline] fn zyzx(self) -> IVec4 { IVec4::new(self.z, self.y, self.z, self.x) } + #[inline] fn zyzy(self) -> IVec4 { IVec4::new(self.z, self.y, self.z, self.y) } + #[inline] fn zyzz(self) -> IVec4 { IVec4::new(self.z, self.y, self.z, self.z) } + #[inline] fn zzxx(self) -> IVec4 { IVec4::new(self.z, self.z, self.x, self.x) } + #[inline] fn zzxy(self) -> IVec4 { IVec4::new(self.z, self.z, self.x, self.y) } + #[inline] fn zzxz(self) -> IVec4 { IVec4::new(self.z, self.z, self.x, self.z) } + #[inline] fn zzyx(self) -> IVec4 { IVec4::new(self.z, self.z, self.y, self.x) } + #[inline] fn zzyy(self) -> IVec4 { IVec4::new(self.z, self.z, self.y, self.y) } + #[inline] fn zzyz(self) -> IVec4 { IVec4::new(self.z, self.z, self.y, self.z) } + #[inline] fn zzzx(self) -> IVec4 { IVec4::new(self.z, self.z, self.z, self.x) } + #[inline] fn zzzy(self) -> IVec4 { IVec4::new(self.z, self.z, self.z, self.y) } + #[inline] fn zzzz(self) -> IVec4 { IVec4::new(self.z, self.z, self.z, self.z) } - #[inline] - fn xxx(self) -> Self { - Self::new(self.x, self.x, self.x) - } - #[inline] - fn xxy(self) -> Self { - Self::new(self.x, self.x, self.y) - } - #[inline] - fn xxz(self) -> Self { - Self::new(self.x, self.x, self.z) - } - #[inline] - fn xyx(self) -> Self { - Self::new(self.x, self.y, self.x) - } - #[inline] - fn xyy(self) -> Self { - Self::new(self.x, self.y, self.y) - } - #[inline] - fn xzx(self) -> Self { - Self::new(self.x, self.z, self.x) - } - #[inline] - fn xzy(self) -> Self { - Self::new(self.x, self.z, self.y) - } - #[inline] - fn xzz(self) -> Self { - Self::new(self.x, self.z, self.z) - } - #[inline] - fn yxx(self) -> Self { - Self::new(self.y, self.x, self.x) - } - #[inline] - fn yxy(self) -> Self { - Self::new(self.y, self.x, self.y) - } - #[inline] - fn yxz(self) -> Self { - Self::new(self.y, self.x, self.z) - } - #[inline] - fn yyx(self) -> Self { - Self::new(self.y, self.y, self.x) - } - #[inline] - fn yyy(self) -> Self { - Self::new(self.y, self.y, self.y) - } - #[inline] - fn yyz(self) -> Self { - Self::new(self.y, self.y, self.z) - } - #[inline] - fn yzx(self) -> Self { - Self::new(self.y, self.z, self.x) - } - #[inline] - fn yzy(self) -> Self { - Self::new(self.y, self.z, self.y) - } - #[inline] - fn yzz(self) -> Self { - Self::new(self.y, self.z, self.z) - } - #[inline] - fn zxx(self) -> Self { - Self::new(self.z, self.x, self.x) - } - #[inline] - fn zxy(self) -> Self { - Self::new(self.z, self.x, self.y) - } - #[inline] - fn zxz(self) -> Self { - Self::new(self.z, self.x, self.z) - } - #[inline] - fn zyx(self) -> Self { - Self::new(self.z, self.y, self.x) - } - #[inline] - fn zyy(self) -> Self { - Self::new(self.z, self.y, self.y) - } - #[inline] - fn zyz(self) -> Self { - Self::new(self.z, self.y, self.z) - } - #[inline] - fn zzx(self) -> Self { - Self::new(self.z, self.z, self.x) - } - #[inline] - fn zzy(self) -> Self { - Self::new(self.z, self.z, self.y) - } - #[inline] - fn zzz(self) -> Self { - Self::new(self.z, self.z, self.z) - } - #[inline] - fn xx(self) -> IVec2 { - IVec2::new(self.x, self.x) - } - #[inline] - fn xy(self) -> IVec2 { - IVec2::new(self.x, self.y) - } - #[inline] - fn xz(self) -> IVec2 { - IVec2::new(self.x, self.z) - } - #[inline] - fn yx(self) -> IVec2 { - IVec2::new(self.y, self.x) - } - #[inline] - fn yy(self) -> IVec2 { - IVec2::new(self.y, self.y) - } - #[inline] - fn yz(self) -> IVec2 { - IVec2::new(self.y, self.z) - } - #[inline] - fn zx(self) -> IVec2 { - IVec2::new(self.z, self.x) - } - #[inline] - fn zy(self) -> IVec2 { - IVec2::new(self.z, self.y) - } - #[inline] - fn zz(self) -> IVec2 { - IVec2::new(self.z, self.z) - } } diff --git a/src/swizzles/ivec4_impl_scalar.rs b/src/swizzles/ivec4_impl_scalar.rs index a4985af5..6ebd0dd4 100644 --- a/src/swizzles/ivec4_impl_scalar.rs +++ b/src/swizzles/ivec4_impl_scalar.rs @@ -1,1350 +1,1996 @@ -// Generated by swizzlegen. Do not edit. +// Generated from swizzle_impl.rs template. Edit the template, not the generated file. + +#![allow(clippy::useless_conversion)] use super::Vec4Swizzles; use crate::{IVec2, IVec3, IVec4}; impl Vec4Swizzles for IVec4 { type Vec2 = IVec2; + type Vec3 = IVec3; #[inline] - fn xxxx(self) -> IVec4 { - IVec4::new(self.x, self.x, self.x, self.x) + fn xx(self) -> IVec2 { + IVec2 { + x: self.x, + y: self.x, + } } + #[inline] - fn xxxy(self) -> IVec4 { - IVec4::new(self.x, self.x, self.x, self.y) + fn xy(self) -> IVec2 { + IVec2 { + x: self.x, + y: self.y, + } } + #[inline] - fn xxxz(self) -> IVec4 { - IVec4::new(self.x, self.x, self.x, self.z) + fn xz(self) -> IVec2 { + IVec2 { + x: self.x, + y: self.z, + } } + #[inline] - fn xxxw(self) -> IVec4 { - IVec4::new(self.x, self.x, self.x, self.w) + fn xw(self) -> IVec2 { + IVec2 { + x: self.x, + y: self.w, + } } + #[inline] - fn xxyx(self) -> IVec4 { - IVec4::new(self.x, self.x, self.y, self.x) + fn yx(self) -> IVec2 { + IVec2 { + x: self.y, + y: self.x, + } } + #[inline] - fn xxyy(self) -> IVec4 { - IVec4::new(self.x, self.x, self.y, self.y) + fn yy(self) -> IVec2 { + IVec2 { + x: self.y, + y: self.y, + } } + #[inline] - fn xxyz(self) -> IVec4 { - IVec4::new(self.x, self.x, self.y, self.z) + fn yz(self) -> IVec2 { + IVec2 { + x: self.y, + y: self.z, + } } + #[inline] - fn xxyw(self) -> IVec4 { - IVec4::new(self.x, self.x, self.y, self.w) + fn yw(self) -> IVec2 { + IVec2 { + x: self.y, + y: self.w, + } } + #[inline] - fn xxzx(self) -> IVec4 { - IVec4::new(self.x, self.x, self.z, self.x) + fn zx(self) -> IVec2 { + IVec2 { + x: self.z, + y: self.x, + } } + #[inline] - fn xxzy(self) -> IVec4 { - IVec4::new(self.x, self.x, self.z, self.y) + fn zy(self) -> IVec2 { + IVec2 { + x: self.z, + y: self.y, + } } + #[inline] - fn xxzz(self) -> IVec4 { - IVec4::new(self.x, self.x, self.z, self.z) + fn zz(self) -> IVec2 { + IVec2 { + x: self.z, + y: self.z, + } } + #[inline] - fn xxzw(self) -> IVec4 { - IVec4::new(self.x, self.x, self.z, self.w) + fn zw(self) -> IVec2 { + IVec2 { + x: self.z, + y: self.w, + } } + #[inline] - fn xxwx(self) -> IVec4 { - IVec4::new(self.x, self.x, self.w, self.x) + fn wx(self) -> IVec2 { + IVec2 { + x: self.w, + y: self.x, + } } + #[inline] - fn xxwy(self) -> IVec4 { - IVec4::new(self.x, self.x, self.w, self.y) + fn wy(self) -> IVec2 { + IVec2 { + x: self.w, + y: self.y, + } } + #[inline] - fn xxwz(self) -> IVec4 { - IVec4::new(self.x, self.x, self.w, self.z) + fn wz(self) -> IVec2 { + IVec2 { + x: self.w, + y: self.z, + } } + #[inline] - fn xxww(self) -> IVec4 { - IVec4::new(self.x, self.x, self.w, self.w) + fn ww(self) -> IVec2 { + IVec2 { + x: self.w, + y: self.w, + } } + #[inline] - fn xyxx(self) -> IVec4 { - IVec4::new(self.x, self.y, self.x, self.x) + fn xxx(self) -> IVec3 { + IVec3 { + x: self.x, + y: self.x, + z: self.x, + } } + #[inline] - fn xyxy(self) -> IVec4 { - IVec4::new(self.x, self.y, self.x, self.y) + fn xxy(self) -> IVec3 { + IVec3 { + x: self.x, + y: self.x, + z: self.y, + } } + #[inline] - fn xyxz(self) -> IVec4 { - IVec4::new(self.x, self.y, self.x, self.z) + fn xxz(self) -> IVec3 { + IVec3 { + x: self.x, + y: self.x, + z: self.z, + } } + #[inline] - fn xyxw(self) -> IVec4 { - IVec4::new(self.x, self.y, self.x, self.w) + fn xxw(self) -> IVec3 { + IVec3 { + x: self.x, + y: self.x, + z: self.w, + } } + #[inline] - fn xyyx(self) -> IVec4 { - IVec4::new(self.x, self.y, self.y, self.x) + fn xyx(self) -> IVec3 { + IVec3 { + x: self.x, + y: self.y, + z: self.x, + } } + #[inline] - fn xyyy(self) -> IVec4 { - IVec4::new(self.x, self.y, self.y, self.y) + fn xyy(self) -> IVec3 { + IVec3 { + x: self.x, + y: self.y, + z: self.y, + } } + #[inline] - fn xyyz(self) -> IVec4 { - IVec4::new(self.x, self.y, self.y, self.z) + fn xyz(self) -> IVec3 { + IVec3 { + x: self.x, + y: self.y, + z: self.z, + } } + #[inline] - fn xyyw(self) -> IVec4 { - IVec4::new(self.x, self.y, self.y, self.w) + fn xyw(self) -> IVec3 { + IVec3 { + x: self.x, + y: self.y, + z: self.w, + } } + #[inline] - fn xyzx(self) -> IVec4 { - IVec4::new(self.x, self.y, self.z, self.x) + fn xzx(self) -> IVec3 { + IVec3 { + x: self.x, + y: self.z, + z: self.x, + } } + #[inline] - fn xyzy(self) -> IVec4 { - IVec4::new(self.x, self.y, self.z, self.y) + fn xzy(self) -> IVec3 { + IVec3 { + x: self.x, + y: self.z, + z: self.y, + } } + #[inline] - fn xyzz(self) -> IVec4 { - IVec4::new(self.x, self.y, self.z, self.z) + fn xzz(self) -> IVec3 { + IVec3 { + x: self.x, + y: self.z, + z: self.z, + } } + #[inline] - fn xywx(self) -> IVec4 { - IVec4::new(self.x, self.y, self.w, self.x) + fn xzw(self) -> IVec3 { + IVec3 { + x: self.x, + y: self.z, + z: self.w, + } } + #[inline] - fn xywy(self) -> IVec4 { - IVec4::new(self.x, self.y, self.w, self.y) + fn xwx(self) -> IVec3 { + IVec3 { + x: self.x, + y: self.w, + z: self.x, + } } + #[inline] - fn xywz(self) -> IVec4 { - IVec4::new(self.x, self.y, self.w, self.z) + fn xwy(self) -> IVec3 { + IVec3 { + x: self.x, + y: self.w, + z: self.y, + } } + #[inline] - fn xyww(self) -> IVec4 { - IVec4::new(self.x, self.y, self.w, self.w) + fn xwz(self) -> IVec3 { + IVec3 { + x: self.x, + y: self.w, + z: self.z, + } } + #[inline] - fn xzxx(self) -> IVec4 { - IVec4::new(self.x, self.z, self.x, self.x) + fn xww(self) -> IVec3 { + IVec3 { + x: self.x, + y: self.w, + z: self.w, + } } + #[inline] - fn xzxy(self) -> IVec4 { - IVec4::new(self.x, self.z, self.x, self.y) + fn yxx(self) -> IVec3 { + IVec3 { + x: self.y, + y: self.x, + z: self.x, + } } + #[inline] - fn xzxz(self) -> IVec4 { - IVec4::new(self.x, self.z, self.x, self.z) + fn yxy(self) -> IVec3 { + IVec3 { + x: self.y, + y: self.x, + z: self.y, + } } + #[inline] - fn xzxw(self) -> IVec4 { - IVec4::new(self.x, self.z, self.x, self.w) + fn yxz(self) -> IVec3 { + IVec3 { + x: self.y, + y: self.x, + z: self.z, + } } + #[inline] - fn xzyx(self) -> IVec4 { - IVec4::new(self.x, self.z, self.y, self.x) + fn yxw(self) -> IVec3 { + IVec3 { + x: self.y, + y: self.x, + z: self.w, + } } + #[inline] - fn xzyy(self) -> IVec4 { - IVec4::new(self.x, self.z, self.y, self.y) + fn yyx(self) -> IVec3 { + IVec3 { + x: self.y, + y: self.y, + z: self.x, + } } + #[inline] - fn xzyz(self) -> IVec4 { - IVec4::new(self.x, self.z, self.y, self.z) + fn yyy(self) -> IVec3 { + IVec3 { + x: self.y, + y: self.y, + z: self.y, + } } + #[inline] - fn xzyw(self) -> IVec4 { - IVec4::new(self.x, self.z, self.y, self.w) + fn yyz(self) -> IVec3 { + IVec3 { + x: self.y, + y: self.y, + z: self.z, + } } + #[inline] - fn xzzx(self) -> IVec4 { - IVec4::new(self.x, self.z, self.z, self.x) + fn yyw(self) -> IVec3 { + IVec3 { + x: self.y, + y: self.y, + z: self.w, + } } + #[inline] - fn xzzy(self) -> IVec4 { - IVec4::new(self.x, self.z, self.z, self.y) + fn yzx(self) -> IVec3 { + IVec3 { + x: self.y, + y: self.z, + z: self.x, + } } + #[inline] - fn xzzz(self) -> IVec4 { - IVec4::new(self.x, self.z, self.z, self.z) + fn yzy(self) -> IVec3 { + IVec3 { + x: self.y, + y: self.z, + z: self.y, + } } + #[inline] - fn xzzw(self) -> IVec4 { - IVec4::new(self.x, self.z, self.z, self.w) + fn yzz(self) -> IVec3 { + IVec3 { + x: self.y, + y: self.z, + z: self.z, + } } + #[inline] - fn xzwx(self) -> IVec4 { - IVec4::new(self.x, self.z, self.w, self.x) + fn yzw(self) -> IVec3 { + IVec3 { + x: self.y, + y: self.z, + z: self.w, + } } + #[inline] - fn xzwy(self) -> IVec4 { - IVec4::new(self.x, self.z, self.w, self.y) + fn ywx(self) -> IVec3 { + IVec3 { + x: self.y, + y: self.w, + z: self.x, + } } + #[inline] - fn xzwz(self) -> IVec4 { - IVec4::new(self.x, self.z, self.w, self.z) + fn ywy(self) -> IVec3 { + IVec3 { + x: self.y, + y: self.w, + z: self.y, + } } + #[inline] - fn xzww(self) -> IVec4 { - IVec4::new(self.x, self.z, self.w, self.w) + fn ywz(self) -> IVec3 { + IVec3 { + x: self.y, + y: self.w, + z: self.z, + } } + #[inline] - fn xwxx(self) -> IVec4 { - IVec4::new(self.x, self.w, self.x, self.x) + fn yww(self) -> IVec3 { + IVec3 { + x: self.y, + y: self.w, + z: self.w, + } } + #[inline] - fn xwxy(self) -> IVec4 { - IVec4::new(self.x, self.w, self.x, self.y) + fn zxx(self) -> IVec3 { + IVec3 { + x: self.z, + y: self.x, + z: self.x, + } } + #[inline] - fn xwxz(self) -> IVec4 { - IVec4::new(self.x, self.w, self.x, self.z) + fn zxy(self) -> IVec3 { + IVec3 { + x: self.z, + y: self.x, + z: self.y, + } } + #[inline] - fn xwxw(self) -> IVec4 { - IVec4::new(self.x, self.w, self.x, self.w) + fn zxz(self) -> IVec3 { + IVec3 { + x: self.z, + y: self.x, + z: self.z, + } } + #[inline] - fn xwyx(self) -> IVec4 { - IVec4::new(self.x, self.w, self.y, self.x) + fn zxw(self) -> IVec3 { + IVec3 { + x: self.z, + y: self.x, + z: self.w, + } } + #[inline] - fn xwyy(self) -> IVec4 { - IVec4::new(self.x, self.w, self.y, self.y) + fn zyx(self) -> IVec3 { + IVec3 { + x: self.z, + y: self.y, + z: self.x, + } } + #[inline] - fn xwyz(self) -> IVec4 { - IVec4::new(self.x, self.w, self.y, self.z) + fn zyy(self) -> IVec3 { + IVec3 { + x: self.z, + y: self.y, + z: self.y, + } } + #[inline] - fn xwyw(self) -> IVec4 { - IVec4::new(self.x, self.w, self.y, self.w) + fn zyz(self) -> IVec3 { + IVec3 { + x: self.z, + y: self.y, + z: self.z, + } } + #[inline] - fn xwzx(self) -> IVec4 { - IVec4::new(self.x, self.w, self.z, self.x) + fn zyw(self) -> IVec3 { + IVec3 { + x: self.z, + y: self.y, + z: self.w, + } } + #[inline] - fn xwzy(self) -> IVec4 { - IVec4::new(self.x, self.w, self.z, self.y) + fn zzx(self) -> IVec3 { + IVec3 { + x: self.z, + y: self.z, + z: self.x, + } } + #[inline] - fn xwzz(self) -> IVec4 { - IVec4::new(self.x, self.w, self.z, self.z) + fn zzy(self) -> IVec3 { + IVec3 { + x: self.z, + y: self.z, + z: self.y, + } } + #[inline] - fn xwzw(self) -> IVec4 { - IVec4::new(self.x, self.w, self.z, self.w) + fn zzz(self) -> IVec3 { + IVec3 { + x: self.z, + y: self.z, + z: self.z, + } } + #[inline] - fn xwwx(self) -> IVec4 { - IVec4::new(self.x, self.w, self.w, self.x) + fn zzw(self) -> IVec3 { + IVec3 { + x: self.z, + y: self.z, + z: self.w, + } } + #[inline] - fn xwwy(self) -> IVec4 { - IVec4::new(self.x, self.w, self.w, self.y) + fn zwx(self) -> IVec3 { + IVec3 { + x: self.z, + y: self.w, + z: self.x, + } } + #[inline] - fn xwwz(self) -> IVec4 { - IVec4::new(self.x, self.w, self.w, self.z) + fn zwy(self) -> IVec3 { + IVec3 { + x: self.z, + y: self.w, + z: self.y, + } } + #[inline] - fn xwww(self) -> IVec4 { - IVec4::new(self.x, self.w, self.w, self.w) + fn zwz(self) -> IVec3 { + IVec3 { + x: self.z, + y: self.w, + z: self.z, + } } + #[inline] - fn yxxx(self) -> IVec4 { - IVec4::new(self.y, self.x, self.x, self.x) + fn zww(self) -> IVec3 { + IVec3 { + x: self.z, + y: self.w, + z: self.w, + } } + #[inline] - fn yxxy(self) -> IVec4 { - IVec4::new(self.y, self.x, self.x, self.y) + fn wxx(self) -> IVec3 { + IVec3 { + x: self.w, + y: self.x, + z: self.x, + } } + #[inline] - fn yxxz(self) -> IVec4 { - IVec4::new(self.y, self.x, self.x, self.z) + fn wxy(self) -> IVec3 { + IVec3 { + x: self.w, + y: self.x, + z: self.y, + } } + #[inline] - fn yxxw(self) -> IVec4 { - IVec4::new(self.y, self.x, self.x, self.w) + fn wxz(self) -> IVec3 { + IVec3 { + x: self.w, + y: self.x, + z: self.z, + } } + #[inline] - fn yxyx(self) -> IVec4 { - IVec4::new(self.y, self.x, self.y, self.x) + fn wxw(self) -> IVec3 { + IVec3 { + x: self.w, + y: self.x, + z: self.w, + } } + #[inline] - fn yxyy(self) -> IVec4 { - IVec4::new(self.y, self.x, self.y, self.y) + fn wyx(self) -> IVec3 { + IVec3 { + x: self.w, + y: self.y, + z: self.x, + } } + #[inline] - fn yxyz(self) -> IVec4 { - IVec4::new(self.y, self.x, self.y, self.z) + fn wyy(self) -> IVec3 { + IVec3 { + x: self.w, + y: self.y, + z: self.y, + } } + #[inline] - fn yxyw(self) -> IVec4 { - IVec4::new(self.y, self.x, self.y, self.w) + fn wyz(self) -> IVec3 { + IVec3 { + x: self.w, + y: self.y, + z: self.z, + } } + #[inline] - fn yxzx(self) -> IVec4 { - IVec4::new(self.y, self.x, self.z, self.x) + fn wyw(self) -> IVec3 { + IVec3 { + x: self.w, + y: self.y, + z: self.w, + } } + #[inline] - fn yxzy(self) -> IVec4 { - IVec4::new(self.y, self.x, self.z, self.y) + fn wzx(self) -> IVec3 { + IVec3 { + x: self.w, + y: self.z, + z: self.x, + } } + #[inline] - fn yxzz(self) -> IVec4 { - IVec4::new(self.y, self.x, self.z, self.z) + fn wzy(self) -> IVec3 { + IVec3 { + x: self.w, + y: self.z, + z: self.y, + } } + #[inline] - fn yxzw(self) -> IVec4 { - IVec4::new(self.y, self.x, self.z, self.w) + fn wzz(self) -> IVec3 { + IVec3 { + x: self.w, + y: self.z, + z: self.z, + } } + #[inline] - fn yxwx(self) -> IVec4 { - IVec4::new(self.y, self.x, self.w, self.x) + fn wzw(self) -> IVec3 { + IVec3 { + x: self.w, + y: self.z, + z: self.w, + } } + #[inline] - fn yxwy(self) -> IVec4 { - IVec4::new(self.y, self.x, self.w, self.y) + fn wwx(self) -> IVec3 { + IVec3 { + x: self.w, + y: self.w, + z: self.x, + } } + #[inline] - fn yxwz(self) -> IVec4 { - IVec4::new(self.y, self.x, self.w, self.z) + fn wwy(self) -> IVec3 { + IVec3 { + x: self.w, + y: self.w, + z: self.y, + } } + #[inline] - fn yxww(self) -> IVec4 { - IVec4::new(self.y, self.x, self.w, self.w) + fn wwz(self) -> IVec3 { + IVec3 { + x: self.w, + y: self.w, + z: self.z, + } } + #[inline] - fn yyxx(self) -> IVec4 { - IVec4::new(self.y, self.y, self.x, self.x) + fn www(self) -> IVec3 { + IVec3 { + x: self.w, + y: self.w, + z: self.w, + } } + #[inline] - fn yyxy(self) -> IVec4 { - IVec4::new(self.y, self.y, self.x, self.y) + fn xxxx(self) -> IVec4 { + IVec4::new(self.x, self.x, self.x, self.x) } + #[inline] - fn yyxz(self) -> IVec4 { - IVec4::new(self.y, self.y, self.x, self.z) + fn xxxy(self) -> IVec4 { + IVec4::new(self.x, self.x, self.x, self.y) } + #[inline] - fn yyxw(self) -> IVec4 { - IVec4::new(self.y, self.y, self.x, self.w) + fn xxxz(self) -> IVec4 { + IVec4::new(self.x, self.x, self.x, self.z) } + #[inline] - fn yyyx(self) -> IVec4 { - IVec4::new(self.y, self.y, self.y, self.x) + fn xxxw(self) -> IVec4 { + IVec4::new(self.x, self.x, self.x, self.w) } + #[inline] - fn yyyy(self) -> IVec4 { - IVec4::new(self.y, self.y, self.y, self.y) + fn xxyx(self) -> IVec4 { + IVec4::new(self.x, self.x, self.y, self.x) } + #[inline] - fn yyyz(self) -> IVec4 { - IVec4::new(self.y, self.y, self.y, self.z) + fn xxyy(self) -> IVec4 { + IVec4::new(self.x, self.x, self.y, self.y) } + #[inline] - fn yyyw(self) -> IVec4 { - IVec4::new(self.y, self.y, self.y, self.w) + fn xxyz(self) -> IVec4 { + IVec4::new(self.x, self.x, self.y, self.z) } + #[inline] - fn yyzx(self) -> IVec4 { - IVec4::new(self.y, self.y, self.z, self.x) + fn xxyw(self) -> IVec4 { + IVec4::new(self.x, self.x, self.y, self.w) } + #[inline] - fn yyzy(self) -> IVec4 { - IVec4::new(self.y, self.y, self.z, self.y) + fn xxzx(self) -> IVec4 { + IVec4::new(self.x, self.x, self.z, self.x) } + #[inline] - fn yyzz(self) -> IVec4 { - IVec4::new(self.y, self.y, self.z, self.z) + fn xxzy(self) -> IVec4 { + IVec4::new(self.x, self.x, self.z, self.y) } + #[inline] - fn yyzw(self) -> IVec4 { - IVec4::new(self.y, self.y, self.z, self.w) + fn xxzz(self) -> IVec4 { + IVec4::new(self.x, self.x, self.z, self.z) } + #[inline] - fn yywx(self) -> IVec4 { - IVec4::new(self.y, self.y, self.w, self.x) + fn xxzw(self) -> IVec4 { + IVec4::new(self.x, self.x, self.z, self.w) } + #[inline] - fn yywy(self) -> IVec4 { - IVec4::new(self.y, self.y, self.w, self.y) + fn xxwx(self) -> IVec4 { + IVec4::new(self.x, self.x, self.w, self.x) } + #[inline] - fn yywz(self) -> IVec4 { - IVec4::new(self.y, self.y, self.w, self.z) + fn xxwy(self) -> IVec4 { + IVec4::new(self.x, self.x, self.w, self.y) } + #[inline] - fn yyww(self) -> IVec4 { - IVec4::new(self.y, self.y, self.w, self.w) + fn xxwz(self) -> IVec4 { + IVec4::new(self.x, self.x, self.w, self.z) } + #[inline] - fn yzxx(self) -> IVec4 { - IVec4::new(self.y, self.z, self.x, self.x) + fn xxww(self) -> IVec4 { + IVec4::new(self.x, self.x, self.w, self.w) } + #[inline] - fn yzxy(self) -> IVec4 { - IVec4::new(self.y, self.z, self.x, self.y) + fn xyxx(self) -> IVec4 { + IVec4::new(self.x, self.y, self.x, self.x) } + #[inline] - fn yzxz(self) -> IVec4 { - IVec4::new(self.y, self.z, self.x, self.z) + fn xyxy(self) -> IVec4 { + IVec4::new(self.x, self.y, self.x, self.y) } + #[inline] - fn yzxw(self) -> IVec4 { - IVec4::new(self.y, self.z, self.x, self.w) + fn xyxz(self) -> IVec4 { + IVec4::new(self.x, self.y, self.x, self.z) } + #[inline] - fn yzyx(self) -> IVec4 { - IVec4::new(self.y, self.z, self.y, self.x) + fn xyxw(self) -> IVec4 { + IVec4::new(self.x, self.y, self.x, self.w) } + #[inline] - fn yzyy(self) -> IVec4 { - IVec4::new(self.y, self.z, self.y, self.y) + fn xyyx(self) -> IVec4 { + IVec4::new(self.x, self.y, self.y, self.x) } + #[inline] - fn yzyz(self) -> IVec4 { - IVec4::new(self.y, self.z, self.y, self.z) + fn xyyy(self) -> IVec4 { + IVec4::new(self.x, self.y, self.y, self.y) } + #[inline] - fn yzyw(self) -> IVec4 { - IVec4::new(self.y, self.z, self.y, self.w) + fn xyyz(self) -> IVec4 { + IVec4::new(self.x, self.y, self.y, self.z) } + #[inline] - fn yzzx(self) -> IVec4 { - IVec4::new(self.y, self.z, self.z, self.x) + fn xyyw(self) -> IVec4 { + IVec4::new(self.x, self.y, self.y, self.w) } + #[inline] - fn yzzy(self) -> IVec4 { - IVec4::new(self.y, self.z, self.z, self.y) + fn xyzx(self) -> IVec4 { + IVec4::new(self.x, self.y, self.z, self.x) } + #[inline] - fn yzzz(self) -> IVec4 { - IVec4::new(self.y, self.z, self.z, self.z) + fn xyzy(self) -> IVec4 { + IVec4::new(self.x, self.y, self.z, self.y) } + #[inline] - fn yzzw(self) -> IVec4 { - IVec4::new(self.y, self.z, self.z, self.w) + fn xyzz(self) -> IVec4 { + IVec4::new(self.x, self.y, self.z, self.z) } + #[inline] - fn yzwx(self) -> IVec4 { - IVec4::new(self.y, self.z, self.w, self.x) + fn xyzw(self) -> IVec4 { + IVec4::new(self.x, self.y, self.z, self.w) } + #[inline] - fn yzwy(self) -> IVec4 { - IVec4::new(self.y, self.z, self.w, self.y) + fn xywx(self) -> IVec4 { + IVec4::new(self.x, self.y, self.w, self.x) } + #[inline] - fn yzwz(self) -> IVec4 { - IVec4::new(self.y, self.z, self.w, self.z) + fn xywy(self) -> IVec4 { + IVec4::new(self.x, self.y, self.w, self.y) } + #[inline] - fn yzww(self) -> IVec4 { - IVec4::new(self.y, self.z, self.w, self.w) + fn xywz(self) -> IVec4 { + IVec4::new(self.x, self.y, self.w, self.z) } + #[inline] - fn ywxx(self) -> IVec4 { - IVec4::new(self.y, self.w, self.x, self.x) + fn xyww(self) -> IVec4 { + IVec4::new(self.x, self.y, self.w, self.w) } + #[inline] - fn ywxy(self) -> IVec4 { - IVec4::new(self.y, self.w, self.x, self.y) + fn xzxx(self) -> IVec4 { + IVec4::new(self.x, self.z, self.x, self.x) } + #[inline] - fn ywxz(self) -> IVec4 { - IVec4::new(self.y, self.w, self.x, self.z) + fn xzxy(self) -> IVec4 { + IVec4::new(self.x, self.z, self.x, self.y) } + #[inline] - fn ywxw(self) -> IVec4 { - IVec4::new(self.y, self.w, self.x, self.w) + fn xzxz(self) -> IVec4 { + IVec4::new(self.x, self.z, self.x, self.z) } + #[inline] - fn ywyx(self) -> IVec4 { - IVec4::new(self.y, self.w, self.y, self.x) + fn xzxw(self) -> IVec4 { + IVec4::new(self.x, self.z, self.x, self.w) } + #[inline] - fn ywyy(self) -> IVec4 { - IVec4::new(self.y, self.w, self.y, self.y) + fn xzyx(self) -> IVec4 { + IVec4::new(self.x, self.z, self.y, self.x) } + #[inline] - fn ywyz(self) -> IVec4 { - IVec4::new(self.y, self.w, self.y, self.z) + fn xzyy(self) -> IVec4 { + IVec4::new(self.x, self.z, self.y, self.y) } + #[inline] - fn ywyw(self) -> IVec4 { - IVec4::new(self.y, self.w, self.y, self.w) + fn xzyz(self) -> IVec4 { + IVec4::new(self.x, self.z, self.y, self.z) } + #[inline] - fn ywzx(self) -> IVec4 { - IVec4::new(self.y, self.w, self.z, self.x) + fn xzyw(self) -> IVec4 { + IVec4::new(self.x, self.z, self.y, self.w) } + #[inline] - fn ywzy(self) -> IVec4 { - IVec4::new(self.y, self.w, self.z, self.y) + fn xzzx(self) -> IVec4 { + IVec4::new(self.x, self.z, self.z, self.x) } + #[inline] - fn ywzz(self) -> IVec4 { - IVec4::new(self.y, self.w, self.z, self.z) + fn xzzy(self) -> IVec4 { + IVec4::new(self.x, self.z, self.z, self.y) } + #[inline] - fn ywzw(self) -> IVec4 { - IVec4::new(self.y, self.w, self.z, self.w) + fn xzzz(self) -> IVec4 { + IVec4::new(self.x, self.z, self.z, self.z) } + #[inline] - fn ywwx(self) -> IVec4 { - IVec4::new(self.y, self.w, self.w, self.x) + fn xzzw(self) -> IVec4 { + IVec4::new(self.x, self.z, self.z, self.w) } + #[inline] - fn ywwy(self) -> IVec4 { - IVec4::new(self.y, self.w, self.w, self.y) + fn xzwx(self) -> IVec4 { + IVec4::new(self.x, self.z, self.w, self.x) } + #[inline] - fn ywwz(self) -> IVec4 { - IVec4::new(self.y, self.w, self.w, self.z) + fn xzwy(self) -> IVec4 { + IVec4::new(self.x, self.z, self.w, self.y) } + #[inline] - fn ywww(self) -> IVec4 { - IVec4::new(self.y, self.w, self.w, self.w) + fn xzwz(self) -> IVec4 { + IVec4::new(self.x, self.z, self.w, self.z) } + #[inline] - fn zxxx(self) -> IVec4 { - IVec4::new(self.z, self.x, self.x, self.x) + fn xzww(self) -> IVec4 { + IVec4::new(self.x, self.z, self.w, self.w) } + #[inline] - fn zxxy(self) -> IVec4 { - IVec4::new(self.z, self.x, self.x, self.y) + fn xwxx(self) -> IVec4 { + IVec4::new(self.x, self.w, self.x, self.x) } + #[inline] - fn zxxz(self) -> IVec4 { - IVec4::new(self.z, self.x, self.x, self.z) + fn xwxy(self) -> IVec4 { + IVec4::new(self.x, self.w, self.x, self.y) } + #[inline] - fn zxxw(self) -> IVec4 { - IVec4::new(self.z, self.x, self.x, self.w) + fn xwxz(self) -> IVec4 { + IVec4::new(self.x, self.w, self.x, self.z) } + #[inline] - fn zxyx(self) -> IVec4 { - IVec4::new(self.z, self.x, self.y, self.x) + fn xwxw(self) -> IVec4 { + IVec4::new(self.x, self.w, self.x, self.w) } + #[inline] - fn zxyy(self) -> IVec4 { - IVec4::new(self.z, self.x, self.y, self.y) + fn xwyx(self) -> IVec4 { + IVec4::new(self.x, self.w, self.y, self.x) } + #[inline] - fn zxyz(self) -> IVec4 { - IVec4::new(self.z, self.x, self.y, self.z) + fn xwyy(self) -> IVec4 { + IVec4::new(self.x, self.w, self.y, self.y) } + #[inline] - fn zxyw(self) -> IVec4 { - IVec4::new(self.z, self.x, self.y, self.w) + fn xwyz(self) -> IVec4 { + IVec4::new(self.x, self.w, self.y, self.z) } + #[inline] - fn zxzx(self) -> IVec4 { - IVec4::new(self.z, self.x, self.z, self.x) + fn xwyw(self) -> IVec4 { + IVec4::new(self.x, self.w, self.y, self.w) } + #[inline] - fn zxzy(self) -> IVec4 { - IVec4::new(self.z, self.x, self.z, self.y) + fn xwzx(self) -> IVec4 { + IVec4::new(self.x, self.w, self.z, self.x) } + #[inline] - fn zxzz(self) -> IVec4 { - IVec4::new(self.z, self.x, self.z, self.z) + fn xwzy(self) -> IVec4 { + IVec4::new(self.x, self.w, self.z, self.y) } + #[inline] - fn zxzw(self) -> IVec4 { - IVec4::new(self.z, self.x, self.z, self.w) + fn xwzz(self) -> IVec4 { + IVec4::new(self.x, self.w, self.z, self.z) } + #[inline] - fn zxwx(self) -> IVec4 { - IVec4::new(self.z, self.x, self.w, self.x) + fn xwzw(self) -> IVec4 { + IVec4::new(self.x, self.w, self.z, self.w) } + #[inline] - fn zxwy(self) -> IVec4 { - IVec4::new(self.z, self.x, self.w, self.y) + fn xwwx(self) -> IVec4 { + IVec4::new(self.x, self.w, self.w, self.x) } + #[inline] - fn zxwz(self) -> IVec4 { - IVec4::new(self.z, self.x, self.w, self.z) + fn xwwy(self) -> IVec4 { + IVec4::new(self.x, self.w, self.w, self.y) } + #[inline] - fn zxww(self) -> IVec4 { - IVec4::new(self.z, self.x, self.w, self.w) + fn xwwz(self) -> IVec4 { + IVec4::new(self.x, self.w, self.w, self.z) } + #[inline] - fn zyxx(self) -> IVec4 { - IVec4::new(self.z, self.y, self.x, self.x) + fn xwww(self) -> IVec4 { + IVec4::new(self.x, self.w, self.w, self.w) } + #[inline] - fn zyxy(self) -> IVec4 { - IVec4::new(self.z, self.y, self.x, self.y) + fn yxxx(self) -> IVec4 { + IVec4::new(self.y, self.x, self.x, self.x) } + #[inline] - fn zyxz(self) -> IVec4 { - IVec4::new(self.z, self.y, self.x, self.z) + fn yxxy(self) -> IVec4 { + IVec4::new(self.y, self.x, self.x, self.y) } + #[inline] - fn zyxw(self) -> IVec4 { - IVec4::new(self.z, self.y, self.x, self.w) + fn yxxz(self) -> IVec4 { + IVec4::new(self.y, self.x, self.x, self.z) } + #[inline] - fn zyyx(self) -> IVec4 { - IVec4::new(self.z, self.y, self.y, self.x) + fn yxxw(self) -> IVec4 { + IVec4::new(self.y, self.x, self.x, self.w) } + #[inline] - fn zyyy(self) -> IVec4 { - IVec4::new(self.z, self.y, self.y, self.y) + fn yxyx(self) -> IVec4 { + IVec4::new(self.y, self.x, self.y, self.x) } + #[inline] - fn zyyz(self) -> IVec4 { - IVec4::new(self.z, self.y, self.y, self.z) + fn yxyy(self) -> IVec4 { + IVec4::new(self.y, self.x, self.y, self.y) } + #[inline] - fn zyyw(self) -> IVec4 { - IVec4::new(self.z, self.y, self.y, self.w) + fn yxyz(self) -> IVec4 { + IVec4::new(self.y, self.x, self.y, self.z) } + #[inline] - fn zyzx(self) -> IVec4 { - IVec4::new(self.z, self.y, self.z, self.x) + fn yxyw(self) -> IVec4 { + IVec4::new(self.y, self.x, self.y, self.w) } + #[inline] - fn zyzy(self) -> IVec4 { - IVec4::new(self.z, self.y, self.z, self.y) + fn yxzx(self) -> IVec4 { + IVec4::new(self.y, self.x, self.z, self.x) } + #[inline] - fn zyzz(self) -> IVec4 { - IVec4::new(self.z, self.y, self.z, self.z) + fn yxzy(self) -> IVec4 { + IVec4::new(self.y, self.x, self.z, self.y) } + #[inline] - fn zyzw(self) -> IVec4 { - IVec4::new(self.z, self.y, self.z, self.w) + fn yxzz(self) -> IVec4 { + IVec4::new(self.y, self.x, self.z, self.z) } + #[inline] - fn zywx(self) -> IVec4 { - IVec4::new(self.z, self.y, self.w, self.x) + fn yxzw(self) -> IVec4 { + IVec4::new(self.y, self.x, self.z, self.w) } + #[inline] - fn zywy(self) -> IVec4 { - IVec4::new(self.z, self.y, self.w, self.y) + fn yxwx(self) -> IVec4 { + IVec4::new(self.y, self.x, self.w, self.x) } + #[inline] - fn zywz(self) -> IVec4 { - IVec4::new(self.z, self.y, self.w, self.z) + fn yxwy(self) -> IVec4 { + IVec4::new(self.y, self.x, self.w, self.y) } + #[inline] - fn zyww(self) -> IVec4 { - IVec4::new(self.z, self.y, self.w, self.w) + fn yxwz(self) -> IVec4 { + IVec4::new(self.y, self.x, self.w, self.z) } + #[inline] - fn zzxx(self) -> IVec4 { - IVec4::new(self.z, self.z, self.x, self.x) + fn yxww(self) -> IVec4 { + IVec4::new(self.y, self.x, self.w, self.w) } + #[inline] - fn zzxy(self) -> IVec4 { - IVec4::new(self.z, self.z, self.x, self.y) + fn yyxx(self) -> IVec4 { + IVec4::new(self.y, self.y, self.x, self.x) } + #[inline] - fn zzxz(self) -> IVec4 { - IVec4::new(self.z, self.z, self.x, self.z) + fn yyxy(self) -> IVec4 { + IVec4::new(self.y, self.y, self.x, self.y) } + #[inline] - fn zzxw(self) -> IVec4 { - IVec4::new(self.z, self.z, self.x, self.w) + fn yyxz(self) -> IVec4 { + IVec4::new(self.y, self.y, self.x, self.z) } + #[inline] - fn zzyx(self) -> IVec4 { - IVec4::new(self.z, self.z, self.y, self.x) + fn yyxw(self) -> IVec4 { + IVec4::new(self.y, self.y, self.x, self.w) } + #[inline] - fn zzyy(self) -> IVec4 { - IVec4::new(self.z, self.z, self.y, self.y) + fn yyyx(self) -> IVec4 { + IVec4::new(self.y, self.y, self.y, self.x) } + #[inline] - fn zzyz(self) -> IVec4 { - IVec4::new(self.z, self.z, self.y, self.z) + fn yyyy(self) -> IVec4 { + IVec4::new(self.y, self.y, self.y, self.y) } + #[inline] - fn zzyw(self) -> IVec4 { - IVec4::new(self.z, self.z, self.y, self.w) + fn yyyz(self) -> IVec4 { + IVec4::new(self.y, self.y, self.y, self.z) } + #[inline] - fn zzzx(self) -> IVec4 { - IVec4::new(self.z, self.z, self.z, self.x) + fn yyyw(self) -> IVec4 { + IVec4::new(self.y, self.y, self.y, self.w) } + #[inline] - fn zzzy(self) -> IVec4 { - IVec4::new(self.z, self.z, self.z, self.y) + fn yyzx(self) -> IVec4 { + IVec4::new(self.y, self.y, self.z, self.x) } + #[inline] - fn zzzz(self) -> IVec4 { - IVec4::new(self.z, self.z, self.z, self.z) + fn yyzy(self) -> IVec4 { + IVec4::new(self.y, self.y, self.z, self.y) } + #[inline] - fn zzzw(self) -> IVec4 { - IVec4::new(self.z, self.z, self.z, self.w) + fn yyzz(self) -> IVec4 { + IVec4::new(self.y, self.y, self.z, self.z) } + #[inline] - fn zzwx(self) -> IVec4 { - IVec4::new(self.z, self.z, self.w, self.x) + fn yyzw(self) -> IVec4 { + IVec4::new(self.y, self.y, self.z, self.w) } + #[inline] - fn zzwy(self) -> IVec4 { - IVec4::new(self.z, self.z, self.w, self.y) + fn yywx(self) -> IVec4 { + IVec4::new(self.y, self.y, self.w, self.x) } + #[inline] - fn zzwz(self) -> IVec4 { - IVec4::new(self.z, self.z, self.w, self.z) + fn yywy(self) -> IVec4 { + IVec4::new(self.y, self.y, self.w, self.y) } + #[inline] - fn zzww(self) -> IVec4 { - IVec4::new(self.z, self.z, self.w, self.w) + fn yywz(self) -> IVec4 { + IVec4::new(self.y, self.y, self.w, self.z) } + #[inline] - fn zwxx(self) -> IVec4 { - IVec4::new(self.z, self.w, self.x, self.x) + fn yyww(self) -> IVec4 { + IVec4::new(self.y, self.y, self.w, self.w) } + #[inline] - fn zwxy(self) -> IVec4 { - IVec4::new(self.z, self.w, self.x, self.y) + fn yzxx(self) -> IVec4 { + IVec4::new(self.y, self.z, self.x, self.x) } + #[inline] - fn zwxz(self) -> IVec4 { - IVec4::new(self.z, self.w, self.x, self.z) + fn yzxy(self) -> IVec4 { + IVec4::new(self.y, self.z, self.x, self.y) } + #[inline] - fn zwxw(self) -> IVec4 { - IVec4::new(self.z, self.w, self.x, self.w) + fn yzxz(self) -> IVec4 { + IVec4::new(self.y, self.z, self.x, self.z) } + #[inline] - fn zwyx(self) -> IVec4 { - IVec4::new(self.z, self.w, self.y, self.x) + fn yzxw(self) -> IVec4 { + IVec4::new(self.y, self.z, self.x, self.w) } + #[inline] - fn zwyy(self) -> IVec4 { - IVec4::new(self.z, self.w, self.y, self.y) + fn yzyx(self) -> IVec4 { + IVec4::new(self.y, self.z, self.y, self.x) } + #[inline] - fn zwyz(self) -> IVec4 { - IVec4::new(self.z, self.w, self.y, self.z) + fn yzyy(self) -> IVec4 { + IVec4::new(self.y, self.z, self.y, self.y) } + #[inline] - fn zwyw(self) -> IVec4 { - IVec4::new(self.z, self.w, self.y, self.w) + fn yzyz(self) -> IVec4 { + IVec4::new(self.y, self.z, self.y, self.z) } + #[inline] - fn zwzx(self) -> IVec4 { - IVec4::new(self.z, self.w, self.z, self.x) + fn yzyw(self) -> IVec4 { + IVec4::new(self.y, self.z, self.y, self.w) } + #[inline] - fn zwzy(self) -> IVec4 { - IVec4::new(self.z, self.w, self.z, self.y) + fn yzzx(self) -> IVec4 { + IVec4::new(self.y, self.z, self.z, self.x) } + #[inline] - fn zwzz(self) -> IVec4 { - IVec4::new(self.z, self.w, self.z, self.z) + fn yzzy(self) -> IVec4 { + IVec4::new(self.y, self.z, self.z, self.y) } + #[inline] - fn zwzw(self) -> IVec4 { - IVec4::new(self.z, self.w, self.z, self.w) + fn yzzz(self) -> IVec4 { + IVec4::new(self.y, self.z, self.z, self.z) } + #[inline] - fn zwwx(self) -> IVec4 { - IVec4::new(self.z, self.w, self.w, self.x) + fn yzzw(self) -> IVec4 { + IVec4::new(self.y, self.z, self.z, self.w) } + #[inline] - fn zwwy(self) -> IVec4 { - IVec4::new(self.z, self.w, self.w, self.y) + fn yzwx(self) -> IVec4 { + IVec4::new(self.y, self.z, self.w, self.x) } + #[inline] - fn zwwz(self) -> IVec4 { - IVec4::new(self.z, self.w, self.w, self.z) + fn yzwy(self) -> IVec4 { + IVec4::new(self.y, self.z, self.w, self.y) } + #[inline] - fn zwww(self) -> IVec4 { - IVec4::new(self.z, self.w, self.w, self.w) + fn yzwz(self) -> IVec4 { + IVec4::new(self.y, self.z, self.w, self.z) } + #[inline] - fn wxxx(self) -> IVec4 { - IVec4::new(self.w, self.x, self.x, self.x) + fn yzww(self) -> IVec4 { + IVec4::new(self.y, self.z, self.w, self.w) } + #[inline] - fn wxxy(self) -> IVec4 { - IVec4::new(self.w, self.x, self.x, self.y) + fn ywxx(self) -> IVec4 { + IVec4::new(self.y, self.w, self.x, self.x) } + #[inline] - fn wxxz(self) -> IVec4 { - IVec4::new(self.w, self.x, self.x, self.z) + fn ywxy(self) -> IVec4 { + IVec4::new(self.y, self.w, self.x, self.y) } + #[inline] - fn wxxw(self) -> IVec4 { - IVec4::new(self.w, self.x, self.x, self.w) + fn ywxz(self) -> IVec4 { + IVec4::new(self.y, self.w, self.x, self.z) } + #[inline] - fn wxyx(self) -> IVec4 { - IVec4::new(self.w, self.x, self.y, self.x) + fn ywxw(self) -> IVec4 { + IVec4::new(self.y, self.w, self.x, self.w) } + #[inline] - fn wxyy(self) -> IVec4 { - IVec4::new(self.w, self.x, self.y, self.y) + fn ywyx(self) -> IVec4 { + IVec4::new(self.y, self.w, self.y, self.x) } + #[inline] - fn wxyz(self) -> IVec4 { - IVec4::new(self.w, self.x, self.y, self.z) + fn ywyy(self) -> IVec4 { + IVec4::new(self.y, self.w, self.y, self.y) } + #[inline] - fn wxyw(self) -> IVec4 { - IVec4::new(self.w, self.x, self.y, self.w) + fn ywyz(self) -> IVec4 { + IVec4::new(self.y, self.w, self.y, self.z) } + #[inline] - fn wxzx(self) -> IVec4 { - IVec4::new(self.w, self.x, self.z, self.x) + fn ywyw(self) -> IVec4 { + IVec4::new(self.y, self.w, self.y, self.w) } + #[inline] - fn wxzy(self) -> IVec4 { - IVec4::new(self.w, self.x, self.z, self.y) + fn ywzx(self) -> IVec4 { + IVec4::new(self.y, self.w, self.z, self.x) } + #[inline] - fn wxzz(self) -> IVec4 { - IVec4::new(self.w, self.x, self.z, self.z) + fn ywzy(self) -> IVec4 { + IVec4::new(self.y, self.w, self.z, self.y) } + #[inline] - fn wxzw(self) -> IVec4 { - IVec4::new(self.w, self.x, self.z, self.w) + fn ywzz(self) -> IVec4 { + IVec4::new(self.y, self.w, self.z, self.z) } + #[inline] - fn wxwx(self) -> IVec4 { - IVec4::new(self.w, self.x, self.w, self.x) + fn ywzw(self) -> IVec4 { + IVec4::new(self.y, self.w, self.z, self.w) } + #[inline] - fn wxwy(self) -> IVec4 { - IVec4::new(self.w, self.x, self.w, self.y) + fn ywwx(self) -> IVec4 { + IVec4::new(self.y, self.w, self.w, self.x) } + #[inline] - fn wxwz(self) -> IVec4 { - IVec4::new(self.w, self.x, self.w, self.z) + fn ywwy(self) -> IVec4 { + IVec4::new(self.y, self.w, self.w, self.y) } + #[inline] - fn wxww(self) -> IVec4 { - IVec4::new(self.w, self.x, self.w, self.w) + fn ywwz(self) -> IVec4 { + IVec4::new(self.y, self.w, self.w, self.z) } + #[inline] - fn wyxx(self) -> IVec4 { - IVec4::new(self.w, self.y, self.x, self.x) + fn ywww(self) -> IVec4 { + IVec4::new(self.y, self.w, self.w, self.w) } + #[inline] - fn wyxy(self) -> IVec4 { - IVec4::new(self.w, self.y, self.x, self.y) + fn zxxx(self) -> IVec4 { + IVec4::new(self.z, self.x, self.x, self.x) } + #[inline] - fn wyxz(self) -> IVec4 { - IVec4::new(self.w, self.y, self.x, self.z) + fn zxxy(self) -> IVec4 { + IVec4::new(self.z, self.x, self.x, self.y) } + #[inline] - fn wyxw(self) -> IVec4 { - IVec4::new(self.w, self.y, self.x, self.w) + fn zxxz(self) -> IVec4 { + IVec4::new(self.z, self.x, self.x, self.z) } + #[inline] - fn wyyx(self) -> IVec4 { - IVec4::new(self.w, self.y, self.y, self.x) + fn zxxw(self) -> IVec4 { + IVec4::new(self.z, self.x, self.x, self.w) } + #[inline] - fn wyyy(self) -> IVec4 { - IVec4::new(self.w, self.y, self.y, self.y) + fn zxyx(self) -> IVec4 { + IVec4::new(self.z, self.x, self.y, self.x) } + #[inline] - fn wyyz(self) -> IVec4 { - IVec4::new(self.w, self.y, self.y, self.z) + fn zxyy(self) -> IVec4 { + IVec4::new(self.z, self.x, self.y, self.y) } + #[inline] - fn wyyw(self) -> IVec4 { - IVec4::new(self.w, self.y, self.y, self.w) + fn zxyz(self) -> IVec4 { + IVec4::new(self.z, self.x, self.y, self.z) } + #[inline] - fn wyzx(self) -> IVec4 { - IVec4::new(self.w, self.y, self.z, self.x) + fn zxyw(self) -> IVec4 { + IVec4::new(self.z, self.x, self.y, self.w) } + #[inline] - fn wyzy(self) -> IVec4 { - IVec4::new(self.w, self.y, self.z, self.y) + fn zxzx(self) -> IVec4 { + IVec4::new(self.z, self.x, self.z, self.x) + } + + #[inline] + fn zxzy(self) -> IVec4 { + IVec4::new(self.z, self.x, self.z, self.y) } + #[inline] - fn wyzz(self) -> IVec4 { - IVec4::new(self.w, self.y, self.z, self.z) + fn zxzz(self) -> IVec4 { + IVec4::new(self.z, self.x, self.z, self.z) } + #[inline] - fn wyzw(self) -> IVec4 { - IVec4::new(self.w, self.y, self.z, self.w) + fn zxzw(self) -> IVec4 { + IVec4::new(self.z, self.x, self.z, self.w) } + #[inline] - fn wywx(self) -> IVec4 { - IVec4::new(self.w, self.y, self.w, self.x) + fn zxwx(self) -> IVec4 { + IVec4::new(self.z, self.x, self.w, self.x) } + #[inline] - fn wywy(self) -> IVec4 { - IVec4::new(self.w, self.y, self.w, self.y) + fn zxwy(self) -> IVec4 { + IVec4::new(self.z, self.x, self.w, self.y) } + #[inline] - fn wywz(self) -> IVec4 { - IVec4::new(self.w, self.y, self.w, self.z) + fn zxwz(self) -> IVec4 { + IVec4::new(self.z, self.x, self.w, self.z) } + #[inline] - fn wyww(self) -> IVec4 { - IVec4::new(self.w, self.y, self.w, self.w) + fn zxww(self) -> IVec4 { + IVec4::new(self.z, self.x, self.w, self.w) } + #[inline] - fn wzxx(self) -> IVec4 { - IVec4::new(self.w, self.z, self.x, self.x) + fn zyxx(self) -> IVec4 { + IVec4::new(self.z, self.y, self.x, self.x) } + #[inline] - fn wzxy(self) -> IVec4 { - IVec4::new(self.w, self.z, self.x, self.y) + fn zyxy(self) -> IVec4 { + IVec4::new(self.z, self.y, self.x, self.y) } + #[inline] - fn wzxz(self) -> IVec4 { - IVec4::new(self.w, self.z, self.x, self.z) + fn zyxz(self) -> IVec4 { + IVec4::new(self.z, self.y, self.x, self.z) } + #[inline] - fn wzxw(self) -> IVec4 { - IVec4::new(self.w, self.z, self.x, self.w) + fn zyxw(self) -> IVec4 { + IVec4::new(self.z, self.y, self.x, self.w) } + #[inline] - fn wzyx(self) -> IVec4 { - IVec4::new(self.w, self.z, self.y, self.x) + fn zyyx(self) -> IVec4 { + IVec4::new(self.z, self.y, self.y, self.x) } + #[inline] - fn wzyy(self) -> IVec4 { - IVec4::new(self.w, self.z, self.y, self.y) + fn zyyy(self) -> IVec4 { + IVec4::new(self.z, self.y, self.y, self.y) } + #[inline] - fn wzyz(self) -> IVec4 { - IVec4::new(self.w, self.z, self.y, self.z) + fn zyyz(self) -> IVec4 { + IVec4::new(self.z, self.y, self.y, self.z) } + #[inline] - fn wzyw(self) -> IVec4 { - IVec4::new(self.w, self.z, self.y, self.w) + fn zyyw(self) -> IVec4 { + IVec4::new(self.z, self.y, self.y, self.w) } + #[inline] - fn wzzx(self) -> IVec4 { - IVec4::new(self.w, self.z, self.z, self.x) + fn zyzx(self) -> IVec4 { + IVec4::new(self.z, self.y, self.z, self.x) } + #[inline] - fn wzzy(self) -> IVec4 { - IVec4::new(self.w, self.z, self.z, self.y) + fn zyzy(self) -> IVec4 { + IVec4::new(self.z, self.y, self.z, self.y) } + #[inline] - fn wzzz(self) -> IVec4 { - IVec4::new(self.w, self.z, self.z, self.z) + fn zyzz(self) -> IVec4 { + IVec4::new(self.z, self.y, self.z, self.z) } + #[inline] - fn wzzw(self) -> IVec4 { - IVec4::new(self.w, self.z, self.z, self.w) + fn zyzw(self) -> IVec4 { + IVec4::new(self.z, self.y, self.z, self.w) } + #[inline] - fn wzwx(self) -> IVec4 { - IVec4::new(self.w, self.z, self.w, self.x) + fn zywx(self) -> IVec4 { + IVec4::new(self.z, self.y, self.w, self.x) } + #[inline] - fn wzwy(self) -> IVec4 { - IVec4::new(self.w, self.z, self.w, self.y) + fn zywy(self) -> IVec4 { + IVec4::new(self.z, self.y, self.w, self.y) } + #[inline] - fn wzwz(self) -> IVec4 { - IVec4::new(self.w, self.z, self.w, self.z) + fn zywz(self) -> IVec4 { + IVec4::new(self.z, self.y, self.w, self.z) } + #[inline] - fn wzww(self) -> IVec4 { - IVec4::new(self.w, self.z, self.w, self.w) + fn zyww(self) -> IVec4 { + IVec4::new(self.z, self.y, self.w, self.w) } + #[inline] - fn wwxx(self) -> IVec4 { - IVec4::new(self.w, self.w, self.x, self.x) + fn zzxx(self) -> IVec4 { + IVec4::new(self.z, self.z, self.x, self.x) } + #[inline] - fn wwxy(self) -> IVec4 { - IVec4::new(self.w, self.w, self.x, self.y) + fn zzxy(self) -> IVec4 { + IVec4::new(self.z, self.z, self.x, self.y) } + #[inline] - fn wwxz(self) -> IVec4 { - IVec4::new(self.w, self.w, self.x, self.z) + fn zzxz(self) -> IVec4 { + IVec4::new(self.z, self.z, self.x, self.z) } + #[inline] - fn wwxw(self) -> IVec4 { - IVec4::new(self.w, self.w, self.x, self.w) + fn zzxw(self) -> IVec4 { + IVec4::new(self.z, self.z, self.x, self.w) } + #[inline] - fn wwyx(self) -> IVec4 { - IVec4::new(self.w, self.w, self.y, self.x) + fn zzyx(self) -> IVec4 { + IVec4::new(self.z, self.z, self.y, self.x) } + #[inline] - fn wwyy(self) -> IVec4 { - IVec4::new(self.w, self.w, self.y, self.y) + fn zzyy(self) -> IVec4 { + IVec4::new(self.z, self.z, self.y, self.y) } + #[inline] - fn wwyz(self) -> IVec4 { - IVec4::new(self.w, self.w, self.y, self.z) + fn zzyz(self) -> IVec4 { + IVec4::new(self.z, self.z, self.y, self.z) } + #[inline] - fn wwyw(self) -> IVec4 { - IVec4::new(self.w, self.w, self.y, self.w) + fn zzyw(self) -> IVec4 { + IVec4::new(self.z, self.z, self.y, self.w) } + #[inline] - fn wwzx(self) -> IVec4 { - IVec4::new(self.w, self.w, self.z, self.x) + fn zzzx(self) -> IVec4 { + IVec4::new(self.z, self.z, self.z, self.x) } + #[inline] - fn wwzy(self) -> IVec4 { - IVec4::new(self.w, self.w, self.z, self.y) + fn zzzy(self) -> IVec4 { + IVec4::new(self.z, self.z, self.z, self.y) } + #[inline] - fn wwzz(self) -> IVec4 { - IVec4::new(self.w, self.w, self.z, self.z) + fn zzzz(self) -> IVec4 { + IVec4::new(self.z, self.z, self.z, self.z) } + #[inline] - fn wwzw(self) -> IVec4 { - IVec4::new(self.w, self.w, self.z, self.w) + fn zzzw(self) -> IVec4 { + IVec4::new(self.z, self.z, self.z, self.w) } + #[inline] - fn wwwx(self) -> IVec4 { - IVec4::new(self.w, self.w, self.w, self.x) + fn zzwx(self) -> IVec4 { + IVec4::new(self.z, self.z, self.w, self.x) } + #[inline] - fn wwwy(self) -> IVec4 { - IVec4::new(self.w, self.w, self.w, self.y) + fn zzwy(self) -> IVec4 { + IVec4::new(self.z, self.z, self.w, self.y) } + #[inline] - fn wwwz(self) -> IVec4 { - IVec4::new(self.w, self.w, self.w, self.z) + fn zzwz(self) -> IVec4 { + IVec4::new(self.z, self.z, self.w, self.z) } + #[inline] - fn wwww(self) -> IVec4 { - IVec4::new(self.w, self.w, self.w, self.w) + fn zzww(self) -> IVec4 { + IVec4::new(self.z, self.z, self.w, self.w) } + #[inline] - fn xxx(self) -> IVec3 { - IVec3::new(self.x, self.x, self.x) + fn zwxx(self) -> IVec4 { + IVec4::new(self.z, self.w, self.x, self.x) } + #[inline] - fn xxy(self) -> IVec3 { - IVec3::new(self.x, self.x, self.y) + fn zwxy(self) -> IVec4 { + IVec4::new(self.z, self.w, self.x, self.y) } + #[inline] - fn xxz(self) -> IVec3 { - IVec3::new(self.x, self.x, self.z) + fn zwxz(self) -> IVec4 { + IVec4::new(self.z, self.w, self.x, self.z) } + #[inline] - fn xxw(self) -> IVec3 { - IVec3::new(self.x, self.x, self.w) + fn zwxw(self) -> IVec4 { + IVec4::new(self.z, self.w, self.x, self.w) } + #[inline] - fn xyx(self) -> IVec3 { - IVec3::new(self.x, self.y, self.x) + fn zwyx(self) -> IVec4 { + IVec4::new(self.z, self.w, self.y, self.x) } + #[inline] - fn xyy(self) -> IVec3 { - IVec3::new(self.x, self.y, self.y) + fn zwyy(self) -> IVec4 { + IVec4::new(self.z, self.w, self.y, self.y) } + #[inline] - fn xyz(self) -> IVec3 { - IVec3::new(self.x, self.y, self.z) + fn zwyz(self) -> IVec4 { + IVec4::new(self.z, self.w, self.y, self.z) } + #[inline] - fn xyw(self) -> IVec3 { - IVec3::new(self.x, self.y, self.w) + fn zwyw(self) -> IVec4 { + IVec4::new(self.z, self.w, self.y, self.w) } + #[inline] - fn xzx(self) -> IVec3 { - IVec3::new(self.x, self.z, self.x) + fn zwzx(self) -> IVec4 { + IVec4::new(self.z, self.w, self.z, self.x) } + #[inline] - fn xzy(self) -> IVec3 { - IVec3::new(self.x, self.z, self.y) + fn zwzy(self) -> IVec4 { + IVec4::new(self.z, self.w, self.z, self.y) } + #[inline] - fn xzz(self) -> IVec3 { - IVec3::new(self.x, self.z, self.z) + fn zwzz(self) -> IVec4 { + IVec4::new(self.z, self.w, self.z, self.z) } + #[inline] - fn xzw(self) -> IVec3 { - IVec3::new(self.x, self.z, self.w) + fn zwzw(self) -> IVec4 { + IVec4::new(self.z, self.w, self.z, self.w) } + #[inline] - fn xwx(self) -> IVec3 { - IVec3::new(self.x, self.w, self.x) + fn zwwx(self) -> IVec4 { + IVec4::new(self.z, self.w, self.w, self.x) } + #[inline] - fn xwy(self) -> IVec3 { - IVec3::new(self.x, self.w, self.y) + fn zwwy(self) -> IVec4 { + IVec4::new(self.z, self.w, self.w, self.y) } + #[inline] - fn xwz(self) -> IVec3 { - IVec3::new(self.x, self.w, self.z) + fn zwwz(self) -> IVec4 { + IVec4::new(self.z, self.w, self.w, self.z) } + #[inline] - fn xww(self) -> IVec3 { - IVec3::new(self.x, self.w, self.w) + fn zwww(self) -> IVec4 { + IVec4::new(self.z, self.w, self.w, self.w) } + #[inline] - fn yxx(self) -> IVec3 { - IVec3::new(self.y, self.x, self.x) + fn wxxx(self) -> IVec4 { + IVec4::new(self.w, self.x, self.x, self.x) } + #[inline] - fn yxy(self) -> IVec3 { - IVec3::new(self.y, self.x, self.y) + fn wxxy(self) -> IVec4 { + IVec4::new(self.w, self.x, self.x, self.y) } + #[inline] - fn yxz(self) -> IVec3 { - IVec3::new(self.y, self.x, self.z) + fn wxxz(self) -> IVec4 { + IVec4::new(self.w, self.x, self.x, self.z) } + #[inline] - fn yxw(self) -> IVec3 { - IVec3::new(self.y, self.x, self.w) + fn wxxw(self) -> IVec4 { + IVec4::new(self.w, self.x, self.x, self.w) } + #[inline] - fn yyx(self) -> IVec3 { - IVec3::new(self.y, self.y, self.x) + fn wxyx(self) -> IVec4 { + IVec4::new(self.w, self.x, self.y, self.x) } + #[inline] - fn yyy(self) -> IVec3 { - IVec3::new(self.y, self.y, self.y) + fn wxyy(self) -> IVec4 { + IVec4::new(self.w, self.x, self.y, self.y) } + #[inline] - fn yyz(self) -> IVec3 { - IVec3::new(self.y, self.y, self.z) + fn wxyz(self) -> IVec4 { + IVec4::new(self.w, self.x, self.y, self.z) } + #[inline] - fn yyw(self) -> IVec3 { - IVec3::new(self.y, self.y, self.w) + fn wxyw(self) -> IVec4 { + IVec4::new(self.w, self.x, self.y, self.w) } + #[inline] - fn yzx(self) -> IVec3 { - IVec3::new(self.y, self.z, self.x) + fn wxzx(self) -> IVec4 { + IVec4::new(self.w, self.x, self.z, self.x) } + #[inline] - fn yzy(self) -> IVec3 { - IVec3::new(self.y, self.z, self.y) + fn wxzy(self) -> IVec4 { + IVec4::new(self.w, self.x, self.z, self.y) } + #[inline] - fn yzz(self) -> IVec3 { - IVec3::new(self.y, self.z, self.z) + fn wxzz(self) -> IVec4 { + IVec4::new(self.w, self.x, self.z, self.z) } + #[inline] - fn yzw(self) -> IVec3 { - IVec3::new(self.y, self.z, self.w) + fn wxzw(self) -> IVec4 { + IVec4::new(self.w, self.x, self.z, self.w) } + #[inline] - fn ywx(self) -> IVec3 { - IVec3::new(self.y, self.w, self.x) + fn wxwx(self) -> IVec4 { + IVec4::new(self.w, self.x, self.w, self.x) } + #[inline] - fn ywy(self) -> IVec3 { - IVec3::new(self.y, self.w, self.y) + fn wxwy(self) -> IVec4 { + IVec4::new(self.w, self.x, self.w, self.y) } + #[inline] - fn ywz(self) -> IVec3 { - IVec3::new(self.y, self.w, self.z) + fn wxwz(self) -> IVec4 { + IVec4::new(self.w, self.x, self.w, self.z) } + #[inline] - fn yww(self) -> IVec3 { - IVec3::new(self.y, self.w, self.w) + fn wxww(self) -> IVec4 { + IVec4::new(self.w, self.x, self.w, self.w) } + #[inline] - fn zxx(self) -> IVec3 { - IVec3::new(self.z, self.x, self.x) + fn wyxx(self) -> IVec4 { + IVec4::new(self.w, self.y, self.x, self.x) } + #[inline] - fn zxy(self) -> IVec3 { - IVec3::new(self.z, self.x, self.y) + fn wyxy(self) -> IVec4 { + IVec4::new(self.w, self.y, self.x, self.y) } + #[inline] - fn zxz(self) -> IVec3 { - IVec3::new(self.z, self.x, self.z) + fn wyxz(self) -> IVec4 { + IVec4::new(self.w, self.y, self.x, self.z) } + #[inline] - fn zxw(self) -> IVec3 { - IVec3::new(self.z, self.x, self.w) + fn wyxw(self) -> IVec4 { + IVec4::new(self.w, self.y, self.x, self.w) } + #[inline] - fn zyx(self) -> IVec3 { - IVec3::new(self.z, self.y, self.x) + fn wyyx(self) -> IVec4 { + IVec4::new(self.w, self.y, self.y, self.x) } + #[inline] - fn zyy(self) -> IVec3 { - IVec3::new(self.z, self.y, self.y) + fn wyyy(self) -> IVec4 { + IVec4::new(self.w, self.y, self.y, self.y) } + #[inline] - fn zyz(self) -> IVec3 { - IVec3::new(self.z, self.y, self.z) + fn wyyz(self) -> IVec4 { + IVec4::new(self.w, self.y, self.y, self.z) } + #[inline] - fn zyw(self) -> IVec3 { - IVec3::new(self.z, self.y, self.w) + fn wyyw(self) -> IVec4 { + IVec4::new(self.w, self.y, self.y, self.w) } + #[inline] - fn zzx(self) -> IVec3 { - IVec3::new(self.z, self.z, self.x) + fn wyzx(self) -> IVec4 { + IVec4::new(self.w, self.y, self.z, self.x) } + #[inline] - fn zzy(self) -> IVec3 { - IVec3::new(self.z, self.z, self.y) + fn wyzy(self) -> IVec4 { + IVec4::new(self.w, self.y, self.z, self.y) } + #[inline] - fn zzz(self) -> IVec3 { - IVec3::new(self.z, self.z, self.z) + fn wyzz(self) -> IVec4 { + IVec4::new(self.w, self.y, self.z, self.z) } + #[inline] - fn zzw(self) -> IVec3 { - IVec3::new(self.z, self.z, self.w) + fn wyzw(self) -> IVec4 { + IVec4::new(self.w, self.y, self.z, self.w) } + #[inline] - fn zwx(self) -> IVec3 { - IVec3::new(self.z, self.w, self.x) + fn wywx(self) -> IVec4 { + IVec4::new(self.w, self.y, self.w, self.x) } + #[inline] - fn zwy(self) -> IVec3 { - IVec3::new(self.z, self.w, self.y) + fn wywy(self) -> IVec4 { + IVec4::new(self.w, self.y, self.w, self.y) } + #[inline] - fn zwz(self) -> IVec3 { - IVec3::new(self.z, self.w, self.z) + fn wywz(self) -> IVec4 { + IVec4::new(self.w, self.y, self.w, self.z) } + #[inline] - fn zww(self) -> IVec3 { - IVec3::new(self.z, self.w, self.w) + fn wyww(self) -> IVec4 { + IVec4::new(self.w, self.y, self.w, self.w) } + #[inline] - fn wxx(self) -> IVec3 { - IVec3::new(self.w, self.x, self.x) + fn wzxx(self) -> IVec4 { + IVec4::new(self.w, self.z, self.x, self.x) } + #[inline] - fn wxy(self) -> IVec3 { - IVec3::new(self.w, self.x, self.y) + fn wzxy(self) -> IVec4 { + IVec4::new(self.w, self.z, self.x, self.y) } + #[inline] - fn wxz(self) -> IVec3 { - IVec3::new(self.w, self.x, self.z) + fn wzxz(self) -> IVec4 { + IVec4::new(self.w, self.z, self.x, self.z) } + #[inline] - fn wxw(self) -> IVec3 { - IVec3::new(self.w, self.x, self.w) + fn wzxw(self) -> IVec4 { + IVec4::new(self.w, self.z, self.x, self.w) } + #[inline] - fn wyx(self) -> IVec3 { - IVec3::new(self.w, self.y, self.x) + fn wzyx(self) -> IVec4 { + IVec4::new(self.w, self.z, self.y, self.x) } + #[inline] - fn wyy(self) -> IVec3 { - IVec3::new(self.w, self.y, self.y) + fn wzyy(self) -> IVec4 { + IVec4::new(self.w, self.z, self.y, self.y) } + #[inline] - fn wyz(self) -> IVec3 { - IVec3::new(self.w, self.y, self.z) + fn wzyz(self) -> IVec4 { + IVec4::new(self.w, self.z, self.y, self.z) } + #[inline] - fn wyw(self) -> IVec3 { - IVec3::new(self.w, self.y, self.w) + fn wzyw(self) -> IVec4 { + IVec4::new(self.w, self.z, self.y, self.w) } + #[inline] - fn wzx(self) -> IVec3 { - IVec3::new(self.w, self.z, self.x) + fn wzzx(self) -> IVec4 { + IVec4::new(self.w, self.z, self.z, self.x) } + #[inline] - fn wzy(self) -> IVec3 { - IVec3::new(self.w, self.z, self.y) + fn wzzy(self) -> IVec4 { + IVec4::new(self.w, self.z, self.z, self.y) } + #[inline] - fn wzz(self) -> IVec3 { - IVec3::new(self.w, self.z, self.z) + fn wzzz(self) -> IVec4 { + IVec4::new(self.w, self.z, self.z, self.z) } + #[inline] - fn wzw(self) -> IVec3 { - IVec3::new(self.w, self.z, self.w) + fn wzzw(self) -> IVec4 { + IVec4::new(self.w, self.z, self.z, self.w) } + #[inline] - fn wwx(self) -> IVec3 { - IVec3::new(self.w, self.w, self.x) + fn wzwx(self) -> IVec4 { + IVec4::new(self.w, self.z, self.w, self.x) } + #[inline] - fn wwy(self) -> IVec3 { - IVec3::new(self.w, self.w, self.y) + fn wzwy(self) -> IVec4 { + IVec4::new(self.w, self.z, self.w, self.y) } + #[inline] - fn wwz(self) -> IVec3 { - IVec3::new(self.w, self.w, self.z) + fn wzwz(self) -> IVec4 { + IVec4::new(self.w, self.z, self.w, self.z) } + #[inline] - fn www(self) -> IVec3 { - IVec3::new(self.w, self.w, self.w) + fn wzww(self) -> IVec4 { + IVec4::new(self.w, self.z, self.w, self.w) } + #[inline] - fn xx(self) -> IVec2 { - IVec2::new(self.x, self.x) + fn wwxx(self) -> IVec4 { + IVec4::new(self.w, self.w, self.x, self.x) } + #[inline] - fn xy(self) -> IVec2 { - IVec2::new(self.x, self.y) + fn wwxy(self) -> IVec4 { + IVec4::new(self.w, self.w, self.x, self.y) } + #[inline] - fn xz(self) -> IVec2 { - IVec2::new(self.x, self.z) + fn wwxz(self) -> IVec4 { + IVec4::new(self.w, self.w, self.x, self.z) } + #[inline] - fn xw(self) -> IVec2 { - IVec2::new(self.x, self.w) + fn wwxw(self) -> IVec4 { + IVec4::new(self.w, self.w, self.x, self.w) } + #[inline] - fn yx(self) -> IVec2 { - IVec2::new(self.y, self.x) + fn wwyx(self) -> IVec4 { + IVec4::new(self.w, self.w, self.y, self.x) } + #[inline] - fn yy(self) -> IVec2 { - IVec2::new(self.y, self.y) + fn wwyy(self) -> IVec4 { + IVec4::new(self.w, self.w, self.y, self.y) } + #[inline] - fn yz(self) -> IVec2 { - IVec2::new(self.y, self.z) + fn wwyz(self) -> IVec4 { + IVec4::new(self.w, self.w, self.y, self.z) } + #[inline] - fn yw(self) -> IVec2 { - IVec2::new(self.y, self.w) + fn wwyw(self) -> IVec4 { + IVec4::new(self.w, self.w, self.y, self.w) } + #[inline] - fn zx(self) -> IVec2 { - IVec2::new(self.z, self.x) + fn wwzx(self) -> IVec4 { + IVec4::new(self.w, self.w, self.z, self.x) } + #[inline] - fn zy(self) -> IVec2 { - IVec2::new(self.z, self.y) + fn wwzy(self) -> IVec4 { + IVec4::new(self.w, self.w, self.z, self.y) } + #[inline] - fn zz(self) -> IVec2 { - IVec2::new(self.z, self.z) + fn wwzz(self) -> IVec4 { + IVec4::new(self.w, self.w, self.z, self.z) } + #[inline] - fn zw(self) -> IVec2 { - IVec2::new(self.z, self.w) + fn wwzw(self) -> IVec4 { + IVec4::new(self.w, self.w, self.z, self.w) } + #[inline] - fn wx(self) -> IVec2 { - IVec2::new(self.w, self.x) + fn wwwx(self) -> IVec4 { + IVec4::new(self.w, self.w, self.w, self.x) } + #[inline] - fn wy(self) -> IVec2 { - IVec2::new(self.w, self.y) + fn wwwy(self) -> IVec4 { + IVec4::new(self.w, self.w, self.w, self.y) } + #[inline] - fn wz(self) -> IVec2 { - IVec2::new(self.w, self.z) + fn wwwz(self) -> IVec4 { + IVec4::new(self.w, self.w, self.w, self.z) } + #[inline] - fn ww(self) -> IVec2 { - IVec2::new(self.w, self.w) + fn wwww(self) -> IVec4 { + IVec4::new(self.w, self.w, self.w, self.w) } } diff --git a/src/swizzles/uvec2_impl_scalar.rs b/src/swizzles/uvec2_impl_scalar.rs index 60ba8572..5843341b 100644 --- a/src/swizzles/uvec2_impl_scalar.rs +++ b/src/swizzles/uvec2_impl_scalar.rs @@ -1,118 +1,196 @@ -// Generated by swizzlegen. Do not edit. +// Generated from swizzle_impl.rs template. Edit the template, not the generated file. + +#![allow(clippy::useless_conversion)] use super::Vec2Swizzles; use crate::{UVec2, UVec3, UVec4}; impl Vec2Swizzles for UVec2 { type Vec3 = UVec3; + type Vec4 = UVec4; + #[inline] + fn xx(self) -> UVec2 { + UVec2 { + x: self.x, + y: self.x, + } + } + + #[inline] + fn xy(self) -> UVec2 { + UVec2 { + x: self.x, + y: self.y, + } + } + + #[inline] + fn yx(self) -> UVec2 { + UVec2 { + x: self.y, + y: self.x, + } + } + + #[inline] + fn yy(self) -> UVec2 { + UVec2 { + x: self.y, + y: self.y, + } + } + + #[inline] + fn xxx(self) -> UVec3 { + UVec3 { + x: self.x, + y: self.x, + z: self.x, + } + } + + #[inline] + fn xxy(self) -> UVec3 { + UVec3 { + x: self.x, + y: self.x, + z: self.y, + } + } + + #[inline] + fn xyx(self) -> UVec3 { + UVec3 { + x: self.x, + y: self.y, + z: self.x, + } + } + + #[inline] + fn xyy(self) -> UVec3 { + UVec3 { + x: self.x, + y: self.y, + z: self.y, + } + } + + #[inline] + fn yxx(self) -> UVec3 { + UVec3 { + x: self.y, + y: self.x, + z: self.x, + } + } + + #[inline] + fn yxy(self) -> UVec3 { + UVec3 { + x: self.y, + y: self.x, + z: self.y, + } + } + + #[inline] + fn yyx(self) -> UVec3 { + UVec3 { + x: self.y, + y: self.y, + z: self.x, + } + } + + #[inline] + fn yyy(self) -> UVec3 { + UVec3 { + x: self.y, + y: self.y, + z: self.y, + } + } + #[inline] fn xxxx(self) -> UVec4 { UVec4::new(self.x, self.x, self.x, self.x) } + #[inline] fn xxxy(self) -> UVec4 { UVec4::new(self.x, self.x, self.x, self.y) } + #[inline] fn xxyx(self) -> UVec4 { UVec4::new(self.x, self.x, self.y, self.x) } + #[inline] fn xxyy(self) -> UVec4 { UVec4::new(self.x, self.x, self.y, self.y) } + #[inline] fn xyxx(self) -> UVec4 { UVec4::new(self.x, self.y, self.x, self.x) } + #[inline] fn xyxy(self) -> UVec4 { UVec4::new(self.x, self.y, self.x, self.y) } + #[inline] fn xyyx(self) -> UVec4 { UVec4::new(self.x, self.y, self.y, self.x) } + #[inline] fn xyyy(self) -> UVec4 { UVec4::new(self.x, self.y, self.y, self.y) } + #[inline] fn yxxx(self) -> UVec4 { UVec4::new(self.y, self.x, self.x, self.x) } + #[inline] fn yxxy(self) -> UVec4 { UVec4::new(self.y, self.x, self.x, self.y) } + #[inline] fn yxyx(self) -> UVec4 { UVec4::new(self.y, self.x, self.y, self.x) } + #[inline] fn yxyy(self) -> UVec4 { UVec4::new(self.y, self.x, self.y, self.y) } + #[inline] fn yyxx(self) -> UVec4 { UVec4::new(self.y, self.y, self.x, self.x) } + #[inline] fn yyxy(self) -> UVec4 { UVec4::new(self.y, self.y, self.x, self.y) } + #[inline] fn yyyx(self) -> UVec4 { UVec4::new(self.y, self.y, self.y, self.x) } + #[inline] fn yyyy(self) -> UVec4 { UVec4::new(self.y, self.y, self.y, self.y) } - #[inline] - fn xxx(self) -> UVec3 { - UVec3::new(self.x, self.x, self.x) - } - #[inline] - fn xxy(self) -> UVec3 { - UVec3::new(self.x, self.x, self.y) - } - #[inline] - fn xyx(self) -> UVec3 { - UVec3::new(self.x, self.y, self.x) - } - #[inline] - fn xyy(self) -> UVec3 { - UVec3::new(self.x, self.y, self.y) - } - #[inline] - fn yxx(self) -> UVec3 { - UVec3::new(self.y, self.x, self.x) - } - #[inline] - fn yxy(self) -> UVec3 { - UVec3::new(self.y, self.x, self.y) - } - #[inline] - fn yyx(self) -> UVec3 { - UVec3::new(self.y, self.y, self.x) - } - #[inline] - fn yyy(self) -> UVec3 { - UVec3::new(self.y, self.y, self.y) - } - #[inline] - fn xx(self) -> Self { - Self::new(self.x, self.x) - } - #[inline] - fn yx(self) -> Self { - Self::new(self.y, self.x) - } - #[inline] - fn yy(self) -> Self { - Self::new(self.y, self.y) - } } diff --git a/src/swizzles/uvec3_impl_scalar.rs b/src/swizzles/uvec3_impl_scalar.rs index 5158e071..e33891d1 100644 --- a/src/swizzles/uvec3_impl_scalar.rs +++ b/src/swizzles/uvec3_impl_scalar.rs @@ -1,474 +1,732 @@ -// Generated by swizzlegen. Do not edit. +// Generated from swizzle_impl.rs template. Edit the template, not the generated file. + +#![allow(clippy::useless_conversion)] use super::Vec3Swizzles; use crate::{UVec2, UVec3, UVec4}; impl Vec3Swizzles for UVec3 { type Vec2 = UVec2; + type Vec4 = UVec4; + #[inline] + fn xx(self) -> UVec2 { + UVec2 { + x: self.x, + y: self.x, + } + } + + #[inline] + fn xy(self) -> UVec2 { + UVec2 { + x: self.x, + y: self.y, + } + } + + #[inline] + fn xz(self) -> UVec2 { + UVec2 { + x: self.x, + y: self.z, + } + } + + #[inline] + fn yx(self) -> UVec2 { + UVec2 { + x: self.y, + y: self.x, + } + } + + #[inline] + fn yy(self) -> UVec2 { + UVec2 { + x: self.y, + y: self.y, + } + } + + #[inline] + fn yz(self) -> UVec2 { + UVec2 { + x: self.y, + y: self.z, + } + } + + #[inline] + fn zx(self) -> UVec2 { + UVec2 { + x: self.z, + y: self.x, + } + } + + #[inline] + fn zy(self) -> UVec2 { + UVec2 { + x: self.z, + y: self.y, + } + } + + #[inline] + fn zz(self) -> UVec2 { + UVec2 { + x: self.z, + y: self.z, + } + } + + #[inline] + fn xxx(self) -> UVec3 { + UVec3 { + x: self.x, + y: self.x, + z: self.x, + } + } + + #[inline] + fn xxy(self) -> UVec3 { + UVec3 { + x: self.x, + y: self.x, + z: self.y, + } + } + + #[inline] + fn xxz(self) -> UVec3 { + UVec3 { + x: self.x, + y: self.x, + z: self.z, + } + } + + #[inline] + fn xyx(self) -> UVec3 { + UVec3 { + x: self.x, + y: self.y, + z: self.x, + } + } + + #[inline] + fn xyy(self) -> UVec3 { + UVec3 { + x: self.x, + y: self.y, + z: self.y, + } + } + + #[inline] + fn xyz(self) -> UVec3 { + UVec3 { + x: self.x, + y: self.y, + z: self.z, + } + } + + #[inline] + fn xzx(self) -> UVec3 { + UVec3 { + x: self.x, + y: self.z, + z: self.x, + } + } + + #[inline] + fn xzy(self) -> UVec3 { + UVec3 { + x: self.x, + y: self.z, + z: self.y, + } + } + + #[inline] + fn xzz(self) -> UVec3 { + UVec3 { + x: self.x, + y: self.z, + z: self.z, + } + } + + #[inline] + fn yxx(self) -> UVec3 { + UVec3 { + x: self.y, + y: self.x, + z: self.x, + } + } + + #[inline] + fn yxy(self) -> UVec3 { + UVec3 { + x: self.y, + y: self.x, + z: self.y, + } + } + + #[inline] + fn yxz(self) -> UVec3 { + UVec3 { + x: self.y, + y: self.x, + z: self.z, + } + } + + #[inline] + fn yyx(self) -> UVec3 { + UVec3 { + x: self.y, + y: self.y, + z: self.x, + } + } + + #[inline] + fn yyy(self) -> UVec3 { + UVec3 { + x: self.y, + y: self.y, + z: self.y, + } + } + + #[inline] + fn yyz(self) -> UVec3 { + UVec3 { + x: self.y, + y: self.y, + z: self.z, + } + } + + #[inline] + fn yzx(self) -> UVec3 { + UVec3 { + x: self.y, + y: self.z, + z: self.x, + } + } + + #[inline] + fn yzy(self) -> UVec3 { + UVec3 { + x: self.y, + y: self.z, + z: self.y, + } + } + + #[inline] + fn yzz(self) -> UVec3 { + UVec3 { + x: self.y, + y: self.z, + z: self.z, + } + } + + #[inline] + fn zxx(self) -> UVec3 { + UVec3 { + x: self.z, + y: self.x, + z: self.x, + } + } + + #[inline] + fn zxy(self) -> UVec3 { + UVec3 { + x: self.z, + y: self.x, + z: self.y, + } + } + + #[inline] + fn zxz(self) -> UVec3 { + UVec3 { + x: self.z, + y: self.x, + z: self.z, + } + } + + #[inline] + fn zyx(self) -> UVec3 { + UVec3 { + x: self.z, + y: self.y, + z: self.x, + } + } + + #[inline] + fn zyy(self) -> UVec3 { + UVec3 { + x: self.z, + y: self.y, + z: self.y, + } + } + + #[inline] + fn zyz(self) -> UVec3 { + UVec3 { + x: self.z, + y: self.y, + z: self.z, + } + } + + #[inline] + fn zzx(self) -> UVec3 { + UVec3 { + x: self.z, + y: self.z, + z: self.x, + } + } + + #[inline] + fn zzy(self) -> UVec3 { + UVec3 { + x: self.z, + y: self.z, + z: self.y, + } + } + + #[inline] + fn zzz(self) -> UVec3 { + UVec3 { + x: self.z, + y: self.z, + z: self.z, + } + } + #[inline] fn xxxx(self) -> UVec4 { UVec4::new(self.x, self.x, self.x, self.x) } + #[inline] fn xxxy(self) -> UVec4 { UVec4::new(self.x, self.x, self.x, self.y) } + #[inline] fn xxxz(self) -> UVec4 { UVec4::new(self.x, self.x, self.x, self.z) } + #[inline] fn xxyx(self) -> UVec4 { UVec4::new(self.x, self.x, self.y, self.x) } + #[inline] fn xxyy(self) -> UVec4 { UVec4::new(self.x, self.x, self.y, self.y) } + #[inline] fn xxyz(self) -> UVec4 { UVec4::new(self.x, self.x, self.y, self.z) } + #[inline] fn xxzx(self) -> UVec4 { UVec4::new(self.x, self.x, self.z, self.x) } + #[inline] fn xxzy(self) -> UVec4 { UVec4::new(self.x, self.x, self.z, self.y) } + #[inline] fn xxzz(self) -> UVec4 { UVec4::new(self.x, self.x, self.z, self.z) } + #[inline] fn xyxx(self) -> UVec4 { UVec4::new(self.x, self.y, self.x, self.x) } + #[inline] fn xyxy(self) -> UVec4 { UVec4::new(self.x, self.y, self.x, self.y) } + #[inline] fn xyxz(self) -> UVec4 { UVec4::new(self.x, self.y, self.x, self.z) } + #[inline] fn xyyx(self) -> UVec4 { UVec4::new(self.x, self.y, self.y, self.x) } + #[inline] fn xyyy(self) -> UVec4 { UVec4::new(self.x, self.y, self.y, self.y) } + #[inline] fn xyyz(self) -> UVec4 { UVec4::new(self.x, self.y, self.y, self.z) } + #[inline] fn xyzx(self) -> UVec4 { UVec4::new(self.x, self.y, self.z, self.x) } + #[inline] fn xyzy(self) -> UVec4 { UVec4::new(self.x, self.y, self.z, self.y) } + #[inline] fn xyzz(self) -> UVec4 { UVec4::new(self.x, self.y, self.z, self.z) } + #[inline] fn xzxx(self) -> UVec4 { UVec4::new(self.x, self.z, self.x, self.x) } + #[inline] fn xzxy(self) -> UVec4 { UVec4::new(self.x, self.z, self.x, self.y) } + #[inline] fn xzxz(self) -> UVec4 { UVec4::new(self.x, self.z, self.x, self.z) } + #[inline] fn xzyx(self) -> UVec4 { UVec4::new(self.x, self.z, self.y, self.x) } + #[inline] fn xzyy(self) -> UVec4 { UVec4::new(self.x, self.z, self.y, self.y) } + #[inline] fn xzyz(self) -> UVec4 { UVec4::new(self.x, self.z, self.y, self.z) } + #[inline] fn xzzx(self) -> UVec4 { UVec4::new(self.x, self.z, self.z, self.x) } + #[inline] fn xzzy(self) -> UVec4 { UVec4::new(self.x, self.z, self.z, self.y) } + #[inline] fn xzzz(self) -> UVec4 { UVec4::new(self.x, self.z, self.z, self.z) } + #[inline] fn yxxx(self) -> UVec4 { UVec4::new(self.y, self.x, self.x, self.x) } + #[inline] fn yxxy(self) -> UVec4 { UVec4::new(self.y, self.x, self.x, self.y) } + #[inline] fn yxxz(self) -> UVec4 { UVec4::new(self.y, self.x, self.x, self.z) } + #[inline] fn yxyx(self) -> UVec4 { UVec4::new(self.y, self.x, self.y, self.x) } + #[inline] fn yxyy(self) -> UVec4 { UVec4::new(self.y, self.x, self.y, self.y) } + #[inline] fn yxyz(self) -> UVec4 { UVec4::new(self.y, self.x, self.y, self.z) } + #[inline] fn yxzx(self) -> UVec4 { UVec4::new(self.y, self.x, self.z, self.x) } + #[inline] fn yxzy(self) -> UVec4 { UVec4::new(self.y, self.x, self.z, self.y) } + #[inline] fn yxzz(self) -> UVec4 { UVec4::new(self.y, self.x, self.z, self.z) } + #[inline] fn yyxx(self) -> UVec4 { UVec4::new(self.y, self.y, self.x, self.x) } + #[inline] fn yyxy(self) -> UVec4 { UVec4::new(self.y, self.y, self.x, self.y) } + #[inline] fn yyxz(self) -> UVec4 { UVec4::new(self.y, self.y, self.x, self.z) } + #[inline] fn yyyx(self) -> UVec4 { UVec4::new(self.y, self.y, self.y, self.x) } + #[inline] fn yyyy(self) -> UVec4 { UVec4::new(self.y, self.y, self.y, self.y) } + #[inline] fn yyyz(self) -> UVec4 { UVec4::new(self.y, self.y, self.y, self.z) } + #[inline] fn yyzx(self) -> UVec4 { UVec4::new(self.y, self.y, self.z, self.x) } + #[inline] fn yyzy(self) -> UVec4 { UVec4::new(self.y, self.y, self.z, self.y) } + #[inline] fn yyzz(self) -> UVec4 { UVec4::new(self.y, self.y, self.z, self.z) } + #[inline] fn yzxx(self) -> UVec4 { UVec4::new(self.y, self.z, self.x, self.x) } + #[inline] fn yzxy(self) -> UVec4 { UVec4::new(self.y, self.z, self.x, self.y) } + #[inline] fn yzxz(self) -> UVec4 { UVec4::new(self.y, self.z, self.x, self.z) } + #[inline] fn yzyx(self) -> UVec4 { UVec4::new(self.y, self.z, self.y, self.x) } + #[inline] fn yzyy(self) -> UVec4 { UVec4::new(self.y, self.z, self.y, self.y) } + #[inline] fn yzyz(self) -> UVec4 { UVec4::new(self.y, self.z, self.y, self.z) } + #[inline] fn yzzx(self) -> UVec4 { UVec4::new(self.y, self.z, self.z, self.x) } + #[inline] fn yzzy(self) -> UVec4 { UVec4::new(self.y, self.z, self.z, self.y) } + #[inline] fn yzzz(self) -> UVec4 { UVec4::new(self.y, self.z, self.z, self.z) } + #[inline] fn zxxx(self) -> UVec4 { UVec4::new(self.z, self.x, self.x, self.x) } + #[inline] fn zxxy(self) -> UVec4 { UVec4::new(self.z, self.x, self.x, self.y) } + #[inline] fn zxxz(self) -> UVec4 { UVec4::new(self.z, self.x, self.x, self.z) } + #[inline] fn zxyx(self) -> UVec4 { UVec4::new(self.z, self.x, self.y, self.x) } + #[inline] fn zxyy(self) -> UVec4 { UVec4::new(self.z, self.x, self.y, self.y) } + #[inline] fn zxyz(self) -> UVec4 { UVec4::new(self.z, self.x, self.y, self.z) } + #[inline] fn zxzx(self) -> UVec4 { UVec4::new(self.z, self.x, self.z, self.x) } + #[inline] fn zxzy(self) -> UVec4 { UVec4::new(self.z, self.x, self.z, self.y) } + #[inline] fn zxzz(self) -> UVec4 { UVec4::new(self.z, self.x, self.z, self.z) } + #[inline] fn zyxx(self) -> UVec4 { UVec4::new(self.z, self.y, self.x, self.x) } + #[inline] fn zyxy(self) -> UVec4 { UVec4::new(self.z, self.y, self.x, self.y) } + #[inline] fn zyxz(self) -> UVec4 { UVec4::new(self.z, self.y, self.x, self.z) } + #[inline] fn zyyx(self) -> UVec4 { UVec4::new(self.z, self.y, self.y, self.x) } + #[inline] fn zyyy(self) -> UVec4 { UVec4::new(self.z, self.y, self.y, self.y) } + #[inline] fn zyyz(self) -> UVec4 { UVec4::new(self.z, self.y, self.y, self.z) } + #[inline] fn zyzx(self) -> UVec4 { UVec4::new(self.z, self.y, self.z, self.x) } + #[inline] fn zyzy(self) -> UVec4 { UVec4::new(self.z, self.y, self.z, self.y) } + #[inline] fn zyzz(self) -> UVec4 { UVec4::new(self.z, self.y, self.z, self.z) } + #[inline] fn zzxx(self) -> UVec4 { UVec4::new(self.z, self.z, self.x, self.x) } + #[inline] fn zzxy(self) -> UVec4 { UVec4::new(self.z, self.z, self.x, self.y) } + #[inline] fn zzxz(self) -> UVec4 { UVec4::new(self.z, self.z, self.x, self.z) } + #[inline] fn zzyx(self) -> UVec4 { UVec4::new(self.z, self.z, self.y, self.x) } + #[inline] fn zzyy(self) -> UVec4 { UVec4::new(self.z, self.z, self.y, self.y) } + #[inline] fn zzyz(self) -> UVec4 { UVec4::new(self.z, self.z, self.y, self.z) } + #[inline] fn zzzx(self) -> UVec4 { UVec4::new(self.z, self.z, self.z, self.x) } + #[inline] fn zzzy(self) -> UVec4 { UVec4::new(self.z, self.z, self.z, self.y) } + #[inline] fn zzzz(self) -> UVec4 { UVec4::new(self.z, self.z, self.z, self.z) } - #[inline] - fn xxx(self) -> Self { - Self::new(self.x, self.x, self.x) - } - #[inline] - fn xxy(self) -> Self { - Self::new(self.x, self.x, self.y) - } - #[inline] - fn xxz(self) -> Self { - Self::new(self.x, self.x, self.z) - } - #[inline] - fn xyx(self) -> Self { - Self::new(self.x, self.y, self.x) - } - #[inline] - fn xyy(self) -> Self { - Self::new(self.x, self.y, self.y) - } - #[inline] - fn xzx(self) -> Self { - Self::new(self.x, self.z, self.x) - } - #[inline] - fn xzy(self) -> Self { - Self::new(self.x, self.z, self.y) - } - #[inline] - fn xzz(self) -> Self { - Self::new(self.x, self.z, self.z) - } - #[inline] - fn yxx(self) -> Self { - Self::new(self.y, self.x, self.x) - } - #[inline] - fn yxy(self) -> Self { - Self::new(self.y, self.x, self.y) - } - #[inline] - fn yxz(self) -> Self { - Self::new(self.y, self.x, self.z) - } - #[inline] - fn yyx(self) -> Self { - Self::new(self.y, self.y, self.x) - } - #[inline] - fn yyy(self) -> Self { - Self::new(self.y, self.y, self.y) - } - #[inline] - fn yyz(self) -> Self { - Self::new(self.y, self.y, self.z) - } - #[inline] - fn yzx(self) -> Self { - Self::new(self.y, self.z, self.x) - } - #[inline] - fn yzy(self) -> Self { - Self::new(self.y, self.z, self.y) - } - #[inline] - fn yzz(self) -> Self { - Self::new(self.y, self.z, self.z) - } - #[inline] - fn zxx(self) -> Self { - Self::new(self.z, self.x, self.x) - } - #[inline] - fn zxy(self) -> Self { - Self::new(self.z, self.x, self.y) - } - #[inline] - fn zxz(self) -> Self { - Self::new(self.z, self.x, self.z) - } - #[inline] - fn zyx(self) -> Self { - Self::new(self.z, self.y, self.x) - } - #[inline] - fn zyy(self) -> Self { - Self::new(self.z, self.y, self.y) - } - #[inline] - fn zyz(self) -> Self { - Self::new(self.z, self.y, self.z) - } - #[inline] - fn zzx(self) -> Self { - Self::new(self.z, self.z, self.x) - } - #[inline] - fn zzy(self) -> Self { - Self::new(self.z, self.z, self.y) - } - #[inline] - fn zzz(self) -> Self { - Self::new(self.z, self.z, self.z) - } - #[inline] - fn xx(self) -> UVec2 { - UVec2::new(self.x, self.x) - } - #[inline] - fn xy(self) -> UVec2 { - UVec2::new(self.x, self.y) - } - #[inline] - fn xz(self) -> UVec2 { - UVec2::new(self.x, self.z) - } - #[inline] - fn yx(self) -> UVec2 { - UVec2::new(self.y, self.x) - } - #[inline] - fn yy(self) -> UVec2 { - UVec2::new(self.y, self.y) - } - #[inline] - fn yz(self) -> UVec2 { - UVec2::new(self.y, self.z) - } - #[inline] - fn zx(self) -> UVec2 { - UVec2::new(self.z, self.x) - } - #[inline] - fn zy(self) -> UVec2 { - UVec2::new(self.z, self.y) - } - #[inline] - fn zz(self) -> UVec2 { - UVec2::new(self.z, self.z) - } } diff --git a/src/swizzles/uvec4_impl_scalar.rs b/src/swizzles/uvec4_impl_scalar.rs index be4824c8..e641d662 100644 --- a/src/swizzles/uvec4_impl_scalar.rs +++ b/src/swizzles/uvec4_impl_scalar.rs @@ -1,1350 +1,1996 @@ -// Generated by swizzlegen. Do not edit. +// Generated from swizzle_impl.rs template. Edit the template, not the generated file. + +#![allow(clippy::useless_conversion)] use super::Vec4Swizzles; use crate::{UVec2, UVec3, UVec4}; impl Vec4Swizzles for UVec4 { type Vec2 = UVec2; + type Vec3 = UVec3; #[inline] - fn xxxx(self) -> UVec4 { - UVec4::new(self.x, self.x, self.x, self.x) + fn xx(self) -> UVec2 { + UVec2 { + x: self.x, + y: self.x, + } } + #[inline] - fn xxxy(self) -> UVec4 { - UVec4::new(self.x, self.x, self.x, self.y) + fn xy(self) -> UVec2 { + UVec2 { + x: self.x, + y: self.y, + } } + #[inline] - fn xxxz(self) -> UVec4 { - UVec4::new(self.x, self.x, self.x, self.z) + fn xz(self) -> UVec2 { + UVec2 { + x: self.x, + y: self.z, + } } + #[inline] - fn xxxw(self) -> UVec4 { - UVec4::new(self.x, self.x, self.x, self.w) + fn xw(self) -> UVec2 { + UVec2 { + x: self.x, + y: self.w, + } } + #[inline] - fn xxyx(self) -> UVec4 { - UVec4::new(self.x, self.x, self.y, self.x) + fn yx(self) -> UVec2 { + UVec2 { + x: self.y, + y: self.x, + } } + #[inline] - fn xxyy(self) -> UVec4 { - UVec4::new(self.x, self.x, self.y, self.y) + fn yy(self) -> UVec2 { + UVec2 { + x: self.y, + y: self.y, + } } + #[inline] - fn xxyz(self) -> UVec4 { - UVec4::new(self.x, self.x, self.y, self.z) + fn yz(self) -> UVec2 { + UVec2 { + x: self.y, + y: self.z, + } } + #[inline] - fn xxyw(self) -> UVec4 { - UVec4::new(self.x, self.x, self.y, self.w) + fn yw(self) -> UVec2 { + UVec2 { + x: self.y, + y: self.w, + } } + #[inline] - fn xxzx(self) -> UVec4 { - UVec4::new(self.x, self.x, self.z, self.x) + fn zx(self) -> UVec2 { + UVec2 { + x: self.z, + y: self.x, + } } + #[inline] - fn xxzy(self) -> UVec4 { - UVec4::new(self.x, self.x, self.z, self.y) + fn zy(self) -> UVec2 { + UVec2 { + x: self.z, + y: self.y, + } } + #[inline] - fn xxzz(self) -> UVec4 { - UVec4::new(self.x, self.x, self.z, self.z) + fn zz(self) -> UVec2 { + UVec2 { + x: self.z, + y: self.z, + } } + #[inline] - fn xxzw(self) -> UVec4 { - UVec4::new(self.x, self.x, self.z, self.w) + fn zw(self) -> UVec2 { + UVec2 { + x: self.z, + y: self.w, + } } + #[inline] - fn xxwx(self) -> UVec4 { - UVec4::new(self.x, self.x, self.w, self.x) + fn wx(self) -> UVec2 { + UVec2 { + x: self.w, + y: self.x, + } } + #[inline] - fn xxwy(self) -> UVec4 { - UVec4::new(self.x, self.x, self.w, self.y) + fn wy(self) -> UVec2 { + UVec2 { + x: self.w, + y: self.y, + } } + #[inline] - fn xxwz(self) -> UVec4 { - UVec4::new(self.x, self.x, self.w, self.z) + fn wz(self) -> UVec2 { + UVec2 { + x: self.w, + y: self.z, + } } + #[inline] - fn xxww(self) -> UVec4 { - UVec4::new(self.x, self.x, self.w, self.w) + fn ww(self) -> UVec2 { + UVec2 { + x: self.w, + y: self.w, + } } + #[inline] - fn xyxx(self) -> UVec4 { - UVec4::new(self.x, self.y, self.x, self.x) + fn xxx(self) -> UVec3 { + UVec3 { + x: self.x, + y: self.x, + z: self.x, + } } + #[inline] - fn xyxy(self) -> UVec4 { - UVec4::new(self.x, self.y, self.x, self.y) + fn xxy(self) -> UVec3 { + UVec3 { + x: self.x, + y: self.x, + z: self.y, + } } + #[inline] - fn xyxz(self) -> UVec4 { - UVec4::new(self.x, self.y, self.x, self.z) + fn xxz(self) -> UVec3 { + UVec3 { + x: self.x, + y: self.x, + z: self.z, + } } + #[inline] - fn xyxw(self) -> UVec4 { - UVec4::new(self.x, self.y, self.x, self.w) + fn xxw(self) -> UVec3 { + UVec3 { + x: self.x, + y: self.x, + z: self.w, + } } + #[inline] - fn xyyx(self) -> UVec4 { - UVec4::new(self.x, self.y, self.y, self.x) + fn xyx(self) -> UVec3 { + UVec3 { + x: self.x, + y: self.y, + z: self.x, + } } + #[inline] - fn xyyy(self) -> UVec4 { - UVec4::new(self.x, self.y, self.y, self.y) + fn xyy(self) -> UVec3 { + UVec3 { + x: self.x, + y: self.y, + z: self.y, + } } + #[inline] - fn xyyz(self) -> UVec4 { - UVec4::new(self.x, self.y, self.y, self.z) + fn xyz(self) -> UVec3 { + UVec3 { + x: self.x, + y: self.y, + z: self.z, + } } + #[inline] - fn xyyw(self) -> UVec4 { - UVec4::new(self.x, self.y, self.y, self.w) + fn xyw(self) -> UVec3 { + UVec3 { + x: self.x, + y: self.y, + z: self.w, + } } + #[inline] - fn xyzx(self) -> UVec4 { - UVec4::new(self.x, self.y, self.z, self.x) + fn xzx(self) -> UVec3 { + UVec3 { + x: self.x, + y: self.z, + z: self.x, + } } + #[inline] - fn xyzy(self) -> UVec4 { - UVec4::new(self.x, self.y, self.z, self.y) + fn xzy(self) -> UVec3 { + UVec3 { + x: self.x, + y: self.z, + z: self.y, + } } + #[inline] - fn xyzz(self) -> UVec4 { - UVec4::new(self.x, self.y, self.z, self.z) + fn xzz(self) -> UVec3 { + UVec3 { + x: self.x, + y: self.z, + z: self.z, + } } + #[inline] - fn xywx(self) -> UVec4 { - UVec4::new(self.x, self.y, self.w, self.x) + fn xzw(self) -> UVec3 { + UVec3 { + x: self.x, + y: self.z, + z: self.w, + } } + #[inline] - fn xywy(self) -> UVec4 { - UVec4::new(self.x, self.y, self.w, self.y) + fn xwx(self) -> UVec3 { + UVec3 { + x: self.x, + y: self.w, + z: self.x, + } } + #[inline] - fn xywz(self) -> UVec4 { - UVec4::new(self.x, self.y, self.w, self.z) + fn xwy(self) -> UVec3 { + UVec3 { + x: self.x, + y: self.w, + z: self.y, + } } + #[inline] - fn xyww(self) -> UVec4 { - UVec4::new(self.x, self.y, self.w, self.w) + fn xwz(self) -> UVec3 { + UVec3 { + x: self.x, + y: self.w, + z: self.z, + } } + #[inline] - fn xzxx(self) -> UVec4 { - UVec4::new(self.x, self.z, self.x, self.x) + fn xww(self) -> UVec3 { + UVec3 { + x: self.x, + y: self.w, + z: self.w, + } } + #[inline] - fn xzxy(self) -> UVec4 { - UVec4::new(self.x, self.z, self.x, self.y) + fn yxx(self) -> UVec3 { + UVec3 { + x: self.y, + y: self.x, + z: self.x, + } } + #[inline] - fn xzxz(self) -> UVec4 { - UVec4::new(self.x, self.z, self.x, self.z) + fn yxy(self) -> UVec3 { + UVec3 { + x: self.y, + y: self.x, + z: self.y, + } } + #[inline] - fn xzxw(self) -> UVec4 { - UVec4::new(self.x, self.z, self.x, self.w) + fn yxz(self) -> UVec3 { + UVec3 { + x: self.y, + y: self.x, + z: self.z, + } } + #[inline] - fn xzyx(self) -> UVec4 { - UVec4::new(self.x, self.z, self.y, self.x) + fn yxw(self) -> UVec3 { + UVec3 { + x: self.y, + y: self.x, + z: self.w, + } } + #[inline] - fn xzyy(self) -> UVec4 { - UVec4::new(self.x, self.z, self.y, self.y) + fn yyx(self) -> UVec3 { + UVec3 { + x: self.y, + y: self.y, + z: self.x, + } } + #[inline] - fn xzyz(self) -> UVec4 { - UVec4::new(self.x, self.z, self.y, self.z) + fn yyy(self) -> UVec3 { + UVec3 { + x: self.y, + y: self.y, + z: self.y, + } } + #[inline] - fn xzyw(self) -> UVec4 { - UVec4::new(self.x, self.z, self.y, self.w) + fn yyz(self) -> UVec3 { + UVec3 { + x: self.y, + y: self.y, + z: self.z, + } } + #[inline] - fn xzzx(self) -> UVec4 { - UVec4::new(self.x, self.z, self.z, self.x) + fn yyw(self) -> UVec3 { + UVec3 { + x: self.y, + y: self.y, + z: self.w, + } } + #[inline] - fn xzzy(self) -> UVec4 { - UVec4::new(self.x, self.z, self.z, self.y) + fn yzx(self) -> UVec3 { + UVec3 { + x: self.y, + y: self.z, + z: self.x, + } } + #[inline] - fn xzzz(self) -> UVec4 { - UVec4::new(self.x, self.z, self.z, self.z) + fn yzy(self) -> UVec3 { + UVec3 { + x: self.y, + y: self.z, + z: self.y, + } } + #[inline] - fn xzzw(self) -> UVec4 { - UVec4::new(self.x, self.z, self.z, self.w) + fn yzz(self) -> UVec3 { + UVec3 { + x: self.y, + y: self.z, + z: self.z, + } } + #[inline] - fn xzwx(self) -> UVec4 { - UVec4::new(self.x, self.z, self.w, self.x) + fn yzw(self) -> UVec3 { + UVec3 { + x: self.y, + y: self.z, + z: self.w, + } } + #[inline] - fn xzwy(self) -> UVec4 { - UVec4::new(self.x, self.z, self.w, self.y) + fn ywx(self) -> UVec3 { + UVec3 { + x: self.y, + y: self.w, + z: self.x, + } } + #[inline] - fn xzwz(self) -> UVec4 { - UVec4::new(self.x, self.z, self.w, self.z) + fn ywy(self) -> UVec3 { + UVec3 { + x: self.y, + y: self.w, + z: self.y, + } } + #[inline] - fn xzww(self) -> UVec4 { - UVec4::new(self.x, self.z, self.w, self.w) + fn ywz(self) -> UVec3 { + UVec3 { + x: self.y, + y: self.w, + z: self.z, + } } + #[inline] - fn xwxx(self) -> UVec4 { - UVec4::new(self.x, self.w, self.x, self.x) + fn yww(self) -> UVec3 { + UVec3 { + x: self.y, + y: self.w, + z: self.w, + } } + #[inline] - fn xwxy(self) -> UVec4 { - UVec4::new(self.x, self.w, self.x, self.y) + fn zxx(self) -> UVec3 { + UVec3 { + x: self.z, + y: self.x, + z: self.x, + } } + #[inline] - fn xwxz(self) -> UVec4 { - UVec4::new(self.x, self.w, self.x, self.z) + fn zxy(self) -> UVec3 { + UVec3 { + x: self.z, + y: self.x, + z: self.y, + } } + #[inline] - fn xwxw(self) -> UVec4 { - UVec4::new(self.x, self.w, self.x, self.w) + fn zxz(self) -> UVec3 { + UVec3 { + x: self.z, + y: self.x, + z: self.z, + } } + #[inline] - fn xwyx(self) -> UVec4 { - UVec4::new(self.x, self.w, self.y, self.x) + fn zxw(self) -> UVec3 { + UVec3 { + x: self.z, + y: self.x, + z: self.w, + } } + #[inline] - fn xwyy(self) -> UVec4 { - UVec4::new(self.x, self.w, self.y, self.y) + fn zyx(self) -> UVec3 { + UVec3 { + x: self.z, + y: self.y, + z: self.x, + } } + #[inline] - fn xwyz(self) -> UVec4 { - UVec4::new(self.x, self.w, self.y, self.z) + fn zyy(self) -> UVec3 { + UVec3 { + x: self.z, + y: self.y, + z: self.y, + } } + #[inline] - fn xwyw(self) -> UVec4 { - UVec4::new(self.x, self.w, self.y, self.w) + fn zyz(self) -> UVec3 { + UVec3 { + x: self.z, + y: self.y, + z: self.z, + } } + #[inline] - fn xwzx(self) -> UVec4 { - UVec4::new(self.x, self.w, self.z, self.x) + fn zyw(self) -> UVec3 { + UVec3 { + x: self.z, + y: self.y, + z: self.w, + } } + #[inline] - fn xwzy(self) -> UVec4 { - UVec4::new(self.x, self.w, self.z, self.y) + fn zzx(self) -> UVec3 { + UVec3 { + x: self.z, + y: self.z, + z: self.x, + } } + #[inline] - fn xwzz(self) -> UVec4 { - UVec4::new(self.x, self.w, self.z, self.z) + fn zzy(self) -> UVec3 { + UVec3 { + x: self.z, + y: self.z, + z: self.y, + } } + #[inline] - fn xwzw(self) -> UVec4 { - UVec4::new(self.x, self.w, self.z, self.w) + fn zzz(self) -> UVec3 { + UVec3 { + x: self.z, + y: self.z, + z: self.z, + } } + #[inline] - fn xwwx(self) -> UVec4 { - UVec4::new(self.x, self.w, self.w, self.x) + fn zzw(self) -> UVec3 { + UVec3 { + x: self.z, + y: self.z, + z: self.w, + } } + #[inline] - fn xwwy(self) -> UVec4 { - UVec4::new(self.x, self.w, self.w, self.y) + fn zwx(self) -> UVec3 { + UVec3 { + x: self.z, + y: self.w, + z: self.x, + } } + #[inline] - fn xwwz(self) -> UVec4 { - UVec4::new(self.x, self.w, self.w, self.z) + fn zwy(self) -> UVec3 { + UVec3 { + x: self.z, + y: self.w, + z: self.y, + } } + #[inline] - fn xwww(self) -> UVec4 { - UVec4::new(self.x, self.w, self.w, self.w) + fn zwz(self) -> UVec3 { + UVec3 { + x: self.z, + y: self.w, + z: self.z, + } } + #[inline] - fn yxxx(self) -> UVec4 { - UVec4::new(self.y, self.x, self.x, self.x) + fn zww(self) -> UVec3 { + UVec3 { + x: self.z, + y: self.w, + z: self.w, + } } + #[inline] - fn yxxy(self) -> UVec4 { - UVec4::new(self.y, self.x, self.x, self.y) + fn wxx(self) -> UVec3 { + UVec3 { + x: self.w, + y: self.x, + z: self.x, + } } + #[inline] - fn yxxz(self) -> UVec4 { - UVec4::new(self.y, self.x, self.x, self.z) + fn wxy(self) -> UVec3 { + UVec3 { + x: self.w, + y: self.x, + z: self.y, + } } + #[inline] - fn yxxw(self) -> UVec4 { - UVec4::new(self.y, self.x, self.x, self.w) + fn wxz(self) -> UVec3 { + UVec3 { + x: self.w, + y: self.x, + z: self.z, + } } + #[inline] - fn yxyx(self) -> UVec4 { - UVec4::new(self.y, self.x, self.y, self.x) + fn wxw(self) -> UVec3 { + UVec3 { + x: self.w, + y: self.x, + z: self.w, + } } + #[inline] - fn yxyy(self) -> UVec4 { - UVec4::new(self.y, self.x, self.y, self.y) + fn wyx(self) -> UVec3 { + UVec3 { + x: self.w, + y: self.y, + z: self.x, + } } + #[inline] - fn yxyz(self) -> UVec4 { - UVec4::new(self.y, self.x, self.y, self.z) + fn wyy(self) -> UVec3 { + UVec3 { + x: self.w, + y: self.y, + z: self.y, + } } + #[inline] - fn yxyw(self) -> UVec4 { - UVec4::new(self.y, self.x, self.y, self.w) + fn wyz(self) -> UVec3 { + UVec3 { + x: self.w, + y: self.y, + z: self.z, + } } + #[inline] - fn yxzx(self) -> UVec4 { - UVec4::new(self.y, self.x, self.z, self.x) + fn wyw(self) -> UVec3 { + UVec3 { + x: self.w, + y: self.y, + z: self.w, + } } + #[inline] - fn yxzy(self) -> UVec4 { - UVec4::new(self.y, self.x, self.z, self.y) + fn wzx(self) -> UVec3 { + UVec3 { + x: self.w, + y: self.z, + z: self.x, + } } + #[inline] - fn yxzz(self) -> UVec4 { - UVec4::new(self.y, self.x, self.z, self.z) + fn wzy(self) -> UVec3 { + UVec3 { + x: self.w, + y: self.z, + z: self.y, + } } + #[inline] - fn yxzw(self) -> UVec4 { - UVec4::new(self.y, self.x, self.z, self.w) + fn wzz(self) -> UVec3 { + UVec3 { + x: self.w, + y: self.z, + z: self.z, + } } + #[inline] - fn yxwx(self) -> UVec4 { - UVec4::new(self.y, self.x, self.w, self.x) + fn wzw(self) -> UVec3 { + UVec3 { + x: self.w, + y: self.z, + z: self.w, + } } + #[inline] - fn yxwy(self) -> UVec4 { - UVec4::new(self.y, self.x, self.w, self.y) + fn wwx(self) -> UVec3 { + UVec3 { + x: self.w, + y: self.w, + z: self.x, + } } + #[inline] - fn yxwz(self) -> UVec4 { - UVec4::new(self.y, self.x, self.w, self.z) + fn wwy(self) -> UVec3 { + UVec3 { + x: self.w, + y: self.w, + z: self.y, + } } + #[inline] - fn yxww(self) -> UVec4 { - UVec4::new(self.y, self.x, self.w, self.w) + fn wwz(self) -> UVec3 { + UVec3 { + x: self.w, + y: self.w, + z: self.z, + } } + #[inline] - fn yyxx(self) -> UVec4 { - UVec4::new(self.y, self.y, self.x, self.x) + fn www(self) -> UVec3 { + UVec3 { + x: self.w, + y: self.w, + z: self.w, + } } + #[inline] - fn yyxy(self) -> UVec4 { - UVec4::new(self.y, self.y, self.x, self.y) + fn xxxx(self) -> UVec4 { + UVec4::new(self.x, self.x, self.x, self.x) } + #[inline] - fn yyxz(self) -> UVec4 { - UVec4::new(self.y, self.y, self.x, self.z) + fn xxxy(self) -> UVec4 { + UVec4::new(self.x, self.x, self.x, self.y) } + #[inline] - fn yyxw(self) -> UVec4 { - UVec4::new(self.y, self.y, self.x, self.w) + fn xxxz(self) -> UVec4 { + UVec4::new(self.x, self.x, self.x, self.z) } + #[inline] - fn yyyx(self) -> UVec4 { - UVec4::new(self.y, self.y, self.y, self.x) + fn xxxw(self) -> UVec4 { + UVec4::new(self.x, self.x, self.x, self.w) } + #[inline] - fn yyyy(self) -> UVec4 { - UVec4::new(self.y, self.y, self.y, self.y) + fn xxyx(self) -> UVec4 { + UVec4::new(self.x, self.x, self.y, self.x) } + #[inline] - fn yyyz(self) -> UVec4 { - UVec4::new(self.y, self.y, self.y, self.z) + fn xxyy(self) -> UVec4 { + UVec4::new(self.x, self.x, self.y, self.y) } + #[inline] - fn yyyw(self) -> UVec4 { - UVec4::new(self.y, self.y, self.y, self.w) + fn xxyz(self) -> UVec4 { + UVec4::new(self.x, self.x, self.y, self.z) } + #[inline] - fn yyzx(self) -> UVec4 { - UVec4::new(self.y, self.y, self.z, self.x) + fn xxyw(self) -> UVec4 { + UVec4::new(self.x, self.x, self.y, self.w) } + #[inline] - fn yyzy(self) -> UVec4 { - UVec4::new(self.y, self.y, self.z, self.y) + fn xxzx(self) -> UVec4 { + UVec4::new(self.x, self.x, self.z, self.x) } + #[inline] - fn yyzz(self) -> UVec4 { - UVec4::new(self.y, self.y, self.z, self.z) + fn xxzy(self) -> UVec4 { + UVec4::new(self.x, self.x, self.z, self.y) } + #[inline] - fn yyzw(self) -> UVec4 { - UVec4::new(self.y, self.y, self.z, self.w) + fn xxzz(self) -> UVec4 { + UVec4::new(self.x, self.x, self.z, self.z) } + #[inline] - fn yywx(self) -> UVec4 { - UVec4::new(self.y, self.y, self.w, self.x) + fn xxzw(self) -> UVec4 { + UVec4::new(self.x, self.x, self.z, self.w) } + #[inline] - fn yywy(self) -> UVec4 { - UVec4::new(self.y, self.y, self.w, self.y) + fn xxwx(self) -> UVec4 { + UVec4::new(self.x, self.x, self.w, self.x) } + #[inline] - fn yywz(self) -> UVec4 { - UVec4::new(self.y, self.y, self.w, self.z) + fn xxwy(self) -> UVec4 { + UVec4::new(self.x, self.x, self.w, self.y) } + #[inline] - fn yyww(self) -> UVec4 { - UVec4::new(self.y, self.y, self.w, self.w) + fn xxwz(self) -> UVec4 { + UVec4::new(self.x, self.x, self.w, self.z) } + #[inline] - fn yzxx(self) -> UVec4 { - UVec4::new(self.y, self.z, self.x, self.x) + fn xxww(self) -> UVec4 { + UVec4::new(self.x, self.x, self.w, self.w) } + #[inline] - fn yzxy(self) -> UVec4 { - UVec4::new(self.y, self.z, self.x, self.y) + fn xyxx(self) -> UVec4 { + UVec4::new(self.x, self.y, self.x, self.x) } + #[inline] - fn yzxz(self) -> UVec4 { - UVec4::new(self.y, self.z, self.x, self.z) + fn xyxy(self) -> UVec4 { + UVec4::new(self.x, self.y, self.x, self.y) } + #[inline] - fn yzxw(self) -> UVec4 { - UVec4::new(self.y, self.z, self.x, self.w) + fn xyxz(self) -> UVec4 { + UVec4::new(self.x, self.y, self.x, self.z) } + #[inline] - fn yzyx(self) -> UVec4 { - UVec4::new(self.y, self.z, self.y, self.x) + fn xyxw(self) -> UVec4 { + UVec4::new(self.x, self.y, self.x, self.w) } + #[inline] - fn yzyy(self) -> UVec4 { - UVec4::new(self.y, self.z, self.y, self.y) + fn xyyx(self) -> UVec4 { + UVec4::new(self.x, self.y, self.y, self.x) } + #[inline] - fn yzyz(self) -> UVec4 { - UVec4::new(self.y, self.z, self.y, self.z) + fn xyyy(self) -> UVec4 { + UVec4::new(self.x, self.y, self.y, self.y) } + #[inline] - fn yzyw(self) -> UVec4 { - UVec4::new(self.y, self.z, self.y, self.w) + fn xyyz(self) -> UVec4 { + UVec4::new(self.x, self.y, self.y, self.z) } + #[inline] - fn yzzx(self) -> UVec4 { - UVec4::new(self.y, self.z, self.z, self.x) + fn xyyw(self) -> UVec4 { + UVec4::new(self.x, self.y, self.y, self.w) } + #[inline] - fn yzzy(self) -> UVec4 { - UVec4::new(self.y, self.z, self.z, self.y) + fn xyzx(self) -> UVec4 { + UVec4::new(self.x, self.y, self.z, self.x) } + #[inline] - fn yzzz(self) -> UVec4 { - UVec4::new(self.y, self.z, self.z, self.z) + fn xyzy(self) -> UVec4 { + UVec4::new(self.x, self.y, self.z, self.y) } + #[inline] - fn yzzw(self) -> UVec4 { - UVec4::new(self.y, self.z, self.z, self.w) + fn xyzz(self) -> UVec4 { + UVec4::new(self.x, self.y, self.z, self.z) } + #[inline] - fn yzwx(self) -> UVec4 { - UVec4::new(self.y, self.z, self.w, self.x) + fn xyzw(self) -> UVec4 { + UVec4::new(self.x, self.y, self.z, self.w) } + #[inline] - fn yzwy(self) -> UVec4 { - UVec4::new(self.y, self.z, self.w, self.y) + fn xywx(self) -> UVec4 { + UVec4::new(self.x, self.y, self.w, self.x) } + #[inline] - fn yzwz(self) -> UVec4 { - UVec4::new(self.y, self.z, self.w, self.z) + fn xywy(self) -> UVec4 { + UVec4::new(self.x, self.y, self.w, self.y) } + #[inline] - fn yzww(self) -> UVec4 { - UVec4::new(self.y, self.z, self.w, self.w) + fn xywz(self) -> UVec4 { + UVec4::new(self.x, self.y, self.w, self.z) } + #[inline] - fn ywxx(self) -> UVec4 { - UVec4::new(self.y, self.w, self.x, self.x) + fn xyww(self) -> UVec4 { + UVec4::new(self.x, self.y, self.w, self.w) } + #[inline] - fn ywxy(self) -> UVec4 { - UVec4::new(self.y, self.w, self.x, self.y) + fn xzxx(self) -> UVec4 { + UVec4::new(self.x, self.z, self.x, self.x) } + #[inline] - fn ywxz(self) -> UVec4 { - UVec4::new(self.y, self.w, self.x, self.z) + fn xzxy(self) -> UVec4 { + UVec4::new(self.x, self.z, self.x, self.y) } + #[inline] - fn ywxw(self) -> UVec4 { - UVec4::new(self.y, self.w, self.x, self.w) + fn xzxz(self) -> UVec4 { + UVec4::new(self.x, self.z, self.x, self.z) } + #[inline] - fn ywyx(self) -> UVec4 { - UVec4::new(self.y, self.w, self.y, self.x) + fn xzxw(self) -> UVec4 { + UVec4::new(self.x, self.z, self.x, self.w) } + #[inline] - fn ywyy(self) -> UVec4 { - UVec4::new(self.y, self.w, self.y, self.y) + fn xzyx(self) -> UVec4 { + UVec4::new(self.x, self.z, self.y, self.x) } + #[inline] - fn ywyz(self) -> UVec4 { - UVec4::new(self.y, self.w, self.y, self.z) + fn xzyy(self) -> UVec4 { + UVec4::new(self.x, self.z, self.y, self.y) } + #[inline] - fn ywyw(self) -> UVec4 { - UVec4::new(self.y, self.w, self.y, self.w) + fn xzyz(self) -> UVec4 { + UVec4::new(self.x, self.z, self.y, self.z) } + #[inline] - fn ywzx(self) -> UVec4 { - UVec4::new(self.y, self.w, self.z, self.x) + fn xzyw(self) -> UVec4 { + UVec4::new(self.x, self.z, self.y, self.w) } + #[inline] - fn ywzy(self) -> UVec4 { - UVec4::new(self.y, self.w, self.z, self.y) + fn xzzx(self) -> UVec4 { + UVec4::new(self.x, self.z, self.z, self.x) } + #[inline] - fn ywzz(self) -> UVec4 { - UVec4::new(self.y, self.w, self.z, self.z) + fn xzzy(self) -> UVec4 { + UVec4::new(self.x, self.z, self.z, self.y) } + #[inline] - fn ywzw(self) -> UVec4 { - UVec4::new(self.y, self.w, self.z, self.w) + fn xzzz(self) -> UVec4 { + UVec4::new(self.x, self.z, self.z, self.z) } + #[inline] - fn ywwx(self) -> UVec4 { - UVec4::new(self.y, self.w, self.w, self.x) + fn xzzw(self) -> UVec4 { + UVec4::new(self.x, self.z, self.z, self.w) } + #[inline] - fn ywwy(self) -> UVec4 { - UVec4::new(self.y, self.w, self.w, self.y) + fn xzwx(self) -> UVec4 { + UVec4::new(self.x, self.z, self.w, self.x) } + #[inline] - fn ywwz(self) -> UVec4 { - UVec4::new(self.y, self.w, self.w, self.z) + fn xzwy(self) -> UVec4 { + UVec4::new(self.x, self.z, self.w, self.y) } + #[inline] - fn ywww(self) -> UVec4 { - UVec4::new(self.y, self.w, self.w, self.w) + fn xzwz(self) -> UVec4 { + UVec4::new(self.x, self.z, self.w, self.z) } + #[inline] - fn zxxx(self) -> UVec4 { - UVec4::new(self.z, self.x, self.x, self.x) + fn xzww(self) -> UVec4 { + UVec4::new(self.x, self.z, self.w, self.w) } + #[inline] - fn zxxy(self) -> UVec4 { - UVec4::new(self.z, self.x, self.x, self.y) + fn xwxx(self) -> UVec4 { + UVec4::new(self.x, self.w, self.x, self.x) } + #[inline] - fn zxxz(self) -> UVec4 { - UVec4::new(self.z, self.x, self.x, self.z) + fn xwxy(self) -> UVec4 { + UVec4::new(self.x, self.w, self.x, self.y) } + #[inline] - fn zxxw(self) -> UVec4 { - UVec4::new(self.z, self.x, self.x, self.w) + fn xwxz(self) -> UVec4 { + UVec4::new(self.x, self.w, self.x, self.z) } + #[inline] - fn zxyx(self) -> UVec4 { - UVec4::new(self.z, self.x, self.y, self.x) + fn xwxw(self) -> UVec4 { + UVec4::new(self.x, self.w, self.x, self.w) } + #[inline] - fn zxyy(self) -> UVec4 { - UVec4::new(self.z, self.x, self.y, self.y) + fn xwyx(self) -> UVec4 { + UVec4::new(self.x, self.w, self.y, self.x) } + #[inline] - fn zxyz(self) -> UVec4 { - UVec4::new(self.z, self.x, self.y, self.z) + fn xwyy(self) -> UVec4 { + UVec4::new(self.x, self.w, self.y, self.y) } + #[inline] - fn zxyw(self) -> UVec4 { - UVec4::new(self.z, self.x, self.y, self.w) + fn xwyz(self) -> UVec4 { + UVec4::new(self.x, self.w, self.y, self.z) } + #[inline] - fn zxzx(self) -> UVec4 { - UVec4::new(self.z, self.x, self.z, self.x) + fn xwyw(self) -> UVec4 { + UVec4::new(self.x, self.w, self.y, self.w) } + #[inline] - fn zxzy(self) -> UVec4 { - UVec4::new(self.z, self.x, self.z, self.y) + fn xwzx(self) -> UVec4 { + UVec4::new(self.x, self.w, self.z, self.x) } + #[inline] - fn zxzz(self) -> UVec4 { - UVec4::new(self.z, self.x, self.z, self.z) + fn xwzy(self) -> UVec4 { + UVec4::new(self.x, self.w, self.z, self.y) } + #[inline] - fn zxzw(self) -> UVec4 { - UVec4::new(self.z, self.x, self.z, self.w) + fn xwzz(self) -> UVec4 { + UVec4::new(self.x, self.w, self.z, self.z) } + #[inline] - fn zxwx(self) -> UVec4 { - UVec4::new(self.z, self.x, self.w, self.x) + fn xwzw(self) -> UVec4 { + UVec4::new(self.x, self.w, self.z, self.w) } + #[inline] - fn zxwy(self) -> UVec4 { - UVec4::new(self.z, self.x, self.w, self.y) + fn xwwx(self) -> UVec4 { + UVec4::new(self.x, self.w, self.w, self.x) } + #[inline] - fn zxwz(self) -> UVec4 { - UVec4::new(self.z, self.x, self.w, self.z) + fn xwwy(self) -> UVec4 { + UVec4::new(self.x, self.w, self.w, self.y) } + #[inline] - fn zxww(self) -> UVec4 { - UVec4::new(self.z, self.x, self.w, self.w) + fn xwwz(self) -> UVec4 { + UVec4::new(self.x, self.w, self.w, self.z) } + #[inline] - fn zyxx(self) -> UVec4 { - UVec4::new(self.z, self.y, self.x, self.x) + fn xwww(self) -> UVec4 { + UVec4::new(self.x, self.w, self.w, self.w) } + #[inline] - fn zyxy(self) -> UVec4 { - UVec4::new(self.z, self.y, self.x, self.y) + fn yxxx(self) -> UVec4 { + UVec4::new(self.y, self.x, self.x, self.x) } + #[inline] - fn zyxz(self) -> UVec4 { - UVec4::new(self.z, self.y, self.x, self.z) + fn yxxy(self) -> UVec4 { + UVec4::new(self.y, self.x, self.x, self.y) } + #[inline] - fn zyxw(self) -> UVec4 { - UVec4::new(self.z, self.y, self.x, self.w) + fn yxxz(self) -> UVec4 { + UVec4::new(self.y, self.x, self.x, self.z) } + #[inline] - fn zyyx(self) -> UVec4 { - UVec4::new(self.z, self.y, self.y, self.x) + fn yxxw(self) -> UVec4 { + UVec4::new(self.y, self.x, self.x, self.w) } + #[inline] - fn zyyy(self) -> UVec4 { - UVec4::new(self.z, self.y, self.y, self.y) + fn yxyx(self) -> UVec4 { + UVec4::new(self.y, self.x, self.y, self.x) } + #[inline] - fn zyyz(self) -> UVec4 { - UVec4::new(self.z, self.y, self.y, self.z) + fn yxyy(self) -> UVec4 { + UVec4::new(self.y, self.x, self.y, self.y) } + #[inline] - fn zyyw(self) -> UVec4 { - UVec4::new(self.z, self.y, self.y, self.w) + fn yxyz(self) -> UVec4 { + UVec4::new(self.y, self.x, self.y, self.z) } + #[inline] - fn zyzx(self) -> UVec4 { - UVec4::new(self.z, self.y, self.z, self.x) + fn yxyw(self) -> UVec4 { + UVec4::new(self.y, self.x, self.y, self.w) } + #[inline] - fn zyzy(self) -> UVec4 { - UVec4::new(self.z, self.y, self.z, self.y) + fn yxzx(self) -> UVec4 { + UVec4::new(self.y, self.x, self.z, self.x) } + #[inline] - fn zyzz(self) -> UVec4 { - UVec4::new(self.z, self.y, self.z, self.z) + fn yxzy(self) -> UVec4 { + UVec4::new(self.y, self.x, self.z, self.y) } + #[inline] - fn zyzw(self) -> UVec4 { - UVec4::new(self.z, self.y, self.z, self.w) + fn yxzz(self) -> UVec4 { + UVec4::new(self.y, self.x, self.z, self.z) } + #[inline] - fn zywx(self) -> UVec4 { - UVec4::new(self.z, self.y, self.w, self.x) + fn yxzw(self) -> UVec4 { + UVec4::new(self.y, self.x, self.z, self.w) } + #[inline] - fn zywy(self) -> UVec4 { - UVec4::new(self.z, self.y, self.w, self.y) + fn yxwx(self) -> UVec4 { + UVec4::new(self.y, self.x, self.w, self.x) } + #[inline] - fn zywz(self) -> UVec4 { - UVec4::new(self.z, self.y, self.w, self.z) + fn yxwy(self) -> UVec4 { + UVec4::new(self.y, self.x, self.w, self.y) } + #[inline] - fn zyww(self) -> UVec4 { - UVec4::new(self.z, self.y, self.w, self.w) + fn yxwz(self) -> UVec4 { + UVec4::new(self.y, self.x, self.w, self.z) } + #[inline] - fn zzxx(self) -> UVec4 { - UVec4::new(self.z, self.z, self.x, self.x) + fn yxww(self) -> UVec4 { + UVec4::new(self.y, self.x, self.w, self.w) } + #[inline] - fn zzxy(self) -> UVec4 { - UVec4::new(self.z, self.z, self.x, self.y) + fn yyxx(self) -> UVec4 { + UVec4::new(self.y, self.y, self.x, self.x) } + #[inline] - fn zzxz(self) -> UVec4 { - UVec4::new(self.z, self.z, self.x, self.z) + fn yyxy(self) -> UVec4 { + UVec4::new(self.y, self.y, self.x, self.y) } + #[inline] - fn zzxw(self) -> UVec4 { - UVec4::new(self.z, self.z, self.x, self.w) + fn yyxz(self) -> UVec4 { + UVec4::new(self.y, self.y, self.x, self.z) } + #[inline] - fn zzyx(self) -> UVec4 { - UVec4::new(self.z, self.z, self.y, self.x) + fn yyxw(self) -> UVec4 { + UVec4::new(self.y, self.y, self.x, self.w) } + #[inline] - fn zzyy(self) -> UVec4 { - UVec4::new(self.z, self.z, self.y, self.y) + fn yyyx(self) -> UVec4 { + UVec4::new(self.y, self.y, self.y, self.x) } + #[inline] - fn zzyz(self) -> UVec4 { - UVec4::new(self.z, self.z, self.y, self.z) + fn yyyy(self) -> UVec4 { + UVec4::new(self.y, self.y, self.y, self.y) } + #[inline] - fn zzyw(self) -> UVec4 { - UVec4::new(self.z, self.z, self.y, self.w) + fn yyyz(self) -> UVec4 { + UVec4::new(self.y, self.y, self.y, self.z) } + #[inline] - fn zzzx(self) -> UVec4 { - UVec4::new(self.z, self.z, self.z, self.x) + fn yyyw(self) -> UVec4 { + UVec4::new(self.y, self.y, self.y, self.w) } + #[inline] - fn zzzy(self) -> UVec4 { - UVec4::new(self.z, self.z, self.z, self.y) + fn yyzx(self) -> UVec4 { + UVec4::new(self.y, self.y, self.z, self.x) } + #[inline] - fn zzzz(self) -> UVec4 { - UVec4::new(self.z, self.z, self.z, self.z) + fn yyzy(self) -> UVec4 { + UVec4::new(self.y, self.y, self.z, self.y) } + #[inline] - fn zzzw(self) -> UVec4 { - UVec4::new(self.z, self.z, self.z, self.w) + fn yyzz(self) -> UVec4 { + UVec4::new(self.y, self.y, self.z, self.z) } + #[inline] - fn zzwx(self) -> UVec4 { - UVec4::new(self.z, self.z, self.w, self.x) + fn yyzw(self) -> UVec4 { + UVec4::new(self.y, self.y, self.z, self.w) } + #[inline] - fn zzwy(self) -> UVec4 { - UVec4::new(self.z, self.z, self.w, self.y) + fn yywx(self) -> UVec4 { + UVec4::new(self.y, self.y, self.w, self.x) } + #[inline] - fn zzwz(self) -> UVec4 { - UVec4::new(self.z, self.z, self.w, self.z) + fn yywy(self) -> UVec4 { + UVec4::new(self.y, self.y, self.w, self.y) } + #[inline] - fn zzww(self) -> UVec4 { - UVec4::new(self.z, self.z, self.w, self.w) + fn yywz(self) -> UVec4 { + UVec4::new(self.y, self.y, self.w, self.z) } + #[inline] - fn zwxx(self) -> UVec4 { - UVec4::new(self.z, self.w, self.x, self.x) + fn yyww(self) -> UVec4 { + UVec4::new(self.y, self.y, self.w, self.w) } + #[inline] - fn zwxy(self) -> UVec4 { - UVec4::new(self.z, self.w, self.x, self.y) + fn yzxx(self) -> UVec4 { + UVec4::new(self.y, self.z, self.x, self.x) } + #[inline] - fn zwxz(self) -> UVec4 { - UVec4::new(self.z, self.w, self.x, self.z) + fn yzxy(self) -> UVec4 { + UVec4::new(self.y, self.z, self.x, self.y) } + #[inline] - fn zwxw(self) -> UVec4 { - UVec4::new(self.z, self.w, self.x, self.w) + fn yzxz(self) -> UVec4 { + UVec4::new(self.y, self.z, self.x, self.z) } + #[inline] - fn zwyx(self) -> UVec4 { - UVec4::new(self.z, self.w, self.y, self.x) + fn yzxw(self) -> UVec4 { + UVec4::new(self.y, self.z, self.x, self.w) } + #[inline] - fn zwyy(self) -> UVec4 { - UVec4::new(self.z, self.w, self.y, self.y) + fn yzyx(self) -> UVec4 { + UVec4::new(self.y, self.z, self.y, self.x) } + #[inline] - fn zwyz(self) -> UVec4 { - UVec4::new(self.z, self.w, self.y, self.z) + fn yzyy(self) -> UVec4 { + UVec4::new(self.y, self.z, self.y, self.y) } + #[inline] - fn zwyw(self) -> UVec4 { - UVec4::new(self.z, self.w, self.y, self.w) + fn yzyz(self) -> UVec4 { + UVec4::new(self.y, self.z, self.y, self.z) } + #[inline] - fn zwzx(self) -> UVec4 { - UVec4::new(self.z, self.w, self.z, self.x) + fn yzyw(self) -> UVec4 { + UVec4::new(self.y, self.z, self.y, self.w) } + #[inline] - fn zwzy(self) -> UVec4 { - UVec4::new(self.z, self.w, self.z, self.y) + fn yzzx(self) -> UVec4 { + UVec4::new(self.y, self.z, self.z, self.x) } + #[inline] - fn zwzz(self) -> UVec4 { - UVec4::new(self.z, self.w, self.z, self.z) + fn yzzy(self) -> UVec4 { + UVec4::new(self.y, self.z, self.z, self.y) } + #[inline] - fn zwzw(self) -> UVec4 { - UVec4::new(self.z, self.w, self.z, self.w) + fn yzzz(self) -> UVec4 { + UVec4::new(self.y, self.z, self.z, self.z) } + #[inline] - fn zwwx(self) -> UVec4 { - UVec4::new(self.z, self.w, self.w, self.x) + fn yzzw(self) -> UVec4 { + UVec4::new(self.y, self.z, self.z, self.w) } + #[inline] - fn zwwy(self) -> UVec4 { - UVec4::new(self.z, self.w, self.w, self.y) + fn yzwx(self) -> UVec4 { + UVec4::new(self.y, self.z, self.w, self.x) } + #[inline] - fn zwwz(self) -> UVec4 { - UVec4::new(self.z, self.w, self.w, self.z) + fn yzwy(self) -> UVec4 { + UVec4::new(self.y, self.z, self.w, self.y) } + #[inline] - fn zwww(self) -> UVec4 { - UVec4::new(self.z, self.w, self.w, self.w) + fn yzwz(self) -> UVec4 { + UVec4::new(self.y, self.z, self.w, self.z) } + #[inline] - fn wxxx(self) -> UVec4 { - UVec4::new(self.w, self.x, self.x, self.x) + fn yzww(self) -> UVec4 { + UVec4::new(self.y, self.z, self.w, self.w) } + #[inline] - fn wxxy(self) -> UVec4 { - UVec4::new(self.w, self.x, self.x, self.y) + fn ywxx(self) -> UVec4 { + UVec4::new(self.y, self.w, self.x, self.x) } + #[inline] - fn wxxz(self) -> UVec4 { - UVec4::new(self.w, self.x, self.x, self.z) + fn ywxy(self) -> UVec4 { + UVec4::new(self.y, self.w, self.x, self.y) } + #[inline] - fn wxxw(self) -> UVec4 { - UVec4::new(self.w, self.x, self.x, self.w) + fn ywxz(self) -> UVec4 { + UVec4::new(self.y, self.w, self.x, self.z) } + #[inline] - fn wxyx(self) -> UVec4 { - UVec4::new(self.w, self.x, self.y, self.x) + fn ywxw(self) -> UVec4 { + UVec4::new(self.y, self.w, self.x, self.w) } + #[inline] - fn wxyy(self) -> UVec4 { - UVec4::new(self.w, self.x, self.y, self.y) + fn ywyx(self) -> UVec4 { + UVec4::new(self.y, self.w, self.y, self.x) } + #[inline] - fn wxyz(self) -> UVec4 { - UVec4::new(self.w, self.x, self.y, self.z) + fn ywyy(self) -> UVec4 { + UVec4::new(self.y, self.w, self.y, self.y) } + #[inline] - fn wxyw(self) -> UVec4 { - UVec4::new(self.w, self.x, self.y, self.w) + fn ywyz(self) -> UVec4 { + UVec4::new(self.y, self.w, self.y, self.z) } + #[inline] - fn wxzx(self) -> UVec4 { - UVec4::new(self.w, self.x, self.z, self.x) + fn ywyw(self) -> UVec4 { + UVec4::new(self.y, self.w, self.y, self.w) } + #[inline] - fn wxzy(self) -> UVec4 { - UVec4::new(self.w, self.x, self.z, self.y) + fn ywzx(self) -> UVec4 { + UVec4::new(self.y, self.w, self.z, self.x) } + #[inline] - fn wxzz(self) -> UVec4 { - UVec4::new(self.w, self.x, self.z, self.z) + fn ywzy(self) -> UVec4 { + UVec4::new(self.y, self.w, self.z, self.y) } + #[inline] - fn wxzw(self) -> UVec4 { - UVec4::new(self.w, self.x, self.z, self.w) + fn ywzz(self) -> UVec4 { + UVec4::new(self.y, self.w, self.z, self.z) } + #[inline] - fn wxwx(self) -> UVec4 { - UVec4::new(self.w, self.x, self.w, self.x) + fn ywzw(self) -> UVec4 { + UVec4::new(self.y, self.w, self.z, self.w) } + #[inline] - fn wxwy(self) -> UVec4 { - UVec4::new(self.w, self.x, self.w, self.y) + fn ywwx(self) -> UVec4 { + UVec4::new(self.y, self.w, self.w, self.x) } + #[inline] - fn wxwz(self) -> UVec4 { - UVec4::new(self.w, self.x, self.w, self.z) + fn ywwy(self) -> UVec4 { + UVec4::new(self.y, self.w, self.w, self.y) } + #[inline] - fn wxww(self) -> UVec4 { - UVec4::new(self.w, self.x, self.w, self.w) + fn ywwz(self) -> UVec4 { + UVec4::new(self.y, self.w, self.w, self.z) } + #[inline] - fn wyxx(self) -> UVec4 { - UVec4::new(self.w, self.y, self.x, self.x) + fn ywww(self) -> UVec4 { + UVec4::new(self.y, self.w, self.w, self.w) } + #[inline] - fn wyxy(self) -> UVec4 { - UVec4::new(self.w, self.y, self.x, self.y) + fn zxxx(self) -> UVec4 { + UVec4::new(self.z, self.x, self.x, self.x) } + #[inline] - fn wyxz(self) -> UVec4 { - UVec4::new(self.w, self.y, self.x, self.z) + fn zxxy(self) -> UVec4 { + UVec4::new(self.z, self.x, self.x, self.y) } + #[inline] - fn wyxw(self) -> UVec4 { - UVec4::new(self.w, self.y, self.x, self.w) + fn zxxz(self) -> UVec4 { + UVec4::new(self.z, self.x, self.x, self.z) } + #[inline] - fn wyyx(self) -> UVec4 { - UVec4::new(self.w, self.y, self.y, self.x) + fn zxxw(self) -> UVec4 { + UVec4::new(self.z, self.x, self.x, self.w) } + #[inline] - fn wyyy(self) -> UVec4 { - UVec4::new(self.w, self.y, self.y, self.y) + fn zxyx(self) -> UVec4 { + UVec4::new(self.z, self.x, self.y, self.x) } + #[inline] - fn wyyz(self) -> UVec4 { - UVec4::new(self.w, self.y, self.y, self.z) + fn zxyy(self) -> UVec4 { + UVec4::new(self.z, self.x, self.y, self.y) } + #[inline] - fn wyyw(self) -> UVec4 { - UVec4::new(self.w, self.y, self.y, self.w) + fn zxyz(self) -> UVec4 { + UVec4::new(self.z, self.x, self.y, self.z) } + #[inline] - fn wyzx(self) -> UVec4 { - UVec4::new(self.w, self.y, self.z, self.x) + fn zxyw(self) -> UVec4 { + UVec4::new(self.z, self.x, self.y, self.w) } + #[inline] - fn wyzy(self) -> UVec4 { - UVec4::new(self.w, self.y, self.z, self.y) + fn zxzx(self) -> UVec4 { + UVec4::new(self.z, self.x, self.z, self.x) + } + + #[inline] + fn zxzy(self) -> UVec4 { + UVec4::new(self.z, self.x, self.z, self.y) } + #[inline] - fn wyzz(self) -> UVec4 { - UVec4::new(self.w, self.y, self.z, self.z) + fn zxzz(self) -> UVec4 { + UVec4::new(self.z, self.x, self.z, self.z) } + #[inline] - fn wyzw(self) -> UVec4 { - UVec4::new(self.w, self.y, self.z, self.w) + fn zxzw(self) -> UVec4 { + UVec4::new(self.z, self.x, self.z, self.w) } + #[inline] - fn wywx(self) -> UVec4 { - UVec4::new(self.w, self.y, self.w, self.x) + fn zxwx(self) -> UVec4 { + UVec4::new(self.z, self.x, self.w, self.x) } + #[inline] - fn wywy(self) -> UVec4 { - UVec4::new(self.w, self.y, self.w, self.y) + fn zxwy(self) -> UVec4 { + UVec4::new(self.z, self.x, self.w, self.y) } + #[inline] - fn wywz(self) -> UVec4 { - UVec4::new(self.w, self.y, self.w, self.z) + fn zxwz(self) -> UVec4 { + UVec4::new(self.z, self.x, self.w, self.z) } + #[inline] - fn wyww(self) -> UVec4 { - UVec4::new(self.w, self.y, self.w, self.w) + fn zxww(self) -> UVec4 { + UVec4::new(self.z, self.x, self.w, self.w) } + #[inline] - fn wzxx(self) -> UVec4 { - UVec4::new(self.w, self.z, self.x, self.x) + fn zyxx(self) -> UVec4 { + UVec4::new(self.z, self.y, self.x, self.x) } + #[inline] - fn wzxy(self) -> UVec4 { - UVec4::new(self.w, self.z, self.x, self.y) + fn zyxy(self) -> UVec4 { + UVec4::new(self.z, self.y, self.x, self.y) } + #[inline] - fn wzxz(self) -> UVec4 { - UVec4::new(self.w, self.z, self.x, self.z) + fn zyxz(self) -> UVec4 { + UVec4::new(self.z, self.y, self.x, self.z) } + #[inline] - fn wzxw(self) -> UVec4 { - UVec4::new(self.w, self.z, self.x, self.w) + fn zyxw(self) -> UVec4 { + UVec4::new(self.z, self.y, self.x, self.w) } + #[inline] - fn wzyx(self) -> UVec4 { - UVec4::new(self.w, self.z, self.y, self.x) + fn zyyx(self) -> UVec4 { + UVec4::new(self.z, self.y, self.y, self.x) } + #[inline] - fn wzyy(self) -> UVec4 { - UVec4::new(self.w, self.z, self.y, self.y) + fn zyyy(self) -> UVec4 { + UVec4::new(self.z, self.y, self.y, self.y) } + #[inline] - fn wzyz(self) -> UVec4 { - UVec4::new(self.w, self.z, self.y, self.z) + fn zyyz(self) -> UVec4 { + UVec4::new(self.z, self.y, self.y, self.z) } + #[inline] - fn wzyw(self) -> UVec4 { - UVec4::new(self.w, self.z, self.y, self.w) + fn zyyw(self) -> UVec4 { + UVec4::new(self.z, self.y, self.y, self.w) } + #[inline] - fn wzzx(self) -> UVec4 { - UVec4::new(self.w, self.z, self.z, self.x) + fn zyzx(self) -> UVec4 { + UVec4::new(self.z, self.y, self.z, self.x) } + #[inline] - fn wzzy(self) -> UVec4 { - UVec4::new(self.w, self.z, self.z, self.y) + fn zyzy(self) -> UVec4 { + UVec4::new(self.z, self.y, self.z, self.y) } + #[inline] - fn wzzz(self) -> UVec4 { - UVec4::new(self.w, self.z, self.z, self.z) + fn zyzz(self) -> UVec4 { + UVec4::new(self.z, self.y, self.z, self.z) } + #[inline] - fn wzzw(self) -> UVec4 { - UVec4::new(self.w, self.z, self.z, self.w) + fn zyzw(self) -> UVec4 { + UVec4::new(self.z, self.y, self.z, self.w) } + #[inline] - fn wzwx(self) -> UVec4 { - UVec4::new(self.w, self.z, self.w, self.x) + fn zywx(self) -> UVec4 { + UVec4::new(self.z, self.y, self.w, self.x) } + #[inline] - fn wzwy(self) -> UVec4 { - UVec4::new(self.w, self.z, self.w, self.y) + fn zywy(self) -> UVec4 { + UVec4::new(self.z, self.y, self.w, self.y) } + #[inline] - fn wzwz(self) -> UVec4 { - UVec4::new(self.w, self.z, self.w, self.z) + fn zywz(self) -> UVec4 { + UVec4::new(self.z, self.y, self.w, self.z) } + #[inline] - fn wzww(self) -> UVec4 { - UVec4::new(self.w, self.z, self.w, self.w) + fn zyww(self) -> UVec4 { + UVec4::new(self.z, self.y, self.w, self.w) } + #[inline] - fn wwxx(self) -> UVec4 { - UVec4::new(self.w, self.w, self.x, self.x) + fn zzxx(self) -> UVec4 { + UVec4::new(self.z, self.z, self.x, self.x) } + #[inline] - fn wwxy(self) -> UVec4 { - UVec4::new(self.w, self.w, self.x, self.y) + fn zzxy(self) -> UVec4 { + UVec4::new(self.z, self.z, self.x, self.y) } + #[inline] - fn wwxz(self) -> UVec4 { - UVec4::new(self.w, self.w, self.x, self.z) + fn zzxz(self) -> UVec4 { + UVec4::new(self.z, self.z, self.x, self.z) } + #[inline] - fn wwxw(self) -> UVec4 { - UVec4::new(self.w, self.w, self.x, self.w) + fn zzxw(self) -> UVec4 { + UVec4::new(self.z, self.z, self.x, self.w) } + #[inline] - fn wwyx(self) -> UVec4 { - UVec4::new(self.w, self.w, self.y, self.x) + fn zzyx(self) -> UVec4 { + UVec4::new(self.z, self.z, self.y, self.x) } + #[inline] - fn wwyy(self) -> UVec4 { - UVec4::new(self.w, self.w, self.y, self.y) + fn zzyy(self) -> UVec4 { + UVec4::new(self.z, self.z, self.y, self.y) } + #[inline] - fn wwyz(self) -> UVec4 { - UVec4::new(self.w, self.w, self.y, self.z) + fn zzyz(self) -> UVec4 { + UVec4::new(self.z, self.z, self.y, self.z) } + #[inline] - fn wwyw(self) -> UVec4 { - UVec4::new(self.w, self.w, self.y, self.w) + fn zzyw(self) -> UVec4 { + UVec4::new(self.z, self.z, self.y, self.w) } + #[inline] - fn wwzx(self) -> UVec4 { - UVec4::new(self.w, self.w, self.z, self.x) + fn zzzx(self) -> UVec4 { + UVec4::new(self.z, self.z, self.z, self.x) } + #[inline] - fn wwzy(self) -> UVec4 { - UVec4::new(self.w, self.w, self.z, self.y) + fn zzzy(self) -> UVec4 { + UVec4::new(self.z, self.z, self.z, self.y) } + #[inline] - fn wwzz(self) -> UVec4 { - UVec4::new(self.w, self.w, self.z, self.z) + fn zzzz(self) -> UVec4 { + UVec4::new(self.z, self.z, self.z, self.z) } + #[inline] - fn wwzw(self) -> UVec4 { - UVec4::new(self.w, self.w, self.z, self.w) + fn zzzw(self) -> UVec4 { + UVec4::new(self.z, self.z, self.z, self.w) } + #[inline] - fn wwwx(self) -> UVec4 { - UVec4::new(self.w, self.w, self.w, self.x) + fn zzwx(self) -> UVec4 { + UVec4::new(self.z, self.z, self.w, self.x) } + #[inline] - fn wwwy(self) -> UVec4 { - UVec4::new(self.w, self.w, self.w, self.y) + fn zzwy(self) -> UVec4 { + UVec4::new(self.z, self.z, self.w, self.y) } + #[inline] - fn wwwz(self) -> UVec4 { - UVec4::new(self.w, self.w, self.w, self.z) + fn zzwz(self) -> UVec4 { + UVec4::new(self.z, self.z, self.w, self.z) } + #[inline] - fn wwww(self) -> UVec4 { - UVec4::new(self.w, self.w, self.w, self.w) + fn zzww(self) -> UVec4 { + UVec4::new(self.z, self.z, self.w, self.w) } + #[inline] - fn xxx(self) -> UVec3 { - UVec3::new(self.x, self.x, self.x) + fn zwxx(self) -> UVec4 { + UVec4::new(self.z, self.w, self.x, self.x) } + #[inline] - fn xxy(self) -> UVec3 { - UVec3::new(self.x, self.x, self.y) + fn zwxy(self) -> UVec4 { + UVec4::new(self.z, self.w, self.x, self.y) } + #[inline] - fn xxz(self) -> UVec3 { - UVec3::new(self.x, self.x, self.z) + fn zwxz(self) -> UVec4 { + UVec4::new(self.z, self.w, self.x, self.z) } + #[inline] - fn xxw(self) -> UVec3 { - UVec3::new(self.x, self.x, self.w) + fn zwxw(self) -> UVec4 { + UVec4::new(self.z, self.w, self.x, self.w) } + #[inline] - fn xyx(self) -> UVec3 { - UVec3::new(self.x, self.y, self.x) + fn zwyx(self) -> UVec4 { + UVec4::new(self.z, self.w, self.y, self.x) } + #[inline] - fn xyy(self) -> UVec3 { - UVec3::new(self.x, self.y, self.y) + fn zwyy(self) -> UVec4 { + UVec4::new(self.z, self.w, self.y, self.y) } + #[inline] - fn xyz(self) -> UVec3 { - UVec3::new(self.x, self.y, self.z) + fn zwyz(self) -> UVec4 { + UVec4::new(self.z, self.w, self.y, self.z) } + #[inline] - fn xyw(self) -> UVec3 { - UVec3::new(self.x, self.y, self.w) + fn zwyw(self) -> UVec4 { + UVec4::new(self.z, self.w, self.y, self.w) } + #[inline] - fn xzx(self) -> UVec3 { - UVec3::new(self.x, self.z, self.x) + fn zwzx(self) -> UVec4 { + UVec4::new(self.z, self.w, self.z, self.x) } + #[inline] - fn xzy(self) -> UVec3 { - UVec3::new(self.x, self.z, self.y) + fn zwzy(self) -> UVec4 { + UVec4::new(self.z, self.w, self.z, self.y) } + #[inline] - fn xzz(self) -> UVec3 { - UVec3::new(self.x, self.z, self.z) + fn zwzz(self) -> UVec4 { + UVec4::new(self.z, self.w, self.z, self.z) } + #[inline] - fn xzw(self) -> UVec3 { - UVec3::new(self.x, self.z, self.w) + fn zwzw(self) -> UVec4 { + UVec4::new(self.z, self.w, self.z, self.w) } + #[inline] - fn xwx(self) -> UVec3 { - UVec3::new(self.x, self.w, self.x) + fn zwwx(self) -> UVec4 { + UVec4::new(self.z, self.w, self.w, self.x) } + #[inline] - fn xwy(self) -> UVec3 { - UVec3::new(self.x, self.w, self.y) + fn zwwy(self) -> UVec4 { + UVec4::new(self.z, self.w, self.w, self.y) } + #[inline] - fn xwz(self) -> UVec3 { - UVec3::new(self.x, self.w, self.z) + fn zwwz(self) -> UVec4 { + UVec4::new(self.z, self.w, self.w, self.z) } + #[inline] - fn xww(self) -> UVec3 { - UVec3::new(self.x, self.w, self.w) + fn zwww(self) -> UVec4 { + UVec4::new(self.z, self.w, self.w, self.w) } + #[inline] - fn yxx(self) -> UVec3 { - UVec3::new(self.y, self.x, self.x) + fn wxxx(self) -> UVec4 { + UVec4::new(self.w, self.x, self.x, self.x) } + #[inline] - fn yxy(self) -> UVec3 { - UVec3::new(self.y, self.x, self.y) + fn wxxy(self) -> UVec4 { + UVec4::new(self.w, self.x, self.x, self.y) } + #[inline] - fn yxz(self) -> UVec3 { - UVec3::new(self.y, self.x, self.z) + fn wxxz(self) -> UVec4 { + UVec4::new(self.w, self.x, self.x, self.z) } + #[inline] - fn yxw(self) -> UVec3 { - UVec3::new(self.y, self.x, self.w) + fn wxxw(self) -> UVec4 { + UVec4::new(self.w, self.x, self.x, self.w) } + #[inline] - fn yyx(self) -> UVec3 { - UVec3::new(self.y, self.y, self.x) + fn wxyx(self) -> UVec4 { + UVec4::new(self.w, self.x, self.y, self.x) } + #[inline] - fn yyy(self) -> UVec3 { - UVec3::new(self.y, self.y, self.y) + fn wxyy(self) -> UVec4 { + UVec4::new(self.w, self.x, self.y, self.y) } + #[inline] - fn yyz(self) -> UVec3 { - UVec3::new(self.y, self.y, self.z) + fn wxyz(self) -> UVec4 { + UVec4::new(self.w, self.x, self.y, self.z) } + #[inline] - fn yyw(self) -> UVec3 { - UVec3::new(self.y, self.y, self.w) + fn wxyw(self) -> UVec4 { + UVec4::new(self.w, self.x, self.y, self.w) } + #[inline] - fn yzx(self) -> UVec3 { - UVec3::new(self.y, self.z, self.x) + fn wxzx(self) -> UVec4 { + UVec4::new(self.w, self.x, self.z, self.x) } + #[inline] - fn yzy(self) -> UVec3 { - UVec3::new(self.y, self.z, self.y) + fn wxzy(self) -> UVec4 { + UVec4::new(self.w, self.x, self.z, self.y) } + #[inline] - fn yzz(self) -> UVec3 { - UVec3::new(self.y, self.z, self.z) + fn wxzz(self) -> UVec4 { + UVec4::new(self.w, self.x, self.z, self.z) } + #[inline] - fn yzw(self) -> UVec3 { - UVec3::new(self.y, self.z, self.w) + fn wxzw(self) -> UVec4 { + UVec4::new(self.w, self.x, self.z, self.w) } + #[inline] - fn ywx(self) -> UVec3 { - UVec3::new(self.y, self.w, self.x) + fn wxwx(self) -> UVec4 { + UVec4::new(self.w, self.x, self.w, self.x) } + #[inline] - fn ywy(self) -> UVec3 { - UVec3::new(self.y, self.w, self.y) + fn wxwy(self) -> UVec4 { + UVec4::new(self.w, self.x, self.w, self.y) } + #[inline] - fn ywz(self) -> UVec3 { - UVec3::new(self.y, self.w, self.z) + fn wxwz(self) -> UVec4 { + UVec4::new(self.w, self.x, self.w, self.z) } + #[inline] - fn yww(self) -> UVec3 { - UVec3::new(self.y, self.w, self.w) + fn wxww(self) -> UVec4 { + UVec4::new(self.w, self.x, self.w, self.w) } + #[inline] - fn zxx(self) -> UVec3 { - UVec3::new(self.z, self.x, self.x) + fn wyxx(self) -> UVec4 { + UVec4::new(self.w, self.y, self.x, self.x) } + #[inline] - fn zxy(self) -> UVec3 { - UVec3::new(self.z, self.x, self.y) + fn wyxy(self) -> UVec4 { + UVec4::new(self.w, self.y, self.x, self.y) } + #[inline] - fn zxz(self) -> UVec3 { - UVec3::new(self.z, self.x, self.z) + fn wyxz(self) -> UVec4 { + UVec4::new(self.w, self.y, self.x, self.z) } + #[inline] - fn zxw(self) -> UVec3 { - UVec3::new(self.z, self.x, self.w) + fn wyxw(self) -> UVec4 { + UVec4::new(self.w, self.y, self.x, self.w) } + #[inline] - fn zyx(self) -> UVec3 { - UVec3::new(self.z, self.y, self.x) + fn wyyx(self) -> UVec4 { + UVec4::new(self.w, self.y, self.y, self.x) } + #[inline] - fn zyy(self) -> UVec3 { - UVec3::new(self.z, self.y, self.y) + fn wyyy(self) -> UVec4 { + UVec4::new(self.w, self.y, self.y, self.y) } + #[inline] - fn zyz(self) -> UVec3 { - UVec3::new(self.z, self.y, self.z) + fn wyyz(self) -> UVec4 { + UVec4::new(self.w, self.y, self.y, self.z) } + #[inline] - fn zyw(self) -> UVec3 { - UVec3::new(self.z, self.y, self.w) + fn wyyw(self) -> UVec4 { + UVec4::new(self.w, self.y, self.y, self.w) } + #[inline] - fn zzx(self) -> UVec3 { - UVec3::new(self.z, self.z, self.x) + fn wyzx(self) -> UVec4 { + UVec4::new(self.w, self.y, self.z, self.x) } + #[inline] - fn zzy(self) -> UVec3 { - UVec3::new(self.z, self.z, self.y) + fn wyzy(self) -> UVec4 { + UVec4::new(self.w, self.y, self.z, self.y) } + #[inline] - fn zzz(self) -> UVec3 { - UVec3::new(self.z, self.z, self.z) + fn wyzz(self) -> UVec4 { + UVec4::new(self.w, self.y, self.z, self.z) } + #[inline] - fn zzw(self) -> UVec3 { - UVec3::new(self.z, self.z, self.w) + fn wyzw(self) -> UVec4 { + UVec4::new(self.w, self.y, self.z, self.w) } + #[inline] - fn zwx(self) -> UVec3 { - UVec3::new(self.z, self.w, self.x) + fn wywx(self) -> UVec4 { + UVec4::new(self.w, self.y, self.w, self.x) } + #[inline] - fn zwy(self) -> UVec3 { - UVec3::new(self.z, self.w, self.y) + fn wywy(self) -> UVec4 { + UVec4::new(self.w, self.y, self.w, self.y) } + #[inline] - fn zwz(self) -> UVec3 { - UVec3::new(self.z, self.w, self.z) + fn wywz(self) -> UVec4 { + UVec4::new(self.w, self.y, self.w, self.z) } + #[inline] - fn zww(self) -> UVec3 { - UVec3::new(self.z, self.w, self.w) + fn wyww(self) -> UVec4 { + UVec4::new(self.w, self.y, self.w, self.w) } + #[inline] - fn wxx(self) -> UVec3 { - UVec3::new(self.w, self.x, self.x) + fn wzxx(self) -> UVec4 { + UVec4::new(self.w, self.z, self.x, self.x) } + #[inline] - fn wxy(self) -> UVec3 { - UVec3::new(self.w, self.x, self.y) + fn wzxy(self) -> UVec4 { + UVec4::new(self.w, self.z, self.x, self.y) } + #[inline] - fn wxz(self) -> UVec3 { - UVec3::new(self.w, self.x, self.z) + fn wzxz(self) -> UVec4 { + UVec4::new(self.w, self.z, self.x, self.z) } + #[inline] - fn wxw(self) -> UVec3 { - UVec3::new(self.w, self.x, self.w) + fn wzxw(self) -> UVec4 { + UVec4::new(self.w, self.z, self.x, self.w) } + #[inline] - fn wyx(self) -> UVec3 { - UVec3::new(self.w, self.y, self.x) + fn wzyx(self) -> UVec4 { + UVec4::new(self.w, self.z, self.y, self.x) } + #[inline] - fn wyy(self) -> UVec3 { - UVec3::new(self.w, self.y, self.y) + fn wzyy(self) -> UVec4 { + UVec4::new(self.w, self.z, self.y, self.y) } + #[inline] - fn wyz(self) -> UVec3 { - UVec3::new(self.w, self.y, self.z) + fn wzyz(self) -> UVec4 { + UVec4::new(self.w, self.z, self.y, self.z) } + #[inline] - fn wyw(self) -> UVec3 { - UVec3::new(self.w, self.y, self.w) + fn wzyw(self) -> UVec4 { + UVec4::new(self.w, self.z, self.y, self.w) } + #[inline] - fn wzx(self) -> UVec3 { - UVec3::new(self.w, self.z, self.x) + fn wzzx(self) -> UVec4 { + UVec4::new(self.w, self.z, self.z, self.x) } + #[inline] - fn wzy(self) -> UVec3 { - UVec3::new(self.w, self.z, self.y) + fn wzzy(self) -> UVec4 { + UVec4::new(self.w, self.z, self.z, self.y) } + #[inline] - fn wzz(self) -> UVec3 { - UVec3::new(self.w, self.z, self.z) + fn wzzz(self) -> UVec4 { + UVec4::new(self.w, self.z, self.z, self.z) } + #[inline] - fn wzw(self) -> UVec3 { - UVec3::new(self.w, self.z, self.w) + fn wzzw(self) -> UVec4 { + UVec4::new(self.w, self.z, self.z, self.w) } + #[inline] - fn wwx(self) -> UVec3 { - UVec3::new(self.w, self.w, self.x) + fn wzwx(self) -> UVec4 { + UVec4::new(self.w, self.z, self.w, self.x) } + #[inline] - fn wwy(self) -> UVec3 { - UVec3::new(self.w, self.w, self.y) + fn wzwy(self) -> UVec4 { + UVec4::new(self.w, self.z, self.w, self.y) } + #[inline] - fn wwz(self) -> UVec3 { - UVec3::new(self.w, self.w, self.z) + fn wzwz(self) -> UVec4 { + UVec4::new(self.w, self.z, self.w, self.z) } + #[inline] - fn www(self) -> UVec3 { - UVec3::new(self.w, self.w, self.w) + fn wzww(self) -> UVec4 { + UVec4::new(self.w, self.z, self.w, self.w) } + #[inline] - fn xx(self) -> UVec2 { - UVec2::new(self.x, self.x) + fn wwxx(self) -> UVec4 { + UVec4::new(self.w, self.w, self.x, self.x) } + #[inline] - fn xy(self) -> UVec2 { - UVec2::new(self.x, self.y) + fn wwxy(self) -> UVec4 { + UVec4::new(self.w, self.w, self.x, self.y) } + #[inline] - fn xz(self) -> UVec2 { - UVec2::new(self.x, self.z) + fn wwxz(self) -> UVec4 { + UVec4::new(self.w, self.w, self.x, self.z) } + #[inline] - fn xw(self) -> UVec2 { - UVec2::new(self.x, self.w) + fn wwxw(self) -> UVec4 { + UVec4::new(self.w, self.w, self.x, self.w) } + #[inline] - fn yx(self) -> UVec2 { - UVec2::new(self.y, self.x) + fn wwyx(self) -> UVec4 { + UVec4::new(self.w, self.w, self.y, self.x) } + #[inline] - fn yy(self) -> UVec2 { - UVec2::new(self.y, self.y) + fn wwyy(self) -> UVec4 { + UVec4::new(self.w, self.w, self.y, self.y) } + #[inline] - fn yz(self) -> UVec2 { - UVec2::new(self.y, self.z) + fn wwyz(self) -> UVec4 { + UVec4::new(self.w, self.w, self.y, self.z) } + #[inline] - fn yw(self) -> UVec2 { - UVec2::new(self.y, self.w) + fn wwyw(self) -> UVec4 { + UVec4::new(self.w, self.w, self.y, self.w) } + #[inline] - fn zx(self) -> UVec2 { - UVec2::new(self.z, self.x) + fn wwzx(self) -> UVec4 { + UVec4::new(self.w, self.w, self.z, self.x) } + #[inline] - fn zy(self) -> UVec2 { - UVec2::new(self.z, self.y) + fn wwzy(self) -> UVec4 { + UVec4::new(self.w, self.w, self.z, self.y) } + #[inline] - fn zz(self) -> UVec2 { - UVec2::new(self.z, self.z) + fn wwzz(self) -> UVec4 { + UVec4::new(self.w, self.w, self.z, self.z) } + #[inline] - fn zw(self) -> UVec2 { - UVec2::new(self.z, self.w) + fn wwzw(self) -> UVec4 { + UVec4::new(self.w, self.w, self.z, self.w) } + #[inline] - fn wx(self) -> UVec2 { - UVec2::new(self.w, self.x) + fn wwwx(self) -> UVec4 { + UVec4::new(self.w, self.w, self.w, self.x) } + #[inline] - fn wy(self) -> UVec2 { - UVec2::new(self.w, self.y) + fn wwwy(self) -> UVec4 { + UVec4::new(self.w, self.w, self.w, self.y) } + #[inline] - fn wz(self) -> UVec2 { - UVec2::new(self.w, self.z) + fn wwwz(self) -> UVec4 { + UVec4::new(self.w, self.w, self.w, self.z) } + #[inline] - fn ww(self) -> UVec2 { - UVec2::new(self.w, self.w) + fn wwww(self) -> UVec4 { + UVec4::new(self.w, self.w, self.w, self.w) } } diff --git a/src/swizzles/vec2_impl_scalar.rs b/src/swizzles/vec2_impl_scalar.rs index 9968553e..0260933b 100644 --- a/src/swizzles/vec2_impl_scalar.rs +++ b/src/swizzles/vec2_impl_scalar.rs @@ -1,118 +1,196 @@ -// Generated by swizzlegen. Do not edit. +// Generated from swizzle_impl.rs template. Edit the template, not the generated file. + +#![allow(clippy::useless_conversion)] use super::Vec2Swizzles; use crate::{Vec2, Vec3, Vec4}; impl Vec2Swizzles for Vec2 { type Vec3 = Vec3; + type Vec4 = Vec4; + #[inline] + fn xx(self) -> Vec2 { + Vec2 { + x: self.x, + y: self.x, + } + } + + #[inline] + fn xy(self) -> Vec2 { + Vec2 { + x: self.x, + y: self.y, + } + } + + #[inline] + fn yx(self) -> Vec2 { + Vec2 { + x: self.y, + y: self.x, + } + } + + #[inline] + fn yy(self) -> Vec2 { + Vec2 { + x: self.y, + y: self.y, + } + } + + #[inline] + fn xxx(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.x, + z: self.x, + } + } + + #[inline] + fn xxy(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.x, + z: self.y, + } + } + + #[inline] + fn xyx(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.y, + z: self.x, + } + } + + #[inline] + fn xyy(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.y, + z: self.y, + } + } + + #[inline] + fn yxx(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.x, + z: self.x, + } + } + + #[inline] + fn yxy(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.x, + z: self.y, + } + } + + #[inline] + fn yyx(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.y, + z: self.x, + } + } + + #[inline] + fn yyy(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.y, + z: self.y, + } + } + #[inline] fn xxxx(self) -> Vec4 { Vec4::new(self.x, self.x, self.x, self.x) } + #[inline] fn xxxy(self) -> Vec4 { Vec4::new(self.x, self.x, self.x, self.y) } + #[inline] fn xxyx(self) -> Vec4 { Vec4::new(self.x, self.x, self.y, self.x) } + #[inline] fn xxyy(self) -> Vec4 { Vec4::new(self.x, self.x, self.y, self.y) } + #[inline] fn xyxx(self) -> Vec4 { Vec4::new(self.x, self.y, self.x, self.x) } + #[inline] fn xyxy(self) -> Vec4 { Vec4::new(self.x, self.y, self.x, self.y) } + #[inline] fn xyyx(self) -> Vec4 { Vec4::new(self.x, self.y, self.y, self.x) } + #[inline] fn xyyy(self) -> Vec4 { Vec4::new(self.x, self.y, self.y, self.y) } + #[inline] fn yxxx(self) -> Vec4 { Vec4::new(self.y, self.x, self.x, self.x) } + #[inline] fn yxxy(self) -> Vec4 { Vec4::new(self.y, self.x, self.x, self.y) } + #[inline] fn yxyx(self) -> Vec4 { Vec4::new(self.y, self.x, self.y, self.x) } + #[inline] fn yxyy(self) -> Vec4 { Vec4::new(self.y, self.x, self.y, self.y) } + #[inline] fn yyxx(self) -> Vec4 { Vec4::new(self.y, self.y, self.x, self.x) } + #[inline] fn yyxy(self) -> Vec4 { Vec4::new(self.y, self.y, self.x, self.y) } + #[inline] fn yyyx(self) -> Vec4 { Vec4::new(self.y, self.y, self.y, self.x) } + #[inline] fn yyyy(self) -> Vec4 { Vec4::new(self.y, self.y, self.y, self.y) } - #[inline] - fn xxx(self) -> Vec3 { - Vec3::new(self.x, self.x, self.x) - } - #[inline] - fn xxy(self) -> Vec3 { - Vec3::new(self.x, self.x, self.y) - } - #[inline] - fn xyx(self) -> Vec3 { - Vec3::new(self.x, self.y, self.x) - } - #[inline] - fn xyy(self) -> Vec3 { - Vec3::new(self.x, self.y, self.y) - } - #[inline] - fn yxx(self) -> Vec3 { - Vec3::new(self.y, self.x, self.x) - } - #[inline] - fn yxy(self) -> Vec3 { - Vec3::new(self.y, self.x, self.y) - } - #[inline] - fn yyx(self) -> Vec3 { - Vec3::new(self.y, self.y, self.x) - } - #[inline] - fn yyy(self) -> Vec3 { - Vec3::new(self.y, self.y, self.y) - } - #[inline] - fn xx(self) -> Self { - Self::new(self.x, self.x) - } - #[inline] - fn yx(self) -> Self { - Self::new(self.y, self.x) - } - #[inline] - fn yy(self) -> Self { - Self::new(self.y, self.y) - } } diff --git a/src/swizzles/vec3_impl_scalar.rs b/src/swizzles/vec3_impl_scalar.rs index 83d7418f..75f29b86 100644 --- a/src/swizzles/vec3_impl_scalar.rs +++ b/src/swizzles/vec3_impl_scalar.rs @@ -1,474 +1,732 @@ -// Generated by swizzlegen. Do not edit. +// Generated from swizzle_impl.rs template. Edit the template, not the generated file. + +#![allow(clippy::useless_conversion)] use super::Vec3Swizzles; use crate::{Vec2, Vec3, Vec4}; impl Vec3Swizzles for Vec3 { type Vec2 = Vec2; + type Vec4 = Vec4; + #[inline] + fn xx(self) -> Vec2 { + Vec2 { + x: self.x, + y: self.x, + } + } + + #[inline] + fn xy(self) -> Vec2 { + Vec2 { + x: self.x, + y: self.y, + } + } + + #[inline] + fn xz(self) -> Vec2 { + Vec2 { + x: self.x, + y: self.z, + } + } + + #[inline] + fn yx(self) -> Vec2 { + Vec2 { + x: self.y, + y: self.x, + } + } + + #[inline] + fn yy(self) -> Vec2 { + Vec2 { + x: self.y, + y: self.y, + } + } + + #[inline] + fn yz(self) -> Vec2 { + Vec2 { + x: self.y, + y: self.z, + } + } + + #[inline] + fn zx(self) -> Vec2 { + Vec2 { + x: self.z, + y: self.x, + } + } + + #[inline] + fn zy(self) -> Vec2 { + Vec2 { + x: self.z, + y: self.y, + } + } + + #[inline] + fn zz(self) -> Vec2 { + Vec2 { + x: self.z, + y: self.z, + } + } + + #[inline] + fn xxx(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.x, + z: self.x, + } + } + + #[inline] + fn xxy(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.x, + z: self.y, + } + } + + #[inline] + fn xxz(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.x, + z: self.z, + } + } + + #[inline] + fn xyx(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.y, + z: self.x, + } + } + + #[inline] + fn xyy(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.y, + z: self.y, + } + } + + #[inline] + fn xyz(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.y, + z: self.z, + } + } + + #[inline] + fn xzx(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.z, + z: self.x, + } + } + + #[inline] + fn xzy(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.z, + z: self.y, + } + } + + #[inline] + fn xzz(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.z, + z: self.z, + } + } + + #[inline] + fn yxx(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.x, + z: self.x, + } + } + + #[inline] + fn yxy(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.x, + z: self.y, + } + } + + #[inline] + fn yxz(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.x, + z: self.z, + } + } + + #[inline] + fn yyx(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.y, + z: self.x, + } + } + + #[inline] + fn yyy(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.y, + z: self.y, + } + } + + #[inline] + fn yyz(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.y, + z: self.z, + } + } + + #[inline] + fn yzx(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.z, + z: self.x, + } + } + + #[inline] + fn yzy(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.z, + z: self.y, + } + } + + #[inline] + fn yzz(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.z, + z: self.z, + } + } + + #[inline] + fn zxx(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.x, + z: self.x, + } + } + + #[inline] + fn zxy(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.x, + z: self.y, + } + } + + #[inline] + fn zxz(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.x, + z: self.z, + } + } + + #[inline] + fn zyx(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.y, + z: self.x, + } + } + + #[inline] + fn zyy(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.y, + z: self.y, + } + } + + #[inline] + fn zyz(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.y, + z: self.z, + } + } + + #[inline] + fn zzx(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.z, + z: self.x, + } + } + + #[inline] + fn zzy(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.z, + z: self.y, + } + } + + #[inline] + fn zzz(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.z, + z: self.z, + } + } + #[inline] fn xxxx(self) -> Vec4 { Vec4::new(self.x, self.x, self.x, self.x) } + #[inline] fn xxxy(self) -> Vec4 { Vec4::new(self.x, self.x, self.x, self.y) } + #[inline] fn xxxz(self) -> Vec4 { Vec4::new(self.x, self.x, self.x, self.z) } + #[inline] fn xxyx(self) -> Vec4 { Vec4::new(self.x, self.x, self.y, self.x) } + #[inline] fn xxyy(self) -> Vec4 { Vec4::new(self.x, self.x, self.y, self.y) } + #[inline] fn xxyz(self) -> Vec4 { Vec4::new(self.x, self.x, self.y, self.z) } + #[inline] fn xxzx(self) -> Vec4 { Vec4::new(self.x, self.x, self.z, self.x) } + #[inline] fn xxzy(self) -> Vec4 { Vec4::new(self.x, self.x, self.z, self.y) } + #[inline] fn xxzz(self) -> Vec4 { Vec4::new(self.x, self.x, self.z, self.z) } + #[inline] fn xyxx(self) -> Vec4 { Vec4::new(self.x, self.y, self.x, self.x) } + #[inline] fn xyxy(self) -> Vec4 { Vec4::new(self.x, self.y, self.x, self.y) } + #[inline] fn xyxz(self) -> Vec4 { Vec4::new(self.x, self.y, self.x, self.z) } + #[inline] fn xyyx(self) -> Vec4 { Vec4::new(self.x, self.y, self.y, self.x) } + #[inline] fn xyyy(self) -> Vec4 { Vec4::new(self.x, self.y, self.y, self.y) } + #[inline] fn xyyz(self) -> Vec4 { Vec4::new(self.x, self.y, self.y, self.z) } + #[inline] fn xyzx(self) -> Vec4 { Vec4::new(self.x, self.y, self.z, self.x) } + #[inline] fn xyzy(self) -> Vec4 { Vec4::new(self.x, self.y, self.z, self.y) } + #[inline] fn xyzz(self) -> Vec4 { Vec4::new(self.x, self.y, self.z, self.z) } + #[inline] fn xzxx(self) -> Vec4 { Vec4::new(self.x, self.z, self.x, self.x) } + #[inline] fn xzxy(self) -> Vec4 { Vec4::new(self.x, self.z, self.x, self.y) } + #[inline] fn xzxz(self) -> Vec4 { Vec4::new(self.x, self.z, self.x, self.z) } + #[inline] fn xzyx(self) -> Vec4 { Vec4::new(self.x, self.z, self.y, self.x) } + #[inline] fn xzyy(self) -> Vec4 { Vec4::new(self.x, self.z, self.y, self.y) } + #[inline] fn xzyz(self) -> Vec4 { Vec4::new(self.x, self.z, self.y, self.z) } + #[inline] fn xzzx(self) -> Vec4 { Vec4::new(self.x, self.z, self.z, self.x) } + #[inline] fn xzzy(self) -> Vec4 { Vec4::new(self.x, self.z, self.z, self.y) } + #[inline] fn xzzz(self) -> Vec4 { Vec4::new(self.x, self.z, self.z, self.z) } + #[inline] fn yxxx(self) -> Vec4 { Vec4::new(self.y, self.x, self.x, self.x) } + #[inline] fn yxxy(self) -> Vec4 { Vec4::new(self.y, self.x, self.x, self.y) } + #[inline] fn yxxz(self) -> Vec4 { Vec4::new(self.y, self.x, self.x, self.z) } + #[inline] fn yxyx(self) -> Vec4 { Vec4::new(self.y, self.x, self.y, self.x) } + #[inline] fn yxyy(self) -> Vec4 { Vec4::new(self.y, self.x, self.y, self.y) } + #[inline] fn yxyz(self) -> Vec4 { Vec4::new(self.y, self.x, self.y, self.z) } + #[inline] fn yxzx(self) -> Vec4 { Vec4::new(self.y, self.x, self.z, self.x) } + #[inline] fn yxzy(self) -> Vec4 { Vec4::new(self.y, self.x, self.z, self.y) } + #[inline] fn yxzz(self) -> Vec4 { Vec4::new(self.y, self.x, self.z, self.z) } + #[inline] fn yyxx(self) -> Vec4 { Vec4::new(self.y, self.y, self.x, self.x) } + #[inline] fn yyxy(self) -> Vec4 { Vec4::new(self.y, self.y, self.x, self.y) } + #[inline] fn yyxz(self) -> Vec4 { Vec4::new(self.y, self.y, self.x, self.z) } + #[inline] fn yyyx(self) -> Vec4 { Vec4::new(self.y, self.y, self.y, self.x) } + #[inline] fn yyyy(self) -> Vec4 { Vec4::new(self.y, self.y, self.y, self.y) } + #[inline] fn yyyz(self) -> Vec4 { Vec4::new(self.y, self.y, self.y, self.z) } + #[inline] fn yyzx(self) -> Vec4 { Vec4::new(self.y, self.y, self.z, self.x) } + #[inline] fn yyzy(self) -> Vec4 { Vec4::new(self.y, self.y, self.z, self.y) } + #[inline] fn yyzz(self) -> Vec4 { Vec4::new(self.y, self.y, self.z, self.z) } + #[inline] fn yzxx(self) -> Vec4 { Vec4::new(self.y, self.z, self.x, self.x) } + #[inline] fn yzxy(self) -> Vec4 { Vec4::new(self.y, self.z, self.x, self.y) } + #[inline] fn yzxz(self) -> Vec4 { Vec4::new(self.y, self.z, self.x, self.z) } + #[inline] fn yzyx(self) -> Vec4 { Vec4::new(self.y, self.z, self.y, self.x) } + #[inline] fn yzyy(self) -> Vec4 { Vec4::new(self.y, self.z, self.y, self.y) } + #[inline] fn yzyz(self) -> Vec4 { Vec4::new(self.y, self.z, self.y, self.z) } + #[inline] fn yzzx(self) -> Vec4 { Vec4::new(self.y, self.z, self.z, self.x) } + #[inline] fn yzzy(self) -> Vec4 { Vec4::new(self.y, self.z, self.z, self.y) } + #[inline] fn yzzz(self) -> Vec4 { Vec4::new(self.y, self.z, self.z, self.z) } + #[inline] fn zxxx(self) -> Vec4 { Vec4::new(self.z, self.x, self.x, self.x) } + #[inline] fn zxxy(self) -> Vec4 { Vec4::new(self.z, self.x, self.x, self.y) } + #[inline] fn zxxz(self) -> Vec4 { Vec4::new(self.z, self.x, self.x, self.z) } + #[inline] fn zxyx(self) -> Vec4 { Vec4::new(self.z, self.x, self.y, self.x) } + #[inline] fn zxyy(self) -> Vec4 { Vec4::new(self.z, self.x, self.y, self.y) } + #[inline] fn zxyz(self) -> Vec4 { Vec4::new(self.z, self.x, self.y, self.z) } + #[inline] fn zxzx(self) -> Vec4 { Vec4::new(self.z, self.x, self.z, self.x) } + #[inline] fn zxzy(self) -> Vec4 { Vec4::new(self.z, self.x, self.z, self.y) } + #[inline] fn zxzz(self) -> Vec4 { Vec4::new(self.z, self.x, self.z, self.z) } + #[inline] fn zyxx(self) -> Vec4 { Vec4::new(self.z, self.y, self.x, self.x) } + #[inline] fn zyxy(self) -> Vec4 { Vec4::new(self.z, self.y, self.x, self.y) } + #[inline] fn zyxz(self) -> Vec4 { Vec4::new(self.z, self.y, self.x, self.z) } + #[inline] fn zyyx(self) -> Vec4 { Vec4::new(self.z, self.y, self.y, self.x) } + #[inline] fn zyyy(self) -> Vec4 { Vec4::new(self.z, self.y, self.y, self.y) } + #[inline] fn zyyz(self) -> Vec4 { Vec4::new(self.z, self.y, self.y, self.z) } + #[inline] fn zyzx(self) -> Vec4 { Vec4::new(self.z, self.y, self.z, self.x) } + #[inline] fn zyzy(self) -> Vec4 { Vec4::new(self.z, self.y, self.z, self.y) } + #[inline] fn zyzz(self) -> Vec4 { Vec4::new(self.z, self.y, self.z, self.z) } + #[inline] fn zzxx(self) -> Vec4 { Vec4::new(self.z, self.z, self.x, self.x) } + #[inline] fn zzxy(self) -> Vec4 { Vec4::new(self.z, self.z, self.x, self.y) } + #[inline] fn zzxz(self) -> Vec4 { Vec4::new(self.z, self.z, self.x, self.z) } + #[inline] fn zzyx(self) -> Vec4 { Vec4::new(self.z, self.z, self.y, self.x) } + #[inline] fn zzyy(self) -> Vec4 { Vec4::new(self.z, self.z, self.y, self.y) } + #[inline] fn zzyz(self) -> Vec4 { Vec4::new(self.z, self.z, self.y, self.z) } + #[inline] fn zzzx(self) -> Vec4 { Vec4::new(self.z, self.z, self.z, self.x) } + #[inline] fn zzzy(self) -> Vec4 { Vec4::new(self.z, self.z, self.z, self.y) } + #[inline] fn zzzz(self) -> Vec4 { Vec4::new(self.z, self.z, self.z, self.z) } - #[inline] - fn xxx(self) -> Self { - Self::new(self.x, self.x, self.x) - } - #[inline] - fn xxy(self) -> Self { - Self::new(self.x, self.x, self.y) - } - #[inline] - fn xxz(self) -> Self { - Self::new(self.x, self.x, self.z) - } - #[inline] - fn xyx(self) -> Self { - Self::new(self.x, self.y, self.x) - } - #[inline] - fn xyy(self) -> Self { - Self::new(self.x, self.y, self.y) - } - #[inline] - fn xzx(self) -> Self { - Self::new(self.x, self.z, self.x) - } - #[inline] - fn xzy(self) -> Self { - Self::new(self.x, self.z, self.y) - } - #[inline] - fn xzz(self) -> Self { - Self::new(self.x, self.z, self.z) - } - #[inline] - fn yxx(self) -> Self { - Self::new(self.y, self.x, self.x) - } - #[inline] - fn yxy(self) -> Self { - Self::new(self.y, self.x, self.y) - } - #[inline] - fn yxz(self) -> Self { - Self::new(self.y, self.x, self.z) - } - #[inline] - fn yyx(self) -> Self { - Self::new(self.y, self.y, self.x) - } - #[inline] - fn yyy(self) -> Self { - Self::new(self.y, self.y, self.y) - } - #[inline] - fn yyz(self) -> Self { - Self::new(self.y, self.y, self.z) - } - #[inline] - fn yzx(self) -> Self { - Self::new(self.y, self.z, self.x) - } - #[inline] - fn yzy(self) -> Self { - Self::new(self.y, self.z, self.y) - } - #[inline] - fn yzz(self) -> Self { - Self::new(self.y, self.z, self.z) - } - #[inline] - fn zxx(self) -> Self { - Self::new(self.z, self.x, self.x) - } - #[inline] - fn zxy(self) -> Self { - Self::new(self.z, self.x, self.y) - } - #[inline] - fn zxz(self) -> Self { - Self::new(self.z, self.x, self.z) - } - #[inline] - fn zyx(self) -> Self { - Self::new(self.z, self.y, self.x) - } - #[inline] - fn zyy(self) -> Self { - Self::new(self.z, self.y, self.y) - } - #[inline] - fn zyz(self) -> Self { - Self::new(self.z, self.y, self.z) - } - #[inline] - fn zzx(self) -> Self { - Self::new(self.z, self.z, self.x) - } - #[inline] - fn zzy(self) -> Self { - Self::new(self.z, self.z, self.y) - } - #[inline] - fn zzz(self) -> Self { - Self::new(self.z, self.z, self.z) - } - #[inline] - fn xx(self) -> Vec2 { - Vec2::new(self.x, self.x) - } - #[inline] - fn xy(self) -> Vec2 { - Vec2::new(self.x, self.y) - } - #[inline] - fn xz(self) -> Vec2 { - Vec2::new(self.x, self.z) - } - #[inline] - fn yx(self) -> Vec2 { - Vec2::new(self.y, self.x) - } - #[inline] - fn yy(self) -> Vec2 { - Vec2::new(self.y, self.y) - } - #[inline] - fn yz(self) -> Vec2 { - Vec2::new(self.y, self.z) - } - #[inline] - fn zx(self) -> Vec2 { - Vec2::new(self.z, self.x) - } - #[inline] - fn zy(self) -> Vec2 { - Vec2::new(self.z, self.y) - } - #[inline] - fn zz(self) -> Vec2 { - Vec2::new(self.z, self.z) - } } diff --git a/src/swizzles/vec3a_impl_scalar.rs b/src/swizzles/vec3a_impl_scalar.rs index a1aaac30..a8b8e3e0 100644 --- a/src/swizzles/vec3a_impl_scalar.rs +++ b/src/swizzles/vec3a_impl_scalar.rs @@ -1,474 +1,732 @@ -// Generated by swizzlegen. Do not edit. +// Generated from swizzle_impl.rs template. Edit the template, not the generated file. + +#![allow(clippy::useless_conversion)] use super::Vec3Swizzles; use crate::{Vec2, Vec3A, Vec4}; impl Vec3Swizzles for Vec3A { type Vec2 = Vec2; + type Vec4 = Vec4; + #[inline] + fn xx(self) -> Vec2 { + Vec2 { + x: self.x, + y: self.x, + } + } + + #[inline] + fn xy(self) -> Vec2 { + Vec2 { + x: self.x, + y: self.y, + } + } + + #[inline] + fn xz(self) -> Vec2 { + Vec2 { + x: self.x, + y: self.z, + } + } + + #[inline] + fn yx(self) -> Vec2 { + Vec2 { + x: self.y, + y: self.x, + } + } + + #[inline] + fn yy(self) -> Vec2 { + Vec2 { + x: self.y, + y: self.y, + } + } + + #[inline] + fn yz(self) -> Vec2 { + Vec2 { + x: self.y, + y: self.z, + } + } + + #[inline] + fn zx(self) -> Vec2 { + Vec2 { + x: self.z, + y: self.x, + } + } + + #[inline] + fn zy(self) -> Vec2 { + Vec2 { + x: self.z, + y: self.y, + } + } + + #[inline] + fn zz(self) -> Vec2 { + Vec2 { + x: self.z, + y: self.z, + } + } + + #[inline] + fn xxx(self) -> Vec3A { + Vec3A { + x: self.x, + y: self.x, + z: self.x, + } + } + + #[inline] + fn xxy(self) -> Vec3A { + Vec3A { + x: self.x, + y: self.x, + z: self.y, + } + } + + #[inline] + fn xxz(self) -> Vec3A { + Vec3A { + x: self.x, + y: self.x, + z: self.z, + } + } + + #[inline] + fn xyx(self) -> Vec3A { + Vec3A { + x: self.x, + y: self.y, + z: self.x, + } + } + + #[inline] + fn xyy(self) -> Vec3A { + Vec3A { + x: self.x, + y: self.y, + z: self.y, + } + } + + #[inline] + fn xyz(self) -> Vec3A { + Vec3A { + x: self.x, + y: self.y, + z: self.z, + } + } + + #[inline] + fn xzx(self) -> Vec3A { + Vec3A { + x: self.x, + y: self.z, + z: self.x, + } + } + + #[inline] + fn xzy(self) -> Vec3A { + Vec3A { + x: self.x, + y: self.z, + z: self.y, + } + } + + #[inline] + fn xzz(self) -> Vec3A { + Vec3A { + x: self.x, + y: self.z, + z: self.z, + } + } + + #[inline] + fn yxx(self) -> Vec3A { + Vec3A { + x: self.y, + y: self.x, + z: self.x, + } + } + + #[inline] + fn yxy(self) -> Vec3A { + Vec3A { + x: self.y, + y: self.x, + z: self.y, + } + } + + #[inline] + fn yxz(self) -> Vec3A { + Vec3A { + x: self.y, + y: self.x, + z: self.z, + } + } + + #[inline] + fn yyx(self) -> Vec3A { + Vec3A { + x: self.y, + y: self.y, + z: self.x, + } + } + + #[inline] + fn yyy(self) -> Vec3A { + Vec3A { + x: self.y, + y: self.y, + z: self.y, + } + } + + #[inline] + fn yyz(self) -> Vec3A { + Vec3A { + x: self.y, + y: self.y, + z: self.z, + } + } + + #[inline] + fn yzx(self) -> Vec3A { + Vec3A { + x: self.y, + y: self.z, + z: self.x, + } + } + + #[inline] + fn yzy(self) -> Vec3A { + Vec3A { + x: self.y, + y: self.z, + z: self.y, + } + } + + #[inline] + fn yzz(self) -> Vec3A { + Vec3A { + x: self.y, + y: self.z, + z: self.z, + } + } + + #[inline] + fn zxx(self) -> Vec3A { + Vec3A { + x: self.z, + y: self.x, + z: self.x, + } + } + + #[inline] + fn zxy(self) -> Vec3A { + Vec3A { + x: self.z, + y: self.x, + z: self.y, + } + } + + #[inline] + fn zxz(self) -> Vec3A { + Vec3A { + x: self.z, + y: self.x, + z: self.z, + } + } + + #[inline] + fn zyx(self) -> Vec3A { + Vec3A { + x: self.z, + y: self.y, + z: self.x, + } + } + + #[inline] + fn zyy(self) -> Vec3A { + Vec3A { + x: self.z, + y: self.y, + z: self.y, + } + } + + #[inline] + fn zyz(self) -> Vec3A { + Vec3A { + x: self.z, + y: self.y, + z: self.z, + } + } + + #[inline] + fn zzx(self) -> Vec3A { + Vec3A { + x: self.z, + y: self.z, + z: self.x, + } + } + + #[inline] + fn zzy(self) -> Vec3A { + Vec3A { + x: self.z, + y: self.z, + z: self.y, + } + } + + #[inline] + fn zzz(self) -> Vec3A { + Vec3A { + x: self.z, + y: self.z, + z: self.z, + } + } + #[inline] fn xxxx(self) -> Vec4 { Vec4::new(self.x, self.x, self.x, self.x) } + #[inline] fn xxxy(self) -> Vec4 { Vec4::new(self.x, self.x, self.x, self.y) } + #[inline] fn xxxz(self) -> Vec4 { Vec4::new(self.x, self.x, self.x, self.z) } + #[inline] fn xxyx(self) -> Vec4 { Vec4::new(self.x, self.x, self.y, self.x) } + #[inline] fn xxyy(self) -> Vec4 { Vec4::new(self.x, self.x, self.y, self.y) } + #[inline] fn xxyz(self) -> Vec4 { Vec4::new(self.x, self.x, self.y, self.z) } + #[inline] fn xxzx(self) -> Vec4 { Vec4::new(self.x, self.x, self.z, self.x) } + #[inline] fn xxzy(self) -> Vec4 { Vec4::new(self.x, self.x, self.z, self.y) } + #[inline] fn xxzz(self) -> Vec4 { Vec4::new(self.x, self.x, self.z, self.z) } + #[inline] fn xyxx(self) -> Vec4 { Vec4::new(self.x, self.y, self.x, self.x) } + #[inline] fn xyxy(self) -> Vec4 { Vec4::new(self.x, self.y, self.x, self.y) } + #[inline] fn xyxz(self) -> Vec4 { Vec4::new(self.x, self.y, self.x, self.z) } + #[inline] fn xyyx(self) -> Vec4 { Vec4::new(self.x, self.y, self.y, self.x) } + #[inline] fn xyyy(self) -> Vec4 { Vec4::new(self.x, self.y, self.y, self.y) } + #[inline] fn xyyz(self) -> Vec4 { Vec4::new(self.x, self.y, self.y, self.z) } + #[inline] fn xyzx(self) -> Vec4 { Vec4::new(self.x, self.y, self.z, self.x) } + #[inline] fn xyzy(self) -> Vec4 { Vec4::new(self.x, self.y, self.z, self.y) } + #[inline] fn xyzz(self) -> Vec4 { Vec4::new(self.x, self.y, self.z, self.z) } + #[inline] fn xzxx(self) -> Vec4 { Vec4::new(self.x, self.z, self.x, self.x) } + #[inline] fn xzxy(self) -> Vec4 { Vec4::new(self.x, self.z, self.x, self.y) } + #[inline] fn xzxz(self) -> Vec4 { Vec4::new(self.x, self.z, self.x, self.z) } + #[inline] fn xzyx(self) -> Vec4 { Vec4::new(self.x, self.z, self.y, self.x) } + #[inline] fn xzyy(self) -> Vec4 { Vec4::new(self.x, self.z, self.y, self.y) } + #[inline] fn xzyz(self) -> Vec4 { Vec4::new(self.x, self.z, self.y, self.z) } + #[inline] fn xzzx(self) -> Vec4 { Vec4::new(self.x, self.z, self.z, self.x) } + #[inline] fn xzzy(self) -> Vec4 { Vec4::new(self.x, self.z, self.z, self.y) } + #[inline] fn xzzz(self) -> Vec4 { Vec4::new(self.x, self.z, self.z, self.z) } + #[inline] fn yxxx(self) -> Vec4 { Vec4::new(self.y, self.x, self.x, self.x) } + #[inline] fn yxxy(self) -> Vec4 { Vec4::new(self.y, self.x, self.x, self.y) } + #[inline] fn yxxz(self) -> Vec4 { Vec4::new(self.y, self.x, self.x, self.z) } + #[inline] fn yxyx(self) -> Vec4 { Vec4::new(self.y, self.x, self.y, self.x) } + #[inline] fn yxyy(self) -> Vec4 { Vec4::new(self.y, self.x, self.y, self.y) } + #[inline] fn yxyz(self) -> Vec4 { Vec4::new(self.y, self.x, self.y, self.z) } + #[inline] fn yxzx(self) -> Vec4 { Vec4::new(self.y, self.x, self.z, self.x) } + #[inline] fn yxzy(self) -> Vec4 { Vec4::new(self.y, self.x, self.z, self.y) } + #[inline] fn yxzz(self) -> Vec4 { Vec4::new(self.y, self.x, self.z, self.z) } + #[inline] fn yyxx(self) -> Vec4 { Vec4::new(self.y, self.y, self.x, self.x) } + #[inline] fn yyxy(self) -> Vec4 { Vec4::new(self.y, self.y, self.x, self.y) } + #[inline] fn yyxz(self) -> Vec4 { Vec4::new(self.y, self.y, self.x, self.z) } + #[inline] fn yyyx(self) -> Vec4 { Vec4::new(self.y, self.y, self.y, self.x) } + #[inline] fn yyyy(self) -> Vec4 { Vec4::new(self.y, self.y, self.y, self.y) } + #[inline] fn yyyz(self) -> Vec4 { Vec4::new(self.y, self.y, self.y, self.z) } + #[inline] fn yyzx(self) -> Vec4 { Vec4::new(self.y, self.y, self.z, self.x) } + #[inline] fn yyzy(self) -> Vec4 { Vec4::new(self.y, self.y, self.z, self.y) } + #[inline] fn yyzz(self) -> Vec4 { Vec4::new(self.y, self.y, self.z, self.z) } + #[inline] fn yzxx(self) -> Vec4 { Vec4::new(self.y, self.z, self.x, self.x) } + #[inline] fn yzxy(self) -> Vec4 { Vec4::new(self.y, self.z, self.x, self.y) } + #[inline] fn yzxz(self) -> Vec4 { Vec4::new(self.y, self.z, self.x, self.z) } + #[inline] fn yzyx(self) -> Vec4 { Vec4::new(self.y, self.z, self.y, self.x) } + #[inline] fn yzyy(self) -> Vec4 { Vec4::new(self.y, self.z, self.y, self.y) } + #[inline] fn yzyz(self) -> Vec4 { Vec4::new(self.y, self.z, self.y, self.z) } + #[inline] fn yzzx(self) -> Vec4 { Vec4::new(self.y, self.z, self.z, self.x) } + #[inline] fn yzzy(self) -> Vec4 { Vec4::new(self.y, self.z, self.z, self.y) } + #[inline] fn yzzz(self) -> Vec4 { Vec4::new(self.y, self.z, self.z, self.z) } + #[inline] fn zxxx(self) -> Vec4 { Vec4::new(self.z, self.x, self.x, self.x) } + #[inline] fn zxxy(self) -> Vec4 { Vec4::new(self.z, self.x, self.x, self.y) } + #[inline] fn zxxz(self) -> Vec4 { Vec4::new(self.z, self.x, self.x, self.z) } + #[inline] fn zxyx(self) -> Vec4 { Vec4::new(self.z, self.x, self.y, self.x) } + #[inline] fn zxyy(self) -> Vec4 { Vec4::new(self.z, self.x, self.y, self.y) } + #[inline] fn zxyz(self) -> Vec4 { Vec4::new(self.z, self.x, self.y, self.z) } + #[inline] fn zxzx(self) -> Vec4 { Vec4::new(self.z, self.x, self.z, self.x) } + #[inline] fn zxzy(self) -> Vec4 { Vec4::new(self.z, self.x, self.z, self.y) } + #[inline] fn zxzz(self) -> Vec4 { Vec4::new(self.z, self.x, self.z, self.z) } + #[inline] fn zyxx(self) -> Vec4 { Vec4::new(self.z, self.y, self.x, self.x) } + #[inline] fn zyxy(self) -> Vec4 { Vec4::new(self.z, self.y, self.x, self.y) } + #[inline] fn zyxz(self) -> Vec4 { Vec4::new(self.z, self.y, self.x, self.z) } + #[inline] fn zyyx(self) -> Vec4 { Vec4::new(self.z, self.y, self.y, self.x) } + #[inline] fn zyyy(self) -> Vec4 { Vec4::new(self.z, self.y, self.y, self.y) } + #[inline] fn zyyz(self) -> Vec4 { Vec4::new(self.z, self.y, self.y, self.z) } + #[inline] fn zyzx(self) -> Vec4 { Vec4::new(self.z, self.y, self.z, self.x) } + #[inline] fn zyzy(self) -> Vec4 { Vec4::new(self.z, self.y, self.z, self.y) } + #[inline] fn zyzz(self) -> Vec4 { Vec4::new(self.z, self.y, self.z, self.z) } + #[inline] fn zzxx(self) -> Vec4 { Vec4::new(self.z, self.z, self.x, self.x) } + #[inline] fn zzxy(self) -> Vec4 { Vec4::new(self.z, self.z, self.x, self.y) } + #[inline] fn zzxz(self) -> Vec4 { Vec4::new(self.z, self.z, self.x, self.z) } + #[inline] fn zzyx(self) -> Vec4 { Vec4::new(self.z, self.z, self.y, self.x) } + #[inline] fn zzyy(self) -> Vec4 { Vec4::new(self.z, self.z, self.y, self.y) } + #[inline] fn zzyz(self) -> Vec4 { Vec4::new(self.z, self.z, self.y, self.z) } + #[inline] fn zzzx(self) -> Vec4 { Vec4::new(self.z, self.z, self.z, self.x) } + #[inline] fn zzzy(self) -> Vec4 { Vec4::new(self.z, self.z, self.z, self.y) } + #[inline] fn zzzz(self) -> Vec4 { Vec4::new(self.z, self.z, self.z, self.z) } - #[inline] - fn xxx(self) -> Self { - Self::new(self.x, self.x, self.x) - } - #[inline] - fn xxy(self) -> Self { - Self::new(self.x, self.x, self.y) - } - #[inline] - fn xxz(self) -> Self { - Self::new(self.x, self.x, self.z) - } - #[inline] - fn xyx(self) -> Self { - Self::new(self.x, self.y, self.x) - } - #[inline] - fn xyy(self) -> Self { - Self::new(self.x, self.y, self.y) - } - #[inline] - fn xzx(self) -> Self { - Self::new(self.x, self.z, self.x) - } - #[inline] - fn xzy(self) -> Self { - Self::new(self.x, self.z, self.y) - } - #[inline] - fn xzz(self) -> Self { - Self::new(self.x, self.z, self.z) - } - #[inline] - fn yxx(self) -> Self { - Self::new(self.y, self.x, self.x) - } - #[inline] - fn yxy(self) -> Self { - Self::new(self.y, self.x, self.y) - } - #[inline] - fn yxz(self) -> Self { - Self::new(self.y, self.x, self.z) - } - #[inline] - fn yyx(self) -> Self { - Self::new(self.y, self.y, self.x) - } - #[inline] - fn yyy(self) -> Self { - Self::new(self.y, self.y, self.y) - } - #[inline] - fn yyz(self) -> Self { - Self::new(self.y, self.y, self.z) - } - #[inline] - fn yzx(self) -> Self { - Self::new(self.y, self.z, self.x) - } - #[inline] - fn yzy(self) -> Self { - Self::new(self.y, self.z, self.y) - } - #[inline] - fn yzz(self) -> Self { - Self::new(self.y, self.z, self.z) - } - #[inline] - fn zxx(self) -> Self { - Self::new(self.z, self.x, self.x) - } - #[inline] - fn zxy(self) -> Self { - Self::new(self.z, self.x, self.y) - } - #[inline] - fn zxz(self) -> Self { - Self::new(self.z, self.x, self.z) - } - #[inline] - fn zyx(self) -> Self { - Self::new(self.z, self.y, self.x) - } - #[inline] - fn zyy(self) -> Self { - Self::new(self.z, self.y, self.y) - } - #[inline] - fn zyz(self) -> Self { - Self::new(self.z, self.y, self.z) - } - #[inline] - fn zzx(self) -> Self { - Self::new(self.z, self.z, self.x) - } - #[inline] - fn zzy(self) -> Self { - Self::new(self.z, self.z, self.y) - } - #[inline] - fn zzz(self) -> Self { - Self::new(self.z, self.z, self.z) - } - #[inline] - fn xx(self) -> Vec2 { - Vec2::new(self.x, self.x) - } - #[inline] - fn xy(self) -> Vec2 { - Vec2::new(self.x, self.y) - } - #[inline] - fn xz(self) -> Vec2 { - Vec2::new(self.x, self.z) - } - #[inline] - fn yx(self) -> Vec2 { - Vec2::new(self.y, self.x) - } - #[inline] - fn yy(self) -> Vec2 { - Vec2::new(self.y, self.y) - } - #[inline] - fn yz(self) -> Vec2 { - Vec2::new(self.y, self.z) - } - #[inline] - fn zx(self) -> Vec2 { - Vec2::new(self.z, self.x) - } - #[inline] - fn zy(self) -> Vec2 { - Vec2::new(self.z, self.y) - } - #[inline] - fn zz(self) -> Vec2 { - Vec2::new(self.z, self.z) - } } diff --git a/src/swizzles/vec3a_impl_sse2.rs b/src/swizzles/vec3a_impl_sse2.rs index 275ad70e..0358ca3b 100644 --- a/src/swizzles/vec3a_impl_sse2.rs +++ b/src/swizzles/vec3a_impl_sse2.rs @@ -1,7 +1,9 @@ -// Generated by swizzlegen. Do not edit. +// Generated from swizzle_impl.rs template. Edit the template, not the generated file. + +#![allow(clippy::useless_conversion)] use super::Vec3Swizzles; -use crate::{Vec2, Vec3A, Vec4, XY}; +use crate::{Vec2, Vec3A, Vec4}; #[cfg(target_arch = "x86")] use core::arch::x86::*; @@ -10,470 +12,618 @@ use core::arch::x86_64::*; impl Vec3Swizzles for Vec3A { type Vec2 = Vec2; + type Vec4 = Vec4; + #[inline] + fn xx(self) -> Vec2 { + Vec2 { + x: self.x, + y: self.x, + } + } + + #[inline] + fn xy(self) -> Vec2 { + Vec2 { + x: self.x, + y: self.y, + } + } + + #[inline] + fn xz(self) -> Vec2 { + Vec2 { + x: self.x, + y: self.z, + } + } + + #[inline] + fn yx(self) -> Vec2 { + Vec2 { + x: self.y, + y: self.x, + } + } + + #[inline] + fn yy(self) -> Vec2 { + Vec2 { + x: self.y, + y: self.y, + } + } + + #[inline] + fn yz(self) -> Vec2 { + Vec2 { + x: self.y, + y: self.z, + } + } + + #[inline] + fn zx(self) -> Vec2 { + Vec2 { + x: self.z, + y: self.x, + } + } + + #[inline] + fn zy(self) -> Vec2 { + Vec2 { + x: self.z, + y: self.y, + } + } + + #[inline] + fn zz(self) -> Vec2 { + Vec2 { + x: self.z, + y: self.z, + } + } + + #[inline] + fn xxx(self) -> Vec3A { + Vec3A((unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_00_00) }).into()) + } + + #[inline] + fn xxy(self) -> Vec3A { + Vec3A((unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_00_00) }).into()) + } + + #[inline] + fn xxz(self) -> Vec3A { + Vec3A((unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_00_00) }).into()) + } + + #[inline] + fn xyx(self) -> Vec3A { + Vec3A((unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_01_00) }).into()) + } + + #[inline] + fn xyy(self) -> Vec3A { + Vec3A((unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_01_00) }).into()) + } + + #[inline] + fn xyz(self) -> Vec3A { + Vec3A((unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_01_00) }).into()) + } + + #[inline] + fn xzx(self) -> Vec3A { + Vec3A((unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_10_00) }).into()) + } + + #[inline] + fn xzy(self) -> Vec3A { + Vec3A((unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_10_00) }).into()) + } + + #[inline] + fn xzz(self) -> Vec3A { + Vec3A((unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_10_00) }).into()) + } + + #[inline] + fn yxx(self) -> Vec3A { + Vec3A((unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_00_01) }).into()) + } + + #[inline] + fn yxy(self) -> Vec3A { + Vec3A((unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_00_01) }).into()) + } + + #[inline] + fn yxz(self) -> Vec3A { + Vec3A((unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_00_01) }).into()) + } + + #[inline] + fn yyx(self) -> Vec3A { + Vec3A((unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_01_01) }).into()) + } + + #[inline] + fn yyy(self) -> Vec3A { + Vec3A((unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_01_01) }).into()) + } + + #[inline] + fn yyz(self) -> Vec3A { + Vec3A((unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_01_01) }).into()) + } + + #[inline] + fn yzx(self) -> Vec3A { + Vec3A((unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_10_01) }).into()) + } + + #[inline] + fn yzy(self) -> Vec3A { + Vec3A((unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_10_01) }).into()) + } + + #[inline] + fn yzz(self) -> Vec3A { + Vec3A((unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_10_01) }).into()) + } + + #[inline] + fn zxx(self) -> Vec3A { + Vec3A((unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_00_10) }).into()) + } + + #[inline] + fn zxy(self) -> Vec3A { + Vec3A((unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_00_10) }).into()) + } + + #[inline] + fn zxz(self) -> Vec3A { + Vec3A((unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_00_10) }).into()) + } + + #[inline] + fn zyx(self) -> Vec3A { + Vec3A((unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_01_10) }).into()) + } + + #[inline] + fn zyy(self) -> Vec3A { + Vec3A((unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_01_10) }).into()) + } + + #[inline] + fn zyz(self) -> Vec3A { + Vec3A((unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_01_10) }).into()) + } + + #[inline] + fn zzx(self) -> Vec3A { + Vec3A((unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_10_10) }).into()) + } + + #[inline] + fn zzy(self) -> Vec3A { + Vec3A((unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_10_10) }).into()) + } + + #[inline] + fn zzz(self) -> Vec3A { + Vec3A((unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_10_10) }).into()) + } + #[inline] fn xxxx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_00_00_00)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_00_00) }) } + #[inline] fn xxxy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_00_00_00)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_00_00_00) }) } + #[inline] fn xxxz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_00_00_00)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_00_00_00) }) } + #[inline] fn xxyx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_01_00_00)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_00_00) }) } + #[inline] fn xxyy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_01_00_00)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_01_00_00) }) } + #[inline] fn xxyz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_01_00_00)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_01_00_00) }) } + #[inline] fn xxzx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_10_00_00)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_00_00) }) } + #[inline] fn xxzy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_10_00_00)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_10_00_00) }) } + #[inline] fn xxzz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_10_00_00)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_10_00_00) }) } + #[inline] fn xyxx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_00_01_00)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_01_00) }) } + #[inline] fn xyxy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_00_01_00)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_00_01_00) }) } + #[inline] fn xyxz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_00_01_00)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_00_01_00) }) } + #[inline] fn xyyx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_01_01_00)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_01_00) }) } + #[inline] fn xyyy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_01_01_00)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_01_01_00) }) } + #[inline] fn xyyz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_01_01_00)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_01_01_00) }) } + #[inline] fn xyzx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_10_01_00)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_01_00) }) } + #[inline] fn xyzy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_10_01_00)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_10_01_00) }) } + #[inline] fn xyzz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_10_01_00)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_10_01_00) }) } + #[inline] fn xzxx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_00_10_00)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_10_00) }) } + #[inline] fn xzxy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_00_10_00)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_00_10_00) }) } + #[inline] fn xzxz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_00_10_00)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_00_10_00) }) } + #[inline] fn xzyx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_01_10_00)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_10_00) }) } + #[inline] fn xzyy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_01_10_00)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_01_10_00) }) } + #[inline] fn xzyz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_01_10_00)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_01_10_00) }) } + #[inline] fn xzzx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_10_10_00)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_10_00) }) } + #[inline] fn xzzy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_10_10_00)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_10_10_00) }) } + #[inline] fn xzzz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_10_10_00)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_10_10_00) }) } + #[inline] fn yxxx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_00_00_01)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_00_01) }) } + #[inline] fn yxxy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_00_00_01)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_00_00_01) }) } + #[inline] fn yxxz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_00_00_01)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_00_00_01) }) } + #[inline] fn yxyx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_01_00_01)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_00_01) }) } + #[inline] fn yxyy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_01_00_01)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_01_00_01) }) } + #[inline] fn yxyz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_01_00_01)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_01_00_01) }) } + #[inline] fn yxzx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_10_00_01)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_00_01) }) } + #[inline] fn yxzy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_10_00_01)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_10_00_01) }) } + #[inline] fn yxzz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_10_00_01)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_10_00_01) }) } + #[inline] fn yyxx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_00_01_01)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_01_01) }) } + #[inline] fn yyxy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_00_01_01)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_00_01_01) }) } + #[inline] fn yyxz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_00_01_01)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_00_01_01) }) } + #[inline] fn yyyx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_01_01_01)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_01_01) }) } + #[inline] fn yyyy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_01_01_01)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_01_01_01) }) } + #[inline] fn yyyz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_01_01_01)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_01_01_01) }) } + #[inline] fn yyzx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_10_01_01)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_01_01) }) } + #[inline] fn yyzy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_10_01_01)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_10_01_01) }) } + #[inline] fn yyzz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_10_01_01)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_10_01_01) }) } + #[inline] fn yzxx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_00_10_01)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_10_01) }) } + #[inline] fn yzxy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_00_10_01)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_00_10_01) }) } + #[inline] fn yzxz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_00_10_01)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_00_10_01) }) } + #[inline] fn yzyx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_01_10_01)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_10_01) }) } + #[inline] fn yzyy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_01_10_01)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_01_10_01) }) } + #[inline] fn yzyz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_01_10_01)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_01_10_01) }) } + #[inline] fn yzzx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_10_10_01)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_10_01) }) } + #[inline] fn yzzy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_10_10_01)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_10_10_01) }) } + #[inline] fn yzzz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_10_10_01)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_10_10_01) }) } + #[inline] fn zxxx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_00_00_10)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_00_10) }) } + #[inline] fn zxxy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_00_00_10)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_00_00_10) }) } + #[inline] fn zxxz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_00_00_10)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_00_00_10) }) } + #[inline] fn zxyx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_01_00_10)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_00_10) }) } + #[inline] fn zxyy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_01_00_10)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_01_00_10) }) } + #[inline] fn zxyz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_01_00_10)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_01_00_10) }) } + #[inline] fn zxzx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_10_00_10)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_00_10) }) } + #[inline] fn zxzy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_10_00_10)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_10_00_10) }) } + #[inline] fn zxzz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_10_00_10)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_10_00_10) }) } + #[inline] fn zyxx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_00_01_10)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_01_10) }) } + #[inline] fn zyxy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_00_01_10)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_00_01_10) }) } + #[inline] fn zyxz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_00_01_10)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_00_01_10) }) } + #[inline] fn zyyx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_01_01_10)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_01_10) }) } + #[inline] fn zyyy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_01_01_10)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_01_01_10) }) } + #[inline] fn zyyz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_01_01_10)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_01_01_10) }) } + #[inline] fn zyzx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_10_01_10)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_01_10) }) } + #[inline] fn zyzy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_10_01_10)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_10_01_10) }) } + #[inline] fn zyzz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_10_01_10)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_10_01_10) }) } + #[inline] fn zzxx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_00_10_10)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_10_10) }) } + #[inline] fn zzxy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_00_10_10)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_00_10_10) }) } + #[inline] fn zzxz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_00_10_10)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_00_10_10) }) } + #[inline] fn zzyx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_01_10_10)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_10_10) }) } + #[inline] fn zzyy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_01_10_10)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_01_10_10) }) } + #[inline] fn zzyz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_01_10_10)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_01_10_10) }) } + #[inline] fn zzzx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_10_10_10)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_10_10) }) } + #[inline] fn zzzy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_10_10_10)) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_10_10_10) }) } + #[inline] fn zzzz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_10_10_10)) } - } - #[inline] - fn xxx(self) -> Self { - unsafe { Self(_mm_shuffle_ps(self.0, self.0, 0b00_00_00_00)) } - } - #[inline] - fn xxy(self) -> Self { - unsafe { Self(_mm_shuffle_ps(self.0, self.0, 0b00_01_00_00)) } - } - #[inline] - fn xxz(self) -> Self { - unsafe { Self(_mm_shuffle_ps(self.0, self.0, 0b00_10_00_00)) } - } - #[inline] - fn xyx(self) -> Self { - unsafe { Self(_mm_shuffle_ps(self.0, self.0, 0b00_00_01_00)) } - } - #[inline] - fn xyy(self) -> Self { - unsafe { Self(_mm_shuffle_ps(self.0, self.0, 0b00_01_01_00)) } - } - #[inline] - fn xzx(self) -> Self { - unsafe { Self(_mm_shuffle_ps(self.0, self.0, 0b00_00_10_00)) } - } - #[inline] - fn xzy(self) -> Self { - unsafe { Self(_mm_shuffle_ps(self.0, self.0, 0b00_01_10_00)) } - } - #[inline] - fn xzz(self) -> Self { - unsafe { Self(_mm_shuffle_ps(self.0, self.0, 0b00_10_10_00)) } - } - #[inline] - fn yxx(self) -> Self { - unsafe { Self(_mm_shuffle_ps(self.0, self.0, 0b00_00_00_01)) } - } - #[inline] - fn yxy(self) -> Self { - unsafe { Self(_mm_shuffle_ps(self.0, self.0, 0b00_01_00_01)) } - } - #[inline] - fn yxz(self) -> Self { - unsafe { Self(_mm_shuffle_ps(self.0, self.0, 0b00_10_00_01)) } - } - #[inline] - fn yyx(self) -> Self { - unsafe { Self(_mm_shuffle_ps(self.0, self.0, 0b00_00_01_01)) } - } - #[inline] - fn yyy(self) -> Self { - unsafe { Self(_mm_shuffle_ps(self.0, self.0, 0b00_01_01_01)) } - } - #[inline] - fn yyz(self) -> Self { - unsafe { Self(_mm_shuffle_ps(self.0, self.0, 0b00_10_01_01)) } - } - #[inline] - fn yzx(self) -> Self { - unsafe { Self(_mm_shuffle_ps(self.0, self.0, 0b00_00_10_01)) } - } - #[inline] - fn yzy(self) -> Self { - unsafe { Self(_mm_shuffle_ps(self.0, self.0, 0b00_01_10_01)) } - } - #[inline] - fn yzz(self) -> Self { - unsafe { Self(_mm_shuffle_ps(self.0, self.0, 0b00_10_10_01)) } - } - #[inline] - fn zxx(self) -> Self { - unsafe { Self(_mm_shuffle_ps(self.0, self.0, 0b00_00_00_10)) } - } - #[inline] - fn zxy(self) -> Self { - unsafe { Self(_mm_shuffle_ps(self.0, self.0, 0b00_01_00_10)) } - } - #[inline] - fn zxz(self) -> Self { - unsafe { Self(_mm_shuffle_ps(self.0, self.0, 0b00_10_00_10)) } - } - #[inline] - fn zyx(self) -> Self { - unsafe { Self(_mm_shuffle_ps(self.0, self.0, 0b00_00_01_10)) } - } - #[inline] - fn zyy(self) -> Self { - unsafe { Self(_mm_shuffle_ps(self.0, self.0, 0b00_01_01_10)) } - } - #[inline] - fn zyz(self) -> Self { - unsafe { Self(_mm_shuffle_ps(self.0, self.0, 0b00_10_01_10)) } - } - #[inline] - fn zzx(self) -> Self { - unsafe { Self(_mm_shuffle_ps(self.0, self.0, 0b00_00_10_10)) } - } - #[inline] - fn zzy(self) -> Self { - unsafe { Self(_mm_shuffle_ps(self.0, self.0, 0b00_01_10_10)) } - } - #[inline] - fn zzz(self) -> Self { - unsafe { Self(_mm_shuffle_ps(self.0, self.0, 0b00_10_10_10)) } - } - #[inline] - fn xx(self) -> Vec2 { - unsafe { Vec2(XY::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_00_00))) } - } - #[inline] - fn xy(self) -> Vec2 { - unsafe { Vec2(XY::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_01_00))) } - } - #[inline] - fn xz(self) -> Vec2 { - unsafe { Vec2(XY::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_10_00))) } - } - #[inline] - fn yx(self) -> Vec2 { - unsafe { Vec2(XY::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_00_01))) } - } - #[inline] - fn yy(self) -> Vec2 { - unsafe { Vec2(XY::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_01_01))) } - } - #[inline] - fn yz(self) -> Vec2 { - unsafe { Vec2(XY::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_10_01))) } - } - #[inline] - fn zx(self) -> Vec2 { - unsafe { Vec2(XY::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_00_10))) } - } - #[inline] - fn zy(self) -> Vec2 { - unsafe { Vec2(XY::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_01_10))) } - } - #[inline] - fn zz(self) -> Vec2 { - unsafe { Vec2(XY::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_10_10))) } + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_10_10_10) }) } } diff --git a/src/swizzles/vec3a_impl_wasm32.rs b/src/swizzles/vec3a_impl_wasm32.rs index fa5e01af..905e0690 100644 --- a/src/swizzles/vec3a_impl_wasm32.rs +++ b/src/swizzles/vec3a_impl_wasm32.rs @@ -1,476 +1,626 @@ -// Generated by swizzlegen. Do not edit. +// Generated from swizzle_impl.rs template. Edit the template, not the generated file. + +#![allow(clippy::useless_conversion)] use super::Vec3Swizzles; -use crate::{Vec2, Vec3A, Vec4, XY}; +use crate::{Vec2, Vec3A, Vec4}; use core::arch::wasm32::*; impl Vec3Swizzles for Vec3A { type Vec2 = Vec2; + type Vec4 = Vec4; + #[inline] + fn xx(self) -> Vec2 { + Vec2 { + x: self.x, + y: self.x, + } + } + + #[inline] + fn xy(self) -> Vec2 { + Vec2 { + x: self.x, + y: self.y, + } + } + + #[inline] + fn xz(self) -> Vec2 { + Vec2 { + x: self.x, + y: self.z, + } + } + + #[inline] + fn yx(self) -> Vec2 { + Vec2 { + x: self.y, + y: self.x, + } + } + + #[inline] + fn yy(self) -> Vec2 { + Vec2 { + x: self.y, + y: self.y, + } + } + + #[inline] + fn yz(self) -> Vec2 { + Vec2 { + x: self.y, + y: self.z, + } + } + + #[inline] + fn zx(self) -> Vec2 { + Vec2 { + x: self.z, + y: self.x, + } + } + + #[inline] + fn zy(self) -> Vec2 { + Vec2 { + x: self.z, + y: self.y, + } + } + + #[inline] + fn zz(self) -> Vec2 { + Vec2 { + x: self.z, + y: self.z, + } + } + + #[inline] + fn xxx(self) -> Vec3A { + Vec3A(i32x4_shuffle::<0, 0, 4, 4>(self.0, self.0).into()) + } + + #[inline] + fn xxy(self) -> Vec3A { + Vec3A(i32x4_shuffle::<0, 0, 5, 4>(self.0, self.0).into()) + } + + #[inline] + fn xxz(self) -> Vec3A { + Vec3A(i32x4_shuffle::<0, 0, 6, 4>(self.0, self.0).into()) + } + + #[inline] + fn xyx(self) -> Vec3A { + Vec3A(i32x4_shuffle::<0, 1, 4, 4>(self.0, self.0).into()) + } + + #[inline] + fn xyy(self) -> Vec3A { + Vec3A(i32x4_shuffle::<0, 1, 5, 4>(self.0, self.0).into()) + } + + #[inline] + fn xyz(self) -> Vec3A { + Vec3A(i32x4_shuffle::<0, 1, 6, 4>(self.0, self.0).into()) + } + + #[inline] + fn xzx(self) -> Vec3A { + Vec3A(i32x4_shuffle::<0, 2, 4, 4>(self.0, self.0).into()) + } + + #[inline] + fn xzy(self) -> Vec3A { + Vec3A(i32x4_shuffle::<0, 2, 5, 4>(self.0, self.0).into()) + } + + #[inline] + fn xzz(self) -> Vec3A { + Vec3A(i32x4_shuffle::<0, 2, 6, 4>(self.0, self.0).into()) + } + + #[inline] + fn yxx(self) -> Vec3A { + Vec3A(i32x4_shuffle::<1, 0, 4, 4>(self.0, self.0).into()) + } + + #[inline] + fn yxy(self) -> Vec3A { + Vec3A(i32x4_shuffle::<1, 0, 5, 4>(self.0, self.0).into()) + } + + #[inline] + fn yxz(self) -> Vec3A { + Vec3A(i32x4_shuffle::<1, 0, 6, 4>(self.0, self.0).into()) + } + + #[inline] + fn yyx(self) -> Vec3A { + Vec3A(i32x4_shuffle::<1, 1, 4, 4>(self.0, self.0).into()) + } + + #[inline] + fn yyy(self) -> Vec3A { + Vec3A(i32x4_shuffle::<1, 1, 5, 4>(self.0, self.0).into()) + } + + #[inline] + fn yyz(self) -> Vec3A { + Vec3A(i32x4_shuffle::<1, 1, 6, 4>(self.0, self.0).into()) + } + + #[inline] + fn yzx(self) -> Vec3A { + Vec3A(i32x4_shuffle::<1, 2, 4, 4>(self.0, self.0).into()) + } + + #[inline] + fn yzy(self) -> Vec3A { + Vec3A(i32x4_shuffle::<1, 2, 5, 4>(self.0, self.0).into()) + } + + #[inline] + fn yzz(self) -> Vec3A { + Vec3A(i32x4_shuffle::<1, 2, 6, 4>(self.0, self.0).into()) + } + + #[inline] + fn zxx(self) -> Vec3A { + Vec3A(i32x4_shuffle::<2, 0, 4, 4>(self.0, self.0).into()) + } + + #[inline] + fn zxy(self) -> Vec3A { + Vec3A(i32x4_shuffle::<2, 0, 5, 4>(self.0, self.0).into()) + } + + #[inline] + fn zxz(self) -> Vec3A { + Vec3A(i32x4_shuffle::<2, 0, 6, 4>(self.0, self.0).into()) + } + + #[inline] + fn zyx(self) -> Vec3A { + Vec3A(i32x4_shuffle::<2, 1, 4, 4>(self.0, self.0).into()) + } + + #[inline] + fn zyy(self) -> Vec3A { + Vec3A(i32x4_shuffle::<2, 1, 5, 4>(self.0, self.0).into()) + } + + #[inline] + fn zyz(self) -> Vec3A { + Vec3A(i32x4_shuffle::<2, 1, 6, 4>(self.0, self.0).into()) + } + + #[inline] + fn zzx(self) -> Vec3A { + Vec3A(i32x4_shuffle::<2, 2, 4, 4>(self.0, self.0).into()) + } + + #[inline] + fn zzy(self) -> Vec3A { + Vec3A(i32x4_shuffle::<2, 2, 5, 4>(self.0, self.0).into()) + } + + #[inline] + fn zzz(self) -> Vec3A { + Vec3A(i32x4_shuffle::<2, 2, 6, 4>(self.0, self.0).into()) + } + #[inline] fn xxxx(self) -> Vec4 { Vec4(i32x4_shuffle::<0, 0, 4, 4>(self.0, self.0)) } + #[inline] fn xxxy(self) -> Vec4 { Vec4(i32x4_shuffle::<0, 0, 4, 5>(self.0, self.0)) } + #[inline] fn xxxz(self) -> Vec4 { Vec4(i32x4_shuffle::<0, 0, 4, 6>(self.0, self.0)) } + #[inline] fn xxyx(self) -> Vec4 { Vec4(i32x4_shuffle::<0, 0, 5, 4>(self.0, self.0)) } + #[inline] fn xxyy(self) -> Vec4 { Vec4(i32x4_shuffle::<0, 0, 5, 5>(self.0, self.0)) } + #[inline] fn xxyz(self) -> Vec4 { Vec4(i32x4_shuffle::<0, 0, 5, 6>(self.0, self.0)) } + #[inline] fn xxzx(self) -> Vec4 { Vec4(i32x4_shuffle::<0, 0, 6, 4>(self.0, self.0)) } + #[inline] fn xxzy(self) -> Vec4 { Vec4(i32x4_shuffle::<0, 0, 6, 5>(self.0, self.0)) } + #[inline] fn xxzz(self) -> Vec4 { Vec4(i32x4_shuffle::<0, 0, 6, 6>(self.0, self.0)) } + #[inline] fn xyxx(self) -> Vec4 { Vec4(i32x4_shuffle::<0, 1, 4, 4>(self.0, self.0)) } + #[inline] fn xyxy(self) -> Vec4 { Vec4(i32x4_shuffle::<0, 1, 4, 5>(self.0, self.0)) } + #[inline] fn xyxz(self) -> Vec4 { Vec4(i32x4_shuffle::<0, 1, 4, 6>(self.0, self.0)) } + #[inline] fn xyyx(self) -> Vec4 { Vec4(i32x4_shuffle::<0, 1, 5, 4>(self.0, self.0)) } + #[inline] fn xyyy(self) -> Vec4 { Vec4(i32x4_shuffle::<0, 1, 5, 5>(self.0, self.0)) } + #[inline] fn xyyz(self) -> Vec4 { Vec4(i32x4_shuffle::<0, 1, 5, 6>(self.0, self.0)) } + #[inline] fn xyzx(self) -> Vec4 { Vec4(i32x4_shuffle::<0, 1, 6, 4>(self.0, self.0)) } + #[inline] fn xyzy(self) -> Vec4 { Vec4(i32x4_shuffle::<0, 1, 6, 5>(self.0, self.0)) } + #[inline] fn xyzz(self) -> Vec4 { Vec4(i32x4_shuffle::<0, 1, 6, 6>(self.0, self.0)) } + #[inline] fn xzxx(self) -> Vec4 { Vec4(i32x4_shuffle::<0, 2, 4, 4>(self.0, self.0)) } + #[inline] fn xzxy(self) -> Vec4 { Vec4(i32x4_shuffle::<0, 2, 4, 5>(self.0, self.0)) } + #[inline] fn xzxz(self) -> Vec4 { Vec4(i32x4_shuffle::<0, 2, 4, 6>(self.0, self.0)) } + #[inline] fn xzyx(self) -> Vec4 { Vec4(i32x4_shuffle::<0, 2, 5, 4>(self.0, self.0)) } + #[inline] fn xzyy(self) -> Vec4 { Vec4(i32x4_shuffle::<0, 2, 5, 5>(self.0, self.0)) } + #[inline] fn xzyz(self) -> Vec4 { Vec4(i32x4_shuffle::<0, 2, 5, 6>(self.0, self.0)) } + #[inline] fn xzzx(self) -> Vec4 { Vec4(i32x4_shuffle::<0, 2, 6, 4>(self.0, self.0)) } + #[inline] fn xzzy(self) -> Vec4 { Vec4(i32x4_shuffle::<0, 2, 6, 5>(self.0, self.0)) } + #[inline] fn xzzz(self) -> Vec4 { Vec4(i32x4_shuffle::<0, 2, 6, 6>(self.0, self.0)) } + #[inline] fn yxxx(self) -> Vec4 { Vec4(i32x4_shuffle::<1, 0, 4, 4>(self.0, self.0)) } + #[inline] fn yxxy(self) -> Vec4 { Vec4(i32x4_shuffle::<1, 0, 4, 5>(self.0, self.0)) } + #[inline] fn yxxz(self) -> Vec4 { Vec4(i32x4_shuffle::<1, 0, 4, 6>(self.0, self.0)) } + #[inline] fn yxyx(self) -> Vec4 { Vec4(i32x4_shuffle::<1, 0, 5, 4>(self.0, self.0)) } + #[inline] fn yxyy(self) -> Vec4 { Vec4(i32x4_shuffle::<1, 0, 5, 5>(self.0, self.0)) } + #[inline] fn yxyz(self) -> Vec4 { Vec4(i32x4_shuffle::<1, 0, 5, 6>(self.0, self.0)) } + #[inline] fn yxzx(self) -> Vec4 { Vec4(i32x4_shuffle::<1, 0, 6, 4>(self.0, self.0)) } + #[inline] fn yxzy(self) -> Vec4 { Vec4(i32x4_shuffle::<1, 0, 6, 5>(self.0, self.0)) } + #[inline] fn yxzz(self) -> Vec4 { Vec4(i32x4_shuffle::<1, 0, 6, 6>(self.0, self.0)) } + #[inline] fn yyxx(self) -> Vec4 { Vec4(i32x4_shuffle::<1, 1, 4, 4>(self.0, self.0)) } + #[inline] fn yyxy(self) -> Vec4 { Vec4(i32x4_shuffle::<1, 1, 4, 5>(self.0, self.0)) } + #[inline] fn yyxz(self) -> Vec4 { Vec4(i32x4_shuffle::<1, 1, 4, 6>(self.0, self.0)) } + #[inline] fn yyyx(self) -> Vec4 { Vec4(i32x4_shuffle::<1, 1, 5, 4>(self.0, self.0)) } + #[inline] fn yyyy(self) -> Vec4 { Vec4(i32x4_shuffle::<1, 1, 5, 5>(self.0, self.0)) } + #[inline] fn yyyz(self) -> Vec4 { Vec4(i32x4_shuffle::<1, 1, 5, 6>(self.0, self.0)) } + #[inline] fn yyzx(self) -> Vec4 { Vec4(i32x4_shuffle::<1, 1, 6, 4>(self.0, self.0)) } + #[inline] fn yyzy(self) -> Vec4 { Vec4(i32x4_shuffle::<1, 1, 6, 5>(self.0, self.0)) } + #[inline] fn yyzz(self) -> Vec4 { Vec4(i32x4_shuffle::<1, 1, 6, 6>(self.0, self.0)) } + #[inline] fn yzxx(self) -> Vec4 { Vec4(i32x4_shuffle::<1, 2, 4, 4>(self.0, self.0)) } + #[inline] fn yzxy(self) -> Vec4 { Vec4(i32x4_shuffle::<1, 2, 4, 5>(self.0, self.0)) } + #[inline] fn yzxz(self) -> Vec4 { Vec4(i32x4_shuffle::<1, 2, 4, 6>(self.0, self.0)) } + #[inline] fn yzyx(self) -> Vec4 { Vec4(i32x4_shuffle::<1, 2, 5, 4>(self.0, self.0)) } + #[inline] fn yzyy(self) -> Vec4 { Vec4(i32x4_shuffle::<1, 2, 5, 5>(self.0, self.0)) } + #[inline] fn yzyz(self) -> Vec4 { Vec4(i32x4_shuffle::<1, 2, 5, 6>(self.0, self.0)) } + #[inline] fn yzzx(self) -> Vec4 { Vec4(i32x4_shuffle::<1, 2, 6, 4>(self.0, self.0)) } + #[inline] fn yzzy(self) -> Vec4 { Vec4(i32x4_shuffle::<1, 2, 6, 5>(self.0, self.0)) } + #[inline] fn yzzz(self) -> Vec4 { Vec4(i32x4_shuffle::<1, 2, 6, 6>(self.0, self.0)) } + #[inline] fn zxxx(self) -> Vec4 { Vec4(i32x4_shuffle::<2, 0, 4, 4>(self.0, self.0)) } + #[inline] fn zxxy(self) -> Vec4 { Vec4(i32x4_shuffle::<2, 0, 4, 5>(self.0, self.0)) } + #[inline] fn zxxz(self) -> Vec4 { Vec4(i32x4_shuffle::<2, 0, 4, 6>(self.0, self.0)) } + #[inline] fn zxyx(self) -> Vec4 { Vec4(i32x4_shuffle::<2, 0, 5, 4>(self.0, self.0)) } + #[inline] fn zxyy(self) -> Vec4 { Vec4(i32x4_shuffle::<2, 0, 5, 5>(self.0, self.0)) } + #[inline] fn zxyz(self) -> Vec4 { Vec4(i32x4_shuffle::<2, 0, 5, 6>(self.0, self.0)) } + #[inline] fn zxzx(self) -> Vec4 { Vec4(i32x4_shuffle::<2, 0, 6, 4>(self.0, self.0)) } + #[inline] fn zxzy(self) -> Vec4 { Vec4(i32x4_shuffle::<2, 0, 6, 5>(self.0, self.0)) } + #[inline] fn zxzz(self) -> Vec4 { Vec4(i32x4_shuffle::<2, 0, 6, 6>(self.0, self.0)) } + #[inline] fn zyxx(self) -> Vec4 { Vec4(i32x4_shuffle::<2, 1, 4, 4>(self.0, self.0)) } + #[inline] fn zyxy(self) -> Vec4 { Vec4(i32x4_shuffle::<2, 1, 4, 5>(self.0, self.0)) } + #[inline] fn zyxz(self) -> Vec4 { Vec4(i32x4_shuffle::<2, 1, 4, 6>(self.0, self.0)) } + #[inline] fn zyyx(self) -> Vec4 { Vec4(i32x4_shuffle::<2, 1, 5, 4>(self.0, self.0)) } + #[inline] fn zyyy(self) -> Vec4 { Vec4(i32x4_shuffle::<2, 1, 5, 5>(self.0, self.0)) } + #[inline] fn zyyz(self) -> Vec4 { Vec4(i32x4_shuffle::<2, 1, 5, 6>(self.0, self.0)) } + #[inline] fn zyzx(self) -> Vec4 { Vec4(i32x4_shuffle::<2, 1, 6, 4>(self.0, self.0)) } + #[inline] fn zyzy(self) -> Vec4 { Vec4(i32x4_shuffle::<2, 1, 6, 5>(self.0, self.0)) } + #[inline] fn zyzz(self) -> Vec4 { Vec4(i32x4_shuffle::<2, 1, 6, 6>(self.0, self.0)) } + #[inline] fn zzxx(self) -> Vec4 { Vec4(i32x4_shuffle::<2, 2, 4, 4>(self.0, self.0)) } + #[inline] fn zzxy(self) -> Vec4 { Vec4(i32x4_shuffle::<2, 2, 4, 5>(self.0, self.0)) } + #[inline] fn zzxz(self) -> Vec4 { Vec4(i32x4_shuffle::<2, 2, 4, 6>(self.0, self.0)) } + #[inline] fn zzyx(self) -> Vec4 { Vec4(i32x4_shuffle::<2, 2, 5, 4>(self.0, self.0)) } + #[inline] fn zzyy(self) -> Vec4 { Vec4(i32x4_shuffle::<2, 2, 5, 5>(self.0, self.0)) } + #[inline] fn zzyz(self) -> Vec4 { Vec4(i32x4_shuffle::<2, 2, 5, 6>(self.0, self.0)) } + #[inline] fn zzzx(self) -> Vec4 { Vec4(i32x4_shuffle::<2, 2, 6, 4>(self.0, self.0)) } + #[inline] fn zzzy(self) -> Vec4 { Vec4(i32x4_shuffle::<2, 2, 6, 5>(self.0, self.0)) } + #[inline] fn zzzz(self) -> Vec4 { Vec4(i32x4_shuffle::<2, 2, 6, 6>(self.0, self.0)) } - #[inline] - fn xxx(self) -> Self { - Self(i32x4_shuffle::<0, 0, 4, 4>(self.0, self.0)) - } - #[inline] - fn xxy(self) -> Self { - Self(i32x4_shuffle::<0, 0, 5, 4>(self.0, self.0)) - } - #[inline] - fn xxz(self) -> Self { - Self(i32x4_shuffle::<0, 0, 6, 4>(self.0, self.0)) - } - #[inline] - fn xyx(self) -> Self { - Self(i32x4_shuffle::<0, 1, 4, 4>(self.0, self.0)) - } - #[inline] - fn xyy(self) -> Self { - Self(i32x4_shuffle::<0, 1, 5, 4>(self.0, self.0)) - } - #[inline] - fn xzx(self) -> Self { - Self(i32x4_shuffle::<0, 2, 4, 4>(self.0, self.0)) - } - #[inline] - fn xzy(self) -> Self { - Self(i32x4_shuffle::<0, 2, 5, 4>(self.0, self.0)) - } - #[inline] - fn xzz(self) -> Self { - Self(i32x4_shuffle::<0, 2, 6, 4>(self.0, self.0)) - } - #[inline] - fn yxx(self) -> Self { - Self(i32x4_shuffle::<1, 0, 4, 4>(self.0, self.0)) - } - #[inline] - fn yxy(self) -> Self { - Self(i32x4_shuffle::<1, 0, 5, 4>(self.0, self.0)) - } - #[inline] - fn yxz(self) -> Self { - Self(i32x4_shuffle::<1, 0, 6, 4>(self.0, self.0)) - } - #[inline] - fn yyx(self) -> Self { - Self(i32x4_shuffle::<1, 1, 4, 4>(self.0, self.0)) - } - #[inline] - fn yyy(self) -> Self { - Self(i32x4_shuffle::<1, 1, 5, 4>(self.0, self.0)) - } - #[inline] - fn yyz(self) -> Self { - Self(i32x4_shuffle::<1, 1, 6, 4>(self.0, self.0)) - } - #[inline] - fn yzx(self) -> Self { - Self(i32x4_shuffle::<1, 2, 4, 4>(self.0, self.0)) - } - #[inline] - fn yzy(self) -> Self { - Self(i32x4_shuffle::<1, 2, 5, 4>(self.0, self.0)) - } - #[inline] - fn yzz(self) -> Self { - Self(i32x4_shuffle::<1, 2, 6, 4>(self.0, self.0)) - } - #[inline] - fn zxx(self) -> Self { - Self(i32x4_shuffle::<2, 0, 4, 4>(self.0, self.0)) - } - #[inline] - fn zxy(self) -> Self { - Self(i32x4_shuffle::<2, 0, 5, 4>(self.0, self.0)) - } - #[inline] - fn zxz(self) -> Self { - Self(i32x4_shuffle::<2, 0, 6, 4>(self.0, self.0)) - } - #[inline] - fn zyx(self) -> Self { - Self(i32x4_shuffle::<2, 1, 4, 4>(self.0, self.0)) - } - #[inline] - fn zyy(self) -> Self { - Self(i32x4_shuffle::<2, 1, 5, 4>(self.0, self.0)) - } - #[inline] - fn zyz(self) -> Self { - Self(i32x4_shuffle::<2, 1, 6, 4>(self.0, self.0)) - } - #[inline] - fn zzx(self) -> Self { - Self(i32x4_shuffle::<2, 2, 4, 4>(self.0, self.0)) - } - #[inline] - fn zzy(self) -> Self { - Self(i32x4_shuffle::<2, 2, 5, 4>(self.0, self.0)) - } - #[inline] - fn zzz(self) -> Self { - Self(i32x4_shuffle::<2, 2, 6, 4>(self.0, self.0)) - } - #[inline] - fn xx(self) -> Vec2 { - Vec2(XY::from(i32x4_shuffle::<0, 0, 4, 4>(self.0, self.0))) - } - #[inline] - fn xy(self) -> Vec2 { - Vec2(XY::from(i32x4_shuffle::<0, 1, 4, 4>(self.0, self.0))) - } - #[inline] - fn xz(self) -> Vec2 { - Vec2(XY::from(i32x4_shuffle::<0, 2, 4, 4>(self.0, self.0))) - } - #[inline] - fn yx(self) -> Vec2 { - Vec2(XY::from(i32x4_shuffle::<1, 0, 4, 4>(self.0, self.0))) - } - #[inline] - fn yy(self) -> Vec2 { - Vec2(XY::from(i32x4_shuffle::<1, 1, 4, 4>(self.0, self.0))) - } - #[inline] - fn yz(self) -> Vec2 { - Vec2(XY::from(i32x4_shuffle::<1, 2, 4, 4>(self.0, self.0))) - } - #[inline] - fn zx(self) -> Vec2 { - Vec2(XY::from(i32x4_shuffle::<2, 0, 4, 4>(self.0, self.0))) - } - #[inline] - fn zy(self) -> Vec2 { - Vec2(XY::from(i32x4_shuffle::<2, 1, 4, 4>(self.0, self.0))) - } - #[inline] - fn zz(self) -> Vec2 { - Vec2(XY::from(i32x4_shuffle::<2, 2, 4, 4>(self.0, self.0))) - } } diff --git a/src/swizzles/vec4_impl_scalar.rs b/src/swizzles/vec4_impl_scalar.rs index 19f97a76..b29993a4 100644 --- a/src/swizzles/vec4_impl_scalar.rs +++ b/src/swizzles/vec4_impl_scalar.rs @@ -1,1350 +1,1996 @@ -// Generated by swizzlegen. Do not edit. +// Generated from swizzle_impl.rs template. Edit the template, not the generated file. + +#![allow(clippy::useless_conversion)] use super::Vec4Swizzles; use crate::{Vec2, Vec3, Vec4}; impl Vec4Swizzles for Vec4 { type Vec2 = Vec2; + type Vec3 = Vec3; #[inline] - fn xxxx(self) -> Vec4 { - Vec4::new(self.x, self.x, self.x, self.x) + fn xx(self) -> Vec2 { + Vec2 { + x: self.x, + y: self.x, + } } + #[inline] - fn xxxy(self) -> Vec4 { - Vec4::new(self.x, self.x, self.x, self.y) + fn xy(self) -> Vec2 { + Vec2 { + x: self.x, + y: self.y, + } } + #[inline] - fn xxxz(self) -> Vec4 { - Vec4::new(self.x, self.x, self.x, self.z) + fn xz(self) -> Vec2 { + Vec2 { + x: self.x, + y: self.z, + } } + #[inline] - fn xxxw(self) -> Vec4 { - Vec4::new(self.x, self.x, self.x, self.w) + fn xw(self) -> Vec2 { + Vec2 { + x: self.x, + y: self.w, + } } + #[inline] - fn xxyx(self) -> Vec4 { - Vec4::new(self.x, self.x, self.y, self.x) + fn yx(self) -> Vec2 { + Vec2 { + x: self.y, + y: self.x, + } } + #[inline] - fn xxyy(self) -> Vec4 { - Vec4::new(self.x, self.x, self.y, self.y) + fn yy(self) -> Vec2 { + Vec2 { + x: self.y, + y: self.y, + } } + #[inline] - fn xxyz(self) -> Vec4 { - Vec4::new(self.x, self.x, self.y, self.z) + fn yz(self) -> Vec2 { + Vec2 { + x: self.y, + y: self.z, + } } + #[inline] - fn xxyw(self) -> Vec4 { - Vec4::new(self.x, self.x, self.y, self.w) + fn yw(self) -> Vec2 { + Vec2 { + x: self.y, + y: self.w, + } } + #[inline] - fn xxzx(self) -> Vec4 { - Vec4::new(self.x, self.x, self.z, self.x) + fn zx(self) -> Vec2 { + Vec2 { + x: self.z, + y: self.x, + } } + #[inline] - fn xxzy(self) -> Vec4 { - Vec4::new(self.x, self.x, self.z, self.y) + fn zy(self) -> Vec2 { + Vec2 { + x: self.z, + y: self.y, + } } + #[inline] - fn xxzz(self) -> Vec4 { - Vec4::new(self.x, self.x, self.z, self.z) + fn zz(self) -> Vec2 { + Vec2 { + x: self.z, + y: self.z, + } } + #[inline] - fn xxzw(self) -> Vec4 { - Vec4::new(self.x, self.x, self.z, self.w) + fn zw(self) -> Vec2 { + Vec2 { + x: self.z, + y: self.w, + } } + #[inline] - fn xxwx(self) -> Vec4 { - Vec4::new(self.x, self.x, self.w, self.x) + fn wx(self) -> Vec2 { + Vec2 { + x: self.w, + y: self.x, + } } + #[inline] - fn xxwy(self) -> Vec4 { - Vec4::new(self.x, self.x, self.w, self.y) + fn wy(self) -> Vec2 { + Vec2 { + x: self.w, + y: self.y, + } } + #[inline] - fn xxwz(self) -> Vec4 { - Vec4::new(self.x, self.x, self.w, self.z) + fn wz(self) -> Vec2 { + Vec2 { + x: self.w, + y: self.z, + } } + #[inline] - fn xxww(self) -> Vec4 { - Vec4::new(self.x, self.x, self.w, self.w) + fn ww(self) -> Vec2 { + Vec2 { + x: self.w, + y: self.w, + } } + #[inline] - fn xyxx(self) -> Vec4 { - Vec4::new(self.x, self.y, self.x, self.x) + fn xxx(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.x, + z: self.x, + } } + #[inline] - fn xyxy(self) -> Vec4 { - Vec4::new(self.x, self.y, self.x, self.y) + fn xxy(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.x, + z: self.y, + } } + #[inline] - fn xyxz(self) -> Vec4 { - Vec4::new(self.x, self.y, self.x, self.z) + fn xxz(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.x, + z: self.z, + } } + #[inline] - fn xyxw(self) -> Vec4 { - Vec4::new(self.x, self.y, self.x, self.w) + fn xxw(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.x, + z: self.w, + } } + #[inline] - fn xyyx(self) -> Vec4 { - Vec4::new(self.x, self.y, self.y, self.x) + fn xyx(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.y, + z: self.x, + } } + #[inline] - fn xyyy(self) -> Vec4 { - Vec4::new(self.x, self.y, self.y, self.y) + fn xyy(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.y, + z: self.y, + } } + #[inline] - fn xyyz(self) -> Vec4 { - Vec4::new(self.x, self.y, self.y, self.z) + fn xyz(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.y, + z: self.z, + } } + #[inline] - fn xyyw(self) -> Vec4 { - Vec4::new(self.x, self.y, self.y, self.w) + fn xyw(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.y, + z: self.w, + } } + #[inline] - fn xyzx(self) -> Vec4 { - Vec4::new(self.x, self.y, self.z, self.x) + fn xzx(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.z, + z: self.x, + } } + #[inline] - fn xyzy(self) -> Vec4 { - Vec4::new(self.x, self.y, self.z, self.y) + fn xzy(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.z, + z: self.y, + } } + #[inline] - fn xyzz(self) -> Vec4 { - Vec4::new(self.x, self.y, self.z, self.z) + fn xzz(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.z, + z: self.z, + } } + #[inline] - fn xywx(self) -> Vec4 { - Vec4::new(self.x, self.y, self.w, self.x) + fn xzw(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.z, + z: self.w, + } } + #[inline] - fn xywy(self) -> Vec4 { - Vec4::new(self.x, self.y, self.w, self.y) + fn xwx(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.w, + z: self.x, + } } + #[inline] - fn xywz(self) -> Vec4 { - Vec4::new(self.x, self.y, self.w, self.z) + fn xwy(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.w, + z: self.y, + } } + #[inline] - fn xyww(self) -> Vec4 { - Vec4::new(self.x, self.y, self.w, self.w) + fn xwz(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.w, + z: self.z, + } } + #[inline] - fn xzxx(self) -> Vec4 { - Vec4::new(self.x, self.z, self.x, self.x) + fn xww(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.w, + z: self.w, + } } + #[inline] - fn xzxy(self) -> Vec4 { - Vec4::new(self.x, self.z, self.x, self.y) + fn yxx(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.x, + z: self.x, + } } + #[inline] - fn xzxz(self) -> Vec4 { - Vec4::new(self.x, self.z, self.x, self.z) + fn yxy(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.x, + z: self.y, + } } + #[inline] - fn xzxw(self) -> Vec4 { - Vec4::new(self.x, self.z, self.x, self.w) + fn yxz(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.x, + z: self.z, + } } + #[inline] - fn xzyx(self) -> Vec4 { - Vec4::new(self.x, self.z, self.y, self.x) + fn yxw(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.x, + z: self.w, + } } + #[inline] - fn xzyy(self) -> Vec4 { - Vec4::new(self.x, self.z, self.y, self.y) + fn yyx(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.y, + z: self.x, + } } + #[inline] - fn xzyz(self) -> Vec4 { - Vec4::new(self.x, self.z, self.y, self.z) + fn yyy(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.y, + z: self.y, + } } + #[inline] - fn xzyw(self) -> Vec4 { - Vec4::new(self.x, self.z, self.y, self.w) + fn yyz(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.y, + z: self.z, + } } + #[inline] - fn xzzx(self) -> Vec4 { - Vec4::new(self.x, self.z, self.z, self.x) + fn yyw(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.y, + z: self.w, + } } + #[inline] - fn xzzy(self) -> Vec4 { - Vec4::new(self.x, self.z, self.z, self.y) + fn yzx(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.z, + z: self.x, + } } + #[inline] - fn xzzz(self) -> Vec4 { - Vec4::new(self.x, self.z, self.z, self.z) + fn yzy(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.z, + z: self.y, + } } + #[inline] - fn xzzw(self) -> Vec4 { - Vec4::new(self.x, self.z, self.z, self.w) + fn yzz(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.z, + z: self.z, + } } + #[inline] - fn xzwx(self) -> Vec4 { - Vec4::new(self.x, self.z, self.w, self.x) + fn yzw(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.z, + z: self.w, + } } + #[inline] - fn xzwy(self) -> Vec4 { - Vec4::new(self.x, self.z, self.w, self.y) + fn ywx(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.w, + z: self.x, + } } + #[inline] - fn xzwz(self) -> Vec4 { - Vec4::new(self.x, self.z, self.w, self.z) + fn ywy(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.w, + z: self.y, + } } + #[inline] - fn xzww(self) -> Vec4 { - Vec4::new(self.x, self.z, self.w, self.w) + fn ywz(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.w, + z: self.z, + } } + #[inline] - fn xwxx(self) -> Vec4 { - Vec4::new(self.x, self.w, self.x, self.x) + fn yww(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.w, + z: self.w, + } } + #[inline] - fn xwxy(self) -> Vec4 { - Vec4::new(self.x, self.w, self.x, self.y) + fn zxx(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.x, + z: self.x, + } } + #[inline] - fn xwxz(self) -> Vec4 { - Vec4::new(self.x, self.w, self.x, self.z) + fn zxy(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.x, + z: self.y, + } } + #[inline] - fn xwxw(self) -> Vec4 { - Vec4::new(self.x, self.w, self.x, self.w) + fn zxz(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.x, + z: self.z, + } } + #[inline] - fn xwyx(self) -> Vec4 { - Vec4::new(self.x, self.w, self.y, self.x) + fn zxw(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.x, + z: self.w, + } } + #[inline] - fn xwyy(self) -> Vec4 { - Vec4::new(self.x, self.w, self.y, self.y) + fn zyx(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.y, + z: self.x, + } } + #[inline] - fn xwyz(self) -> Vec4 { - Vec4::new(self.x, self.w, self.y, self.z) + fn zyy(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.y, + z: self.y, + } } + #[inline] - fn xwyw(self) -> Vec4 { - Vec4::new(self.x, self.w, self.y, self.w) + fn zyz(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.y, + z: self.z, + } } + #[inline] - fn xwzx(self) -> Vec4 { - Vec4::new(self.x, self.w, self.z, self.x) + fn zyw(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.y, + z: self.w, + } } + #[inline] - fn xwzy(self) -> Vec4 { - Vec4::new(self.x, self.w, self.z, self.y) + fn zzx(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.z, + z: self.x, + } } + #[inline] - fn xwzz(self) -> Vec4 { - Vec4::new(self.x, self.w, self.z, self.z) + fn zzy(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.z, + z: self.y, + } } + #[inline] - fn xwzw(self) -> Vec4 { - Vec4::new(self.x, self.w, self.z, self.w) + fn zzz(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.z, + z: self.z, + } } + #[inline] - fn xwwx(self) -> Vec4 { - Vec4::new(self.x, self.w, self.w, self.x) + fn zzw(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.z, + z: self.w, + } } + #[inline] - fn xwwy(self) -> Vec4 { - Vec4::new(self.x, self.w, self.w, self.y) + fn zwx(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.w, + z: self.x, + } } + #[inline] - fn xwwz(self) -> Vec4 { - Vec4::new(self.x, self.w, self.w, self.z) + fn zwy(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.w, + z: self.y, + } } + #[inline] - fn xwww(self) -> Vec4 { - Vec4::new(self.x, self.w, self.w, self.w) + fn zwz(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.w, + z: self.z, + } } + #[inline] - fn yxxx(self) -> Vec4 { - Vec4::new(self.y, self.x, self.x, self.x) + fn zww(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.w, + z: self.w, + } } + #[inline] - fn yxxy(self) -> Vec4 { - Vec4::new(self.y, self.x, self.x, self.y) + fn wxx(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.x, + z: self.x, + } } + #[inline] - fn yxxz(self) -> Vec4 { - Vec4::new(self.y, self.x, self.x, self.z) + fn wxy(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.x, + z: self.y, + } } + #[inline] - fn yxxw(self) -> Vec4 { - Vec4::new(self.y, self.x, self.x, self.w) + fn wxz(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.x, + z: self.z, + } } + #[inline] - fn yxyx(self) -> Vec4 { - Vec4::new(self.y, self.x, self.y, self.x) + fn wxw(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.x, + z: self.w, + } } + #[inline] - fn yxyy(self) -> Vec4 { - Vec4::new(self.y, self.x, self.y, self.y) + fn wyx(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.y, + z: self.x, + } } + #[inline] - fn yxyz(self) -> Vec4 { - Vec4::new(self.y, self.x, self.y, self.z) + fn wyy(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.y, + z: self.y, + } } + #[inline] - fn yxyw(self) -> Vec4 { - Vec4::new(self.y, self.x, self.y, self.w) + fn wyz(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.y, + z: self.z, + } } + #[inline] - fn yxzx(self) -> Vec4 { - Vec4::new(self.y, self.x, self.z, self.x) + fn wyw(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.y, + z: self.w, + } } + #[inline] - fn yxzy(self) -> Vec4 { - Vec4::new(self.y, self.x, self.z, self.y) + fn wzx(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.z, + z: self.x, + } } + #[inline] - fn yxzz(self) -> Vec4 { - Vec4::new(self.y, self.x, self.z, self.z) + fn wzy(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.z, + z: self.y, + } } + #[inline] - fn yxzw(self) -> Vec4 { - Vec4::new(self.y, self.x, self.z, self.w) + fn wzz(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.z, + z: self.z, + } } + #[inline] - fn yxwx(self) -> Vec4 { - Vec4::new(self.y, self.x, self.w, self.x) + fn wzw(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.z, + z: self.w, + } } + #[inline] - fn yxwy(self) -> Vec4 { - Vec4::new(self.y, self.x, self.w, self.y) + fn wwx(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.w, + z: self.x, + } } + #[inline] - fn yxwz(self) -> Vec4 { - Vec4::new(self.y, self.x, self.w, self.z) + fn wwy(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.w, + z: self.y, + } } + #[inline] - fn yxww(self) -> Vec4 { - Vec4::new(self.y, self.x, self.w, self.w) + fn wwz(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.w, + z: self.z, + } } + #[inline] - fn yyxx(self) -> Vec4 { - Vec4::new(self.y, self.y, self.x, self.x) + fn www(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.w, + z: self.w, + } } + #[inline] - fn yyxy(self) -> Vec4 { - Vec4::new(self.y, self.y, self.x, self.y) + fn xxxx(self) -> Vec4 { + Vec4::new(self.x, self.x, self.x, self.x) } + #[inline] - fn yyxz(self) -> Vec4 { - Vec4::new(self.y, self.y, self.x, self.z) + fn xxxy(self) -> Vec4 { + Vec4::new(self.x, self.x, self.x, self.y) } + #[inline] - fn yyxw(self) -> Vec4 { - Vec4::new(self.y, self.y, self.x, self.w) + fn xxxz(self) -> Vec4 { + Vec4::new(self.x, self.x, self.x, self.z) } + #[inline] - fn yyyx(self) -> Vec4 { - Vec4::new(self.y, self.y, self.y, self.x) + fn xxxw(self) -> Vec4 { + Vec4::new(self.x, self.x, self.x, self.w) } + #[inline] - fn yyyy(self) -> Vec4 { - Vec4::new(self.y, self.y, self.y, self.y) + fn xxyx(self) -> Vec4 { + Vec4::new(self.x, self.x, self.y, self.x) } + #[inline] - fn yyyz(self) -> Vec4 { - Vec4::new(self.y, self.y, self.y, self.z) + fn xxyy(self) -> Vec4 { + Vec4::new(self.x, self.x, self.y, self.y) } + #[inline] - fn yyyw(self) -> Vec4 { - Vec4::new(self.y, self.y, self.y, self.w) + fn xxyz(self) -> Vec4 { + Vec4::new(self.x, self.x, self.y, self.z) } + #[inline] - fn yyzx(self) -> Vec4 { - Vec4::new(self.y, self.y, self.z, self.x) + fn xxyw(self) -> Vec4 { + Vec4::new(self.x, self.x, self.y, self.w) } + #[inline] - fn yyzy(self) -> Vec4 { - Vec4::new(self.y, self.y, self.z, self.y) + fn xxzx(self) -> Vec4 { + Vec4::new(self.x, self.x, self.z, self.x) } + #[inline] - fn yyzz(self) -> Vec4 { - Vec4::new(self.y, self.y, self.z, self.z) + fn xxzy(self) -> Vec4 { + Vec4::new(self.x, self.x, self.z, self.y) } + #[inline] - fn yyzw(self) -> Vec4 { - Vec4::new(self.y, self.y, self.z, self.w) + fn xxzz(self) -> Vec4 { + Vec4::new(self.x, self.x, self.z, self.z) } + #[inline] - fn yywx(self) -> Vec4 { - Vec4::new(self.y, self.y, self.w, self.x) + fn xxzw(self) -> Vec4 { + Vec4::new(self.x, self.x, self.z, self.w) } + #[inline] - fn yywy(self) -> Vec4 { - Vec4::new(self.y, self.y, self.w, self.y) + fn xxwx(self) -> Vec4 { + Vec4::new(self.x, self.x, self.w, self.x) } + #[inline] - fn yywz(self) -> Vec4 { - Vec4::new(self.y, self.y, self.w, self.z) + fn xxwy(self) -> Vec4 { + Vec4::new(self.x, self.x, self.w, self.y) } + #[inline] - fn yyww(self) -> Vec4 { - Vec4::new(self.y, self.y, self.w, self.w) + fn xxwz(self) -> Vec4 { + Vec4::new(self.x, self.x, self.w, self.z) } + #[inline] - fn yzxx(self) -> Vec4 { - Vec4::new(self.y, self.z, self.x, self.x) + fn xxww(self) -> Vec4 { + Vec4::new(self.x, self.x, self.w, self.w) } + #[inline] - fn yzxy(self) -> Vec4 { - Vec4::new(self.y, self.z, self.x, self.y) + fn xyxx(self) -> Vec4 { + Vec4::new(self.x, self.y, self.x, self.x) } + #[inline] - fn yzxz(self) -> Vec4 { - Vec4::new(self.y, self.z, self.x, self.z) + fn xyxy(self) -> Vec4 { + Vec4::new(self.x, self.y, self.x, self.y) } + #[inline] - fn yzxw(self) -> Vec4 { - Vec4::new(self.y, self.z, self.x, self.w) + fn xyxz(self) -> Vec4 { + Vec4::new(self.x, self.y, self.x, self.z) } + #[inline] - fn yzyx(self) -> Vec4 { - Vec4::new(self.y, self.z, self.y, self.x) + fn xyxw(self) -> Vec4 { + Vec4::new(self.x, self.y, self.x, self.w) } + #[inline] - fn yzyy(self) -> Vec4 { - Vec4::new(self.y, self.z, self.y, self.y) + fn xyyx(self) -> Vec4 { + Vec4::new(self.x, self.y, self.y, self.x) } + #[inline] - fn yzyz(self) -> Vec4 { - Vec4::new(self.y, self.z, self.y, self.z) + fn xyyy(self) -> Vec4 { + Vec4::new(self.x, self.y, self.y, self.y) } + #[inline] - fn yzyw(self) -> Vec4 { - Vec4::new(self.y, self.z, self.y, self.w) + fn xyyz(self) -> Vec4 { + Vec4::new(self.x, self.y, self.y, self.z) } + #[inline] - fn yzzx(self) -> Vec4 { - Vec4::new(self.y, self.z, self.z, self.x) + fn xyyw(self) -> Vec4 { + Vec4::new(self.x, self.y, self.y, self.w) } + #[inline] - fn yzzy(self) -> Vec4 { - Vec4::new(self.y, self.z, self.z, self.y) + fn xyzx(self) -> Vec4 { + Vec4::new(self.x, self.y, self.z, self.x) } + #[inline] - fn yzzz(self) -> Vec4 { - Vec4::new(self.y, self.z, self.z, self.z) + fn xyzy(self) -> Vec4 { + Vec4::new(self.x, self.y, self.z, self.y) } + #[inline] - fn yzzw(self) -> Vec4 { - Vec4::new(self.y, self.z, self.z, self.w) + fn xyzz(self) -> Vec4 { + Vec4::new(self.x, self.y, self.z, self.z) } + #[inline] - fn yzwx(self) -> Vec4 { - Vec4::new(self.y, self.z, self.w, self.x) + fn xyzw(self) -> Vec4 { + Vec4::new(self.x, self.y, self.z, self.w) } + #[inline] - fn yzwy(self) -> Vec4 { - Vec4::new(self.y, self.z, self.w, self.y) + fn xywx(self) -> Vec4 { + Vec4::new(self.x, self.y, self.w, self.x) } + #[inline] - fn yzwz(self) -> Vec4 { - Vec4::new(self.y, self.z, self.w, self.z) + fn xywy(self) -> Vec4 { + Vec4::new(self.x, self.y, self.w, self.y) } + #[inline] - fn yzww(self) -> Vec4 { - Vec4::new(self.y, self.z, self.w, self.w) + fn xywz(self) -> Vec4 { + Vec4::new(self.x, self.y, self.w, self.z) } + #[inline] - fn ywxx(self) -> Vec4 { - Vec4::new(self.y, self.w, self.x, self.x) + fn xyww(self) -> Vec4 { + Vec4::new(self.x, self.y, self.w, self.w) } + #[inline] - fn ywxy(self) -> Vec4 { - Vec4::new(self.y, self.w, self.x, self.y) + fn xzxx(self) -> Vec4 { + Vec4::new(self.x, self.z, self.x, self.x) } + #[inline] - fn ywxz(self) -> Vec4 { - Vec4::new(self.y, self.w, self.x, self.z) + fn xzxy(self) -> Vec4 { + Vec4::new(self.x, self.z, self.x, self.y) } + #[inline] - fn ywxw(self) -> Vec4 { - Vec4::new(self.y, self.w, self.x, self.w) + fn xzxz(self) -> Vec4 { + Vec4::new(self.x, self.z, self.x, self.z) } + #[inline] - fn ywyx(self) -> Vec4 { - Vec4::new(self.y, self.w, self.y, self.x) + fn xzxw(self) -> Vec4 { + Vec4::new(self.x, self.z, self.x, self.w) } + #[inline] - fn ywyy(self) -> Vec4 { - Vec4::new(self.y, self.w, self.y, self.y) + fn xzyx(self) -> Vec4 { + Vec4::new(self.x, self.z, self.y, self.x) } + #[inline] - fn ywyz(self) -> Vec4 { - Vec4::new(self.y, self.w, self.y, self.z) + fn xzyy(self) -> Vec4 { + Vec4::new(self.x, self.z, self.y, self.y) } + #[inline] - fn ywyw(self) -> Vec4 { - Vec4::new(self.y, self.w, self.y, self.w) + fn xzyz(self) -> Vec4 { + Vec4::new(self.x, self.z, self.y, self.z) } + #[inline] - fn ywzx(self) -> Vec4 { - Vec4::new(self.y, self.w, self.z, self.x) + fn xzyw(self) -> Vec4 { + Vec4::new(self.x, self.z, self.y, self.w) } + #[inline] - fn ywzy(self) -> Vec4 { - Vec4::new(self.y, self.w, self.z, self.y) + fn xzzx(self) -> Vec4 { + Vec4::new(self.x, self.z, self.z, self.x) } + #[inline] - fn ywzz(self) -> Vec4 { - Vec4::new(self.y, self.w, self.z, self.z) + fn xzzy(self) -> Vec4 { + Vec4::new(self.x, self.z, self.z, self.y) } + #[inline] - fn ywzw(self) -> Vec4 { - Vec4::new(self.y, self.w, self.z, self.w) + fn xzzz(self) -> Vec4 { + Vec4::new(self.x, self.z, self.z, self.z) } + #[inline] - fn ywwx(self) -> Vec4 { - Vec4::new(self.y, self.w, self.w, self.x) + fn xzzw(self) -> Vec4 { + Vec4::new(self.x, self.z, self.z, self.w) } + #[inline] - fn ywwy(self) -> Vec4 { - Vec4::new(self.y, self.w, self.w, self.y) + fn xzwx(self) -> Vec4 { + Vec4::new(self.x, self.z, self.w, self.x) } + #[inline] - fn ywwz(self) -> Vec4 { - Vec4::new(self.y, self.w, self.w, self.z) + fn xzwy(self) -> Vec4 { + Vec4::new(self.x, self.z, self.w, self.y) } + #[inline] - fn ywww(self) -> Vec4 { - Vec4::new(self.y, self.w, self.w, self.w) + fn xzwz(self) -> Vec4 { + Vec4::new(self.x, self.z, self.w, self.z) } + #[inline] - fn zxxx(self) -> Vec4 { - Vec4::new(self.z, self.x, self.x, self.x) + fn xzww(self) -> Vec4 { + Vec4::new(self.x, self.z, self.w, self.w) } + #[inline] - fn zxxy(self) -> Vec4 { - Vec4::new(self.z, self.x, self.x, self.y) + fn xwxx(self) -> Vec4 { + Vec4::new(self.x, self.w, self.x, self.x) } + #[inline] - fn zxxz(self) -> Vec4 { - Vec4::new(self.z, self.x, self.x, self.z) + fn xwxy(self) -> Vec4 { + Vec4::new(self.x, self.w, self.x, self.y) } + #[inline] - fn zxxw(self) -> Vec4 { - Vec4::new(self.z, self.x, self.x, self.w) + fn xwxz(self) -> Vec4 { + Vec4::new(self.x, self.w, self.x, self.z) } + #[inline] - fn zxyx(self) -> Vec4 { - Vec4::new(self.z, self.x, self.y, self.x) + fn xwxw(self) -> Vec4 { + Vec4::new(self.x, self.w, self.x, self.w) } + #[inline] - fn zxyy(self) -> Vec4 { - Vec4::new(self.z, self.x, self.y, self.y) + fn xwyx(self) -> Vec4 { + Vec4::new(self.x, self.w, self.y, self.x) } + #[inline] - fn zxyz(self) -> Vec4 { - Vec4::new(self.z, self.x, self.y, self.z) + fn xwyy(self) -> Vec4 { + Vec4::new(self.x, self.w, self.y, self.y) } + #[inline] - fn zxyw(self) -> Vec4 { - Vec4::new(self.z, self.x, self.y, self.w) + fn xwyz(self) -> Vec4 { + Vec4::new(self.x, self.w, self.y, self.z) } + #[inline] - fn zxzx(self) -> Vec4 { - Vec4::new(self.z, self.x, self.z, self.x) + fn xwyw(self) -> Vec4 { + Vec4::new(self.x, self.w, self.y, self.w) } + #[inline] - fn zxzy(self) -> Vec4 { - Vec4::new(self.z, self.x, self.z, self.y) + fn xwzx(self) -> Vec4 { + Vec4::new(self.x, self.w, self.z, self.x) } + #[inline] - fn zxzz(self) -> Vec4 { - Vec4::new(self.z, self.x, self.z, self.z) + fn xwzy(self) -> Vec4 { + Vec4::new(self.x, self.w, self.z, self.y) } + #[inline] - fn zxzw(self) -> Vec4 { - Vec4::new(self.z, self.x, self.z, self.w) + fn xwzz(self) -> Vec4 { + Vec4::new(self.x, self.w, self.z, self.z) } + #[inline] - fn zxwx(self) -> Vec4 { - Vec4::new(self.z, self.x, self.w, self.x) + fn xwzw(self) -> Vec4 { + Vec4::new(self.x, self.w, self.z, self.w) } + #[inline] - fn zxwy(self) -> Vec4 { - Vec4::new(self.z, self.x, self.w, self.y) + fn xwwx(self) -> Vec4 { + Vec4::new(self.x, self.w, self.w, self.x) } + #[inline] - fn zxwz(self) -> Vec4 { - Vec4::new(self.z, self.x, self.w, self.z) + fn xwwy(self) -> Vec4 { + Vec4::new(self.x, self.w, self.w, self.y) } + #[inline] - fn zxww(self) -> Vec4 { - Vec4::new(self.z, self.x, self.w, self.w) + fn xwwz(self) -> Vec4 { + Vec4::new(self.x, self.w, self.w, self.z) } + #[inline] - fn zyxx(self) -> Vec4 { - Vec4::new(self.z, self.y, self.x, self.x) + fn xwww(self) -> Vec4 { + Vec4::new(self.x, self.w, self.w, self.w) } + #[inline] - fn zyxy(self) -> Vec4 { - Vec4::new(self.z, self.y, self.x, self.y) + fn yxxx(self) -> Vec4 { + Vec4::new(self.y, self.x, self.x, self.x) } + #[inline] - fn zyxz(self) -> Vec4 { - Vec4::new(self.z, self.y, self.x, self.z) + fn yxxy(self) -> Vec4 { + Vec4::new(self.y, self.x, self.x, self.y) } + #[inline] - fn zyxw(self) -> Vec4 { - Vec4::new(self.z, self.y, self.x, self.w) + fn yxxz(self) -> Vec4 { + Vec4::new(self.y, self.x, self.x, self.z) } + #[inline] - fn zyyx(self) -> Vec4 { - Vec4::new(self.z, self.y, self.y, self.x) + fn yxxw(self) -> Vec4 { + Vec4::new(self.y, self.x, self.x, self.w) } + #[inline] - fn zyyy(self) -> Vec4 { - Vec4::new(self.z, self.y, self.y, self.y) + fn yxyx(self) -> Vec4 { + Vec4::new(self.y, self.x, self.y, self.x) } + #[inline] - fn zyyz(self) -> Vec4 { - Vec4::new(self.z, self.y, self.y, self.z) + fn yxyy(self) -> Vec4 { + Vec4::new(self.y, self.x, self.y, self.y) } + #[inline] - fn zyyw(self) -> Vec4 { - Vec4::new(self.z, self.y, self.y, self.w) + fn yxyz(self) -> Vec4 { + Vec4::new(self.y, self.x, self.y, self.z) } + #[inline] - fn zyzx(self) -> Vec4 { - Vec4::new(self.z, self.y, self.z, self.x) + fn yxyw(self) -> Vec4 { + Vec4::new(self.y, self.x, self.y, self.w) } + #[inline] - fn zyzy(self) -> Vec4 { - Vec4::new(self.z, self.y, self.z, self.y) + fn yxzx(self) -> Vec4 { + Vec4::new(self.y, self.x, self.z, self.x) } + #[inline] - fn zyzz(self) -> Vec4 { - Vec4::new(self.z, self.y, self.z, self.z) + fn yxzy(self) -> Vec4 { + Vec4::new(self.y, self.x, self.z, self.y) } + #[inline] - fn zyzw(self) -> Vec4 { - Vec4::new(self.z, self.y, self.z, self.w) + fn yxzz(self) -> Vec4 { + Vec4::new(self.y, self.x, self.z, self.z) } + #[inline] - fn zywx(self) -> Vec4 { - Vec4::new(self.z, self.y, self.w, self.x) + fn yxzw(self) -> Vec4 { + Vec4::new(self.y, self.x, self.z, self.w) } + #[inline] - fn zywy(self) -> Vec4 { - Vec4::new(self.z, self.y, self.w, self.y) + fn yxwx(self) -> Vec4 { + Vec4::new(self.y, self.x, self.w, self.x) } + #[inline] - fn zywz(self) -> Vec4 { - Vec4::new(self.z, self.y, self.w, self.z) + fn yxwy(self) -> Vec4 { + Vec4::new(self.y, self.x, self.w, self.y) } + #[inline] - fn zyww(self) -> Vec4 { - Vec4::new(self.z, self.y, self.w, self.w) + fn yxwz(self) -> Vec4 { + Vec4::new(self.y, self.x, self.w, self.z) } + #[inline] - fn zzxx(self) -> Vec4 { - Vec4::new(self.z, self.z, self.x, self.x) + fn yxww(self) -> Vec4 { + Vec4::new(self.y, self.x, self.w, self.w) } + #[inline] - fn zzxy(self) -> Vec4 { - Vec4::new(self.z, self.z, self.x, self.y) + fn yyxx(self) -> Vec4 { + Vec4::new(self.y, self.y, self.x, self.x) } + #[inline] - fn zzxz(self) -> Vec4 { - Vec4::new(self.z, self.z, self.x, self.z) + fn yyxy(self) -> Vec4 { + Vec4::new(self.y, self.y, self.x, self.y) } + #[inline] - fn zzxw(self) -> Vec4 { - Vec4::new(self.z, self.z, self.x, self.w) + fn yyxz(self) -> Vec4 { + Vec4::new(self.y, self.y, self.x, self.z) } + #[inline] - fn zzyx(self) -> Vec4 { - Vec4::new(self.z, self.z, self.y, self.x) + fn yyxw(self) -> Vec4 { + Vec4::new(self.y, self.y, self.x, self.w) } + #[inline] - fn zzyy(self) -> Vec4 { - Vec4::new(self.z, self.z, self.y, self.y) + fn yyyx(self) -> Vec4 { + Vec4::new(self.y, self.y, self.y, self.x) } + #[inline] - fn zzyz(self) -> Vec4 { - Vec4::new(self.z, self.z, self.y, self.z) + fn yyyy(self) -> Vec4 { + Vec4::new(self.y, self.y, self.y, self.y) } + #[inline] - fn zzyw(self) -> Vec4 { - Vec4::new(self.z, self.z, self.y, self.w) + fn yyyz(self) -> Vec4 { + Vec4::new(self.y, self.y, self.y, self.z) } + #[inline] - fn zzzx(self) -> Vec4 { - Vec4::new(self.z, self.z, self.z, self.x) + fn yyyw(self) -> Vec4 { + Vec4::new(self.y, self.y, self.y, self.w) } + #[inline] - fn zzzy(self) -> Vec4 { - Vec4::new(self.z, self.z, self.z, self.y) + fn yyzx(self) -> Vec4 { + Vec4::new(self.y, self.y, self.z, self.x) } + #[inline] - fn zzzz(self) -> Vec4 { - Vec4::new(self.z, self.z, self.z, self.z) + fn yyzy(self) -> Vec4 { + Vec4::new(self.y, self.y, self.z, self.y) } + #[inline] - fn zzzw(self) -> Vec4 { - Vec4::new(self.z, self.z, self.z, self.w) + fn yyzz(self) -> Vec4 { + Vec4::new(self.y, self.y, self.z, self.z) } + #[inline] - fn zzwx(self) -> Vec4 { - Vec4::new(self.z, self.z, self.w, self.x) + fn yyzw(self) -> Vec4 { + Vec4::new(self.y, self.y, self.z, self.w) } + #[inline] - fn zzwy(self) -> Vec4 { - Vec4::new(self.z, self.z, self.w, self.y) + fn yywx(self) -> Vec4 { + Vec4::new(self.y, self.y, self.w, self.x) } + #[inline] - fn zzwz(self) -> Vec4 { - Vec4::new(self.z, self.z, self.w, self.z) + fn yywy(self) -> Vec4 { + Vec4::new(self.y, self.y, self.w, self.y) } + #[inline] - fn zzww(self) -> Vec4 { - Vec4::new(self.z, self.z, self.w, self.w) + fn yywz(self) -> Vec4 { + Vec4::new(self.y, self.y, self.w, self.z) } + #[inline] - fn zwxx(self) -> Vec4 { - Vec4::new(self.z, self.w, self.x, self.x) + fn yyww(self) -> Vec4 { + Vec4::new(self.y, self.y, self.w, self.w) } + #[inline] - fn zwxy(self) -> Vec4 { - Vec4::new(self.z, self.w, self.x, self.y) + fn yzxx(self) -> Vec4 { + Vec4::new(self.y, self.z, self.x, self.x) } + #[inline] - fn zwxz(self) -> Vec4 { - Vec4::new(self.z, self.w, self.x, self.z) + fn yzxy(self) -> Vec4 { + Vec4::new(self.y, self.z, self.x, self.y) } + #[inline] - fn zwxw(self) -> Vec4 { - Vec4::new(self.z, self.w, self.x, self.w) + fn yzxz(self) -> Vec4 { + Vec4::new(self.y, self.z, self.x, self.z) } + #[inline] - fn zwyx(self) -> Vec4 { - Vec4::new(self.z, self.w, self.y, self.x) + fn yzxw(self) -> Vec4 { + Vec4::new(self.y, self.z, self.x, self.w) } + #[inline] - fn zwyy(self) -> Vec4 { - Vec4::new(self.z, self.w, self.y, self.y) + fn yzyx(self) -> Vec4 { + Vec4::new(self.y, self.z, self.y, self.x) } + #[inline] - fn zwyz(self) -> Vec4 { - Vec4::new(self.z, self.w, self.y, self.z) + fn yzyy(self) -> Vec4 { + Vec4::new(self.y, self.z, self.y, self.y) } + #[inline] - fn zwyw(self) -> Vec4 { - Vec4::new(self.z, self.w, self.y, self.w) + fn yzyz(self) -> Vec4 { + Vec4::new(self.y, self.z, self.y, self.z) } + #[inline] - fn zwzx(self) -> Vec4 { - Vec4::new(self.z, self.w, self.z, self.x) + fn yzyw(self) -> Vec4 { + Vec4::new(self.y, self.z, self.y, self.w) } + #[inline] - fn zwzy(self) -> Vec4 { - Vec4::new(self.z, self.w, self.z, self.y) + fn yzzx(self) -> Vec4 { + Vec4::new(self.y, self.z, self.z, self.x) } + #[inline] - fn zwzz(self) -> Vec4 { - Vec4::new(self.z, self.w, self.z, self.z) + fn yzzy(self) -> Vec4 { + Vec4::new(self.y, self.z, self.z, self.y) } + #[inline] - fn zwzw(self) -> Vec4 { - Vec4::new(self.z, self.w, self.z, self.w) + fn yzzz(self) -> Vec4 { + Vec4::new(self.y, self.z, self.z, self.z) } + #[inline] - fn zwwx(self) -> Vec4 { - Vec4::new(self.z, self.w, self.w, self.x) + fn yzzw(self) -> Vec4 { + Vec4::new(self.y, self.z, self.z, self.w) } + #[inline] - fn zwwy(self) -> Vec4 { - Vec4::new(self.z, self.w, self.w, self.y) + fn yzwx(self) -> Vec4 { + Vec4::new(self.y, self.z, self.w, self.x) } + #[inline] - fn zwwz(self) -> Vec4 { - Vec4::new(self.z, self.w, self.w, self.z) + fn yzwy(self) -> Vec4 { + Vec4::new(self.y, self.z, self.w, self.y) } + #[inline] - fn zwww(self) -> Vec4 { - Vec4::new(self.z, self.w, self.w, self.w) + fn yzwz(self) -> Vec4 { + Vec4::new(self.y, self.z, self.w, self.z) } + #[inline] - fn wxxx(self) -> Vec4 { - Vec4::new(self.w, self.x, self.x, self.x) + fn yzww(self) -> Vec4 { + Vec4::new(self.y, self.z, self.w, self.w) } + #[inline] - fn wxxy(self) -> Vec4 { - Vec4::new(self.w, self.x, self.x, self.y) + fn ywxx(self) -> Vec4 { + Vec4::new(self.y, self.w, self.x, self.x) } + #[inline] - fn wxxz(self) -> Vec4 { - Vec4::new(self.w, self.x, self.x, self.z) + fn ywxy(self) -> Vec4 { + Vec4::new(self.y, self.w, self.x, self.y) } + #[inline] - fn wxxw(self) -> Vec4 { - Vec4::new(self.w, self.x, self.x, self.w) + fn ywxz(self) -> Vec4 { + Vec4::new(self.y, self.w, self.x, self.z) } + #[inline] - fn wxyx(self) -> Vec4 { - Vec4::new(self.w, self.x, self.y, self.x) + fn ywxw(self) -> Vec4 { + Vec4::new(self.y, self.w, self.x, self.w) } + #[inline] - fn wxyy(self) -> Vec4 { - Vec4::new(self.w, self.x, self.y, self.y) + fn ywyx(self) -> Vec4 { + Vec4::new(self.y, self.w, self.y, self.x) } + #[inline] - fn wxyz(self) -> Vec4 { - Vec4::new(self.w, self.x, self.y, self.z) + fn ywyy(self) -> Vec4 { + Vec4::new(self.y, self.w, self.y, self.y) } + #[inline] - fn wxyw(self) -> Vec4 { - Vec4::new(self.w, self.x, self.y, self.w) + fn ywyz(self) -> Vec4 { + Vec4::new(self.y, self.w, self.y, self.z) } + #[inline] - fn wxzx(self) -> Vec4 { - Vec4::new(self.w, self.x, self.z, self.x) + fn ywyw(self) -> Vec4 { + Vec4::new(self.y, self.w, self.y, self.w) } + #[inline] - fn wxzy(self) -> Vec4 { - Vec4::new(self.w, self.x, self.z, self.y) + fn ywzx(self) -> Vec4 { + Vec4::new(self.y, self.w, self.z, self.x) } + #[inline] - fn wxzz(self) -> Vec4 { - Vec4::new(self.w, self.x, self.z, self.z) + fn ywzy(self) -> Vec4 { + Vec4::new(self.y, self.w, self.z, self.y) } + #[inline] - fn wxzw(self) -> Vec4 { - Vec4::new(self.w, self.x, self.z, self.w) + fn ywzz(self) -> Vec4 { + Vec4::new(self.y, self.w, self.z, self.z) } + #[inline] - fn wxwx(self) -> Vec4 { - Vec4::new(self.w, self.x, self.w, self.x) + fn ywzw(self) -> Vec4 { + Vec4::new(self.y, self.w, self.z, self.w) } + #[inline] - fn wxwy(self) -> Vec4 { - Vec4::new(self.w, self.x, self.w, self.y) + fn ywwx(self) -> Vec4 { + Vec4::new(self.y, self.w, self.w, self.x) } + #[inline] - fn wxwz(self) -> Vec4 { - Vec4::new(self.w, self.x, self.w, self.z) + fn ywwy(self) -> Vec4 { + Vec4::new(self.y, self.w, self.w, self.y) } + #[inline] - fn wxww(self) -> Vec4 { - Vec4::new(self.w, self.x, self.w, self.w) + fn ywwz(self) -> Vec4 { + Vec4::new(self.y, self.w, self.w, self.z) } + #[inline] - fn wyxx(self) -> Vec4 { - Vec4::new(self.w, self.y, self.x, self.x) + fn ywww(self) -> Vec4 { + Vec4::new(self.y, self.w, self.w, self.w) } + #[inline] - fn wyxy(self) -> Vec4 { - Vec4::new(self.w, self.y, self.x, self.y) + fn zxxx(self) -> Vec4 { + Vec4::new(self.z, self.x, self.x, self.x) } + #[inline] - fn wyxz(self) -> Vec4 { - Vec4::new(self.w, self.y, self.x, self.z) + fn zxxy(self) -> Vec4 { + Vec4::new(self.z, self.x, self.x, self.y) } + #[inline] - fn wyxw(self) -> Vec4 { - Vec4::new(self.w, self.y, self.x, self.w) + fn zxxz(self) -> Vec4 { + Vec4::new(self.z, self.x, self.x, self.z) } + #[inline] - fn wyyx(self) -> Vec4 { - Vec4::new(self.w, self.y, self.y, self.x) + fn zxxw(self) -> Vec4 { + Vec4::new(self.z, self.x, self.x, self.w) } + #[inline] - fn wyyy(self) -> Vec4 { - Vec4::new(self.w, self.y, self.y, self.y) + fn zxyx(self) -> Vec4 { + Vec4::new(self.z, self.x, self.y, self.x) } + #[inline] - fn wyyz(self) -> Vec4 { - Vec4::new(self.w, self.y, self.y, self.z) + fn zxyy(self) -> Vec4 { + Vec4::new(self.z, self.x, self.y, self.y) } + #[inline] - fn wyyw(self) -> Vec4 { - Vec4::new(self.w, self.y, self.y, self.w) + fn zxyz(self) -> Vec4 { + Vec4::new(self.z, self.x, self.y, self.z) } + #[inline] - fn wyzx(self) -> Vec4 { - Vec4::new(self.w, self.y, self.z, self.x) + fn zxyw(self) -> Vec4 { + Vec4::new(self.z, self.x, self.y, self.w) } + #[inline] - fn wyzy(self) -> Vec4 { - Vec4::new(self.w, self.y, self.z, self.y) + fn zxzx(self) -> Vec4 { + Vec4::new(self.z, self.x, self.z, self.x) + } + + #[inline] + fn zxzy(self) -> Vec4 { + Vec4::new(self.z, self.x, self.z, self.y) } + #[inline] - fn wyzz(self) -> Vec4 { - Vec4::new(self.w, self.y, self.z, self.z) + fn zxzz(self) -> Vec4 { + Vec4::new(self.z, self.x, self.z, self.z) } + #[inline] - fn wyzw(self) -> Vec4 { - Vec4::new(self.w, self.y, self.z, self.w) + fn zxzw(self) -> Vec4 { + Vec4::new(self.z, self.x, self.z, self.w) } + #[inline] - fn wywx(self) -> Vec4 { - Vec4::new(self.w, self.y, self.w, self.x) + fn zxwx(self) -> Vec4 { + Vec4::new(self.z, self.x, self.w, self.x) } + #[inline] - fn wywy(self) -> Vec4 { - Vec4::new(self.w, self.y, self.w, self.y) + fn zxwy(self) -> Vec4 { + Vec4::new(self.z, self.x, self.w, self.y) } + #[inline] - fn wywz(self) -> Vec4 { - Vec4::new(self.w, self.y, self.w, self.z) + fn zxwz(self) -> Vec4 { + Vec4::new(self.z, self.x, self.w, self.z) } + #[inline] - fn wyww(self) -> Vec4 { - Vec4::new(self.w, self.y, self.w, self.w) + fn zxww(self) -> Vec4 { + Vec4::new(self.z, self.x, self.w, self.w) } + #[inline] - fn wzxx(self) -> Vec4 { - Vec4::new(self.w, self.z, self.x, self.x) + fn zyxx(self) -> Vec4 { + Vec4::new(self.z, self.y, self.x, self.x) } + #[inline] - fn wzxy(self) -> Vec4 { - Vec4::new(self.w, self.z, self.x, self.y) + fn zyxy(self) -> Vec4 { + Vec4::new(self.z, self.y, self.x, self.y) } + #[inline] - fn wzxz(self) -> Vec4 { - Vec4::new(self.w, self.z, self.x, self.z) + fn zyxz(self) -> Vec4 { + Vec4::new(self.z, self.y, self.x, self.z) } + #[inline] - fn wzxw(self) -> Vec4 { - Vec4::new(self.w, self.z, self.x, self.w) + fn zyxw(self) -> Vec4 { + Vec4::new(self.z, self.y, self.x, self.w) } + #[inline] - fn wzyx(self) -> Vec4 { - Vec4::new(self.w, self.z, self.y, self.x) + fn zyyx(self) -> Vec4 { + Vec4::new(self.z, self.y, self.y, self.x) } + #[inline] - fn wzyy(self) -> Vec4 { - Vec4::new(self.w, self.z, self.y, self.y) + fn zyyy(self) -> Vec4 { + Vec4::new(self.z, self.y, self.y, self.y) } + #[inline] - fn wzyz(self) -> Vec4 { - Vec4::new(self.w, self.z, self.y, self.z) + fn zyyz(self) -> Vec4 { + Vec4::new(self.z, self.y, self.y, self.z) } + #[inline] - fn wzyw(self) -> Vec4 { - Vec4::new(self.w, self.z, self.y, self.w) + fn zyyw(self) -> Vec4 { + Vec4::new(self.z, self.y, self.y, self.w) } + #[inline] - fn wzzx(self) -> Vec4 { - Vec4::new(self.w, self.z, self.z, self.x) + fn zyzx(self) -> Vec4 { + Vec4::new(self.z, self.y, self.z, self.x) } + #[inline] - fn wzzy(self) -> Vec4 { - Vec4::new(self.w, self.z, self.z, self.y) + fn zyzy(self) -> Vec4 { + Vec4::new(self.z, self.y, self.z, self.y) } + #[inline] - fn wzzz(self) -> Vec4 { - Vec4::new(self.w, self.z, self.z, self.z) + fn zyzz(self) -> Vec4 { + Vec4::new(self.z, self.y, self.z, self.z) } + #[inline] - fn wzzw(self) -> Vec4 { - Vec4::new(self.w, self.z, self.z, self.w) + fn zyzw(self) -> Vec4 { + Vec4::new(self.z, self.y, self.z, self.w) } + #[inline] - fn wzwx(self) -> Vec4 { - Vec4::new(self.w, self.z, self.w, self.x) + fn zywx(self) -> Vec4 { + Vec4::new(self.z, self.y, self.w, self.x) } + #[inline] - fn wzwy(self) -> Vec4 { - Vec4::new(self.w, self.z, self.w, self.y) + fn zywy(self) -> Vec4 { + Vec4::new(self.z, self.y, self.w, self.y) } + #[inline] - fn wzwz(self) -> Vec4 { - Vec4::new(self.w, self.z, self.w, self.z) + fn zywz(self) -> Vec4 { + Vec4::new(self.z, self.y, self.w, self.z) } + #[inline] - fn wzww(self) -> Vec4 { - Vec4::new(self.w, self.z, self.w, self.w) + fn zyww(self) -> Vec4 { + Vec4::new(self.z, self.y, self.w, self.w) } + #[inline] - fn wwxx(self) -> Vec4 { - Vec4::new(self.w, self.w, self.x, self.x) + fn zzxx(self) -> Vec4 { + Vec4::new(self.z, self.z, self.x, self.x) } + #[inline] - fn wwxy(self) -> Vec4 { - Vec4::new(self.w, self.w, self.x, self.y) + fn zzxy(self) -> Vec4 { + Vec4::new(self.z, self.z, self.x, self.y) } + #[inline] - fn wwxz(self) -> Vec4 { - Vec4::new(self.w, self.w, self.x, self.z) + fn zzxz(self) -> Vec4 { + Vec4::new(self.z, self.z, self.x, self.z) } + #[inline] - fn wwxw(self) -> Vec4 { - Vec4::new(self.w, self.w, self.x, self.w) + fn zzxw(self) -> Vec4 { + Vec4::new(self.z, self.z, self.x, self.w) } + #[inline] - fn wwyx(self) -> Vec4 { - Vec4::new(self.w, self.w, self.y, self.x) + fn zzyx(self) -> Vec4 { + Vec4::new(self.z, self.z, self.y, self.x) } + #[inline] - fn wwyy(self) -> Vec4 { - Vec4::new(self.w, self.w, self.y, self.y) + fn zzyy(self) -> Vec4 { + Vec4::new(self.z, self.z, self.y, self.y) } + #[inline] - fn wwyz(self) -> Vec4 { - Vec4::new(self.w, self.w, self.y, self.z) + fn zzyz(self) -> Vec4 { + Vec4::new(self.z, self.z, self.y, self.z) } + #[inline] - fn wwyw(self) -> Vec4 { - Vec4::new(self.w, self.w, self.y, self.w) + fn zzyw(self) -> Vec4 { + Vec4::new(self.z, self.z, self.y, self.w) } + #[inline] - fn wwzx(self) -> Vec4 { - Vec4::new(self.w, self.w, self.z, self.x) + fn zzzx(self) -> Vec4 { + Vec4::new(self.z, self.z, self.z, self.x) } + #[inline] - fn wwzy(self) -> Vec4 { - Vec4::new(self.w, self.w, self.z, self.y) + fn zzzy(self) -> Vec4 { + Vec4::new(self.z, self.z, self.z, self.y) } + #[inline] - fn wwzz(self) -> Vec4 { - Vec4::new(self.w, self.w, self.z, self.z) + fn zzzz(self) -> Vec4 { + Vec4::new(self.z, self.z, self.z, self.z) } + #[inline] - fn wwzw(self) -> Vec4 { - Vec4::new(self.w, self.w, self.z, self.w) + fn zzzw(self) -> Vec4 { + Vec4::new(self.z, self.z, self.z, self.w) } + #[inline] - fn wwwx(self) -> Vec4 { - Vec4::new(self.w, self.w, self.w, self.x) + fn zzwx(self) -> Vec4 { + Vec4::new(self.z, self.z, self.w, self.x) } + #[inline] - fn wwwy(self) -> Vec4 { - Vec4::new(self.w, self.w, self.w, self.y) + fn zzwy(self) -> Vec4 { + Vec4::new(self.z, self.z, self.w, self.y) } + #[inline] - fn wwwz(self) -> Vec4 { - Vec4::new(self.w, self.w, self.w, self.z) + fn zzwz(self) -> Vec4 { + Vec4::new(self.z, self.z, self.w, self.z) } + #[inline] - fn wwww(self) -> Vec4 { - Vec4::new(self.w, self.w, self.w, self.w) + fn zzww(self) -> Vec4 { + Vec4::new(self.z, self.z, self.w, self.w) } + #[inline] - fn xxx(self) -> Vec3 { - Vec3::new(self.x, self.x, self.x) + fn zwxx(self) -> Vec4 { + Vec4::new(self.z, self.w, self.x, self.x) } + #[inline] - fn xxy(self) -> Vec3 { - Vec3::new(self.x, self.x, self.y) + fn zwxy(self) -> Vec4 { + Vec4::new(self.z, self.w, self.x, self.y) } + #[inline] - fn xxz(self) -> Vec3 { - Vec3::new(self.x, self.x, self.z) + fn zwxz(self) -> Vec4 { + Vec4::new(self.z, self.w, self.x, self.z) } + #[inline] - fn xxw(self) -> Vec3 { - Vec3::new(self.x, self.x, self.w) + fn zwxw(self) -> Vec4 { + Vec4::new(self.z, self.w, self.x, self.w) } + #[inline] - fn xyx(self) -> Vec3 { - Vec3::new(self.x, self.y, self.x) + fn zwyx(self) -> Vec4 { + Vec4::new(self.z, self.w, self.y, self.x) } + #[inline] - fn xyy(self) -> Vec3 { - Vec3::new(self.x, self.y, self.y) + fn zwyy(self) -> Vec4 { + Vec4::new(self.z, self.w, self.y, self.y) } + #[inline] - fn xyz(self) -> Vec3 { - Vec3::new(self.x, self.y, self.z) + fn zwyz(self) -> Vec4 { + Vec4::new(self.z, self.w, self.y, self.z) } + #[inline] - fn xyw(self) -> Vec3 { - Vec3::new(self.x, self.y, self.w) + fn zwyw(self) -> Vec4 { + Vec4::new(self.z, self.w, self.y, self.w) } + #[inline] - fn xzx(self) -> Vec3 { - Vec3::new(self.x, self.z, self.x) + fn zwzx(self) -> Vec4 { + Vec4::new(self.z, self.w, self.z, self.x) } + #[inline] - fn xzy(self) -> Vec3 { - Vec3::new(self.x, self.z, self.y) + fn zwzy(self) -> Vec4 { + Vec4::new(self.z, self.w, self.z, self.y) } + #[inline] - fn xzz(self) -> Vec3 { - Vec3::new(self.x, self.z, self.z) + fn zwzz(self) -> Vec4 { + Vec4::new(self.z, self.w, self.z, self.z) } + #[inline] - fn xzw(self) -> Vec3 { - Vec3::new(self.x, self.z, self.w) + fn zwzw(self) -> Vec4 { + Vec4::new(self.z, self.w, self.z, self.w) } + #[inline] - fn xwx(self) -> Vec3 { - Vec3::new(self.x, self.w, self.x) + fn zwwx(self) -> Vec4 { + Vec4::new(self.z, self.w, self.w, self.x) } + #[inline] - fn xwy(self) -> Vec3 { - Vec3::new(self.x, self.w, self.y) + fn zwwy(self) -> Vec4 { + Vec4::new(self.z, self.w, self.w, self.y) } + #[inline] - fn xwz(self) -> Vec3 { - Vec3::new(self.x, self.w, self.z) + fn zwwz(self) -> Vec4 { + Vec4::new(self.z, self.w, self.w, self.z) } + #[inline] - fn xww(self) -> Vec3 { - Vec3::new(self.x, self.w, self.w) + fn zwww(self) -> Vec4 { + Vec4::new(self.z, self.w, self.w, self.w) } + #[inline] - fn yxx(self) -> Vec3 { - Vec3::new(self.y, self.x, self.x) + fn wxxx(self) -> Vec4 { + Vec4::new(self.w, self.x, self.x, self.x) } + #[inline] - fn yxy(self) -> Vec3 { - Vec3::new(self.y, self.x, self.y) + fn wxxy(self) -> Vec4 { + Vec4::new(self.w, self.x, self.x, self.y) } + #[inline] - fn yxz(self) -> Vec3 { - Vec3::new(self.y, self.x, self.z) + fn wxxz(self) -> Vec4 { + Vec4::new(self.w, self.x, self.x, self.z) } + #[inline] - fn yxw(self) -> Vec3 { - Vec3::new(self.y, self.x, self.w) + fn wxxw(self) -> Vec4 { + Vec4::new(self.w, self.x, self.x, self.w) } + #[inline] - fn yyx(self) -> Vec3 { - Vec3::new(self.y, self.y, self.x) + fn wxyx(self) -> Vec4 { + Vec4::new(self.w, self.x, self.y, self.x) } + #[inline] - fn yyy(self) -> Vec3 { - Vec3::new(self.y, self.y, self.y) + fn wxyy(self) -> Vec4 { + Vec4::new(self.w, self.x, self.y, self.y) } + #[inline] - fn yyz(self) -> Vec3 { - Vec3::new(self.y, self.y, self.z) + fn wxyz(self) -> Vec4 { + Vec4::new(self.w, self.x, self.y, self.z) } + #[inline] - fn yyw(self) -> Vec3 { - Vec3::new(self.y, self.y, self.w) + fn wxyw(self) -> Vec4 { + Vec4::new(self.w, self.x, self.y, self.w) } + #[inline] - fn yzx(self) -> Vec3 { - Vec3::new(self.y, self.z, self.x) + fn wxzx(self) -> Vec4 { + Vec4::new(self.w, self.x, self.z, self.x) } + #[inline] - fn yzy(self) -> Vec3 { - Vec3::new(self.y, self.z, self.y) + fn wxzy(self) -> Vec4 { + Vec4::new(self.w, self.x, self.z, self.y) } + #[inline] - fn yzz(self) -> Vec3 { - Vec3::new(self.y, self.z, self.z) + fn wxzz(self) -> Vec4 { + Vec4::new(self.w, self.x, self.z, self.z) } + #[inline] - fn yzw(self) -> Vec3 { - Vec3::new(self.y, self.z, self.w) + fn wxzw(self) -> Vec4 { + Vec4::new(self.w, self.x, self.z, self.w) } + #[inline] - fn ywx(self) -> Vec3 { - Vec3::new(self.y, self.w, self.x) + fn wxwx(self) -> Vec4 { + Vec4::new(self.w, self.x, self.w, self.x) } + #[inline] - fn ywy(self) -> Vec3 { - Vec3::new(self.y, self.w, self.y) + fn wxwy(self) -> Vec4 { + Vec4::new(self.w, self.x, self.w, self.y) } + #[inline] - fn ywz(self) -> Vec3 { - Vec3::new(self.y, self.w, self.z) + fn wxwz(self) -> Vec4 { + Vec4::new(self.w, self.x, self.w, self.z) } + #[inline] - fn yww(self) -> Vec3 { - Vec3::new(self.y, self.w, self.w) + fn wxww(self) -> Vec4 { + Vec4::new(self.w, self.x, self.w, self.w) } + #[inline] - fn zxx(self) -> Vec3 { - Vec3::new(self.z, self.x, self.x) + fn wyxx(self) -> Vec4 { + Vec4::new(self.w, self.y, self.x, self.x) } + #[inline] - fn zxy(self) -> Vec3 { - Vec3::new(self.z, self.x, self.y) + fn wyxy(self) -> Vec4 { + Vec4::new(self.w, self.y, self.x, self.y) } + #[inline] - fn zxz(self) -> Vec3 { - Vec3::new(self.z, self.x, self.z) + fn wyxz(self) -> Vec4 { + Vec4::new(self.w, self.y, self.x, self.z) } + #[inline] - fn zxw(self) -> Vec3 { - Vec3::new(self.z, self.x, self.w) + fn wyxw(self) -> Vec4 { + Vec4::new(self.w, self.y, self.x, self.w) } + #[inline] - fn zyx(self) -> Vec3 { - Vec3::new(self.z, self.y, self.x) + fn wyyx(self) -> Vec4 { + Vec4::new(self.w, self.y, self.y, self.x) } + #[inline] - fn zyy(self) -> Vec3 { - Vec3::new(self.z, self.y, self.y) + fn wyyy(self) -> Vec4 { + Vec4::new(self.w, self.y, self.y, self.y) } + #[inline] - fn zyz(self) -> Vec3 { - Vec3::new(self.z, self.y, self.z) + fn wyyz(self) -> Vec4 { + Vec4::new(self.w, self.y, self.y, self.z) } + #[inline] - fn zyw(self) -> Vec3 { - Vec3::new(self.z, self.y, self.w) + fn wyyw(self) -> Vec4 { + Vec4::new(self.w, self.y, self.y, self.w) } + #[inline] - fn zzx(self) -> Vec3 { - Vec3::new(self.z, self.z, self.x) + fn wyzx(self) -> Vec4 { + Vec4::new(self.w, self.y, self.z, self.x) } + #[inline] - fn zzy(self) -> Vec3 { - Vec3::new(self.z, self.z, self.y) + fn wyzy(self) -> Vec4 { + Vec4::new(self.w, self.y, self.z, self.y) } + #[inline] - fn zzz(self) -> Vec3 { - Vec3::new(self.z, self.z, self.z) + fn wyzz(self) -> Vec4 { + Vec4::new(self.w, self.y, self.z, self.z) } + #[inline] - fn zzw(self) -> Vec3 { - Vec3::new(self.z, self.z, self.w) + fn wyzw(self) -> Vec4 { + Vec4::new(self.w, self.y, self.z, self.w) } + #[inline] - fn zwx(self) -> Vec3 { - Vec3::new(self.z, self.w, self.x) + fn wywx(self) -> Vec4 { + Vec4::new(self.w, self.y, self.w, self.x) } + #[inline] - fn zwy(self) -> Vec3 { - Vec3::new(self.z, self.w, self.y) + fn wywy(self) -> Vec4 { + Vec4::new(self.w, self.y, self.w, self.y) } + #[inline] - fn zwz(self) -> Vec3 { - Vec3::new(self.z, self.w, self.z) + fn wywz(self) -> Vec4 { + Vec4::new(self.w, self.y, self.w, self.z) } + #[inline] - fn zww(self) -> Vec3 { - Vec3::new(self.z, self.w, self.w) + fn wyww(self) -> Vec4 { + Vec4::new(self.w, self.y, self.w, self.w) } + #[inline] - fn wxx(self) -> Vec3 { - Vec3::new(self.w, self.x, self.x) + fn wzxx(self) -> Vec4 { + Vec4::new(self.w, self.z, self.x, self.x) } + #[inline] - fn wxy(self) -> Vec3 { - Vec3::new(self.w, self.x, self.y) + fn wzxy(self) -> Vec4 { + Vec4::new(self.w, self.z, self.x, self.y) } + #[inline] - fn wxz(self) -> Vec3 { - Vec3::new(self.w, self.x, self.z) + fn wzxz(self) -> Vec4 { + Vec4::new(self.w, self.z, self.x, self.z) } + #[inline] - fn wxw(self) -> Vec3 { - Vec3::new(self.w, self.x, self.w) + fn wzxw(self) -> Vec4 { + Vec4::new(self.w, self.z, self.x, self.w) } + #[inline] - fn wyx(self) -> Vec3 { - Vec3::new(self.w, self.y, self.x) + fn wzyx(self) -> Vec4 { + Vec4::new(self.w, self.z, self.y, self.x) } + #[inline] - fn wyy(self) -> Vec3 { - Vec3::new(self.w, self.y, self.y) + fn wzyy(self) -> Vec4 { + Vec4::new(self.w, self.z, self.y, self.y) } + #[inline] - fn wyz(self) -> Vec3 { - Vec3::new(self.w, self.y, self.z) + fn wzyz(self) -> Vec4 { + Vec4::new(self.w, self.z, self.y, self.z) } + #[inline] - fn wyw(self) -> Vec3 { - Vec3::new(self.w, self.y, self.w) + fn wzyw(self) -> Vec4 { + Vec4::new(self.w, self.z, self.y, self.w) } + #[inline] - fn wzx(self) -> Vec3 { - Vec3::new(self.w, self.z, self.x) + fn wzzx(self) -> Vec4 { + Vec4::new(self.w, self.z, self.z, self.x) } + #[inline] - fn wzy(self) -> Vec3 { - Vec3::new(self.w, self.z, self.y) + fn wzzy(self) -> Vec4 { + Vec4::new(self.w, self.z, self.z, self.y) } + #[inline] - fn wzz(self) -> Vec3 { - Vec3::new(self.w, self.z, self.z) + fn wzzz(self) -> Vec4 { + Vec4::new(self.w, self.z, self.z, self.z) } + #[inline] - fn wzw(self) -> Vec3 { - Vec3::new(self.w, self.z, self.w) + fn wzzw(self) -> Vec4 { + Vec4::new(self.w, self.z, self.z, self.w) } + #[inline] - fn wwx(self) -> Vec3 { - Vec3::new(self.w, self.w, self.x) + fn wzwx(self) -> Vec4 { + Vec4::new(self.w, self.z, self.w, self.x) } + #[inline] - fn wwy(self) -> Vec3 { - Vec3::new(self.w, self.w, self.y) + fn wzwy(self) -> Vec4 { + Vec4::new(self.w, self.z, self.w, self.y) } + #[inline] - fn wwz(self) -> Vec3 { - Vec3::new(self.w, self.w, self.z) + fn wzwz(self) -> Vec4 { + Vec4::new(self.w, self.z, self.w, self.z) } + #[inline] - fn www(self) -> Vec3 { - Vec3::new(self.w, self.w, self.w) + fn wzww(self) -> Vec4 { + Vec4::new(self.w, self.z, self.w, self.w) } + #[inline] - fn xx(self) -> Vec2 { - Vec2::new(self.x, self.x) + fn wwxx(self) -> Vec4 { + Vec4::new(self.w, self.w, self.x, self.x) } + #[inline] - fn xy(self) -> Vec2 { - Vec2::new(self.x, self.y) + fn wwxy(self) -> Vec4 { + Vec4::new(self.w, self.w, self.x, self.y) } + #[inline] - fn xz(self) -> Vec2 { - Vec2::new(self.x, self.z) + fn wwxz(self) -> Vec4 { + Vec4::new(self.w, self.w, self.x, self.z) } + #[inline] - fn xw(self) -> Vec2 { - Vec2::new(self.x, self.w) + fn wwxw(self) -> Vec4 { + Vec4::new(self.w, self.w, self.x, self.w) } + #[inline] - fn yx(self) -> Vec2 { - Vec2::new(self.y, self.x) + fn wwyx(self) -> Vec4 { + Vec4::new(self.w, self.w, self.y, self.x) } + #[inline] - fn yy(self) -> Vec2 { - Vec2::new(self.y, self.y) + fn wwyy(self) -> Vec4 { + Vec4::new(self.w, self.w, self.y, self.y) } + #[inline] - fn yz(self) -> Vec2 { - Vec2::new(self.y, self.z) + fn wwyz(self) -> Vec4 { + Vec4::new(self.w, self.w, self.y, self.z) } + #[inline] - fn yw(self) -> Vec2 { - Vec2::new(self.y, self.w) + fn wwyw(self) -> Vec4 { + Vec4::new(self.w, self.w, self.y, self.w) } + #[inline] - fn zx(self) -> Vec2 { - Vec2::new(self.z, self.x) + fn wwzx(self) -> Vec4 { + Vec4::new(self.w, self.w, self.z, self.x) } + #[inline] - fn zy(self) -> Vec2 { - Vec2::new(self.z, self.y) + fn wwzy(self) -> Vec4 { + Vec4::new(self.w, self.w, self.z, self.y) } + #[inline] - fn zz(self) -> Vec2 { - Vec2::new(self.z, self.z) + fn wwzz(self) -> Vec4 { + Vec4::new(self.w, self.w, self.z, self.z) } + #[inline] - fn zw(self) -> Vec2 { - Vec2::new(self.z, self.w) + fn wwzw(self) -> Vec4 { + Vec4::new(self.w, self.w, self.z, self.w) } + #[inline] - fn wx(self) -> Vec2 { - Vec2::new(self.w, self.x) + fn wwwx(self) -> Vec4 { + Vec4::new(self.w, self.w, self.w, self.x) } + #[inline] - fn wy(self) -> Vec2 { - Vec2::new(self.w, self.y) + fn wwwy(self) -> Vec4 { + Vec4::new(self.w, self.w, self.w, self.y) } + #[inline] - fn wz(self) -> Vec2 { - Vec2::new(self.w, self.z) + fn wwwz(self) -> Vec4 { + Vec4::new(self.w, self.w, self.w, self.z) } + #[inline] - fn ww(self) -> Vec2 { - Vec2::new(self.w, self.w) + fn wwww(self) -> Vec4 { + Vec4::new(self.w, self.w, self.w, self.w) } } diff --git a/src/swizzles/vec4_impl_sse2.rs b/src/swizzles/vec4_impl_sse2.rs index ac8d9429..fdf69c0a 100644 --- a/src/swizzles/vec4_impl_sse2.rs +++ b/src/swizzles/vec4_impl_sse2.rs @@ -1,7 +1,9 @@ -// Generated by swizzlegen. Do not edit. +// Generated from swizzle_impl.rs template. Edit the template, not the generated file. + +#![allow(clippy::useless_conversion)] use super::Vec4Swizzles; -use crate::{Vec2, Vec3, Vec4, XY, XYZ}; +use crate::{Vec2, Vec3, Vec4}; #[cfg(target_arch = "x86")] use core::arch::x86::*; @@ -10,1346 +12,1990 @@ use core::arch::x86_64::*; impl Vec4Swizzles for Vec4 { type Vec2 = Vec2; + type Vec3 = Vec3; #[inline] - fn xxxx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_00_00_00)) } + fn xx(self) -> Vec2 { + Vec2 { + x: self.x, + y: self.x, + } } + #[inline] - fn xxxy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_00_00_00)) } + fn xy(self) -> Vec2 { + Vec2 { + x: self.x, + y: self.y, + } } + #[inline] - fn xxxz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_00_00_00)) } + fn xz(self) -> Vec2 { + Vec2 { + x: self.x, + y: self.z, + } } + #[inline] - fn xxxw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_00_00_00)) } + fn xw(self) -> Vec2 { + Vec2 { + x: self.x, + y: self.w, + } } + #[inline] - fn xxyx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_01_00_00)) } + fn yx(self) -> Vec2 { + Vec2 { + x: self.y, + y: self.x, + } } + #[inline] - fn xxyy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_01_00_00)) } + fn yy(self) -> Vec2 { + Vec2 { + x: self.y, + y: self.y, + } } + #[inline] - fn xxyz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_01_00_00)) } + fn yz(self) -> Vec2 { + Vec2 { + x: self.y, + y: self.z, + } } + #[inline] - fn xxyw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_01_00_00)) } + fn yw(self) -> Vec2 { + Vec2 { + x: self.y, + y: self.w, + } } + #[inline] - fn xxzx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_10_00_00)) } + fn zx(self) -> Vec2 { + Vec2 { + x: self.z, + y: self.x, + } } + #[inline] - fn xxzy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_10_00_00)) } + fn zy(self) -> Vec2 { + Vec2 { + x: self.z, + y: self.y, + } } + #[inline] - fn xxzz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_10_00_00)) } + fn zz(self) -> Vec2 { + Vec2 { + x: self.z, + y: self.z, + } } + #[inline] - fn xxzw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_10_00_00)) } + fn zw(self) -> Vec2 { + Vec2 { + x: self.z, + y: self.w, + } } + #[inline] - fn xxwx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_11_00_00)) } + fn wx(self) -> Vec2 { + Vec2 { + x: self.w, + y: self.x, + } } + #[inline] - fn xxwy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_11_00_00)) } + fn wy(self) -> Vec2 { + Vec2 { + x: self.w, + y: self.y, + } } + #[inline] - fn xxwz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_11_00_00)) } + fn wz(self) -> Vec2 { + Vec2 { + x: self.w, + y: self.z, + } } + #[inline] - fn xxww(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_11_00_00)) } + fn ww(self) -> Vec2 { + Vec2 { + x: self.w, + y: self.w, + } } + #[inline] - fn xyxx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_00_01_00)) } + fn xxx(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.x, + z: self.x, + } } + #[inline] - fn xyxy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_00_01_00)) } + fn xxy(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.x, + z: self.y, + } } + #[inline] - fn xyxz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_00_01_00)) } + fn xxz(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.x, + z: self.z, + } } + #[inline] - fn xyxw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_00_01_00)) } + fn xxw(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.x, + z: self.w, + } } + #[inline] - fn xyyx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_01_01_00)) } + fn xyx(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.y, + z: self.x, + } } + #[inline] - fn xyyy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_01_01_00)) } + fn xyy(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.y, + z: self.y, + } } + #[inline] - fn xyyz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_01_01_00)) } + fn xyz(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.y, + z: self.z, + } } + #[inline] - fn xyyw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_01_01_00)) } + fn xyw(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.y, + z: self.w, + } } + #[inline] - fn xyzx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_10_01_00)) } + fn xzx(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.z, + z: self.x, + } } + #[inline] - fn xyzy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_10_01_00)) } + fn xzy(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.z, + z: self.y, + } } + #[inline] - fn xyzz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_10_01_00)) } + fn xzz(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.z, + z: self.z, + } } + #[inline] - fn xywx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_11_01_00)) } + fn xzw(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.z, + z: self.w, + } } + #[inline] - fn xywy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_11_01_00)) } + fn xwx(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.w, + z: self.x, + } } + #[inline] - fn xywz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_11_01_00)) } + fn xwy(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.w, + z: self.y, + } } + #[inline] - fn xyww(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_11_01_00)) } + fn xwz(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.w, + z: self.z, + } } + #[inline] - fn xzxx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_00_10_00)) } + fn xww(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.w, + z: self.w, + } } + #[inline] - fn xzxy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_00_10_00)) } + fn yxx(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.x, + z: self.x, + } } + #[inline] - fn xzxz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_00_10_00)) } + fn yxy(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.x, + z: self.y, + } } + #[inline] - fn xzxw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_00_10_00)) } + fn yxz(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.x, + z: self.z, + } } + #[inline] - fn xzyx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_01_10_00)) } + fn yxw(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.x, + z: self.w, + } } + #[inline] - fn xzyy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_01_10_00)) } + fn yyx(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.y, + z: self.x, + } } + #[inline] - fn xzyz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_01_10_00)) } + fn yyy(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.y, + z: self.y, + } } + #[inline] - fn xzyw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_01_10_00)) } + fn yyz(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.y, + z: self.z, + } } + #[inline] - fn xzzx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_10_10_00)) } + fn yyw(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.y, + z: self.w, + } } + #[inline] - fn xzzy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_10_10_00)) } + fn yzx(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.z, + z: self.x, + } } + #[inline] - fn xzzz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_10_10_00)) } + fn yzy(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.z, + z: self.y, + } } + #[inline] - fn xzzw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_10_10_00)) } + fn yzz(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.z, + z: self.z, + } } + #[inline] - fn xzwx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_11_10_00)) } + fn yzw(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.z, + z: self.w, + } } + #[inline] - fn xzwy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_11_10_00)) } + fn ywx(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.w, + z: self.x, + } } + #[inline] - fn xzwz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_11_10_00)) } + fn ywy(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.w, + z: self.y, + } } + #[inline] - fn xzww(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_11_10_00)) } + fn ywz(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.w, + z: self.z, + } } + #[inline] - fn xwxx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_00_11_00)) } + fn yww(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.w, + z: self.w, + } } + #[inline] - fn xwxy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_00_11_00)) } + fn zxx(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.x, + z: self.x, + } } + #[inline] - fn xwxz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_00_11_00)) } + fn zxy(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.x, + z: self.y, + } } + #[inline] - fn xwxw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_00_11_00)) } + fn zxz(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.x, + z: self.z, + } } + #[inline] - fn xwyx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_01_11_00)) } + fn zxw(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.x, + z: self.w, + } } + #[inline] - fn xwyy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_01_11_00)) } + fn zyx(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.y, + z: self.x, + } } + #[inline] - fn xwyz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_01_11_00)) } + fn zyy(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.y, + z: self.y, + } } + #[inline] - fn xwyw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_01_11_00)) } + fn zyz(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.y, + z: self.z, + } } + #[inline] - fn xwzx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_10_11_00)) } + fn zyw(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.y, + z: self.w, + } } + #[inline] - fn xwzy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_10_11_00)) } + fn zzx(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.z, + z: self.x, + } } + #[inline] - fn xwzz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_10_11_00)) } + fn zzy(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.z, + z: self.y, + } } + #[inline] - fn xwzw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_10_11_00)) } + fn zzz(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.z, + z: self.z, + } } + #[inline] - fn xwwx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_11_11_00)) } + fn zzw(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.z, + z: self.w, + } } + #[inline] - fn xwwy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_11_11_00)) } + fn zwx(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.w, + z: self.x, + } } + #[inline] - fn xwwz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_11_11_00)) } + fn zwy(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.w, + z: self.y, + } } + #[inline] - fn xwww(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_11_11_00)) } + fn zwz(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.w, + z: self.z, + } } + #[inline] - fn yxxx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_00_00_01)) } + fn zww(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.w, + z: self.w, + } } + #[inline] - fn yxxy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_00_00_01)) } + fn wxx(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.x, + z: self.x, + } } + #[inline] - fn yxxz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_00_00_01)) } + fn wxy(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.x, + z: self.y, + } } + #[inline] - fn yxxw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_00_00_01)) } + fn wxz(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.x, + z: self.z, + } } + #[inline] - fn yxyx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_01_00_01)) } + fn wxw(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.x, + z: self.w, + } } + #[inline] - fn yxyy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_01_00_01)) } + fn wyx(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.y, + z: self.x, + } } + #[inline] - fn yxyz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_01_00_01)) } + fn wyy(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.y, + z: self.y, + } } + #[inline] - fn yxyw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_01_00_01)) } + fn wyz(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.y, + z: self.z, + } } + #[inline] - fn yxzx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_10_00_01)) } + fn wyw(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.y, + z: self.w, + } } + #[inline] - fn yxzy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_10_00_01)) } + fn wzx(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.z, + z: self.x, + } } + #[inline] - fn yxzz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_10_00_01)) } + fn wzy(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.z, + z: self.y, + } } + #[inline] - fn yxzw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_10_00_01)) } + fn wzz(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.z, + z: self.z, + } } + #[inline] - fn yxwx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_11_00_01)) } + fn wzw(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.z, + z: self.w, + } } + #[inline] - fn yxwy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_11_00_01)) } + fn wwx(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.w, + z: self.x, + } } + #[inline] - fn yxwz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_11_00_01)) } + fn wwy(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.w, + z: self.y, + } } + #[inline] - fn yxww(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_11_00_01)) } + fn wwz(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.w, + z: self.z, + } } + #[inline] - fn yyxx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_00_01_01)) } + fn www(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.w, + z: self.w, + } } + #[inline] - fn yyxy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_00_01_01)) } + fn xxxx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_00_00) }) } + #[inline] - fn yyxz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_00_01_01)) } + fn xxxy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_00_00_00) }) } + #[inline] - fn yyxw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_00_01_01)) } + fn xxxz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_00_00_00) }) } + #[inline] - fn yyyx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_01_01_01)) } + fn xxxw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_00_00_00) }) } + #[inline] - fn yyyy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_01_01_01)) } + fn xxyx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_00_00) }) } + #[inline] - fn yyyz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_01_01_01)) } + fn xxyy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_01_00_00) }) } + #[inline] - fn yyyw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_01_01_01)) } + fn xxyz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_01_00_00) }) } + #[inline] - fn yyzx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_10_01_01)) } + fn xxyw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_01_00_00) }) } + #[inline] - fn yyzy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_10_01_01)) } + fn xxzx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_00_00) }) } + #[inline] - fn yyzz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_10_01_01)) } + fn xxzy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_10_00_00) }) } + #[inline] - fn yyzw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_10_01_01)) } + fn xxzz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_10_00_00) }) } + #[inline] - fn yywx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_11_01_01)) } + fn xxzw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_10_00_00) }) } + #[inline] - fn yywy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_11_01_01)) } + fn xxwx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_11_00_00) }) } + #[inline] - fn yywz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_11_01_01)) } + fn xxwy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_11_00_00) }) } + #[inline] - fn yyww(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_11_01_01)) } + fn xxwz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_11_00_00) }) } + #[inline] - fn yzxx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_00_10_01)) } + fn xxww(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_11_00_00) }) } + #[inline] - fn yzxy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_00_10_01)) } + fn xyxx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_01_00) }) } + #[inline] - fn yzxz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_00_10_01)) } + fn xyxy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_00_01_00) }) } + #[inline] - fn yzxw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_00_10_01)) } + fn xyxz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_00_01_00) }) } + #[inline] - fn yzyx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_01_10_01)) } + fn xyxw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_00_01_00) }) } + #[inline] - fn yzyy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_01_10_01)) } + fn xyyx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_01_00) }) } + #[inline] - fn yzyz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_01_10_01)) } + fn xyyy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_01_01_00) }) } + #[inline] - fn yzyw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_01_10_01)) } + fn xyyz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_01_01_00) }) } + #[inline] - fn yzzx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_10_10_01)) } + fn xyyw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_01_01_00) }) } + #[inline] - fn yzzy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_10_10_01)) } + fn xyzx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_01_00) }) } + #[inline] - fn yzzz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_10_10_01)) } + fn xyzy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_10_01_00) }) } + #[inline] - fn yzzw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_10_10_01)) } + fn xyzz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_10_01_00) }) } + #[inline] - fn yzwx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_11_10_01)) } + fn xyzw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_10_01_00) }) } + #[inline] - fn yzwy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_11_10_01)) } + fn xywx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_11_01_00) }) } + #[inline] - fn yzwz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_11_10_01)) } + fn xywy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_11_01_00) }) } + #[inline] - fn yzww(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_11_10_01)) } + fn xywz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_11_01_00) }) } + #[inline] - fn ywxx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_00_11_01)) } + fn xyww(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_11_01_00) }) } + #[inline] - fn ywxy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_00_11_01)) } + fn xzxx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_10_00) }) } + #[inline] - fn ywxz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_00_11_01)) } + fn xzxy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_00_10_00) }) } + #[inline] - fn ywxw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_00_11_01)) } + fn xzxz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_00_10_00) }) } + #[inline] - fn ywyx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_01_11_01)) } + fn xzxw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_00_10_00) }) } + #[inline] - fn ywyy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_01_11_01)) } + fn xzyx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_10_00) }) } + #[inline] - fn ywyz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_01_11_01)) } + fn xzyy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_01_10_00) }) } + #[inline] - fn ywyw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_01_11_01)) } + fn xzyz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_01_10_00) }) } + #[inline] - fn ywzx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_10_11_01)) } + fn xzyw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_01_10_00) }) } + #[inline] - fn ywzy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_10_11_01)) } + fn xzzx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_10_00) }) } + #[inline] - fn ywzz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_10_11_01)) } + fn xzzy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_10_10_00) }) } + #[inline] - fn ywzw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_10_11_01)) } + fn xzzz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_10_10_00) }) } + #[inline] - fn ywwx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_11_11_01)) } + fn xzzw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_10_10_00) }) } + #[inline] - fn ywwy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_11_11_01)) } + fn xzwx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_11_10_00) }) } + #[inline] - fn ywwz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_11_11_01)) } + fn xzwy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_11_10_00) }) } + #[inline] - fn ywww(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_11_11_01)) } + fn xzwz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_11_10_00) }) } + #[inline] - fn zxxx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_00_00_10)) } + fn xzww(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_11_10_00) }) } + #[inline] - fn zxxy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_00_00_10)) } + fn xwxx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_11_00) }) } + #[inline] - fn zxxz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_00_00_10)) } + fn xwxy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_00_11_00) }) } + #[inline] - fn zxxw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_00_00_10)) } + fn xwxz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_00_11_00) }) } + #[inline] - fn zxyx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_01_00_10)) } + fn xwxw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_00_11_00) }) } + #[inline] - fn zxyy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_01_00_10)) } + fn xwyx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_11_00) }) } + #[inline] - fn zxyz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_01_00_10)) } + fn xwyy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_01_11_00) }) } + #[inline] - fn zxyw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_01_00_10)) } + fn xwyz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_01_11_00) }) } + #[inline] - fn zxzx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_10_00_10)) } + fn xwyw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_01_11_00) }) } + #[inline] - fn zxzy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_10_00_10)) } + fn xwzx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_11_00) }) } + #[inline] - fn zxzz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_10_00_10)) } + fn xwzy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_10_11_00) }) } + #[inline] - fn zxzw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_10_00_10)) } + fn xwzz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_10_11_00) }) } + #[inline] - fn zxwx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_11_00_10)) } + fn xwzw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_10_11_00) }) } + #[inline] - fn zxwy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_11_00_10)) } + fn xwwx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_11_11_00) }) } + #[inline] - fn zxwz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_11_00_10)) } + fn xwwy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_11_11_00) }) } + #[inline] - fn zxww(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_11_00_10)) } + fn xwwz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_11_11_00) }) } + #[inline] - fn zyxx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_00_01_10)) } + fn xwww(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_11_11_00) }) } + #[inline] - fn zyxy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_00_01_10)) } + fn yxxx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_00_01) }) } + #[inline] - fn zyxz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_00_01_10)) } + fn yxxy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_00_00_01) }) } + #[inline] - fn zyxw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_00_01_10)) } + fn yxxz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_00_00_01) }) } + #[inline] - fn zyyx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_01_01_10)) } + fn yxxw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_00_00_01) }) } + #[inline] - fn zyyy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_01_01_10)) } + fn yxyx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_00_01) }) } + #[inline] - fn zyyz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_01_01_10)) } + fn yxyy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_01_00_01) }) } + #[inline] - fn zyyw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_01_01_10)) } + fn yxyz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_01_00_01) }) } + #[inline] - fn zyzx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_10_01_10)) } + fn yxyw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_01_00_01) }) } + #[inline] - fn zyzy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_10_01_10)) } + fn yxzx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_00_01) }) } + #[inline] - fn zyzz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_10_01_10)) } + fn yxzy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_10_00_01) }) } + #[inline] - fn zyzw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_10_01_10)) } + fn yxzz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_10_00_01) }) } + #[inline] - fn zywx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_11_01_10)) } + fn yxzw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_10_00_01) }) } + #[inline] - fn zywy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_11_01_10)) } + fn yxwx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_11_00_01) }) } + #[inline] - fn zywz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_11_01_10)) } + fn yxwy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_11_00_01) }) } + #[inline] - fn zyww(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_11_01_10)) } + fn yxwz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_11_00_01) }) } + #[inline] - fn zzxx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_00_10_10)) } + fn yxww(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_11_00_01) }) } + #[inline] - fn zzxy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_00_10_10)) } + fn yyxx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_01_01) }) } + #[inline] - fn zzxz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_00_10_10)) } + fn yyxy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_00_01_01) }) } + #[inline] - fn zzxw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_00_10_10)) } + fn yyxz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_00_01_01) }) } + #[inline] - fn zzyx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_01_10_10)) } + fn yyxw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_00_01_01) }) } + #[inline] - fn zzyy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_01_10_10)) } + fn yyyx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_01_01) }) } + #[inline] - fn zzyz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_01_10_10)) } + fn yyyy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_01_01_01) }) } + #[inline] - fn zzyw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_01_10_10)) } + fn yyyz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_01_01_01) }) } + #[inline] - fn zzzx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_10_10_10)) } + fn yyyw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_01_01_01) }) } + #[inline] - fn zzzy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_10_10_10)) } + fn yyzx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_01_01) }) } + #[inline] - fn zzzz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_10_10_10)) } + fn yyzy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_10_01_01) }) } + #[inline] - fn zzzw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_10_10_10)) } + fn yyzz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_10_01_01) }) } + #[inline] - fn zzwx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_11_10_10)) } + fn yyzw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_10_01_01) }) } + #[inline] - fn zzwy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_11_10_10)) } + fn yywx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_11_01_01) }) } + #[inline] - fn zzwz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_11_10_10)) } + fn yywy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_11_01_01) }) } + #[inline] - fn zzww(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_11_10_10)) } + fn yywz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_11_01_01) }) } + #[inline] - fn zwxx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_00_11_10)) } + fn yyww(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_11_01_01) }) } + #[inline] - fn zwxy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_00_11_10)) } + fn yzxx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_10_01) }) } + #[inline] - fn zwxz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_00_11_10)) } + fn yzxy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_00_10_01) }) } + #[inline] - fn zwxw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_00_11_10)) } + fn yzxz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_00_10_01) }) } + #[inline] - fn zwyx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_01_11_10)) } + fn yzxw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_00_10_01) }) } + #[inline] - fn zwyy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_01_11_10)) } + fn yzyx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_10_01) }) } + #[inline] - fn zwyz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_01_11_10)) } + fn yzyy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_01_10_01) }) } + #[inline] - fn zwyw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_01_11_10)) } + fn yzyz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_01_10_01) }) } + #[inline] - fn zwzx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_10_11_10)) } + fn yzyw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_01_10_01) }) } + #[inline] - fn zwzy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_10_11_10)) } + fn yzzx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_10_01) }) } + #[inline] - fn zwzz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_10_11_10)) } + fn yzzy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_10_10_01) }) } + #[inline] - fn zwzw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_10_11_10)) } + fn yzzz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_10_10_01) }) } + #[inline] - fn zwwx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_11_11_10)) } + fn yzzw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_10_10_01) }) } + #[inline] - fn zwwy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_11_11_10)) } + fn yzwx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_11_10_01) }) } + #[inline] - fn zwwz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_11_11_10)) } + fn yzwy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_11_10_01) }) } + #[inline] - fn zwww(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_11_11_10)) } + fn yzwz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_11_10_01) }) } + #[inline] - fn wxxx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_00_00_11)) } + fn yzww(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_11_10_01) }) } + #[inline] - fn wxxy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_00_00_11)) } + fn ywxx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_11_01) }) } + #[inline] - fn wxxz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_00_00_11)) } + fn ywxy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_00_11_01) }) } + #[inline] - fn wxxw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_00_00_11)) } + fn ywxz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_00_11_01) }) } + #[inline] - fn wxyx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_01_00_11)) } + fn ywxw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_00_11_01) }) } + #[inline] - fn wxyy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_01_00_11)) } + fn ywyx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_11_01) }) } + #[inline] - fn wxyz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_01_00_11)) } + fn ywyy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_01_11_01) }) } + #[inline] - fn wxyw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_01_00_11)) } + fn ywyz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_01_11_01) }) } + #[inline] - fn wxzx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_10_00_11)) } + fn ywyw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_01_11_01) }) } + #[inline] - fn wxzy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_10_00_11)) } + fn ywzx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_11_01) }) } + #[inline] - fn wxzz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_10_00_11)) } + fn ywzy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_10_11_01) }) } + #[inline] - fn wxzw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_10_00_11)) } + fn ywzz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_10_11_01) }) } + #[inline] - fn wxwx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_11_00_11)) } + fn ywzw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_10_11_01) }) } + #[inline] - fn wxwy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_11_00_11)) } + fn ywwx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_11_11_01) }) } + #[inline] - fn wxwz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_11_00_11)) } + fn ywwy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_11_11_01) }) } + #[inline] - fn wxww(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_11_00_11)) } + fn ywwz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_11_11_01) }) } + #[inline] - fn wyxx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_00_01_11)) } + fn ywww(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_11_11_01) }) } + #[inline] - fn wyxy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_00_01_11)) } + fn zxxx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_00_10) }) } + #[inline] - fn wyxz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_00_01_11)) } + fn zxxy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_00_00_10) }) } + #[inline] - fn wyxw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_00_01_11)) } + fn zxxz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_00_00_10) }) } + #[inline] - fn wyyx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_01_01_11)) } + fn zxxw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_00_00_10) }) } + #[inline] - fn wyyy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_01_01_11)) } + fn zxyx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_00_10) }) } + #[inline] - fn wyyz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_01_01_11)) } + fn zxyy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_01_00_10) }) } + #[inline] - fn wyyw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_01_01_11)) } + fn zxyz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_01_00_10) }) } + #[inline] - fn wyzx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_10_01_11)) } + fn zxyw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_01_00_10) }) } + #[inline] - fn wyzy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_10_01_11)) } + fn zxzx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_00_10) }) } + #[inline] - fn wyzz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_10_01_11)) } + fn zxzy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_10_00_10) }) } + #[inline] - fn wyzw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_10_01_11)) } + fn zxzz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_10_00_10) }) } + #[inline] - fn wywx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_11_01_11)) } + fn zxzw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_10_00_10) }) } + #[inline] - fn wywy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_11_01_11)) } + fn zxwx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_11_00_10) }) } + #[inline] - fn wywz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_11_01_11)) } + fn zxwy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_11_00_10) }) } + #[inline] - fn wyww(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_11_01_11)) } + fn zxwz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_11_00_10) }) } + #[inline] - fn wzxx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_00_10_11)) } + fn zxww(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_11_00_10) }) } + #[inline] - fn wzxy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_00_10_11)) } + fn zyxx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_01_10) }) } + #[inline] - fn wzxz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_00_10_11)) } + fn zyxy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_00_01_10) }) } + #[inline] - fn wzxw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_00_10_11)) } + fn zyxz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_00_01_10) }) } + #[inline] - fn wzyx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_01_10_11)) } + fn zyxw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_00_01_10) }) } + #[inline] - fn wzyy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_01_10_11)) } + fn zyyx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_01_10) }) } + #[inline] - fn wzyz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_01_10_11)) } + fn zyyy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_01_01_10) }) } + #[inline] - fn wzyw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_01_10_11)) } + fn zyyz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_01_01_10) }) } + #[inline] - fn wzzx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_10_10_11)) } + fn zyyw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_01_01_10) }) } + #[inline] - fn wzzy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_10_10_11)) } + fn zyzx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_01_10) }) } + #[inline] - fn wzzz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_10_10_11)) } + fn zyzy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_10_01_10) }) } + #[inline] - fn wzzw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_10_10_11)) } + fn zyzz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_10_01_10) }) } + #[inline] - fn wzwx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_11_10_11)) } + fn zyzw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_10_01_10) }) } + #[inline] - fn wzwy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_11_10_11)) } + fn zywx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_11_01_10) }) } + #[inline] - fn wzwz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_11_10_11)) } + fn zywy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_11_01_10) }) } + #[inline] - fn wzww(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_11_10_11)) } + fn zywz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_11_01_10) }) } + #[inline] - fn wwxx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_00_11_11)) } + fn zyww(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_11_01_10) }) } + #[inline] - fn wwxy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_00_11_11)) } + fn zzxx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_10_10) }) } + #[inline] - fn wwxz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_00_11_11)) } + fn zzxy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_00_10_10) }) } + #[inline] - fn wwxw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_00_11_11)) } + fn zzxz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_00_10_10) }) } + #[inline] - fn wwyx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_01_11_11)) } + fn zzxw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_00_10_10) }) } + #[inline] - fn wwyy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_01_11_11)) } + fn zzyx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_10_10) }) } + #[inline] - fn wwyz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_01_11_11)) } + fn zzyy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_01_10_10) }) } + #[inline] - fn wwyw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_01_11_11)) } + fn zzyz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_01_10_10) }) } + #[inline] - fn wwzx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_10_11_11)) } + fn zzyw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_01_10_10) }) } + #[inline] - fn wwzy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_10_11_11)) } + fn zzzx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_10_10) }) } + #[inline] - fn wwzz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_10_11_11)) } + fn zzzy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_10_10_10) }) } + #[inline] - fn wwzw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_10_11_11)) } + fn zzzz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_10_10_10) }) } + #[inline] - fn wwwx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_11_11_11)) } + fn zzzw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_10_10_10) }) } + #[inline] - fn wwwy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_11_11_11)) } + fn zzwx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_11_10_10) }) } + #[inline] - fn wwwz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_11_11_11)) } + fn zzwy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_11_10_10) }) } + #[inline] - fn wwww(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_11_11_11)) } + fn zzwz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_11_10_10) }) } + #[inline] - fn xxx(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_00_00))) } + fn zzww(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_11_10_10) }) } + #[inline] - fn xxy(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_01_00_00))) } + fn zwxx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_11_10) }) } + #[inline] - fn xxz(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_10_00_00))) } + fn zwxy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_00_11_10) }) } + #[inline] - fn xxw(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_11_00_00))) } + fn zwxz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_00_11_10) }) } + #[inline] - fn xyx(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_01_00))) } + fn zwxw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_00_11_10) }) } + #[inline] - fn xyy(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_01_01_00))) } + fn zwyx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_11_10) }) } + #[inline] - fn xyz(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_10_01_00))) } + fn zwyy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_01_11_10) }) } + #[inline] - fn xyw(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_11_01_00))) } + fn zwyz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_01_11_10) }) } + #[inline] - fn xzx(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_10_00))) } + fn zwyw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_01_11_10) }) } + #[inline] - fn xzy(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_01_10_00))) } + fn zwzx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_11_10) }) } + #[inline] - fn xzz(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_10_10_00))) } + fn zwzy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_10_11_10) }) } + #[inline] - fn xzw(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_11_10_00))) } + fn zwzz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_10_11_10) }) } + #[inline] - fn xwx(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_11_00))) } + fn zwzw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_10_11_10) }) } + #[inline] - fn xwy(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_01_11_00))) } + fn zwwx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_11_11_10) }) } + #[inline] - fn xwz(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_10_11_00))) } + fn zwwy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_11_11_10) }) } + #[inline] - fn xww(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_11_11_00))) } + fn zwwz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_11_11_10) }) } + #[inline] - fn yxx(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_00_01))) } + fn zwww(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_11_11_10) }) } + #[inline] - fn yxy(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_01_00_01))) } + fn wxxx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_00_11) }) } + #[inline] - fn yxz(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_10_00_01))) } + fn wxxy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_00_00_11) }) } + #[inline] - fn yxw(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_11_00_01))) } + fn wxxz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_00_00_11) }) } + #[inline] - fn yyx(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_01_01))) } + fn wxxw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_00_00_11) }) } + #[inline] - fn yyy(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_01_01_01))) } + fn wxyx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_00_11) }) } + #[inline] - fn yyz(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_10_01_01))) } + fn wxyy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_01_00_11) }) } + #[inline] - fn yyw(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_11_01_01))) } + fn wxyz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_01_00_11) }) } + #[inline] - fn yzx(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_10_01))) } + fn wxyw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_01_00_11) }) } + #[inline] - fn yzy(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_01_10_01))) } + fn wxzx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_00_11) }) } + #[inline] - fn yzz(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_10_10_01))) } + fn wxzy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_10_00_11) }) } + #[inline] - fn yzw(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_11_10_01))) } + fn wxzz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_10_00_11) }) } + #[inline] - fn ywx(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_11_01))) } + fn wxzw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_10_00_11) }) } + #[inline] - fn ywy(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_01_11_01))) } + fn wxwx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_11_00_11) }) } + #[inline] - fn ywz(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_10_11_01))) } + fn wxwy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_11_00_11) }) } + #[inline] - fn yww(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_11_11_01))) } + fn wxwz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_11_00_11) }) } + #[inline] - fn zxx(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_00_10))) } + fn wxww(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_11_00_11) }) } + #[inline] - fn zxy(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_01_00_10))) } + fn wyxx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_01_11) }) } + #[inline] - fn zxz(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_10_00_10))) } + fn wyxy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_00_01_11) }) } + #[inline] - fn zxw(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_11_00_10))) } + fn wyxz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_00_01_11) }) } + #[inline] - fn zyx(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_01_10))) } + fn wyxw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_00_01_11) }) } + #[inline] - fn zyy(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_01_01_10))) } + fn wyyx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_01_11) }) } + #[inline] - fn zyz(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_10_01_10))) } + fn wyyy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_01_01_11) }) } + #[inline] - fn zyw(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_11_01_10))) } + fn wyyz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_01_01_11) }) } + #[inline] - fn zzx(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_10_10))) } + fn wyyw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_01_01_11) }) } + #[inline] - fn zzy(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_01_10_10))) } + fn wyzx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_01_11) }) } + #[inline] - fn zzz(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_10_10_10))) } + fn wyzy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_10_01_11) }) } + #[inline] - fn zzw(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_11_10_10))) } + fn wyzz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_10_01_11) }) } + #[inline] - fn zwx(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_11_10))) } + fn wyzw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_10_01_11) }) } + #[inline] - fn zwy(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_01_11_10))) } + fn wywx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_11_01_11) }) } + #[inline] - fn zwz(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_10_11_10))) } + fn wywy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_11_01_11) }) } + #[inline] - fn zww(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_11_11_10))) } + fn wywz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_11_01_11) }) } + #[inline] - fn wxx(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_00_11))) } + fn wyww(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_11_01_11) }) } + #[inline] - fn wxy(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_01_00_11))) } + fn wzxx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_10_11) }) } + #[inline] - fn wxz(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_10_00_11))) } + fn wzxy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_00_10_11) }) } + #[inline] - fn wxw(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_11_00_11))) } + fn wzxz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_00_10_11) }) } + #[inline] - fn wyx(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_01_11))) } + fn wzxw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_00_10_11) }) } + #[inline] - fn wyy(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_01_01_11))) } + fn wzyx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_10_11) }) } + #[inline] - fn wyz(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_10_01_11))) } + fn wzyy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_01_10_11) }) } + #[inline] - fn wyw(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_11_01_11))) } + fn wzyz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_01_10_11) }) } + #[inline] - fn wzx(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_10_11))) } + fn wzyw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_01_10_11) }) } + #[inline] - fn wzy(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_01_10_11))) } + fn wzzx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_10_11) }) } + #[inline] - fn wzz(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_10_10_11))) } + fn wzzy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_10_10_11) }) } + #[inline] - fn wzw(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_11_10_11))) } + fn wzzz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_10_10_11) }) } + #[inline] - fn wwx(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_11_11))) } + fn wzzw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_10_10_11) }) } + #[inline] - fn wwy(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_01_11_11))) } + fn wzwx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_11_10_11) }) } + #[inline] - fn wwz(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_10_11_11))) } + fn wzwy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_11_10_11) }) } + #[inline] - fn www(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_11_11_11))) } + fn wzwz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_11_10_11) }) } + #[inline] - fn xx(self) -> Vec2 { - unsafe { Vec2(XY::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_00_00))) } + fn wzww(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_11_10_11) }) } + #[inline] - fn xy(self) -> Vec2 { - unsafe { Vec2(XY::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_01_00))) } + fn wwxx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_11_11) }) } + #[inline] - fn xz(self) -> Vec2 { - unsafe { Vec2(XY::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_10_00))) } + fn wwxy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_00_11_11) }) } + #[inline] - fn xw(self) -> Vec2 { - unsafe { Vec2(XY::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_11_00))) } + fn wwxz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_00_11_11) }) } + #[inline] - fn yx(self) -> Vec2 { - unsafe { Vec2(XY::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_00_01))) } + fn wwxw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_00_11_11) }) } + #[inline] - fn yy(self) -> Vec2 { - unsafe { Vec2(XY::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_01_01))) } + fn wwyx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_11_11) }) } + #[inline] - fn yz(self) -> Vec2 { - unsafe { Vec2(XY::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_10_01))) } + fn wwyy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_01_11_11) }) } + #[inline] - fn yw(self) -> Vec2 { - unsafe { Vec2(XY::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_11_01))) } + fn wwyz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_01_11_11) }) } + #[inline] - fn zx(self) -> Vec2 { - unsafe { Vec2(XY::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_00_10))) } + fn wwyw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_01_11_11) }) } + #[inline] - fn zy(self) -> Vec2 { - unsafe { Vec2(XY::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_01_10))) } + fn wwzx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_11_11) }) } + #[inline] - fn zz(self) -> Vec2 { - unsafe { Vec2(XY::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_10_10))) } + fn wwzy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_10_11_11) }) } + #[inline] - fn zw(self) -> Vec2 { - unsafe { Vec2(XY::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_11_10))) } + fn wwzz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_10_11_11) }) } + #[inline] - fn wx(self) -> Vec2 { - unsafe { Vec2(XY::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_00_11))) } + fn wwzw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_10_11_11) }) } + #[inline] - fn wy(self) -> Vec2 { - unsafe { Vec2(XY::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_01_11))) } + fn wwwx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_11_11_11) }) } + #[inline] - fn wz(self) -> Vec2 { - unsafe { Vec2(XY::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_10_11))) } + fn wwwy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_11_11_11) }) } + #[inline] - fn ww(self) -> Vec2 { - unsafe { Vec2(XY::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_11_11))) } + fn wwwz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_11_11_11) }) + } + + #[inline] + fn wwww(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_11_11_11) }) } } diff --git a/src/swizzles/vec4_impl_wasm32.rs b/src/swizzles/vec4_impl_wasm32.rs index 46c7a228..9fa094b2 100644 --- a/src/swizzles/vec4_impl_wasm32.rs +++ b/src/swizzles/vec4_impl_wasm32.rs @@ -1,1352 +1,1998 @@ -// Generated by swizzlegen. Do not edit. +// Generated from swizzle_impl.rs template. Edit the template, not the generated file. + +#![allow(clippy::useless_conversion)] use super::Vec4Swizzles; -use crate::{Vec2, Vec3, Vec4, XY, XYZ}; +use crate::{Vec2, Vec3, Vec4}; use core::arch::wasm32::*; impl Vec4Swizzles for Vec4 { type Vec2 = Vec2; + type Vec3 = Vec3; #[inline] - fn xxxx(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 0, 4, 4>(self.0, self.0)) + fn xx(self) -> Vec2 { + Vec2 { + x: self.x, + y: self.x, + } } + #[inline] - fn xxxy(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 0, 4, 5>(self.0, self.0)) + fn xy(self) -> Vec2 { + Vec2 { + x: self.x, + y: self.y, + } } + #[inline] - fn xxxz(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 0, 4, 6>(self.0, self.0)) + fn xz(self) -> Vec2 { + Vec2 { + x: self.x, + y: self.z, + } } + #[inline] - fn xxxw(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 0, 4, 7>(self.0, self.0)) + fn xw(self) -> Vec2 { + Vec2 { + x: self.x, + y: self.w, + } } + #[inline] - fn xxyx(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 0, 5, 4>(self.0, self.0)) + fn yx(self) -> Vec2 { + Vec2 { + x: self.y, + y: self.x, + } } + #[inline] - fn xxyy(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 0, 5, 5>(self.0, self.0)) + fn yy(self) -> Vec2 { + Vec2 { + x: self.y, + y: self.y, + } } + #[inline] - fn xxyz(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 0, 5, 6>(self.0, self.0)) + fn yz(self) -> Vec2 { + Vec2 { + x: self.y, + y: self.z, + } } + #[inline] - fn xxyw(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 0, 5, 7>(self.0, self.0)) + fn yw(self) -> Vec2 { + Vec2 { + x: self.y, + y: self.w, + } } + #[inline] - fn xxzx(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 0, 6, 4>(self.0, self.0)) + fn zx(self) -> Vec2 { + Vec2 { + x: self.z, + y: self.x, + } } + #[inline] - fn xxzy(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 0, 6, 5>(self.0, self.0)) + fn zy(self) -> Vec2 { + Vec2 { + x: self.z, + y: self.y, + } } + #[inline] - fn xxzz(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 0, 6, 6>(self.0, self.0)) + fn zz(self) -> Vec2 { + Vec2 { + x: self.z, + y: self.z, + } } + #[inline] - fn xxzw(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 0, 6, 7>(self.0, self.0)) + fn zw(self) -> Vec2 { + Vec2 { + x: self.z, + y: self.w, + } } + #[inline] - fn xxwx(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 0, 7, 4>(self.0, self.0)) + fn wx(self) -> Vec2 { + Vec2 { + x: self.w, + y: self.x, + } } + #[inline] - fn xxwy(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 0, 7, 5>(self.0, self.0)) + fn wy(self) -> Vec2 { + Vec2 { + x: self.w, + y: self.y, + } } + #[inline] - fn xxwz(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 0, 7, 6>(self.0, self.0)) + fn wz(self) -> Vec2 { + Vec2 { + x: self.w, + y: self.z, + } } + #[inline] - fn xxww(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 0, 7, 7>(self.0, self.0)) + fn ww(self) -> Vec2 { + Vec2 { + x: self.w, + y: self.w, + } } + #[inline] - fn xyxx(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 1, 4, 4>(self.0, self.0)) + fn xxx(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.x, + z: self.x, + } } + #[inline] - fn xyxy(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 1, 4, 5>(self.0, self.0)) + fn xxy(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.x, + z: self.y, + } } + #[inline] - fn xyxz(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 1, 4, 6>(self.0, self.0)) + fn xxz(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.x, + z: self.z, + } } + #[inline] - fn xyxw(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 1, 4, 7>(self.0, self.0)) + fn xxw(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.x, + z: self.w, + } } + #[inline] - fn xyyx(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 1, 5, 4>(self.0, self.0)) + fn xyx(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.y, + z: self.x, + } } + #[inline] - fn xyyy(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 1, 5, 5>(self.0, self.0)) + fn xyy(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.y, + z: self.y, + } } + #[inline] - fn xyyz(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 1, 5, 6>(self.0, self.0)) + fn xyz(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.y, + z: self.z, + } } + #[inline] - fn xyyw(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 1, 5, 7>(self.0, self.0)) + fn xyw(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.y, + z: self.w, + } } + #[inline] - fn xyzx(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 1, 6, 4>(self.0, self.0)) + fn xzx(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.z, + z: self.x, + } } + #[inline] - fn xyzy(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 1, 6, 5>(self.0, self.0)) + fn xzy(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.z, + z: self.y, + } } + #[inline] - fn xyzz(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 1, 6, 6>(self.0, self.0)) + fn xzz(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.z, + z: self.z, + } } + #[inline] - fn xywx(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 1, 7, 4>(self.0, self.0)) + fn xzw(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.z, + z: self.w, + } } + #[inline] - fn xywy(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 1, 7, 5>(self.0, self.0)) + fn xwx(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.w, + z: self.x, + } } + #[inline] - fn xywz(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 1, 7, 6>(self.0, self.0)) + fn xwy(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.w, + z: self.y, + } } + #[inline] - fn xyww(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 1, 7, 7>(self.0, self.0)) + fn xwz(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.w, + z: self.z, + } } + #[inline] - fn xzxx(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 2, 4, 4>(self.0, self.0)) + fn xww(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.w, + z: self.w, + } } + #[inline] - fn xzxy(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 2, 4, 5>(self.0, self.0)) + fn yxx(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.x, + z: self.x, + } } + #[inline] - fn xzxz(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 2, 4, 6>(self.0, self.0)) + fn yxy(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.x, + z: self.y, + } } + #[inline] - fn xzxw(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 2, 4, 7>(self.0, self.0)) + fn yxz(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.x, + z: self.z, + } } + #[inline] - fn xzyx(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 2, 5, 4>(self.0, self.0)) + fn yxw(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.x, + z: self.w, + } } + #[inline] - fn xzyy(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 2, 5, 5>(self.0, self.0)) + fn yyx(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.y, + z: self.x, + } } + #[inline] - fn xzyz(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 2, 5, 6>(self.0, self.0)) + fn yyy(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.y, + z: self.y, + } } + #[inline] - fn xzyw(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 2, 5, 7>(self.0, self.0)) + fn yyz(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.y, + z: self.z, + } } + #[inline] - fn xzzx(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 2, 6, 4>(self.0, self.0)) + fn yyw(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.y, + z: self.w, + } } + #[inline] - fn xzzy(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 2, 6, 5>(self.0, self.0)) + fn yzx(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.z, + z: self.x, + } } + #[inline] - fn xzzz(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 2, 6, 6>(self.0, self.0)) + fn yzy(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.z, + z: self.y, + } } + #[inline] - fn xzzw(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 2, 6, 7>(self.0, self.0)) + fn yzz(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.z, + z: self.z, + } } + #[inline] - fn xzwx(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 2, 7, 4>(self.0, self.0)) + fn yzw(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.z, + z: self.w, + } } + #[inline] - fn xzwy(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 2, 7, 5>(self.0, self.0)) + fn ywx(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.w, + z: self.x, + } } + #[inline] - fn xzwz(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 2, 7, 6>(self.0, self.0)) + fn ywy(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.w, + z: self.y, + } } + #[inline] - fn xzww(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 2, 7, 7>(self.0, self.0)) + fn ywz(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.w, + z: self.z, + } } + #[inline] - fn xwxx(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 3, 4, 4>(self.0, self.0)) + fn yww(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.w, + z: self.w, + } } + #[inline] - fn xwxy(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 3, 4, 5>(self.0, self.0)) + fn zxx(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.x, + z: self.x, + } } + #[inline] - fn xwxz(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 3, 4, 6>(self.0, self.0)) + fn zxy(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.x, + z: self.y, + } } + #[inline] - fn xwxw(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 3, 4, 7>(self.0, self.0)) + fn zxz(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.x, + z: self.z, + } } + #[inline] - fn xwyx(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 3, 5, 4>(self.0, self.0)) + fn zxw(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.x, + z: self.w, + } } + #[inline] - fn xwyy(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 3, 5, 5>(self.0, self.0)) + fn zyx(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.y, + z: self.x, + } } + #[inline] - fn xwyz(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 3, 5, 6>(self.0, self.0)) + fn zyy(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.y, + z: self.y, + } } + #[inline] - fn xwyw(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 3, 5, 7>(self.0, self.0)) + fn zyz(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.y, + z: self.z, + } } + #[inline] - fn xwzx(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 3, 6, 4>(self.0, self.0)) + fn zyw(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.y, + z: self.w, + } } + #[inline] - fn xwzy(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 3, 6, 5>(self.0, self.0)) + fn zzx(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.z, + z: self.x, + } } + #[inline] - fn xwzz(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 3, 6, 6>(self.0, self.0)) + fn zzy(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.z, + z: self.y, + } } + #[inline] - fn xwzw(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 3, 6, 7>(self.0, self.0)) + fn zzz(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.z, + z: self.z, + } } + #[inline] - fn xwwx(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 3, 7, 4>(self.0, self.0)) + fn zzw(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.z, + z: self.w, + } } + #[inline] - fn xwwy(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 3, 7, 5>(self.0, self.0)) + fn zwx(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.w, + z: self.x, + } } + #[inline] - fn xwwz(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 3, 7, 6>(self.0, self.0)) + fn zwy(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.w, + z: self.y, + } } + #[inline] - fn xwww(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 3, 7, 7>(self.0, self.0)) + fn zwz(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.w, + z: self.z, + } } + #[inline] - fn yxxx(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 0, 4, 4>(self.0, self.0)) + fn zww(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.w, + z: self.w, + } } + #[inline] - fn yxxy(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 0, 4, 5>(self.0, self.0)) + fn wxx(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.x, + z: self.x, + } } + #[inline] - fn yxxz(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 0, 4, 6>(self.0, self.0)) + fn wxy(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.x, + z: self.y, + } } + #[inline] - fn yxxw(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 0, 4, 7>(self.0, self.0)) + fn wxz(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.x, + z: self.z, + } } + #[inline] - fn yxyx(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 0, 5, 4>(self.0, self.0)) + fn wxw(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.x, + z: self.w, + } } + #[inline] - fn yxyy(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 0, 5, 5>(self.0, self.0)) + fn wyx(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.y, + z: self.x, + } } + #[inline] - fn yxyz(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 0, 5, 6>(self.0, self.0)) + fn wyy(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.y, + z: self.y, + } } + #[inline] - fn yxyw(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 0, 5, 7>(self.0, self.0)) + fn wyz(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.y, + z: self.z, + } } + #[inline] - fn yxzx(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 0, 6, 4>(self.0, self.0)) + fn wyw(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.y, + z: self.w, + } } + #[inline] - fn yxzy(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 0, 6, 5>(self.0, self.0)) + fn wzx(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.z, + z: self.x, + } } + #[inline] - fn yxzz(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 0, 6, 6>(self.0, self.0)) + fn wzy(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.z, + z: self.y, + } } + #[inline] - fn yxzw(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 0, 6, 7>(self.0, self.0)) + fn wzz(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.z, + z: self.z, + } } + #[inline] - fn yxwx(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 0, 7, 4>(self.0, self.0)) + fn wzw(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.z, + z: self.w, + } } + #[inline] - fn yxwy(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 0, 7, 5>(self.0, self.0)) + fn wwx(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.w, + z: self.x, + } } + #[inline] - fn yxwz(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 0, 7, 6>(self.0, self.0)) + fn wwy(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.w, + z: self.y, + } } + #[inline] - fn yxww(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 0, 7, 7>(self.0, self.0)) + fn wwz(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.w, + z: self.z, + } } + #[inline] - fn yyxx(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 1, 4, 4>(self.0, self.0)) + fn www(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.w, + z: self.w, + } } + #[inline] - fn yyxy(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 1, 4, 5>(self.0, self.0)) + fn xxxx(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 0, 4, 4>(self.0, self.0)) } + #[inline] - fn yyxz(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 1, 4, 6>(self.0, self.0)) + fn xxxy(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 0, 4, 5>(self.0, self.0)) } + #[inline] - fn yyxw(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 1, 4, 7>(self.0, self.0)) + fn xxxz(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 0, 4, 6>(self.0, self.0)) } + #[inline] - fn yyyx(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 1, 5, 4>(self.0, self.0)) + fn xxxw(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 0, 4, 7>(self.0, self.0)) } + #[inline] - fn yyyy(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 1, 5, 5>(self.0, self.0)) + fn xxyx(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 0, 5, 4>(self.0, self.0)) } + #[inline] - fn yyyz(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 1, 5, 6>(self.0, self.0)) + fn xxyy(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 0, 5, 5>(self.0, self.0)) } + #[inline] - fn yyyw(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 1, 5, 7>(self.0, self.0)) + fn xxyz(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 0, 5, 6>(self.0, self.0)) } + #[inline] - fn yyzx(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 1, 6, 4>(self.0, self.0)) + fn xxyw(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 0, 5, 7>(self.0, self.0)) } + #[inline] - fn yyzy(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 1, 6, 5>(self.0, self.0)) + fn xxzx(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 0, 6, 4>(self.0, self.0)) } + #[inline] - fn yyzz(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 1, 6, 6>(self.0, self.0)) + fn xxzy(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 0, 6, 5>(self.0, self.0)) } + #[inline] - fn yyzw(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 1, 6, 7>(self.0, self.0)) + fn xxzz(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 0, 6, 6>(self.0, self.0)) } + #[inline] - fn yywx(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 1, 7, 4>(self.0, self.0)) + fn xxzw(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 0, 6, 7>(self.0, self.0)) } + #[inline] - fn yywy(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 1, 7, 5>(self.0, self.0)) + fn xxwx(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 0, 7, 4>(self.0, self.0)) } + #[inline] - fn yywz(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 1, 7, 6>(self.0, self.0)) + fn xxwy(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 0, 7, 5>(self.0, self.0)) } + #[inline] - fn yyww(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 1, 7, 7>(self.0, self.0)) + fn xxwz(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 0, 7, 6>(self.0, self.0)) } + #[inline] - fn yzxx(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 2, 4, 4>(self.0, self.0)) + fn xxww(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 0, 7, 7>(self.0, self.0)) } + #[inline] - fn yzxy(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 2, 4, 5>(self.0, self.0)) + fn xyxx(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 1, 4, 4>(self.0, self.0)) } + #[inline] - fn yzxz(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 2, 4, 6>(self.0, self.0)) + fn xyxy(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 1, 4, 5>(self.0, self.0)) } + #[inline] - fn yzxw(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 2, 4, 7>(self.0, self.0)) + fn xyxz(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 1, 4, 6>(self.0, self.0)) } + #[inline] - fn yzyx(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 2, 5, 4>(self.0, self.0)) + fn xyxw(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 1, 4, 7>(self.0, self.0)) } + #[inline] - fn yzyy(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 2, 5, 5>(self.0, self.0)) + fn xyyx(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 1, 5, 4>(self.0, self.0)) } + #[inline] - fn yzyz(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 2, 5, 6>(self.0, self.0)) + fn xyyy(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 1, 5, 5>(self.0, self.0)) } + #[inline] - fn yzyw(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 2, 5, 7>(self.0, self.0)) + fn xyyz(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 1, 5, 6>(self.0, self.0)) } + #[inline] - fn yzzx(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 2, 6, 4>(self.0, self.0)) + fn xyyw(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 1, 5, 7>(self.0, self.0)) } + #[inline] - fn yzzy(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 2, 6, 5>(self.0, self.0)) + fn xyzx(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 1, 6, 4>(self.0, self.0)) } + #[inline] - fn yzzz(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 2, 6, 6>(self.0, self.0)) + fn xyzy(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 1, 6, 5>(self.0, self.0)) } + #[inline] - fn yzzw(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 2, 6, 7>(self.0, self.0)) + fn xyzz(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 1, 6, 6>(self.0, self.0)) } + #[inline] - fn yzwx(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 2, 7, 4>(self.0, self.0)) + fn xyzw(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 1, 6, 7>(self.0, self.0)) } + #[inline] - fn yzwy(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 2, 7, 5>(self.0, self.0)) + fn xywx(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 1, 7, 4>(self.0, self.0)) } + #[inline] - fn yzwz(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 2, 7, 6>(self.0, self.0)) + fn xywy(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 1, 7, 5>(self.0, self.0)) } + #[inline] - fn yzww(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 2, 7, 7>(self.0, self.0)) + fn xywz(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 1, 7, 6>(self.0, self.0)) } + #[inline] - fn ywxx(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 3, 4, 4>(self.0, self.0)) + fn xyww(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 1, 7, 7>(self.0, self.0)) } + #[inline] - fn ywxy(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 3, 4, 5>(self.0, self.0)) + fn xzxx(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 2, 4, 4>(self.0, self.0)) } + #[inline] - fn ywxz(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 3, 4, 6>(self.0, self.0)) + fn xzxy(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 2, 4, 5>(self.0, self.0)) } + #[inline] - fn ywxw(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 3, 4, 7>(self.0, self.0)) + fn xzxz(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 2, 4, 6>(self.0, self.0)) } + #[inline] - fn ywyx(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 3, 5, 4>(self.0, self.0)) + fn xzxw(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 2, 4, 7>(self.0, self.0)) } + #[inline] - fn ywyy(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 3, 5, 5>(self.0, self.0)) + fn xzyx(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 2, 5, 4>(self.0, self.0)) } + #[inline] - fn ywyz(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 3, 5, 6>(self.0, self.0)) + fn xzyy(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 2, 5, 5>(self.0, self.0)) } + #[inline] - fn ywyw(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 3, 5, 7>(self.0, self.0)) + fn xzyz(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 2, 5, 6>(self.0, self.0)) } + #[inline] - fn ywzx(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 3, 6, 4>(self.0, self.0)) + fn xzyw(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 2, 5, 7>(self.0, self.0)) } + #[inline] - fn ywzy(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 3, 6, 5>(self.0, self.0)) + fn xzzx(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 2, 6, 4>(self.0, self.0)) } + #[inline] - fn ywzz(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 3, 6, 6>(self.0, self.0)) + fn xzzy(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 2, 6, 5>(self.0, self.0)) } + #[inline] - fn ywzw(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 3, 6, 7>(self.0, self.0)) + fn xzzz(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 2, 6, 6>(self.0, self.0)) } + #[inline] - fn ywwx(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 3, 7, 4>(self.0, self.0)) + fn xzzw(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 2, 6, 7>(self.0, self.0)) } + #[inline] - fn ywwy(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 3, 7, 5>(self.0, self.0)) + fn xzwx(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 2, 7, 4>(self.0, self.0)) } + #[inline] - fn ywwz(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 3, 7, 6>(self.0, self.0)) + fn xzwy(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 2, 7, 5>(self.0, self.0)) } + #[inline] - fn ywww(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 3, 7, 7>(self.0, self.0)) + fn xzwz(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 2, 7, 6>(self.0, self.0)) } + #[inline] - fn zxxx(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 0, 4, 4>(self.0, self.0)) + fn xzww(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 2, 7, 7>(self.0, self.0)) } + #[inline] - fn zxxy(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 0, 4, 5>(self.0, self.0)) + fn xwxx(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 3, 4, 4>(self.0, self.0)) } + #[inline] - fn zxxz(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 0, 4, 6>(self.0, self.0)) + fn xwxy(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 3, 4, 5>(self.0, self.0)) } + #[inline] - fn zxxw(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 0, 4, 7>(self.0, self.0)) + fn xwxz(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 3, 4, 6>(self.0, self.0)) } + #[inline] - fn zxyx(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 0, 5, 4>(self.0, self.0)) + fn xwxw(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 3, 4, 7>(self.0, self.0)) } + #[inline] - fn zxyy(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 0, 5, 5>(self.0, self.0)) + fn xwyx(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 3, 5, 4>(self.0, self.0)) } + #[inline] - fn zxyz(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 0, 5, 6>(self.0, self.0)) + fn xwyy(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 3, 5, 5>(self.0, self.0)) } + #[inline] - fn zxyw(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 0, 5, 7>(self.0, self.0)) + fn xwyz(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 3, 5, 6>(self.0, self.0)) } + #[inline] - fn zxzx(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 0, 6, 4>(self.0, self.0)) + fn xwyw(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 3, 5, 7>(self.0, self.0)) } + #[inline] - fn zxzy(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 0, 6, 5>(self.0, self.0)) + fn xwzx(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 3, 6, 4>(self.0, self.0)) } + #[inline] - fn zxzz(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 0, 6, 6>(self.0, self.0)) + fn xwzy(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 3, 6, 5>(self.0, self.0)) } + #[inline] - fn zxzw(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 0, 6, 7>(self.0, self.0)) + fn xwzz(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 3, 6, 6>(self.0, self.0)) } + #[inline] - fn zxwx(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 0, 7, 4>(self.0, self.0)) + fn xwzw(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 3, 6, 7>(self.0, self.0)) } + #[inline] - fn zxwy(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 0, 7, 5>(self.0, self.0)) + fn xwwx(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 3, 7, 4>(self.0, self.0)) } + #[inline] - fn zxwz(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 0, 7, 6>(self.0, self.0)) + fn xwwy(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 3, 7, 5>(self.0, self.0)) } + #[inline] - fn zxww(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 0, 7, 7>(self.0, self.0)) + fn xwwz(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 3, 7, 6>(self.0, self.0)) } + #[inline] - fn zyxx(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 1, 4, 4>(self.0, self.0)) + fn xwww(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 3, 7, 7>(self.0, self.0)) } + #[inline] - fn zyxy(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 1, 4, 5>(self.0, self.0)) + fn yxxx(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 0, 4, 4>(self.0, self.0)) } + #[inline] - fn zyxz(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 1, 4, 6>(self.0, self.0)) + fn yxxy(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 0, 4, 5>(self.0, self.0)) } + #[inline] - fn zyxw(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 1, 4, 7>(self.0, self.0)) + fn yxxz(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 0, 4, 6>(self.0, self.0)) } + #[inline] - fn zyyx(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 1, 5, 4>(self.0, self.0)) + fn yxxw(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 0, 4, 7>(self.0, self.0)) } + #[inline] - fn zyyy(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 1, 5, 5>(self.0, self.0)) + fn yxyx(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 0, 5, 4>(self.0, self.0)) } + #[inline] - fn zyyz(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 1, 5, 6>(self.0, self.0)) + fn yxyy(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 0, 5, 5>(self.0, self.0)) } + #[inline] - fn zyyw(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 1, 5, 7>(self.0, self.0)) + fn yxyz(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 0, 5, 6>(self.0, self.0)) } + #[inline] - fn zyzx(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 1, 6, 4>(self.0, self.0)) + fn yxyw(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 0, 5, 7>(self.0, self.0)) } + #[inline] - fn zyzy(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 1, 6, 5>(self.0, self.0)) + fn yxzx(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 0, 6, 4>(self.0, self.0)) } + #[inline] - fn zyzz(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 1, 6, 6>(self.0, self.0)) + fn yxzy(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 0, 6, 5>(self.0, self.0)) } + #[inline] - fn zyzw(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 1, 6, 7>(self.0, self.0)) + fn yxzz(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 0, 6, 6>(self.0, self.0)) } + #[inline] - fn zywx(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 1, 7, 4>(self.0, self.0)) + fn yxzw(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 0, 6, 7>(self.0, self.0)) } + #[inline] - fn zywy(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 1, 7, 5>(self.0, self.0)) + fn yxwx(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 0, 7, 4>(self.0, self.0)) } + #[inline] - fn zywz(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 1, 7, 6>(self.0, self.0)) + fn yxwy(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 0, 7, 5>(self.0, self.0)) } + #[inline] - fn zyww(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 1, 7, 7>(self.0, self.0)) + fn yxwz(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 0, 7, 6>(self.0, self.0)) } + #[inline] - fn zzxx(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 2, 4, 4>(self.0, self.0)) + fn yxww(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 0, 7, 7>(self.0, self.0)) } + #[inline] - fn zzxy(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 2, 4, 5>(self.0, self.0)) + fn yyxx(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 1, 4, 4>(self.0, self.0)) } + #[inline] - fn zzxz(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 2, 4, 6>(self.0, self.0)) + fn yyxy(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 1, 4, 5>(self.0, self.0)) } + #[inline] - fn zzxw(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 2, 4, 7>(self.0, self.0)) + fn yyxz(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 1, 4, 6>(self.0, self.0)) } + #[inline] - fn zzyx(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 2, 5, 4>(self.0, self.0)) + fn yyxw(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 1, 4, 7>(self.0, self.0)) } + #[inline] - fn zzyy(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 2, 5, 5>(self.0, self.0)) + fn yyyx(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 1, 5, 4>(self.0, self.0)) } + #[inline] - fn zzyz(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 2, 5, 6>(self.0, self.0)) + fn yyyy(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 1, 5, 5>(self.0, self.0)) } + #[inline] - fn zzyw(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 2, 5, 7>(self.0, self.0)) + fn yyyz(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 1, 5, 6>(self.0, self.0)) } + #[inline] - fn zzzx(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 2, 6, 4>(self.0, self.0)) + fn yyyw(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 1, 5, 7>(self.0, self.0)) } + #[inline] - fn zzzy(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 2, 6, 5>(self.0, self.0)) + fn yyzx(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 1, 6, 4>(self.0, self.0)) } + #[inline] - fn zzzz(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 2, 6, 6>(self.0, self.0)) + fn yyzy(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 1, 6, 5>(self.0, self.0)) } + #[inline] - fn zzzw(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 2, 6, 7>(self.0, self.0)) + fn yyzz(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 1, 6, 6>(self.0, self.0)) } + #[inline] - fn zzwx(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 2, 7, 4>(self.0, self.0)) + fn yyzw(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 1, 6, 7>(self.0, self.0)) } + #[inline] - fn zzwy(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 2, 7, 5>(self.0, self.0)) + fn yywx(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 1, 7, 4>(self.0, self.0)) } + #[inline] - fn zzwz(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 2, 7, 6>(self.0, self.0)) + fn yywy(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 1, 7, 5>(self.0, self.0)) } + #[inline] - fn zzww(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 2, 7, 7>(self.0, self.0)) + fn yywz(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 1, 7, 6>(self.0, self.0)) } + #[inline] - fn zwxx(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 3, 4, 4>(self.0, self.0)) + fn yyww(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 1, 7, 7>(self.0, self.0)) } + #[inline] - fn zwxy(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 3, 4, 5>(self.0, self.0)) + fn yzxx(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 2, 4, 4>(self.0, self.0)) } + #[inline] - fn zwxz(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 3, 4, 6>(self.0, self.0)) + fn yzxy(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 2, 4, 5>(self.0, self.0)) } + #[inline] - fn zwxw(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 3, 4, 7>(self.0, self.0)) + fn yzxz(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 2, 4, 6>(self.0, self.0)) } + #[inline] - fn zwyx(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 3, 5, 4>(self.0, self.0)) + fn yzxw(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 2, 4, 7>(self.0, self.0)) } + #[inline] - fn zwyy(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 3, 5, 5>(self.0, self.0)) + fn yzyx(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 2, 5, 4>(self.0, self.0)) } + #[inline] - fn zwyz(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 3, 5, 6>(self.0, self.0)) + fn yzyy(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 2, 5, 5>(self.0, self.0)) } + #[inline] - fn zwyw(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 3, 5, 7>(self.0, self.0)) + fn yzyz(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 2, 5, 6>(self.0, self.0)) } + #[inline] - fn zwzx(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 3, 6, 4>(self.0, self.0)) + fn yzyw(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 2, 5, 7>(self.0, self.0)) } + #[inline] - fn zwzy(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 3, 6, 5>(self.0, self.0)) + fn yzzx(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 2, 6, 4>(self.0, self.0)) } + #[inline] - fn zwzz(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 3, 6, 6>(self.0, self.0)) + fn yzzy(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 2, 6, 5>(self.0, self.0)) } + #[inline] - fn zwzw(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 3, 6, 7>(self.0, self.0)) + fn yzzz(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 2, 6, 6>(self.0, self.0)) } + #[inline] - fn zwwx(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 3, 7, 4>(self.0, self.0)) + fn yzzw(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 2, 6, 7>(self.0, self.0)) } + #[inline] - fn zwwy(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 3, 7, 5>(self.0, self.0)) + fn yzwx(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 2, 7, 4>(self.0, self.0)) } + #[inline] - fn zwwz(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 3, 7, 6>(self.0, self.0)) + fn yzwy(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 2, 7, 5>(self.0, self.0)) } + #[inline] - fn zwww(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 3, 7, 7>(self.0, self.0)) + fn yzwz(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 2, 7, 6>(self.0, self.0)) } + #[inline] - fn wxxx(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 0, 4, 4>(self.0, self.0)) + fn yzww(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 2, 7, 7>(self.0, self.0)) } + #[inline] - fn wxxy(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 0, 4, 5>(self.0, self.0)) + fn ywxx(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 3, 4, 4>(self.0, self.0)) } + #[inline] - fn wxxz(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 0, 4, 6>(self.0, self.0)) + fn ywxy(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 3, 4, 5>(self.0, self.0)) } + #[inline] - fn wxxw(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 0, 4, 7>(self.0, self.0)) + fn ywxz(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 3, 4, 6>(self.0, self.0)) } + #[inline] - fn wxyx(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 0, 5, 4>(self.0, self.0)) + fn ywxw(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 3, 4, 7>(self.0, self.0)) } + #[inline] - fn wxyy(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 0, 5, 5>(self.0, self.0)) + fn ywyx(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 3, 5, 4>(self.0, self.0)) } + #[inline] - fn wxyz(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 0, 5, 6>(self.0, self.0)) + fn ywyy(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 3, 5, 5>(self.0, self.0)) } + #[inline] - fn wxyw(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 0, 5, 7>(self.0, self.0)) + fn ywyz(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 3, 5, 6>(self.0, self.0)) } + #[inline] - fn wxzx(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 0, 6, 4>(self.0, self.0)) + fn ywyw(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 3, 5, 7>(self.0, self.0)) } + #[inline] - fn wxzy(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 0, 6, 5>(self.0, self.0)) + fn ywzx(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 3, 6, 4>(self.0, self.0)) } + #[inline] - fn wxzz(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 0, 6, 6>(self.0, self.0)) + fn ywzy(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 3, 6, 5>(self.0, self.0)) } + #[inline] - fn wxzw(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 0, 6, 7>(self.0, self.0)) + fn ywzz(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 3, 6, 6>(self.0, self.0)) } + #[inline] - fn wxwx(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 0, 7, 4>(self.0, self.0)) + fn ywzw(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 3, 6, 7>(self.0, self.0)) } + #[inline] - fn wxwy(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 0, 7, 5>(self.0, self.0)) + fn ywwx(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 3, 7, 4>(self.0, self.0)) } + #[inline] - fn wxwz(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 0, 7, 6>(self.0, self.0)) + fn ywwy(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 3, 7, 5>(self.0, self.0)) } + #[inline] - fn wxww(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 0, 7, 7>(self.0, self.0)) + fn ywwz(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 3, 7, 6>(self.0, self.0)) } + #[inline] - fn wyxx(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 1, 4, 4>(self.0, self.0)) + fn ywww(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 3, 7, 7>(self.0, self.0)) } + #[inline] - fn wyxy(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 1, 4, 5>(self.0, self.0)) + fn zxxx(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 0, 4, 4>(self.0, self.0)) } + #[inline] - fn wyxz(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 1, 4, 6>(self.0, self.0)) + fn zxxy(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 0, 4, 5>(self.0, self.0)) } + #[inline] - fn wyxw(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 1, 4, 7>(self.0, self.0)) + fn zxxz(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 0, 4, 6>(self.0, self.0)) } + #[inline] - fn wyyx(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 1, 5, 4>(self.0, self.0)) + fn zxxw(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 0, 4, 7>(self.0, self.0)) } + #[inline] - fn wyyy(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 1, 5, 5>(self.0, self.0)) + fn zxyx(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 0, 5, 4>(self.0, self.0)) } + #[inline] - fn wyyz(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 1, 5, 6>(self.0, self.0)) + fn zxyy(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 0, 5, 5>(self.0, self.0)) } + #[inline] - fn wyyw(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 1, 5, 7>(self.0, self.0)) + fn zxyz(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 0, 5, 6>(self.0, self.0)) } + #[inline] - fn wyzx(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 1, 6, 4>(self.0, self.0)) + fn zxyw(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 0, 5, 7>(self.0, self.0)) } + #[inline] - fn wyzy(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 1, 6, 5>(self.0, self.0)) + fn zxzx(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 0, 6, 4>(self.0, self.0)) + } + + #[inline] + fn zxzy(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 0, 6, 5>(self.0, self.0)) } + #[inline] - fn wyzz(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 1, 6, 6>(self.0, self.0)) + fn zxzz(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 0, 6, 6>(self.0, self.0)) } + #[inline] - fn wyzw(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 1, 6, 7>(self.0, self.0)) + fn zxzw(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 0, 6, 7>(self.0, self.0)) } + #[inline] - fn wywx(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 1, 7, 4>(self.0, self.0)) + fn zxwx(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 0, 7, 4>(self.0, self.0)) } + #[inline] - fn wywy(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 1, 7, 5>(self.0, self.0)) + fn zxwy(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 0, 7, 5>(self.0, self.0)) } + #[inline] - fn wywz(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 1, 7, 6>(self.0, self.0)) + fn zxwz(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 0, 7, 6>(self.0, self.0)) } + #[inline] - fn wyww(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 1, 7, 7>(self.0, self.0)) + fn zxww(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 0, 7, 7>(self.0, self.0)) } + #[inline] - fn wzxx(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 2, 4, 4>(self.0, self.0)) + fn zyxx(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 1, 4, 4>(self.0, self.0)) } + #[inline] - fn wzxy(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 2, 4, 5>(self.0, self.0)) + fn zyxy(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 1, 4, 5>(self.0, self.0)) } + #[inline] - fn wzxz(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 2, 4, 6>(self.0, self.0)) + fn zyxz(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 1, 4, 6>(self.0, self.0)) } + #[inline] - fn wzxw(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 2, 4, 7>(self.0, self.0)) + fn zyxw(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 1, 4, 7>(self.0, self.0)) } + #[inline] - fn wzyx(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 2, 5, 4>(self.0, self.0)) + fn zyyx(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 1, 5, 4>(self.0, self.0)) } + #[inline] - fn wzyy(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 2, 5, 5>(self.0, self.0)) + fn zyyy(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 1, 5, 5>(self.0, self.0)) } + #[inline] - fn wzyz(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 2, 5, 6>(self.0, self.0)) + fn zyyz(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 1, 5, 6>(self.0, self.0)) } + #[inline] - fn wzyw(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 2, 5, 7>(self.0, self.0)) + fn zyyw(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 1, 5, 7>(self.0, self.0)) } + #[inline] - fn wzzx(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 2, 6, 4>(self.0, self.0)) + fn zyzx(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 1, 6, 4>(self.0, self.0)) } + #[inline] - fn wzzy(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 2, 6, 5>(self.0, self.0)) + fn zyzy(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 1, 6, 5>(self.0, self.0)) } + #[inline] - fn wzzz(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 2, 6, 6>(self.0, self.0)) + fn zyzz(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 1, 6, 6>(self.0, self.0)) } + #[inline] - fn wzzw(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 2, 6, 7>(self.0, self.0)) + fn zyzw(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 1, 6, 7>(self.0, self.0)) } + #[inline] - fn wzwx(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 2, 7, 4>(self.0, self.0)) + fn zywx(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 1, 7, 4>(self.0, self.0)) } + #[inline] - fn wzwy(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 2, 7, 5>(self.0, self.0)) + fn zywy(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 1, 7, 5>(self.0, self.0)) } + #[inline] - fn wzwz(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 2, 7, 6>(self.0, self.0)) + fn zywz(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 1, 7, 6>(self.0, self.0)) } + #[inline] - fn wzww(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 2, 7, 7>(self.0, self.0)) + fn zyww(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 1, 7, 7>(self.0, self.0)) } + #[inline] - fn wwxx(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 3, 4, 4>(self.0, self.0)) + fn zzxx(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 2, 4, 4>(self.0, self.0)) } + #[inline] - fn wwxy(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 3, 4, 5>(self.0, self.0)) + fn zzxy(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 2, 4, 5>(self.0, self.0)) } + #[inline] - fn wwxz(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 3, 4, 6>(self.0, self.0)) + fn zzxz(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 2, 4, 6>(self.0, self.0)) } + #[inline] - fn wwxw(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 3, 4, 7>(self.0, self.0)) + fn zzxw(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 2, 4, 7>(self.0, self.0)) } + #[inline] - fn wwyx(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 3, 5, 4>(self.0, self.0)) + fn zzyx(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 2, 5, 4>(self.0, self.0)) } + #[inline] - fn wwyy(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 3, 5, 5>(self.0, self.0)) + fn zzyy(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 2, 5, 5>(self.0, self.0)) } + #[inline] - fn wwyz(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 3, 5, 6>(self.0, self.0)) + fn zzyz(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 2, 5, 6>(self.0, self.0)) } + #[inline] - fn wwyw(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 3, 5, 7>(self.0, self.0)) + fn zzyw(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 2, 5, 7>(self.0, self.0)) } + #[inline] - fn wwzx(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 3, 6, 4>(self.0, self.0)) + fn zzzx(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 2, 6, 4>(self.0, self.0)) } + #[inline] - fn wwzy(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 3, 6, 5>(self.0, self.0)) + fn zzzy(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 2, 6, 5>(self.0, self.0)) } + #[inline] - fn wwzz(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 3, 6, 6>(self.0, self.0)) + fn zzzz(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 2, 6, 6>(self.0, self.0)) } + #[inline] - fn wwzw(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 3, 6, 7>(self.0, self.0)) + fn zzzw(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 2, 6, 7>(self.0, self.0)) } + #[inline] - fn wwwx(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 3, 7, 4>(self.0, self.0)) + fn zzwx(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 2, 7, 4>(self.0, self.0)) } + #[inline] - fn wwwy(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 3, 7, 5>(self.0, self.0)) + fn zzwy(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 2, 7, 5>(self.0, self.0)) } + #[inline] - fn wwwz(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 3, 7, 6>(self.0, self.0)) + fn zzwz(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 2, 7, 6>(self.0, self.0)) } + #[inline] - fn wwww(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 3, 7, 7>(self.0, self.0)) + fn zzww(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 2, 7, 7>(self.0, self.0)) } + #[inline] - fn xxx(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<0, 0, 4, 4>(self.0, self.0))) + fn zwxx(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 3, 4, 4>(self.0, self.0)) } + #[inline] - fn xxy(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<0, 0, 5, 4>(self.0, self.0))) + fn zwxy(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 3, 4, 5>(self.0, self.0)) } + #[inline] - fn xxz(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<0, 0, 6, 4>(self.0, self.0))) + fn zwxz(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 3, 4, 6>(self.0, self.0)) } + #[inline] - fn xxw(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<0, 0, 7, 4>(self.0, self.0))) + fn zwxw(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 3, 4, 7>(self.0, self.0)) } + #[inline] - fn xyx(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<0, 1, 4, 4>(self.0, self.0))) + fn zwyx(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 3, 5, 4>(self.0, self.0)) } + #[inline] - fn xyy(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<0, 1, 5, 4>(self.0, self.0))) + fn zwyy(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 3, 5, 5>(self.0, self.0)) } + #[inline] - fn xyz(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<0, 1, 6, 4>(self.0, self.0))) + fn zwyz(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 3, 5, 6>(self.0, self.0)) } + #[inline] - fn xyw(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<0, 1, 7, 4>(self.0, self.0))) + fn zwyw(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 3, 5, 7>(self.0, self.0)) } + #[inline] - fn xzx(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<0, 2, 4, 4>(self.0, self.0))) + fn zwzx(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 3, 6, 4>(self.0, self.0)) } + #[inline] - fn xzy(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<0, 2, 5, 4>(self.0, self.0))) + fn zwzy(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 3, 6, 5>(self.0, self.0)) } + #[inline] - fn xzz(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<0, 2, 6, 4>(self.0, self.0))) + fn zwzz(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 3, 6, 6>(self.0, self.0)) } + #[inline] - fn xzw(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<0, 2, 7, 4>(self.0, self.0))) + fn zwzw(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 3, 6, 7>(self.0, self.0)) } + #[inline] - fn xwx(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<0, 3, 4, 4>(self.0, self.0))) + fn zwwx(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 3, 7, 4>(self.0, self.0)) } + #[inline] - fn xwy(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<0, 3, 5, 4>(self.0, self.0))) + fn zwwy(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 3, 7, 5>(self.0, self.0)) } + #[inline] - fn xwz(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<0, 3, 6, 4>(self.0, self.0))) + fn zwwz(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 3, 7, 6>(self.0, self.0)) } + #[inline] - fn xww(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<0, 3, 7, 4>(self.0, self.0))) + fn zwww(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 3, 7, 7>(self.0, self.0)) } + #[inline] - fn yxx(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<1, 0, 4, 4>(self.0, self.0))) + fn wxxx(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 0, 4, 4>(self.0, self.0)) } + #[inline] - fn yxy(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<1, 0, 5, 4>(self.0, self.0))) + fn wxxy(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 0, 4, 5>(self.0, self.0)) } + #[inline] - fn yxz(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<1, 0, 6, 4>(self.0, self.0))) + fn wxxz(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 0, 4, 6>(self.0, self.0)) } + #[inline] - fn yxw(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<1, 0, 7, 4>(self.0, self.0))) + fn wxxw(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 0, 4, 7>(self.0, self.0)) } + #[inline] - fn yyx(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<1, 1, 4, 4>(self.0, self.0))) + fn wxyx(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 0, 5, 4>(self.0, self.0)) } + #[inline] - fn yyy(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<1, 1, 5, 4>(self.0, self.0))) + fn wxyy(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 0, 5, 5>(self.0, self.0)) } + #[inline] - fn yyz(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<1, 1, 6, 4>(self.0, self.0))) + fn wxyz(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 0, 5, 6>(self.0, self.0)) } + #[inline] - fn yyw(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<1, 1, 7, 4>(self.0, self.0))) + fn wxyw(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 0, 5, 7>(self.0, self.0)) } + #[inline] - fn yzx(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<1, 2, 4, 4>(self.0, self.0))) + fn wxzx(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 0, 6, 4>(self.0, self.0)) } + #[inline] - fn yzy(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<1, 2, 5, 4>(self.0, self.0))) + fn wxzy(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 0, 6, 5>(self.0, self.0)) } + #[inline] - fn yzz(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<1, 2, 6, 4>(self.0, self.0))) + fn wxzz(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 0, 6, 6>(self.0, self.0)) } + #[inline] - fn yzw(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<1, 2, 7, 4>(self.0, self.0))) + fn wxzw(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 0, 6, 7>(self.0, self.0)) } + #[inline] - fn ywx(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<1, 3, 4, 4>(self.0, self.0))) + fn wxwx(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 0, 7, 4>(self.0, self.0)) } + #[inline] - fn ywy(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<1, 3, 5, 4>(self.0, self.0))) + fn wxwy(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 0, 7, 5>(self.0, self.0)) } + #[inline] - fn ywz(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<1, 3, 6, 4>(self.0, self.0))) + fn wxwz(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 0, 7, 6>(self.0, self.0)) } + #[inline] - fn yww(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<1, 3, 7, 4>(self.0, self.0))) + fn wxww(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 0, 7, 7>(self.0, self.0)) } + #[inline] - fn zxx(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<2, 0, 4, 4>(self.0, self.0))) + fn wyxx(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 1, 4, 4>(self.0, self.0)) } + #[inline] - fn zxy(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<2, 0, 5, 4>(self.0, self.0))) + fn wyxy(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 1, 4, 5>(self.0, self.0)) } + #[inline] - fn zxz(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<2, 0, 6, 4>(self.0, self.0))) + fn wyxz(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 1, 4, 6>(self.0, self.0)) } + #[inline] - fn zxw(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<2, 0, 7, 4>(self.0, self.0))) + fn wyxw(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 1, 4, 7>(self.0, self.0)) } + #[inline] - fn zyx(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<2, 1, 4, 4>(self.0, self.0))) + fn wyyx(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 1, 5, 4>(self.0, self.0)) } + #[inline] - fn zyy(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<2, 1, 5, 4>(self.0, self.0))) + fn wyyy(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 1, 5, 5>(self.0, self.0)) } + #[inline] - fn zyz(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<2, 1, 6, 4>(self.0, self.0))) + fn wyyz(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 1, 5, 6>(self.0, self.0)) } + #[inline] - fn zyw(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<2, 1, 7, 4>(self.0, self.0))) + fn wyyw(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 1, 5, 7>(self.0, self.0)) } + #[inline] - fn zzx(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<2, 2, 4, 4>(self.0, self.0))) + fn wyzx(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 1, 6, 4>(self.0, self.0)) } + #[inline] - fn zzy(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<2, 2, 5, 4>(self.0, self.0))) + fn wyzy(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 1, 6, 5>(self.0, self.0)) } + #[inline] - fn zzz(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<2, 2, 6, 4>(self.0, self.0))) + fn wyzz(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 1, 6, 6>(self.0, self.0)) } + #[inline] - fn zzw(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<2, 2, 7, 4>(self.0, self.0))) + fn wyzw(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 1, 6, 7>(self.0, self.0)) } + #[inline] - fn zwx(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<2, 3, 4, 4>(self.0, self.0))) + fn wywx(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 1, 7, 4>(self.0, self.0)) } + #[inline] - fn zwy(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<2, 3, 5, 4>(self.0, self.0))) + fn wywy(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 1, 7, 5>(self.0, self.0)) } + #[inline] - fn zwz(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<2, 3, 6, 4>(self.0, self.0))) + fn wywz(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 1, 7, 6>(self.0, self.0)) } + #[inline] - fn zww(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<2, 3, 7, 4>(self.0, self.0))) + fn wyww(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 1, 7, 7>(self.0, self.0)) } + #[inline] - fn wxx(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<3, 0, 4, 4>(self.0, self.0))) + fn wzxx(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 2, 4, 4>(self.0, self.0)) } + #[inline] - fn wxy(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<3, 0, 5, 4>(self.0, self.0))) + fn wzxy(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 2, 4, 5>(self.0, self.0)) } + #[inline] - fn wxz(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<3, 0, 6, 4>(self.0, self.0))) + fn wzxz(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 2, 4, 6>(self.0, self.0)) } + #[inline] - fn wxw(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<3, 0, 7, 4>(self.0, self.0))) + fn wzxw(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 2, 4, 7>(self.0, self.0)) } + #[inline] - fn wyx(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<3, 1, 4, 4>(self.0, self.0))) + fn wzyx(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 2, 5, 4>(self.0, self.0)) } + #[inline] - fn wyy(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<3, 1, 5, 4>(self.0, self.0))) + fn wzyy(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 2, 5, 5>(self.0, self.0)) } + #[inline] - fn wyz(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<3, 1, 6, 4>(self.0, self.0))) + fn wzyz(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 2, 5, 6>(self.0, self.0)) } + #[inline] - fn wyw(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<3, 1, 7, 4>(self.0, self.0))) + fn wzyw(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 2, 5, 7>(self.0, self.0)) } + #[inline] - fn wzx(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<3, 2, 4, 4>(self.0, self.0))) + fn wzzx(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 2, 6, 4>(self.0, self.0)) } + #[inline] - fn wzy(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<3, 2, 5, 4>(self.0, self.0))) + fn wzzy(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 2, 6, 5>(self.0, self.0)) } + #[inline] - fn wzz(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<3, 2, 6, 4>(self.0, self.0))) + fn wzzz(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 2, 6, 6>(self.0, self.0)) } + #[inline] - fn wzw(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<3, 2, 7, 4>(self.0, self.0))) + fn wzzw(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 2, 6, 7>(self.0, self.0)) } + #[inline] - fn wwx(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<3, 3, 4, 4>(self.0, self.0))) + fn wzwx(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 2, 7, 4>(self.0, self.0)) } + #[inline] - fn wwy(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<3, 3, 5, 4>(self.0, self.0))) + fn wzwy(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 2, 7, 5>(self.0, self.0)) } + #[inline] - fn wwz(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<3, 3, 6, 4>(self.0, self.0))) + fn wzwz(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 2, 7, 6>(self.0, self.0)) } + #[inline] - fn www(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<3, 3, 7, 4>(self.0, self.0))) + fn wzww(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 2, 7, 7>(self.0, self.0)) } + #[inline] - fn xx(self) -> Vec2 { - Vec2(XY::from(i32x4_shuffle::<0, 0, 4, 4>(self.0, self.0))) + fn wwxx(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 3, 4, 4>(self.0, self.0)) } + #[inline] - fn xy(self) -> Vec2 { - Vec2(XY::from(i32x4_shuffle::<0, 1, 4, 4>(self.0, self.0))) + fn wwxy(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 3, 4, 5>(self.0, self.0)) } + #[inline] - fn xz(self) -> Vec2 { - Vec2(XY::from(i32x4_shuffle::<0, 2, 4, 4>(self.0, self.0))) + fn wwxz(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 3, 4, 6>(self.0, self.0)) } + #[inline] - fn xw(self) -> Vec2 { - Vec2(XY::from(i32x4_shuffle::<0, 3, 4, 4>(self.0, self.0))) + fn wwxw(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 3, 4, 7>(self.0, self.0)) } + #[inline] - fn yx(self) -> Vec2 { - Vec2(XY::from(i32x4_shuffle::<1, 0, 4, 4>(self.0, self.0))) + fn wwyx(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 3, 5, 4>(self.0, self.0)) } + #[inline] - fn yy(self) -> Vec2 { - Vec2(XY::from(i32x4_shuffle::<1, 1, 4, 4>(self.0, self.0))) + fn wwyy(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 3, 5, 5>(self.0, self.0)) } + #[inline] - fn yz(self) -> Vec2 { - Vec2(XY::from(i32x4_shuffle::<1, 2, 4, 4>(self.0, self.0))) + fn wwyz(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 3, 5, 6>(self.0, self.0)) } + #[inline] - fn yw(self) -> Vec2 { - Vec2(XY::from(i32x4_shuffle::<1, 3, 4, 4>(self.0, self.0))) + fn wwyw(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 3, 5, 7>(self.0, self.0)) } + #[inline] - fn zx(self) -> Vec2 { - Vec2(XY::from(i32x4_shuffle::<2, 0, 4, 4>(self.0, self.0))) + fn wwzx(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 3, 6, 4>(self.0, self.0)) } + #[inline] - fn zy(self) -> Vec2 { - Vec2(XY::from(i32x4_shuffle::<2, 1, 4, 4>(self.0, self.0))) + fn wwzy(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 3, 6, 5>(self.0, self.0)) } + #[inline] - fn zz(self) -> Vec2 { - Vec2(XY::from(i32x4_shuffle::<2, 2, 4, 4>(self.0, self.0))) + fn wwzz(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 3, 6, 6>(self.0, self.0)) } + #[inline] - fn zw(self) -> Vec2 { - Vec2(XY::from(i32x4_shuffle::<2, 3, 4, 4>(self.0, self.0))) + fn wwzw(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 3, 6, 7>(self.0, self.0)) } + #[inline] - fn wx(self) -> Vec2 { - Vec2(XY::from(i32x4_shuffle::<3, 0, 4, 4>(self.0, self.0))) + fn wwwx(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 3, 7, 4>(self.0, self.0)) } + #[inline] - fn wy(self) -> Vec2 { - Vec2(XY::from(i32x4_shuffle::<3, 1, 4, 4>(self.0, self.0))) + fn wwwy(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 3, 7, 5>(self.0, self.0)) } + #[inline] - fn wz(self) -> Vec2 { - Vec2(XY::from(i32x4_shuffle::<3, 2, 4, 4>(self.0, self.0))) + fn wwwz(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 3, 7, 6>(self.0, self.0)) } + #[inline] - fn ww(self) -> Vec2 { - Vec2(XY::from(i32x4_shuffle::<3, 3, 4, 4>(self.0, self.0))) + fn wwww(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 3, 7, 7>(self.0, self.0)) } } diff --git a/src/swizzles/vec_traits.rs b/src/swizzles/vec_traits.rs index fc9bb4ac..64fb482e 100644 --- a/src/swizzles/vec_traits.rs +++ b/src/swizzles/vec_traits.rs @@ -1,7 +1,8 @@ -// Generated by swizzlegen. Do not edit. -/** Swizzle methods for 2-dimensional vector types. */ +// Generated from swizzle_traits.rs template. Edit the template, not the generated file. + pub trait Vec2Swizzles: Sized + Copy + Clone { type Vec3; + type Vec4; #[inline] @@ -9,37 +10,64 @@ pub trait Vec2Swizzles: Sized + Copy + Clone { self } + fn xx(self) -> Self; + + fn yx(self) -> Self; + + fn yy(self) -> Self; + + fn xxx(self) -> Self::Vec3; + + fn xxy(self) -> Self::Vec3; + + fn xyx(self) -> Self::Vec3; + + fn xyy(self) -> Self::Vec3; + + fn yxx(self) -> Self::Vec3; + + fn yxy(self) -> Self::Vec3; + + fn yyx(self) -> Self::Vec3; + + fn yyy(self) -> Self::Vec3; + fn xxxx(self) -> Self::Vec4; + fn xxxy(self) -> Self::Vec4; + fn xxyx(self) -> Self::Vec4; + fn xxyy(self) -> Self::Vec4; + fn xyxx(self) -> Self::Vec4; + fn xyxy(self) -> Self::Vec4; + fn xyyx(self) -> Self::Vec4; + fn xyyy(self) -> Self::Vec4; + fn yxxx(self) -> Self::Vec4; + fn yxxy(self) -> Self::Vec4; + fn yxyx(self) -> Self::Vec4; + fn yxyy(self) -> Self::Vec4; + fn yyxx(self) -> Self::Vec4; + fn yyxy(self) -> Self::Vec4; + fn yyyx(self) -> Self::Vec4; + fn yyyy(self) -> Self::Vec4; - fn xxx(self) -> Self::Vec3; - fn xxy(self) -> Self::Vec3; - fn xyx(self) -> Self::Vec3; - fn xyy(self) -> Self::Vec3; - fn yxx(self) -> Self::Vec3; - fn yxy(self) -> Self::Vec3; - fn yyx(self) -> Self::Vec3; - fn yyy(self) -> Self::Vec3; - fn xx(self) -> Self; - fn yx(self) -> Self; - fn yy(self) -> Self; } -/** Swizzle methods for 3-dimensional vector types. */ + pub trait Vec3Swizzles: Sized + Copy + Clone { type Vec2; + type Vec4; #[inline] @@ -47,466 +75,916 @@ pub trait Vec3Swizzles: Sized + Copy + Clone { self } + fn xx(self) -> Self::Vec2; + + fn xy(self) -> Self::Vec2; + + fn xz(self) -> Self::Vec2; + + fn yx(self) -> Self::Vec2; + + fn yy(self) -> Self::Vec2; + + fn yz(self) -> Self::Vec2; + + fn zx(self) -> Self::Vec2; + + fn zy(self) -> Self::Vec2; + + fn zz(self) -> Self::Vec2; + + fn xxx(self) -> Self; + + fn xxy(self) -> Self; + + fn xxz(self) -> Self; + + fn xyx(self) -> Self; + + fn xyy(self) -> Self; + + fn xzx(self) -> Self; + + fn xzy(self) -> Self; + + fn xzz(self) -> Self; + + fn yxx(self) -> Self; + + fn yxy(self) -> Self; + + fn yxz(self) -> Self; + + fn yyx(self) -> Self; + + fn yyy(self) -> Self; + + fn yyz(self) -> Self; + + fn yzx(self) -> Self; + + fn yzy(self) -> Self; + + fn yzz(self) -> Self; + + fn zxx(self) -> Self; + + fn zxy(self) -> Self; + + fn zxz(self) -> Self; + + fn zyx(self) -> Self; + + fn zyy(self) -> Self; + + fn zyz(self) -> Self; + + fn zzx(self) -> Self; + + fn zzy(self) -> Self; + + fn zzz(self) -> Self; + fn xxxx(self) -> Self::Vec4; + fn xxxy(self) -> Self::Vec4; + fn xxxz(self) -> Self::Vec4; + fn xxyx(self) -> Self::Vec4; + fn xxyy(self) -> Self::Vec4; + fn xxyz(self) -> Self::Vec4; + fn xxzx(self) -> Self::Vec4; + fn xxzy(self) -> Self::Vec4; + fn xxzz(self) -> Self::Vec4; + fn xyxx(self) -> Self::Vec4; + fn xyxy(self) -> Self::Vec4; + fn xyxz(self) -> Self::Vec4; + fn xyyx(self) -> Self::Vec4; + fn xyyy(self) -> Self::Vec4; + fn xyyz(self) -> Self::Vec4; + fn xyzx(self) -> Self::Vec4; + fn xyzy(self) -> Self::Vec4; + fn xyzz(self) -> Self::Vec4; + fn xzxx(self) -> Self::Vec4; + fn xzxy(self) -> Self::Vec4; + fn xzxz(self) -> Self::Vec4; + fn xzyx(self) -> Self::Vec4; + fn xzyy(self) -> Self::Vec4; + fn xzyz(self) -> Self::Vec4; + fn xzzx(self) -> Self::Vec4; + fn xzzy(self) -> Self::Vec4; + fn xzzz(self) -> Self::Vec4; + fn yxxx(self) -> Self::Vec4; + fn yxxy(self) -> Self::Vec4; + fn yxxz(self) -> Self::Vec4; + fn yxyx(self) -> Self::Vec4; + fn yxyy(self) -> Self::Vec4; + fn yxyz(self) -> Self::Vec4; + fn yxzx(self) -> Self::Vec4; + fn yxzy(self) -> Self::Vec4; + fn yxzz(self) -> Self::Vec4; + fn yyxx(self) -> Self::Vec4; + fn yyxy(self) -> Self::Vec4; + fn yyxz(self) -> Self::Vec4; + fn yyyx(self) -> Self::Vec4; + fn yyyy(self) -> Self::Vec4; + fn yyyz(self) -> Self::Vec4; + fn yyzx(self) -> Self::Vec4; + fn yyzy(self) -> Self::Vec4; + fn yyzz(self) -> Self::Vec4; + fn yzxx(self) -> Self::Vec4; + fn yzxy(self) -> Self::Vec4; + fn yzxz(self) -> Self::Vec4; + fn yzyx(self) -> Self::Vec4; + fn yzyy(self) -> Self::Vec4; + fn yzyz(self) -> Self::Vec4; + fn yzzx(self) -> Self::Vec4; + fn yzzy(self) -> Self::Vec4; + fn yzzz(self) -> Self::Vec4; + fn zxxx(self) -> Self::Vec4; + fn zxxy(self) -> Self::Vec4; + fn zxxz(self) -> Self::Vec4; + fn zxyx(self) -> Self::Vec4; + fn zxyy(self) -> Self::Vec4; + fn zxyz(self) -> Self::Vec4; + fn zxzx(self) -> Self::Vec4; + fn zxzy(self) -> Self::Vec4; + fn zxzz(self) -> Self::Vec4; + fn zyxx(self) -> Self::Vec4; + fn zyxy(self) -> Self::Vec4; + fn zyxz(self) -> Self::Vec4; + fn zyyx(self) -> Self::Vec4; + fn zyyy(self) -> Self::Vec4; + fn zyyz(self) -> Self::Vec4; + fn zyzx(self) -> Self::Vec4; + fn zyzy(self) -> Self::Vec4; + fn zyzz(self) -> Self::Vec4; + fn zzxx(self) -> Self::Vec4; + fn zzxy(self) -> Self::Vec4; + fn zzxz(self) -> Self::Vec4; + fn zzyx(self) -> Self::Vec4; + fn zzyy(self) -> Self::Vec4; + fn zzyz(self) -> Self::Vec4; + fn zzzx(self) -> Self::Vec4; + fn zzzy(self) -> Self::Vec4; + fn zzzz(self) -> Self::Vec4; - fn xxx(self) -> Self; - fn xxy(self) -> Self; - fn xxz(self) -> Self; - fn xyx(self) -> Self; - fn xyy(self) -> Self; - fn xzx(self) -> Self; - fn xzy(self) -> Self; - fn xzz(self) -> Self; - fn yxx(self) -> Self; - fn yxy(self) -> Self; - fn yxz(self) -> Self; - fn yyx(self) -> Self; - fn yyy(self) -> Self; - fn yyz(self) -> Self; - fn yzx(self) -> Self; - fn yzy(self) -> Self; - fn yzz(self) -> Self; - fn zxx(self) -> Self; - fn zxy(self) -> Self; - fn zxz(self) -> Self; - fn zyx(self) -> Self; - fn zyy(self) -> Self; - fn zyz(self) -> Self; - fn zzx(self) -> Self; - fn zzy(self) -> Self; - fn zzz(self) -> Self; +} + +pub trait Vec4Swizzles: Sized + Copy + Clone { + type Vec2; + + type Vec3; + + #[inline] + fn xyzw(self) -> Self { + self + } + fn xx(self) -> Self::Vec2; + fn xy(self) -> Self::Vec2; + fn xz(self) -> Self::Vec2; + + fn xw(self) -> Self::Vec2; + fn yx(self) -> Self::Vec2; + fn yy(self) -> Self::Vec2; + fn yz(self) -> Self::Vec2; + + fn yw(self) -> Self::Vec2; + fn zx(self) -> Self::Vec2; + fn zy(self) -> Self::Vec2; + fn zz(self) -> Self::Vec2; -} -/** Swizzle methods for 4-dimensional vector types. */ -pub trait Vec4Swizzles: Sized + Copy + Clone { - type Vec2; - type Vec3; - #[inline] - fn xyzw(self) -> Self { - self - } + fn zw(self) -> Self::Vec2; + + fn wx(self) -> Self::Vec2; + + fn wy(self) -> Self::Vec2; + + fn wz(self) -> Self::Vec2; + + fn ww(self) -> Self::Vec2; + + fn xxx(self) -> Self::Vec3; + + fn xxy(self) -> Self::Vec3; + + fn xxz(self) -> Self::Vec3; + + fn xxw(self) -> Self::Vec3; + + fn xyx(self) -> Self::Vec3; + + fn xyy(self) -> Self::Vec3; + + fn xyz(self) -> Self::Vec3; + + fn xyw(self) -> Self::Vec3; + + fn xzx(self) -> Self::Vec3; + + fn xzy(self) -> Self::Vec3; + + fn xzz(self) -> Self::Vec3; + + fn xzw(self) -> Self::Vec3; + + fn xwx(self) -> Self::Vec3; + + fn xwy(self) -> Self::Vec3; + + fn xwz(self) -> Self::Vec3; + + fn xww(self) -> Self::Vec3; + + fn yxx(self) -> Self::Vec3; + + fn yxy(self) -> Self::Vec3; + + fn yxz(self) -> Self::Vec3; + + fn yxw(self) -> Self::Vec3; + + fn yyx(self) -> Self::Vec3; + + fn yyy(self) -> Self::Vec3; + + fn yyz(self) -> Self::Vec3; + + fn yyw(self) -> Self::Vec3; + + fn yzx(self) -> Self::Vec3; + + fn yzy(self) -> Self::Vec3; + + fn yzz(self) -> Self::Vec3; + + fn yzw(self) -> Self::Vec3; + + fn ywx(self) -> Self::Vec3; + + fn ywy(self) -> Self::Vec3; + + fn ywz(self) -> Self::Vec3; + + fn yww(self) -> Self::Vec3; + + fn zxx(self) -> Self::Vec3; + + fn zxy(self) -> Self::Vec3; + + fn zxz(self) -> Self::Vec3; + + fn zxw(self) -> Self::Vec3; + + fn zyx(self) -> Self::Vec3; + + fn zyy(self) -> Self::Vec3; + + fn zyz(self) -> Self::Vec3; + + fn zyw(self) -> Self::Vec3; + + fn zzx(self) -> Self::Vec3; + + fn zzy(self) -> Self::Vec3; + + fn zzz(self) -> Self::Vec3; + + fn zzw(self) -> Self::Vec3; + + fn zwx(self) -> Self::Vec3; + + fn zwy(self) -> Self::Vec3; + + fn zwz(self) -> Self::Vec3; + + fn zww(self) -> Self::Vec3; + + fn wxx(self) -> Self::Vec3; + + fn wxy(self) -> Self::Vec3; + + fn wxz(self) -> Self::Vec3; + + fn wxw(self) -> Self::Vec3; + + fn wyx(self) -> Self::Vec3; + + fn wyy(self) -> Self::Vec3; + + fn wyz(self) -> Self::Vec3; + + fn wyw(self) -> Self::Vec3; + + fn wzx(self) -> Self::Vec3; + + fn wzy(self) -> Self::Vec3; + + fn wzz(self) -> Self::Vec3; + + fn wzw(self) -> Self::Vec3; + + fn wwx(self) -> Self::Vec3; + + fn wwy(self) -> Self::Vec3; + + fn wwz(self) -> Self::Vec3; + + fn www(self) -> Self::Vec3; fn xxxx(self) -> Self; + fn xxxy(self) -> Self; + fn xxxz(self) -> Self; + fn xxxw(self) -> Self; + fn xxyx(self) -> Self; + fn xxyy(self) -> Self; + fn xxyz(self) -> Self; + fn xxyw(self) -> Self; + fn xxzx(self) -> Self; + fn xxzy(self) -> Self; + fn xxzz(self) -> Self; + fn xxzw(self) -> Self; + fn xxwx(self) -> Self; + fn xxwy(self) -> Self; + fn xxwz(self) -> Self; + fn xxww(self) -> Self; + fn xyxx(self) -> Self; + fn xyxy(self) -> Self; + fn xyxz(self) -> Self; + fn xyxw(self) -> Self; + fn xyyx(self) -> Self; + fn xyyy(self) -> Self; + fn xyyz(self) -> Self; + fn xyyw(self) -> Self; + fn xyzx(self) -> Self; + fn xyzy(self) -> Self; + fn xyzz(self) -> Self; + fn xywx(self) -> Self; + fn xywy(self) -> Self; + fn xywz(self) -> Self; + fn xyww(self) -> Self; + fn xzxx(self) -> Self; + fn xzxy(self) -> Self; + fn xzxz(self) -> Self; + fn xzxw(self) -> Self; + fn xzyx(self) -> Self; + fn xzyy(self) -> Self; + fn xzyz(self) -> Self; + fn xzyw(self) -> Self; + fn xzzx(self) -> Self; + fn xzzy(self) -> Self; + fn xzzz(self) -> Self; + fn xzzw(self) -> Self; + fn xzwx(self) -> Self; + fn xzwy(self) -> Self; + fn xzwz(self) -> Self; + fn xzww(self) -> Self; + fn xwxx(self) -> Self; + fn xwxy(self) -> Self; + fn xwxz(self) -> Self; + fn xwxw(self) -> Self; + fn xwyx(self) -> Self; + fn xwyy(self) -> Self; + fn xwyz(self) -> Self; + fn xwyw(self) -> Self; + fn xwzx(self) -> Self; + fn xwzy(self) -> Self; + fn xwzz(self) -> Self; + fn xwzw(self) -> Self; + fn xwwx(self) -> Self; + fn xwwy(self) -> Self; + fn xwwz(self) -> Self; + fn xwww(self) -> Self; + fn yxxx(self) -> Self; + fn yxxy(self) -> Self; + fn yxxz(self) -> Self; + fn yxxw(self) -> Self; + fn yxyx(self) -> Self; + fn yxyy(self) -> Self; + fn yxyz(self) -> Self; + fn yxyw(self) -> Self; + fn yxzx(self) -> Self; + fn yxzy(self) -> Self; + fn yxzz(self) -> Self; + fn yxzw(self) -> Self; + fn yxwx(self) -> Self; + fn yxwy(self) -> Self; + fn yxwz(self) -> Self; + fn yxww(self) -> Self; + fn yyxx(self) -> Self; + fn yyxy(self) -> Self; + fn yyxz(self) -> Self; + fn yyxw(self) -> Self; + fn yyyx(self) -> Self; + fn yyyy(self) -> Self; + fn yyyz(self) -> Self; + fn yyyw(self) -> Self; + fn yyzx(self) -> Self; + fn yyzy(self) -> Self; + fn yyzz(self) -> Self; + fn yyzw(self) -> Self; + fn yywx(self) -> Self; + fn yywy(self) -> Self; + fn yywz(self) -> Self; + fn yyww(self) -> Self; + fn yzxx(self) -> Self; + fn yzxy(self) -> Self; + fn yzxz(self) -> Self; + fn yzxw(self) -> Self; + fn yzyx(self) -> Self; + fn yzyy(self) -> Self; + fn yzyz(self) -> Self; + fn yzyw(self) -> Self; + fn yzzx(self) -> Self; + fn yzzy(self) -> Self; + fn yzzz(self) -> Self; + fn yzzw(self) -> Self; + fn yzwx(self) -> Self; + fn yzwy(self) -> Self; + fn yzwz(self) -> Self; + fn yzww(self) -> Self; + fn ywxx(self) -> Self; + fn ywxy(self) -> Self; + fn ywxz(self) -> Self; + fn ywxw(self) -> Self; + fn ywyx(self) -> Self; + fn ywyy(self) -> Self; + fn ywyz(self) -> Self; + fn ywyw(self) -> Self; + fn ywzx(self) -> Self; + fn ywzy(self) -> Self; + fn ywzz(self) -> Self; + fn ywzw(self) -> Self; + fn ywwx(self) -> Self; + fn ywwy(self) -> Self; + fn ywwz(self) -> Self; + fn ywww(self) -> Self; + fn zxxx(self) -> Self; + fn zxxy(self) -> Self; + fn zxxz(self) -> Self; + fn zxxw(self) -> Self; + fn zxyx(self) -> Self; + fn zxyy(self) -> Self; + fn zxyz(self) -> Self; + fn zxyw(self) -> Self; + fn zxzx(self) -> Self; + fn zxzy(self) -> Self; + fn zxzz(self) -> Self; + fn zxzw(self) -> Self; + fn zxwx(self) -> Self; + fn zxwy(self) -> Self; + fn zxwz(self) -> Self; + fn zxww(self) -> Self; + fn zyxx(self) -> Self; + fn zyxy(self) -> Self; + fn zyxz(self) -> Self; + fn zyxw(self) -> Self; + fn zyyx(self) -> Self; + fn zyyy(self) -> Self; + fn zyyz(self) -> Self; + fn zyyw(self) -> Self; + fn zyzx(self) -> Self; + fn zyzy(self) -> Self; + fn zyzz(self) -> Self; + fn zyzw(self) -> Self; + fn zywx(self) -> Self; + fn zywy(self) -> Self; + fn zywz(self) -> Self; + fn zyww(self) -> Self; + fn zzxx(self) -> Self; + fn zzxy(self) -> Self; + fn zzxz(self) -> Self; + fn zzxw(self) -> Self; + fn zzyx(self) -> Self; + fn zzyy(self) -> Self; + fn zzyz(self) -> Self; + fn zzyw(self) -> Self; + fn zzzx(self) -> Self; + fn zzzy(self) -> Self; + fn zzzz(self) -> Self; + fn zzzw(self) -> Self; + fn zzwx(self) -> Self; + fn zzwy(self) -> Self; + fn zzwz(self) -> Self; + fn zzww(self) -> Self; + fn zwxx(self) -> Self; + fn zwxy(self) -> Self; + fn zwxz(self) -> Self; + fn zwxw(self) -> Self; + fn zwyx(self) -> Self; + fn zwyy(self) -> Self; + fn zwyz(self) -> Self; + fn zwyw(self) -> Self; + fn zwzx(self) -> Self; + fn zwzy(self) -> Self; + fn zwzz(self) -> Self; + fn zwzw(self) -> Self; + fn zwwx(self) -> Self; + fn zwwy(self) -> Self; + fn zwwz(self) -> Self; + fn zwww(self) -> Self; + fn wxxx(self) -> Self; + fn wxxy(self) -> Self; + fn wxxz(self) -> Self; + fn wxxw(self) -> Self; + fn wxyx(self) -> Self; + fn wxyy(self) -> Self; + fn wxyz(self) -> Self; + fn wxyw(self) -> Self; + fn wxzx(self) -> Self; + fn wxzy(self) -> Self; + fn wxzz(self) -> Self; + fn wxzw(self) -> Self; + fn wxwx(self) -> Self; + fn wxwy(self) -> Self; + fn wxwz(self) -> Self; + fn wxww(self) -> Self; + fn wyxx(self) -> Self; + fn wyxy(self) -> Self; + fn wyxz(self) -> Self; + fn wyxw(self) -> Self; + fn wyyx(self) -> Self; + fn wyyy(self) -> Self; + fn wyyz(self) -> Self; + fn wyyw(self) -> Self; + fn wyzx(self) -> Self; + fn wyzy(self) -> Self; + fn wyzz(self) -> Self; + fn wyzw(self) -> Self; + fn wywx(self) -> Self; + fn wywy(self) -> Self; + fn wywz(self) -> Self; + fn wyww(self) -> Self; + fn wzxx(self) -> Self; + fn wzxy(self) -> Self; + fn wzxz(self) -> Self; + fn wzxw(self) -> Self; + fn wzyx(self) -> Self; + fn wzyy(self) -> Self; + fn wzyz(self) -> Self; + fn wzyw(self) -> Self; + fn wzzx(self) -> Self; + fn wzzy(self) -> Self; + fn wzzz(self) -> Self; + fn wzzw(self) -> Self; + fn wzwx(self) -> Self; + fn wzwy(self) -> Self; + fn wzwz(self) -> Self; + fn wzww(self) -> Self; + fn wwxx(self) -> Self; + fn wwxy(self) -> Self; + fn wwxz(self) -> Self; + fn wwxw(self) -> Self; + fn wwyx(self) -> Self; + fn wwyy(self) -> Self; + fn wwyz(self) -> Self; + fn wwyw(self) -> Self; + fn wwzx(self) -> Self; + fn wwzy(self) -> Self; + fn wwzz(self) -> Self; + fn wwzw(self) -> Self; + fn wwwx(self) -> Self; + fn wwwy(self) -> Self; + fn wwwz(self) -> Self; + fn wwww(self) -> Self; - fn xxx(self) -> Self::Vec3; - fn xxy(self) -> Self::Vec3; - fn xxz(self) -> Self::Vec3; - fn xxw(self) -> Self::Vec3; - fn xyx(self) -> Self::Vec3; - fn xyy(self) -> Self::Vec3; - fn xyz(self) -> Self::Vec3; - fn xyw(self) -> Self::Vec3; - fn xzx(self) -> Self::Vec3; - fn xzy(self) -> Self::Vec3; - fn xzz(self) -> Self::Vec3; - fn xzw(self) -> Self::Vec3; - fn xwx(self) -> Self::Vec3; - fn xwy(self) -> Self::Vec3; - fn xwz(self) -> Self::Vec3; - fn xww(self) -> Self::Vec3; - fn yxx(self) -> Self::Vec3; - fn yxy(self) -> Self::Vec3; - fn yxz(self) -> Self::Vec3; - fn yxw(self) -> Self::Vec3; - fn yyx(self) -> Self::Vec3; - fn yyy(self) -> Self::Vec3; - fn yyz(self) -> Self::Vec3; - fn yyw(self) -> Self::Vec3; - fn yzx(self) -> Self::Vec3; - fn yzy(self) -> Self::Vec3; - fn yzz(self) -> Self::Vec3; - fn yzw(self) -> Self::Vec3; - fn ywx(self) -> Self::Vec3; - fn ywy(self) -> Self::Vec3; - fn ywz(self) -> Self::Vec3; - fn yww(self) -> Self::Vec3; - fn zxx(self) -> Self::Vec3; - fn zxy(self) -> Self::Vec3; - fn zxz(self) -> Self::Vec3; - fn zxw(self) -> Self::Vec3; - fn zyx(self) -> Self::Vec3; - fn zyy(self) -> Self::Vec3; - fn zyz(self) -> Self::Vec3; - fn zyw(self) -> Self::Vec3; - fn zzx(self) -> Self::Vec3; - fn zzy(self) -> Self::Vec3; - fn zzz(self) -> Self::Vec3; - fn zzw(self) -> Self::Vec3; - fn zwx(self) -> Self::Vec3; - fn zwy(self) -> Self::Vec3; - fn zwz(self) -> Self::Vec3; - fn zww(self) -> Self::Vec3; - fn wxx(self) -> Self::Vec3; - fn wxy(self) -> Self::Vec3; - fn wxz(self) -> Self::Vec3; - fn wxw(self) -> Self::Vec3; - fn wyx(self) -> Self::Vec3; - fn wyy(self) -> Self::Vec3; - fn wyz(self) -> Self::Vec3; - fn wyw(self) -> Self::Vec3; - fn wzx(self) -> Self::Vec3; - fn wzy(self) -> Self::Vec3; - fn wzz(self) -> Self::Vec3; - fn wzw(self) -> Self::Vec3; - fn wwx(self) -> Self::Vec3; - fn wwy(self) -> Self::Vec3; - fn wwz(self) -> Self::Vec3; - fn www(self) -> Self::Vec3; - fn xx(self) -> Self::Vec2; - fn xy(self) -> Self::Vec2; - fn xz(self) -> Self::Vec2; - fn xw(self) -> Self::Vec2; - fn yx(self) -> Self::Vec2; - fn yy(self) -> Self::Vec2; - fn yz(self) -> Self::Vec2; - fn yw(self) -> Self::Vec2; - fn zx(self) -> Self::Vec2; - fn zy(self) -> Self::Vec2; - fn zz(self) -> Self::Vec2; - fn zw(self) -> Self::Vec2; - fn wx(self) -> Self::Vec2; - fn wy(self) -> Self::Vec2; - fn wz(self) -> Self::Vec2; - fn ww(self) -> Self::Vec2; } diff --git a/src/transform.rs b/src/transform.rs deleted file mode 100644 index d7b1b668..00000000 --- a/src/transform.rs +++ /dev/null @@ -1,432 +0,0 @@ -#![allow(deprecated)] - -use crate::{Affine3A, Mat4, Quat, Vec3, Vec3A, Vec3Swizzles}; -use core::ops::Mul; - -#[cfg(feature = "rand")] -use rand::{ - distributions::{Distribution, Standard}, - Rng, -}; - -/** - * A transform containing non-uniform scale, rotation and translation. - * - * Scale and translation are stored as `Vec3A` for better performance. - */ -#[derive(Clone, Copy, PartialEq, Debug)] -#[repr(C)] -#[deprecated( - since = "0.15.0", - note = "Moving to a separate crate, see https://github.com/bitshifter/glam-rs/issues/175" -)] -pub struct TransformSRT { - pub rotation: Quat, - pub translation: Vec3, - pub scale: Vec3, -} - -impl Default for TransformSRT { - #[inline] - fn default() -> Self { - Self::IDENTITY - } -} - -/** - * A transform containing rotation and translation. - * - * Translation is stored as a `Vec3A` for better performance. - */ -#[derive(Clone, Copy, PartialEq, Debug)] -#[repr(C)] -#[deprecated( - since = "0.15.0", - note = "Moving to a separate crate, see https://github.com/bitshifter/glam-rs/issues/175" -)] -pub struct TransformRT { - pub rotation: Quat, - pub translation: Vec3, -} - -impl Default for TransformRT { - #[inline] - fn default() -> Self { - Self::IDENTITY - } -} - -impl TransformSRT { - /// The identity transforms that does nothing. - pub const IDENTITY: Self = Self { - scale: Vec3::ONE, - rotation: Quat::IDENTITY, - translation: Vec3::ZERO, - }; - - /// All NaN:s. - pub const NAN: Self = Self { - scale: Vec3::NAN, - rotation: Quat::NAN, - translation: Vec3::NAN, - }; - - #[inline] - pub fn from_scale_rotation_translation(scale: Vec3, rotation: Quat, translation: Vec3) -> Self { - Self { - rotation, - translation, - scale, - } - } - - /// Returns `true` if, and only if, all elements are finite. - /// If any element is either `NaN`, positive or negative infinity, this will return `false`. - #[inline] - pub fn is_finite(&self) -> bool { - self.rotation.is_finite() && self.translation.is_finite() - } - - /// Returns `true` if, and only if, any element is `NaN`. - #[inline] - pub fn is_nan(&self) -> bool { - self.rotation.is_nan() || self.translation.is_nan() - } - - #[inline] - pub fn inverse(&self) -> Self { - let scale = self.scale.recip(); - let rotation = self.rotation.conjugate(); - let translation = -(rotation * (self.translation * scale)); - Self { - rotation, - translation, - scale, - } - } - - #[inline] - pub fn normalize(&self) -> Self { - let rotation = self.rotation.normalize(); - Self { - scale: self.scale, - rotation, - translation: self.translation, - } - } - - #[inline] - pub fn mul_transform(&self, other: &Self) -> Self { - mul_srt_srt(self, other) - } - - #[deprecated( - since = "0.15.0", - note = "Please use `transform_point3(other)` instead" - )] - #[inline] - pub fn transform_vec3(&self, other: Vec3) -> Vec3 { - self.transform_point3(other) - } - - #[inline] - pub fn transform_point3(&self, other: Vec3) -> Vec3 { - self.transform_point3a(other.into()).into() - } - - #[inline] - pub fn transform_vector3(&self, other: Vec3) -> Vec3 { - self.transform_vector3a(other.into()).into() - } - - #[inline] - pub fn transform_point3a(&self, other: Vec3A) -> Vec3A { - (self.rotation * (other * Vec3A::from(self.scale))) + Vec3A::from(self.translation) - } - - #[inline] - pub fn transform_vector3a(&self, other: Vec3A) -> Vec3A { - self.rotation * (other * Vec3A::from(self.scale)) - } - - /// Returns true if the absolute difference of all elements between `self` - /// and `other` is less than or equal to `max_abs_diff`. - /// - /// This can be used to compare if two `Mat4`'s contain similar elements. It - /// works best when comparing with a known value. The `max_abs_diff` that - /// should be used used depends on the values being compared against. - /// - /// For more on floating point comparisons see - /// https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ - #[inline] - pub fn abs_diff_eq(&self, other: Self, max_abs_diff: f32) -> bool { - self.scale.abs_diff_eq(other.scale, max_abs_diff) - && self.rotation.abs_diff_eq(other.rotation, max_abs_diff) - && self - .translation - .abs_diff_eq(other.translation, max_abs_diff) - } -} - -#[inline] -fn mul_srt_srt(lhs: &TransformSRT, rhs: &TransformSRT) -> TransformSRT { - // Based on https://github.com/nfrechette/rtm `rtm::qvv_mul` - let lhs_scale = Vec3A::from(lhs.scale); - let rhs_scale = Vec3A::from(rhs.scale); - let min_scale = lhs_scale.min(rhs_scale); - let scale = lhs_scale * rhs_scale; - - if min_scale.cmplt(Vec3A::ZERO).any() { - // If negative scale, we go through a matrix - let lhs_mtx = - Affine3A::from_scale_rotation_translation(lhs.scale, lhs.rotation, lhs.translation); - let rhs_mtx = - Affine3A::from_scale_rotation_translation(rhs.scale, rhs.rotation, rhs.translation); - let mut result_mtx = lhs_mtx * rhs_mtx; - - let sign = scale.signum(); - result_mtx.x_axis = result_mtx.x_axis.normalize() * sign.xxx(); - result_mtx.y_axis = result_mtx.y_axis.normalize() * sign.yyy(); - result_mtx.z_axis = result_mtx.z_axis.normalize() * sign.zzz(); - - let scale = Vec3::from(scale); - let rotation = Quat::from_affine3(&result_mtx); - let translation = Vec3::from(result_mtx.translation); - TransformSRT { - rotation, - translation, - scale, - } - } else { - let rotation = lhs.rotation * rhs.rotation; - let translation = (rhs.rotation * (lhs.translation * rhs.scale)) + rhs.translation; - TransformSRT { - rotation, - translation, - scale: scale.into(), - } - } -} - -#[inline] -fn mul_rt_rt(lhs: &TransformRT, rhs: &TransformRT) -> TransformRT { - let rotation = lhs.rotation * rhs.rotation; - let translation = (rhs.rotation * lhs.translation) + rhs.translation; - TransformRT { - rotation, - translation, - } -} - -impl TransformRT { - /// The identity transforms that does nothing. - pub const IDENTITY: Self = Self { - rotation: Quat::IDENTITY, - translation: Vec3::ZERO, - }; - - /// All NaN:s. - pub const NAN: Self = Self { - rotation: Quat::NAN, - translation: Vec3::NAN, - }; - - #[inline] - pub fn from_rotation_translation(rotation: Quat, translation: Vec3) -> Self { - Self { - rotation, - translation, - } - } - - /// Returns `true` if, and only if, all elements are finite. - /// If any element is either `NaN`, positive or negative infinity, this will return `false`. - #[inline] - pub fn is_finite(&self) -> bool { - self.rotation.is_finite() && self.translation.is_finite() - } - - /// Returns `true` if, and only if, any element is `NaN`. - #[inline] - pub fn is_nan(&self) -> bool { - self.rotation.is_nan() || self.translation.is_nan() - } - - #[inline] - pub fn inverse(&self) -> Self { - let rotation = self.rotation.conjugate(); - let translation = -(rotation * self.translation); - Self { - rotation, - translation, - } - } - - #[inline] - pub fn normalize(&self) -> Self { - let rotation = self.rotation.normalize(); - Self { - rotation, - translation: self.translation, - } - } - - #[inline] - pub fn mul_transform(&self, other: &Self) -> Self { - mul_rt_rt(self, other) - } - - #[deprecated( - since = "0.15.0", - note = "Please use `transform_point3(other)` instead" - )] - #[inline] - pub fn transform_vec3(self, other: Vec3) -> Vec3 { - self.transform_point3(other) - } - - #[inline] - pub fn transform_point3(&self, other: Vec3) -> Vec3 { - self.transform_point3a(other.into()).into() - } - - #[inline] - pub fn transform_vector3(&self, other: Vec3) -> Vec3 { - self.transform_vector3a(other.into()).into() - } - - #[inline] - pub fn transform_point3a(&self, other: Vec3A) -> Vec3A { - (self.rotation * other) + Vec3A::from(self.translation) - } - - #[inline] - pub fn transform_vector3a(&self, other: Vec3A) -> Vec3A { - self.rotation * other - } - - /// Returns true if the absolute difference of all elements between `self` - /// and `other` is less than or equal to `max_abs_diff`. - /// - /// This can be used to compare if two `Mat4`'s contain similar elements. It - /// works best when comparing with a known value. The `max_abs_diff` that - /// should be used used depends on the values being compared against. - /// - /// For more on floating point comparisons see - /// https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ - #[inline] - pub fn abs_diff_eq(&self, other: Self, max_abs_diff: f32) -> bool { - self.rotation.abs_diff_eq(other.rotation, max_abs_diff) - && self - .translation - .abs_diff_eq(other.translation, max_abs_diff) - } -} - -impl Mul for TransformRT { - type Output = TransformRT; - #[inline] - fn mul(self, other: TransformRT) -> TransformRT { - mul_rt_rt(&self, &other) - } -} - -impl Mul for TransformSRT { - type Output = Self; - #[inline] - fn mul(self, other: Self) -> Self::Output { - mul_srt_srt(&self, &other) - } -} - -impl Mul for TransformSRT { - type Output = TransformSRT; - #[inline] - fn mul(self, other: TransformRT) -> Self::Output { - mul_srt_srt(&self, &other.into()) - } -} - -impl Mul for TransformRT { - type Output = TransformSRT; - #[inline] - fn mul(self, other: TransformSRT) -> Self::Output { - mul_srt_srt(&self.into(), &other) - } -} - -impl From for TransformSRT { - #[inline] - fn from(tr: TransformRT) -> Self { - Self { - translation: tr.translation, - rotation: tr.rotation, - scale: Vec3::ONE, - } - } -} - -#[cfg(feature = "rand")] -impl Distribution for Standard { - #[inline] - fn sample(&self, rng: &mut R) -> TransformRT { - TransformRT::from_rotation_translation( - rng.gen::(), - Vec3::new( - rng.gen_range(core::f32::MIN..=core::f32::MAX), - rng.gen_range(core::f32::MIN..=core::f32::MAX), - rng.gen_range(core::f32::MIN..=core::f32::MAX), - ), - ) - } -} - -#[cfg(feature = "rand")] -impl Distribution for Standard { - #[inline] - fn sample(&self, rng: &mut R) -> TransformSRT { - let mut gen_non_zero = || loop { - let f: f32 = rng.gen_range(core::f32::MIN..=core::f32::MAX); - if f.abs() > core::f32::MIN_POSITIVE { - return f; - } - }; - TransformSRT::from_scale_rotation_translation( - Vec3::new(gen_non_zero(), gen_non_zero(), gen_non_zero()), - rng.gen::(), - Vec3::new( - rng.gen_range(core::f32::MIN..=core::f32::MAX), - rng.gen_range(core::f32::MIN..=core::f32::MAX), - rng.gen_range(core::f32::MIN..=core::f32::MAX), - ), - ) - } -} - -impl From for Mat4 { - #[inline] - fn from(srt: TransformSRT) -> Self { - Self::from_scale_rotation_translation(srt.scale, srt.rotation, srt.translation) - } -} - -impl From for Mat4 { - #[inline] - fn from(rt: TransformRT) -> Self { - Self::from_rotation_translation(rt.rotation, rt.translation) - } -} - -impl From for Affine3A { - #[inline] - fn from(srt: TransformSRT) -> Self { - Self::from_scale_rotation_translation(srt.scale, srt.rotation, srt.translation) - } -} - -impl From for Affine3A { - #[inline] - fn from(rt: TransformRT) -> Self { - Self::from_rotation_translation(rt.rotation, rt.translation) - } -} diff --git a/src/u32.rs b/src/u32.rs new file mode 100644 index 00000000..698cc2fe --- /dev/null +++ b/src/u32.rs @@ -0,0 +1,37 @@ +mod uvec2; +mod uvec3; +mod uvec4; + +pub use uvec2::{uvec2, UVec2}; +pub use uvec3::{uvec3, UVec3}; +pub use uvec4::{uvec4, UVec4}; + +mod const_test_uvec2 { + #[cfg(not(feature = "cuda"))] + const_assert_eq!( + core::mem::align_of::(), + core::mem::align_of::() + ); + #[cfg(feature = "cuda")] + const_assert_eq!(8, core::mem::align_of::()); + const_assert_eq!(8, core::mem::size_of::()); +} + +mod const_test_uvec3 { + const_assert_eq!( + core::mem::align_of::(), + core::mem::align_of::() + ); + const_assert_eq!(12, core::mem::size_of::()); +} + +mod const_test_uvec4 { + #[cfg(not(feature = "cuda"))] + const_assert_eq!( + core::mem::align_of::(), + core::mem::align_of::() + ); + #[cfg(feature = "cuda")] + const_assert_eq!(16, core::mem::align_of::()); + const_assert_eq!(16, core::mem::size_of::()); +} diff --git a/src/u32/uvec2.rs b/src/u32/uvec2.rs new file mode 100644 index 00000000..b8a4e32a --- /dev/null +++ b/src/u32/uvec2.rs @@ -0,0 +1,864 @@ +// Generated from vec.rs template. Edit the template, not the generated file. + +use crate::{BVec2, UVec3}; + +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::iter::{Product, Sum}; +use core::{f32, ops::*}; + +/// Creates a 2-dimensional vector. +#[inline(always)] +pub const fn uvec2(x: u32, y: u32) -> UVec2 { + UVec2::new(x, y) +} + +/// A 2-dimensional vector. +#[derive(Clone, Copy)] +#[cfg_attr(feature = "cuda", repr(C, align(8)))] +pub struct UVec2 { + pub x: u32, + pub y: u32, +} + +impl UVec2 { + /// All zeroes. + pub const ZERO: Self = Self::splat(0); + + /// All ones. + pub const ONE: Self = Self::splat(1); + + /// `[1, 0]`: a unit-length vector pointing along the positive X axis. + pub const X: Self = Self::from_array([1, 0]); + + /// `[0, 1]`: a unit-length vector pointing along the positive Y axis. + pub const Y: Self = Self::from_array([0, 1]); + + /// The unit axes. + pub const AXES: [Self; 2] = [Self::X, Self::Y]; + + /// Creates a new vector. + #[inline(always)] + pub const fn new(x: u32, y: u32) -> Self { + Self { x, y } + } + + /// Creates a vector with all elements set to `v`. + #[inline] + pub const fn splat(v: u32) -> Self { + Self { x: v, y: v } + } + + /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use + /// for each element of `self`. + /// + /// A true element in the mask uses the corresponding element from `if_true`, and false + /// uses the element from `if_false`. + #[inline] + pub fn select(mask: BVec2, if_true: Self, if_false: Self) -> Self { + Self { + x: if mask.x { if_true.x } else { if_false.x }, + y: if mask.y { if_true.y } else { if_false.y }, + } + } + + /// Creates a new vector from an array. + #[inline] + pub const fn from_array(a: [u32; 2]) -> Self { + Self::new(a[0], a[1]) + } + + /// `[x, y]` + #[inline] + pub const fn to_array(&self) -> [u32; 2] { + [self.x, self.y] + } + + /// Creates a vector from the first N values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than N elements long. + #[inline] + pub const fn from_slice(slice: &[u32]) -> Self { + Self::new(slice[0], slice[1]) + } + + /// Writes the elements of `self` to the first 2 elements in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than N elements long. + #[inline] + pub fn write_to_slice(self, slice: &mut [u32]) { + slice[0] = self.x; + slice[1] = self.y; + } + + /// Creates a 3D vector from `self` and the given `z` value. + #[inline] + pub const fn extend(self, z: u32) -> UVec3 { + UVec3::new(self.x, self.y, z) + } + + /// Computes the dot product of `self` and `rhs`. + #[inline] + pub fn dot(self, rhs: Self) -> u32 { + (self.x * rhs.x) + (self.y * rhs.y) + } + + /// Returns a vector containing the minimum values for each element of `self` and `rhs`. + /// + /// In other words this computes `[self.x.min(rhs.x), self.y.min(rhs.y), ..]`. + #[inline] + pub fn min(self, rhs: Self) -> Self { + Self { + x: self.x.min(rhs.x), + y: self.y.min(rhs.y), + } + } + + /// Returns a vector containing the maximum values for each element of `self` and `rhs`. + /// + /// In other words this computes `[self.x.max(rhs.x), self.y.max(rhs.y), ..]`. + #[inline] + pub fn max(self, rhs: Self) -> Self { + Self { + x: self.x.max(rhs.x), + y: self.y.max(rhs.y), + } + } + + /// Component-wise clamping of values, similar to [`f32::clamp`]. + /// + /// Each element in `min` must be less-or-equal to the corresponding element in `max`. + /// + /// # Panics + /// + /// Will panic if `min` is greater than `max` when `glam_assert` is enabled. + #[inline] + pub fn clamp(self, min: Self, max: Self) -> Self { + glam_assert!(min.cmple(max).all(), "clamp: expected min <= max"); + self.max(min).min(max) + } + + /// Returns the horizontal minimum of `self`. + /// + /// In other words this computes `min(x, y, ..)`. + #[inline] + pub fn min_element(self) -> u32 { + self.x.min(self.y) + } + + /// Returns the horizontal maximum of `self`. + /// + /// In other words this computes `max(x, y, ..)`. + #[inline] + pub fn max_element(self) -> u32 { + self.x.max(self.y) + } + + /// Returns a vector mask containing the result of a `==` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words, this computes `[self.x == rhs.x, self.y == rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpeq(self, rhs: Self) -> BVec2 { + BVec2::new(self.x.eq(&rhs.x), self.y.eq(&rhs.y)) + } + + /// Returns a vector mask containing the result of a `!=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x != rhs.x, self.y != rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpne(self, rhs: Self) -> BVec2 { + BVec2::new(self.x.ne(&rhs.x), self.y.ne(&rhs.y)) + } + + /// Returns a vector mask containing the result of a `>=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x >= rhs.x, self.y >= rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpge(self, rhs: Self) -> BVec2 { + BVec2::new(self.x.ge(&rhs.x), self.y.ge(&rhs.y)) + } + + /// Returns a vector mask containing the result of a `>` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x > rhs.x, self.y > rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpgt(self, rhs: Self) -> BVec2 { + BVec2::new(self.x.gt(&rhs.x), self.y.gt(&rhs.y)) + } + + /// Returns a vector mask containing the result of a `<=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x <= rhs.x, self.y <= rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmple(self, rhs: Self) -> BVec2 { + BVec2::new(self.x.le(&rhs.x), self.y.le(&rhs.y)) + } + + /// Returns a vector mask containing the result of a `<` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x < rhs.x, self.y < rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmplt(self, rhs: Self) -> BVec2 { + BVec2::new(self.x.lt(&rhs.x), self.y.lt(&rhs.y)) + } + + /// Casts all elements of `self` to `f32`. + #[inline] + pub fn as_vec2(&self) -> crate::Vec2 { + crate::Vec2::new(self.x as f32, self.y as f32) + } + + /// Casts all elements of `self` to `f64`. + #[inline] + pub fn as_dvec2(&self) -> crate::DVec2 { + crate::DVec2::new(self.x as f64, self.y as f64) + } + + /// Casts all elements of `self` to `i32`. + #[inline] + pub fn as_ivec2(&self) -> crate::IVec2 { + crate::IVec2::new(self.x as i32, self.y as i32) + } +} + +impl Default for UVec2 { + #[inline(always)] + fn default() -> Self { + Self::ZERO + } +} + +impl PartialEq for UVec2 { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.cmpeq(*rhs).all() + } +} + +impl Div for UVec2 { + type Output = Self; + #[inline] + fn div(self, rhs: Self) -> Self { + Self { + x: self.x.div(rhs.x), + y: self.y.div(rhs.y), + } + } +} + +impl DivAssign for UVec2 { + #[inline] + fn div_assign(&mut self, rhs: Self) { + self.x.div_assign(rhs.x); + self.y.div_assign(rhs.y); + } +} + +impl Div for UVec2 { + type Output = Self; + #[inline] + fn div(self, rhs: u32) -> Self { + Self { + x: self.x.div(rhs), + y: self.y.div(rhs), + } + } +} + +impl DivAssign for UVec2 { + #[inline] + fn div_assign(&mut self, rhs: u32) { + self.x.div_assign(rhs); + self.y.div_assign(rhs); + } +} + +impl Div for u32 { + type Output = UVec2; + #[inline] + fn div(self, rhs: UVec2) -> UVec2 { + UVec2 { + x: self.div(rhs.x), + y: self.div(rhs.y), + } + } +} + +impl Mul for UVec2 { + type Output = Self; + #[inline] + fn mul(self, rhs: Self) -> Self { + Self { + x: self.x.mul(rhs.x), + y: self.y.mul(rhs.y), + } + } +} + +impl MulAssign for UVec2 { + #[inline] + fn mul_assign(&mut self, rhs: Self) { + self.x.mul_assign(rhs.x); + self.y.mul_assign(rhs.y); + } +} + +impl Mul for UVec2 { + type Output = Self; + #[inline] + fn mul(self, rhs: u32) -> Self { + Self { + x: self.x.mul(rhs), + y: self.y.mul(rhs), + } + } +} + +impl MulAssign for UVec2 { + #[inline] + fn mul_assign(&mut self, rhs: u32) { + self.x.mul_assign(rhs); + self.y.mul_assign(rhs); + } +} + +impl Mul for u32 { + type Output = UVec2; + #[inline] + fn mul(self, rhs: UVec2) -> UVec2 { + UVec2 { + x: self.mul(rhs.x), + y: self.mul(rhs.y), + } + } +} + +impl Add for UVec2 { + type Output = Self; + #[inline] + fn add(self, rhs: Self) -> Self { + Self { + x: self.x.add(rhs.x), + y: self.y.add(rhs.y), + } + } +} + +impl AddAssign for UVec2 { + #[inline] + fn add_assign(&mut self, rhs: Self) { + self.x.add_assign(rhs.x); + self.y.add_assign(rhs.y); + } +} + +impl Add for UVec2 { + type Output = Self; + #[inline] + fn add(self, rhs: u32) -> Self { + Self { + x: self.x.add(rhs), + y: self.y.add(rhs), + } + } +} + +impl AddAssign for UVec2 { + #[inline] + fn add_assign(&mut self, rhs: u32) { + self.x.add_assign(rhs); + self.y.add_assign(rhs); + } +} + +impl Add for u32 { + type Output = UVec2; + #[inline] + fn add(self, rhs: UVec2) -> UVec2 { + UVec2 { + x: self.add(rhs.x), + y: self.add(rhs.y), + } + } +} + +impl Sub for UVec2 { + type Output = Self; + #[inline] + fn sub(self, rhs: Self) -> Self { + Self { + x: self.x.sub(rhs.x), + y: self.y.sub(rhs.y), + } + } +} + +impl SubAssign for UVec2 { + #[inline] + fn sub_assign(&mut self, rhs: UVec2) { + self.x.sub_assign(rhs.x); + self.y.sub_assign(rhs.y); + } +} + +impl Sub for UVec2 { + type Output = Self; + #[inline] + fn sub(self, rhs: u32) -> Self { + Self { + x: self.x.sub(rhs), + y: self.y.sub(rhs), + } + } +} + +impl SubAssign for UVec2 { + #[inline] + fn sub_assign(&mut self, rhs: u32) { + self.x.sub_assign(rhs); + self.y.sub_assign(rhs); + } +} + +impl Sub for u32 { + type Output = UVec2; + #[inline] + fn sub(self, rhs: UVec2) -> UVec2 { + UVec2 { + x: self.sub(rhs.x), + y: self.sub(rhs.y), + } + } +} + +impl Rem for UVec2 { + type Output = Self; + #[inline] + fn rem(self, rhs: Self) -> Self { + Self { + x: self.x.rem(rhs.x), + y: self.y.rem(rhs.y), + } + } +} + +impl RemAssign for UVec2 { + #[inline] + fn rem_assign(&mut self, rhs: Self) { + self.x.rem_assign(rhs.x); + self.y.rem_assign(rhs.y); + } +} + +impl Rem for UVec2 { + type Output = Self; + #[inline] + fn rem(self, rhs: u32) -> Self { + Self { + x: self.x.rem(rhs), + y: self.y.rem(rhs), + } + } +} + +impl RemAssign for UVec2 { + #[inline] + fn rem_assign(&mut self, rhs: u32) { + self.x.rem_assign(rhs); + self.y.rem_assign(rhs); + } +} + +impl Rem for u32 { + type Output = UVec2; + #[inline] + fn rem(self, rhs: UVec2) -> UVec2 { + UVec2 { + x: self.rem(rhs.x), + y: self.rem(rhs.y), + } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsRef<[u32; 2]> for UVec2 { + #[inline] + fn as_ref(&self) -> &[u32; 2] { + unsafe { &*(self as *const UVec2 as *const [u32; 2]) } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsMut<[u32; 2]> for UVec2 { + #[inline] + fn as_mut(&mut self) -> &mut [u32; 2] { + unsafe { &mut *(self as *mut UVec2 as *mut [u32; 2]) } + } +} + +impl<'a> Sum<&'a Self> for UVec2 { + #[inline] + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, |a, &b| Self::add(a, b)) + } +} + +impl<'a> Product<&'a Self> for UVec2 { + #[inline] + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ONE, |a, &b| Self::mul(a, b)) + } +} + +impl Eq for UVec2 {} + +#[cfg(not(target_arch = "spirv"))] +impl core::hash::Hash for UVec2 { + fn hash(&self, state: &mut H) { + let inner: &[u32; 2] = self.as_ref(); + inner.hash(state); + } +} + +impl Not for UVec2 { + type Output = Self; + #[inline] + fn not(self) -> Self::Output { + Self { + x: self.x.not(), + y: self.y.not(), + } + } +} + +impl BitAnd for UVec2 { + type Output = Self; + #[inline] + fn bitand(self, rhs: Self) -> Self::Output { + Self { + x: self.x.bitand(rhs.x), + y: self.y.bitand(rhs.y), + } + } +} + +impl BitOr for UVec2 { + type Output = Self; + #[inline] + fn bitor(self, rhs: Self) -> Self::Output { + Self { + x: self.x.bitor(rhs.x), + y: self.y.bitor(rhs.y), + } + } +} + +impl BitXor for UVec2 { + type Output = Self; + #[inline] + fn bitxor(self, rhs: Self) -> Self::Output { + Self { + x: self.x.bitxor(rhs.x), + y: self.y.bitxor(rhs.y), + } + } +} + +impl BitAnd for UVec2 { + type Output = Self; + #[inline] + fn bitand(self, rhs: u32) -> Self::Output { + Self { + x: self.x.bitand(rhs), + y: self.y.bitand(rhs), + } + } +} + +impl BitOr for UVec2 { + type Output = Self; + #[inline] + fn bitor(self, rhs: u32) -> Self::Output { + Self { + x: self.x.bitor(rhs), + y: self.y.bitor(rhs), + } + } +} + +impl BitXor for UVec2 { + type Output = Self; + #[inline] + fn bitxor(self, rhs: u32) -> Self::Output { + Self { + x: self.x.bitxor(rhs), + y: self.y.bitxor(rhs), + } + } +} + +impl Shl for UVec2 { + type Output = Self; + #[inline] + fn shl(self, rhs: i8) -> Self::Output { + Self { + x: self.x.shl(rhs), + y: self.y.shl(rhs), + } + } +} + +impl Shr for UVec2 { + type Output = Self; + #[inline] + fn shr(self, rhs: i8) -> Self::Output { + Self { + x: self.x.shr(rhs), + y: self.y.shr(rhs), + } + } +} + +impl Shl for UVec2 { + type Output = Self; + #[inline] + fn shl(self, rhs: i16) -> Self::Output { + Self { + x: self.x.shl(rhs), + y: self.y.shl(rhs), + } + } +} + +impl Shr for UVec2 { + type Output = Self; + #[inline] + fn shr(self, rhs: i16) -> Self::Output { + Self { + x: self.x.shr(rhs), + y: self.y.shr(rhs), + } + } +} + +impl Shl for UVec2 { + type Output = Self; + #[inline] + fn shl(self, rhs: i32) -> Self::Output { + Self { + x: self.x.shl(rhs), + y: self.y.shl(rhs), + } + } +} + +impl Shr for UVec2 { + type Output = Self; + #[inline] + fn shr(self, rhs: i32) -> Self::Output { + Self { + x: self.x.shr(rhs), + y: self.y.shr(rhs), + } + } +} + +impl Shl for UVec2 { + type Output = Self; + #[inline] + fn shl(self, rhs: u8) -> Self::Output { + Self { + x: self.x.shl(rhs), + y: self.y.shl(rhs), + } + } +} + +impl Shr for UVec2 { + type Output = Self; + #[inline] + fn shr(self, rhs: u8) -> Self::Output { + Self { + x: self.x.shr(rhs), + y: self.y.shr(rhs), + } + } +} + +impl Shl for UVec2 { + type Output = Self; + #[inline] + fn shl(self, rhs: u16) -> Self::Output { + Self { + x: self.x.shl(rhs), + y: self.y.shl(rhs), + } + } +} + +impl Shr for UVec2 { + type Output = Self; + #[inline] + fn shr(self, rhs: u16) -> Self::Output { + Self { + x: self.x.shr(rhs), + y: self.y.shr(rhs), + } + } +} + +impl Shl for UVec2 { + type Output = Self; + #[inline] + fn shl(self, rhs: u32) -> Self::Output { + Self { + x: self.x.shl(rhs), + y: self.y.shl(rhs), + } + } +} + +impl Shr for UVec2 { + type Output = Self; + #[inline] + fn shr(self, rhs: u32) -> Self::Output { + Self { + x: self.x.shr(rhs), + y: self.y.shr(rhs), + } + } +} + +impl Shl for UVec2 { + type Output = Self; + #[inline] + fn shl(self, rhs: crate::IVec2) -> Self::Output { + Self { + x: self.x.shl(rhs.x), + y: self.y.shl(rhs.y), + } + } +} + +impl Shr for UVec2 { + type Output = Self; + #[inline] + fn shr(self, rhs: crate::IVec2) -> Self::Output { + Self { + x: self.x.shr(rhs.x), + y: self.y.shr(rhs.y), + } + } +} + +impl Shl for UVec2 { + type Output = Self; + #[inline] + fn shl(self, rhs: crate::UVec2) -> Self::Output { + Self { + x: self.x.shl(rhs.x), + y: self.y.shl(rhs.y), + } + } +} + +impl Shr for UVec2 { + type Output = Self; + #[inline] + fn shr(self, rhs: crate::UVec2) -> Self::Output { + Self { + x: self.x.shr(rhs.x), + y: self.y.shr(rhs.y), + } + } +} + +impl Index for UVec2 { + type Output = u32; + #[inline] + fn index(&self, index: usize) -> &Self::Output { + match index { + 0 => &self.x, + 1 => &self.y, + _ => panic!("index out of bounds"), + } + } +} + +impl IndexMut for UVec2 { + #[inline] + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + match index { + 0 => &mut self.x, + 1 => &mut self.y, + _ => panic!("index out of bounds"), + } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Display for UVec2 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "[{}, {}]", self.x, self.y) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Debug for UVec2 { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_tuple(stringify!(UVec2)) + .field(&self.x) + .field(&self.y) + .finish() + } +} + +impl From<[u32; 2]> for UVec2 { + #[inline] + fn from(a: [u32; 2]) -> Self { + Self::new(a[0], a[1]) + } +} + +impl From for [u32; 2] { + #[inline] + fn from(v: UVec2) -> Self { + [v.x, v.y] + } +} + +impl From<(u32, u32)> for UVec2 { + #[inline] + fn from(t: (u32, u32)) -> Self { + Self::new(t.0, t.1) + } +} + +impl From for (u32, u32) { + #[inline] + fn from(v: UVec2) -> Self { + (v.x, v.y) + } +} diff --git a/src/u32/uvec3.rs b/src/u32/uvec3.rs new file mode 100644 index 00000000..c8a280f6 --- /dev/null +++ b/src/u32/uvec3.rs @@ -0,0 +1,965 @@ +// Generated from vec.rs template. Edit the template, not the generated file. + +use crate::{BVec3, UVec2, UVec4}; + +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::iter::{Product, Sum}; +use core::{f32, ops::*}; + +/// Creates a 3-dimensional vector. +#[inline(always)] +pub const fn uvec3(x: u32, y: u32, z: u32) -> UVec3 { + UVec3::new(x, y, z) +} + +/// A 3-dimensional vector. +#[derive(Clone, Copy)] +pub struct UVec3 { + pub x: u32, + pub y: u32, + pub z: u32, +} + +impl UVec3 { + /// All zeroes. + pub const ZERO: Self = Self::splat(0); + + /// All ones. + pub const ONE: Self = Self::splat(1); + + /// `[1, 0, 0]`: a unit-length vector pointing along the positive X axis. + pub const X: Self = Self::from_array([1, 0, 0]); + + /// `[0, 1, 0]`: a unit-length vector pointing along the positive Y axis. + pub const Y: Self = Self::from_array([0, 1, 0]); + + /// `[0, 0, 1]`: a unit-length vector pointing along the positive Z axis. + pub const Z: Self = Self::from_array([0, 0, 1]); + + /// The unit axes. + pub const AXES: [Self; 3] = [Self::X, Self::Y, Self::Z]; + + /// Creates a new vector. + #[inline(always)] + pub const fn new(x: u32, y: u32, z: u32) -> Self { + Self { x, y, z } + } + + /// Creates a vector with all elements set to `v`. + #[inline] + pub const fn splat(v: u32) -> Self { + Self { x: v, y: v, z: v } + } + + /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use + /// for each element of `self`. + /// + /// A true element in the mask uses the corresponding element from `if_true`, and false + /// uses the element from `if_false`. + #[inline] + pub fn select(mask: BVec3, if_true: Self, if_false: Self) -> Self { + Self { + x: if mask.x { if_true.x } else { if_false.x }, + y: if mask.y { if_true.y } else { if_false.y }, + z: if mask.z { if_true.z } else { if_false.z }, + } + } + + /// Creates a new vector from an array. + #[inline] + pub const fn from_array(a: [u32; 3]) -> Self { + Self::new(a[0], a[1], a[2]) + } + + /// `[x, y, z]` + #[inline] + pub const fn to_array(&self) -> [u32; 3] { + [self.x, self.y, self.z] + } + + /// Creates a vector from the first N values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than N elements long. + #[inline] + pub const fn from_slice(slice: &[u32]) -> Self { + Self::new(slice[0], slice[1], slice[2]) + } + + /// Writes the elements of `self` to the first 3 elements in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than N elements long. + #[inline] + pub fn write_to_slice(self, slice: &mut [u32]) { + slice[0] = self.x; + slice[1] = self.y; + slice[2] = self.z; + } + + /// Internal method for creating a 3D vector from a 4D vector, discarding `w`. + #[allow(dead_code)] + #[inline] + pub(crate) fn from_vec4(v: UVec4) -> Self { + Self { + x: v.x, + y: v.y, + z: v.z, + } + } + + /// Creates a 4D vector from `self` and the given `w` value. + #[inline] + pub fn extend(self, w: u32) -> UVec4 { + UVec4::new(self.x, self.y, self.z, w) + } + + /// Creates a 2D vector from the `x` and `y` elements of `self`, discarding `z`. + /// + /// Truncation may also be performed by using `self.xy()` or `UVec2::from()`. + #[inline] + pub fn truncate(self) -> UVec2 { + use crate::swizzles::Vec3Swizzles; + self.xy() + } + + /// Computes the dot product of `self` and `rhs`. + #[inline] + pub fn dot(self, rhs: Self) -> u32 { + (self.x * rhs.x) + (self.y * rhs.y) + (self.z * rhs.z) + } + + /// Computes the cross product of `self` and `rhs`. + #[inline] + pub fn cross(self, rhs: Self) -> Self { + Self { + x: self.y * rhs.z - rhs.y * self.z, + y: self.z * rhs.x - rhs.z * self.x, + z: self.x * rhs.y - rhs.x * self.y, + } + } + + /// Returns a vector containing the minimum values for each element of `self` and `rhs`. + /// + /// In other words this computes `[self.x.min(rhs.x), self.y.min(rhs.y), ..]`. + #[inline] + pub fn min(self, rhs: Self) -> Self { + Self { + x: self.x.min(rhs.x), + y: self.y.min(rhs.y), + z: self.z.min(rhs.z), + } + } + + /// Returns a vector containing the maximum values for each element of `self` and `rhs`. + /// + /// In other words this computes `[self.x.max(rhs.x), self.y.max(rhs.y), ..]`. + #[inline] + pub fn max(self, rhs: Self) -> Self { + Self { + x: self.x.max(rhs.x), + y: self.y.max(rhs.y), + z: self.z.max(rhs.z), + } + } + + /// Component-wise clamping of values, similar to [`f32::clamp`]. + /// + /// Each element in `min` must be less-or-equal to the corresponding element in `max`. + /// + /// # Panics + /// + /// Will panic if `min` is greater than `max` when `glam_assert` is enabled. + #[inline] + pub fn clamp(self, min: Self, max: Self) -> Self { + glam_assert!(min.cmple(max).all(), "clamp: expected min <= max"); + self.max(min).min(max) + } + + /// Returns the horizontal minimum of `self`. + /// + /// In other words this computes `min(x, y, ..)`. + #[inline] + pub fn min_element(self) -> u32 { + self.x.min(self.y.min(self.z)) + } + + /// Returns the horizontal maximum of `self`. + /// + /// In other words this computes `max(x, y, ..)`. + #[inline] + pub fn max_element(self) -> u32 { + self.x.max(self.y.max(self.z)) + } + + /// Returns a vector mask containing the result of a `==` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words, this computes `[self.x == rhs.x, self.y == rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpeq(self, rhs: Self) -> BVec3 { + BVec3::new(self.x.eq(&rhs.x), self.y.eq(&rhs.y), self.z.eq(&rhs.z)) + } + + /// Returns a vector mask containing the result of a `!=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x != rhs.x, self.y != rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpne(self, rhs: Self) -> BVec3 { + BVec3::new(self.x.ne(&rhs.x), self.y.ne(&rhs.y), self.z.ne(&rhs.z)) + } + + /// Returns a vector mask containing the result of a `>=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x >= rhs.x, self.y >= rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpge(self, rhs: Self) -> BVec3 { + BVec3::new(self.x.ge(&rhs.x), self.y.ge(&rhs.y), self.z.ge(&rhs.z)) + } + + /// Returns a vector mask containing the result of a `>` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x > rhs.x, self.y > rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpgt(self, rhs: Self) -> BVec3 { + BVec3::new(self.x.gt(&rhs.x), self.y.gt(&rhs.y), self.z.gt(&rhs.z)) + } + + /// Returns a vector mask containing the result of a `<=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x <= rhs.x, self.y <= rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmple(self, rhs: Self) -> BVec3 { + BVec3::new(self.x.le(&rhs.x), self.y.le(&rhs.y), self.z.le(&rhs.z)) + } + + /// Returns a vector mask containing the result of a `<` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x < rhs.x, self.y < rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmplt(self, rhs: Self) -> BVec3 { + BVec3::new(self.x.lt(&rhs.x), self.y.lt(&rhs.y), self.z.lt(&rhs.z)) + } + + /// Casts all elements of `self` to `f32`. + #[inline] + pub fn as_vec3(&self) -> crate::Vec3 { + crate::Vec3::new(self.x as f32, self.y as f32, self.z as f32) + } + + /// Casts all elements of `self` to `f32`. + #[inline] + pub fn as_vec3a(&self) -> crate::Vec3A { + crate::Vec3A::new(self.x as f32, self.y as f32, self.z as f32) + } + + /// Casts all elements of `self` to `f64`. + #[inline] + pub fn as_dvec3(&self) -> crate::DVec3 { + crate::DVec3::new(self.x as f64, self.y as f64, self.z as f64) + } + + /// Casts all elements of `self` to `i32`. + #[inline] + pub fn as_ivec3(&self) -> crate::IVec3 { + crate::IVec3::new(self.x as i32, self.y as i32, self.z as i32) + } +} + +impl Default for UVec3 { + #[inline(always)] + fn default() -> Self { + Self::ZERO + } +} + +impl PartialEq for UVec3 { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.cmpeq(*rhs).all() + } +} + +impl Div for UVec3 { + type Output = Self; + #[inline] + fn div(self, rhs: Self) -> Self { + Self { + x: self.x.div(rhs.x), + y: self.y.div(rhs.y), + z: self.z.div(rhs.z), + } + } +} + +impl DivAssign for UVec3 { + #[inline] + fn div_assign(&mut self, rhs: Self) { + self.x.div_assign(rhs.x); + self.y.div_assign(rhs.y); + self.z.div_assign(rhs.z); + } +} + +impl Div for UVec3 { + type Output = Self; + #[inline] + fn div(self, rhs: u32) -> Self { + Self { + x: self.x.div(rhs), + y: self.y.div(rhs), + z: self.z.div(rhs), + } + } +} + +impl DivAssign for UVec3 { + #[inline] + fn div_assign(&mut self, rhs: u32) { + self.x.div_assign(rhs); + self.y.div_assign(rhs); + self.z.div_assign(rhs); + } +} + +impl Div for u32 { + type Output = UVec3; + #[inline] + fn div(self, rhs: UVec3) -> UVec3 { + UVec3 { + x: self.div(rhs.x), + y: self.div(rhs.y), + z: self.div(rhs.z), + } + } +} + +impl Mul for UVec3 { + type Output = Self; + #[inline] + fn mul(self, rhs: Self) -> Self { + Self { + x: self.x.mul(rhs.x), + y: self.y.mul(rhs.y), + z: self.z.mul(rhs.z), + } + } +} + +impl MulAssign for UVec3 { + #[inline] + fn mul_assign(&mut self, rhs: Self) { + self.x.mul_assign(rhs.x); + self.y.mul_assign(rhs.y); + self.z.mul_assign(rhs.z); + } +} + +impl Mul for UVec3 { + type Output = Self; + #[inline] + fn mul(self, rhs: u32) -> Self { + Self { + x: self.x.mul(rhs), + y: self.y.mul(rhs), + z: self.z.mul(rhs), + } + } +} + +impl MulAssign for UVec3 { + #[inline] + fn mul_assign(&mut self, rhs: u32) { + self.x.mul_assign(rhs); + self.y.mul_assign(rhs); + self.z.mul_assign(rhs); + } +} + +impl Mul for u32 { + type Output = UVec3; + #[inline] + fn mul(self, rhs: UVec3) -> UVec3 { + UVec3 { + x: self.mul(rhs.x), + y: self.mul(rhs.y), + z: self.mul(rhs.z), + } + } +} + +impl Add for UVec3 { + type Output = Self; + #[inline] + fn add(self, rhs: Self) -> Self { + Self { + x: self.x.add(rhs.x), + y: self.y.add(rhs.y), + z: self.z.add(rhs.z), + } + } +} + +impl AddAssign for UVec3 { + #[inline] + fn add_assign(&mut self, rhs: Self) { + self.x.add_assign(rhs.x); + self.y.add_assign(rhs.y); + self.z.add_assign(rhs.z); + } +} + +impl Add for UVec3 { + type Output = Self; + #[inline] + fn add(self, rhs: u32) -> Self { + Self { + x: self.x.add(rhs), + y: self.y.add(rhs), + z: self.z.add(rhs), + } + } +} + +impl AddAssign for UVec3 { + #[inline] + fn add_assign(&mut self, rhs: u32) { + self.x.add_assign(rhs); + self.y.add_assign(rhs); + self.z.add_assign(rhs); + } +} + +impl Add for u32 { + type Output = UVec3; + #[inline] + fn add(self, rhs: UVec3) -> UVec3 { + UVec3 { + x: self.add(rhs.x), + y: self.add(rhs.y), + z: self.add(rhs.z), + } + } +} + +impl Sub for UVec3 { + type Output = Self; + #[inline] + fn sub(self, rhs: Self) -> Self { + Self { + x: self.x.sub(rhs.x), + y: self.y.sub(rhs.y), + z: self.z.sub(rhs.z), + } + } +} + +impl SubAssign for UVec3 { + #[inline] + fn sub_assign(&mut self, rhs: UVec3) { + self.x.sub_assign(rhs.x); + self.y.sub_assign(rhs.y); + self.z.sub_assign(rhs.z); + } +} + +impl Sub for UVec3 { + type Output = Self; + #[inline] + fn sub(self, rhs: u32) -> Self { + Self { + x: self.x.sub(rhs), + y: self.y.sub(rhs), + z: self.z.sub(rhs), + } + } +} + +impl SubAssign for UVec3 { + #[inline] + fn sub_assign(&mut self, rhs: u32) { + self.x.sub_assign(rhs); + self.y.sub_assign(rhs); + self.z.sub_assign(rhs); + } +} + +impl Sub for u32 { + type Output = UVec3; + #[inline] + fn sub(self, rhs: UVec3) -> UVec3 { + UVec3 { + x: self.sub(rhs.x), + y: self.sub(rhs.y), + z: self.sub(rhs.z), + } + } +} + +impl Rem for UVec3 { + type Output = Self; + #[inline] + fn rem(self, rhs: Self) -> Self { + Self { + x: self.x.rem(rhs.x), + y: self.y.rem(rhs.y), + z: self.z.rem(rhs.z), + } + } +} + +impl RemAssign for UVec3 { + #[inline] + fn rem_assign(&mut self, rhs: Self) { + self.x.rem_assign(rhs.x); + self.y.rem_assign(rhs.y); + self.z.rem_assign(rhs.z); + } +} + +impl Rem for UVec3 { + type Output = Self; + #[inline] + fn rem(self, rhs: u32) -> Self { + Self { + x: self.x.rem(rhs), + y: self.y.rem(rhs), + z: self.z.rem(rhs), + } + } +} + +impl RemAssign for UVec3 { + #[inline] + fn rem_assign(&mut self, rhs: u32) { + self.x.rem_assign(rhs); + self.y.rem_assign(rhs); + self.z.rem_assign(rhs); + } +} + +impl Rem for u32 { + type Output = UVec3; + #[inline] + fn rem(self, rhs: UVec3) -> UVec3 { + UVec3 { + x: self.rem(rhs.x), + y: self.rem(rhs.y), + z: self.rem(rhs.z), + } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsRef<[u32; 3]> for UVec3 { + #[inline] + fn as_ref(&self) -> &[u32; 3] { + unsafe { &*(self as *const UVec3 as *const [u32; 3]) } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsMut<[u32; 3]> for UVec3 { + #[inline] + fn as_mut(&mut self) -> &mut [u32; 3] { + unsafe { &mut *(self as *mut UVec3 as *mut [u32; 3]) } + } +} + +impl<'a> Sum<&'a Self> for UVec3 { + #[inline] + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, |a, &b| Self::add(a, b)) + } +} + +impl<'a> Product<&'a Self> for UVec3 { + #[inline] + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ONE, |a, &b| Self::mul(a, b)) + } +} + +impl Eq for UVec3 {} + +#[cfg(not(target_arch = "spirv"))] +impl core::hash::Hash for UVec3 { + fn hash(&self, state: &mut H) { + let inner: &[u32; 3] = self.as_ref(); + inner.hash(state); + } +} + +impl Not for UVec3 { + type Output = Self; + #[inline] + fn not(self) -> Self::Output { + Self { + x: self.x.not(), + y: self.y.not(), + z: self.z.not(), + } + } +} + +impl BitAnd for UVec3 { + type Output = Self; + #[inline] + fn bitand(self, rhs: Self) -> Self::Output { + Self { + x: self.x.bitand(rhs.x), + y: self.y.bitand(rhs.y), + z: self.z.bitand(rhs.z), + } + } +} + +impl BitOr for UVec3 { + type Output = Self; + #[inline] + fn bitor(self, rhs: Self) -> Self::Output { + Self { + x: self.x.bitor(rhs.x), + y: self.y.bitor(rhs.y), + z: self.z.bitor(rhs.z), + } + } +} + +impl BitXor for UVec3 { + type Output = Self; + #[inline] + fn bitxor(self, rhs: Self) -> Self::Output { + Self { + x: self.x.bitxor(rhs.x), + y: self.y.bitxor(rhs.y), + z: self.z.bitxor(rhs.z), + } + } +} + +impl BitAnd for UVec3 { + type Output = Self; + #[inline] + fn bitand(self, rhs: u32) -> Self::Output { + Self { + x: self.x.bitand(rhs), + y: self.y.bitand(rhs), + z: self.z.bitand(rhs), + } + } +} + +impl BitOr for UVec3 { + type Output = Self; + #[inline] + fn bitor(self, rhs: u32) -> Self::Output { + Self { + x: self.x.bitor(rhs), + y: self.y.bitor(rhs), + z: self.z.bitor(rhs), + } + } +} + +impl BitXor for UVec3 { + type Output = Self; + #[inline] + fn bitxor(self, rhs: u32) -> Self::Output { + Self { + x: self.x.bitxor(rhs), + y: self.y.bitxor(rhs), + z: self.z.bitxor(rhs), + } + } +} + +impl Shl for UVec3 { + type Output = Self; + #[inline] + fn shl(self, rhs: i8) -> Self::Output { + Self { + x: self.x.shl(rhs), + y: self.y.shl(rhs), + z: self.z.shl(rhs), + } + } +} + +impl Shr for UVec3 { + type Output = Self; + #[inline] + fn shr(self, rhs: i8) -> Self::Output { + Self { + x: self.x.shr(rhs), + y: self.y.shr(rhs), + z: self.z.shr(rhs), + } + } +} + +impl Shl for UVec3 { + type Output = Self; + #[inline] + fn shl(self, rhs: i16) -> Self::Output { + Self { + x: self.x.shl(rhs), + y: self.y.shl(rhs), + z: self.z.shl(rhs), + } + } +} + +impl Shr for UVec3 { + type Output = Self; + #[inline] + fn shr(self, rhs: i16) -> Self::Output { + Self { + x: self.x.shr(rhs), + y: self.y.shr(rhs), + z: self.z.shr(rhs), + } + } +} + +impl Shl for UVec3 { + type Output = Self; + #[inline] + fn shl(self, rhs: i32) -> Self::Output { + Self { + x: self.x.shl(rhs), + y: self.y.shl(rhs), + z: self.z.shl(rhs), + } + } +} + +impl Shr for UVec3 { + type Output = Self; + #[inline] + fn shr(self, rhs: i32) -> Self::Output { + Self { + x: self.x.shr(rhs), + y: self.y.shr(rhs), + z: self.z.shr(rhs), + } + } +} + +impl Shl for UVec3 { + type Output = Self; + #[inline] + fn shl(self, rhs: u8) -> Self::Output { + Self { + x: self.x.shl(rhs), + y: self.y.shl(rhs), + z: self.z.shl(rhs), + } + } +} + +impl Shr for UVec3 { + type Output = Self; + #[inline] + fn shr(self, rhs: u8) -> Self::Output { + Self { + x: self.x.shr(rhs), + y: self.y.shr(rhs), + z: self.z.shr(rhs), + } + } +} + +impl Shl for UVec3 { + type Output = Self; + #[inline] + fn shl(self, rhs: u16) -> Self::Output { + Self { + x: self.x.shl(rhs), + y: self.y.shl(rhs), + z: self.z.shl(rhs), + } + } +} + +impl Shr for UVec3 { + type Output = Self; + #[inline] + fn shr(self, rhs: u16) -> Self::Output { + Self { + x: self.x.shr(rhs), + y: self.y.shr(rhs), + z: self.z.shr(rhs), + } + } +} + +impl Shl for UVec3 { + type Output = Self; + #[inline] + fn shl(self, rhs: u32) -> Self::Output { + Self { + x: self.x.shl(rhs), + y: self.y.shl(rhs), + z: self.z.shl(rhs), + } + } +} + +impl Shr for UVec3 { + type Output = Self; + #[inline] + fn shr(self, rhs: u32) -> Self::Output { + Self { + x: self.x.shr(rhs), + y: self.y.shr(rhs), + z: self.z.shr(rhs), + } + } +} + +impl Shl for UVec3 { + type Output = Self; + #[inline] + fn shl(self, rhs: crate::IVec3) -> Self::Output { + Self { + x: self.x.shl(rhs.x), + y: self.y.shl(rhs.y), + z: self.z.shl(rhs.z), + } + } +} + +impl Shr for UVec3 { + type Output = Self; + #[inline] + fn shr(self, rhs: crate::IVec3) -> Self::Output { + Self { + x: self.x.shr(rhs.x), + y: self.y.shr(rhs.y), + z: self.z.shr(rhs.z), + } + } +} + +impl Shl for UVec3 { + type Output = Self; + #[inline] + fn shl(self, rhs: crate::UVec3) -> Self::Output { + Self { + x: self.x.shl(rhs.x), + y: self.y.shl(rhs.y), + z: self.z.shl(rhs.z), + } + } +} + +impl Shr for UVec3 { + type Output = Self; + #[inline] + fn shr(self, rhs: crate::UVec3) -> Self::Output { + Self { + x: self.x.shr(rhs.x), + y: self.y.shr(rhs.y), + z: self.z.shr(rhs.z), + } + } +} + +impl Index for UVec3 { + type Output = u32; + #[inline] + fn index(&self, index: usize) -> &Self::Output { + match index { + 0 => &self.x, + 1 => &self.y, + 2 => &self.z, + _ => panic!("index out of bounds"), + } + } +} + +impl IndexMut for UVec3 { + #[inline] + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + match index { + 0 => &mut self.x, + 1 => &mut self.y, + 2 => &mut self.z, + _ => panic!("index out of bounds"), + } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Display for UVec3 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "[{}, {}, {}]", self.x, self.y, self.z) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Debug for UVec3 { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_tuple(stringify!(UVec3)) + .field(&self.x) + .field(&self.y) + .field(&self.z) + .finish() + } +} + +impl From<[u32; 3]> for UVec3 { + #[inline] + fn from(a: [u32; 3]) -> Self { + Self::new(a[0], a[1], a[2]) + } +} + +impl From for [u32; 3] { + #[inline] + fn from(v: UVec3) -> Self { + [v.x, v.y, v.z] + } +} + +impl From<(u32, u32, u32)> for UVec3 { + #[inline] + fn from(t: (u32, u32, u32)) -> Self { + Self::new(t.0, t.1, t.2) + } +} + +impl From for (u32, u32, u32) { + #[inline] + fn from(v: UVec3) -> Self { + (v.x, v.y, v.z) + } +} + +impl From<(UVec2, u32)> for UVec3 { + #[inline] + fn from((v, z): (UVec2, u32)) -> Self { + Self::new(v.x, v.y, z) + } +} diff --git a/src/u32/uvec4.rs b/src/u32/uvec4.rs new file mode 100644 index 00000000..0a893112 --- /dev/null +++ b/src/u32/uvec4.rs @@ -0,0 +1,1051 @@ +// Generated from vec.rs template. Edit the template, not the generated file. + +use crate::{BVec4, UVec2, UVec3}; + +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::iter::{Product, Sum}; +use core::{f32, ops::*}; + +/// Creates a 4-dimensional vector. +#[inline(always)] +pub const fn uvec4(x: u32, y: u32, z: u32, w: u32) -> UVec4 { + UVec4::new(x, y, z, w) +} + +/// A 4-dimensional vector. +#[derive(Clone, Copy)] +#[cfg_attr(feature = "cuda", repr(C, align(16)))] +pub struct UVec4 { + pub x: u32, + pub y: u32, + pub z: u32, + pub w: u32, +} + +impl UVec4 { + /// All zeroes. + pub const ZERO: Self = Self::splat(0); + + /// All ones. + pub const ONE: Self = Self::splat(1); + + /// `[1, 0, 0, 0]`: a unit-length vector pointing along the positive X axis. + pub const X: Self = Self::from_array([1, 0, 0, 0]); + + /// `[0, 1, 0, 0]`: a unit-length vector pointing along the positive Y axis. + pub const Y: Self = Self::from_array([0, 1, 0, 0]); + + /// `[0, 0, 1, 0]`: a unit-length vector pointing along the positive Z axis. + pub const Z: Self = Self::from_array([0, 0, 1, 0]); + + /// `[0, 0, 0, 1]`: a unit-length vector pointing along the positive W axis. + pub const W: Self = Self::from_array([0, 0, 0, 1]); + + /// The unit axes. + pub const AXES: [Self; 4] = [Self::X, Self::Y, Self::Z, Self::W]; + + /// Creates a new vector. + #[inline(always)] + pub const fn new(x: u32, y: u32, z: u32, w: u32) -> Self { + Self { x, y, z, w } + } + + /// Creates a vector with all elements set to `v`. + #[inline] + pub const fn splat(v: u32) -> Self { + Self { + x: v, + + y: v, + + z: v, + + w: v, + } + } + + /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use + /// for each element of `self`. + /// + /// A true element in the mask uses the corresponding element from `if_true`, and false + /// uses the element from `if_false`. + #[inline] + pub fn select(mask: BVec4, if_true: Self, if_false: Self) -> Self { + Self { + x: if mask.x { if_true.x } else { if_false.x }, + y: if mask.y { if_true.y } else { if_false.y }, + z: if mask.z { if_true.z } else { if_false.z }, + w: if mask.w { if_true.w } else { if_false.w }, + } + } + + /// Creates a new vector from an array. + #[inline] + pub const fn from_array(a: [u32; 4]) -> Self { + Self::new(a[0], a[1], a[2], a[3]) + } + + /// `[x, y, z, w]` + #[inline] + pub const fn to_array(&self) -> [u32; 4] { + [self.x, self.y, self.z, self.w] + } + + /// Creates a vector from the first N values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than N elements long. + #[inline] + pub const fn from_slice(slice: &[u32]) -> Self { + Self::new(slice[0], slice[1], slice[2], slice[3]) + } + + /// Writes the elements of `self` to the first 4 elements in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than N elements long. + #[inline] + pub fn write_to_slice(self, slice: &mut [u32]) { + slice[0] = self.x; + slice[1] = self.y; + slice[2] = self.z; + slice[3] = self.w; + } + + /// Creates a 2D vector from the `x`, `y` and `z` elements of `self`, discarding `w`. + /// + /// Truncation to `UVec3` may also be performed by using `self.xyz()` or `UVec3::from()`. + #[inline] + pub fn truncate(self) -> UVec3 { + use crate::swizzles::Vec4Swizzles; + self.xyz() + } + + /// Computes the dot product of `self` and `rhs`. + #[inline] + pub fn dot(self, rhs: Self) -> u32 { + (self.x * rhs.x) + (self.y * rhs.y) + (self.z * rhs.z) + (self.w * rhs.w) + } + + /// Returns a vector containing the minimum values for each element of `self` and `rhs`. + /// + /// In other words this computes `[self.x.min(rhs.x), self.y.min(rhs.y), ..]`. + #[inline] + pub fn min(self, rhs: Self) -> Self { + Self { + x: self.x.min(rhs.x), + y: self.y.min(rhs.y), + z: self.z.min(rhs.z), + w: self.w.min(rhs.w), + } + } + + /// Returns a vector containing the maximum values for each element of `self` and `rhs`. + /// + /// In other words this computes `[self.x.max(rhs.x), self.y.max(rhs.y), ..]`. + #[inline] + pub fn max(self, rhs: Self) -> Self { + Self { + x: self.x.max(rhs.x), + y: self.y.max(rhs.y), + z: self.z.max(rhs.z), + w: self.w.max(rhs.w), + } + } + + /// Component-wise clamping of values, similar to [`f32::clamp`]. + /// + /// Each element in `min` must be less-or-equal to the corresponding element in `max`. + /// + /// # Panics + /// + /// Will panic if `min` is greater than `max` when `glam_assert` is enabled. + #[inline] + pub fn clamp(self, min: Self, max: Self) -> Self { + glam_assert!(min.cmple(max).all(), "clamp: expected min <= max"); + self.max(min).min(max) + } + + /// Returns the horizontal minimum of `self`. + /// + /// In other words this computes `min(x, y, ..)`. + #[inline] + pub fn min_element(self) -> u32 { + self.x.min(self.y.min(self.z.min(self.w))) + } + + /// Returns the horizontal maximum of `self`. + /// + /// In other words this computes `max(x, y, ..)`. + #[inline] + pub fn max_element(self) -> u32 { + self.x.max(self.y.max(self.z.max(self.w))) + } + + /// Returns a vector mask containing the result of a `==` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words, this computes `[self.x == rhs.x, self.y == rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpeq(self, rhs: Self) -> BVec4 { + BVec4::new( + self.x.eq(&rhs.x), + self.y.eq(&rhs.y), + self.z.eq(&rhs.z), + self.w.eq(&rhs.w), + ) + } + + /// Returns a vector mask containing the result of a `!=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x != rhs.x, self.y != rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpne(self, rhs: Self) -> BVec4 { + BVec4::new( + self.x.ne(&rhs.x), + self.y.ne(&rhs.y), + self.z.ne(&rhs.z), + self.w.ne(&rhs.w), + ) + } + + /// Returns a vector mask containing the result of a `>=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x >= rhs.x, self.y >= rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpge(self, rhs: Self) -> BVec4 { + BVec4::new( + self.x.ge(&rhs.x), + self.y.ge(&rhs.y), + self.z.ge(&rhs.z), + self.w.ge(&rhs.w), + ) + } + + /// Returns a vector mask containing the result of a `>` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x > rhs.x, self.y > rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmpgt(self, rhs: Self) -> BVec4 { + BVec4::new( + self.x.gt(&rhs.x), + self.y.gt(&rhs.y), + self.z.gt(&rhs.z), + self.w.gt(&rhs.w), + ) + } + + /// Returns a vector mask containing the result of a `<=` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x <= rhs.x, self.y <= rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmple(self, rhs: Self) -> BVec4 { + BVec4::new( + self.x.le(&rhs.x), + self.y.le(&rhs.y), + self.z.le(&rhs.z), + self.w.le(&rhs.w), + ) + } + + /// Returns a vector mask containing the result of a `<` comparison for each element of + /// `self` and `rhs`. + /// + /// In other words this computes `[self.x < rhs.x, self.y < rhs.y, ..]` for all + /// elements. + #[inline] + pub fn cmplt(self, rhs: Self) -> BVec4 { + BVec4::new( + self.x.lt(&rhs.x), + self.y.lt(&rhs.y), + self.z.lt(&rhs.z), + self.w.lt(&rhs.w), + ) + } + + /// Casts all elements of `self` to `f32`. + #[inline] + pub fn as_vec4(&self) -> crate::Vec4 { + crate::Vec4::new(self.x as f32, self.y as f32, self.z as f32, self.w as f32) + } + + /// Casts all elements of `self` to `f64`. + #[inline] + pub fn as_dvec4(&self) -> crate::DVec4 { + crate::DVec4::new(self.x as f64, self.y as f64, self.z as f64, self.w as f64) + } + + /// Casts all elements of `self` to `i32`. + #[inline] + pub fn as_ivec4(&self) -> crate::IVec4 { + crate::IVec4::new(self.x as i32, self.y as i32, self.z as i32, self.w as i32) + } +} + +impl Default for UVec4 { + #[inline(always)] + fn default() -> Self { + Self::ZERO + } +} + +impl PartialEq for UVec4 { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.cmpeq(*rhs).all() + } +} + +impl Div for UVec4 { + type Output = Self; + #[inline] + fn div(self, rhs: Self) -> Self { + Self { + x: self.x.div(rhs.x), + y: self.y.div(rhs.y), + z: self.z.div(rhs.z), + w: self.w.div(rhs.w), + } + } +} + +impl DivAssign for UVec4 { + #[inline] + fn div_assign(&mut self, rhs: Self) { + self.x.div_assign(rhs.x); + self.y.div_assign(rhs.y); + self.z.div_assign(rhs.z); + self.w.div_assign(rhs.w); + } +} + +impl Div for UVec4 { + type Output = Self; + #[inline] + fn div(self, rhs: u32) -> Self { + Self { + x: self.x.div(rhs), + y: self.y.div(rhs), + z: self.z.div(rhs), + w: self.w.div(rhs), + } + } +} + +impl DivAssign for UVec4 { + #[inline] + fn div_assign(&mut self, rhs: u32) { + self.x.div_assign(rhs); + self.y.div_assign(rhs); + self.z.div_assign(rhs); + self.w.div_assign(rhs); + } +} + +impl Div for u32 { + type Output = UVec4; + #[inline] + fn div(self, rhs: UVec4) -> UVec4 { + UVec4 { + x: self.div(rhs.x), + y: self.div(rhs.y), + z: self.div(rhs.z), + w: self.div(rhs.w), + } + } +} + +impl Mul for UVec4 { + type Output = Self; + #[inline] + fn mul(self, rhs: Self) -> Self { + Self { + x: self.x.mul(rhs.x), + y: self.y.mul(rhs.y), + z: self.z.mul(rhs.z), + w: self.w.mul(rhs.w), + } + } +} + +impl MulAssign for UVec4 { + #[inline] + fn mul_assign(&mut self, rhs: Self) { + self.x.mul_assign(rhs.x); + self.y.mul_assign(rhs.y); + self.z.mul_assign(rhs.z); + self.w.mul_assign(rhs.w); + } +} + +impl Mul for UVec4 { + type Output = Self; + #[inline] + fn mul(self, rhs: u32) -> Self { + Self { + x: self.x.mul(rhs), + y: self.y.mul(rhs), + z: self.z.mul(rhs), + w: self.w.mul(rhs), + } + } +} + +impl MulAssign for UVec4 { + #[inline] + fn mul_assign(&mut self, rhs: u32) { + self.x.mul_assign(rhs); + self.y.mul_assign(rhs); + self.z.mul_assign(rhs); + self.w.mul_assign(rhs); + } +} + +impl Mul for u32 { + type Output = UVec4; + #[inline] + fn mul(self, rhs: UVec4) -> UVec4 { + UVec4 { + x: self.mul(rhs.x), + y: self.mul(rhs.y), + z: self.mul(rhs.z), + w: self.mul(rhs.w), + } + } +} + +impl Add for UVec4 { + type Output = Self; + #[inline] + fn add(self, rhs: Self) -> Self { + Self { + x: self.x.add(rhs.x), + y: self.y.add(rhs.y), + z: self.z.add(rhs.z), + w: self.w.add(rhs.w), + } + } +} + +impl AddAssign for UVec4 { + #[inline] + fn add_assign(&mut self, rhs: Self) { + self.x.add_assign(rhs.x); + self.y.add_assign(rhs.y); + self.z.add_assign(rhs.z); + self.w.add_assign(rhs.w); + } +} + +impl Add for UVec4 { + type Output = Self; + #[inline] + fn add(self, rhs: u32) -> Self { + Self { + x: self.x.add(rhs), + y: self.y.add(rhs), + z: self.z.add(rhs), + w: self.w.add(rhs), + } + } +} + +impl AddAssign for UVec4 { + #[inline] + fn add_assign(&mut self, rhs: u32) { + self.x.add_assign(rhs); + self.y.add_assign(rhs); + self.z.add_assign(rhs); + self.w.add_assign(rhs); + } +} + +impl Add for u32 { + type Output = UVec4; + #[inline] + fn add(self, rhs: UVec4) -> UVec4 { + UVec4 { + x: self.add(rhs.x), + y: self.add(rhs.y), + z: self.add(rhs.z), + w: self.add(rhs.w), + } + } +} + +impl Sub for UVec4 { + type Output = Self; + #[inline] + fn sub(self, rhs: Self) -> Self { + Self { + x: self.x.sub(rhs.x), + y: self.y.sub(rhs.y), + z: self.z.sub(rhs.z), + w: self.w.sub(rhs.w), + } + } +} + +impl SubAssign for UVec4 { + #[inline] + fn sub_assign(&mut self, rhs: UVec4) { + self.x.sub_assign(rhs.x); + self.y.sub_assign(rhs.y); + self.z.sub_assign(rhs.z); + self.w.sub_assign(rhs.w); + } +} + +impl Sub for UVec4 { + type Output = Self; + #[inline] + fn sub(self, rhs: u32) -> Self { + Self { + x: self.x.sub(rhs), + y: self.y.sub(rhs), + z: self.z.sub(rhs), + w: self.w.sub(rhs), + } + } +} + +impl SubAssign for UVec4 { + #[inline] + fn sub_assign(&mut self, rhs: u32) { + self.x.sub_assign(rhs); + self.y.sub_assign(rhs); + self.z.sub_assign(rhs); + self.w.sub_assign(rhs); + } +} + +impl Sub for u32 { + type Output = UVec4; + #[inline] + fn sub(self, rhs: UVec4) -> UVec4 { + UVec4 { + x: self.sub(rhs.x), + y: self.sub(rhs.y), + z: self.sub(rhs.z), + w: self.sub(rhs.w), + } + } +} + +impl Rem for UVec4 { + type Output = Self; + #[inline] + fn rem(self, rhs: Self) -> Self { + Self { + x: self.x.rem(rhs.x), + y: self.y.rem(rhs.y), + z: self.z.rem(rhs.z), + w: self.w.rem(rhs.w), + } + } +} + +impl RemAssign for UVec4 { + #[inline] + fn rem_assign(&mut self, rhs: Self) { + self.x.rem_assign(rhs.x); + self.y.rem_assign(rhs.y); + self.z.rem_assign(rhs.z); + self.w.rem_assign(rhs.w); + } +} + +impl Rem for UVec4 { + type Output = Self; + #[inline] + fn rem(self, rhs: u32) -> Self { + Self { + x: self.x.rem(rhs), + y: self.y.rem(rhs), + z: self.z.rem(rhs), + w: self.w.rem(rhs), + } + } +} + +impl RemAssign for UVec4 { + #[inline] + fn rem_assign(&mut self, rhs: u32) { + self.x.rem_assign(rhs); + self.y.rem_assign(rhs); + self.z.rem_assign(rhs); + self.w.rem_assign(rhs); + } +} + +impl Rem for u32 { + type Output = UVec4; + #[inline] + fn rem(self, rhs: UVec4) -> UVec4 { + UVec4 { + x: self.rem(rhs.x), + y: self.rem(rhs.y), + z: self.rem(rhs.z), + w: self.rem(rhs.w), + } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsRef<[u32; 4]> for UVec4 { + #[inline] + fn as_ref(&self) -> &[u32; 4] { + unsafe { &*(self as *const UVec4 as *const [u32; 4]) } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl AsMut<[u32; 4]> for UVec4 { + #[inline] + fn as_mut(&mut self) -> &mut [u32; 4] { + unsafe { &mut *(self as *mut UVec4 as *mut [u32; 4]) } + } +} + +impl<'a> Sum<&'a Self> for UVec4 { + #[inline] + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, |a, &b| Self::add(a, b)) + } +} + +impl<'a> Product<&'a Self> for UVec4 { + #[inline] + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ONE, |a, &b| Self::mul(a, b)) + } +} + +impl Eq for UVec4 {} + +#[cfg(not(target_arch = "spirv"))] +impl core::hash::Hash for UVec4 { + fn hash(&self, state: &mut H) { + let inner: &[u32; 4] = self.as_ref(); + inner.hash(state); + } +} + +impl Not for UVec4 { + type Output = Self; + #[inline] + fn not(self) -> Self::Output { + Self { + x: self.x.not(), + y: self.y.not(), + z: self.z.not(), + w: self.w.not(), + } + } +} + +impl BitAnd for UVec4 { + type Output = Self; + #[inline] + fn bitand(self, rhs: Self) -> Self::Output { + Self { + x: self.x.bitand(rhs.x), + y: self.y.bitand(rhs.y), + z: self.z.bitand(rhs.z), + w: self.w.bitand(rhs.w), + } + } +} + +impl BitOr for UVec4 { + type Output = Self; + #[inline] + fn bitor(self, rhs: Self) -> Self::Output { + Self { + x: self.x.bitor(rhs.x), + y: self.y.bitor(rhs.y), + z: self.z.bitor(rhs.z), + w: self.w.bitor(rhs.w), + } + } +} + +impl BitXor for UVec4 { + type Output = Self; + #[inline] + fn bitxor(self, rhs: Self) -> Self::Output { + Self { + x: self.x.bitxor(rhs.x), + y: self.y.bitxor(rhs.y), + z: self.z.bitxor(rhs.z), + w: self.w.bitxor(rhs.w), + } + } +} + +impl BitAnd for UVec4 { + type Output = Self; + #[inline] + fn bitand(self, rhs: u32) -> Self::Output { + Self { + x: self.x.bitand(rhs), + y: self.y.bitand(rhs), + z: self.z.bitand(rhs), + w: self.w.bitand(rhs), + } + } +} + +impl BitOr for UVec4 { + type Output = Self; + #[inline] + fn bitor(self, rhs: u32) -> Self::Output { + Self { + x: self.x.bitor(rhs), + y: self.y.bitor(rhs), + z: self.z.bitor(rhs), + w: self.w.bitor(rhs), + } + } +} + +impl BitXor for UVec4 { + type Output = Self; + #[inline] + fn bitxor(self, rhs: u32) -> Self::Output { + Self { + x: self.x.bitxor(rhs), + y: self.y.bitxor(rhs), + z: self.z.bitxor(rhs), + w: self.w.bitxor(rhs), + } + } +} + +impl Shl for UVec4 { + type Output = Self; + #[inline] + fn shl(self, rhs: i8) -> Self::Output { + Self { + x: self.x.shl(rhs), + y: self.y.shl(rhs), + z: self.z.shl(rhs), + w: self.w.shl(rhs), + } + } +} + +impl Shr for UVec4 { + type Output = Self; + #[inline] + fn shr(self, rhs: i8) -> Self::Output { + Self { + x: self.x.shr(rhs), + y: self.y.shr(rhs), + z: self.z.shr(rhs), + w: self.w.shr(rhs), + } + } +} + +impl Shl for UVec4 { + type Output = Self; + #[inline] + fn shl(self, rhs: i16) -> Self::Output { + Self { + x: self.x.shl(rhs), + y: self.y.shl(rhs), + z: self.z.shl(rhs), + w: self.w.shl(rhs), + } + } +} + +impl Shr for UVec4 { + type Output = Self; + #[inline] + fn shr(self, rhs: i16) -> Self::Output { + Self { + x: self.x.shr(rhs), + y: self.y.shr(rhs), + z: self.z.shr(rhs), + w: self.w.shr(rhs), + } + } +} + +impl Shl for UVec4 { + type Output = Self; + #[inline] + fn shl(self, rhs: i32) -> Self::Output { + Self { + x: self.x.shl(rhs), + y: self.y.shl(rhs), + z: self.z.shl(rhs), + w: self.w.shl(rhs), + } + } +} + +impl Shr for UVec4 { + type Output = Self; + #[inline] + fn shr(self, rhs: i32) -> Self::Output { + Self { + x: self.x.shr(rhs), + y: self.y.shr(rhs), + z: self.z.shr(rhs), + w: self.w.shr(rhs), + } + } +} + +impl Shl for UVec4 { + type Output = Self; + #[inline] + fn shl(self, rhs: u8) -> Self::Output { + Self { + x: self.x.shl(rhs), + y: self.y.shl(rhs), + z: self.z.shl(rhs), + w: self.w.shl(rhs), + } + } +} + +impl Shr for UVec4 { + type Output = Self; + #[inline] + fn shr(self, rhs: u8) -> Self::Output { + Self { + x: self.x.shr(rhs), + y: self.y.shr(rhs), + z: self.z.shr(rhs), + w: self.w.shr(rhs), + } + } +} + +impl Shl for UVec4 { + type Output = Self; + #[inline] + fn shl(self, rhs: u16) -> Self::Output { + Self { + x: self.x.shl(rhs), + y: self.y.shl(rhs), + z: self.z.shl(rhs), + w: self.w.shl(rhs), + } + } +} + +impl Shr for UVec4 { + type Output = Self; + #[inline] + fn shr(self, rhs: u16) -> Self::Output { + Self { + x: self.x.shr(rhs), + y: self.y.shr(rhs), + z: self.z.shr(rhs), + w: self.w.shr(rhs), + } + } +} + +impl Shl for UVec4 { + type Output = Self; + #[inline] + fn shl(self, rhs: u32) -> Self::Output { + Self { + x: self.x.shl(rhs), + y: self.y.shl(rhs), + z: self.z.shl(rhs), + w: self.w.shl(rhs), + } + } +} + +impl Shr for UVec4 { + type Output = Self; + #[inline] + fn shr(self, rhs: u32) -> Self::Output { + Self { + x: self.x.shr(rhs), + y: self.y.shr(rhs), + z: self.z.shr(rhs), + w: self.w.shr(rhs), + } + } +} + +impl Shl for UVec4 { + type Output = Self; + #[inline] + fn shl(self, rhs: crate::IVec4) -> Self::Output { + Self { + x: self.x.shl(rhs.x), + y: self.y.shl(rhs.y), + z: self.z.shl(rhs.z), + w: self.w.shl(rhs.w), + } + } +} + +impl Shr for UVec4 { + type Output = Self; + #[inline] + fn shr(self, rhs: crate::IVec4) -> Self::Output { + Self { + x: self.x.shr(rhs.x), + y: self.y.shr(rhs.y), + z: self.z.shr(rhs.z), + w: self.w.shr(rhs.w), + } + } +} + +impl Shl for UVec4 { + type Output = Self; + #[inline] + fn shl(self, rhs: crate::UVec4) -> Self::Output { + Self { + x: self.x.shl(rhs.x), + y: self.y.shl(rhs.y), + z: self.z.shl(rhs.z), + w: self.w.shl(rhs.w), + } + } +} + +impl Shr for UVec4 { + type Output = Self; + #[inline] + fn shr(self, rhs: crate::UVec4) -> Self::Output { + Self { + x: self.x.shr(rhs.x), + y: self.y.shr(rhs.y), + z: self.z.shr(rhs.z), + w: self.w.shr(rhs.w), + } + } +} + +impl Index for UVec4 { + type Output = u32; + #[inline] + fn index(&self, index: usize) -> &Self::Output { + match index { + 0 => &self.x, + 1 => &self.y, + 2 => &self.z, + 3 => &self.w, + _ => panic!("index out of bounds"), + } + } +} + +impl IndexMut for UVec4 { + #[inline] + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + match index { + 0 => &mut self.x, + 1 => &mut self.y, + 2 => &mut self.z, + 3 => &mut self.w, + _ => panic!("index out of bounds"), + } + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Display for UVec4 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "[{}, {}, {}, {}]", self.x, self.y, self.z, self.w) + } +} + +#[cfg(not(target_arch = "spirv"))] +impl fmt::Debug for UVec4 { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_tuple(stringify!(UVec4)) + .field(&self.x) + .field(&self.y) + .field(&self.z) + .field(&self.w) + .finish() + } +} + +impl From<[u32; 4]> for UVec4 { + #[inline] + fn from(a: [u32; 4]) -> Self { + Self::new(a[0], a[1], a[2], a[3]) + } +} + +impl From for [u32; 4] { + #[inline] + fn from(v: UVec4) -> Self { + [v.x, v.y, v.z, v.w] + } +} + +impl From<(u32, u32, u32, u32)> for UVec4 { + #[inline] + fn from(t: (u32, u32, u32, u32)) -> Self { + Self::new(t.0, t.1, t.2, t.3) + } +} + +impl From for (u32, u32, u32, u32) { + #[inline] + fn from(v: UVec4) -> Self { + (v.x, v.y, v.z, v.w) + } +} + +impl From<(UVec3, u32)> for UVec4 { + #[inline] + fn from((v, w): (UVec3, u32)) -> Self { + Self::new(v.x, v.y, v.z, w) + } +} + +impl From<(u32, UVec3)> for UVec4 { + #[inline] + fn from((x, v): (u32, UVec3)) -> Self { + Self::new(x, v.x, v.y, v.z) + } +} + +impl From<(UVec2, u32, u32)> for UVec4 { + #[inline] + fn from((v, z, w): (UVec2, u32, u32)) -> Self { + Self::new(v.x, v.y, z, w) + } +} + +impl From<(UVec2, UVec2)> for UVec4 { + #[inline] + fn from((v, u): (UVec2, UVec2)) -> Self { + Self::new(v.x, v.y, u.x, u.y) + } +} diff --git a/src/vec.rs b/src/vec.rs deleted file mode 100644 index a96e7efe..00000000 --- a/src/vec.rs +++ /dev/null @@ -1,1029 +0,0 @@ -// Adds common vector methods to an impl. - -// The methods here should be supported for all types of $t and all sizes of vector. -macro_rules! impl_vecn_common_methods { - ($t:ty, $vecn:ident, $mask:ident, $inner:ident, $vectrait:ident) => { - /// Creates a vector with all elements set to `v`. - #[inline(always)] - pub fn splat(v: $t) -> Self { - Self($inner::splat(v)) - } - - /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use - /// for each element of `self`. - /// - /// A true element in the mask uses the corresponding element from `if_true`, and false - /// uses the element from `if_false`. - #[inline(always)] - pub fn select(mask: $mask, if_true: $vecn, if_false: $vecn) -> $vecn { - Self($inner::select(mask.0, if_true.0, if_false.0)) - } - - /// Computes the dot product of `self` and `other`. - #[inline(always)] - pub fn dot(self, other: Self) -> $t { - $vectrait::dot(self.0, other.0) - } - - /// Returns a vector containing the minimum values for each element of `self` and `other`. - /// - /// In other words this computes `[self.x.min(other.x), self.y.min(other.y), ..]`. - #[inline(always)] - pub fn min(self, other: Self) -> Self { - Self(self.0.min(other.0)) - } - - /// Returns a vector containing the maximum values for each element of `self` and `other`. - /// - /// In other words this computes `[self.x.max(other.x), self.y.max(other.y), ..]`. - #[inline(always)] - pub fn max(self, other: Self) -> Self { - Self(self.0.max(other.0)) - } - - /// Component-wise clamping of values, similar to [`f32::clamp`]. - /// - /// Each element in `min` must be less-or-equal to the corresponding element in `max`. - /// - /// # Panics - /// - /// Will panic if `min` is greater than `max` when `glam_assert` is enabled. - #[inline(always)] - pub fn clamp(self, min: Self, max: Self) -> Self { - Self($vectrait::clamp(self.0, min.0, max.0)) - } - - /// Returns the horizontal minimum of `self`. - /// - /// In other words this computes `min(x, y, ..)`. - #[inline(always)] - pub fn min_element(self) -> $t { - $vectrait::min_element(self.0) - } - - /// Returns the horizontal maximum of `self`. - /// - /// In other words this computes `max(x, y, ..)`. - #[inline(always)] - pub fn max_element(self) -> $t { - $vectrait::max_element(self.0) - } - - /// Returns a vector mask containing the result of a `==` comparison for each element of - /// `self` and `other`. - /// - /// In other words, this computes `[self.x == other.x, self.y == other.y, ..]` for all - /// elements. - #[inline(always)] - pub fn cmpeq(self, other: Self) -> $mask { - $mask(self.0.cmpeq(other.0)) - } - - /// Returns a vector mask containing the result of a `!=` comparison for each element of - /// `self` and `other`. - /// - /// In other words this computes `[self.x != other.x, self.y != other.y, ..]` for all - /// elements. - #[inline(always)] - pub fn cmpne(self, other: Self) -> $mask { - $mask(self.0.cmpne(other.0)) - } - - /// Returns a vector mask containing the result of a `>=` comparison for each element of - /// `self` and `other`. - /// - /// In other words this computes `[self.x >= other.x, self.y >= other.y, ..]` for all - /// elements. - #[inline(always)] - pub fn cmpge(self, other: Self) -> $mask { - $mask(self.0.cmpge(other.0)) - } - - /// Returns a vector mask containing the result of a `>` comparison for each element of - /// `self` and `other`. - /// - /// In other words this computes `[self.x > other.x, self.y > other.y, ..]` for all - /// elements. - #[inline(always)] - pub fn cmpgt(self, other: Self) -> $mask { - $mask(self.0.cmpgt(other.0)) - } - - /// Returns a vector mask containing the result of a `<=` comparison for each element of - /// `self` and `other`. - /// - /// In other words this computes `[self.x <= other.x, self.y <= other.y, ..]` for all - /// elements. - #[inline(always)] - pub fn cmple(self, other: Self) -> $mask { - $mask(self.0.cmple(other.0)) - } - - /// Returns a vector mask containing the result of a `<` comparison for each element of - /// `self` and `other`. - /// - /// In other words this computes `[self.x < other.x, self.y < other.y, ..]` for all - /// elements. - #[inline(always)] - pub fn cmplt(self, other: Self) -> $mask { - $mask(self.0.cmplt(other.0)) - } - - /// Creates a vector from the first N values in `slice`. - /// - /// # Panics - /// - /// Panics if `slice` is less than N elements long. - #[inline(always)] - pub fn from_slice(slice: &[$t]) -> Self { - Self($vectrait::from_slice_unaligned(slice)) - } - - /// Writes the elements of `self` to the first N elements in `slice`. - /// - /// # Panics - /// - /// Panics if `slice` is less than N elements long. - #[inline(always)] - pub fn write_to_slice(self, slice: &mut [$t]) { - $vectrait::write_to_slice_unaligned(self.0, slice) - } - }; -} - -// Adds signed type vector methods to an impl. -// The methods here should be supported for signed types of $t and all sizes of vector. -macro_rules! impl_vecn_signed_methods { - ($t:ty, $vecn:ident, $mask:ident, $inner:ident, $sgntrait:ident) => { - // impl_vecn_common_methods!($t, $vecn, $mask, $inner, $vectrait); - - /// Returns a vector containing the absolute value of each element of `self`. - #[inline(always)] - pub fn abs(self) -> Self { - Self($sgntrait::abs(self.0)) - } - - /// Returns a vector with elements representing the sign of `self`. - /// - /// - `1.0` if the number is positive, `+0.0` or `INFINITY` - /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` - /// - `NAN` if the number is `NAN` - #[inline(always)] - pub fn signum(self) -> Self { - Self($sgntrait::signum(self.0)) - } - }; -} - -// Adds float type vector methods to an impl. -// The methods here should be supported for float types of $t and all sizes of vector. -macro_rules! impl_vecn_float_methods { - ($t:ty, $vecn:ident, $mask:ident, $inner:ident, $flttrait:ident) => { - // impl_vecn_signed_methods!($t, $vecn, $mask, $inner, $sgntrait, $vectrait); - - /// All NAN. - pub const NAN: Self = Self(<$inner as crate::core::traits::scalar::NanConstEx>::NAN); - - /// Returns `true` if, and only if, all elements are finite. If any element is either - /// `NaN`, positive or negative infinity, this will return `false`. - #[inline(always)] - pub fn is_finite(self) -> bool { - $flttrait::is_finite(self.0) - } - - /// Returns `true` if any elements are `NaN`. - #[inline(always)] - pub fn is_nan(self) -> bool { - $flttrait::is_nan(self.0) - } - - /// Performs `is_nan` on each element of self, returning a vector mask of the results. - /// - /// In other words, this computes `[x.is_nan(), y.is_nan(), z.is_nan(), w.is_nan()]`. - #[inline(always)] - pub fn is_nan_mask(self) -> $mask { - $mask($flttrait::is_nan_mask(self.0)) - } - - /// Computes the length of `self`. - #[doc(alias = "magnitude")] - #[inline(always)] - pub fn length(self) -> $t { - $flttrait::length(self.0) - } - - /// Computes the squared length of `self`. - /// - /// This is faster than `length()` as it avoids a square root operation. - #[doc(alias = "magnitude2")] - #[inline(always)] - pub fn length_squared(self) -> $t { - $flttrait::length_squared(self.0) - } - - /// Computes `1.0 / length()`. - /// - /// For valid results, `self` must _not_ be of length zero. - #[inline(always)] - pub fn length_recip(self) -> $t { - $flttrait::length_recip(self.0) - } - - /// Computes the Euclidean distance between two points in space. - #[inline] - pub fn distance(self, other: Self) -> $t { - (self - other).length() - } - - /// Compute the squared euclidean distance between two points in space. - #[inline] - pub fn distance_squared(self, other: Self) -> $t { - (self - other).length_squared() - } - - /// Returns `self` normalized to length 1.0. - /// - /// For valid results, `self` must _not_ be of length zero, nor very close to zero. - /// - /// See also [`Self::try_normalize`] and [`Self::normalize_or_zero`]. - /// - /// Panics - /// - /// Will panic if `self` is zero length when `glam_assert` is enabled. - #[must_use] - #[inline(always)] - pub fn normalize(self) -> Self { - Self($flttrait::normalize(self.0)) - } - - /// Returns `self` normalized to length 1.0 if possible, else returns `None`. - /// - /// In particular, if the input is zero (or very close to zero), or non-finite, - /// the result of this operation will be `None`. - /// - /// See also [`Self::normalize_or_zero`]. - #[must_use] - #[inline] - pub fn try_normalize(self) -> Option { - let rcp = self.length_recip(); - if rcp.is_finite() && rcp > 0.0 { - Some(self * rcp) - } else { - None - } - } - - /// Returns `self` normalized to length 1.0 if possible, else returns zero. - /// - /// In particular, if the input is zero (or very close to zero), or non-finite, - /// the result of this operation will be zero. - /// - /// See also [`Self::try_normalize`]. - #[must_use] - #[inline] - pub fn normalize_or_zero(self) -> Self { - let rcp = self.length_recip(); - if rcp.is_finite() && rcp > 0.0 { - self * rcp - } else { - Self::ZERO - } - } - - /// Returns whether `self` is length `1.0` or not. - /// - /// Uses a precision threshold of `1e-6`. - #[inline(always)] - pub fn is_normalized(self) -> bool { - $flttrait::is_normalized(self.0) - } - - /// Returns the vector projection of `self` onto `other`. - /// - /// `other` must be of non-zero length. - /// - /// # Panics - /// - /// Will panic if `other` is zero length when `glam_assert` is enabled. - #[must_use] - #[inline] - pub fn project_onto(self, other: Self) -> Self { - let other_len_sq_rcp = other.dot(other).recip(); - glam_assert!(other_len_sq_rcp.is_finite()); - other * self.dot(other) * other_len_sq_rcp - } - - /// Returns the vector rejection of `self` from `other`. - /// - /// The vector rejection is the vector perpendicular to the projection of `self` onto - /// `other`, in other words the result of `self - self.project_onto(other)`. - /// - /// `other` must be of non-zero length. - /// - /// # Panics - /// - /// Will panic if `other` has a length of zero when `glam_assert` is enabled. - #[must_use] - #[inline] - pub fn reject_from(self, other: Self) -> Self { - self - self.project_onto(other) - } - - /// Returns the vector projection of `self` onto `other`. - /// - /// `other` must be normalized. - /// - /// # Panics - /// - /// Will panic if `other` is not normalized when `glam_assert` is enabled. - #[must_use] - #[inline] - pub fn project_onto_normalized(self, other: Self) -> Self { - glam_assert!(other.is_normalized()); - other * self.dot(other) - } - - /// Returns the vector rejection of `self` from `other`. - /// - /// The vector rejection is the vector perpendicular to the projection of `self` onto - /// `other`, in other words the result of `self - self.project_onto(other)`. - /// - /// `other` must be normalized. - /// - /// # Panics - /// - /// Will panic if `other` is not normalized when `glam_assert` is enabled. - #[must_use] - #[inline] - pub fn reject_from_normalized(self, other: Self) -> Self { - self - self.project_onto_normalized(other) - } - - /// Returns a vector containing the nearest integer to a number for each element of `self`. - /// Round half-way cases away from 0.0. - #[inline(always)] - pub fn round(self) -> Self { - Self($flttrait::round(self.0)) - } - - /// Returns a vector containing the largest integer less than or equal to a number for each - /// element of `self`. - #[inline(always)] - pub fn floor(self) -> Self { - Self($flttrait::floor(self.0)) - } - - /// Returns a vector containing the smallest integer greater than or equal to a number for - /// each element of `self`. - #[inline(always)] - pub fn ceil(self) -> Self { - Self($flttrait::ceil(self.0)) - } - - /// Returns a vector containing the fractional part of the vector, e.g. `self - - /// self.floor()`. - /// - /// Note that this is fast but not precise for large numbers. - #[inline(always)] - pub fn fract(self) -> Self { - self - self.floor() - } - - /// Returns a vector containing `e^self` (the exponential function) for each element of - /// `self`. - #[inline(always)] - pub fn exp(self) -> Self { - Self($flttrait::exp(self.0)) - } - - /// Returns a vector containing each element of `self` raised to the power of `n`. - #[inline(always)] - pub fn powf(self, n: $t) -> Self { - Self($flttrait::powf(self.0, n)) - } - - /// Returns a vector containing the reciprocal `1.0/n` of each element of `self`. - #[inline(always)] - pub fn recip(self) -> Self { - Self($flttrait::recip(self.0)) - } - - /// Performs a linear interpolation between `self` and `other` based on the value `s`. - /// - /// When `s` is `0.0`, the result will be equal to `self`. When `s` is `1.0`, the result - /// will be equal to `other`. When `s` is outside of range [0,1], the result is linearly - /// extrapolated. - #[doc(alias = "mix")] - #[inline] - pub fn lerp(self, other: Self, s: $t) -> Self { - self + ((other - self) * s) - } - - /// Returns true if the absolute difference of all elements between `self` and `other` is - /// less than or equal to `max_abs_diff`. - /// - /// This can be used to compare if two vectors contain similar elements. It works best when - /// comparing with a known value. The `max_abs_diff` that should be used used depends on - /// the values being compared against. - /// - /// For more see - /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/). - #[inline(always)] - pub fn abs_diff_eq(self, other: Self, max_abs_diff: $t) -> bool { - $flttrait::abs_diff_eq(self.0, other.0, max_abs_diff) - } - - /// Returns a vector with a length no less than `min` and no more than `max` - /// - /// # Panics - /// - /// Will panic if `min` is greater than `max` when `glam_assert` is enabled. - #[inline] - pub fn clamp_length(self, min: $t, max: $t) -> Self { - glam_assert!(min <= max); - let length_sq = self.length_squared(); - if length_sq < min * min { - self * (length_sq.sqrt().recip() * min) - } else if length_sq > max * max { - self * (length_sq.sqrt().recip() * max) - } else { - self - } - } - - /// Returns a vector with a length no more than `max` - pub fn clamp_length_max(self, max: $t) -> Self { - let length_sq = self.length_squared(); - if length_sq > max * max { - self * (length_sq.sqrt().recip() * max) - } else { - self - } - } - - /// Returns a vector with a length no less than `min` - pub fn clamp_length_min(self, min: $t) -> Self { - let length_sq = self.length_squared(); - if length_sq < min * min { - self * (length_sq.sqrt().recip() * min) - } else { - self - } - } - - /// Fused multiply-add. Computes `(self * a) + b` element-wise with only one rounding - /// error, yielding a more accurate result than an unfused multiply-add. - /// - /// Using `mul_add` *may* be more performant than an unfused multiply-add if the target - /// architecture has a dedicated fma CPU instruction. However, this is not always true, - /// and will be heavily dependant on designing algorithms with specific target hardware in - /// mind. - #[inline(always)] - pub fn mul_add(self, a: Self, b: Self) -> Self { - Self($flttrait::mul_add(self.0, a.0, b.0)) - } - }; -} - -// Adds common vector trait implementations. -// The traits here should be supported for all types of $t and all sizes of vector. -macro_rules! impl_vecn_common_traits { - ($t:ty, $size:literal, $vecn:ident, $inner:ident, $trait:ident) => { - impl Default for $vecn { - #[inline(always)] - fn default() -> Self { - Self($inner::ZERO) - } - } - - impl PartialEq for $vecn { - #[inline(always)] - fn eq(&self, other: &Self) -> bool { - self.cmpeq(*other).all() - } - } - - impl From<$vecn> for $inner { - #[inline(always)] - fn from(t: $vecn) -> Self { - t.0 - } - } - - impl From<$inner> for $vecn { - #[inline(always)] - fn from(t: $inner) -> Self { - Self(t) - } - } - - impl Div<$vecn> for $vecn { - type Output = Self; - #[inline(always)] - fn div(self, other: $vecn) -> Self { - Self(self.0.div(other.0)) - } - } - - impl DivAssign<$vecn> for $vecn { - #[inline(always)] - fn div_assign(&mut self, other: $vecn) { - self.0 = self.0.div(other.0) - } - } - - impl Div<$t> for $vecn { - type Output = Self; - #[inline(always)] - fn div(self, other: $t) -> Self { - Self(self.0.div_scalar(other)) - } - } - - impl DivAssign<$t> for $vecn { - #[inline(always)] - fn div_assign(&mut self, other: $t) { - self.0 = self.0.div_scalar(other) - } - } - - impl Div<$vecn> for $t { - type Output = $vecn; - #[inline(always)] - fn div(self, other: $vecn) -> $vecn { - $vecn($inner::splat(self).div(other.0)) - } - } - - impl Mul<$vecn> for $vecn { - type Output = Self; - #[inline(always)] - fn mul(self, other: $vecn) -> Self { - Self(self.0.mul(other.0)) - } - } - - impl MulAssign<$vecn> for $vecn { - #[inline(always)] - fn mul_assign(&mut self, other: $vecn) { - self.0 = self.0.mul(other.0) - } - } - - impl Mul<$t> for $vecn { - type Output = Self; - #[inline(always)] - fn mul(self, other: $t) -> Self { - Self(self.0.mul_scalar(other)) - } - } - - impl MulAssign<$t> for $vecn { - #[inline(always)] - fn mul_assign(&mut self, other: $t) { - self.0 = self.0.mul_scalar(other) - } - } - - impl Mul<$vecn> for $t { - type Output = $vecn; - #[inline(always)] - fn mul(self, other: $vecn) -> $vecn { - $vecn($inner::splat(self).mul(other.0)) - } - } - - impl Add<$vecn> for $vecn { - type Output = Self; - #[inline(always)] - fn add(self, other: $vecn) -> Self { - Self(self.0.add(other.0)) - } - } - - impl AddAssign<$vecn> for $vecn { - #[inline(always)] - fn add_assign(&mut self, other: $vecn) { - self.0 = self.0.add(other.0) - } - } - - impl Add<$t> for $vecn { - type Output = Self; - #[inline(always)] - fn add(self, other: $t) -> Self { - Self(self.0.add_scalar(other)) - } - } - - impl AddAssign<$t> for $vecn { - #[inline(always)] - fn add_assign(&mut self, other: $t) { - self.0 = self.0.add_scalar(other) - } - } - - impl Add<$vecn> for $t { - type Output = $vecn; - #[inline(always)] - fn add(self, other: $vecn) -> $vecn { - $vecn($inner::splat(self).add(other.0)) - } - } - - impl Sub<$vecn> for $vecn { - type Output = Self; - #[inline(always)] - fn sub(self, other: $vecn) -> Self { - Self(self.0.sub(other.0)) - } - } - - impl SubAssign<$vecn> for $vecn { - #[inline(always)] - fn sub_assign(&mut self, other: $vecn) { - self.0 = self.0.sub(other.0) - } - } - - impl Sub<$t> for $vecn { - type Output = Self; - #[inline(always)] - fn sub(self, other: $t) -> Self { - Self(self.0.sub_scalar(other)) - } - } - - impl SubAssign<$t> for $vecn { - #[inline(always)] - fn sub_assign(&mut self, other: $t) { - self.0 = self.0.sub_scalar(other) - } - } - - impl Sub<$vecn> for $t { - type Output = $vecn; - #[inline(always)] - fn sub(self, other: $vecn) -> $vecn { - $vecn($inner::splat(self).sub(other.0)) - } - } - - impl Rem<$vecn> for $vecn { - type Output = Self; - #[inline(always)] - fn rem(self, other: $vecn) -> Self { - Self(self.0.rem(other.0)) - } - } - - impl RemAssign<$vecn> for $vecn { - #[inline(always)] - fn rem_assign(&mut self, other: $vecn) { - self.0 = self.0.rem(other.0) - } - } - - impl Rem<$t> for $vecn { - type Output = Self; - #[inline(always)] - fn rem(self, other: $t) -> Self { - Self(self.0.rem_scalar(other)) - } - } - - impl RemAssign<$t> for $vecn { - #[inline(always)] - fn rem_assign(&mut self, other: $t) { - self.0 = self.0.rem_scalar(other) - } - } - - impl Rem<$vecn> for $t { - type Output = $vecn; - #[inline(always)] - fn rem(self, other: $vecn) -> $vecn { - $vecn($inner::splat(self).rem(other.0)) - } - } - - #[cfg(not(target_arch = "spirv"))] - impl AsRef<[$t; $size]> for $vecn { - #[inline(always)] - fn as_ref(&self) -> &[$t; $size] { - unsafe { &*(self as *const $vecn as *const [$t; $size]) } - } - } - - #[cfg(not(target_arch = "spirv"))] - impl AsMut<[$t; $size]> for $vecn { - #[inline(always)] - fn as_mut(&mut self) -> &mut [$t; $size] { - unsafe { &mut *(self as *mut $vecn as *mut [$t; $size]) } - } - } - - impl From<[$t; $size]> for $vecn { - #[inline(always)] - fn from(a: [$t; $size]) -> Self { - Self($trait::from_array(a)) - } - } - - impl From<$vecn> for [$t; $size] { - #[inline(always)] - fn from(v: $vecn) -> Self { - v.into_array() - } - } - - impl<'a> Sum<&'a Self> for $vecn { - #[inline] - fn sum(iter: I) -> Self - where - I: Iterator, - { - iter.fold(Self::ZERO, |a, &b| Self::add(a, b)) - } - } - - impl<'a> Product<&'a Self> for $vecn { - #[inline] - fn product(iter: I) -> Self - where - I: Iterator, - { - iter.fold(Self::ONE, |a, &b| Self::mul(a, b)) - } - } - }; -} - -macro_rules! impl_vecn_eq_hash_traits { - ($t:ty, $size:literal, $vecn:ident) => { - impl Eq for $vecn {} - - #[cfg(not(target_arch = "spirv"))] - impl core::hash::Hash for $vecn { - fn hash(&self, state: &mut H) { - let inner: &[$t; $size] = self.as_ref(); - inner.hash(state); - } - } - }; -} - -// Adds signed vector trait implementations. -// The traits here should be supported for signed types of $t and all sizes of vector. -macro_rules! impl_vecn_signed_traits { - ($t:ty, $size:literal, $vecn:ident, $inner:ident, $sgntrait:ident) => { - impl Neg for $vecn { - type Output = Self; - #[inline(always)] - fn neg(self) -> Self { - Self(self.0.neg()) - } - } - }; -} - -macro_rules! impl_vecn_shift_op_traits { - ($vecn:ident, $rhs:ty, $inner:ident) => { - impl Shl<$rhs> for $vecn { - type Output = Self; - - #[inline(always)] - fn shl(self, rhs: $rhs) -> Self::Output { - $vecn($inner::vector_shl(self.0, rhs.0)) - } - } - - impl Shr<$rhs> for $vecn { - type Output = Self; - - #[inline(always)] - fn shr(self, rhs: $rhs) -> Self::Output { - $vecn($inner::vector_shr(self.0, rhs.0)) - } - } - }; -} - -macro_rules! impl_vecn_scalar_shift_op_traits { - ($vecn:ident, $rhs:ty, $inner:ident) => { - impl Shl<$rhs> for $vecn { - type Output = Self; - - #[inline(always)] - fn shl(self, rhs: $rhs) -> Self::Output { - $vecn($inner::scalar_shl(self.0, rhs)) - } - } - - impl Shr<$rhs> for $vecn { - type Output = Self; - - #[inline(always)] - fn shr(self, rhs: $rhs) -> Self::Output { - $vecn($inner::scalar_shr(self.0, rhs)) - } - } - }; -} - -macro_rules! impl_vecn_bit_op_traits { - ($vecn:ident, $inner:ident) => { - impl Not for $vecn { - type Output = Self; - - #[inline(always)] - fn not(self) -> Self::Output { - $vecn($inner::not(self.0)) - } - } - - impl BitAnd for $vecn { - type Output = Self; - - #[inline(always)] - fn bitand(self, rhs: Self) -> Self::Output { - $vecn($inner::vector_bitand(self.0, rhs.0)) - } - } - - impl BitOr for $vecn { - type Output = Self; - - #[inline(always)] - fn bitor(self, rhs: Self) -> Self::Output { - $vecn($inner::vector_bitor(self.0, rhs.0)) - } - } - - impl BitXor for $vecn { - type Output = Self; - - #[inline(always)] - fn bitxor(self, rhs: Self) -> Self::Output { - $vecn($inner::vector_bitxor(self.0, rhs.0)) - } - } - }; -} - -macro_rules! impl_vecn_scalar_bit_op_traits { - ($vecn:ident, $rhs:ty, $inner:ident) => { - impl BitAnd<$rhs> for $vecn { - type Output = Self; - - #[inline(always)] - fn bitand(self, rhs: $rhs) -> Self::Output { - $vecn($inner::scalar_bitand(self.0, rhs)) - } - } - - impl BitOr<$rhs> for $vecn { - type Output = Self; - - #[inline(always)] - fn bitor(self, rhs: $rhs) -> Self::Output { - $vecn($inner::scalar_bitor(self.0, rhs)) - } - } - - impl BitXor<$rhs> for $vecn { - type Output = Self; - - #[inline(always)] - fn bitxor(self, rhs: $rhs) -> Self::Output { - $vecn($inner::scalar_bitxor(self.0, rhs)) - } - } - }; -} - -macro_rules! impl_as_vec2 { - () => { - /// Casts all elements of `self` to `f32`. - #[inline(always)] - pub fn as_vec2(&self) -> Vec2 { - Vec2::new(self.x as f32, self.y as f32) - } - }; -} - -macro_rules! impl_as_vec3 { - () => { - /// Casts all elements of `self` to `f32`. - #[inline(always)] - pub fn as_vec3(&self) -> Vec3 { - Vec3::new(self.x as f32, self.y as f32, self.z as f32) - } - - /// Casts all elements of `self` to `f32`. - #[inline(always)] - pub fn as_vec3a(&self) -> Vec3A { - Vec3A::new(self.x as f32, self.y as f32, self.z as f32) - } - }; -} - -macro_rules! impl_as_vec4 { - () => { - /// Casts all elements of `self` to `f32`. - #[inline(always)] - pub fn as_vec4(&self) -> Vec4 { - Vec4::new(self.x as f32, self.y as f32, self.z as f32, self.w as f32) - } - }; -} - -macro_rules! impl_as_dvec2 { - () => { - /// Casts all elements of `self` to `f64`. - #[inline(always)] - pub fn as_dvec2(&self) -> DVec2 { - DVec2::new(self.x as f64, self.y as f64) - } - }; -} - -macro_rules! impl_as_dvec3 { - () => { - /// Casts all elements of `self` to `f64`. - #[inline(always)] - pub fn as_dvec3(&self) -> DVec3 { - DVec3::new(self.x as f64, self.y as f64, self.z as f64) - } - }; -} - -macro_rules! impl_as_dvec4 { - () => { - /// Casts all elements of `self` to `f64`. - #[inline(always)] - pub fn as_dvec4(&self) -> DVec4 { - DVec4::new(self.x as f64, self.y as f64, self.z as f64, self.w as f64) - } - }; -} - -macro_rules! impl_as_ivec2 { - () => { - /// Casts all elements of `self` to `i32`. - #[inline(always)] - pub fn as_ivec2(&self) -> IVec2 { - IVec2::new(self.x as i32, self.y as i32) - } - }; -} - -macro_rules! impl_as_ivec3 { - () => { - /// Casts all elements of `self` to `i32`. - #[inline(always)] - pub fn as_ivec3(&self) -> IVec3 { - IVec3::new(self.x as i32, self.y as i32, self.z as i32) - } - }; -} - -macro_rules! impl_as_ivec4 { - () => { - /// Casts all elements of `self` to `i32`. - #[inline(always)] - pub fn as_ivec4(&self) -> IVec4 { - IVec4::new(self.x as i32, self.y as i32, self.z as i32, self.w as i32) - } - }; -} - -macro_rules! impl_as_uvec2 { - () => { - /// Casts all elements of `self` to `u32`. - #[inline(always)] - pub fn as_uvec2(&self) -> UVec2 { - UVec2::new(self.x as u32, self.y as u32) - } - }; -} - -macro_rules! impl_as_uvec3 { - () => { - /// Casts all elements of `self` to `u32`. - #[inline(always)] - pub fn as_uvec3(&self) -> UVec3 { - UVec3::new(self.x as u32, self.y as u32, self.z as u32) - } - }; -} - -macro_rules! impl_as_uvec4 { - () => { - /// Casts all elements of `self` to `u32`. - #[inline(always)] - pub fn as_uvec4(&self) -> UVec4 { - UVec4::new(self.x as u32, self.y as u32, self.z as u32, self.w as u32) - } - }; -} diff --git a/src/vec2.rs b/src/vec2.rs deleted file mode 100644 index 6d9004e0..00000000 --- a/src/vec2.rs +++ /dev/null @@ -1,334 +0,0 @@ -use crate::core::traits::vector::*; -use crate::{BVec2, DVec3, IVec3, UVec3, Vec3, XY}; -#[cfg(not(target_arch = "spirv"))] -use core::fmt; -use core::iter::{Product, Sum}; -use core::{f32, ops::*}; - -#[cfg(not(feature = "std"))] -use num_traits::Float; - -macro_rules! impl_vec2_common_methods { - ($t:ty, $vec2:ident, $vec3:ident, $mask:ident, $inner:ident) => { - /// All zeroes. - pub const ZERO: Self = Self($inner::ZERO); - - /// All ones. - pub const ONE: Self = Self($inner::ONE); - - /// `[1, 0]`: a unit-length vector pointing along the positive X axis. - pub const X: Self = Self($inner::X); - - /// `[0, 1]`: a unit-length vector pointing along the positive Y axis. - pub const Y: Self = Self($inner::Y); - - /// The unit axes. - pub const AXES: [Self; 2] = [Self::X, Self::Y]; - - /// Creates a new vector. - #[inline(always)] - pub fn new(x: $t, y: $t) -> $vec2 { - Self(Vector2::new(x, y)) - } - - /// Creates a 3D vector from `self` and the given `z` value. - #[inline(always)] - pub fn extend(self, z: $t) -> $vec3 { - $vec3::new(self.x, self.y, z) - } - - /// `[x, y]` - #[inline(always)] - pub fn to_array(&self) -> [$t; 2] { - [self.x, self.y] - } - - impl_vecn_common_methods!($t, $vec2, $mask, $inner, Vector2); - }; -} - -macro_rules! impl_vec2_signed_methods { - ($t:ty, $vec2:ident, $vec3:ident, $mask:ident, $inner:ident) => { - impl_vec2_common_methods!($t, $vec2, $vec3, $mask, $inner); - impl_vecn_signed_methods!($t, $vec2, $mask, $inner, SignedVector2); - - /// Returns a vector that is equal to `self` rotated by 90 degrees. - #[inline(always)] - pub fn perp(self) -> Self { - Self(self.0.perp()) - } - - /// The perpendicular dot product of `self` and `other`. - /// Also known as the wedge product, 2d cross product, and determinant. - #[doc(alias = "wedge")] - #[doc(alias = "cross")] - #[doc(alias = "determinant")] - #[inline(always)] - pub fn perp_dot(self, other: $vec2) -> $t { - self.0.perp_dot(other.0) - } - - /// Returns `other` rotated by the angle of `self`. If `self` is normalized, - /// then this just rotation. This is what you usually want. Otherwise, - /// it will be like a rotation with a multiplication by `self`'s length. - #[must_use] - #[inline(always)] - pub fn rotate(self, other: Self) -> Self { - Self(self.0.rotate(other.0)) - } - }; -} - -macro_rules! impl_vec2_float_methods { - ($t:ty, $vec2:ident, $vec3:ident, $mask:ident, $inner:ident) => { - impl_vec2_signed_methods!($t, $vec2, $vec3, $mask, $inner); - impl_vecn_float_methods!($t, $vec2, $mask, $inner, FloatVector2); - - /// Creates a 2D vector containing `[angle.cos(), angle.sin()]`. This can be used in - /// conjunction with the `rotate` method, e.g. `Vec2::from_angle(PI).rotate(Vec2::Y)` will - /// create the vector [-1, 0] and rotate `Vec2::Y` around it returning `-Vec2::Y`. - #[inline(always)] - pub fn from_angle(angle: $t) -> Self { - Self(FloatVector2::from_angle(angle)) - } - - /// Returns the angle (in radians) between `self` and `other`. - /// - /// The input vectors do not need to be unit length however they must be non-zero. - #[inline(always)] - pub fn angle_between(self, other: Self) -> $t { - self.0.angle_between(other.0) - } - }; -} - -macro_rules! impl_vec2_common_traits { - ($t:ty, $new:ident, $vec2:ident, $vec3:ident, $mask:ident, $inner:ident) => { - /// Creates a 2-dimensional vector. - #[inline(always)] - pub fn $new(x: $t, y: $t) -> $vec2 { - $vec2::new(x, y) - } - - impl Index for $vec2 { - type Output = $t; - #[inline(always)] - fn index(&self, index: usize) -> &Self::Output { - match index { - 0 => &self.x, - 1 => &self.y, - _ => panic!("index out of bounds"), - } - } - } - - impl IndexMut for $vec2 { - #[inline(always)] - fn index_mut(&mut self, index: usize) -> &mut Self::Output { - match index { - 0 => &mut self.x, - 1 => &mut self.y, - _ => panic!("index out of bounds"), - } - } - } - #[cfg(not(target_arch = "spirv"))] - impl fmt::Display for $vec2 { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "[{}, {}]", self.x, self.y) - } - } - - #[cfg(not(target_arch = "spirv"))] - impl fmt::Debug for $vec2 { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_tuple(stringify!($vec2)) - .field(&self.x) - .field(&self.y) - .finish() - } - } - - impl From<($t, $t)> for $vec2 { - #[inline(always)] - fn from(t: ($t, $t)) -> Self { - Self($inner::from_tuple(t)) - } - } - - impl From<$vec2> for ($t, $t) { - #[inline(always)] - fn from(v: $vec2) -> Self { - v.0.into_tuple() - } - } - - impl Deref for $vec2 { - type Target = XY<$t>; - #[inline(always)] - fn deref(&self) -> &Self::Target { - self.0.as_ref_xy() - } - } - - impl DerefMut for $vec2 { - #[inline(always)] - fn deref_mut(&mut self) -> &mut Self::Target { - self.0.as_mut_xy() - } - } - - impl_vecn_common_traits!($t, 2, $vec2, $inner, Vector2); - }; -} - -macro_rules! impl_vec2_unsigned_traits { - ($t:ty, $new:ident, $vec2:ident, $vec3:ident, $mask:ident, $inner:ident) => { - impl_vec2_common_traits!($t, $new, $vec2, $vec3, $mask, $inner); - }; -} - -macro_rules! impl_vec2_signed_traits { - ($t:ty, $new:ident, $vec2:ident, $vec3:ident, $mask:ident, $inner:ident) => { - impl_vec2_common_traits!($t, $new, $vec2, $vec3, $mask, $inner); - impl_vecn_signed_traits!($t, 2, $vec2, $inner, SignedVector2); - }; -} - -type XYF32 = XY; - -/// A 2-dimensional vector. -#[derive(Clone, Copy)] -#[cfg_attr(feature = "cuda", repr(C, align(8)))] -#[cfg_attr(not(feature = "cuda"), repr(transparent))] -pub struct Vec2(pub(crate) XYF32); - -impl Vec2 { - impl_vec2_float_methods!(f32, Vec2, Vec3, BVec2, XYF32); - impl_as_dvec2!(); - impl_as_ivec2!(); - impl_as_uvec2!(); -} -impl_vec2_signed_traits!(f32, vec2, Vec2, Vec3, BVec2, XYF32); - -type XYF64 = XY; - -/// A 2-dimensional vector. -#[derive(Clone, Copy)] -#[cfg_attr(feature = "cuda", repr(C, align(16)))] -#[cfg_attr(not(feature = "cuda"), repr(transparent))] -pub struct DVec2(pub(crate) XYF64); - -impl DVec2 { - impl_vec2_float_methods!(f64, DVec2, DVec3, BVec2, XYF64); - impl_as_vec2!(); - impl_as_ivec2!(); - impl_as_uvec2!(); -} -impl_vec2_signed_traits!(f64, dvec2, DVec2, DVec3, BVec2, XYF64); - -type XYI32 = XY; - -/// A 2-dimensional vector. -#[derive(Clone, Copy)] -#[cfg_attr(feature = "cuda", repr(C, align(8)))] -#[cfg_attr(not(feature = "cuda"), repr(transparent))] -pub struct IVec2(pub(crate) XYI32); - -impl IVec2 { - impl_vec2_signed_methods!(i32, IVec2, IVec3, BVec2, XYI32); - impl_as_vec2!(); - impl_as_dvec2!(); - impl_as_uvec2!(); -} -impl_vec2_signed_traits!(i32, ivec2, IVec2, IVec3, BVec2, XYI32); -impl_vecn_eq_hash_traits!(i32, 2, IVec2); - -impl_vecn_scalar_shift_op_traits!(IVec2, i8, XYI32); -impl_vecn_scalar_shift_op_traits!(IVec2, i16, XYI32); -impl_vecn_scalar_shift_op_traits!(IVec2, i32, XYI32); -impl_vecn_scalar_shift_op_traits!(IVec2, u8, XYI32); -impl_vecn_scalar_shift_op_traits!(IVec2, u16, XYI32); -impl_vecn_scalar_shift_op_traits!(IVec2, u32, XYI32); - -impl_vecn_shift_op_traits!(IVec2, IVec2, XYI32); -impl_vecn_shift_op_traits!(IVec2, UVec2, XYI32); - -impl_vecn_scalar_bit_op_traits!(IVec2, i32, XYI32); - -impl_vecn_bit_op_traits!(IVec2, XYI32); - -type XYU32 = XY; - -/// A 2-dimensional vector. -#[derive(Clone, Copy)] -#[cfg_attr(feature = "cuda", repr(C, align(8)))] -#[cfg_attr(not(feature = "cuda"), repr(transparent))] -pub struct UVec2(pub(crate) XYU32); - -impl UVec2 { - impl_vec2_common_methods!(u32, UVec2, UVec3, BVec2, XYU32); - impl_as_vec2!(); - impl_as_dvec2!(); - impl_as_ivec2!(); -} -impl_vec2_unsigned_traits!(u32, uvec2, UVec2, UVec3, BVec2, XYU32); -impl_vecn_eq_hash_traits!(u32, 2, UVec2); - -impl_vecn_scalar_shift_op_traits!(UVec2, i8, XYU32); -impl_vecn_scalar_shift_op_traits!(UVec2, i16, XYU32); -impl_vecn_scalar_shift_op_traits!(UVec2, i32, XYU32); -impl_vecn_scalar_shift_op_traits!(UVec2, u8, XYU32); -impl_vecn_scalar_shift_op_traits!(UVec2, u16, XYU32); -impl_vecn_scalar_shift_op_traits!(UVec2, u32, XYU32); - -impl_vecn_shift_op_traits!(UVec2, IVec2, XYU32); -impl_vecn_shift_op_traits!(UVec2, UVec2, XYU32); - -impl_vecn_scalar_bit_op_traits!(UVec2, u32, XYU32); - -impl_vecn_bit_op_traits!(UVec2, XYU32); - -mod const_test_vec2 { - #[cfg(not(feature = "cuda"))] - const_assert_eq!( - core::mem::align_of::(), - core::mem::align_of::() - ); - #[cfg(feature = "cuda")] - const_assert_eq!(8, core::mem::align_of::()); - const_assert_eq!(8, core::mem::size_of::()); -} - -mod const_test_dvec2 { - #[cfg(not(feature = "cuda"))] - const_assert_eq!( - core::mem::align_of::(), - core::mem::align_of::() - ); - #[cfg(feature = "cuda")] - const_assert_eq!(16, core::mem::align_of::()); - const_assert_eq!(16, core::mem::size_of::()); -} - -mod const_test_ivec2 { - #[cfg(not(feature = "cuda"))] - const_assert_eq!( - core::mem::align_of::(), - core::mem::align_of::() - ); - #[cfg(feature = "cuda")] - const_assert_eq!(8, core::mem::align_of::()); - const_assert_eq!(8, core::mem::size_of::()); -} - -mod const_test_uvec2 { - #[cfg(not(feature = "cuda"))] - const_assert_eq!( - core::mem::align_of::(), - core::mem::align_of::() - ); - #[cfg(feature = "cuda")] - const_assert_eq!(8, core::mem::align_of::()); - const_assert_eq!(8, core::mem::size_of::()); -} diff --git a/src/vec3.rs b/src/vec3.rs deleted file mode 100644 index 56978d3a..00000000 --- a/src/vec3.rs +++ /dev/null @@ -1,454 +0,0 @@ -use crate::core::traits::vector::*; -#[cfg(all( - any(target_feature = "sse2", target_feature = "simd128"), - not(feature = "scalar-math") -))] -use crate::BVec3A; -use crate::{BVec3, DVec2, DVec4, IVec2, IVec4, UVec2, UVec4, Vec2, Vec4, XYZ}; -#[cfg(not(target_arch = "spirv"))] -use core::fmt; -use core::iter::{Product, Sum}; -use core::{f32, ops::*}; - -#[cfg(not(feature = "std"))] -use num_traits::Float; - -#[cfg(all( - target_arch = "x86", - target_feature = "sse2", - not(feature = "scalar-math") -))] -use core::arch::x86::*; -#[cfg(all( - target_arch = "x86_64", - target_feature = "sse2", - not(feature = "scalar-math") -))] -use core::arch::x86_64::*; - -#[cfg(all(target_feature = "simd128", not(feature = "scalar-math")))] -use core::arch::wasm32::v128; - -macro_rules! impl_vec3_common_methods { - ($t:ty, $vec2:ident, $vec3:ident, $vec4:ident, $mask:ident, $inner:ident) => { - /// All zeroes. - pub const ZERO: Self = Self(VectorConst::ZERO); - - /// All ones. - pub const ONE: Self = Self(VectorConst::ONE); - - /// `[1, 0, 0]`: a unit-length vector pointing along the positive X axis. - pub const X: Self = Self(Vector3Const::X); - - /// `[0, 1, 0]`: a unit-length vector pointing along the positive Y axis. - pub const Y: Self = Self(Vector3Const::Y); - - /// `[0, 0, 1]`: a unit-length vector pointing along the positive Z axis. - pub const Z: Self = Self(Vector3Const::Z); - - /// The unit axes. - pub const AXES: [Self; 3] = [Self::X, Self::Y, Self::Z]; - - /// Creates a new 3D vector. - #[inline(always)] - pub fn new(x: $t, y: $t, z: $t) -> Self { - Self(Vector3::new(x, y, z)) - } - - /// Creates a 4D vector from `self` and the given `w` value. - #[inline(always)] - pub fn extend(self, w: $t) -> $vec4 { - // TODO: Optimize? - $vec4(Vector4::new(self.x, self.y, self.z, w)) - } - - /// Creates a `Vec2` from the `x` and `y` elements of `self`, discarding `z`. - /// - /// Truncation may also be performed by using `self.xy()` or `Vec2::from()`. - #[inline(always)] - pub fn truncate(self) -> $vec2 { - $vec2(Vector3::into_xy(self.0)) - } - - /// Returns the dot product result in all elements of the vector - #[inline(always)] - #[allow(dead_code)] - pub(crate) fn dot_as_vec3(self, other: Self) -> Self { - Self(Vector3::dot_into_vec(self.0, other.0)) - } - - /// Computes the cross product of `self` and `other`. - #[inline(always)] - pub fn cross(self, other: Self) -> Self { - Self(self.0.cross(other.0)) - } - - /// `[x, y, z]` - #[inline(always)] - pub fn to_array(&self) -> [$t; 3] { - [self.x, self.y, self.z] - } - - impl_vecn_common_methods!($t, $vec3, $mask, $inner, Vector3); - }; -} - -macro_rules! impl_vec3_common_traits { - ($t:ty, $new:ident, $vec2:ident, $vec3:ident, $vec4:ident, $inner:ident) => { - /// Creates a 3-dimensional vector. - #[inline(always)] - pub fn $new(x: $t, y: $t, z: $t) -> $vec3 { - $vec3::new(x, y, z) - } - - impl Index for $vec3 { - type Output = $t; - #[inline(always)] - fn index(&self, index: usize) -> &Self::Output { - match index { - 0 => &self.x, - 1 => &self.y, - 2 => &self.z, - _ => panic!("index out of bounds"), - } - } - } - - impl IndexMut for $vec3 { - #[inline(always)] - fn index_mut(&mut self, index: usize) -> &mut Self::Output { - match index { - 0 => &mut self.x, - 1 => &mut self.y, - 2 => &mut self.z, - _ => panic!("index out of bounds"), - } - } - } - - #[cfg(not(target_arch = "spirv"))] - impl fmt::Debug for $vec3 { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_tuple(stringify!($vec3)) - .field(&self.x) - .field(&self.y) - .field(&self.z) - .finish() - } - } - - #[cfg(not(target_arch = "spirv"))] - impl fmt::Display for $vec3 { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "[{}, {}, {}]", self.x, self.y, self.z) - } - } - - impl From<($vec2, $t)> for $vec3 { - #[inline(always)] - fn from((v, z): ($vec2, $t)) -> Self { - Self::new(v.x, v.y, z) - } - } - - impl From<($t, $t, $t)> for $vec3 { - #[inline(always)] - fn from(t: ($t, $t, $t)) -> Self { - Self(Vector3::from_tuple(t)) - } - } - - impl From<$vec3> for ($t, $t, $t) { - #[inline(always)] - fn from(v: $vec3) -> Self { - v.into_tuple() - } - } - - impl Deref for $vec3 { - type Target = XYZ<$t>; - #[inline(always)] - fn deref(&self) -> &Self::Target { - self.0.as_ref_xyz() - } - } - - impl DerefMut for $vec3 { - #[inline(always)] - fn deref_mut(&mut self) -> &mut Self::Target { - self.0.as_mut_xyz() - } - } - - impl_vecn_common_traits!($t, 3, $vec3, $inner, Vector3); - }; -} - -macro_rules! impl_vec3_signed_methods { - ($t:ty, $vec2:ident, $vec3:ident, $vec4:ident, $mask:ident, $inner:ident) => { - impl_vec3_common_methods!($t, $vec2, $vec3, $vec4, $mask, $inner); - impl_vecn_signed_methods!($t, $vec3, $mask, $inner, SignedVector3); - }; -} - -macro_rules! impl_vec3_float_methods { - ($t:ty, $vec2:ident, $vec3:ident, $vec4:ident, $mask:ident, $inner:ident) => { - impl_vec3_signed_methods!($t, $vec2, $vec3, $vec4, $mask, $inner); - impl_vecn_float_methods!($t, $vec3, $mask, $inner, FloatVector3); - - /// Returns the angle (in radians) between two vectors. - /// - /// The input vectors do not need to be unit length however they must be non-zero. - #[inline(always)] - pub fn angle_between(self, other: Self) -> $t { - self.0.angle_between(other.0) - } - - /// Returns some vector that is orthogonal to the given one. - /// - /// The input vector must be finite and non-zero. - /// - /// The output vector is not necessarily unit-length. - /// For that use [`Self::any_orthonormal_vector`] instead. - #[inline] - pub fn any_orthogonal_vector(&self) -> Self { - // This can probably be optimized - if self.x.abs() > self.y.abs() { - Self::new(-self.z, 0.0, self.x) // self.cross(Self::Y) - } else { - Self::new(0.0, self.z, -self.y) // self.cross(Self::X) - } - } - - /// Returns any unit-length vector that is orthogonal to the given one. - /// The input vector must be finite and non-zero. - /// - /// # Panics - /// - /// Will panic if `self` is not normalized when `glam_assert` is enabled. - #[inline] - pub fn any_orthonormal_vector(&self) -> Self { - glam_assert!(self.is_normalized()); - // From https://graphics.pixar.com/library/OrthonormalB/paper.pdf - #[cfg(feature = "std")] - let sign = (1.0 as $t).copysign(self.z); - #[cfg(not(feature = "std"))] - let sign = self.z.signum(); - let a = -1.0 / (sign + self.z); - let b = self.x * self.y * a; - Self::new(b, sign + self.y * self.y * a, -self.y) - } - - /// Given a unit-length vector return two other vectors that together form an orthonormal - /// basis. That is, all three vectors are orthogonal to each other and are normalized. - /// - /// # Panics - /// - /// Will panic if `self` is not normalized when `glam_assert` is enabled. - #[inline] - pub fn any_orthonormal_pair(&self) -> (Self, Self) { - glam_assert!(self.is_normalized()); - // From https://graphics.pixar.com/library/OrthonormalB/paper.pdf - #[cfg(feature = "std")] - let sign = (1.0 as $t).copysign(self.z); - #[cfg(not(feature = "std"))] - let sign = self.z.signum(); - let a = -1.0 / (sign + self.z); - let b = self.x * self.y * a; - ( - Self::new(1.0 + sign * self.x * self.x * a, sign * b, -sign * self.x), - Self::new(b, sign + self.y * self.y * a, -self.y), - ) - } - }; -} - -// implements traits that are common between `Vec3`, `Vec3A` and `Vec4` types. -macro_rules! impl_vec3_float_traits { - ($t:ty, $new:ident, $vec2:ident, $vec3:ident, $vec4:ident, $inner:ident) => { - impl_vec3_common_traits!($t, $new, $vec2, $vec3, $vec4, $inner); - impl_vecn_signed_traits!($t, 3, $vec3, $inner, SignedVector3); - }; -} - -// implements f32 functionality common between `Vec3` and `Vec3A` types. -macro_rules! impl_f32_vec3 { - ($new:ident, $vec2:ident, $vec3:ident, $vec4:ident, $mask:ident, $inner:ident) => { - impl $vec3 { - impl_vec3_float_methods!(f32, $vec2, $vec3, $vec4, $mask, $inner); - impl_as_dvec3!(); - impl_as_ivec3!(); - impl_as_uvec3!(); - } - impl_vec3_float_traits!(f32, $new, $vec2, $vec3, $vec4, $inner); - }; -} - -type XYZF32 = XYZ; - -/// A 3-dimensional vector without SIMD support. -#[derive(Clone, Copy)] -#[repr(transparent)] -pub struct Vec3(pub(crate) XYZF32); -impl_f32_vec3!(vec3, Vec2, Vec3, Vec4, BVec3, XYZF32); - -#[cfg(all(target_feature = "sse2", not(feature = "scalar-math")))] -type XYZF32A = __m128; -#[cfg(all(target_feature = "simd128", not(feature = "scalar-math")))] -type XYZF32A = v128; - -#[cfg(any( - not(any(target_feature = "sse2", target_feature = "simd128")), - feature = "scalar-math" -))] -type XYZF32A = crate::core::storage::XYZF32A16; - -/// A 3-dimensional vector with SIMD support. -/// -/// This type is 16 byte aligned. A SIMD vector type is used for storage on supported platforms for -/// better performance than the `Vec3` type. -/// -/// It is possible to convert between `Vec3` and `Vec3A` types using `From` trait implementations. -#[derive(Clone, Copy)] -#[repr(transparent)] -pub struct Vec3A(pub(crate) XYZF32A); - -#[cfg(all( - any(target_feature = "sse2", target_feature = "simd128"), - not(feature = "scalar-math") -))] -impl_f32_vec3!(vec3a, Vec2, Vec3A, Vec4, BVec3A, XYZF32A); - -#[cfg(any( - not(any(target_feature = "sse2", target_feature = "simd128")), - feature = "scalar-math" -))] -impl_f32_vec3!(vec3a, Vec2, Vec3A, Vec4, BVec3, XYZF32A); - -impl From for Vec3A { - #[inline(always)] - fn from(v: Vec3) -> Self { - Self(v.0.into()) - } -} - -impl From for Vec3 { - #[inline(always)] - fn from(v: Vec3A) -> Self { - Self(v.0.into()) - } -} - -type XYZF64 = XYZ; - -/// A 3-dimensional vector. -#[derive(Clone, Copy)] -#[repr(transparent)] -pub struct DVec3(pub(crate) XYZF64); - -impl DVec3 { - impl_vec3_float_methods!(f64, DVec2, DVec3, DVec4, BVec3, XYZF64); - impl_as_vec3!(); - impl_as_ivec3!(); - impl_as_uvec3!(); -} -impl_vec3_float_traits!(f64, dvec3, DVec2, DVec3, DVec4, XYZF64); - -type XYZI32 = XYZ; - -/// A 3-dimensional vector. -#[derive(Clone, Copy)] -#[repr(transparent)] -pub struct IVec3(pub(crate) XYZI32); - -impl IVec3 { - impl_vec3_common_methods!(i32, IVec2, IVec3, IVec4, BVec3, XYZI32); - impl_vecn_signed_methods!(i32, IVec3, BVec3, XYZI32, SignedVector3); - impl_as_vec3!(); - impl_as_dvec3!(); - impl_as_uvec3!(); -} -impl_vec3_common_traits!(i32, ivec3, IVec2, IVec3, IVec4, XYZI32); -impl_vecn_signed_traits!(i32, 3, IVec3, XYZI32, SignedVector3); -impl_vecn_eq_hash_traits!(i32, 3, IVec3); - -impl_vecn_scalar_shift_op_traits!(IVec3, i8, XYZI32); -impl_vecn_scalar_shift_op_traits!(IVec3, i16, XYZI32); -impl_vecn_scalar_shift_op_traits!(IVec3, i32, XYZI32); -impl_vecn_scalar_shift_op_traits!(IVec3, u8, XYZI32); -impl_vecn_scalar_shift_op_traits!(IVec3, u16, XYZI32); -impl_vecn_scalar_shift_op_traits!(IVec3, u32, XYZI32); - -impl_vecn_shift_op_traits!(IVec3, IVec3, XYZI32); -impl_vecn_shift_op_traits!(IVec3, UVec3, XYZI32); - -impl_vecn_scalar_bit_op_traits!(IVec3, i32, XYZI32); - -impl_vecn_bit_op_traits!(IVec3, XYZI32); - -type XYZU32 = XYZ; - -/// A 3-dimensional vector. -#[derive(Clone, Copy)] -#[repr(transparent)] -pub struct UVec3(pub(crate) XYZU32); - -impl UVec3 { - impl_vec3_common_methods!(u32, UVec2, UVec3, UVec4, BVec3, XYZU32); - impl_as_vec3!(); - impl_as_dvec3!(); - impl_as_ivec3!(); -} -impl_vec3_common_traits!(u32, uvec3, UVec2, UVec3, UVec4, XYZU32); -impl_vecn_eq_hash_traits!(u32, 3, UVec3); - -impl_vecn_scalar_shift_op_traits!(UVec3, i8, XYZU32); -impl_vecn_scalar_shift_op_traits!(UVec3, i16, XYZU32); -impl_vecn_scalar_shift_op_traits!(UVec3, i32, XYZU32); -impl_vecn_scalar_shift_op_traits!(UVec3, u8, XYZU32); -impl_vecn_scalar_shift_op_traits!(UVec3, u16, XYZU32); -impl_vecn_scalar_shift_op_traits!(UVec3, u32, XYZU32); - -impl_vecn_shift_op_traits!(UVec3, IVec3, XYZU32); -impl_vecn_shift_op_traits!(UVec3, UVec3, XYZU32); - -impl_vecn_scalar_bit_op_traits!(UVec3, u32, XYZU32); - -impl_vecn_bit_op_traits!(UVec3, XYZU32); - -mod const_test_vec3 { - const_assert_eq!( - core::mem::align_of::(), - core::mem::align_of::() - ); - const_assert_eq!(12, core::mem::size_of::()); -} - -mod const_test_vec3a { - const_assert_eq!(16, core::mem::align_of::()); - const_assert_eq!(16, core::mem::size_of::()); -} - -mod const_test_dvec3 { - const_assert_eq!( - core::mem::align_of::(), - core::mem::align_of::() - ); - const_assert_eq!(24, core::mem::size_of::()); -} - -mod const_test_ivec3 { - const_assert_eq!( - core::mem::align_of::(), - core::mem::align_of::() - ); - const_assert_eq!(12, core::mem::size_of::()); -} - -mod const_test_uvec3 { - const_assert_eq!( - core::mem::align_of::(), - core::mem::align_of::() - ); - const_assert_eq!(12, core::mem::size_of::()); -} diff --git a/src/vec4.rs b/src/vec4.rs deleted file mode 100644 index 9f12b895..00000000 --- a/src/vec4.rs +++ /dev/null @@ -1,434 +0,0 @@ -use crate::core::traits::vector::*; - -#[cfg(all( - any(target_feature = "sse2", target_feature = "simd128"), - not(feature = "scalar-math") -))] -use crate::BVec4A; -use crate::{BVec4, DVec2, DVec3, IVec2, IVec3, UVec2, UVec3, Vec2, Vec3, Vec3A, XYZW}; -use core::f32; -#[cfg(not(target_arch = "spirv"))] -use core::fmt; -use core::iter::{Product, Sum}; -use core::ops::*; - -#[cfg(not(feature = "std"))] -use num_traits::Float; - -#[cfg(all( - target_arch = "x86", - target_feature = "sse2", - not(feature = "scalar-math") -))] -use core::arch::x86::*; -#[cfg(all( - target_arch = "x86_64", - target_feature = "sse2", - not(feature = "scalar-math") -))] -use core::arch::x86_64::*; - -#[cfg(all(target_feature = "simd128", not(feature = "scalar-math")))] -use core::arch::wasm32::v128; - -macro_rules! impl_vec4_common_methods { - ($t:ty, $vec2:ident, $vec3:ident, $vec4:ident, $mask:ident, $inner:ident) => { - /// All zeroes. - pub const ZERO: Self = Self(VectorConst::ZERO); - - /// All ones. - pub const ONE: Self = Self(VectorConst::ONE); - - /// `[1, 0, 0, 0]`: a unit-length vector pointing along the positive X axis. - pub const X: Self = Self(Vector4Const::X); - - /// `[0, 1, 0, 0]`: a unit-length vector pointing along the positive Y axis. - pub const Y: Self = Self(Vector4Const::Y); - - /// `[0, 0, 1, 0]`: a unit-length vector pointing along the positive Z axis. - pub const Z: Self = Self(Vector4Const::Z); - - /// `[0, 0, 0, 1]`: a unit-length vector pointing along the positive W axis. - pub const W: Self = Self(Vector4Const::W); - - /// The unit axes. - pub const AXES: [Self; 4] = [Self::X, Self::Y, Self::Z, Self::W]; - - /// Creates a new 4D vector. - #[inline(always)] - pub fn new(x: $t, y: $t, z: $t, w: $t) -> Self { - Self(Vector4::new(x, y, z, w)) - } - - /// Creates a `Vec3` from the `x`, `y` and `z` elements of `self`, discarding `w`. - /// - /// Truncation to `Vec3` may also be performed by using `self.xyz()` or `Vec3::from()`. - /// - /// To truncate to `Vec3A` use `Vec3A::from()`. - #[inline(always)] - pub fn truncate(self) -> $vec3 { - $vec3::new(self.x, self.y, self.z) - } - - /// `[x, y, z, w]` - #[inline(always)] - pub fn to_array(&self) -> [$t; 4] { - [self.x, self.y, self.z, self.w] - } - - impl_vecn_common_methods!($t, $vec4, $mask, $inner, Vector4); - }; -} - -macro_rules! impl_vec4_common_traits { - ($t:ty, $new:ident, $vec2:ident, $vec3:ident, $vec4:ident, $mask:ident, $inner:ident) => { - /// Creates a 4-dimensional vector. - #[inline(always)] - pub fn $new(x: $t, y: $t, z: $t, w: $t) -> $vec4 { - $vec4::new(x, y, z, w) - } - - impl Index for $vec4 { - type Output = $t; - #[inline(always)] - fn index(&self, index: usize) -> &Self::Output { - match index { - 0 => &self.x, - 1 => &self.y, - 2 => &self.z, - 3 => &self.w, - _ => panic!("index out of bounds"), - } - } - } - - impl IndexMut for $vec4 { - #[inline(always)] - fn index_mut(&mut self, index: usize) -> &mut Self::Output { - match index { - 0 => &mut self.x, - 1 => &mut self.y, - 2 => &mut self.z, - 3 => &mut self.w, - _ => panic!("index out of bounds"), - } - } - } - - #[cfg(not(target_arch = "spirv"))] - impl fmt::Debug for $vec4 { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_tuple(stringify!($vec4)) - .field(&self.x) - .field(&self.y) - .field(&self.z) - .field(&self.w) - .finish() - } - } - - #[cfg(not(target_arch = "spirv"))] - impl fmt::Display for $vec4 { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(fmt, "[{}, {}, {}, {}]", self.x, self.y, self.z, self.w) - } - } - - impl From<($t, $t, $t, $t)> for $vec4 { - #[inline(always)] - fn from(t: ($t, $t, $t, $t)) -> Self { - Self(Vector4::from_tuple(t)) - } - } - - impl From<$vec4> for ($t, $t, $t, $t) { - #[inline(always)] - fn from(v: $vec4) -> Self { - Vector4::into_tuple(v.0) - } - } - - impl From<($vec3, $t)> for $vec4 { - #[inline(always)] - fn from((v, w): ($vec3, $t)) -> Self { - Self::new(v.x, v.y, v.z, w) - } - } - - impl From<($t, $vec3)> for $vec4 { - #[inline(always)] - fn from((x, v): ($t, $vec3)) -> Self { - Self::new(x, v.x, v.y, v.z) - } - } - - impl From<($vec2, $t, $t)> for $vec4 { - #[inline(always)] - fn from((v, z, w): ($vec2, $t, $t)) -> Self { - Self::new(v.x, v.y, z, w) - } - } - - impl From<($vec2, $vec2)> for $vec4 { - #[inline(always)] - fn from((v, u): ($vec2, $vec2)) -> Self { - Self::new(v.x, v.y, u.x, u.y) - } - } - - impl Deref for $vec4 { - type Target = XYZW<$t>; - #[inline(always)] - fn deref(&self) -> &Self::Target { - self.0.as_ref_xyzw() - } - } - - impl DerefMut for $vec4 { - #[inline(always)] - fn deref_mut(&mut self) -> &mut Self::Target { - self.0.as_mut_xyzw() - } - } - - impl_vecn_common_traits!($t, 4, $vec4, $inner, Vector4); - }; -} - -macro_rules! impl_vec4_signed_methods { - ($t:ty, $vec2:ident, $vec3:ident, $vec4:ident, $mask:ident, $inner:ident) => { - impl_vec4_common_methods!($t, $vec2, $vec3, $vec4, $mask, $inner); - impl_vecn_signed_methods!($t, $vec4, $mask, $inner, SignedVector4); - }; -} - -macro_rules! impl_vec4_signed_traits { - ($t:ty, $new:ident, $vec2:ident, $vec3:ident, $vec4:ident, $mask:ident, $inner:ident) => { - impl_vec4_common_traits!($t, $new, $vec2, $vec3, $vec4, $mask, $inner); - impl_vecn_signed_traits!($t, 4, $vec4, $inner, SignedVector4); - }; -} - -macro_rules! impl_vec4_float_methods { - ($t:ty, $vec2:ident, $vec3:ident, $vec4:ident, $mask:ident, $inner:ident) => { - impl_vec4_signed_methods!($t, $vec2, $vec3, $vec4, $mask, $inner); - impl_vecn_float_methods!($t, $vec4, $mask, $inner, FloatVector4); - }; -} - -// implement `Vec4` functionality -macro_rules! impl_f32_vec4 { - ($new:ident, $vec2:ident, $vec3:ident, $vec4:ident, $mask:ident, $inner:ident) => { - impl $vec4 { - impl_vec4_float_methods!(f32, $vec2, $vec3, $vec4, $mask, $inner); - impl_as_dvec4!(); - impl_as_ivec4!(); - impl_as_uvec4!(); - } - impl_vec4_signed_traits!(f32, $new, $vec2, $vec3, $vec4, $mask, $inner); - }; -} - -#[cfg(any( - not(any(target_feature = "sse2", target_feature = "simd128")), - feature = "scalar-math" -))] -type XYZWF32 = XYZW; - -#[cfg(all(target_feature = "sse2", not(feature = "scalar-math")))] -type XYZWF32 = __m128; - -#[cfg(all(target_feature = "simd128", not(feature = "scalar-math")))] -type XYZWF32 = v128; - -/// A 4-dimensional vector. -/// -/// This type uses 16 byte aligned SIMD vector type for storage on supported platforms. -#[derive(Clone, Copy)] -#[cfg_attr( - any( - not(any( - feature = "scalar-math", - target_arch = "spirv", - target_feature = "sse2", - target_feature = "simd128" - )), - feature = "cuda" - ), - repr(C, align(16)) -)] -#[cfg_attr( - all( - any( - feature = "scalar-math", - target_arch = "spirv", - target_feature = "sse2", - target_feature = "simd128" - ), - not(feature = "cuda") - ), - repr(transparent) -)] -pub struct Vec4(pub(crate) XYZWF32); - -#[cfg(any( - not(any(target_feature = "sse2", target_feature = "simd128")), - feature = "scalar-math" -))] -impl_f32_vec4!(vec4, Vec2, Vec3, Vec4, BVec4, XYZWF32); - -#[cfg(all( - any(target_feature = "sse2", target_feature = "simd128"), - not(feature = "scalar-math") -))] -impl_f32_vec4!(vec4, Vec2, Vec3, Vec4, BVec4A, XYZWF32); - -impl From for Vec3A { - /// Creates a `Vec3A` from the `x`, `y` and `z` elements of `self` discarding `w`. - /// - /// On architectures where SIMD is supported such as SSE2 on `x86_64` this conversion is a noop. - #[inline(always)] - fn from(v: Vec4) -> Self { - #[allow(clippy::useless_conversion)] - Self(v.0.into()) - } -} - -impl From<(Vec3A, f32)> for Vec4 { - #[inline(always)] - fn from((v, w): (Vec3A, f32)) -> Self { - v.extend(w) - } -} - -impl From<(f32, Vec3A)> for Vec4 { - #[inline(always)] - fn from((x, v): (f32, Vec3A)) -> Self { - Self::new(x, v.x, v.y, v.z) - } -} - -type XYZWF64 = XYZW; - -/// A 4-dimensional vector. -#[derive(Clone, Copy)] -#[cfg_attr(not(feature = "cuda"), repr(transparent))] -#[cfg_attr(feature = "cuda", repr(C, align(16)))] -pub struct DVec4(pub(crate) XYZWF64); - -impl DVec4 { - impl_vec4_float_methods!(f64, DVec2, DVec3, DVec4, BVec4, XYZWF64); - impl_as_vec4!(); - impl_as_ivec4!(); - impl_as_uvec4!(); -} -impl_vec4_signed_traits!(f64, dvec4, DVec2, DVec3, DVec4, BVec4, XYZWF64); - -type XYZWI32 = XYZW; - -/// A 4-dimensional vector. -#[derive(Clone, Copy)] -#[cfg_attr(not(feature = "cuda"), repr(transparent))] -#[cfg_attr(feature = "cuda", repr(C, align(16)))] -pub struct IVec4(pub(crate) XYZWI32); - -impl IVec4 { - impl_vec4_signed_methods!(i32, IVec2, IVec3, IVec4, BVec4, XYZWI32); - impl_as_vec4!(); - impl_as_dvec4!(); - impl_as_uvec4!(); -} -impl_vec4_signed_traits!(i32, ivec4, IVec2, IVec3, IVec4, BVec4, XYZWI32); -impl_vecn_eq_hash_traits!(i32, 4, IVec4); - -impl_vecn_scalar_shift_op_traits!(IVec4, i8, XYZWI32); -impl_vecn_scalar_shift_op_traits!(IVec4, i16, XYZWI32); -impl_vecn_scalar_shift_op_traits!(IVec4, i32, XYZWI32); -impl_vecn_scalar_shift_op_traits!(IVec4, u8, XYZWI32); -impl_vecn_scalar_shift_op_traits!(IVec4, u16, XYZWI32); -impl_vecn_scalar_shift_op_traits!(IVec4, u32, XYZWI32); - -impl_vecn_shift_op_traits!(IVec4, IVec4, XYZWI32); -impl_vecn_shift_op_traits!(IVec4, UVec4, XYZWI32); - -impl_vecn_scalar_bit_op_traits!(IVec4, i32, XYZWI32); - -impl_vecn_bit_op_traits!(IVec4, XYZWI32); - -type XYZWU32 = XYZW; - -/// A 4-dimensional vector. -#[derive(Clone, Copy)] -#[cfg_attr(not(feature = "cuda"), repr(transparent))] -#[cfg_attr(feature = "cuda", repr(C, align(16)))] -pub struct UVec4(pub(crate) XYZWU32); - -impl UVec4 { - impl_vec4_common_methods!(u32, UVec2, UVec3, UVec4, BVec4, XYZWU32); - impl_as_vec4!(); - impl_as_dvec4!(); - impl_as_ivec4!(); -} -impl_vec4_common_traits!(u32, uvec4, UVec2, UVec3, UVec4, BVec4, XYZWU32); -impl_vecn_eq_hash_traits!(u32, 4, UVec4); - -impl_vecn_scalar_shift_op_traits!(UVec4, i8, XYZWU32); -impl_vecn_scalar_shift_op_traits!(UVec4, i16, XYZWU32); -impl_vecn_scalar_shift_op_traits!(UVec4, i32, XYZWU32); -impl_vecn_scalar_shift_op_traits!(UVec4, u8, XYZWU32); -impl_vecn_scalar_shift_op_traits!(UVec4, u16, XYZWU32); -impl_vecn_scalar_shift_op_traits!(UVec4, u32, XYZWU32); - -impl_vecn_shift_op_traits!(UVec4, IVec4, XYZWU32); -impl_vecn_shift_op_traits!(UVec4, UVec4, XYZWU32); - -impl_vecn_scalar_bit_op_traits!(UVec4, u32, XYZWU32); - -impl_vecn_bit_op_traits!(UVec4, XYZWU32); - -mod const_test_vec4 { - #[cfg(all( - any(feature = "scalar-math", target_arch = "spirv"), - not(feature = "cuda") - ))] - const_assert_eq!( - core::mem::align_of::(), - core::mem::align_of::() - ); - #[cfg(not(any(feature = "scalar-math", target_arch = "spirv")))] - const_assert_eq!(16, core::mem::align_of::()); - const_assert_eq!(16, core::mem::size_of::()); -} - -mod const_test_dvec4 { - #[cfg(not(feature = "cuda"))] - const_assert_eq!( - core::mem::align_of::(), - core::mem::align_of::() - ); - #[cfg(feature = "cuda")] - const_assert_eq!(16, core::mem::align_of::()); - const_assert_eq!(32, core::mem::size_of::()); -} - -mod const_test_ivec4 { - #[cfg(not(feature = "cuda"))] - const_assert_eq!( - core::mem::align_of::(), - core::mem::align_of::() - ); - #[cfg(feature = "cuda")] - const_assert_eq!(16, core::mem::align_of::()); - const_assert_eq!(16, core::mem::size_of::()); -} - -mod const_test_uvec4 { - #[cfg(not(feature = "cuda"))] - const_assert_eq!( - core::mem::align_of::(), - core::mem::align_of::() - ); - #[cfg(feature = "cuda")] - const_assert_eq!(16, core::mem::align_of::()); - const_assert_eq!(16, core::mem::size_of::()); -} diff --git a/src/vec_mask.rs b/src/vec_mask.rs deleted file mode 100644 index 882ead35..00000000 --- a/src/vec_mask.rs +++ /dev/null @@ -1,460 +0,0 @@ -use crate::core::traits::vector::{ - MaskVector, MaskVector2, MaskVector3, MaskVector4, MaskVectorConst, -}; -#[cfg(not(target_arch = "spirv"))] -use core::fmt; -use core::{hash, ops::*}; - -#[cfg(all( - target_arch = "x86", - target_feature = "sse2", - not(feature = "scalar-math") -))] -use core::arch::x86::*; -#[cfg(all( - target_arch = "x86_64", - target_feature = "sse2", - not(feature = "scalar-math") -))] -use core::arch::x86_64::*; - -#[cfg(all(target_feature = "simd128", not(feature = "scalar-math")))] -use core::arch::wasm32::v128; - -macro_rules! impl_vecnmask_methods { - ($vecnmask:ident, $trait:ident) => { - /// Returns a bitmask with the lowest two bits set from the elements of `self`. - /// - /// A true element results in a `1` bit and a false element in a `0` bit. Element `x` goes - /// into the first lowest bit, element `y` into the second, etc. - #[inline] - pub fn bitmask(self) -> u32 { - $trait::bitmask(self.0) - } - - /// Returns true if any of the elements are true, false otherwise. - #[inline] - pub fn any(self) -> bool { - $trait::any(self.0) - } - - /// Returns true if all the elements are true, false otherwise. - #[inline] - pub fn all(self) -> bool { - $trait::all(self.0) - } - }; -} - -macro_rules! impl_vecnmask_traits { - ($vecnmask:ident, $inner:ident) => { - impl Default for $vecnmask { - #[inline] - fn default() -> Self { - Self($inner::FALSE) - } - } - - impl PartialEq for $vecnmask { - #[inline] - fn eq(&self, other: &Self) -> bool { - self.bitmask().eq(&other.bitmask()) - } - } - - impl Eq for $vecnmask {} - - impl hash::Hash for $vecnmask { - #[inline] - fn hash(&self, state: &mut H) { - self.bitmask().hash(state); - } - } - - impl BitAnd for $vecnmask { - type Output = Self; - #[inline] - fn bitand(self, other: Self) -> Self { - Self(MaskVector::bitand(self.0, other.0)) - } - } - - impl BitAndAssign for $vecnmask { - #[inline] - fn bitand_assign(&mut self, other: Self) { - self.0 = MaskVector::bitand(self.0, other.0); - } - } - - impl BitOr for $vecnmask { - type Output = Self; - #[inline] - fn bitor(self, other: Self) -> Self { - Self(MaskVector::bitor(self.0, other.0)) - } - } - - impl BitOrAssign for $vecnmask { - #[inline] - fn bitor_assign(&mut self, other: Self) { - self.0 = MaskVector::bitor(self.0, other.0); - } - } - - impl Not for $vecnmask { - type Output = Self; - #[inline] - fn not(self) -> Self { - Self(MaskVector::not(self.0)) - } - } - - impl From<$vecnmask> for $inner { - #[inline] - fn from(t: $vecnmask) -> Self { - t.0 - } - } - }; -} - -macro_rules! impl_vec2mask { - ($vec2mask:ident, $t:ty, $inner:ident) => { - impl $vec2mask { - /// Creates a new vector mask. - #[inline] - pub fn new(x: bool, y: bool) -> Self { - Self(MaskVector2::new(x, y)) - } - - impl_vecnmask_methods!($vec2mask, MaskVector2); - } - - impl_vecnmask_traits!($vec2mask, $inner); - - #[cfg(not(target_arch = "spirv"))] - impl fmt::Debug for $vec2mask { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let arr = self.0.into_u32_array(); - write!(f, "{}({:#x}, {:#x})", stringify!($vec2mask), arr[0], arr[1]) - } - } - - #[cfg(not(target_arch = "spirv"))] - impl fmt::Display for $vec2mask { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let arr = self.0.into_bool_array(); - write!(f, "[{}, {}]", arr[0], arr[1]) - } - } - - impl From<$vec2mask> for [bool; 2] { - #[inline] - fn from(mask: $vec2mask) -> Self { - mask.0.into_bool_array() - } - } - - impl From<$vec2mask> for [u32; 2] { - #[inline] - fn from(mask: $vec2mask) -> Self { - mask.0.into_u32_array() - } - } - - #[cfg(not(target_arch = "spirv"))] - impl AsRef<[$t; 2]> for $vec2mask { - #[inline] - fn as_ref(&self) -> &[$t; 2] { - unsafe { &*(self as *const Self as *const [$t; 2]) } - } - } - }; -} - -macro_rules! impl_vec3mask { - ($vec3mask:ident, $t:ty, $inner:ident) => { - impl $vec3mask { - /// Creates a new vector mask. - #[inline] - pub fn new(x: bool, y: bool, z: bool) -> Self { - Self(MaskVector3::new(x, y, z)) - } - - impl_vecnmask_methods!($vec3mask, MaskVector3); - } - - impl_vecnmask_traits!($vec3mask, $inner); - - #[cfg(not(target_arch = "spirv"))] - impl fmt::Debug for $vec3mask { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let arr = MaskVector3::into_u32_array(self.0); - write!( - f, - "{}({:#x}, {:#x}, {:#x})", - stringify!($vec3mask), - arr[0], - arr[1], - arr[2] - ) - } - } - - #[cfg(not(target_arch = "spirv"))] - impl fmt::Display for $vec3mask { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let arr = MaskVector3::into_bool_array(self.0); - write!(f, "[{}, {}, {}]", arr[0], arr[1], arr[2]) - } - } - - impl From<$vec3mask> for [bool; 3] { - #[inline] - fn from(mask: $vec3mask) -> Self { - MaskVector3::into_bool_array(mask.0) - } - } - - impl From<$vec3mask> for [u32; 3] { - #[inline] - fn from(mask: $vec3mask) -> Self { - MaskVector3::into_u32_array(mask.0) - } - } - - #[cfg(not(target_arch = "spirv"))] - impl AsRef<[$t; 3]> for $vec3mask { - #[inline] - fn as_ref(&self) -> &[$t; 3] { - unsafe { &*(self as *const Self as *const [$t; 3]) } - } - } - }; -} - -macro_rules! impl_vec4mask { - ($vec4mask:ident, $t:ty, $inner:ident) => { - impl $vec4mask { - /// Creates a new vector mask. - #[inline] - pub fn new(x: bool, y: bool, z: bool, w: bool) -> Self { - Self(MaskVector4::new(x, y, z, w)) - } - - impl_vecnmask_methods!($vec4mask, MaskVector4); - } - - impl_vecnmask_traits!($vec4mask, $inner); - - #[cfg(not(target_arch = "spirv"))] - impl fmt::Debug for $vec4mask { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let arr = MaskVector4::into_u32_array(self.0); - write!( - f, - "{}({:#x}, {:#x}, {:#x}, {:#x})", - stringify!($vec4mask), - arr[0], - arr[1], - arr[2], - arr[3] - ) - } - } - - #[cfg(not(target_arch = "spirv"))] - impl fmt::Display for $vec4mask { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let arr = MaskVector4::into_bool_array(self.0); - write!(f, "[{}, {}, {}, {}]", arr[0], arr[1], arr[2], arr[3]) - } - } - - impl From<$vec4mask> for [bool; 4] { - #[inline] - fn from(mask: $vec4mask) -> Self { - MaskVector4::into_bool_array(mask.0) - } - } - - impl From<$vec4mask> for [u32; 4] { - #[inline] - fn from(mask: $vec4mask) -> Self { - MaskVector4::into_u32_array(mask.0) - } - } - - #[cfg(not(target_arch = "spirv"))] - impl AsRef<[$t; 4]> for $vec4mask { - #[inline] - fn as_ref(&self) -> &[$t; 4] { - unsafe { &*(self as *const Self as *const [$t; 4]) } - } - } - }; -} - -// BVec3A ///////////////////////////////////////////////////////////////////////////////////////// - -#[cfg(all(target_feature = "sse2", not(feature = "scalar-math")))] -type Mask128 = __m128; -#[cfg(all(target_feature = "simd128", not(feature = "scalar-math")))] -type Mask128 = v128; - -/// A 3-dimensional SIMD vector mask. -/// -/// This type is 16 byte aligned and is backed by a SIMD vector. If SIMD is not available `BVec3A` -/// will be a type alias for `BVec3`. -#[cfg(all( - any(target_feature = "sse2", target_feature = "simd128"), - not(feature = "scalar-math") -))] -#[derive(Clone, Copy)] -#[repr(transparent)] -pub struct BVec3A(pub(crate) Mask128); - -#[cfg(all( - any(target_feature = "sse2", target_feature = "simd128"), - not(feature = "scalar-math") -))] -impl_vec3mask!(BVec3A, u32, Mask128); - -#[cfg(any( - not(any(target_feature = "sse2", target_feature = "simd128")), - feature = "scalar-math" -))] -pub type BVec3A = BVec3; - -#[cfg(all( - any(target_feature = "sse2", target_feature = "simd128"), - not(feature = "scalar-math") -))] -impl From for BVec3A { - #[inline] - fn from(b: BVec3) -> Self { - Self::new(b.0.x, b.0.y, b.0.z) - } -} - -#[cfg(all( - any(target_feature = "sse2", target_feature = "simd128"), - not(feature = "scalar-math") -))] -impl From for BVec3 { - #[inline] - fn from(b: BVec3A) -> Self { - let b: [bool; 3] = b.into(); - Self::new(b[0], b[1], b[2]) - } -} - -// BVec4A //////////////////////////////////////////////////////////////////////////////////////// - -/// A 4-dimensional SIMD vector mask. -/// -/// This type is 16 byte aligned and is backed by a SIMD vector. If SIMD is not available `BVec4A` -/// will be a type alias for `BVec4`. -#[cfg(all( - any(target_feature = "sse2", target_feature = "simd128"), - not(feature = "scalar-math") -))] -#[derive(Clone, Copy)] -#[repr(transparent)] -pub struct BVec4A(pub(crate) Mask128); - -#[cfg(all( - any(target_feature = "sse2", target_feature = "simd128"), - not(feature = "scalar-math") -))] -impl_vec4mask!(BVec4A, u32, Mask128); - -#[cfg(any( - not(any(target_feature = "sse2", target_feature = "simd128")), - feature = "scalar-math" -))] -pub type BVec4A = BVec4; - -#[cfg(all( - any(target_feature = "sse2", target_feature = "simd128"), - not(feature = "scalar-math") -))] -impl From for BVec4A { - #[inline] - fn from(b: BVec4) -> Self { - Self::new(b.0.x, b.0.y, b.0.z, b.0.w) - } -} - -#[cfg(all( - any(target_feature = "sse2", target_feature = "simd128"), - not(feature = "scalar-math") -))] -impl From for BVec4 { - #[inline] - fn from(b: BVec4A) -> Self { - let b: [bool; 4] = b.into(); - Self::new(b[0], b[1], b[2], b[3]) - } -} - -// boolean vectors //////////////////////////////////////////////////////////////////////////////// -type XYBool = crate::XY; - -/// A 2-dimensional boolean vector. -#[derive(Copy, Clone)] -#[repr(transparent)] -pub struct BVec2(pub(crate) XYBool); -impl_vec2mask!(BVec2, bool, XYBool); - -type XYZBool = crate::XYZ; - -/// A 3-dimensional boolean vector. -#[derive(Copy, Clone)] -#[repr(transparent)] -pub struct BVec3(pub(crate) XYZBool); -impl_vec3mask!(BVec3, bool, XYZBool); - -type XYZWBool = crate::XYZW; - -/// A 4-dimensional boolean vector. -#[derive(Copy, Clone)] -#[repr(transparent)] -pub struct BVec4(pub(crate) XYZWBool); -impl_vec4mask!(BVec4, bool, XYZWBool); - -mod const_test_bvec2 { - const_assert_eq!( - core::mem::align_of::(), - core::mem::align_of::() - ); - const_assert_eq!(2, core::mem::size_of::()); -} - -mod const_test_bvec3 { - const_assert_eq!( - core::mem::align_of::(), - core::mem::align_of::() - ); - const_assert_eq!(3, core::mem::size_of::()); -} - -#[cfg(all(target_feature = "sse2", not(feature = "scalar-math")))] -mod const_test_bvec3a { - const_assert_eq!(16, core::mem::align_of::()); - const_assert_eq!(16, core::mem::size_of::()); -} - -mod const_test_bvec4 { - const_assert_eq!( - core::mem::align_of::(), - core::mem::align_of::() - ); - const_assert_eq!(4, core::mem::size_of::()); -} - -#[cfg(all(target_feature = "sse2", not(feature = "scalar-math")))] -mod const_test_bvec4a { - const_assert_eq!(16, core::mem::align_of::()); - const_assert_eq!(16, core::mem::size_of::()); -} diff --git a/src/wasm32.rs b/src/wasm32.rs new file mode 100644 index 00000000..e5456e98 --- /dev/null +++ b/src/wasm32.rs @@ -0,0 +1,43 @@ +use core::arch::wasm32::*; + +/// Calculates the vector 3 dot product and returns answer in x lane of v128. +#[inline(always)] +pub(crate) fn dot3_in_x(lhs: v128, rhs: v128) -> v128 { + let x2_y2_z2_w2 = f32x4_mul(lhs, rhs); + let y2_0_0_0 = i32x4_shuffle::<1, 0, 0, 0>(x2_y2_z2_w2, x2_y2_z2_w2); + let z2_0_0_0 = i32x4_shuffle::<2, 0, 0, 0>(x2_y2_z2_w2, x2_y2_z2_w2); + let x2y2_0_0_0 = f32x4_add(x2_y2_z2_w2, y2_0_0_0); + f32x4_add(x2y2_0_0_0, z2_0_0_0) +} + +/// Calculates the vector 4 dot product and returns answer in x lane of v128. +#[inline(always)] +pub(crate) fn dot4_in_x(lhs: v128, rhs: v128) -> v128 { + let x2_y2_z2_w2 = f32x4_mul(lhs, rhs); + let z2_w2_0_0 = i32x4_shuffle::<2, 3, 0, 0>(x2_y2_z2_w2, x2_y2_z2_w2); + let x2z2_y2w2_0_0 = f32x4_add(x2_y2_z2_w2, z2_w2_0_0); + let y2w2_0_0_0 = i32x4_shuffle::<1, 0, 0, 0>(x2z2_y2w2_0_0, x2z2_y2w2_0_0); + f32x4_add(x2z2_y2w2_0_0, y2w2_0_0_0) +} + +#[inline] +pub(crate) fn dot3(lhs: v128, rhs: v128) -> f32 { + f32x4_extract_lane::<0>(dot3_in_x(lhs, rhs)) +} + +#[inline] +pub(crate) fn dot3_into_v128(lhs: v128, rhs: v128) -> v128 { + let dot_in_x = dot3_in_x(lhs, rhs); + i32x4_shuffle::<0, 0, 0, 0>(dot_in_x, dot_in_x) +} + +#[inline] +pub(crate) fn dot4(lhs: v128, rhs: v128) -> f32 { + f32x4_extract_lane::<0>(dot4_in_x(lhs, rhs)) +} + +#[inline] +pub(crate) fn dot4_into_v128(lhs: v128, rhs: v128) -> v128 { + let dot_in_x = dot4_in_x(lhs, rhs); + i32x4_shuffle::<0, 0, 0, 0>(dot_in_x, dot_in_x) +} diff --git a/swizzlegen/.gitignore b/swizzlegen/.gitignore deleted file mode 100644 index 2f7896d1..00000000 --- a/swizzlegen/.gitignore +++ /dev/null @@ -1 +0,0 @@ -target/ diff --git a/swizzlegen/Cargo.toml b/swizzlegen/Cargo.toml deleted file mode 100644 index 2dd35043..00000000 --- a/swizzlegen/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "swizzlegen" -version = "0.1.0" -authors = ["Cameron Hart "] -edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] diff --git a/swizzlegen/src/main.rs b/swizzlegen/src/main.rs deleted file mode 100644 index eb711d09..00000000 --- a/swizzlegen/src/main.rs +++ /dev/null @@ -1,948 +0,0 @@ -use std::fs::File; -use std::io::{Result, Write}; - -const E: [char; 4] = ['x', 'y', 'z', 'w']; // element name -const B: [&str; 4] = ["00", "01", "10", "11"]; // shuffle bits -const V: [&str; 4] = ["1", "2", "3", "4"]; // element value -const L: [&str; 4] = ["0", "1", "2", "3"]; // low index -const H: [&str; 4] = ["4", "5", "6", "7"]; // high index - -// const VEC4: &str = "Vec4"; -// const VEC3A: &str = "Vec3A"; -// const VEC3: &str = "Vec3"; -// const VEC2: &str = "Vec2"; - -fn write_swizzle_head(out: &mut impl Write) -> Result<()> { - writeln!(out, "// Generated by swizzlegen. Do not edit.")?; - Ok(()) -} - -fn write_loops_vec4(out: &mut W, size: usize, vec4fn: F4) -> Result<()> -where - W: Write, - F4: Fn(&mut W, usize, usize, usize, usize) -> Result<()>, -{ - for e0 in 0..size { - for e1 in 0..size { - for e2 in 0..size { - for e3 in 0..size { - if size == 4 && e0 == 0 && e1 == 1 && e2 == 2 && e3 == 3 { - continue; - } - vec4fn(out, e0, e1, e2, e3)?; - } - } - } - } - Ok(()) -} - -fn write_loops_vec3(out: &mut W, size: usize, vec3fn: F3) -> Result<()> -where - W: Write, - F3: Fn(&mut W, usize, usize, usize) -> Result<()>, -{ - for e0 in 0..size { - for e1 in 0..size { - for e2 in 0..size { - if size == 3 && e0 == 0 && e1 == 1 && e2 == 2 { - continue; - } - vec3fn(out, e0, e1, e2)?; - } - } - } - Ok(()) -} - -fn write_loops_vec2(out: &mut W, size: usize, vec2fn: F2) -> Result<()> -where - W: Write, - F2: Fn(&mut W, usize, usize) -> Result<()>, -{ - for e0 in 0..size { - for e1 in 0..size { - if size == 2 && e0 == 0 && e1 == 1 { - continue; - } - vec2fn(out, e0, e1)?; - } - } - Ok(()) -} - -fn write_loops( - out: &mut W, - size: usize, - vec4fn: F4, - vec3fn: F3, - vec2fn: F2, -) -> Result<()> -where - W: Write, - F4: Fn(&mut W, usize, usize, usize, usize) -> Result<()>, - F3: Fn(&mut W, usize, usize, usize) -> Result<()>, - F2: Fn(&mut W, usize, usize) -> Result<()>, -{ - write_loops_vec4(out, size, vec4fn)?; - write_loops_vec3(out, size, vec3fn)?; - write_loops_vec2(out, size, vec2fn)?; - Ok(()) -} - -fn write_swizzle_trait( - out: &mut impl Write, - size: usize, - vec4t: &str, - vec3t: &str, - vec2t: &str, -) -> Result<()> { - let t = match size { - 4 => vec4t, - 3 => vec3t, - 2 => vec2t, - _ => unreachable!(), - }; - - writeln!(out, r#"pub trait {}Swizzles: Sized + Copy + Clone {{"#, t)?; - - if size != 2 { - writeln!(out, r#" type Vec2;"#)?; - } - - if size != 3 { - writeln!(out, r#" type Vec3;"#)?; - } - - if size != 4 { - writeln!(out, r#" type Vec4;"#)?; - } - - match size { - 4 => { - writeln!( - out, - r#" - #[inline] - fn xyzw(self) -> Self {{ - self - }}"#, - )?; - } - 3 => { - writeln!( - out, - r#" - #[inline] - fn xyz(self) -> Self {{ - self - }}"#, - )?; - } - 2 => { - writeln!( - out, - r#" - #[inline] - fn xy(self) -> Self {{ - self - }}"#, - )?; - } - _ => unreachable!(), - } - - write_loops( - out, - size, - |out, e0, e1, e2, e3| { - write!( - out, - r#" - fn {}{}{}{}(self) -> {};"#, - E[e0], - E[e1], - E[e2], - E[e3], - if size == 4 { "Self" } else { "Self::Vec4" } - ) - }, - |out, e0, e1, e2| { - write!( - out, - r#" - fn {}{}{}(self) -> {};"#, - E[e0], - E[e1], - E[e2], - if size == 3 { "Self" } else { "Self::Vec3" } - ) - }, - |out, e0, e1| { - write!( - out, - r#" - fn {}{}(self) -> {};"#, - E[e0], - E[e1], - if size == 2 { "Self" } else { "Self::Vec2" } - ) - }, - )?; - - writeln!( - out, - r#" -}}"# - )?; - - Ok(()) -} - -fn write_vec4_impl_scalar( - out: &mut impl Write, - vec4t: &str, - vec3t: &str, - vec2t: &str, -) -> Result<()> { - const SIZE: usize = 4; - - write_swizzle_head(out)?; - - write!( - out, - r#" -use super::Vec4Swizzles; -use crate::{{{}, {}, {}}}; -"#, - vec2t, vec3t, vec4t, - )?; - - write!( - out, - r#" -impl Vec4Swizzles for {} {{ - type Vec2 = {}; - type Vec3 = {}; -"#, - vec4t, vec2t, vec3t, - )?; - - write_loops( - out, - SIZE, - |out, e0, e1, e2, e3| { - write!( - out, - r#" - #[inline] - fn {}{}{}{}(self) -> {} {{ - {}::new(self.{}, self.{}, self.{}, self.{}) - }}"#, - E[e0], E[e1], E[e2], E[e3], vec4t, vec4t, E[e0], E[e1], E[e2], E[e3], - ) - }, - |out, e0, e1, e2| { - write!( - out, - r#" - #[inline] - fn {}{}{}(self) -> {} {{ - {}::new(self.{}, self.{}, self.{}) - }}"#, - E[e0], E[e1], E[e2], vec3t, vec3t, E[e0], E[e1], E[e2] - ) - }, - |out, e0, e1| { - write!( - out, - r#" - #[inline] - fn {}{}(self) -> {} {{ - {}::new(self.{}, self.{}) - }}"#, - E[e0], E[e1], vec2t, vec2t, E[e0], E[e1] - ) - }, - )?; - - write!(out, "\n}}\n")?; - - Ok(()) -} - -fn write_vec4_impl_sse2(out: &mut impl Write) -> Result<()> { - const SIZE: usize = 4; - - write_swizzle_head(out)?; - - write!( - out, - r#" -use super::Vec4Swizzles; -use crate::{{Vec2, Vec3, Vec4, XY, XYZ}}; - -#[cfg(target_arch = "x86")] -use core::arch::x86::*; -#[cfg(target_arch = "x86_64")] -use core::arch::x86_64::*; -"# - )?; - - write!( - out, - r#" -impl Vec4Swizzles for Vec4 {{ - type Vec2 = Vec2; - type Vec3 = Vec3; -"#, - )?; - - write_loops( - out, - SIZE, - |out, e0, e1, e2, e3| { - write!( - out, - r#" - #[inline] - fn {}{}{}{}(self) -> Vec4 {{ - unsafe {{ Vec4(_mm_shuffle_ps(self.0, self.0, 0b{}_{}_{}_{})) }} - }}"#, - E[e0], E[e1], E[e2], E[e3], B[e3], B[e2], B[e1], B[e0], - ) - }, - |out, e0, e1, e2| { - write!( - out, - r#" - #[inline] - fn {}{}{}(self) -> Vec3 {{ - unsafe {{ Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_{}_{}_{}))) }} - }}"#, - E[e0], E[e1], E[e2], B[e2], B[e1], B[e0], - ) - }, - |out, e0, e1| { - write!( - out, - r#" - #[inline] - fn {}{}(self) -> Vec2 {{ - unsafe {{ Vec2(XY::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_{}_{}))) }} - }}"#, - E[e0], E[e1], B[e1], B[e0], - ) - }, - )?; - - write!(out, "\n}}\n")?; - - Ok(()) -} - -fn write_vec3a_impl_sse2(out: &mut impl Write) -> Result<()> { - const SIZE: usize = 3; - - write_swizzle_head(out)?; - - write!( - out, - r#" -use super::Vec3Swizzles; -use crate::{{Vec2, Vec3A, Vec4, XY}}; - -#[cfg(target_arch = "x86")] -use core::arch::x86::*; -#[cfg(target_arch = "x86_64")] -use core::arch::x86_64::*; -"# - )?; - - write!( - out, - r#" -impl Vec3Swizzles for Vec3A {{ - type Vec2 = Vec2; - type Vec4 = Vec4; -"# - )?; - - write_loops( - out, - SIZE, - |out, e0, e1, e2, e3| { - write!( - out, - r#" - #[inline] - fn {}{}{}{}(self) -> Vec4 {{ - unsafe {{ Vec4(_mm_shuffle_ps(self.0, self.0, 0b{}_{}_{}_{})) }} - }}"#, - E[e0], E[e1], E[e2], E[e3], B[e3], B[e2], B[e1], B[e0], - ) - }, - |out, e0, e1, e2| { - write!( - out, - r#" - #[inline] - fn {}{}{}(self) -> Self {{ - unsafe {{ Self(_mm_shuffle_ps(self.0, self.0, 0b00_{}_{}_{})) }} - }}"#, - E[e0], E[e1], E[e2], B[e2], B[e1], B[e0], - ) - }, - |out, e0, e1| { - write!( - out, - r#" - #[inline] - fn {}{}(self) -> Vec2 {{ - unsafe {{ Vec2(XY::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_{}_{}))) }} - }}"#, - E[e0], E[e1], B[e1], B[e0], - ) - }, - )?; - - write!(out, "\n}}\n")?; - - Ok(()) -} - -fn write_vec4_impl_wasm32(out: &mut impl Write) -> Result<()> { - const SIZE: usize = 4; - - write_swizzle_head(out)?; - - write!( - out, - r#" -use super::Vec4Swizzles; -use crate::{{Vec2, Vec3, Vec4, XY, XYZ}}; - -use core::arch::wasm32::*; -"# - )?; - - write!( - out, - r#" -impl Vec4Swizzles for Vec4 {{ - type Vec2 = Vec2; - type Vec3 = Vec3; -"#, - )?; - - write_loops( - out, - SIZE, - |out, e0, e1, e2, e3| { - write!( - out, - r#" - #[inline] - fn {}{}{}{}(self) -> Vec4 {{ - Vec4(i32x4_shuffle::<{}, {}, {}, {}>(self.0, self.0)) - }}"#, - E[e0], E[e1], E[e2], E[e3], L[e0], L[e1], H[e2], H[e3], - ) - }, - |out, e0, e1, e2| { - write!( - out, - r#" - #[inline] - fn {}{}{}(self) -> Vec3 {{ - Vec3(XYZ::from(i32x4_shuffle::<{}, {}, {}, {}>(self.0, self.0))) - }}"#, - E[e0], E[e1], E[e2], L[e0], L[e1], H[e2], H[0], - ) - }, - |out, e0, e1| { - write!( - out, - r#" - #[inline] - fn {}{}(self) -> Vec2 {{ - Vec2(XY::from(i32x4_shuffle::<{}, {}, {}, {}>(self.0, self.0))) - }}"#, - E[e0], E[e1], L[e0], L[e1], H[0], H[0], - ) - }, - )?; - - write!(out, "\n}}\n")?; - - Ok(()) -} - -fn write_vec3a_impl_wasm32(out: &mut impl Write) -> Result<()> { - const SIZE: usize = 3; - - write_swizzle_head(out)?; - - write!( - out, - r#" -use super::Vec3Swizzles; -use crate::{{Vec2, Vec3A, Vec4, XY}}; - -use core::arch::wasm32::*; -"# - )?; - - write!( - out, - r#" -impl Vec3Swizzles for Vec3A {{ - type Vec2 = Vec2; - type Vec4 = Vec4; -"# - )?; - - write_loops( - out, - SIZE, - |out, e0, e1, e2, e3| { - write!( - out, - r#" - #[inline] - fn {}{}{}{}(self) -> Vec4 {{ - Vec4(i32x4_shuffle::<{}, {}, {}, {}>(self.0, self.0)) - }}"#, - E[e0], E[e1], E[e2], E[e3], L[e0], L[e1], H[e2], H[e3], - ) - }, - |out, e0, e1, e2| { - write!( - out, - r#" - #[inline] - fn {}{}{}(self) -> Self {{ - Self(i32x4_shuffle::<{}, {}, {}, {}>(self.0, self.0)) - }}"#, - E[e0], E[e1], E[e2], L[e0], L[e1], H[e2], H[0], - ) - }, - |out, e0, e1| { - write!( - out, - r#" - #[inline] - fn {}{}(self) -> Vec2 {{ - Vec2(XY::from(i32x4_shuffle::<{}, {}, {}, {}>(self.0, self.0))) - }}"#, - E[e0], E[e1], L[e0], L[e1], H[0], H[0], - ) - }, - )?; - - write!(out, "\n}}\n")?; - - Ok(()) -} - -fn write_vec3_impl_scalar( - out: &mut impl Write, - vec4t: &str, - vec3t: &str, - vec2t: &str, -) -> Result<()> { - const SIZE: usize = 3; - - write_swizzle_head(out)?; - - write!( - out, - r#" -use super::Vec3Swizzles; -use crate::{{{}, {}, {}}}; -"#, - vec2t, vec3t, vec4t - )?; - - write!( - out, - r#" -impl Vec3Swizzles for {} {{ - type Vec2 = {}; - type Vec4 = {}; -"#, - vec3t, vec2t, vec4t, - )?; - - write_loops( - out, - SIZE, - |out, e0, e1, e2, e3| { - write!( - out, - r#" - #[inline] - fn {}{}{}{}(self) -> {} {{ - {}::new(self.{}, self.{}, self.{}, self.{}) - }}"#, - E[e0], E[e1], E[e2], E[e3], vec4t, vec4t, E[e0], E[e1], E[e2], E[e3], - ) - }, - |out, e0, e1, e2| { - write!( - out, - r#" - #[inline] - fn {}{}{}(self) -> Self {{ - Self::new(self.{}, self.{}, self.{}) - }}"#, - E[e0], E[e1], E[e2], E[e0], E[e1], E[e2] - ) - }, - |out, e0, e1| { - write!( - out, - r#" - #[inline] - fn {}{}(self) -> {} {{ - {}::new(self.{}, self.{}) - }}"#, - E[e0], E[e1], vec2t, vec2t, E[e0], E[e1] - ) - }, - )?; - - write!(out, "\n}}\n")?; - - Ok(()) -} - -fn write_vec2_impl_scalar( - out: &mut impl Write, - vec4t: &str, - vec3t: &str, - vec2t: &str, -) -> Result<()> { - const SIZE: usize = 2; - - write_swizzle_head(out)?; - - write!( - out, - r#" -use super::Vec2Swizzles; -use crate::{{{}, {}, {}}}; -"#, - vec2t, vec3t, vec4t, - )?; - - write!( - out, - r#" -impl Vec2Swizzles for {} {{ - type Vec3 = {}; - type Vec4 = {}; -"#, - vec2t, vec3t, vec4t, - )?; - - write_loops( - out, - SIZE, - |out, e0, e1, e2, e3| { - write!( - out, - r#" - #[inline] - fn {}{}{}{}(self) -> {} {{ - {}::new(self.{}, self.{}, self.{}, self.{}) - }}"#, - E[e0], E[e1], E[e2], E[e3], vec4t, vec4t, E[e0], E[e1], E[e2], E[e3], - ) - }, - |out, e0, e1, e2| { - write!( - out, - r#" - #[inline] - fn {}{}{}(self) -> {} {{ - {}::new(self.{}, self.{}, self.{}) - }}"#, - E[e0], E[e1], E[e2], vec3t, vec3t, E[e0], E[e1], E[e2] - ) - }, - |out, e0, e1| { - write!( - out, - r#" - #[inline] - fn {}{}(self) -> Self {{ - Self::new(self.{}, self.{}) - }}"#, - E[e0], E[e1], E[e0], E[e1] - ) - }, - )?; - - write!(out, "\n}}\n")?; - - Ok(()) -} - -fn write_swizzle_traits() -> Result<()> { - let mut out = File::create("../src/swizzles/vec_traits.rs")?; - write_swizzle_head(&mut out)?; - writeln!( - out, - r#"/** Swizzle methods for 2-dimensional vector types. */"# - )?; - write_swizzle_trait(&mut out, 2, "Vec4", "Vec3", "Vec2")?; - writeln!( - out, - r#"/** Swizzle methods for 3-dimensional vector types. */"# - )?; - write_swizzle_trait(&mut out, 3, "Vec4", "Vec3", "Vec2")?; - writeln!( - out, - r#"/** Swizzle methods for 4-dimensional vector types. */"# - )?; - write_swizzle_trait(&mut out, 4, "Vec4", "Vec3", "Vec2")?; - - Ok(()) -} - -fn write_swizzle_impls_f32() -> Result<()> { - let mut out = File::create("../src/swizzles/vec4_impl_scalar.rs")?; - write_vec4_impl_scalar(&mut out, "Vec4", "Vec3", "Vec2")?; - - let mut out = File::create("../src/swizzles/vec3_impl_scalar.rs")?; - write_vec3_impl_scalar(&mut out, "Vec4", "Vec3", "Vec2")?; - - let mut out = File::create("../src/swizzles/vec2_impl_scalar.rs")?; - write_vec2_impl_scalar(&mut out, "Vec4", "Vec3", "Vec2")?; - - let mut out = File::create("../src/swizzles/vec3a_impl_scalar.rs")?; - write_vec3_impl_scalar(&mut out, "Vec4", "Vec3A", "Vec2")?; - - let mut out = File::create("../src/swizzles/vec4_impl_sse2.rs")?; - write_vec4_impl_sse2(&mut out)?; - - let mut out = File::create("../src/swizzles/vec3a_impl_sse2.rs")?; - write_vec3a_impl_sse2(&mut out)?; - - let mut out = File::create("../src/swizzles/vec4_impl_wasm32.rs")?; - write_vec4_impl_wasm32(&mut out)?; - - let mut out = File::create("../src/swizzles/vec3a_impl_wasm32.rs")?; - write_vec3a_impl_wasm32(&mut out)?; - Ok(()) -} - -fn write_swizzle_impls_f64() -> Result<()> { - let mut out = File::create("../src/swizzles/dvec4_impl_scalar.rs")?; - write_vec4_impl_scalar(&mut out, "DVec4", "DVec3", "DVec2")?; - - let mut out = File::create("../src/swizzles/dvec3_impl_scalar.rs")?; - write_vec3_impl_scalar(&mut out, "DVec4", "DVec3", "DVec2")?; - - let mut out = File::create("../src/swizzles/dvec2_impl_scalar.rs")?; - write_vec2_impl_scalar(&mut out, "DVec4", "DVec3", "DVec2")?; - - Ok(()) -} - -fn write_swizzle_impls_i32() -> Result<()> { - let mut out = File::create("../src/swizzles/ivec4_impl_scalar.rs")?; - write_vec4_impl_scalar(&mut out, "IVec4", "IVec3", "IVec2")?; - - let mut out = File::create("../src/swizzles/ivec3_impl_scalar.rs")?; - write_vec3_impl_scalar(&mut out, "IVec4", "IVec3", "IVec2")?; - - let mut out = File::create("../src/swizzles/ivec2_impl_scalar.rs")?; - write_vec2_impl_scalar(&mut out, "IVec4", "IVec3", "IVec2")?; - - Ok(()) -} - -fn write_swizzle_impls_u32() -> Result<()> { - let mut out = File::create("../src/swizzles/uvec4_impl_scalar.rs")?; - write_vec4_impl_scalar(&mut out, "UVec4", "UVec3", "UVec2")?; - - let mut out = File::create("../src/swizzles/uvec3_impl_scalar.rs")?; - write_vec3_impl_scalar(&mut out, "UVec4", "UVec3", "UVec2")?; - - let mut out = File::create("../src/swizzles/uvec2_impl_scalar.rs")?; - write_vec2_impl_scalar(&mut out, "UVec4", "UVec3", "UVec2")?; - - Ok(()) -} - -fn write_test_vec4( - out: &mut impl Write, - t: &str, - vec4t: &str, - vec3t: &str, - vec2t: &str, -) -> Result<()> { - const SIZE: usize = 4; - - write!( - out, - r#" -glam_test!(test_{}_swizzles, {{ - let v = {}(1_{}, 2_{}, 3_{}, 4_{}); -"#, - vec4t, vec4t, t, t, t, t, - )?; - - writeln!(out, " assert_eq!(v, v.xyzw());")?; - - write_test_loops(out, SIZE, t, vec4t, vec3t, vec2t)?; - - writeln!(out, "}});")?; - - Ok(()) -} - -fn write_test_vec3( - out: &mut impl Write, - t: &str, - vec4t: &str, - vec3t: &str, - vec2t: &str, -) -> Result<()> { - const SIZE: usize = 3; - - write!( - out, - r#" -glam_test!(test_{}_swizzles, {{ - let v = {}(1_{}, 2_{}, 3_{}); -"#, - vec3t, vec3t, t, t, t, - )?; - - writeln!(out, " assert_eq!(v, v.xyz());")?; - - write_test_loops(out, SIZE, t, vec4t, vec3t, vec2t)?; - - writeln!(out, "}});")?; - - Ok(()) -} - -fn write_test_vec2( - out: &mut impl Write, - t: &str, - vec4t: &str, - vec3t: &str, - vec2t: &str, -) -> Result<()> { - const SIZE: usize = 2; - - write!( - out, - r#" -glam_test!(test_{}_swizzles, {{ - let v = {}(1_{}, 2_{}); -"#, - vec2t, vec2t, t, t, - )?; - - writeln!(out, " assert_eq!(v, v.xy());")?; - - write_test_loops(out, SIZE, t, vec4t, vec3t, vec2t)?; - - writeln!(out, "}});")?; - - Ok(()) -} - -fn write_test_loops( - out: &mut impl Write, - size: usize, - t: &str, - vec4t: &str, - vec3t: &str, - vec2t: &str, -) -> Result<()> { - write_loops_vec4(out, size, |out, e0, e1, e2, e3| { - writeln!( - out, - " assert_eq!(v.{}{}{}{}(), {}({}_{}, {}_{}, {}_{}, {}_{}));", - E[e0], E[e1], E[e2], E[e3], vec4t, V[e0], t, V[e1], t, V[e2], t, V[e3], t - ) - })?; - write_loops_vec3(out, size, |out, e0, e1, e2| { - writeln!( - out, - " assert_eq!(v.{}{}{}(), {}({}_{}, {}_{}, {}_{}));", - E[e0], E[e1], E[e2], vec3t, V[e0], t, V[e1], t, V[e2], t, - ) - })?; - write_loops_vec2(out, size, |out, e0, e1| { - writeln!( - out, - " assert_eq!(v.{}{}(), {}({}_{}, {}_{}));", - E[e0], E[e1], vec2t, V[e0], t, V[e1], t, - ) - })?; - Ok(()) -} - -fn write_swizzle_tests_preamble(filename: &str) -> Result { - let mut out = File::create(filename)?; - write_swizzle_head(&mut out)?; - writeln!( - &mut out, - r#"#[macro_use] -mod support; -use glam::*; -"# - )?; - Ok(out) -} - -fn write_swizzle_tests() -> Result<()> { - { - let mut out = write_swizzle_tests_preamble("../tests/swizzles_f32.rs")?; - write_test_vec4(&mut out, "f32", "vec4", "vec3", "vec2")?; - write_test_vec3(&mut out, "f32", "vec4", "vec3a", "vec2")?; - write_test_vec3(&mut out, "f32", "vec4", "vec3", "vec2")?; - write_test_vec2(&mut out, "f32", "vec4", "vec3", "vec2")?; - } - - // split f64 swizzle tests up so they don't exceed some wasm code size - { - let mut out = write_swizzle_tests_preamble("../tests/swizzles_f64.rs")?; - write_test_vec4(&mut out, "f64", "dvec4", "dvec3", "dvec2")?; - write_test_vec3(&mut out, "f64", "dvec4", "dvec3", "dvec2")?; - write_test_vec2(&mut out, "f64", "dvec4", "dvec3", "dvec2")?; - } - - { - let mut out = write_swizzle_tests_preamble("../tests/swizzles_i32.rs")?; - write_test_vec4(&mut out, "i32", "ivec4", "ivec3", "ivec2")?; - write_test_vec3(&mut out, "i32", "ivec4", "ivec3", "ivec2")?; - write_test_vec2(&mut out, "i32", "ivec4", "ivec3", "ivec2")?; - } - - { - let mut out = write_swizzle_tests_preamble("../tests/swizzles_u32.rs")?; - write_test_vec4(&mut out, "u32", "uvec4", "uvec3", "uvec2")?; - write_test_vec3(&mut out, "u32", "uvec4", "uvec3", "uvec2")?; - write_test_vec2(&mut out, "u32", "uvec4", "uvec3", "uvec2")?; - } - - Ok(()) -} - -fn main() -> Result<()> { - write_swizzle_traits()?; - write_swizzle_impls_f32()?; - write_swizzle_impls_f64()?; - write_swizzle_impls_i32()?; - write_swizzle_impls_u32()?; - write_swizzle_tests()?; - Ok(()) -} diff --git a/tests/affine2.rs b/tests/affine2.rs index 35424a1b..86280ed3 100644 --- a/tests/affine2.rs +++ b/tests/affine2.rs @@ -2,7 +2,8 @@ mod support; macro_rules! impl_affine2_tests { - ($t:ident, $affine2:ident, $vec2:ident) => { + ($t:ident, $affine2:ident, $vec2:ident, $mat2:ident, $mat3:ident) => { + const MATRIX1D: [$t; 6] = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0]; const MATRIX2D: [[$t; 2]; 3] = [[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]]; use core::$t::NAN; @@ -25,6 +26,53 @@ macro_rules! impl_affine2_tests { assert!(!$affine2::NAN.is_finite()); }); + glam_test!(test_affine2_from_cols, { + let a = $affine2::from_cols( + $vec2::from_array(MATRIX2D[0]), + $vec2::from_array(MATRIX2D[1]), + $vec2::from_array(MATRIX2D[2]), + ); + assert_eq!(MATRIX2D, a.to_cols_array_2d()); + + let a = $affine2::from_cols_array(&MATRIX1D); + assert_eq!(MATRIX1D, a.to_cols_array()); + + let a = $affine2::from_cols_array_2d(&MATRIX2D); + assert_eq!(MATRIX2D, a.to_cols_array_2d()); + }); + + glam_test!(test_affine2_deref, { + let a = $affine2::from_cols_array_2d(&MATRIX2D); + assert_eq!(MATRIX2D[0], a.x_axis.to_array()); + assert_eq!(MATRIX2D[1], a.y_axis.to_array()); + assert_eq!(MATRIX2D[2], a.z_axis.to_array()); + + let mut b = a; + b.x_axis *= 2.0; + b.y_axis *= 2.0; + b.z_axis *= 2.0; + assert_eq!(a * 2.0, b); + }); + + glam_test!(test_affine2_from_mat2, { + let m = $mat2::from_cols_array_2d(&[MATRIX2D[0], MATRIX2D[1]]); + let a = $affine2::from_mat2(m); + assert_eq!(m, a.matrix2); + assert_eq!($vec2::ZERO, a.translation); + + let t = $vec2::from_array(MATRIX2D[2]); + let a = $affine2::from_mat2_translation(m, t); + assert_eq!(MATRIX2D, a.to_cols_array_2d()); + }); + + glam_test!(test_affine2_from_mat3, { + let m = $mat3::from_cols_array_2d(&[[1.0, 2.0, 0.0], [3.0, 4.0, 0.0], [5.0, 6.0, 1.0]]); + let a = $affine2::from_mat3(m); + assert_eq!(MATRIX2D, a.to_cols_array_2d()); + + assert_eq!(m, $mat3::from(a)); + }); + glam_test!(test_affine2_translation, { let translate = $affine2::from_translation($vec2::new(1.0, 2.0)); assert_eq!(translate.translation, $vec2::new(1.0, 2.0).into()); @@ -39,6 +87,10 @@ macro_rules! impl_affine2_tests { let result3 = m.transform_vector2($vec2::Y); assert_approx_eq!($vec2::new(-1.0, 0.0), result3); + let m = $affine2::from_angle_translation(deg(90.0), $vec2::new(1.0, 2.0)); + let result3 = m.transform_vector2($vec2::Y); + assert_approx_eq!($vec2::new(-1.0, 0.0), result3, 1.0e-6); + let m = $affine2::from_scale_angle_translation( $vec2::new(0.5, 1.5), deg(90.0), @@ -104,6 +156,10 @@ macro_rules! impl_affine2_tests { assert_eq!($affine2::ZERO, m0 - m0); assert_approx_eq!(m0, m0 * $affine2::IDENTITY); assert_approx_eq!(m0, $affine2::IDENTITY * m0); + + let mat3 = $mat3::from(m0); + assert_approx_eq!(mat3, $affine2::IDENTITY * mat3); + assert_approx_eq!(mat3, mat3 * $affine2::IDENTITY); }); glam_test!(test_affine2_fmt, { @@ -112,7 +168,6 @@ macro_rules! impl_affine2_tests { }); glam_test!(test_affine2_to_from_slice, { - const MATRIX1D: [$t; 6] = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0]; let m = $affine2::from_cols_slice(&MATRIX1D); assert_eq!($affine2::from_cols_array(&MATRIX1D), m); assert_eq!(MATRIX1D, m.to_cols_array()); @@ -148,7 +203,7 @@ macro_rules! impl_affine2_tests { mod affine2 { use super::support::{deg, FloatCompare}; - use glam::{Affine2, Vec2}; + use glam::{Affine2, Mat2, Mat3, Vec2}; impl FloatCompare for Affine2 { #[inline] @@ -178,12 +233,12 @@ mod affine2 { } }); - impl_affine2_tests!(f32, Affine2, Vec2); + impl_affine2_tests!(f32, Affine2, Vec2, Mat2, Mat3); } mod daffine2 { use super::support::{deg, FloatCompare}; - use glam::{DAffine2, DVec2}; + use glam::{DAffine2, DMat2, DMat3, DVec2}; impl FloatCompare for DAffine2 { #[inline] @@ -213,5 +268,5 @@ mod daffine2 { assert_eq!(16, mem::align_of::()); }); - impl_affine2_tests!(f64, DAffine2, DVec2); + impl_affine2_tests!(f64, DAffine2, DVec2, DMat2, DMat3); } diff --git a/tests/affine3.rs b/tests/affine3.rs index 06fd7ca0..9e7f59fb 100644 --- a/tests/affine3.rs +++ b/tests/affine3.rs @@ -2,7 +2,10 @@ mod support; macro_rules! impl_affine3_tests { - ($t:ident, $affine3:ident, $quat:ident, $vec3:ident) => { + ($t:ident, $affine3:ident, $quat:ident, $vec3:ident, $mat3:ident, $mat4:ident) => { + const MATRIX1D: [$t; 12] = [ + 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, + ]; const MATRIX2D: [[$t; 3]; 4] = [ [1.0, 2.0, 3.0], [4.0, 5.0, 6.0], @@ -30,6 +33,61 @@ macro_rules! impl_affine3_tests { assert!(!$affine3::NAN.is_finite()); }); + glam_test!(test_affine3_from_cols, { + let a = $affine3::from_cols( + $vec3::from_array(MATRIX2D[0]).into(), + $vec3::from_array(MATRIX2D[1]).into(), + $vec3::from_array(MATRIX2D[2]).into(), + $vec3::from_array(MATRIX2D[3]).into(), + ); + assert_eq!(MATRIX2D, a.to_cols_array_2d()); + + let a = $affine3::from_cols_array(&MATRIX1D); + assert_eq!(MATRIX1D, a.to_cols_array()); + + let a = $affine3::from_cols_array_2d(&MATRIX2D); + assert_eq!(MATRIX2D, a.to_cols_array_2d()); + }); + + glam_test!(test_affine3_deref, { + let a = $affine3::from_cols_array_2d(&MATRIX2D); + assert_eq!(MATRIX2D[0], a.x_axis.to_array()); + assert_eq!(MATRIX2D[1], a.y_axis.to_array()); + assert_eq!(MATRIX2D[2], a.z_axis.to_array()); + assert_eq!(MATRIX2D[3], a.w_axis.to_array()); + + let mut b = a; + b.x_axis *= 2.0; + b.y_axis *= 2.0; + b.z_axis *= 2.0; + b.w_axis *= 2.0; + assert_eq!(a * 2.0, b); + }); + + glam_test!(test_affine3_from_mat3, { + let m = $mat3::from_cols_array_2d(&[MATRIX2D[0], MATRIX2D[1], MATRIX2D[2]]); + let a = $affine3::from_mat3(m); + assert_eq!(m, a.matrix3.into()); + assert_eq!($vec3::ZERO, a.translation.into()); + + let t = $vec3::from_array(MATRIX2D[3]); + let a = $affine3::from_mat3_translation(m, t); + assert_eq!(MATRIX2D, a.to_cols_array_2d()); + }); + + glam_test!(test_affine2_from_mat4, { + let m = $mat4::from_cols_array_2d(&[ + [1.0, 2.0, 3.0, 0.0], + [4.0, 5.0, 6.0, 0.0], + [7.0, 8.0, 9.0, 0.0], + [10.0, 11.0, 12.0, 1.0], + ]); + let a = $affine3::from_mat4(m); + assert_eq!(MATRIX2D, a.to_cols_array_2d()); + + assert_eq!(m, $mat4::from(a)); + }); + glam_test!(test_affine3_translation, { let translate = $affine3::from_translation($vec3::new(1.0, 2.0, 3.0)); assert_eq!(translate.translation, $vec3::new(1.0, 2.0, 3.0).into()); @@ -51,6 +109,23 @@ macro_rules! impl_affine3_tests { let rot_z2 = $affine3::from_axis_angle($vec3::Z, deg(180.0)); assert_approx_eq!(rot_z1, rot_z2, eps); + assert_approx_eq!( + $affine3::from_rotation_x(deg(180.0)), + $affine3::from_quat($quat::from_rotation_x(deg(180.0))) + ); + + assert_approx_eq!( + $quat::from_affine3(&$affine3::from_rotation_x(deg(180.0))), + $quat::from_rotation_x(deg(180.0)) + ); + + let m = $affine3::from_rotation_translation( + $quat::from_rotation_x(deg(90.0)), + $vec3::new(1.0, 2.0, 3.0), + ); + let result3 = m.transform_vector3($vec3::Y); + assert_approx_eq!($vec3::new(0.0, 0.0, 1.0), result3, 1.0e-6); + should_glam_assert!({ $affine3::from_axis_angle($vec3::ZERO, 0.0) }); should_glam_assert!({ $affine3::from_quat($quat::IDENTITY * 2.0) }); }); @@ -220,6 +295,10 @@ macro_rules! impl_affine3_tests { assert_eq!($affine3::ZERO, m0 - m0); assert_approx_eq!(m0, m0 * $affine3::IDENTITY); assert_approx_eq!(m0, $affine3::IDENTITY * m0); + + let mat4 = $mat4::from(m0); + assert_approx_eq!(mat4, $affine3::IDENTITY * mat4); + assert_approx_eq!(mat4, mat4 * $affine3::IDENTITY); }); glam_test!(test_affine3_fmt, { @@ -231,9 +310,6 @@ macro_rules! impl_affine3_tests { }); glam_test!(test_affine3_to_from_slice, { - const MATRIX1D: [$t; 12] = [ - 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, - ]; let m = $affine3::from_cols_slice(&MATRIX1D); assert_eq!($affine3::from_cols_array(&MATRIX1D), m); assert_eq!(MATRIX1D, m.to_cols_array()); @@ -274,7 +350,7 @@ macro_rules! impl_affine3_tests { mod affine3a { use super::support::{deg, FloatCompare}; - use glam::{Affine3A, Quat, Vec3, Vec3A}; + use glam::{Affine3A, Mat3, Mat4, Quat, Vec3, Vec3A}; impl FloatCompare for Affine3A { #[inline] @@ -313,12 +389,12 @@ mod affine3a { assert_approx_eq!(Vec3A::new(1.0, 2.0, 4.5), result3, 1.0e-6); }); - impl_affine3_tests!(f32, Affine3A, Quat, Vec3); + impl_affine3_tests!(f32, Affine3A, Quat, Vec3, Mat3, Mat4); } mod daffine3 { use super::support::{deg, FloatCompare}; - use glam::{DAffine3, DQuat, DVec3}; + use glam::{DAffine3, DMat3, DMat4, DQuat, DVec3}; impl FloatCompare for DAffine3 { #[inline] @@ -340,5 +416,5 @@ mod daffine3 { assert_eq!(mem::align_of::(), mem::align_of::()); }); - impl_affine3_tests!(f64, DAffine3, DQuat, DVec3); + impl_affine3_tests!(f64, DAffine3, DQuat, DVec3, DMat3, DMat4); } diff --git a/tests/euler.rs b/tests/euler.rs index f6cab9e9..3441d536 100644 --- a/tests/euler.rs +++ b/tests/euler.rs @@ -1,8 +1,6 @@ #[macro_use] mod support; -use glam::{DQuat, Quat}; - /// Helper to calculate the inner angle in the range [0, 2*PI) trait AngleDiff { type Output; @@ -47,41 +45,6 @@ macro_rules! assert_approx_angle { }}; } -trait EqApprox { - type EPS; - fn eq_approx(self, other: Self, axis_eps: Self::EPS, rot_axis: Self::EPS) -> bool; -} - -macro_rules! impl_eq_approx { - ($t:ty, $quat:ident, $pi:expr) => { - impl EqApprox for $quat { - type EPS = $t; - fn eq_approx(self, other: Self, axis_eps: Self::EPS, rot_axis: Self::EPS) -> bool { - let (s_axis, s_angle) = self.to_axis_angle(); - let (o_axis, o_angle) = other.to_axis_angle(); - if s_angle.abs() < rot_axis && o_angle.abs() < rot_axis { - // No rotation - true - } else { - let a = s_axis.angle_between(o_axis); - if a < axis_eps { - // Same axes - (s_angle - o_angle).abs() < rot_axis - } else if ($pi - a).abs() < axis_eps { - // Inverted axes (180°) - (s_angle + o_angle).abs() < rot_axis - } else { - // Other - false - } - } - } - } - }; -} -impl_eq_approx!(f32, Quat, std::f32::consts::PI); -impl_eq_approx!(f64, DQuat, std::f64::consts::PI); - #[macro_export] macro_rules! impl_3axis_test { ($name:ident, $t:ty, $quat:ident, $euler:path, $U:path, $V:path, $W:path, $vec:ident) => { diff --git a/tests/mat2.rs b/tests/mat2.rs index 860f25a3..6ba5d775 100644 --- a/tests/mat2.rs +++ b/tests/mat2.rs @@ -7,9 +7,24 @@ macro_rules! impl_mat2_tests { const MATRIX: [[$t; 2]; 2] = [[1.0, 2.0], [3.0, 4.0]]; + const MATRIX1D: [$t; 4] = [1.0, 2.0, 3.0, 4.0]; + glam_test!(test_const, { + const M0: $mat2 = $mat2::from_cols($newvec2(1.0, 2.0), $newvec2(3.0, 4.0)); + const M1: $mat2 = $mat2::from_cols_array(&MATRIX1D); + const M2: $mat2 = $mat2::from_cols_array_2d(&MATRIX); + + assert_eq!(MATRIX1D, M0.to_cols_array()); + assert_eq!(MATRIX1D, M1.to_cols_array()); + assert_eq!(MATRIX1D, M2.to_cols_array()); + }); + + glam_test!(test_const_macros, { + #[allow(deprecated)] const M0: $mat2 = $const_new!([0.0; 4]); + #[allow(deprecated)] const M1: $mat2 = $const_new!([1.0, 2.0, 3.0, 4.0]); + #[allow(deprecated)] const M2: $mat2 = $const_new!([1.0, 2.0], [3.0, 4.0]); assert_eq!($mat2::ZERO, M0); assert_eq!($mat2::from_cols_array(&[1.0, 2.0, 3.0, 4.0]), M1); @@ -23,6 +38,7 @@ macro_rules! impl_mat2_tests { assert_eq!($mat2::from_cols_array_2d(&IDENTITY), identity); assert_eq!(identity, identity * identity); assert_eq!(identity, $mat2::default()); + assert_eq!(identity, $mat2::from_diagonal($vec2::ONE)); }); glam_test!(test_mat2_zero, { @@ -186,7 +202,6 @@ macro_rules! impl_mat2_tests { }); glam_test!(test_mat2_to_from_slice, { - const MATRIX1D: [$t; 4] = [1.0, 2.0, 3.0, 4.0]; let m = $mat2::from_cols_slice(&MATRIX1D); assert_eq!($mat2::from_cols_array(&MATRIX1D), m); let mut out: [$t; 4] = Default::default(); @@ -219,8 +234,23 @@ macro_rules! impl_mat2_tests { }; } +macro_rules! impl_as_ref_tests { + ($mat:ident) => { + glam_test!(test_as_ref, { + let m = $mat::from_cols_array_2d(&MATRIX); + assert_eq!(MATRIX1D, *m.as_ref()); + }); + glam_test!(test_as_mut, { + let mut m = $mat::ZERO; + *m.as_mut() = MATRIX1D; + assert_eq!($mat::from_cols_array_2d(&MATRIX), m); + }); + }; +} + mod mat2 { use super::support::deg; + #[allow(deprecated)] use glam::{const_mat2, mat2, swizzles::*, vec2, Mat2, Mat3, Vec2}; glam_test!(test_align, { @@ -246,10 +276,12 @@ mod mat2 { }); impl_mat2_tests!(f32, const_mat2, mat2, Mat2, Mat3, vec2, Vec2); + impl_as_ref_tests!(Mat2); } mod dmat2 { use super::support::deg; + #[allow(deprecated)] use glam::{const_dmat2, dmat2, dvec2, swizzles::*, DMat2, DMat3, DVec2}; glam_test!(test_align, { @@ -259,4 +291,5 @@ mod dmat2 { }); impl_mat2_tests!(f64, const_dmat2, dmat2, DMat2, DMat3, dvec2, DVec2); + impl_as_ref_tests!(DMat2); } diff --git a/tests/mat3.rs b/tests/mat3.rs index 0f015df8..adfc28d8 100644 --- a/tests/mat3.rs +++ b/tests/mat3.rs @@ -11,9 +11,28 @@ macro_rules! impl_mat3_tests { const MATRIX: [[$t; 3]; 3] = [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]]; + const MATRIX1D: [$t; 9] = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]; + glam_test!(test_const, { + const M0: $mat3 = $mat3::from_cols( + $newvec3(1.0, 2.0, 3.0), + $newvec3(4.0, 5.0, 6.0), + $newvec3(7.0, 8.0, 9.0), + ); + const M1: $mat3 = $mat3::from_cols_array(&MATRIX1D); + const M2: $mat3 = $mat3::from_cols_array_2d(&MATRIX); + + assert_eq!(MATRIX1D, M0.to_cols_array()); + assert_eq!(MATRIX1D, M1.to_cols_array()); + assert_eq!(MATRIX1D, M2.to_cols_array()); + }); + + glam_test!(test_const_macros, { + #[allow(deprecated)] const M0: $mat3 = $const_new!([0.0; 9]); + #[allow(deprecated)] const M1: $mat3 = $const_new!([1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]); + #[allow(deprecated)] const M2: $mat3 = $const_new!([1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]); assert_eq!($mat3::ZERO, M0); assert_eq!( @@ -40,6 +59,7 @@ macro_rules! impl_mat3_tests { assert_eq!($mat3::from_cols_array_2d(&IDENTITY), identity); assert_eq!(identity, identity * identity); assert_eq!(identity, $mat3::default()); + assert_eq!(identity, $mat3::from_diagonal($vec3::ONE)); }); glam_test!(test_mat3_zero, { @@ -327,7 +347,6 @@ macro_rules! impl_mat3_tests { }); glam_test!(test_mat3_to_from_slice, { - const MATRIX1D: [$t; 9] = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]; let m = $mat3::from_cols_slice(&MATRIX1D); assert_eq!($mat3::from_cols_array(&MATRIX1D), m); let mut out: [$t; 9] = Default::default(); @@ -357,8 +376,23 @@ macro_rules! impl_mat3_tests { }; } +macro_rules! impl_as_ref_tests { + ($mat:ident) => { + glam_test!(test_as_ref, { + let m = $mat::from_cols_array_2d(&MATRIX); + assert_eq!(MATRIX1D, *m.as_ref()); + }); + glam_test!(test_as_mut, { + let mut m = $mat::ZERO; + *m.as_mut() = MATRIX1D; + assert_eq!($mat::from_cols_array_2d(&MATRIX), m); + }); + }; +} + mod mat3 { use super::support::deg; + #[allow(deprecated)] use glam::{ const_mat3, mat3, swizzles::*, vec3, vec3a, Mat2, Mat3, Mat4, Quat, Vec2, Vec3, Vec3A, }; @@ -388,10 +422,12 @@ mod mat3 { }); impl_mat3_tests!(f32, const_mat3, mat3, Mat3, Mat2, Mat4, Quat, vec3, Vec3, Vec2); + impl_as_ref_tests!(Mat3); } mod mat3a { use super::support::deg; + #[allow(deprecated)] use glam::{ const_mat3a, mat3a, swizzles::*, vec3a, Mat2, Mat3A, Mat4, Quat, Vec2, Vec3, Vec3A, }; @@ -432,6 +468,7 @@ mod mat3a { mod dmat3 { use super::support::deg; + #[allow(deprecated)] use glam::{const_dmat3, dmat3, dvec3, swizzles::*, DMat2, DMat3, DMat4, DQuat, DVec2, DVec3}; glam_test!(test_align, { @@ -452,4 +489,5 @@ mod dmat3 { DVec3, DVec2 ); + impl_as_ref_tests!(DMat3); } diff --git a/tests/mat4.rs b/tests/mat4.rs index 85d670d2..67836f59 100644 --- a/tests/mat4.rs +++ b/tests/mat4.rs @@ -20,12 +20,34 @@ macro_rules! impl_mat4_tests { [13.0, 14.0, 15.0, 16.0], ]; + const MATRIX1D: [$t; 16] = [ + 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, + ]; + glam_test!(test_const, { + const M0: $mat4 = $mat4::from_cols( + $newvec4(1.0, 2.0, 3.0, 4.0), + $newvec4(5.0, 6.0, 7.0, 8.0), + $newvec4(9.0, 10.0, 11.0, 12.0), + $newvec4(13.0, 14.0, 15.0, 16.0), + ); + const M1: $mat4 = $mat4::from_cols_array(&MATRIX1D); + const M2: $mat4 = $mat4::from_cols_array_2d(&MATRIX); + + assert_eq!(MATRIX1D, M0.to_cols_array()); + assert_eq!(MATRIX1D, M1.to_cols_array()); + assert_eq!(MATRIX1D, M2.to_cols_array()); + }); + + glam_test!(test_const_macros, { + #[allow(deprecated)] const M0: $mat4 = $const_new!([0.0; 16]); + #[allow(deprecated)] const M1: $mat4 = $const_new!([ 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0 ]); + #[allow(deprecated)] const M2: $mat4 = $const_new!( [1.0, 2.0, 3.0, 4.0], [5.0, 6.0, 7.0, 8.0], @@ -68,6 +90,7 @@ macro_rules! impl_mat4_tests { assert_eq!($mat4::from_cols_array_2d(&IDENTITY), identity); assert_eq!(identity, identity * identity); assert_eq!(identity, $mat4::default()); + assert_eq!(identity, $mat4::from_diagonal($vec4::ONE)); }); glam_test!(test_mat4_zero, { @@ -640,10 +663,6 @@ macro_rules! impl_mat4_tests { }); glam_test!(test_mat4_to_from_slice, { - const MATRIX1D: [$t; 16] = [ - 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, - 16.0, - ]; let m = $mat4::from_cols_slice(&MATRIX1D); assert_eq!($mat4::from_cols_array(&MATRIX1D), m); let mut out: [$t; 16] = Default::default(); @@ -673,8 +692,23 @@ macro_rules! impl_mat4_tests { }; } +macro_rules! impl_as_ref_tests { + ($mat:ident) => { + glam_test!(test_as_ref, { + let m = $mat::from_cols_array_2d(&MATRIX); + assert_eq!(MATRIX1D, *m.as_ref()); + }); + glam_test!(test_as_mut, { + let mut m = $mat::ZERO; + *m.as_mut() = MATRIX1D; + assert_eq!($mat::from_cols_array_2d(&MATRIX), m); + }); + }; +} + mod mat4 { use super::support::deg; + #[allow(deprecated)] use glam::{const_mat4, mat4, swizzles::*, vec3, vec4, Mat3, Mat4, Quat, Vec3, Vec4}; glam_test!(test_align, { @@ -718,10 +752,12 @@ mod mat4 { }); impl_mat4_tests!(f32, const_mat4, mat4, vec4, vec3, Mat4, Mat3, Quat, Vec4, Vec3); + impl_as_ref_tests!(Mat4); } mod dmat4 { use super::support::deg; + #[allow(deprecated)] use glam::{const_dmat4, dmat4, dvec3, dvec4, swizzles::*, DMat3, DMat4, DQuat, DVec3, DVec4}; glam_test!(test_align, { @@ -742,4 +778,5 @@ mod dmat4 { DVec4, DVec3 ); + impl_as_ref_tests!(DMat4); } diff --git a/tests/quat.rs b/tests/quat.rs index b76a1c0f..67a33841 100644 --- a/tests/quat.rs +++ b/tests/quat.rs @@ -8,8 +8,13 @@ macro_rules! impl_quat_tests { use core::$t::NEG_INFINITY; glam_test!(test_const, { - const Q: $quat = $const_new!([1.0, 2.0, 3.0, 4.0]); - assert_eq!($quat::from_xyzw(1.0, 2.0, 3.0, 4.0), Q); + const Q0: $quat = $quat::from_xyzw(1.0, 2.0, 3.0, 4.0); + const Q1: $quat = $quat::from_array([1.0, 2.0, 3.0, 4.0]); + #[allow(deprecated)] + const Q2: $quat = $const_new!([1.0, 2.0, 3.0, 4.0]); + assert_eq!([1.0, 2.0, 3.0, 4.0], *Q0.as_ref()); + assert_eq!([1.0, 2.0, 3.0, 4.0], *Q1.as_ref()); + assert_eq!([1.0, 2.0, 3.0, 4.0], *Q2.as_ref()); }); glam_test!(test_nan, { @@ -32,6 +37,8 @@ macro_rules! impl_quat_tests { assert_eq!([v1.x, v1.y, v1.z, v1.w], a1); assert_eq!(q1, $quat::from_array(a1)); + + assert_eq!(a1, *q0.as_ref()); }); glam_test!(test_funcs, { @@ -128,6 +135,10 @@ macro_rules! impl_quat_tests { assert_eq!(axis, $vec3::X); assert_eq!(angle, rad(0.0)); + let mut x0 = $quat::from_rotation_x(pitch); + x0 *= x0; + assert_approx_eq!(x0, $quat::from_rotation_x(pitch * 2.0)); + should_glam_assert!({ ($quat::IDENTITY * 2.0).inverse() }); should_glam_assert!({ $quat::from_axis_angle($vec3::ZERO, 0.0) }); }); @@ -501,6 +512,7 @@ macro_rules! impl_quat_tests { mod quat { use crate::support::{deg, rad}; use core::ops::Neg; + #[allow(deprecated)] use glam::{const_quat, quat, EulerRot, Mat3, Mat4, Quat, Vec2, Vec3, Vec3A, Vec4}; glam_test!(test_align, { @@ -592,6 +604,7 @@ mod quat { mod dquat { use crate::support::{deg, rad}; use core::ops::Neg; + #[allow(deprecated)] use glam::{const_dquat, dquat, DMat3, DMat4, DQuat, DVec2, DVec3, DVec4, EulerRot}; glam_test!(test_align, { diff --git a/tests/support.rs b/tests/support.rs index a2c56af9..08000e94 100644 --- a/tests/support.rs +++ b/tests/support.rs @@ -75,7 +75,7 @@ impl FloatCompare for f64 { impl FloatCompare for Mat2 { #[inline] fn approx_eq(&self, other: &Self, max_abs_diff: f32) -> bool { - self.abs_diff_eq(other, max_abs_diff) + self.abs_diff_eq(*other, max_abs_diff) } #[inline] fn abs_diff(&self, other: &Self) -> Self { @@ -89,7 +89,7 @@ impl FloatCompare for Mat2 { impl FloatCompare for DMat2 { #[inline] fn approx_eq(&self, other: &Self, max_abs_diff: f32) -> bool { - self.abs_diff_eq(other, max_abs_diff as f64) + self.abs_diff_eq(*other, max_abs_diff as f64) } #[inline] fn abs_diff(&self, other: &Self) -> Self { diff --git a/tests/transform.rs b/tests/transform.rs deleted file mode 100644 index e7f77152..00000000 --- a/tests/transform.rs +++ /dev/null @@ -1,129 +0,0 @@ -#![allow(deprecated)] - -#[cfg(feature = "transform-types")] -#[macro_use] -mod support; - -#[cfg(feature = "transform-types")] -mod transform { - use crate::support::FloatCompare; - use glam::*; - - impl FloatCompare for TransformSRT { - #[inline] - fn approx_eq(&self, other: &Self, max_abs_diff: f32) -> bool { - self.abs_diff_eq(*other, max_abs_diff) - } - - #[inline] - fn abs_diff(&self, other: &Self) -> Self { - Self::from_scale_rotation_translation( - self.scale.abs_diff(&other.scale), - self.rotation.abs_diff(&other.rotation), - self.translation.abs_diff(&other.translation), - ) - } - } - - impl FloatCompare for TransformRT { - #[inline] - fn approx_eq(&self, other: &Self, max_abs_diff: f32) -> bool { - self.abs_diff_eq(*other, max_abs_diff) - } - - #[inline] - fn abs_diff(&self, other: &Self) -> Self { - Self::from_rotation_translation( - self.rotation.abs_diff(&other.rotation), - self.translation.abs_diff(&other.translation), - ) - } - } - - #[test] - fn test_identity() { - let tr = TransformRT::IDENTITY; - assert_eq!(tr.rotation, Quat::IDENTITY); - assert_eq!(tr.translation, Vec3::ZERO); - - let srt = TransformSRT::IDENTITY; - assert_eq!(srt.scale, Vec3::ONE); - assert_eq!(srt.rotation, Quat::IDENTITY); - assert_eq!(srt.translation, Vec3::ZERO); - - assert_eq!(srt, tr.into()); - - assert_eq!(TransformRT::IDENTITY, TransformRT::default()); - assert_eq!(TransformSRT::IDENTITY, TransformSRT::default()); - } - - #[test] - fn test_nan() { - assert!(TransformRT::NAN.is_nan()); - assert!(!TransformRT::NAN.is_finite()); - - assert!(TransformSRT::NAN.is_nan()); - assert!(!TransformSRT::NAN.is_finite()); - } - - #[test] - fn test_new() { - let t = Vec3::new(1.0, 2.0, 3.0); - let r = Quat::from_rotation_y(90.0_f32.to_radians()); - let s = Vec3::new(-1.0, -2.0, -3.0); - - let tr = TransformRT::from_rotation_translation(r, t); - assert_eq!(tr.rotation, r); - assert_eq!(tr.translation, t); - - let srt = TransformSRT::from_scale_rotation_translation(s, r, t); - assert_eq!(srt.scale, s); - assert_eq!(srt.rotation, r); - assert_eq!(srt.translation, t); - - assert_eq!(tr, tr); - assert_eq!(srt, srt); - } - - #[test] - fn test_mul() { - let tr = TransformRT::from_rotation_translation( - Quat::from_rotation_z(-90.0_f32.to_radians()), - Vec3::X, - ); - let v0 = Vec3A::Y; - let v1 = tr.transform_point3a(v0); - assert_approx_eq!(v1, Vec3A::X * 2.0); - assert_approx_eq!(v1, tr.transform_point3a(v0)); - let inv_tr = tr.inverse(); - let v2 = inv_tr.transform_point3a(v1); - assert_approx_eq!(v0, v2); - - assert_eq!(tr * TransformRT::IDENTITY, tr); - assert_approx_eq!(tr * inv_tr, TransformRT::IDENTITY); - - assert_eq!(tr * TransformSRT::IDENTITY, TransformSRT::from(tr)); - assert_eq!(TransformSRT::IDENTITY * tr, TransformSRT::from(tr)); - - let s = Vec3::splat(2.0); - let r = Quat::from_rotation_y(180.0_f32.to_radians()); - let t = -Vec3::Y; - let srt = TransformSRT::from_scale_rotation_translation(s, r, t); - let v0 = Vec3A::X; - let v1 = srt.transform_point3a(v0); - assert_approx_eq!(v1, (r * (v0 * Vec3A::from(s))) + Vec3A::from(t)); - assert_approx_eq!(v1, srt.transform_point3a(v0)); - let inv_srt = srt.inverse(); - let v2 = inv_srt.transform_point3a(v1); - assert_approx_eq!(v0, v2); - - assert_eq!(srt * TransformSRT::IDENTITY, srt); - assert_eq!(srt * inv_srt, TransformSRT::IDENTITY); - - // negative scale mul test - let s = Vec3::splat(-2.0); - let srt = TransformSRT::from_scale_rotation_translation(s, r, t); - let inv_srt = srt.inverse(); - assert_eq!(srt * inv_srt, TransformSRT::IDENTITY); - } -} diff --git a/tests/vec2.rs b/tests/vec2.rs index 99377aab..47f4c10f 100644 --- a/tests/vec2.rs +++ b/tests/vec2.rs @@ -4,8 +4,15 @@ mod support; macro_rules! impl_vec2_tests { ($t:ty, $const_new:ident, $new:ident, $vec2:ident, $vec3:ident, $mask:ident) => { glam_test!(test_const, { - const V: $vec2 = $const_new!([1 as $t, 2 as $t]); - assert_eq!($vec2::new(1 as $t, 2 as $t), V); + const V0: $vec2 = $vec2::splat(1 as $t); + const V1: $vec2 = $vec2::new(1 as $t, 2 as $t); + const V2: $vec2 = $vec2::from_array([1 as $t, 2 as $t]); + #[allow(deprecated)] + const V3: $vec2 = $const_new!([1 as $t, 2 as $t]); + assert_eq!([1 as $t, 1 as $t], *V0.as_ref()); + assert_eq!([1 as $t, 2 as $t], *V1.as_ref()); + assert_eq!([1 as $t, 2 as $t], *V2.as_ref()); + assert_eq!([1 as $t, 2 as $t], *V3.as_ref()); }); glam_test!(test_new, { @@ -23,6 +30,13 @@ macro_rules! impl_vec2_tests { let a1: [$t; 2] = v.into(); assert_eq!(a, a1); + assert_eq!(a, v.to_array()); + assert_eq!(a, *v.as_ref()); + + let mut v2 = $vec2::default(); + *v2.as_mut() = a; + assert_eq!(a, v2.to_array()); + let v = $vec2::new(t.0, t.1); assert_eq!(t, v.into()); @@ -36,7 +50,15 @@ macro_rules! impl_vec2_tests { format!("{:?}", a), format!("{}({:?}, {:?})", stringify!($vec2), a.x, a.y) ); - // assert_eq!(format!("{:#?}", a), "$vec2(\n 1.0,\n 2.0\n)"); + assert_eq!( + format!("{:#?}", a), + format!( + "{}(\n {:#?},\n {:#?},\n)", + stringify!($vec2), + a.x, + a.y + ) + ); assert_eq!(format!("{}", a), "[1, 2]"); }); @@ -77,7 +99,9 @@ macro_rules! impl_vec2_tests { glam_test!(test_ops, { let a = $new(2 as $t, 4 as $t); assert_eq!($new(4 as $t, 8 as $t), (a + a)); + assert_eq!($new(2 as $t, 4 as $t), 0 as $t + a); assert_eq!($new(0 as $t, 0 as $t), (a - a)); + assert_eq!($new(14 as $t, 12 as $t), 16 as $t - a); assert_eq!($new(4 as $t, 16 as $t), (a * a)); assert_eq!($new(4 as $t, 8 as $t), (a * 2 as $t)); assert_eq!($new(4 as $t, 8 as $t), (2 as $t * a)); @@ -95,6 +119,19 @@ macro_rules! impl_vec2_tests { glam_test!(test_assign_ops, { let a = $new(1 as $t, 2 as $t); let mut b = a; + + b += 2 as $t; + assert_eq!($new(3 as $t, 4 as $t), b); + b -= 2 as $t; + assert_eq!($new(1 as $t, 2 as $t), b); + b *= 2 as $t; + assert_eq!($new(2 as $t, 4 as $t), b); + b /= 2 as $t; + assert_eq!($new(1 as $t, 2 as $t), b); + b %= 2 as $t; + assert_eq!($new(1 as $t, 0 as $t), b); + + b = a; b += a; assert_eq!($new(2 as $t, 4 as $t), b); b -= a; @@ -196,21 +233,32 @@ macro_rules! impl_vec2_tests { assert!(b.cmpeq($vec2::splat(1 as $t)).all()); }); - // #[test] - // fn test_mask_as_ref() { - // assert_eq!($mask::new(false, false).as_ref(), &[0, 0]); - // assert_eq!($mask::new(true, false).as_ref(), &[!0, 0]); - // assert_eq!($mask::new(false, true).as_ref(), &[0, !0]); - // assert_eq!($mask::new(true, true).as_ref(), &[!0, !0]); - // } - - glam_test!(test_mask_from, { + glam_test!(test_mask_into_array_u32, { assert_eq!(Into::<[u32; 2]>::into($mask::new(false, false)), [0, 0]); assert_eq!(Into::<[u32; 2]>::into($mask::new(true, false)), [!0, 0]); assert_eq!(Into::<[u32; 2]>::into($mask::new(false, true)), [0, !0]); assert_eq!(Into::<[u32; 2]>::into($mask::new(true, true)), [!0, !0]); }); + glam_test!(test_mask_into_array_bool, { + assert_eq!( + Into::<[bool; 2]>::into($mask::new(false, false)), + [false, false] + ); + assert_eq!( + Into::<[bool; 2]>::into($mask::new(true, false)), + [true, false] + ); + assert_eq!( + Into::<[bool; 2]>::into($mask::new(false, true)), + [false, true] + ); + assert_eq!( + Into::<[bool; 2]>::into($mask::new(true, true)), + [true, true] + ); + }); + glam_test!(test_mask_bitmask, { assert_eq!($mask::new(false, false).bitmask(), 0b00); assert_eq!($mask::new(true, false).bitmask(), 0b01); @@ -821,6 +869,7 @@ macro_rules! impl_vec2_bit_op_tests { } mod vec2 { + #[allow(deprecated)] use glam::{const_vec2, vec2, BVec2, Vec2, Vec3}; glam_test!(test_align, { @@ -857,6 +906,7 @@ mod vec2 { } mod dvec2 { + #[allow(deprecated)] use glam::{const_dvec2, dvec2, BVec2, DVec2, DVec3}; glam_test!(test_align, { @@ -874,6 +924,7 @@ mod dvec2 { } mod ivec2 { + #[allow(deprecated)] use glam::{const_ivec2, ivec2, BVec2, IVec2, IVec3, UVec2}; glam_test!(test_align, { @@ -898,6 +949,7 @@ mod ivec2 { } mod uvec2 { + #[allow(deprecated)] use glam::{const_uvec2, uvec2, BVec2, IVec2, UVec2, UVec3}; glam_test!(test_align, { diff --git a/tests/vec3.rs b/tests/vec3.rs index 35c7e6e8..c0f990cf 100644 --- a/tests/vec3.rs +++ b/tests/vec3.rs @@ -4,8 +4,15 @@ mod support; macro_rules! impl_vec3_tests { ($t:ident, $const_new:ident, $new:ident, $vec3:ident, $mask:ident) => { glam_test!(test_const, { - const V: $vec3 = $const_new!([1 as $t, 2 as $t, 3 as $t]); - assert_eq!($vec3::new(1 as $t, 2 as $t, 3 as $t), V); + const V0: $vec3 = $vec3::splat(1 as $t); + const V1: $vec3 = $vec3::new(1 as $t, 2 as $t, 3 as $t); + const V2: $vec3 = $vec3::from_array([1 as $t, 2 as $t, 3 as $t]); + #[allow(deprecated)] + const V3: $vec3 = $const_new!([1 as $t, 2 as $t, 3 as $t]); + assert_eq!([1 as $t, 1 as $t, 1 as $t], *V0.as_ref()); + assert_eq!([1 as $t, 2 as $t, 3 as $t], *V1.as_ref()); + assert_eq!([1 as $t, 2 as $t, 3 as $t], *V2.as_ref()); + assert_eq!([1 as $t, 2 as $t, 3 as $t], *V3.as_ref()); }); glam_test!(test_new, { @@ -24,6 +31,13 @@ macro_rules! impl_vec3_tests { let a1: [$t; 3] = v.into(); assert_eq!(a, a1); + assert_eq!(a, v.to_array()); + assert_eq!(a, *v.as_ref()); + + let mut v2 = $vec3::default(); + *v2.as_mut() = a; + assert_eq!(a, v2.to_array()); + let v = $vec3::new(t.0, t.1, t.2); assert_eq!(t, v.into()); @@ -38,7 +52,16 @@ macro_rules! impl_vec3_tests { format!("{:?}", a), format!("{}({:?}, {:?}, {:?})", stringify!($vec3), a.x, a.y, a.z) ); - // assert_eq!(format!("{:#?}", a), "$vec3(\n 1.0,\n 2.0,\n 3.0\n)"); + assert_eq!( + format!("{:#?}", a), + format!( + "{}(\n {:#?},\n {:#?},\n {:#?},\n)", + stringify!($vec3), + a.x, + a.y, + a.z + ) + ); assert_eq!(format!("{}", a), "[1, 2, 3]"); }); @@ -91,7 +114,9 @@ macro_rules! impl_vec3_tests { glam_test!(test_ops, { let a = $new(2 as $t, 4 as $t, 8 as $t); assert_eq!($new(4 as $t, 8 as $t, 16 as $t), a + a); + assert_eq!($new(2 as $t, 4 as $t, 8 as $t), 0 as $t + a); assert_eq!($new(0 as $t, 0 as $t, 0 as $t), a - a); + assert_eq!($new(14 as $t, 12 as $t, 8 as $t), 16 as $t - a); assert_eq!($new(4 as $t, 16 as $t, 64 as $t), a * a); assert_eq!($new(4 as $t, 8 as $t, 16 as $t), a * 2 as $t); assert_eq!($new(4 as $t, 8 as $t, 16 as $t), 2 as $t * a); @@ -109,6 +134,19 @@ macro_rules! impl_vec3_tests { glam_test!(test_assign_ops, { let a = $new(1 as $t, 2 as $t, 3 as $t); let mut b = a; + + b += 2 as $t; + assert_eq!($new(3 as $t, 4 as $t, 5 as $t), b); + b -= 2 as $t; + assert_eq!($new(1 as $t, 2 as $t, 3 as $t), b); + b *= 2 as $t; + assert_eq!($new(2 as $t, 4 as $t, 6 as $t), b); + b /= 2 as $t; + assert_eq!($new(1 as $t, 2 as $t, 3 as $t), b); + b %= 2 as $t; + assert_eq!($new(1 as $t, 0 as $t, 1 as $t), b); + + b = a; b += a; assert_eq!($new(2 as $t, 4 as $t, 6 as $t), b); b -= a; @@ -214,17 +252,7 @@ macro_rules! impl_vec3_tests { assert!(a.cmpeq($vec3::ONE).all()); }); - // #[test] - // fn test_mask_as_ref() { - // assert_eq!($mask::new(false, false, false).as_ref(), &[0, 0, 0]); - // assert_eq!($mask::new(true, false, false).as_ref(), &[!0, 0, 0]); - // assert_eq!($mask::new(false, true, true).as_ref(), &[0, !0, !0]); - // assert_eq!($mask::new(false, true, false).as_ref(), &[0, !0, 0]); - // assert_eq!($mask::new(true, false, true).as_ref(), &[!0, 0, !0]); - // assert_eq!($mask::new(true, true, true).as_ref(), &[!0, !0, !0]); - // } - - glam_test!(test_mask_from, { + glam_test!(test_mask_into_array_u32, { assert_eq!( Into::<[u32; 3]>::into($mask::new(false, false, false)), [0, 0, 0] @@ -251,6 +279,33 @@ macro_rules! impl_vec3_tests { ); }); + glam_test!(test_mask_into_array_bool, { + assert_eq!( + Into::<[bool; 3]>::into($mask::new(false, false, false)), + [false, false, false] + ); + assert_eq!( + Into::<[bool; 3]>::into($mask::new(true, false, false)), + [true, false, false] + ); + assert_eq!( + Into::<[bool; 3]>::into($mask::new(false, true, true)), + [false, true, true] + ); + assert_eq!( + Into::<[bool; 3]>::into($mask::new(false, true, false)), + [false, true, false] + ); + assert_eq!( + Into::<[bool; 3]>::into($mask::new(true, false, true)), + [true, false, true] + ); + assert_eq!( + Into::<[u32; 3]>::into($mask::new(true, true, true)), + [!0, !0, !0] + ); + }); + glam_test!(test_mask_bitmask, { assert_eq!($mask::new(false, false, false).bitmask(), 0b000); assert_eq!($mask::new(true, false, false).bitmask(), 0b001); @@ -351,11 +406,11 @@ macro_rules! impl_vec3_tests { glam_test!(test_mask_fmt, { let a = $mask::new(true, false, false); - // // debug fmt - // assert_eq!( - // format!("{:?}", a), - // format!("{}(0xffffffff, 0x0, 0x0)", stringify!($mask)) - // ); + // debug fmt + assert_eq!( + format!("{:?}", a), + format!("{}(0xffffffff, 0x0, 0x0)", stringify!($mask)) + ); // display fmt assert_eq!(format!("{}", a), "[true, false, false]"); @@ -904,6 +959,7 @@ macro_rules! impl_vec3_bit_op_tests { } mod vec3 { + #[allow(deprecated)] use glam::{const_vec3, vec3, BVec3, Vec3}; glam_test!(test_align, { @@ -974,7 +1030,8 @@ mod vec3 { } mod vec3a { - use glam::{const_vec3a, vec3a, BVec3A, Vec3A, Vec4}; + #[allow(deprecated)] + use glam::{const_vec3a, vec3a, BVec3, BVec3A, Vec3A, Vec4}; glam_test!(test_align, { use std::mem; @@ -988,8 +1045,8 @@ mod vec3a { assert_eq!(16, mem::align_of::()); } else { // BVec3A aliases BVec3 - assert_eq!(3, mem::size_of::()); - assert_eq!(1, mem::align_of::()); + assert_eq!(3, mem::size_of::()); + assert_eq!(1, mem::align_of::()); } }); @@ -1045,10 +1102,21 @@ mod vec3a { assert_eq!(v2.min_element(), 2.0); }); + #[cfg(all( + any(target_feature = "sse2", target_feature = "simd128"), + not(feature = "scalar-math") + ))] impl_vec3_float_tests!(f32, const_vec3a, vec3a, Vec3A, BVec3A); + + #[cfg(any( + not(any(target_feature = "sse2", target_feature = "simd128")), + feature = "scalar-math" + ))] + impl_vec3_float_tests!(f32, const_vec3a, vec3a, Vec3A, BVec3); } mod dvec3 { + #[allow(deprecated)] use glam::{const_dvec3, dvec3, BVec3, DVec3}; glam_test!(test_align, { @@ -1063,6 +1131,7 @@ mod dvec3 { } mod ivec3 { + #[allow(deprecated)] use glam::{const_ivec3, ivec3, BVec3, IVec3, UVec3}; glam_test!(test_align, { @@ -1084,6 +1153,7 @@ mod ivec3 { } mod uvec3 { + #[allow(deprecated)] use glam::{const_uvec3, uvec3, BVec3, IVec3, UVec3}; glam_test!(test_align, { diff --git a/tests/vec4.rs b/tests/vec4.rs index 3a722ae8..3c1d7f52 100644 --- a/tests/vec4.rs +++ b/tests/vec4.rs @@ -4,8 +4,15 @@ mod support; macro_rules! impl_vec4_tests { ($t:ident, $const_new:ident, $new:ident, $vec4:ident, $vec3:ident, $vec2:ident, $mask:ident) => { glam_test!(test_const, { - const V: $vec4 = $const_new!([1 as $t, 2 as $t, 3 as $t, 4 as $t]); - assert_eq!($vec4::new(1 as $t, 2 as $t, 3 as $t, 4 as $t), V); + const V0: $vec4 = $vec4::splat(1 as $t); + const V1: $vec4 = $vec4::new(1 as $t, 2 as $t, 3 as $t, 4 as $t); + const V2: $vec4 = $vec4::from_array([1 as $t, 2 as $t, 3 as $t, 4 as $t]); + #[allow(deprecated)] + const V3: $vec4 = $const_new!([1 as $t, 2 as $t, 3 as $t, 4 as $t]); + assert_eq!([1 as $t, 1 as $t, 1 as $t, 1 as $t], *V0.as_ref()); + assert_eq!([1 as $t, 2 as $t, 3 as $t, 4 as $t], *V1.as_ref()); + assert_eq!([1 as $t, 2 as $t, 3 as $t, 4 as $t], *V2.as_ref()); + assert_eq!([1 as $t, 2 as $t, 3 as $t, 4 as $t], *V3.as_ref()); }); glam_test!(test_vec4_consts, { @@ -34,6 +41,13 @@ macro_rules! impl_vec4_tests { let a1: [$t; 4] = v.into(); assert_eq!(a, a1); + assert_eq!(a, v.to_array()); + assert_eq!(a, *v.as_ref()); + + let mut v2 = $vec4::default(); + *v2.as_mut() = a; + assert_eq!(a, v2.to_array()); + let v = $vec4::new(t.0, t.1, t.2, t.3); assert_eq!(t, v.into()); @@ -75,10 +89,17 @@ macro_rules! impl_vec4_tests { a.w ) ); - // assert_eq!( - // format!("{:#?}", a), - // "$vec4(\n 1.0,\n 2.0,\n 3.0,\n 4.0\n)" - // ); + assert_eq!( + format!("{:#?}", a), + format!( + "{}(\n {:#?},\n {:#?},\n {:#?},\n {:#?},\n)", + stringify!($vec4), + a.x, + a.y, + a.z, + a.w + ) + ); assert_eq!(format!("{}", a), "[1, 2, 3, 4]"); }); @@ -131,7 +152,9 @@ macro_rules! impl_vec4_tests { glam_test!(test_ops, { let a = $new(2 as $t, 4 as $t, 8 as $t, 16 as $t); assert_eq!($new(4 as $t, 8 as $t, 16 as $t, 32 as $t), a + a); + assert_eq!($new(2 as $t, 4 as $t, 8 as $t, 16 as $t), 0 as $t + a); assert_eq!($new(0 as $t, 0 as $t, 0 as $t, 0 as $t), a - a); + assert_eq!($new(14 as $t, 12 as $t, 8 as $t, 0 as $t), 16 as $t - a); assert_eq!($new(4 as $t, 16 as $t, 64 as $t, 256 as $t), a * a); assert_eq!($new(4 as $t, 8 as $t, 16 as $t, 32 as $t), a * 2 as $t); assert_eq!($new(4 as $t, 8 as $t, 16 as $t, 32 as $t), 2 as $t * a); @@ -149,6 +172,19 @@ macro_rules! impl_vec4_tests { glam_test!(test_assign_ops, { let a = $new(1 as $t, 2 as $t, 3 as $t, 4 as $t); let mut b = a; + + b += 2 as $t; + assert_eq!($new(3 as $t, 4 as $t, 5 as $t, 6 as $t), b); + b -= 2 as $t; + assert_eq!($new(1 as $t, 2 as $t, 3 as $t, 4 as $t), b); + b *= 2 as $t; + assert_eq!($new(2 as $t, 4 as $t, 6 as $t, 8 as $t), b); + b /= 2 as $t; + assert_eq!($new(1 as $t, 2 as $t, 3 as $t, 4 as $t), b); + b %= 2 as $t; + assert_eq!($new(1 as $t, 0 as $t, 1 as $t, 0 as $t), b); + + b = a; b += a; assert_eq!($new(2 as $t, 4 as $t, 6 as $t, 8 as $t), b); b -= a; @@ -294,35 +330,7 @@ macro_rules! impl_vec4_tests { should_panic!({ $vec4::from_slice(&[0 as $t; 3]) }); }); - // #[test] - // fn test_mask_as_ref() { - // assert_eq!( - // $mask::new(false, false, false, false).as_ref(), - // &[0, 0, 0, 0] - // ); - // assert_eq!( - // $mask::new(false, false, true, true).as_ref(), - // &[0, 0, !0, !0] - // ); - // assert_eq!( - // $mask::new(true, true, false, false).as_ref(), - // &[!0, !0, 0, 0] - // ); - // assert_eq!( - // $mask::new(false, true, false, true).as_ref(), - // &[0, !0, 0, !0] - // ); - // assert_eq!( - // $mask::new(true, false, true, false).as_ref(), - // &[!0, 0, !0, 0] - // ); - // assert_eq!( - // $mask::new(true, true, true, true).as_ref(), - // &[!0, !0, !0, !0] - // ); - // } - - glam_test!(test_mask_from, { + glam_test!(test_mask_into_array_u32, { assert_eq!( Into::<[u32; 4]>::into($mask::new(false, false, false, false)), [0, 0, 0, 0] @@ -349,6 +357,33 @@ macro_rules! impl_vec4_tests { ); }); + glam_test!(test_mask_into_array_bool, { + assert_eq!( + Into::<[bool; 4]>::into($mask::new(false, false, false, false)), + [false, false, false, false] + ); + assert_eq!( + Into::<[bool; 4]>::into($mask::new(false, false, true, true)), + [false, false, true, true] + ); + assert_eq!( + Into::<[bool; 4]>::into($mask::new(true, true, false, false)), + [true, true, false, false] + ); + assert_eq!( + Into::<[bool; 4]>::into($mask::new(false, true, false, true)), + [false, true, false, true] + ); + assert_eq!( + Into::<[bool; 4]>::into($mask::new(true, false, true, false)), + [true, false, true, false] + ); + assert_eq!( + Into::<[bool; 4]>::into($mask::new(true, true, true, true)), + [true, true, true, true] + ); + }); + glam_test!(test_mask_bitmask, { assert_eq!($mask::new(false, false, false, false).bitmask(), 0b0000); assert_eq!($mask::new(false, false, true, true).bitmask(), 0b1100); @@ -458,10 +493,10 @@ macro_rules! impl_vec4_tests { let a = $mask::new(true, false, true, false); assert_eq!(format!("{}", a), "[true, false, true, false]"); - // assert_eq!( - // format!("{:?}", a), - // format!("{}(0xffffffff, 0x0, 0xffffffff, 0x0)", stringify!($mask)) - // ); + assert_eq!( + format!("{:?}", a), + format!("{}(0xffffffff, 0x0, 0xffffffff, 0x0)", stringify!($mask)) + ); }); glam_test!(test_mask_eq, { @@ -995,19 +1030,8 @@ macro_rules! impl_vec4_bit_op_tests { }; } mod vec4 { - use glam::{const_vec4, vec4, Vec2, Vec3, Vec4}; - - #[cfg(all( - any(target_feature = "sse2", target_feature = "simd128"), - not(feature = "scalar-math") - ))] - type Vec4Mask = glam::BVec4A; - - #[cfg(any( - not(any(target_feature = "sse2", target_feature = "simd128")), - feature = "scalar-math" - ))] - type Vec4Mask = glam::BVec4; + #[allow(deprecated)] + use glam::{const_vec4, vec4, BVec4, BVec4A, Vec2, Vec3, Vec4}; glam_test!(test_align, { use std::mem; @@ -1021,11 +1045,11 @@ mod vec4 { any(target_feature = "sse2", target_feature = "simd128"), not(feature = "scalar-math") )) { - assert_eq!(16, mem::size_of::()); - assert_eq!(16, mem::align_of::()); + assert_eq!(16, mem::size_of::()); + assert_eq!(16, mem::align_of::()); } else { - assert_eq!(4, mem::size_of::()); - assert_eq!(1, mem::align_of::()); + assert_eq!(4, mem::size_of::()); + assert_eq!(1, mem::align_of::()); } }); @@ -1053,7 +1077,7 @@ mod vec4 { #[repr(C, align(16))] struct U32x4_A16([u32; 4]); - let v0 = Vec4Mask::new(true, false, true, false); + let v0 = BVec4A::new(true, false, true, false); let m0: __m128 = v0.into(); let mut a0 = U32x4_A16([1, 2, 3, 4]); unsafe { @@ -1123,10 +1147,21 @@ mod vec4 { ); }); - impl_vec4_float_tests!(f32, const_vec4, vec4, Vec4, Vec3, Vec2, Vec4Mask); + #[cfg(all( + any(target_feature = "sse2", target_feature = "simd128"), + not(feature = "scalar-math") + ))] + impl_vec4_float_tests!(f32, const_vec4, vec4, Vec4, Vec3, Vec2, BVec4A); + + #[cfg(any( + not(any(target_feature = "sse2", target_feature = "simd128")), + feature = "scalar-math" + ))] + impl_vec4_float_tests!(f32, const_vec4, vec4, Vec4, Vec3, Vec2, BVec4); } mod dvec4 { + #[allow(deprecated)] use glam::{const_dvec4, dvec4, BVec4, DVec2, DVec3, DVec4}; glam_test!(test_align, { @@ -1144,6 +1179,7 @@ mod dvec4 { } mod ivec4 { + #[allow(deprecated)] use glam::{const_ivec4, ivec4, BVec4, IVec2, IVec3, IVec4, UVec4}; glam_test!(test_align, { @@ -1168,6 +1204,7 @@ mod ivec4 { } mod uvec4 { + #[allow(deprecated)] use glam::{const_uvec4, uvec4, BVec4, IVec4, UVec2, UVec3, UVec4}; glam_test!(test_align, {