From 43114ee6a78aab3c21de340031c2173dc95b64a1 Mon Sep 17 00:00:00 2001 From: Jeff Vander Stoep Date: Mon, 12 Dec 2022 11:05:26 +0100 Subject: Upgrade glam to 0.22.0 This project was upgraded with external_updater. Usage: tools/external_updater/updater.sh update rust/crates/glam For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md Test: TreeHugger Change-Id: Ib60bda028b6a7bc8e6a3d863839e6d8ea249b2d4 --- .gitattributes | 1 + .github/workflows/ci.yml | 23 +- .github/workflows/coverage.yml | 4 +- .tarpaulin.toml | 8 +- ARCHITECTURE.md | 151 +-- Android.bp | 10 +- CHANGELOG.md | 158 ++- CONTRIBUTING.md | 5 +- Cargo.toml | 31 +- Cargo.toml.orig | 24 +- METADATA | 13 +- README.md | 30 +- benches/support.rs | 129 +++ benches/support/mod.rs | 129 --- benches/transform.rs | 132 --- benches/vec3.rs | 2 +- build_all_msrv.sh | 8 +- build_and_test_features.sh | 19 +- clippy.toml | 2 +- deny.toml | 13 +- src/affine2.rs | 519 --------- src/affine3.rs | 631 ----------- src/align16.rs | 27 + src/bool.rs | 100 ++ src/bool/bvec2.rs | 168 +++ src/bool/bvec3.rs | 184 ++++ src/bool/bvec4.rs | 191 ++++ src/bool/coresimd.rs | 2 + src/bool/coresimd/bvec3a.rs | 204 ++++ src/bool/coresimd/bvec4a.rs | 216 ++++ src/bool/scalar.rs | 2 + src/bool/scalar/bvec3a.rs | 188 ++++ src/bool/scalar/bvec4a.rs | 196 ++++ src/bool/sse2.rs | 2 + src/bool/sse2/bvec3a.rs | 207 ++++ src/bool/sse2/bvec4a.rs | 219 ++++ src/bool/wasm32.rs | 2 + src/bool/wasm32/bvec3a.rs | 199 ++++ src/bool/wasm32/bvec4a.rs | 206 ++++ src/cast.rs | 167 --- src/core/mod.rs | 18 - src/core/scalar/mask.rs | 452 -------- src/core/scalar/matrix.rs | 285 ----- src/core/scalar/mod.rs | 4 - src/core/scalar/quaternion.rs | 87 -- src/core/scalar/vector.rs | 1465 ------------------------- src/core/sse2/float.rs | 280 ----- src/core/sse2/matrix.rs | 558 ---------- src/core/sse2/mod.rs | 4 - src/core/sse2/quaternion.rs | 135 --- src/core/sse2/vector.rs | 871 --------------- src/core/storage.rs | 128 --- src/core/traits/matrix.rs | 985 ----------------- src/core/traits/mod.rs | 5 - src/core/traits/projection.rs | 164 --- src/core/traits/quaternion.rs | 140 --- src/core/traits/scalar.rs | 434 -------- src/core/traits/vector.rs | 854 --------------- src/core/wasm32/float.rs | 113 -- src/core/wasm32/matrix.rs | 532 ---------- src/core/wasm32/mod.rs | 4 - src/core/wasm32/quaternion.rs | 130 --- src/core/wasm32/vector.rs | 812 -------------- src/coresimd.rs | 57 + src/deref.rs | 50 + src/euler.rs | 140 +-- src/f32.rs | 165 +++ src/f32/affine2.rs | 398 +++++++ src/f32/affine3a.rs | 531 ++++++++++ src/f32/coresimd.rs | 6 + src/f32/coresimd/mat2.rs | 478 +++++++++ src/f32/coresimd/mat3a.rs | 747 +++++++++++++ src/f32/coresimd/mat4.rs | 1506 ++++++++++++++++++++++++++ src/f32/coresimd/quat.rs | 917 ++++++++++++++++ src/f32/coresimd/vec3a.rs | 1086 +++++++++++++++++++ src/f32/coresimd/vec4.rs | 1009 ++++++++++++++++++ src/f32/mat3.rs | 737 +++++++++++++ src/f32/scalar.rs | 6 + src/f32/scalar/mat2.rs | 458 ++++++++ src/f32/scalar/mat3a.rs | 725 +++++++++++++ src/f32/scalar/mat4.rs | 1276 ++++++++++++++++++++++ src/f32/scalar/quat.rs | 872 +++++++++++++++ src/f32/scalar/vec3a.rs | 1189 +++++++++++++++++++++ src/f32/scalar/vec4.rs | 1196 +++++++++++++++++++++ src/f32/sse2.rs | 6 + src/f32/sse2/mat2.rs | 505 +++++++++ src/f32/sse2/mat3a.rs | 732 +++++++++++++ src/f32/sse2/mat4.rs | 1371 ++++++++++++++++++++++++ src/f32/sse2/quat.rs | 942 +++++++++++++++++ src/f32/sse2/vec3a.rs | 1157 ++++++++++++++++++++ src/f32/sse2/vec4.rs | 1078 +++++++++++++++++++ src/f32/vec2.rs | 1047 ++++++++++++++++++ src/f32/vec3.rs | 1151 ++++++++++++++++++++ src/f32/wasm32.rs | 6 + src/f32/wasm32/mat2.rs | 480 +++++++++ src/f32/wasm32/mat3a.rs | 727 +++++++++++++ src/f32/wasm32/mat4.rs | 1362 ++++++++++++++++++++++++ src/f32/wasm32/quat.rs | 932 ++++++++++++++++ src/f32/wasm32/vec3a.rs | 1107 +++++++++++++++++++ src/f32/wasm32/vec4.rs | 1041 ++++++++++++++++++ src/f64.rs | 99 ++ src/f64/daffine2.rs | 359 +++++++ src/f64/daffine3.rs | 520 +++++++++ src/f64/dmat2.rs | 448 ++++++++ src/f64/dmat3.rs | 716 +++++++++++++ src/f64/dmat4.rs | 1243 ++++++++++++++++++++++ src/f64/dquat.rs | 848 +++++++++++++++ src/f64/dvec2.rs | 1047 ++++++++++++++++++ src/f64/dvec3.rs | 1157 ++++++++++++++++++++ src/f64/dvec4.rs | 1174 ++++++++++++++++++++ src/features.rs | 17 + src/features/impl_serde.rs | 221 +++- src/features/mod.rs | 17 - src/float_ex.rs | 51 + src/i32.rs | 42 + src/i32/ivec2.rs | 958 +++++++++++++++++ src/i32/ivec3.rs | 1036 ++++++++++++++++++ src/i32/ivec4.rs | 1129 ++++++++++++++++++++ src/lib.rs | 118 +-- src/macros.rs | 459 +------- src/mat.rs | 114 -- src/mat2.rs | 398 ------- src/mat3.rs | 596 ----------- src/mat4.rs | 890 ---------------- src/quat.rs | 825 --------------- src/sse2.rs | 238 +++++ src/swizzles.rs | 42 + src/swizzles/coresimd.rs | 2 + src/swizzles/coresimd/vec3a_impl.rs | 625 +++++++++++ src/swizzles/coresimd/vec4_impl.rs | 1997 ++++++++++++++++++++++++++++++++++ src/swizzles/dvec2_impl.rs | 193 ++++ src/swizzles/dvec2_impl_scalar.rs | 118 --- src/swizzles/dvec3_impl.rs | 729 +++++++++++++ src/swizzles/dvec3_impl_scalar.rs | 474 --------- src/swizzles/dvec4_impl.rs | 1993 ++++++++++++++++++++++++++++++++++ src/swizzles/dvec4_impl_scalar.rs | 1350 ----------------------- src/swizzles/ivec2_impl.rs | 193 ++++ src/swizzles/ivec2_impl_scalar.rs | 118 --- src/swizzles/ivec3_impl.rs | 729 +++++++++++++ src/swizzles/ivec3_impl_scalar.rs | 474 --------- src/swizzles/ivec4_impl.rs | 1993 ++++++++++++++++++++++++++++++++++ src/swizzles/ivec4_impl_scalar.rs | 1350 ----------------------- src/swizzles/mod.rs | 35 - src/swizzles/scalar.rs | 2 + src/swizzles/scalar/vec3a_impl.rs | 729 +++++++++++++ src/swizzles/scalar/vec4_impl.rs | 1993 ++++++++++++++++++++++++++++++++++ src/swizzles/sse2.rs | 2 + src/swizzles/sse2/vec3a_impl.rs | 628 +++++++++++ src/swizzles/sse2/vec4_impl.rs | 2000 +++++++++++++++++++++++++++++++++++ src/swizzles/uvec2_impl.rs | 193 ++++ src/swizzles/uvec2_impl_scalar.rs | 118 --- src/swizzles/uvec3_impl.rs | 729 +++++++++++++ src/swizzles/uvec3_impl_scalar.rs | 474 --------- src/swizzles/uvec4_impl.rs | 1993 ++++++++++++++++++++++++++++++++++ src/swizzles/uvec4_impl_scalar.rs | 1350 ----------------------- src/swizzles/vec2_impl.rs | 193 ++++ src/swizzles/vec2_impl_scalar.rs | 118 --- src/swizzles/vec3_impl.rs | 729 +++++++++++++ src/swizzles/vec3_impl_scalar.rs | 474 --------- src/swizzles/vec3a_impl_scalar.rs | 474 --------- src/swizzles/vec3a_impl_sse2.rs | 479 --------- src/swizzles/vec3a_impl_wasm32.rs | 476 --------- src/swizzles/vec4_impl_scalar.rs | 1350 ----------------------- src/swizzles/vec4_impl_sse2.rs | 1355 ------------------------ src/swizzles/vec4_impl_wasm32.rs | 1352 ----------------------- src/swizzles/vec_traits.rs | 736 ++++++++++--- src/swizzles/wasm32.rs | 2 + src/swizzles/wasm32/vec3a_impl.rs | 625 +++++++++++ src/swizzles/wasm32/vec4_impl.rs | 1997 ++++++++++++++++++++++++++++++++++ src/transform.rs | 432 -------- src/u32.rs | 41 + src/u32/uvec2.rs | 876 +++++++++++++++ src/u32/uvec3.rs | 977 +++++++++++++++++ src/u32/uvec4.rs | 1063 +++++++++++++++++++ src/vec.rs | 1029 ------------------ src/vec2.rs | 317 ------ src/vec3.rs | 454 -------- src/vec4.rs | 434 -------- src/vec_mask.rs | 460 -------- src/wasm32.rs | 47 + tests/affine2.rs | 81 +- tests/affine3.rs | 114 +- tests/euler.rs | 98 +- tests/mat2.rs | 52 +- tests/mat3.rs | 83 +- tests/mat4.rs | 131 +-- tests/quat.rs | 88 +- tests/support.rs | 281 +++++ tests/support/macros.rs | 4 +- tests/support/mod.rs | 280 ----- tests/transform.rs | 129 --- tests/vec2.rs | 214 +++- tests/vec3.rs | 242 ++++- tests/vec4.rs | 298 ++++-- 194 files changed, 66319 insertions(+), 29787 deletions(-) create mode 100644 .gitattributes create mode 100644 benches/support.rs delete mode 100644 benches/support/mod.rs delete mode 100644 benches/transform.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/coresimd.rs create mode 100644 src/bool/coresimd/bvec3a.rs create mode 100644 src/bool/coresimd/bvec4a.rs create mode 100644 src/bool/scalar.rs create mode 100644 src/bool/scalar/bvec3a.rs create mode 100644 src/bool/scalar/bvec4a.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/cast.rs delete mode 100644 src/core/mod.rs delete mode 100644 src/core/scalar/mask.rs delete mode 100644 src/core/scalar/matrix.rs delete mode 100644 src/core/scalar/mod.rs delete mode 100644 src/core/scalar/quaternion.rs delete mode 100644 src/core/scalar/vector.rs delete mode 100644 src/core/sse2/float.rs delete mode 100644 src/core/sse2/matrix.rs delete mode 100644 src/core/sse2/mod.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/matrix.rs delete mode 100644 src/core/traits/mod.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/float.rs delete mode 100644 src/core/wasm32/matrix.rs delete mode 100644 src/core/wasm32/mod.rs delete mode 100644 src/core/wasm32/quaternion.rs delete mode 100644 src/core/wasm32/vector.rs create mode 100644 src/coresimd.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/coresimd.rs create mode 100644 src/f32/coresimd/mat2.rs create mode 100644 src/f32/coresimd/mat3a.rs create mode 100644 src/f32/coresimd/mat4.rs create mode 100644 src/f32/coresimd/quat.rs create mode 100644 src/f32/coresimd/vec3a.rs create mode 100644 src/f32/coresimd/vec4.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/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/features.rs delete mode 100644 src/features/mod.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 create mode 100644 src/sse2.rs create mode 100644 src/swizzles.rs create mode 100644 src/swizzles/coresimd.rs create mode 100644 src/swizzles/coresimd/vec3a_impl.rs create mode 100644 src/swizzles/coresimd/vec4_impl.rs create mode 100644 src/swizzles/dvec2_impl.rs delete mode 100644 src/swizzles/dvec2_impl_scalar.rs create mode 100644 src/swizzles/dvec3_impl.rs delete mode 100644 src/swizzles/dvec3_impl_scalar.rs create mode 100644 src/swizzles/dvec4_impl.rs delete mode 100644 src/swizzles/dvec4_impl_scalar.rs create mode 100644 src/swizzles/ivec2_impl.rs delete mode 100644 src/swizzles/ivec2_impl_scalar.rs create mode 100644 src/swizzles/ivec3_impl.rs delete mode 100644 src/swizzles/ivec3_impl_scalar.rs create mode 100644 src/swizzles/ivec4_impl.rs delete mode 100644 src/swizzles/ivec4_impl_scalar.rs delete mode 100644 src/swizzles/mod.rs create mode 100644 src/swizzles/scalar.rs create mode 100644 src/swizzles/scalar/vec3a_impl.rs create mode 100644 src/swizzles/scalar/vec4_impl.rs create mode 100644 src/swizzles/sse2.rs create mode 100644 src/swizzles/sse2/vec3a_impl.rs create mode 100644 src/swizzles/sse2/vec4_impl.rs create mode 100644 src/swizzles/uvec2_impl.rs delete mode 100644 src/swizzles/uvec2_impl_scalar.rs create mode 100644 src/swizzles/uvec3_impl.rs delete mode 100644 src/swizzles/uvec3_impl_scalar.rs create mode 100644 src/swizzles/uvec4_impl.rs delete mode 100644 src/swizzles/uvec4_impl_scalar.rs create mode 100644 src/swizzles/vec2_impl.rs delete mode 100644 src/swizzles/vec2_impl_scalar.rs create mode 100644 src/swizzles/vec3_impl.rs delete mode 100644 src/swizzles/vec3_impl_scalar.rs delete mode 100644 src/swizzles/vec3a_impl_scalar.rs delete mode 100644 src/swizzles/vec3a_impl_sse2.rs delete mode 100644 src/swizzles/vec3a_impl_wasm32.rs delete mode 100644 src/swizzles/vec4_impl_scalar.rs delete mode 100644 src/swizzles/vec4_impl_sse2.rs delete mode 100644 src/swizzles/vec4_impl_wasm32.rs create mode 100644 src/swizzles/wasm32.rs create mode 100644 src/swizzles/wasm32/vec3a_impl.rs create mode 100644 src/swizzles/wasm32/vec4_impl.rs 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 create mode 100644 tests/support.rs delete mode 100644 tests/support/mod.rs delete mode 100644 tests/transform.rs diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..8d2e819 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.rs.tera linguist-language=Rust diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9ce0c54..0d06e33 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,14 +20,18 @@ jobs: # run clippy to verify we have no warnings - run: cargo fetch - name: cargo clippy - run: cargo clippy --all-features -- -D warnings + run: cargo clippy --workspace --all-targets --all-features -- -D warnings + + # check that codegen output matches committed source files + - name: codegen + run: cargo run --release -p codegen -- --check test: name: Test 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 @@ -36,7 +40,22 @@ jobs: - run: ./build_and_test_features.sh shell: bash + test-core-simd: + name: Test portable simd + strategy: + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + toolchain: [nightly] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v2 + - run: rustup update --no-self-update ${{ matrix.toolchain }} + - run: rustup default ${{ matrix.toolchain }} + - run: cargo test --features core-simd + shell: bash + test-wasm: + name: Test wasm strategy: matrix: toolchain: [stable] diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 504edd3..6ed2dcb 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -3,7 +3,7 @@ on: [push] jobs: coverage: container: - image: xd009642/tarpaulin + image: xd009642/tarpaulin:develop-nightly options: --security-opt seccomp=unconfined runs-on: ubuntu-latest steps: @@ -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 +nightly 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 9fe5954..ec32887 100644 --- a/.tarpaulin.toml +++ b/.tarpaulin.toml @@ -1,7 +1,11 @@ [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/wasm32/*", "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/wasm32/*", "benches/*", "tests/support.rs"] + +[core_simd] +features = "core-simd approx bytemuck mint rand rkyv serde debug-glam-assert" +exclude-files = ["codegen/*", "src/wasm32.rs", "src/bool/wasm32/*", "src/f32/wasm32/*", "src/swizzles/wasm32/*", "benches/*", "tests/support.rs"] diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 47c5332..cee12dd 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -70,148 +70,15 @@ some additional complexity in implementation. for `f32`, `f64`, `i32` and `u32` primitives, with SSE2 or wasm32 for some `f32` types and scalar fallbacks if SIMD is not available. -This is done with a combination of Rust macros for generating the public facing -types and documentation, e.g. `Vec4` and inner storage types which have a number -of traits implemented for different kinds of storage. - -### Inner types and traits - -Many `glam` types may use SIMD storage where available, e.g. `Vec4` might use -`__m128` for storage if available or an inner storage struct `XYZW` for -the scalar implementation. - -There are a number of internal traits defined in `core::traits` for scalar, -vector, matrix and quaternion functionality that glam needs. These traits are -implemented for the different storage types, e.g. -`core::traits::vector::Vector4` has an implementations for `__m128`, `simd128` -and the `XYZW` struct. +### Component access via Deref -The traits will provide default definitions where possible so not every trait -method needs to be implemented for every storage type. +The `Deref` trait is used to provide direct access to SIMD vector components +like `.x`, `.y` and so on. The `Deref` implementation will return `XYZ` +structure on which the vector components are accessible. Unfortunately if users +dereference the public types they will see confusing errors messages about +`XYZ` types but this on balance seemed preferable to needing to setter and +getting methods to read and write component values. -### Component access via Deref +## Code generation -Because `glam` uses an inner storage type which could be a simple struct or a -SIMD vector it is not possible to provide direct access to the vector's -component values (e.g. `.x`, `.y`, and `.z`). The `Deref` trait is used to work -around this and provide direct access to vector components like `.x`, `.y` and -so on. The `Deref` implementation will return `XYZ` structure on which the -vector components are accessible. Unfortunately if users dereference the public -types they will see confusing errors messages about `XYZ` types but this on -balance seemed preferable to needing to setter and getting methods to read and -write component values. - -### Public types and macros - -Macros are used to generate the public types to reuse common implementation -details where possible. - -Generally the public type `struct` is declared then it's methods are populated -with multiple macros within a single `impl`. Methods are all declared within a -single `impl` definition for documentation purposes. While it is possible to -have multiple `impl` blocks for the same type this splits the method -documentation generated by `rustdoc`. - -A lot of the motivation for removing duplication is documentation. It is -reasonably easy to find discrepancies in duplicated code through unit testing -but documentation is a lot harder to keep in sync. - -## A walkthrough of 3D vectors - -3D vectors are the most complicated case in `glam`. There are 5 different 3D -vector types, including `Vec3`, `Vec3A` (16 byte aligned SIMD), `DVec3`, `IVec3` -and `UVec3`. There is some common code used by all of these types and some that -is specific to the primitives and storage that they implement. Note that there -is also a `BVec3` but as that type is used as a mask it is quite separate. - -### Storage - -Store for a 3D vector may use `XYZ` where `T` is one of `f32`, `f64`, `i32`, -or `u32` for the scalar case and `__m128` or `simd128` for the SIMD case for -SSE2 or wasm32 respectively. There is also `XYZF32A16` which is used as storage -for `Vec3A` when SIMD is not available. - -### Traits - -There are quite a few traits involved in implementing a 3D vector. To start with -there are scalar traits which set up some constants and expected operations for -scalar types in the `core::trait::scalar` module: - -* `NumConstsEx` - defines `ZERO` and `ONE` constants -* `FloatConstEx` - defines `NEG_ONE`, `TWO` and `HALF` constants -* `NumEx` - base number trait, implemented for `f32`, `f64`, `i32` and `u32` -* `SignedEx` - signed number trait, implemented for `i32`, `f32` and `f64` -* `FloatEx` - float number trait, implemented for `f32` and `f64` - -Then vector traits are defined in `core::trait::vector`: - -* `VectorConst` - defines `ZERO` and `ONE` constants for vectors -* `Vector3Const` - defines 3D vector constants, `X`, `Y`, and `Z` -* `Vector` - defines methods for any size of vector, typically these methods - can be implemented without needing to know the number of components, e.g. - `splat` -* `SignedVector` - defines methods for signed vectors of any size, e.g. `neg` -* `Vector3` - defines methods for 3D vectors, e.g. `dot` needs to know how many - components to operate on -* `SignedVector3` - defines methods for signed vector types with 3 components, - in this case the default implementation of some methods needs to know the - number of components, e.g. `abs` -* `FloatVector3` - defines methods for float vector types with 3 components, for - when the implementation needs to know the number of components, e.g. `length` - -Note that the `Vector` trait also has an associated `Mask` type which is the -type used for returning from comparison operators. Different types are used for -scalar and SIMD types. - -### Macros - -The different 3D vector types are declared in the `vec3` module and macros are -used to implement the majority of their methods. Macros specific to 3D vectors -are found in the `vec3` module, most macros call other macros. - -* `impl_f32_vec3` - implements methods and traits common to `Vec3` and `Vec3A` -* `impl_vec3_float_methods` - implements methods for 3D vectors of floats -* `impl_vec3_signed_methods` - implements methods for 3D vectors of signed types -* `impl_vec3_common_methods` - implements common methods for 3D vectors -* `impl_vec3_float_traits` - implements traits for 3D vector float operators -* `impl_vec3_common_traits` - implements traits for common 3D vector operators - -Macros that define functionality to vectors of any size are found in -`src/vec.rs`. These do not call other macros. - -* `impl_vecn_float_methods` - implements common methods for vectors of floats -* `impl_vecn_signed_methods` - implements common methods for vectors of signed -* `imp_vecn_common_methods` - implements common methods for all vector types -* `impl_vecn_signed_traits` - implements trait operators for signed vector types -* `impl_vecn_common_traits` - implements common trait operators for all vectors - -### Summary - -Functionality is broken down to the point that there is very little duplicated -code. Macros are also used to avoid duplicating comments. Functionality is -implemented through traits operating on different storage types. Common -functionality is often implemented in default trait implementations. - -## Limitations - -Adding support for types other than `f32` greatly increased the complexity of -the internal implementation of the crate. - -While the current approach works well for keeping the public interface and -documentation simple and clean complexity exists under the surface. The use of -macros unfortunately obfuscates the source code for anyone trying to read it. -The largest issues being when users navigate to glam code in an IDE they are -usually presented with a very high level macro and need to manually hunt down -the actual implementation. The same issue exists when attempting to view source -in the `rustdoc` generated documentation. - -One way to address this would be to use an offline code generator instead of a -compile time code generator (i.e. Rust macros) which would remove macros from -the code that users end up viewing. The main downside is it would take a while -to write this and it might be more confusing for contributors. Another option -might be to improve tooling so that IDEs and rustdoc navigate directly to the -code that was generated by the macro rather than the macro itself. - -The use of `Deref` does occasionally cause confusion. It would be good if it was -only necessary to implement `Deref` on the SIMD types but currently that is not -possible. +See [codegen/README.md] for information on `glam`'s code generation process. diff --git a/Android.bp b/Android.bp index 79bd206..7ac23d2 100644 --- a/Android.bp +++ b/Android.bp @@ -1,8 +1,6 @@ // This file is generated by cargo2android.py --run. // Do not modify this file as changes will be overridden on upgrade. - - package { default_applicable_licenses: ["external_rust_crates_glam_license"], } @@ -45,11 +43,15 @@ rust_library_host { name: "libglam", crate_name: "glam", cargo_env_compat: true, - cargo_pkg_version: "0.20.3", + cargo_pkg_version: "0.22.0", srcs: ["src/lib.rs"], - edition: "2018", + edition: "2021", features: [ "default", "std", ], + apex_available: [ + "//apex_available:platform", + "//apex_available:anyapex", + ], } diff --git a/CHANGELOG.md b/CHANGELOG.md index f2e54b1..97e2544 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,153 @@ 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]. +## [0.22.0] - 2022-10-24 + +### Breaking changes + +* Added `u32` implementation of `BVec3A` and `BVec4` when SIMD is not available. + These are used instead of aliasing to the `bool` implementations. + +* Removed `Add`, `Sub`, and scalar `Mul` implementations from affine types as + they didn't make sense on these types. + +* Removed deprecated `const_*` macros. These have been replaced by `const fn` + methods. + +### Fixed + +* Fixed `neg` and `signum` to consistently handle negative zero across multiple + platforms. + +* Removed `register_attr` feature usage for SPIR-V targets. + +### Added + +* Added missing `Serialize`, `Deserialize` and `PartialEq` implementations. + +* Added `Sum` and `Product` implementations for all vector, matrix + and quaternion types. + +* Added 4x4 matrix methods `look_at_lh` and `look_at_rh`. These were previously + private. + +* Added `dot_into_vec` methods to vector which returns the result of the dot + product splatted to all vector lanes. + +* Added `is_negative_bitmask` to vector types which returns a `u32` of bits for + each negative vector lane. + +* Added `splat` method and `TRUE` and `FALSE` constants to all `BVec` types. + +* Added `from_mat3a` methods to `Affine2`, `Mat2`, `Mat4` and `Quat` types. + +### Changed + +* Disable `serde` default features. + +* Made `to_cols_array`, `to_cols_array_2d`, and `from_diagonal` methods + `const fn`. + +## [0.21.3] - 2022-08-02 + +### Fixed + +* Fixed `glam_assert` being too restrictive in matrix transform point and + transform vector methods. + +### Added + +* Added experimental `core-simd` feature which enables SIMD support via the + unstable `core::simd` module. + +### Changed + +* Derive from `PartialEq` and `Eq` instead of providing a trait implementation + for all non SIMD types. + +## [0.21.2] - 2022-06-25 + +### Fixed + +* Restore missing `$crate::` prefix in deprecated `const_*` macros. + +* Fixed some performance regressions in affine and matrix determinant and + inverses due to lack of inlining. + +* Fixed some performance regressions in the SSE2 `Vec3A` to `Vec3` from + conversion. + +### Added + +* Implemented `BitXor` and `BitXorAssign` traits for `bool` vectors. + +## [0.21.1] - 2022-06-22 + +### Fixed + +* Fix compilation when FMA support is enabled. + +## [0.21.0] - 2022-06-22 + +### 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. + +* The `AsMut` and `Deref` trait implementations on `Quat` and `DQuat` was + removed. Quaternion fields are now public. + +* The `AsRef` trait implementations were removed from `BVec2`, `BVec3`, + `BVec3A`, `BVec4` and `BVec4A`. + +### Added + +* `NEG_ONE` constant was added to all signed vector types. + +* `NEG_X`, `NEG_Y`, `NEG_Z` and `NEG_W` negative axis vectors were added to + signed vector types. + +* The `rotate` and `from_angle` methods were added to `Vec2` and `DVec2`. + `from_angle` returns a 2D vector containing `[angle.cos(), angle.sin()]` that + can be used to `rotate` another 2D vector. + +* The `from_array` `const` function was added to all vector types. + +### Changed + +* Source code is now largely generated. This removes most usage of macros + internally to improve readability. There should be no change in API or + behavior other than what is documented here. + +* Many methods have been made `const fn`: + * `new`, `splat`, `from_slice`, `to_array` and `extend` on vector types + * `from_cols`, `from_cols_array`, `from_cols_array_2d`, `from_cols_slice` on + matrix types + * `from_xyzw` and `from_array` on quaternion types + * `from_cols` on affine types + +* The `const` new macros where deprecated. + +### Removed + +* Deleted deprecated `TransformRT` and `TransformSRT` types. + +## [0.20.5] - 2022-04-12 + +### Fixed + +* Fixed a bug in the scalar implementation of 4D vector `max_element` method + where the `w` element check was incorrect. + +## [0.20.4] - 2022-04-11 + +### Fixed + +* Fixed a bug with quaternion `slerp` with a rotation of tau. + ## [0.20.3] - 2022-03-28 ### Added @@ -28,7 +175,7 @@ The format is based on [Keep a Changelog], and this project adheres to ## [0.20.1] - 2021-11-23 -### Addeed +### Added * Added the `from_rotation_arc_2d()` method to `Quat` and `DQuat` which will return a rotation between two 2D vectors around the z axis. @@ -742,7 +889,14 @@ The format is based on [Keep a Changelog], and this project adheres to [Keep a Changelog]: https://keepachangelog.com/ [Semantic Versioning]: https://semver.org/spec/v2.0.0.html -[Unreleased]: https://github.com/bitshifter/glam-rs/compare/0.20.3...HEAD +[Unreleased]: https://github.com/bitshifter/glam-rs/compare/0.22.0...HEAD +[0.22.0]: https://github.com/bitshifter/glam-rs/compare/0.21.3...0.22.0 +[0.21.3]: https://github.com/bitshifter/glam-rs/compare/0.21.2...0.21.3 +[0.21.2]: https://github.com/bitshifter/glam-rs/compare/0.21.1...0.21.2 +[0.21.1]: https://github.com/bitshifter/glam-rs/compare/0.21.0...0.21.1 +[0.21.0]: https://github.com/bitshifter/glam-rs/compare/0.20.5...0.21.0 +[0.20.5]: https://github.com/bitshifter/glam-rs/compare/0.20.4...0.20.5 +[0.20.4]: https://github.com/bitshifter/glam-rs/compare/0.20.3...0.20.4 [0.20.3]: https://github.com/bitshifter/glam-rs/compare/0.20.2...0.20.3 [0.20.2]: https://github.com/bitshifter/glam-rs/compare/0.20.1...0.20.2 [0.20.1]: https://github.com/bitshifter/glam-rs/compare/0.20.0...0.20.1 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5e9965f..c3d8086 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -42,8 +42,8 @@ If you feel any documentation could be added or improved please ## Code contributions -Depending on the complexity of the change, it might be worth reading about -`glam`'s [ARCHITECTURE]. +Most of `glam`'s source code is generated. See the [codegen README] on how +to modify the code templates and generate new source code. You can run some of `glam`'s test suite locally by running the `build_and_test_features.sh` script. It's worth running that before creating a @@ -56,3 +56,4 @@ Also run `cargo fmt` and `cargo clippy` on any new code. [ask a question]: https://github.com/bitshifter/glam-rs/discussions/new?category=q-a [suggest a new feature]: https://github.com/bitshifter/glam-rs/discussions/new?category=ideas [ARCHITECTURE]: ARCHITECTURE.md +[codegen README]: codegen/README.md diff --git a/Cargo.toml b/Cargo.toml index 8360666..624a2fa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,14 +10,24 @@ # See Cargo.toml.orig for the original contents. [package] -edition = "2018" +edition = "2021" +rust-version = "1.58.1" name = "glam" -version = "0.20.3" +version = "0.22.0" authors = ["Cameron Hart "] description = "A simple and fast 3D math library for games and graphics" readme = "README.md" -keywords = ["gamedev", "math", "matrix", "vector", "quaternion"] -categories = ["game-engines", "no-std"] +keywords = [ + "gamedev", + "math", + "matrix", + "vector", + "quaternion", +] +categories = [ + "game-engines", + "no-std", +] license = "MIT OR Apache-2.0" repository = "https://github.com/bitshifter/glam-rs" @@ -52,11 +62,6 @@ harness = false name = "quat" harness = false -[[bench]] -name = "transform" -harness = false -required-features = ["transform-types"] - [[bench]] name = "vec2" harness = false @@ -72,6 +77,7 @@ harness = false [[bench]] name = "vec4" harness = false + [dependencies.approx] version = "0.5" optional = true @@ -110,6 +116,8 @@ optional = true version = "1.0" features = ["derive"] optional = true +default-features = false + [dev-dependencies.rand_xoshiro] version = "0.6" @@ -117,6 +125,7 @@ version = "0.6" version = "1.0" [features] +core-simd = [] cuda = [] debug-glam-assert = [] default = ["std"] @@ -125,11 +134,13 @@ glam-assert = [] libm = ["num-traits/libm"] scalar-math = [] std = [] -transform-types = [] + [target."cfg(not(target_arch = \"wasm32\"))".dev-dependencies.criterion] version = "0.3" features = ["html_reports"] + [target."cfg(target_arch = \"wasm32\")".dev-dependencies.wasm-bindgen-test] version = "0.3.0" + [badges.maintenance] status = "actively-developed" diff --git a/Cargo.toml.orig b/Cargo.toml.orig index 2935e65..f145c6e 100644 --- a/Cargo.toml.orig +++ b/Cargo.toml.orig @@ -1,7 +1,7 @@ [package] name = "glam" -version = "0.20.3" # remember to update html_root_url -edition = "2018" +version = "0.22.0" # remember to update html_root_url +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"] @@ -43,13 +41,16 @@ cuda = [] # the end binary build instead. fast-math = [] +# experimental nightly portable-simd support +core-simd = [] + [dependencies] approx = { version = "0.5", optional = true, default-features = false } bytemuck = { version = "1.5", optional = true, default-features = false } mint = { version = "0.5.8", optional = true, default-features = false } num-traits = { version = "0.2.14", optional = true, default-features = false } rand = { version = "0.8", optional = true, default-features = false } -serde = { version = "1.0", optional = true, features = ["derive"] } +serde = { version = "1.0", optional = true, default-features = false, features = ["derive"] } rkyv = { version = "0.7", optional = true } bytecheck = { version = "0.6", optional = true, default-features = false} @@ -95,11 +96,6 @@ harness = false name = "quat" harness = false -[[bench]] -name = "transform" -harness = false -required-features = ["transform-types"] - [[bench]] name = "vec2" harness = false @@ -115,3 +111,9 @@ harness = false [[bench]] name = "vec4" harness = false + +[workspace] +members = [ + "codegen", + "test_no_std", +] diff --git a/METADATA b/METADATA index 5a00bef..085b098 100644 --- a/METADATA +++ b/METADATA @@ -1,3 +1,7 @@ +# This project was upgraded with external_updater. +# Usage: tools/external_updater/updater.sh update rust/crates/glam +# For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md + name: "glam" description: "A simple and fast 3D math library for games and graphics" third_party { @@ -7,14 +11,13 @@ third_party { } url { type: ARCHIVE - value: "https://static.crates.io/crates/glam/glam-0.20.3.crate" + value: "https://static.crates.io/crates/glam/glam-0.22.0.crate" } - version: "0.20.3" - # Dual-licensed, using the least restrictive per go/thirdpartylicenses#same. + version: "0.22.0" license_type: NOTICE last_upgrade_date { year: 2022 - month: 4 - day: 11 + month: 12 + day: 12 } } diff --git a/README.md b/README.md index 555159d..3e13cf5 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. @@ -54,10 +54,14 @@ SIMD is supported on `x86`, `x86_64` and `wasm32` targets. `RUSTCFLAGS`. * To enable `simd128` on `wasm32` targets add `-C target-feature=+simd128` to `RUSTFLAGS`. +* Experimental [portable simd] support can be enabled with the `core-simd` + feature. This requires the nightly compiler as it is still unstable in Rust. Note that SIMD on `wasm32` passes tests but has not been benchmarked, performance may or may not be better than scalar math. +[portable simd]: https://doc.rust-lang.org/core/simd/index.html + ### `no_std` support `no_std` support can be enabled by compiling with `--no-default-features` to @@ -66,7 +70,7 @@ defined in `std`. For example: ```toml [dependencies] -glam = { version = "0.20.3", default-features = false, features = ["libm"] } +glam = { version = "0.22", default-features = false, features = ["libm"] } ``` To support both `std` and `no_std` builds in project, you can use the following @@ -80,7 +84,7 @@ std = ["glam/std"] libm = ["glam/libm"] [dependencies] -glam = { version = "0.20.3", default-features = false } +glam = { version = "0.22", default-features = false } ``` ### Optional features @@ -100,11 +104,6 @@ glam = { version = "0.20.3", default-features = false } `scalar-math` feature. It should work between all other builds of `glam`. Endian conversion is currently not supported * [`bytecheck`] - to perform archive validation when using the `rkyv` feature -* [`fast-math`] - By default, glam attempts to provide bit-for-bit identical - results on all platforms. Using this feature will enable platform specific - optimizations that may not be identical to other platforms. **Intermediate - libraries should not use this feature and defer the decision to the final - binary build**. [`approx`]: https://docs.rs/approx [`bytemuck`]: https://docs.rs/bytemuck @@ -123,14 +122,19 @@ glam = { version = "0.20.3", default-features = false } of parameters passed to `glam` to help catch runtime errors * `glam-assert` - adds validation assertions to all builds * `cuda` - forces `glam` types to match expected [cuda alignment] +* `fast-math` - By default, glam attempts to provide bit-for-bit identical + results on all platforms. Using this feature will enable platform specific + optimizations that may not be identical to other platforms. **Intermediate + libraries should not use this feature and defer the decision to the final + binary build**. +* `core-simd` - enables SIMD support via the [portable simd] module. This is an + unstable feature which requires a nightly Rust toolchain and `std` support. [cuda alignment]: https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#built-in-vector-types ### 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 +253,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/support.rs b/benches/support.rs new file mode 100644 index 0000000..3fe5dd7 --- /dev/null +++ b/benches/support.rs @@ -0,0 +1,129 @@ +#![allow(dead_code)] +use core::f32; +use glam::{Mat2, Mat3, Mat3A, Mat4, Quat, Vec2, Vec3, Vec3A, Vec4}; + +pub struct PCG32 { + state: u64, + inc: u64, +} + +impl PCG32 { + pub fn seed(initstate: u64, initseq: u64) -> Self { + let mut rng = PCG32 { + state: 0, + inc: (initseq << 1) | 1, + }; + rng.next_u32(); + rng.state = rng.state.wrapping_add(initstate); + rng.next_u32(); + rng + } + + pub fn default() -> Self { + PCG32::seed(0x853c49e6748fea9b, 0xda3e39cb94b95bdb) + } + + pub fn next_u32(&mut self) -> u32 { + let oldstate = self.state; + self.state = oldstate + .wrapping_mul(6364136223846793005) + .wrapping_add(self.inc | 1); + let xorshifted = ((oldstate >> 18) ^ oldstate) >> 27; + let rot = oldstate >> 59; + ((xorshifted >> rot) | (xorshifted << (rot.wrapping_neg() & 31))) as u32 + } + + pub fn next_f32(&mut self) -> f32 { + (self.next_u32() & 0xffffff) as f32 / 16777216.0 + } +} + +pub fn random_vec2(rng: &mut PCG32) -> Vec2 { + Vec2::new(rng.next_f32(), rng.next_f32()) +} + +pub fn random_vec3(rng: &mut PCG32) -> Vec3 { + Vec3::new(rng.next_f32(), rng.next_f32(), rng.next_f32()) +} + +pub fn random_vec3a(rng: &mut PCG32) -> Vec3A { + Vec3A::new(rng.next_f32(), rng.next_f32(), rng.next_f32()) +} + +pub fn random_vec4(rng: &mut PCG32) -> Vec4 { + Vec4::new( + rng.next_f32(), + rng.next_f32(), + rng.next_f32(), + rng.next_f32(), + ) +} + +pub fn random_nonzero_vec2(rng: &mut PCG32) -> Vec2 { + loop { + let v = random_vec2(rng); + if v.length_squared() > 0.01 { + return v; + } + } +} + +pub fn random_nonzero_vec3(rng: &mut PCG32) -> Vec3 { + loop { + let v = random_vec3(rng); + if v.length_squared() > 0.01 { + return v; + } + } +} + +pub fn random_f32(rng: &mut PCG32) -> f32 { + rng.next_f32() +} + +pub fn random_radians(rng: &mut PCG32) -> f32 { + -f32::consts::PI + rng.next_f32() * 2.0 * f32::consts::PI +} + +pub fn random_quat(rng: &mut PCG32) -> Quat { + let yaw = random_radians(rng); + let pitch = random_radians(rng); + let roll = random_radians(rng); + Quat::from_euler(glam::EulerRot::YXZ, yaw, pitch, roll) +} + +pub fn random_mat2(rng: &mut PCG32) -> Mat2 { + Mat2::from_cols(random_vec2(rng), random_vec2(rng)) +} + +pub fn random_mat3(rng: &mut PCG32) -> Mat3 { + Mat3::from_cols(random_vec3(rng), random_vec3(rng), random_vec3(rng)) +} + +pub fn random_srt_mat3(rng: &mut PCG32) -> Mat3 { + Mat3::from_scale_angle_translation( + random_nonzero_vec2(rng), + random_radians(rng), + random_vec2(rng), + ) +} + +pub fn random_mat3a(rng: &mut PCG32) -> Mat3A { + Mat3A::from_cols(random_vec3a(rng), random_vec3a(rng), random_vec3a(rng)) +} + +pub fn random_srt_mat3a(rng: &mut PCG32) -> Mat3A { + Mat3A::from_scale_angle_translation( + random_nonzero_vec2(rng), + random_radians(rng), + random_vec2(rng), + ) +} + +pub fn random_srt_mat4(rng: &mut PCG32) -> Mat4 { + Mat4::from_scale_rotation_translation( + random_nonzero_vec3(rng), + random_quat(rng), + random_vec3(rng), + ) +} diff --git a/benches/support/mod.rs b/benches/support/mod.rs deleted file mode 100644 index 3fe5dd7..0000000 --- a/benches/support/mod.rs +++ /dev/null @@ -1,129 +0,0 @@ -#![allow(dead_code)] -use core::f32; -use glam::{Mat2, Mat3, Mat3A, Mat4, Quat, Vec2, Vec3, Vec3A, Vec4}; - -pub struct PCG32 { - state: u64, - inc: u64, -} - -impl PCG32 { - pub fn seed(initstate: u64, initseq: u64) -> Self { - let mut rng = PCG32 { - state: 0, - inc: (initseq << 1) | 1, - }; - rng.next_u32(); - rng.state = rng.state.wrapping_add(initstate); - rng.next_u32(); - rng - } - - pub fn default() -> Self { - PCG32::seed(0x853c49e6748fea9b, 0xda3e39cb94b95bdb) - } - - pub fn next_u32(&mut self) -> u32 { - let oldstate = self.state; - self.state = oldstate - .wrapping_mul(6364136223846793005) - .wrapping_add(self.inc | 1); - let xorshifted = ((oldstate >> 18) ^ oldstate) >> 27; - let rot = oldstate >> 59; - ((xorshifted >> rot) | (xorshifted << (rot.wrapping_neg() & 31))) as u32 - } - - pub fn next_f32(&mut self) -> f32 { - (self.next_u32() & 0xffffff) as f32 / 16777216.0 - } -} - -pub fn random_vec2(rng: &mut PCG32) -> Vec2 { - Vec2::new(rng.next_f32(), rng.next_f32()) -} - -pub fn random_vec3(rng: &mut PCG32) -> Vec3 { - Vec3::new(rng.next_f32(), rng.next_f32(), rng.next_f32()) -} - -pub fn random_vec3a(rng: &mut PCG32) -> Vec3A { - Vec3A::new(rng.next_f32(), rng.next_f32(), rng.next_f32()) -} - -pub fn random_vec4(rng: &mut PCG32) -> Vec4 { - Vec4::new( - rng.next_f32(), - rng.next_f32(), - rng.next_f32(), - rng.next_f32(), - ) -} - -pub fn random_nonzero_vec2(rng: &mut PCG32) -> Vec2 { - loop { - let v = random_vec2(rng); - if v.length_squared() > 0.01 { - return v; - } - } -} - -pub fn random_nonzero_vec3(rng: &mut PCG32) -> Vec3 { - loop { - let v = random_vec3(rng); - if v.length_squared() > 0.01 { - return v; - } - } -} - -pub fn random_f32(rng: &mut PCG32) -> f32 { - rng.next_f32() -} - -pub fn random_radians(rng: &mut PCG32) -> f32 { - -f32::consts::PI + rng.next_f32() * 2.0 * f32::consts::PI -} - -pub fn random_quat(rng: &mut PCG32) -> Quat { - let yaw = random_radians(rng); - let pitch = random_radians(rng); - let roll = random_radians(rng); - Quat::from_euler(glam::EulerRot::YXZ, yaw, pitch, roll) -} - -pub fn random_mat2(rng: &mut PCG32) -> Mat2 { - Mat2::from_cols(random_vec2(rng), random_vec2(rng)) -} - -pub fn random_mat3(rng: &mut PCG32) -> Mat3 { - Mat3::from_cols(random_vec3(rng), random_vec3(rng), random_vec3(rng)) -} - -pub fn random_srt_mat3(rng: &mut PCG32) -> Mat3 { - Mat3::from_scale_angle_translation( - random_nonzero_vec2(rng), - random_radians(rng), - random_vec2(rng), - ) -} - -pub fn random_mat3a(rng: &mut PCG32) -> Mat3A { - Mat3A::from_cols(random_vec3a(rng), random_vec3a(rng), random_vec3a(rng)) -} - -pub fn random_srt_mat3a(rng: &mut PCG32) -> Mat3A { - Mat3A::from_scale_angle_translation( - random_nonzero_vec2(rng), - random_radians(rng), - random_vec2(rng), - ) -} - -pub fn random_srt_mat4(rng: &mut PCG32) -> Mat4 { - Mat4::from_scale_rotation_translation( - random_nonzero_vec3(rng), - random_quat(rng), - random_vec3(rng), - ) -} diff --git a/benches/transform.rs b/benches/transform.rs deleted file mode 100644 index 2510397..0000000 --- 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/benches/vec3.rs b/benches/vec3.rs index a8d8b6a..78d5d63 100644 --- a/benches/vec3.rs +++ b/benches/vec3.rs @@ -19,7 +19,7 @@ bench_binop!( #[inline] fn vec3_to_rgb_op(v: Vec3) -> u32 { let (red, green, blue) = (v.min(Vec3::ONE).max(Vec3::ZERO) * 255.0).into(); - ((red as u32) << 16 | (green as u32) << 8 | (blue as u32)).into() + (red as u32) << 16 | (green as u32) << 8 | (blue as u32) } #[inline] diff --git a/build_all_msrv.sh b/build_all_msrv.sh index eea2672..402cf76 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 8ceb4b4..47d82a5 100755 --- a/build_and_test_features.sh +++ b/build_and_test_features.sh @@ -1,28 +1,29 @@ #!/bin/bash -set -e +set -ex # Set of features to build & test. 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 for features in "${FEATURE_SETS[@]}" do - : - cargo build --tests --no-default-features --features="$features" - echo cargo test --no-default-features --features=\"$features\" - cargo test --no-default-features --features="$features" + : + cargo build --tests --no-default-features --features="$features" + cargo test --no-default-features --features="$features" done -pushd test_no_std && cargo check +RUSTFLAGS='-C target-feature=+fma' cargo check + +cargo check -p glam-no_std \ No newline at end of file diff --git a/clippy.toml b/clippy.toml index 829dd1c..ddbdbc1 100644 --- a/clippy.toml +++ b/clippy.toml @@ -1 +1 @@ -msrv = "1.51" +msrv = "1.58" diff --git a/deny.toml b/deny.toml index a9cd9cb..ad8a958 100644 --- a/deny.toml +++ b/deny.toml @@ -1,3 +1,7 @@ +[advisories] +# criterion is currently failing cargo-deny due to serde_cbor being unmaintained +unmaintained = "warn" + [bans] multiple-versions = "deny" deny = [] @@ -10,9 +14,10 @@ skip-tree = [ unlicensed = "deny" allow = [ "Apache-2.0", - "BSD-2-Clause", - "BSD-3-Clause", - "ISC", "MIT", - "MPL-2.0", +] +exceptions = [ + { allow = [ + "Unicode-DFS-2016", + ], name = "unicode-ident" }, ] diff --git a/src/affine2.rs b/src/affine2.rs deleted file mode 100644 index f3b9e3b..0000000 --- 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 afde949..0000000 --- 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 0000000..4e0e725 --- /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 0000000..889a0ed --- /dev/null +++ b/src/bool.rs @@ -0,0 +1,100 @@ +mod bvec2; +mod bvec3; +mod bvec4; + +#[cfg(all(feature = "core-simd", not(feature = "scalar-math")))] +mod coresimd; + +#[cfg(all( + target_feature = "sse2", + not(any(feature = "core-simd", feature = "scalar-math")) +))] +mod sse2; + +#[cfg(all( + target_feature = "simd128", + not(any(feature = "core-simd", feature = "scalar-math")) +))] +mod wasm32; + +#[cfg(not(any( + feature = "scalar-math", + feature = "core-simd", + target_feature = "sse2", + target_feature = "simd128" +),))] +mod scalar; + +pub use bvec2::BVec2; +pub use bvec3::BVec3; +pub use bvec4::BVec4; + +#[cfg(all( + target_feature = "sse2", + not(any(feature = "core-simd", feature = "scalar-math")) +))] +pub use sse2::bvec3a::BVec3A; +#[cfg(all( + target_feature = "sse2", + not(any(feature = "core-simd", feature = "scalar-math")) +))] +pub use sse2::bvec4a::BVec4A; + +#[cfg(all( + target_feature = "simd128", + not(any(feature = "core-simd", feature = "scalar-math")) +))] +pub use wasm32::bvec3a::BVec3A; +#[cfg(all( + target_feature = "simd128", + not(any(feature = "core-simd", feature = "scalar-math")) +))] +pub use wasm32::bvec4a::BVec4A; + +#[cfg(all(feature = "core-simd", not(feature = "scalar-math")))] +pub use coresimd::bvec3a::BVec3A; +#[cfg(all(feature = "core-simd", not(feature = "scalar-math")))] +pub use coresimd::bvec4a::BVec4A; + +#[cfg(not(any( + feature = "scalar-math", + feature = "core-simd", + target_feature = "sse2", + target_feature = "simd128" +),))] +pub use scalar::bvec3a::BVec3A; + +#[cfg(not(any( + feature = "scalar-math", + feature = "core-simd", + target_feature = "sse2", + target_feature = "simd128" +),))] +pub use scalar::bvec4a::BVec4A; + +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(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(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 0000000..e69fcfc --- /dev/null +++ b/src/bool/bvec2.rs @@ -0,0 +1,168 @@ +// Generated from vec_mask.rs.tera template. Edit the template, not the generated file. + +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::ops::*; + +/// A 2-dimensional `bool` vector mask. +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +#[repr(C, align(1))] +pub struct BVec2 { + pub x: bool, + pub y: bool, +} + +const MASK: [u32; 2] = [0, 0xff_ff_ff_ff]; + +impl BVec2 { + /// All false. + pub const FALSE: Self = Self::splat(false); + + /// All true. + pub const TRUE: Self = Self::splat(true); + + /// Creates a new vector mask. + #[inline(always)] + pub const fn new(x: bool, y: bool) -> Self { + Self { x, y } + } + + /// Creates a vector with all elements set to `v`. + #[inline] + pub const fn splat(v: bool) -> Self { + Self::new(v, v) + } + + /// Returns a bitmask with the lowest 2 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 { + Self::FALSE + } +} + +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 BitXor for BVec2 { + type Output = Self; + #[inline] + fn bitxor(self, rhs: Self) -> Self { + Self { + x: self.x ^ rhs.x, + y: self.y ^ rhs.y, + } + } +} + +impl BitXorAssign for BVec2 { + #[inline] + fn bitxor_assign(&mut self, rhs: Self) { + *self = self.bitxor(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 0000000..91331e2 --- /dev/null +++ b/src/bool/bvec3.rs @@ -0,0 +1,184 @@ +// Generated from vec_mask.rs.tera template. Edit the template, not the generated file. + +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::ops::*; + +/// A 3-dimensional `bool` vector mask. +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +#[repr(C, align(1))] +pub struct BVec3 { + pub x: bool, + pub y: bool, + pub z: bool, +} + +const MASK: [u32; 2] = [0, 0xff_ff_ff_ff]; + +impl BVec3 { + /// All false. + pub const FALSE: Self = Self::splat(false); + + /// All true. + pub const TRUE: Self = Self::splat(true); + + /// Creates a new vector mask. + #[inline(always)] + pub const fn new(x: bool, y: bool, z: bool) -> Self { + Self { x, y, z } + } + + /// Creates a vector with all elements set to `v`. + #[inline] + pub const fn splat(v: bool) -> Self { + Self::new(v, v, v) + } + + /// Returns a bitmask with the lowest 3 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 { + Self::FALSE + } +} + +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 BitXor for BVec3 { + type Output = Self; + #[inline] + fn bitxor(self, rhs: Self) -> Self { + Self { + x: self.x ^ rhs.x, + y: self.y ^ rhs.y, + z: self.z ^ rhs.z, + } + } +} + +impl BitXorAssign for BVec3 { + #[inline] + fn bitxor_assign(&mut self, rhs: Self) { + *self = self.bitxor(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 0000000..7754cd4 --- /dev/null +++ b/src/bool/bvec4.rs @@ -0,0 +1,191 @@ +// Generated from vec_mask.rs.tera template. Edit the template, not the generated file. + +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::ops::*; + +/// A 4-dimensional `bool` vector mask. +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +#[repr(C, align(1))] +pub struct BVec4 { + pub x: bool, + pub y: bool, + pub z: bool, + pub w: bool, +} + +const MASK: [u32; 2] = [0, 0xff_ff_ff_ff]; + +impl BVec4 { + /// All false. + pub const FALSE: Self = Self::splat(false); + + /// All true. + pub const TRUE: Self = Self::splat(true); + + /// 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 } + } + + /// Creates a vector with all elements set to `v`. + #[inline] + pub const fn splat(v: bool) -> Self { + Self::new(v, v, v, v) + } + + /// Returns a bitmask with the lowest 4 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 { + Self::FALSE + } +} + +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 BitXor for BVec4 { + type Output = Self; + #[inline] + fn 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, + } + } +} + +impl BitXorAssign for BVec4 { + #[inline] + fn bitxor_assign(&mut self, rhs: Self) { + *self = self.bitxor(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/coresimd.rs b/src/bool/coresimd.rs new file mode 100644 index 0000000..9a9a329 --- /dev/null +++ b/src/bool/coresimd.rs @@ -0,0 +1,2 @@ +pub mod bvec3a; +pub mod bvec4a; diff --git a/src/bool/coresimd/bvec3a.rs b/src/bool/coresimd/bvec3a.rs new file mode 100644 index 0000000..79f3a57 --- /dev/null +++ b/src/bool/coresimd/bvec3a.rs @@ -0,0 +1,204 @@ +// Generated from vec_mask.rs.tera template. Edit the template, not the generated file. + +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::ops::*; + +use core::simd::*; + +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) mask32x4); + +const MASK: [u32; 2] = [0, 0xff_ff_ff_ff]; + +impl BVec3A { + /// All false. + pub const FALSE: Self = Self::splat(false); + + /// All true. + pub const TRUE: Self = Self::splat(true); + + /// 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 + } + } + + /// Creates a vector with all elements set to `v`. + #[inline] + pub const fn splat(v: bool) -> Self { + Self::new(v, v, v) + } + + /// Returns a bitmask with the lowest 3 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.0.to_bitmask() & 0x7) as u32 + } + + /// Returns true if any of the elements are true, false otherwise. + #[inline] + pub fn any(self) -> bool { + self.bitmask() != 0 + } + + /// Returns true if all the elements are true, false otherwise. + #[inline] + pub fn all(self) -> bool { + self.bitmask() == 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 { + Self::FALSE + } +} + +impl PartialEq for BVec3A { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.bitmask().eq(&rhs.bitmask()) + } +} + +impl Eq for BVec3A {} + +impl core::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(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(self.0 | rhs.0) + } +} + +impl BitOrAssign for BVec3A { + #[inline] + fn bitor_assign(&mut self, rhs: Self) { + *self = self.bitor(rhs); + } +} + +impl BitXor for BVec3A { + type Output = Self; + #[inline] + fn bitxor(self, rhs: Self) -> Self { + Self(self.0 ^ rhs.0) + } +} + +impl BitXorAssign for BVec3A { + #[inline] + fn bitxor_assign(&mut self, rhs: Self) { + *self = self.bitxor(rhs); + } +} + +impl Not for BVec3A { + type Output = Self; + #[inline] + fn not(self) -> Self { + Self(!self.0) + } +} + +impl From for mask32x4 { + #[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/coresimd/bvec4a.rs b/src/bool/coresimd/bvec4a.rs new file mode 100644 index 0000000..381ee0b --- /dev/null +++ b/src/bool/coresimd/bvec4a.rs @@ -0,0 +1,216 @@ +// Generated from vec_mask.rs.tera template. Edit the template, not the generated file. + +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::ops::*; + +use core::simd::*; + +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) mask32x4); + +const MASK: [u32; 2] = [0, 0xff_ff_ff_ff]; + +impl BVec4A { + /// All false. + pub const FALSE: Self = Self::splat(false); + + /// All true. + pub const TRUE: Self = Self::splat(true); + + /// 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 + } + } + + /// Creates a vector with all elements set to `v`. + #[inline] + pub const fn splat(v: bool) -> Self { + Self::new(v, v, v, v) + } + + /// Returns a bitmask with the lowest 4 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.0.to_bitmask() as u32 + } + + /// Returns true if any of the elements are true, false otherwise. + #[inline] + pub fn any(self) -> bool { + self.bitmask() != 0 + } + + /// Returns true if all the elements are true, false otherwise. + #[inline] + pub fn all(self) -> bool { + self.bitmask() == 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 { + Self::FALSE + } +} + +impl PartialEq for BVec4A { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.bitmask().eq(&rhs.bitmask()) + } +} + +impl Eq for BVec4A {} + +impl core::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(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(self.0 | rhs.0) + } +} + +impl BitOrAssign for BVec4A { + #[inline] + fn bitor_assign(&mut self, rhs: Self) { + *self = self.bitor(rhs); + } +} + +impl BitXor for BVec4A { + type Output = Self; + #[inline] + fn bitxor(self, rhs: Self) -> Self { + Self(self.0 ^ rhs.0) + } +} + +impl BitXorAssign for BVec4A { + #[inline] + fn bitxor_assign(&mut self, rhs: Self) { + *self = self.bitxor(rhs); + } +} + +impl Not for BVec4A { + type Output = Self; + #[inline] + fn not(self) -> Self { + Self(!self.0) + } +} + +impl From for mask32x4 { + #[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/scalar.rs b/src/bool/scalar.rs new file mode 100644 index 0000000..9a9a329 --- /dev/null +++ b/src/bool/scalar.rs @@ -0,0 +1,2 @@ +pub mod bvec3a; +pub mod bvec4a; diff --git a/src/bool/scalar/bvec3a.rs b/src/bool/scalar/bvec3a.rs new file mode 100644 index 0000000..dbae395 --- /dev/null +++ b/src/bool/scalar/bvec3a.rs @@ -0,0 +1,188 @@ +// Generated from vec_mask.rs.tera template. Edit the template, not the generated file. + +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::ops::*; + +/// A 3-dimensional `u32` vector mask. +#[derive(Clone, Copy)] +#[repr(C, align(16))] +pub struct BVec3A { + pub x: u32, + pub y: u32, + pub z: u32, +} + +const MASK: [u32; 2] = [0, 0xff_ff_ff_ff]; + +impl BVec3A { + /// All false. + pub const FALSE: Self = Self::splat(false); + + /// All true. + pub const TRUE: Self = Self::splat(true); + + /// Creates a new vector mask. + #[inline(always)] + pub const fn new(x: bool, y: bool, z: bool) -> Self { + Self { + x: MASK[x as usize], + y: MASK[y as usize], + z: MASK[z as usize], + } + } + + /// Creates a vector with all elements set to `v`. + #[inline] + pub const fn splat(v: bool) -> Self { + Self::new(v, v, v) + } + + /// Returns a bitmask with the lowest 3 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 & 0x1) | (self.y & 0x1) << 1 | (self.z & 0x1) << 2 + } + + /// Returns true if any of the elements are true, false otherwise. + #[inline] + pub fn any(self) -> bool { + ((self.x | self.y | self.z) & 0x1) != 0 + } + + /// Returns true if all the elements are true, false otherwise. + #[inline] + pub fn all(self) -> bool { + ((self.x & self.y & self.z) & 0x1) != 0 + } + + #[inline] + fn into_bool_array(self) -> [bool; 3] { + [ + (self.x & 0x1) != 0, + (self.y & 0x1) != 0, + (self.z & 0x1) != 0, + ] + } + + #[inline] + fn into_u32_array(self) -> [u32; 3] { + [self.x, self.y, self.z] + } +} + +impl Default for BVec3A { + #[inline] + fn default() -> Self { + Self::FALSE + } +} + +impl BitAnd for BVec3A { + 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 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 { + x: self.x | rhs.x, + y: self.y | rhs.y, + z: self.z | rhs.z, + } + } +} + +impl BitOrAssign for BVec3A { + #[inline] + fn bitor_assign(&mut self, rhs: Self) { + *self = self.bitor(rhs); + } +} + +impl BitXor for BVec3A { + type Output = Self; + #[inline] + fn bitxor(self, rhs: Self) -> Self { + Self { + x: self.x ^ rhs.x, + y: self.y ^ rhs.y, + z: self.z ^ rhs.z, + } + } +} + +impl BitXorAssign for BVec3A { + #[inline] + fn bitxor_assign(&mut self, rhs: Self) { + *self = self.bitxor(rhs); + } +} + +impl Not for BVec3A { + 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 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/scalar/bvec4a.rs b/src/bool/scalar/bvec4a.rs new file mode 100644 index 0000000..c12d127 --- /dev/null +++ b/src/bool/scalar/bvec4a.rs @@ -0,0 +1,196 @@ +// Generated from vec_mask.rs.tera template. Edit the template, not the generated file. + +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::ops::*; + +/// A 4-dimensional `u32` vector mask. +#[derive(Clone, Copy)] +#[repr(C, align(16))] +pub struct BVec4A { + pub x: u32, + pub y: u32, + pub z: u32, + pub w: u32, +} + +const MASK: [u32; 2] = [0, 0xff_ff_ff_ff]; + +impl BVec4A { + /// All false. + pub const FALSE: Self = Self::splat(false); + + /// All true. + pub const TRUE: Self = Self::splat(true); + + /// Creates a new vector mask. + #[inline(always)] + pub const fn new(x: bool, y: bool, z: bool, w: bool) -> Self { + Self { + x: MASK[x as usize], + y: MASK[y as usize], + z: MASK[z as usize], + w: MASK[w as usize], + } + } + + /// Creates a vector with all elements set to `v`. + #[inline] + pub const fn splat(v: bool) -> Self { + Self::new(v, v, v, v) + } + + /// Returns a bitmask with the lowest 4 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 & 0x1) | (self.y & 0x1) << 1 | (self.z & 0x1) << 2 | (self.w & 0x1) << 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) & 0x1) != 0 + } + + /// Returns true if all the elements are true, false otherwise. + #[inline] + pub fn all(self) -> bool { + ((self.x & self.y & self.z & self.w) & 0x1) != 0 + } + + #[inline] + fn into_bool_array(self) -> [bool; 4] { + [ + (self.x & 0x1) != 0, + (self.y & 0x1) != 0, + (self.z & 0x1) != 0, + (self.w & 0x1) != 0, + ] + } + + #[inline] + fn into_u32_array(self) -> [u32; 4] { + [self.x, self.y, self.z, self.w] + } +} + +impl Default for BVec4A { + #[inline] + fn default() -> Self { + Self::FALSE + } +} + +impl BitAnd for BVec4A { + 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 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 { + x: self.x | rhs.x, + y: self.y | rhs.y, + z: self.z | rhs.z, + w: self.w | rhs.w, + } + } +} + +impl BitOrAssign for BVec4A { + #[inline] + fn bitor_assign(&mut self, rhs: Self) { + *self = self.bitor(rhs); + } +} + +impl BitXor for BVec4A { + type Output = Self; + #[inline] + fn 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, + } + } +} + +impl BitXorAssign for BVec4A { + #[inline] + fn bitxor_assign(&mut self, rhs: Self) { + *self = self.bitxor(rhs); + } +} + +impl Not for BVec4A { + 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 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/sse2.rs b/src/bool/sse2.rs new file mode 100644 index 0000000..9a9a329 --- /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 0000000..0fdbdf6 --- /dev/null +++ b/src/bool/sse2/bvec3a.rs @@ -0,0 +1,207 @@ +// Generated from vec_mask.rs.tera template. Edit the template, not the generated file. + +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::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]; + +impl BVec3A { + /// All false. + pub const FALSE: Self = Self::splat(false); + + /// All true. + pub const TRUE: Self = Self::splat(true); + + /// 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 + } + } + + /// Creates a vector with all elements set to `v`. + #[inline] + pub const fn splat(v: bool) -> Self { + Self::new(v, v, v) + } + + /// Returns a bitmask with the lowest 3 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 { + self.bitmask() != 0 + } + + /// Returns true if all the elements are true, false otherwise. + #[inline] + pub fn all(self) -> bool { + self.bitmask() == 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 { + Self::FALSE + } +} + +impl PartialEq for BVec3A { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.bitmask().eq(&rhs.bitmask()) + } +} + +impl Eq for BVec3A {} + +impl core::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 BitXor for BVec3A { + type Output = Self; + #[inline] + fn bitxor(self, rhs: Self) -> Self { + Self(unsafe { _mm_xor_ps(self.0, rhs.0) }) + } +} + +impl BitXorAssign for BVec3A { + #[inline] + fn bitxor_assign(&mut self, rhs: Self) { + *self = self.bitxor(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 0000000..fc9d08c --- /dev/null +++ b/src/bool/sse2/bvec4a.rs @@ -0,0 +1,219 @@ +// Generated from vec_mask.rs.tera template. Edit the template, not the generated file. + +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::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]; + +impl BVec4A { + /// All false. + pub const FALSE: Self = Self::splat(false); + + /// All true. + pub const TRUE: Self = Self::splat(true); + + /// 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 + } + } + + /// Creates a vector with all elements set to `v`. + #[inline] + pub const fn splat(v: bool) -> Self { + Self::new(v, v, v, v) + } + + /// Returns a bitmask with the lowest 4 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 { + self.bitmask() != 0 + } + + /// Returns true if all the elements are true, false otherwise. + #[inline] + pub fn all(self) -> bool { + self.bitmask() == 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 { + Self::FALSE + } +} + +impl PartialEq for BVec4A { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.bitmask().eq(&rhs.bitmask()) + } +} + +impl Eq for BVec4A {} + +impl core::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 BitXor for BVec4A { + type Output = Self; + #[inline] + fn bitxor(self, rhs: Self) -> Self { + Self(unsafe { _mm_xor_ps(self.0, rhs.0) }) + } +} + +impl BitXorAssign for BVec4A { + #[inline] + fn bitxor_assign(&mut self, rhs: Self) { + *self = self.bitxor(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 0000000..9a9a329 --- /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 0000000..755246a --- /dev/null +++ b/src/bool/wasm32/bvec3a.rs @@ -0,0 +1,199 @@ +// Generated from vec_mask.rs.tera template. Edit the template, not the generated file. + +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::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]; + +impl BVec3A { + /// All false. + pub const FALSE: Self = Self::splat(false); + + /// All true. + pub const TRUE: Self = Self::splat(true); + + /// 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, + )) + } + + /// Creates a vector with all elements set to `v`. + #[inline] + pub const fn splat(v: bool) -> Self { + Self::new(v, v, v) + } + + /// Returns a bitmask with the lowest 3 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 { + self.bitmask() != 0 + } + + /// Returns true if all the elements are true, false otherwise. + #[inline] + pub fn all(self) -> bool { + self.bitmask() == 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 { + Self::FALSE + } +} + +impl PartialEq for BVec3A { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.bitmask().eq(&rhs.bitmask()) + } +} + +impl Eq for BVec3A {} + +impl core::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 BitXor for BVec3A { + type Output = Self; + #[inline] + fn bitxor(self, rhs: Self) -> Self { + Self(v128_xor(self.0, rhs.0)) + } +} + +impl BitXorAssign for BVec3A { + #[inline] + fn bitxor_assign(&mut self, rhs: Self) { + *self = self.bitxor(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 0000000..cdec83f --- /dev/null +++ b/src/bool/wasm32/bvec4a.rs @@ -0,0 +1,206 @@ +// Generated from vec_mask.rs.tera template. Edit the template, not the generated file. + +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::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]; + +impl BVec4A { + /// All false. + pub const FALSE: Self = Self::splat(false); + + /// All true. + pub const TRUE: Self = Self::splat(true); + + /// 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], + )) + } + + /// Creates a vector with all elements set to `v`. + #[inline] + pub const fn splat(v: bool) -> Self { + Self::new(v, v, v, v) + } + + /// Returns a bitmask with the lowest 4 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 { + self.bitmask() != 0 + } + + /// Returns true if all the elements are true, false otherwise. + #[inline] + pub fn all(self) -> bool { + self.bitmask() == 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 { + Self::FALSE + } +} + +impl PartialEq for BVec4A { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.bitmask().eq(&rhs.bitmask()) + } +} + +impl Eq for BVec4A {} + +impl core::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 BitXor for BVec4A { + type Output = Self; + #[inline] + fn bitxor(self, rhs: Self) -> Self { + Self(v128_xor(self.0, rhs.0)) + } +} + +impl BitXorAssign for BVec4A { + #[inline] + fn bitxor_assign(&mut self, rhs: Self) { + *self = self.bitxor(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/cast.rs b/src/cast.rs deleted file mode 100644 index 7742260..0000000 --- a/src/cast.rs +++ /dev/null @@ -1,167 +0,0 @@ -use crate::{DMat2, DMat3, DMat4, DQuat, DVec2, DVec3, DVec4}; -use crate::{IVec2, IVec3, IVec4}; -use crate::{Mat2, Mat3, Mat3A, Mat4, Quat, Vec2, Vec3, Vec3A, Vec4}; -use crate::{UVec2, UVec3, UVec4}; -#[cfg(target_feature = "simd128")] -use core::arch::wasm32::v128; -#[cfg(target_arch = "x86")] -use core::arch::x86::*; -#[cfg(target_arch = "x86_64")] -use core::arch::x86_64::*; - -#[repr(C)] -pub union Vec4Cast { - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - pub m128: __m128, - #[cfg(target_feature = "simd128")] - pub v128: v128, - pub fx4: [f32; 4], - pub fx2x2: [[f32; 2]; 2], - pub v4: Vec4, - pub v3a: Vec3A, - pub q: Quat, -} - -#[repr(C)] -pub union Vec3Cast { - pub fx3: [f32; 3], - pub v3: Vec3, -} - -#[repr(C)] -pub union Vec2Cast { - pub fx2: [f32; 2], - pub v2: Vec2, -} - -#[repr(C)] -pub union F32x9Cast { - pub fx3x3: [[f32; 3]; 3], - pub fx9: [f32; 9], -} - -#[repr(C)] -pub union F32x16Cast { - pub fx4x4: [[f32; 4]; 4], - pub fx16: [f32; 16], -} - -#[repr(C)] -pub union Mat4Cast { - pub v4x4: [Vec4; 4], - pub m4: Mat4, -} - -#[repr(C)] -pub union Mat3Cast { - pub v3x3: [Vec3; 3], - pub m3: Mat3, -} - -#[repr(C)] -pub union Mat3ACast { - pub v3x3: [Vec3A; 3], - pub m3: Mat3A, -} - -#[repr(C)] -pub union Mat2Cast { - pub v2x2: [Vec2; 2], - pub m2: Mat2, -} - -#[repr(C)] -pub union DVec4Cast { - pub fx4: [f64; 4], - pub fx2x2: [[f64; 2]; 2], - pub v4: DVec4, - pub q: DQuat, -} - -#[repr(C)] -pub union DVec3Cast { - pub fx3: [f64; 3], - pub v3: DVec3, -} - -#[repr(C)] -pub union DVec2Cast { - pub fx2: [f64; 2], - pub v2: DVec2, -} - -#[repr(C)] -pub union F64x9Cast { - pub fx3x3: [[f64; 3]; 3], - pub fx9: [f64; 9], -} - -#[repr(C)] -pub union F64x16Cast { - pub fx4x4: [[f64; 4]; 4], - pub fx16: [f64; 16], -} - -#[repr(C)] -pub union DMat4Cast { - pub v4x4: [DVec4; 4], - pub m4: DMat4, -} - -#[repr(C)] -pub union DMat3Cast { - pub v3x3: [DVec3; 3], - pub m3: DMat3, -} - -#[repr(C)] -pub union DMat2Cast { - pub v2x2: [DVec2; 2], - pub m2: DMat2, -} - -#[repr(C)] -pub union IVec4Cast { - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - pub m128: __m128i, - #[cfg(target_feature = "simd128")] - pub v128: v128, - pub ix4: [i32; 4], - pub ix2x2: [[i32; 2]; 2], - pub v4: IVec4, -} - -#[repr(C)] -pub union IVec3Cast { - pub ix3: [i32; 3], - pub v3: IVec3, -} - -#[repr(C)] -pub union IVec2Cast { - pub ix2: [i32; 2], - pub v2: IVec2, -} - -#[repr(C)] -pub union UVec4Cast { - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - pub m128: __m128, - #[cfg(target_feature = "simd128")] - pub v128: v128, - pub ux4: [u32; 4], - pub ux2x2: [[u32; 2]; 2], - pub v4: UVec4, -} - -#[repr(C)] -pub union UVec3Cast { - pub ux3: [u32; 3], - pub v3: UVec3, -} - -#[repr(C)] -pub union UVec2Cast { - pub ux2: [u32; 2], - pub v2: UVec2, -} diff --git a/src/core/mod.rs b/src/core/mod.rs deleted file mode 100644 index 8eba6e4..0000000 --- a/src/core/mod.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/mask.rs b/src/core/scalar/mask.rs deleted file mode 100644 index 7745826..0000000 --- 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 34b0211..0000000 --- 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/mod.rs b/src/core/scalar/mod.rs deleted file mode 100644 index 88050c0..0000000 --- a/src/core/scalar/mod.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/quaternion.rs b/src/core/scalar/quaternion.rs deleted file mode 100644 index a483ed1..0000000 --- a/src/core/scalar/quaternion.rs +++ /dev/null @@ -1,87 +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, 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 dot = self.dot(end); - - 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 4712502..0000000 --- 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.min(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/float.rs b/src/core/sse2/float.rs deleted file mode 100644 index 9c3ac8e..0000000 --- a/src/core/sse2/float.rs +++ /dev/null @@ -1,280 +0,0 @@ -#[cfg(target_arch = "x86")] -use core::arch::x86::*; -#[cfg(target_arch = "x86_64")] -use core::arch::x86_64::*; - -macro_rules! const_u32x4 { - ($ux4:expr) => { - unsafe { $crate::cast::UVec4Cast { ux4: $ux4 }.m128 } - }; -} - -const PS_INV_SIGN_MASK: __m128 = const_u32x4!([!0x8000_0000; 4]); -const PS_SIGN_MASK: __m128 = const_u32x4!([0x8000_0000; 4]); -const PS_NO_FRACTION: __m128 = const_f32x4!([8388608.0; 4]); -const PS_NEGATIVE_ZERO: __m128 = const_u32x4!([0x8000_0000; 4]); -const PS_PI: __m128 = const_f32x4!([core::f32::consts::PI; 4]); -const PS_HALF_PI: __m128 = const_f32x4!([core::f32::consts::FRAC_PI_2; 4]); -const PS_SIN_COEFFICIENTS0: __m128 = - const_f32x4!([-0.16666667, 0.008_333_331, -0.00019840874, 2.752_556_2e-6]); -const PS_SIN_COEFFICIENTS1: __m128 = const_f32x4!([ - -2.388_985_9e-8, - -0.16665852, /*Est1*/ - 0.008_313_95, /*Est2*/ - -0.000_185_246_7 /*Est3*/ -]); -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]); - -#[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] -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) -} - -#[inline] -pub(crate) unsafe fn m128_floor(v: __m128) -> __m128 { - // Based on https://github.com/microsoft/DirectXMath `XMVectorFloor` - // To handle NAN, INF and numbers greater than 8388608, use masking - let test = _mm_and_si128(_mm_castps_si128(v), _mm_castps_si128(PS_INV_SIGN_MASK)); - let test = _mm_cmplt_epi32(test, _mm_castps_si128(PS_NO_FRACTION)); - // Truncate - let vint = _mm_cvttps_epi32(v); - let result = _mm_cvtepi32_ps(vint); - let larger = _mm_cmpgt_ps(result, v); - // 0 -> 0, 0xffffffff -> -1.0f - let larger = _mm_cvtepi32_ps(_mm_castps_si128(larger)); - let result = _mm_add_ps(result, larger); - // All numbers less than 8388608 will use the round to int - let result = _mm_and_ps(result, _mm_castsi128_ps(test)); - // All others, use the ORIGINAL value - let test = _mm_andnot_si128(test, _mm_castps_si128(v)); - _mm_or_ps(result, _mm_castsi128_ps(test)) -} - -#[inline] -pub(crate) unsafe fn m128_ceil(v: __m128) -> __m128 { - // Based on https://github.com/microsoft/DirectXMath `XMVectorCeil` - // To handle NAN, INF and numbers greater than 8388608, use masking - let test = _mm_and_si128(_mm_castps_si128(v), _mm_castps_si128(PS_INV_SIGN_MASK)); - let test = _mm_cmplt_epi32(test, _mm_castps_si128(PS_NO_FRACTION)); - // Truncate - let vint = _mm_cvttps_epi32(v); - let result = _mm_cvtepi32_ps(vint); - let smaller = _mm_cmplt_ps(result, v); - // 0 -> 0, 0xffffffff -> -1.0f - let smaller = _mm_cvtepi32_ps(_mm_castps_si128(smaller)); - let result = _mm_sub_ps(result, smaller); - // All numbers less than 8388608 will use the round to int - let result = _mm_and_ps(result, _mm_castsi128_ps(test)); - // All others, use the ORIGINAL value - let test = _mm_andnot_si128(test, _mm_castps_si128(v)); - _mm_or_ps(result, _mm_castsi128_ps(test)) -} - -#[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 - // platform supports it. Otherwise this may break cross-platform determinism. - #[cfg(all(feature = "fast-math", target_feature = "fma"))] - { - _mm_fmadd_ps(a, b, c) - } - - #[cfg(any(not(feature = "fast-math"), not(target_feature = "fma")))] - { - _mm_add_ps(_mm_mul_ps(a, b), c) - } -} - -#[inline(always)] -pub(crate) unsafe fn m128_neg_mul_sub(a: __m128, b: __m128, c: __m128) -> __m128 { - _mm_sub_ps(c, _mm_mul_ps(a, b)) -} - -/// Returns a vector whose components are the corresponding components of Angles modulo 2PI. -#[inline] -pub(crate) unsafe fn m128_mod_angles(angles: __m128) -> __m128 { - // Based on https://github.com/microsoft/DirectXMath `XMVectorModAngles` - let v = _mm_mul_ps(angles, PS_RECIPROCAL_TWO_PI); - let v = m128_round(v); - m128_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) unsafe fn m128_sin(v: __m128) -> __m128 { - // Based on https://github.com/microsoft/DirectXMath `XMVectorSin` - - // 11-degree minimax approximation - - // Force the value within the bounds of pi - let mut x = m128_mod_angles(v); - - // Map in [-pi/2,pi/2] with sin(y) = sin(x). - let sign = _mm_and_ps(x, PS_NEGATIVE_ZERO); - // pi when x >= 0, -pi when x < 0 - let c = _mm_or_ps(PS_PI, sign); - // |x| - let absx = _mm_andnot_ps(sign, x); - let rflx = _mm_sub_ps(c, x); - let comp = _mm_cmple_ps(absx, PS_HALF_PI); - let select0 = _mm_and_ps(comp, x); - let select1 = _mm_andnot_ps(comp, rflx); - x = _mm_or_ps(select0, select1); - - let x2 = _mm_mul_ps(x, x); - - // Compute polynomial approximation - const SC1: __m128 = PS_SIN_COEFFICIENTS1; - let v_constants_b = _mm_shuffle_ps(SC1, SC1, 0b00_00_00_00); - - const SC0: __m128 = PS_SIN_COEFFICIENTS0; - let mut v_constants = _mm_shuffle_ps(SC0, SC0, 0b11_11_11_11); - let mut result = m128_mul_add(v_constants_b, x2, v_constants); - - v_constants = _mm_shuffle_ps(SC0, SC0, 0b10_10_10_10); - result = m128_mul_add(result, x2, v_constants); - - v_constants = _mm_shuffle_ps(SC0, SC0, 0b01_01_01_01); - result = m128_mul_add(result, x2, v_constants); - - v_constants = _mm_shuffle_ps(SC0, SC0, 0b00_00_00_00); - result = m128_mul_add(result, x2, v_constants); - - result = m128_mul_add(result, x2, PS_ONE); - result = _mm_mul_ps(result, x); - - 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 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 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_sse2_m128_sin_angle(a); - a += step; - } -} diff --git a/src/core/sse2/matrix.rs b/src/core/sse2/matrix.rs deleted file mode 100644 index 5850928..0000000 --- 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/mod.rs b/src/core/sse2/mod.rs deleted file mode 100644 index 4b78bfa..0000000 --- a/src/core/sse2/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -mod float; -pub mod matrix; -pub mod quaternion; -pub mod vector; diff --git a/src/core/sse2/quaternion.rs b/src/core/sse2/quaternion.rs deleted file mode 100644 index 6ffea3b..0000000 --- a/src/core/sse2/quaternion.rs +++ /dev/null @@ -1,135 +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, 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(); - - 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 d5380ce..0000000 --- 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 19bf35d..0000000 --- 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/matrix.rs b/src/core/traits/matrix.rs deleted file mode 100644 index f1b00eb..0000000 --- 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/mod.rs b/src/core/traits/mod.rs deleted file mode 100644 index 917ae32..0000000 --- a/src/core/traits/mod.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/projection.rs b/src/core/traits/projection.rs deleted file mode 100644 index bc90b56..0000000 --- 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 8a3836c..0000000 --- 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 bf2b135..0000000 --- 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 16ff5fe..0000000 --- a/src/core/traits/vector.rs +++ /dev/null @@ -1,854 +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()) - } -} - -/// 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 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(); - - if self.perp_dot(other) < T::ZERO { - -angle - } else { - angle - } - } -} - -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/float.rs b/src/core/wasm32/float.rs deleted file mode 100644 index 0bd80b4..0000000 --- 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 d2a280a..0000000 --- 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/mod.rs b/src/core/wasm32/mod.rs deleted file mode 100644 index 23a1dff..0000000 --- a/src/core/wasm32/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -// mod float; -pub mod matrix; -pub mod quaternion; -pub mod vector; diff --git a/src/core/wasm32/quaternion.rs b/src/core/wasm32/quaternion.rs deleted file mode 100644 index 1899ee4..0000000 --- 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 9ecaa77..0000000 --- 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/coresimd.rs b/src/coresimd.rs new file mode 100644 index 0000000..c6a87d5 --- /dev/null +++ b/src/coresimd.rs @@ -0,0 +1,57 @@ +use core::simd::*; + +/// Calculates the vector 3 dot product and returns answer in x lane of f32x4. +#[inline(always)] +pub(crate) fn dot3_in_x(lhs: f32x4, rhs: f32x4) -> f32x4 { + let x2_y2_z2_w2 = lhs * rhs; + let y2_0_0_0 = simd_swizzle!(x2_y2_z2_w2, [1, 0, 0, 0]); + let z2_0_0_0 = simd_swizzle!(x2_y2_z2_w2, [2, 0, 0, 0]); + let x2y2_0_0_0 = x2_y2_z2_w2 + y2_0_0_0; + x2y2_0_0_0 + z2_0_0_0 +} + +/// Calculates the vector 4 dot product and returns answer in x lane of f32x4. +#[inline(always)] +pub(crate) fn dot4_in_x(lhs: f32x4, rhs: f32x4) -> f32x4 { + let x2_y2_z2_w2 = lhs * rhs; + let z2_w2_0_0 = simd_swizzle!(x2_y2_z2_w2, [2, 3, 0, 0]); + let x2z2_y2w2_0_0 = x2_y2_z2_w2 + z2_w2_0_0; + let y2w2_0_0_0 = simd_swizzle!(x2z2_y2w2_0_0, [1, 0, 0, 0]); + x2z2_y2w2_0_0 + y2w2_0_0_0 +} + +#[inline] +pub(crate) fn dot3(lhs: f32x4, rhs: f32x4) -> f32 { + dot3_in_x(lhs, rhs)[0] +} + +#[inline] +pub(crate) fn dot3_into_f32x4(lhs: f32x4, rhs: f32x4) -> f32x4 { + let dot_in_x = dot3_in_x(lhs, rhs); + simd_swizzle!(dot_in_x, [0, 0, 0, 0]) +} + +#[inline] +pub(crate) fn dot4(lhs: f32x4, rhs: f32x4) -> f32 { + dot4_in_x(lhs, rhs)[0] +} + +#[inline] +pub(crate) fn dot4_into_f32x4(lhs: f32x4, rhs: f32x4) -> f32x4 { + let dot_in_x = dot4_in_x(lhs, rhs); + simd_swizzle!(dot_in_x, [0, 0, 0, 0]) +} + +#[inline(always)] +pub(crate) fn f32x4_bitand(a: f32x4, b: f32x4) -> f32x4 { + let a = a.to_bits(); + let b = b.to_bits(); + f32x4::from_bits(a & b) +} + +#[inline(always)] +pub(crate) fn f32x4_bitxor(a: f32x4, b: f32x4) -> f32x4 { + let a = a.to_bits(); + let b = b.to_bits(); + f32x4::from_bits(a ^ b) +} diff --git a/src/deref.rs b/src/deref.rs new file mode 100644 index 0000000..34361f4 --- /dev/null +++ b/src/deref.rs @@ -0,0 +1,50 @@ +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, 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, Eq, PartialOrd)] +#[cfg_attr(target_arch = "spirv", repr(simd))] +#[cfg_attr(not(target_arch = "spirv"), repr(C))] +pub struct Vec3 { + pub x: T, + pub y: T, + pub z: T, +} + +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd)] +#[cfg_attr(target_arch = "spirv", repr(simd))] +#[cfg_attr(not(target_arch = "spirv"), repr(C))] +pub struct Vec4 { + pub x: T, + pub y: T, + pub z: T, + pub w: T, +} + +#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd)] +#[cfg_attr(not(target_arch = "spirv"), repr(C))] +pub struct Cols2 { + pub x_axis: V, + pub y_axis: V, +} + +#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd)] +#[cfg_attr(not(target_arch = "spirv"), repr(C))] +pub struct Cols3 { + pub x_axis: V, + pub y_axis: V, + pub z_axis: V, +} + +#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd)] +#[cfg_attr(not(target_arch = "spirv"), repr(C))] +pub struct Cols4 { + 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 558400a..c97a962 100644 --- a/src/euler.rs +++ b/src/euler.rs @@ -4,8 +4,11 @@ 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(feature = "libm")] +#[allow(unused_imports)] +use num_traits::Float; /// Euler rotation sequences. /// @@ -13,9 +16,8 @@ use crate::core::traits::scalar::*; /// E.g. XYZ will first apply the z-axis rotation. /// /// YXZ can be used for yaw (y-axis), pitch (x-axis), roll (z-axis). -/// -/// The two-axis rotations (e.g. ZYZ) are not fully tested and have to be treated with caution. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub enum EulerRot { /// Intrinsic three-axis rotation ZYX ZYX, @@ -29,25 +31,6 @@ pub enum EulerRot { XYZ, /// Intrinsic three-axis rotation XZY XZY, - - /// Intrinsic two-axis rotation ZYZ - #[deprecated(note = "Untested! Use at own risk!")] - ZYZ, - /// Intrinsic two-axis rotation ZXZ - #[deprecated(note = "Untested! Use at own risk!")] - ZXZ, - /// Intrinsic two-axis rotation YXY - #[deprecated(note = "Untested! Use at own risk!")] - YXY, - /// Intrinsic two-axis rotation YZY - #[deprecated(note = "Untested! Use at own risk!")] - YZY, - /// Intrinsic two-axis rotation XYX - #[deprecated(note = "Untested! Use at own risk!")] - XYX, - /// Intrinsic two-axis rotation XZX - #[deprecated(note = "Untested! Use at own risk!")] - XZX, } impl Default for EulerRot { @@ -58,8 +41,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 +57,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 +65,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 +87,18 @@ 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)), - #[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)), - #[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)), - #[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)), - #[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)), - #[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)), } } @@ -142,66 +107,35 @@ 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(), - #[allow(deprecated)] - ZYZ => arc_clamp(q.w * q.w - q.x * q.x - q.y * q.y + q.z * q.z).acos(), - #[allow(deprecated)] - ZXZ => arc_clamp(q.w * q.w - q.x * q.x - q.y * q.y + q.z * q.z).acos(), - #[allow(deprecated)] - YXY => arc_clamp(q.w * q.w - q.x * q.x + q.y * q.y - q.z * q.z).acos(), - #[allow(deprecated)] - YZY => arc_clamp(q.w * q.w - q.x * q.x + q.y * q.y - q.z * q.z).acos(), - #[allow(deprecated)] - XYX => arc_clamp(q.w * q.w + q.x * q.x - q.y * q.y - q.z * q.z).acos(), - #[allow(deprecated)] - XZX => arc_clamp(q.w * q.w + q.x * q.x - q.y * q.y - q.z * q.z).acos(), + 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(), } } fn third(self, q: $quat) -> $t { 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)), - #[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)), - #[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)), - #[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)), - #[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)), - #[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)), } } } @@ -235,18 +169,6 @@ macro_rules! impl_to_quat { YZX => rot_y(u) * rot_z(v) * rot_x(w), XYZ => rot_x(u) * rot_y(v) * rot_z(w), XZY => rot_x(u) * rot_z(v) * rot_y(w), - #[allow(deprecated)] - ZYZ => rot_z(u) * rot_y(v) * rot_z(w), - #[allow(deprecated)] - ZXZ => rot_z(u) * rot_x(v) * rot_z(w), - #[allow(deprecated)] - YXY => rot_y(u) * rot_x(v) * rot_y(w), - #[allow(deprecated)] - YZY => rot_y(u) * rot_z(v) * rot_y(w), - #[allow(deprecated)] - XYX => rot_x(u) * rot_y(v) * rot_x(w), - #[allow(deprecated)] - XZX => rot_x(u) * rot_z(v) * rot_x(w), } .normalize() } diff --git a/src/f32.rs b/src/f32.rs new file mode 100644 index 0000000..2076bd4 --- /dev/null +++ b/src/f32.rs @@ -0,0 +1,165 @@ +mod affine2; +mod affine3a; +mod mat3; +mod vec2; +mod vec3; + +#[cfg(all(feature = "core-simd", not(feature = "scalar-math")))] +mod coresimd; + +#[cfg(any( + not(any( + feature = "core-simd", + target_feature = "sse2", + target_feature = "simd128" + )), + feature = "scalar-math" +))] +mod scalar; + +#[cfg(all( + target_feature = "sse2", + not(any(feature = "core-simd", feature = "scalar-math")) +))] +mod sse2; + +#[cfg(all( + target_feature = "simd128", + not(any(feature = "core-simd", feature = "scalar-math")) +))] +mod wasm32; + +#[cfg(any( + not(any( + feature = "core-simd", + target_feature = "sse2", + target_feature = "simd128" + )), + feature = "scalar-math" +))] +use scalar::*; + +#[cfg(all( + target_feature = "sse2", + not(any(feature = "core-simd", feature = "scalar-math")) +))] +use sse2::*; + +#[cfg(all( + target_feature = "simd128", + not(any(feature = "core-simd", feature = "scalar-math")) +))] +use wasm32::*; + +#[cfg(all(feature = "core-simd", not(feature = "scalar-math")))] +use coresimd::*; + +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(not(target_arch = "spirv"))] +mod test { + use super::*; + + #[cfg(all(not(feature = "cuda"), feature = "scalar-math"))] + 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(feature = "scalar-math"))] + 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(feature = "scalar-math")] + 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(feature = "scalar-math")] + 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(feature = "scalar-math", not(feature = "cuda")))] + const_assert_eq!( + core::mem::align_of::(), + core::mem::align_of::() + ); + #[cfg(not(feature = "scalar-math"))] + 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 0000000..c2a438e --- /dev/null +++ b/src/f32/affine2.rs @@ -0,0 +1,398 @@ +// Generated from affine.rs.tera template. Edit the template, not the generated file. + +use crate::{Mat2, Mat3, Mat3A, Vec2, Vec3A}; +use core::ops::{Deref, DerefMut, Mul}; + +/// 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. + #[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. + #[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(), + } + } + + /// The given `Mat3A` must be an affine transform, + #[inline] + pub fn from_mat3a(m: Mat3A) -> 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::Cols3; + #[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 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 0000000..40cc66e --- /dev/null +++ b/src/f32/affine3a.rs @@ -0,0 +1,531 @@ +// Generated from affine.rs.tera template. Edit the template, not the generated file. + +use crate::{Mat3, Mat3A, Mat4, Quat, Vec3, Vec3A}; +use core::ops::{Deref, DerefMut, Mul}; + +/// 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. + #[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. + #[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(feature = "libm")] + #[allow(unused_imports)] + use num_traits::Float; + + 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()) + } + + /// Creates a left-handed view transform using a camera position, an up direction, and a facing + /// direction. + /// + /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=forward`. + #[inline] + pub fn look_to_lh(eye: Vec3, dir: Vec3, up: Vec3) -> Self { + Self::look_to_rh(eye, -dir, up) + } + + /// Creates a right-handed view transform using a camera position, an up direction, and a facing + /// direction. + /// + /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=back`. + #[inline] + pub fn look_to_rh(eye: Vec3, dir: Vec3, up: Vec3) -> Self { + let f = dir.normalize(); + let s = f.cross(up).normalize(); + let u = s.cross(f); + + 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(-eye.dot(s), -eye.dot(u), eye.dot(f)), + } + } + + /// 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_rh(eye, center - eye, 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_point3a`] 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::Cols4; + #[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 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/coresimd.rs b/src/f32/coresimd.rs new file mode 100644 index 0000000..24171e5 --- /dev/null +++ b/src/f32/coresimd.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/coresimd/mat2.rs b/src/f32/coresimd/mat2.rs new file mode 100644 index 0000000..200aa52 --- /dev/null +++ b/src/f32/coresimd/mat2.rs @@ -0,0 +1,478 @@ +// Generated from mat.rs.tera template. Edit the template, not the generated file. + +use crate::{swizzles::*, DMat2, Mat3, Mat3A, 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::simd::{Which::*, *}; + +#[cfg(feature = "libm")] +#[allow(unused_imports)] +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) f32x4); + +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::from_array([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::from_array([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(f32x4::from_array(*m)) + } + + /// 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 const fn to_cols_array(&self) -> [f32; 4] { + unsafe { *(self as *const Self as *const [f32; 4]) } + } + + /// 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 const fn to_cols_array_2d(&self) -> [[f32; 2]; 2] { + unsafe { *(self as *const Self as *const [[f32; 2]; 2]) } + } + + /// Creates a 2x2 matrix with its diagonal set to `diagonal` and all other entries set to 0. + #[doc(alias = "scale")] + #[inline] + pub const 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 a 3x3 matrix, discarding the 2nd row and column. + #[inline] + pub fn from_mat3a(m: Mat3A) -> 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(simd_swizzle!(self.0, [0, 2, 1, 3])) + } + + /// Returns the determinant of `self`. + #[inline] + pub fn determinant(&self) -> f32 { + let abcd = self.0; + let dcba = simd_swizzle!(abcd, [3, 2, 1, 0]); + let prod = abcd * dcba; + let det = prod - simd_swizzle!(prod, [1, 1, 1, 1]); + det[0] + } + + /// 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] + pub fn inverse(&self) -> Self { + const SIGN: f32x4 = f32x4::from_array([1.0, -1.0, -1.0, 1.0]); + let abcd = self.0; + let dcba = simd_swizzle!(abcd, [3, 2, 1, 0]); + let prod = abcd * dcba; + let sub = prod - simd_swizzle!(prod, [1, 1, 1, 1]); + let det = simd_swizzle!(sub, [0, 0, 0, 0]); + let tmp = SIGN / det; + glam_assert!(Mat2(tmp).is_finite()); + let dbca = simd_swizzle!(abcd, [3, 1, 2, 0]); + Self(dbca.mul(tmp)) + } + + /// Transforms a 2D vector. + #[inline] + pub fn mul_vec2(&self, rhs: Vec2) -> Vec2 { + let abcd = self.0; + let xxyy = f32x4::from_array([rhs.x, rhs.x, rhs.y, rhs.y]); + let axbxcydy = abcd.mul(xxyy); + let cydyaxbx = simd_swizzle!(axbxcydy, [2, 3, 0, 1]); + let result = axbxcydy.add(cydyaxbx); + unsafe { *(&result as *const f32x4 as *const Vec2) } + } + + /// Multiplies two 2x2 matrices. + #[inline] + pub fn mul_mat2(&self, rhs: &Self) -> Self { + let abcd = self.0; + let xxyy0 = simd_swizzle!(rhs.0, [0, 0, 1, 1]); + let xxyy1 = simd_swizzle!(rhs.0, [2, 2, 3, 3]); + let axbxcydy0 = abcd * xxyy0; + let axbxcydy1 = abcd * xxyy1; + let cydyaxbx0 = simd_swizzle!(axbxcydy0, [2, 3, 0, 1]); + let cydyaxbx1 = simd_swizzle!(axbxcydy1, [2, 3, 0, 1]); + let result0 = axbxcydy0 + cydyaxbx0; + let result1 = axbxcydy1 + cydyaxbx1; + Self(simd_swizzle!( + result0, + result1, + [First(0), First(1), Second(0), Second(1)] + )) + } + + /// Adds two 2x2 matrices. + #[inline] + pub fn add_mat2(&self, rhs: &Self) -> Self { + Self(self.0 + rhs.0) + } + + /// Subtracts two 2x2 matrices. + #[inline] + pub fn sub_mat2(&self, rhs: &Self) -> Self { + Self(self.0 - rhs.0) + } + + /// Multiplies a 2x2 matrix by a scalar. + #[inline] + pub fn mul_scalar(&self, rhs: f32) -> Self { + Self(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(-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 Sum for Mat2 { + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, Self::add) + } +} + +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 Product for Mat2 { + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::IDENTITY, Self::mul) + } +} + +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::Cols2; + #[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/coresimd/mat3a.rs b/src/f32/coresimd/mat3a.rs new file mode 100644 index 0000000..bda6d27 --- /dev/null +++ b/src/f32/coresimd/mat3a.rs @@ -0,0 +1,747 @@ +// Generated from mat.rs.tera 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::simd::{Which::*, *}; + +#[cfg(feature = "libm")] +#[allow(unused_imports)] +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)] +#[repr(C)] +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 const fn to_cols_array(&self) -> [f32; 9] { + let [x_axis_x, x_axis_y, x_axis_z] = self.x_axis.to_array(); + let [y_axis_x, y_axis_y, y_axis_z] = self.y_axis.to_array(); + let [z_axis_x, z_axis_y, z_axis_z] = self.z_axis.to_array(); + + [ + 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, + ] + } + + /// 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 const 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 const 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 4th 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 = simd_swizzle!( + self.x_axis.0, + self.y_axis.0, + [First(0), First(1), Second(0), Second(1)] + ); + let tmp1 = simd_swizzle!( + self.x_axis.0, + self.y_axis.0, + [First(2), First(3), Second(2), Second(3)] + ); + + Self { + x_axis: Vec3A(simd_swizzle!( + tmp0, + self.z_axis.0, + [First(0), First(2), Second(0), Second(0)] + )), + y_axis: Vec3A(simd_swizzle!( + tmp0, + self.z_axis.0, + [First(1), First(3), Second(1), Second(1)] + )), + z_axis: Vec3A(simd_swizzle!( + tmp1, + self.z_axis.0, + [First(0), First(2), Second(2), Second(2)] + )), + } + } + + /// Returns the determinant of `self`. + #[inline] + 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] + #[inline] + 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. + /// + /// # Panics + /// + /// Will panic if the 2nd row of `self` is not `(0, 0, 1)` when `glam_assert` is enabled. + #[inline] + pub fn transform_point2(&self, rhs: Vec2) -> Vec2 { + glam_assert!(self.row(2).abs_diff_eq(Vec3A::Z, 1e-6)); + 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. + /// + /// # Panics + /// + /// Will panic if the 2nd row of `self` is not `(0, 0, 1)` when `glam_assert` is enabled. + #[inline] + pub fn transform_vector2(&self, rhs: Vec2) -> Vec2 { + glam_assert!(self.row(2).abs_diff_eq(Vec3A::Z, 1e-6)); + 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 Sum for Mat3A { + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, Self::add) + } +} + +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 Product for Mat3A { + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::IDENTITY, Self::mul) + } +} + +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/coresimd/mat4.rs b/src/f32/coresimd/mat4.rs new file mode 100644 index 0000000..26239ba --- /dev/null +++ b/src/f32/coresimd/mat4.rs @@ -0,0 +1,1506 @@ +// Generated from mat.rs.tera template. Edit the template, not the generated file. + +use crate::{coresimd::*, swizzles::*, DMat4, EulerRot, Mat3, Mat3A, 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::simd::{Which::*, *}; + +#[cfg(feature = "libm")] +#[allow(unused_imports)] +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)] +#[repr(C)] +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 const fn to_cols_array(&self) -> [f32; 16] { + let [x_axis_x, x_axis_y, x_axis_z, x_axis_w] = self.x_axis.to_array(); + let [y_axis_x, y_axis_y, y_axis_z, y_axis_w] = self.y_axis.to_array(); + let [z_axis_x, z_axis_y, z_axis_z, z_axis_w] = self.z_axis.to_array(); + let [w_axis_x, w_axis_y, w_axis_z, w_axis_w] = self.w_axis.to_array(); + + [ + 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, + ] + } + + /// 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 const 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 const fn from_diagonal(diagonal: Vec4) -> Self { + // diagonal.x, diagonal.y etc can't be done in a const-context + let [x, y, z, w] = diagonal.to_array(); + Self::new( + x, 0.0, 0.0, 0.0, 0.0, y, 0.0, 0.0, 0.0, 0.0, z, 0.0, 0.0, 0.0, 0.0, w, + ) + } + + #[inline] + 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 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_mat3a(m: Mat3A) -> 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 = simd_swizzle!( + self.x_axis.0, + self.y_axis.0, + [First(0), First(1), Second(0), Second(1)] + ); + let tmp1 = simd_swizzle!( + self.x_axis.0, + self.y_axis.0, + [First(2), First(3), Second(2), Second(3)] + ); + let tmp2 = simd_swizzle!( + self.z_axis.0, + self.w_axis.0, + [First(0), First(1), Second(0), Second(1)] + ); + let tmp3 = simd_swizzle!( + self.z_axis.0, + self.w_axis.0, + [First(2), First(3), Second(2), Second(3)] + ); + + Self { + x_axis: Vec4(simd_swizzle!( + tmp0, + tmp2, + [First(0), First(2), Second(0), Second(2)] + )), + y_axis: Vec4(simd_swizzle!( + tmp0, + tmp2, + [First(1), First(3), Second(1), Second(3)] + )), + z_axis: Vec4(simd_swizzle!( + tmp1, + tmp3, + [First(0), First(2), Second(0), Second(2)] + )), + w_axis: Vec4(simd_swizzle!( + tmp1, + tmp3, + [First(1), First(3), Second(1), Second(3)] + )), + } + } + + /// Returns the determinant of `self`. + pub fn determinant(&self) -> f32 { + // Based on https://github.com/g-truc/glm `glm_mat4_determinant` + let swp2a = simd_swizzle!(self.z_axis.0, [2, 1, 1, 0]); + let swp3a = simd_swizzle!(self.w_axis.0, [3, 3, 2, 3]); + let swp2b = simd_swizzle!(self.z_axis.0, [3, 3, 2, 3]); + let swp3b = simd_swizzle!(self.w_axis.0, [2, 1, 1, 0]); + let swp2c = simd_swizzle!(self.z_axis.0, [2, 1, 0, 0]); + let swp3c = simd_swizzle!(self.w_axis.0, [0, 0, 2, 1]); + + let mula = swp2a * swp3a; + let mulb = swp2b * swp3b; + let mulc = swp2c * swp3c; + let sube = mula - mulb; + let subf = simd_swizzle!(mulc, [2, 3, 2, 3]) - mulc; + + let subfaca = simd_swizzle!(sube, [0, 0, 1, 2]); + let swpfaca = simd_swizzle!(self.y_axis.0, [1, 0, 0, 0]); + let mulfaca = swpfaca * subfaca; + + let subtmpb = simd_swizzle!(sube, subf, [First(1), First(3), Second(0), Second(0)]); + let subfacb = simd_swizzle!(subtmpb, [0, 1, 1, 3]); + let swpfacb = simd_swizzle!(self.y_axis.0, [2, 2, 1, 1]); + let mulfacb = swpfacb * subfacb; + + let subres = mulfaca - mulfacb; + let subtmpc = simd_swizzle!(sube, subf, [First(2), First(2), Second(0), Second(1)]); + let subfacc = simd_swizzle!(subtmpc, [0, 2, 3, 3]); + let swpfacc = simd_swizzle!(self.y_axis.0, [3, 3, 3, 2]); + let mulfacc = swpfacc * subfacc; + + let addres = subres + mulfacc; + let detcof = addres * f32x4::from_array([1.0, -1.0, 1.0, -1.0]); + + 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 = simd_swizzle!( + self.w_axis.0, + self.z_axis.0, + [First(3), First(3), Second(3), Second(3)] + ); + let swp0b = simd_swizzle!( + self.w_axis.0, + self.z_axis.0, + [First(2), First(2), Second(2), Second(2)] + ); + + let swp00 = simd_swizzle!( + self.z_axis.0, + self.y_axis.0, + [First(2), First(2), Second(2), Second(2)] + ); + let swp01 = simd_swizzle!(swp0a, [0, 0, 0, 2]); + let swp02 = simd_swizzle!(swp0b, [0, 0, 0, 2]); + let swp03 = simd_swizzle!( + self.z_axis.0, + self.y_axis.0, + [First(3), First(3), Second(3), Second(3)] + ); + + let mul00 = swp00 * swp01; + let mul01 = swp02 * swp03; + mul00 - mul01 + }; + let fac1 = { + let swp0a = simd_swizzle!( + self.w_axis.0, + self.z_axis.0, + [First(3), First(3), Second(3), Second(3)] + ); + let swp0b = simd_swizzle!( + self.w_axis.0, + self.z_axis.0, + [First(1), First(1), Second(1), Second(1)] + ); + + let swp00 = simd_swizzle!( + self.z_axis.0, + self.y_axis.0, + [First(1), First(1), Second(1), Second(1)] + ); + let swp01 = simd_swizzle!(swp0a, [0, 0, 0, 2]); + let swp02 = simd_swizzle!(swp0b, [0, 0, 0, 2]); + let swp03 = simd_swizzle!( + self.z_axis.0, + self.y_axis.0, + [First(3), First(3), Second(3), Second(3)] + ); + + let mul00 = swp00 * swp01; + let mul01 = swp02 * swp03; + mul00 - mul01 + }; + let fac2 = { + let swp0a = simd_swizzle!( + self.w_axis.0, + self.z_axis.0, + [First(2), First(2), Second(2), Second(2)] + ); + let swp0b = simd_swizzle!( + self.w_axis.0, + self.z_axis.0, + [First(1), First(1), Second(1), Second(1)] + ); + + let swp00 = simd_swizzle!( + self.z_axis.0, + self.y_axis.0, + [First(1), First(1), Second(1), Second(1)] + ); + let swp01 = simd_swizzle!(swp0a, [0, 0, 0, 2]); + let swp02 = simd_swizzle!(swp0b, [0, 0, 0, 2]); + let swp03 = simd_swizzle!( + self.z_axis.0, + self.y_axis.0, + [First(2), First(2), Second(2), Second(2)] + ); + + let mul00 = swp00 * swp01; + let mul01 = swp02 * swp03; + mul00 - mul01 + }; + let fac3 = { + let swp0a = simd_swizzle!( + self.w_axis.0, + self.z_axis.0, + [First(3), First(3), Second(3), Second(3)] + ); + let swp0b = simd_swizzle!( + self.w_axis.0, + self.z_axis.0, + [First(0), First(0), Second(0), Second(0)] + ); + + let swp00 = simd_swizzle!( + self.z_axis.0, + self.y_axis.0, + [First(0), First(0), Second(0), Second(0)] + ); + let swp01 = simd_swizzle!(swp0a, [0, 0, 0, 2]); + let swp02 = simd_swizzle!(swp0b, [0, 0, 0, 2]); + let swp03 = simd_swizzle!( + self.z_axis.0, + self.y_axis.0, + [First(3), First(3), Second(3), Second(3)] + ); + + let mul00 = swp00 * swp01; + let mul01 = swp02 * swp03; + mul00 - mul01 + }; + let fac4 = { + let swp0a = simd_swizzle!( + self.w_axis.0, + self.z_axis.0, + [First(2), First(2), Second(2), Second(2)] + ); + let swp0b = simd_swizzle!( + self.w_axis.0, + self.z_axis.0, + [First(0), First(0), Second(0), Second(0)] + ); + + let swp00 = simd_swizzle!( + self.z_axis.0, + self.y_axis.0, + [First(0), First(0), Second(0), Second(0)] + ); + let swp01 = simd_swizzle!(swp0a, [0, 0, 0, 2]); + let swp02 = simd_swizzle!(swp0b, [0, 0, 0, 2]); + let swp03 = simd_swizzle!( + self.z_axis.0, + self.y_axis.0, + [First(2), First(2), Second(2), Second(2)] + ); + + let mul00 = swp00 * swp01; + let mul01 = swp02 * swp03; + mul00 - mul01 + }; + let fac5 = { + let swp0a = simd_swizzle!( + self.w_axis.0, + self.z_axis.0, + [First(1), First(1), Second(1), Second(1)] + ); + let swp0b = simd_swizzle!( + self.w_axis.0, + self.z_axis.0, + [First(0), First(0), Second(0), Second(0)] + ); + + let swp00 = simd_swizzle!( + self.z_axis.0, + self.y_axis.0, + [First(0), First(0), Second(0), Second(0)] + ); + let swp01 = simd_swizzle!(swp0a, [0, 0, 0, 2]); + let swp02 = simd_swizzle!(swp0b, [0, 0, 0, 2]); + let swp03 = simd_swizzle!( + self.z_axis.0, + self.y_axis.0, + [First(1), First(1), Second(1), Second(1)] + ); + + let mul00 = swp00 * swp01; + let mul01 = swp02 * swp03; + mul00 - mul01 + }; + let sign_a = f32x4::from_array([-1.0, 1.0, -1.0, 1.0]); + let sign_b = f32x4::from_array([1.0, -1.0, 1.0, -1.0]); + + let temp0 = simd_swizzle!( + self.y_axis.0, + self.x_axis.0, + [First(0), First(0), Second(0), Second(0)] + ); + let vec0 = simd_swizzle!(temp0, [0, 2, 2, 2]); + + let temp1 = simd_swizzle!( + self.y_axis.0, + self.x_axis.0, + [First(1), First(1), Second(1), Second(1)] + ); + let vec1 = simd_swizzle!(temp1, [0, 2, 2, 2]); + + let temp2 = simd_swizzle!( + self.y_axis.0, + self.x_axis.0, + [First(2), First(2), Second(2), Second(2)] + ); + let vec2 = simd_swizzle!(temp2, [0, 2, 2, 2]); + + let temp3 = simd_swizzle!( + self.y_axis.0, + self.x_axis.0, + [First(3), First(3), Second(3), Second(3)] + ); + let vec3 = simd_swizzle!(temp3, [0, 2, 2, 2]); + + let mul00 = vec1 * fac0; + let mul01 = vec2 * fac1; + let mul02 = vec3 * fac2; + let sub00 = mul00 - mul01; + let add00 = sub00 + mul02; + let inv0 = sign_b * add00; + + let mul03 = vec0 * fac0; + let mul04 = vec2 * fac3; + let mul05 = vec3 * fac4; + let sub01 = mul03 - mul04; + let add01 = sub01 + mul05; + let inv1 = sign_a * add01; + + let mul06 = vec0 * fac1; + let mul07 = vec1 * fac3; + let mul08 = vec3 * fac5; + let sub02 = mul06 - mul07; + let add02 = sub02 + mul08; + let inv2 = sign_b * add02; + + let mul09 = vec0 * fac2; + let mul10 = vec1 * fac4; + let mul11 = vec2 * fac5; + let sub03 = mul09 - mul10; + let add03 = sub03 + mul11; + let inv3 = sign_a * add03; + + let row0 = simd_swizzle!(inv0, inv1, [First(0), First(0), Second(0), Second(0)]); + let row1 = simd_swizzle!(inv2, inv3, [First(0), First(0), Second(0), Second(0)]); + let row2 = simd_swizzle!(row0, row1, [First(0), First(2), Second(0), Second(2)]); + + let dot0 = dot4(self.x_axis.0, row2); + glam_assert!(dot0 != 0.0); + + let rcp0 = f32x4::splat(dot0.recip()); + + Self { + x_axis: Vec4(inv0 * rcp0), + y_axis: Vec4(inv1 * rcp0), + z_axis: Vec4(inv2 * rcp0), + w_axis: Vec4(inv3 * rcp0), + } + } + + /// Creates a left-handed view matrix using a camera position, an up direction, and a facing + /// direction. + /// + /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=forward`. + #[inline] + pub fn look_to_lh(eye: Vec3, dir: Vec3, up: Vec3) -> Self { + Self::look_to_rh(eye, -dir, up) + } + + /// Creates a right-handed view matrix using a camera position, an up direction, and a facing + /// direction. + /// + /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=back`. + #[inline] + pub fn look_to_rh(eye: Vec3, dir: Vec3, up: Vec3) -> Self { + let f = dir.normalize(); + let s = f.cross(up).normalize(); + let u = s.cross(f); + + 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(-eye.dot(s), -eye.dot(u), eye.dot(f), 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_rh(eye, center.sub(eye), 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).abs_diff_eq(Vec4::W, 1e-6)); + 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).abs_diff_eq(Vec4::W, 1e-6)); + 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 { + glam_assert!(self.row(3).abs_diff_eq(Vec4::W, 1e-6)); + 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 { + glam_assert!(self.row(3).abs_diff_eq(Vec4::W, 1e-6)); + 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 Sum for Mat4 { + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, Self::add) + } +} + +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 Product for Mat4 { + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::IDENTITY, Self::mul) + } +} + +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/coresimd/quat.rs b/src/f32/coresimd/quat.rs new file mode 100644 index 0000000..21aa519 --- /dev/null +++ b/src/f32/coresimd/quat.rs @@ -0,0 +1,917 @@ +// Generated from quat.rs.tera template. Edit the template, not the generated file. + +use crate::{ + coresimd::*, + euler::{EulerFromQuaternion, EulerRot, EulerToQuaternion}, + DQuat, FloatEx, Mat3, Mat3A, Mat4, Vec2, Vec3, Vec3A, Vec4, +}; + +#[cfg(feature = "libm")] +#[allow(unused_imports)] +use num_traits::Float; + +use core::simd::*; + +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::iter::{Product, Sum}; +use core::ops::{Add, Deref, DerefMut, 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) f32x4); + +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::from_array([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(f32x4::from_array(a)) + } + + /// 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` + 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 SIMD aligned rotation matrix. + #[inline] + pub fn from_mat3a(mat: &Mat3A) -> Self { + Self::from_rotation_axes(mat.x_axis.into(), mat.y_axis.into(), mat.z_axis.into()) + } + + /// 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: f32x4 = f32x4::from_array([-1.0, -1.0, -1.0, 1.0]); + Self(self.0.mul(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: f32x4 = f32x4::from_array([-0.0; 4]); + let start = self.0; + let end = end.0; + let dot = dot4_into_f32x4(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 = f32x4_bitand(dot, NEG_ZERO); + let interpolated = start + ((f32x4_bitxor(end, bias) - start) * f32x4::splat(s)); + 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 = (theta * (1.0 - s)).sin(); + let y = (theta * s).sin(); + let z = theta.sin(); + let w = 0.0; + let tmp = f32x4::from_array([x, y, z, w]); + + let scale1 = simd_swizzle!(tmp, [0, 0, 0, 0]); + let scale2 = simd_swizzle!(tmp, [1, 1, 1, 1]); + let theta_sin = simd_swizzle!(tmp, [2, 2, 2, 2]); + + Self(self.0.mul(scale1).add(end.0.mul(scale2)).div(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: f32x4 = f32x4::from_array([1.0, -1.0, 1.0, -1.0]); + const CONTROL_ZWXY: f32x4 = f32x4::from_array([1.0, 1.0, -1.0, -1.0]); + const CONTROL_YXWZ: f32x4 = f32x4::from_array([-1.0, 1.0, 1.0, -1.0]); + + let r_xxxx = simd_swizzle!(lhs, [0, 0, 0, 0]); + let r_yyyy = simd_swizzle!(lhs, [1, 1, 1, 1]); + let r_zzzz = simd_swizzle!(lhs, [2, 2, 2, 2]); + let r_wwww = simd_swizzle!(lhs, [3, 3, 3, 3]); + + let lxrw_lyrw_lzrw_lwrw = r_wwww * rhs; + let l_wzyx = simd_swizzle!(rhs, [3, 2, 1, 0]); + + let lwrx_lzrx_lyrx_lxrx = r_xxxx * l_wzyx; + let l_zwxy = simd_swizzle!(l_wzyx, [1, 0, 3, 2]); + + let lwrx_nlzrx_lyrx_nlxrx = lwrx_lzrx_lyrx_lxrx * CONTROL_WZYX; + + let lzry_lwry_lxry_lyry = r_yyyy * l_zwxy; + let l_yxwz = simd_swizzle!(l_zwxy, [3, 2, 1, 0]); + + let lzry_lwry_nlxry_nlyry = lzry_lwry_lxry_lyry * CONTROL_ZWXY; + + let lyrz_lxrz_lwrz_lzrz = r_zzzz * l_yxwz; + let result0 = lxrw_lyrw_lzrw_lwrw + lwrx_nlzrx_lyrx_nlxrx; + + let nlyrz_lxrz_lwrz_wlzrz = lyrz_lxrz_lwrz_lzrz * CONTROL_YXWZ; + let result1 = lzry_lwry_nlxry_nlyry + nlyrz_lxrz_lwrz_wlzrz; + Self(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: f32x4 = f32x4::from_array([2.0; 4]); + let w = simd_swizzle!(self.0, [3, 3, 3, 3]); + let b = self.0; + let b2 = dot3_into_f32x4(b, b); + Vec3A( + rhs.0 + .mul(w.mul(w).sub(b2)) + .add(b.mul(dot3_into_f32x4(rhs.0, b).mul(TWO))) + .add(Vec3A(b).cross(rhs).0.mul(w.mul(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 Sum for Quat { + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, Self::add) + } +} + +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 Product for Quat { + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::IDENTITY, Self::mul) + } +} + +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 f32x4 { + #[inline] + fn from(q: Quat) -> Self { + q.0 + } +} + +impl Deref for Quat { + type Target = crate::deref::Vec4; + #[inline] + fn deref(&self) -> &Self::Target { + unsafe { &*(self as *const Self).cast() } + } +} + +impl DerefMut for Quat { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { &mut *(self as *mut Self).cast() } + } +} diff --git a/src/f32/coresimd/vec3a.rs b/src/f32/coresimd/vec3a.rs new file mode 100644 index 0000000..adaceb6 --- /dev/null +++ b/src/f32/coresimd/vec3a.rs @@ -0,0 +1,1086 @@ +// Generated from vec.rs.tera template. Edit the template, not the generated file. + +use crate::{coresimd::*, BVec3A, Vec2, Vec3, Vec4}; + +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::iter::{Product, Sum}; +use core::{f32, ops::*}; + +use core::simd::*; +use std::simd::StdFloat; + +#[cfg(feature = "libm")] +#[allow(unused_imports)] +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(transparent)] +pub struct Vec3A(pub(crate) f32x4); + +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); + + /// A unit-length vector pointing along the positive X axis. + pub const X: Self = Self::new(1.0, 0.0, 0.0); + + /// A unit-length vector pointing along the positive Y axis. + pub const Y: Self = Self::new(0.0, 1.0, 0.0); + + /// A unit-length vector pointing along the positive Z axis. + pub const Z: Self = Self::new(0.0, 0.0, 1.0); + + /// A unit-length vector pointing along the negative X axis. + pub const NEG_X: Self = Self::new(-1.0, 0.0, 0.0); + + /// A unit-length vector pointing along the negative Y axis. + pub const NEG_Y: Self = Self::new(0.0, -1.0, 0.0); + + /// A unit-length vector pointing along the negative Z axis. + pub const NEG_Z: Self = Self::new(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::from_array([x, y, z, z])) + } + + /// Creates a vector with all elements set to `v`. + #[inline] + pub const fn splat(v: f32) -> Self { + Self(Simd::from_array([v; 4])) + } + + /// 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(mask.0.select(if_true.0, if_false.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 3 values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 3 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 3 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 { + dot3(self.0, rhs.0) + } + + /// Returns a vector where every component is the dot product of `self` and `rhs`. + #[inline] + pub fn dot_into_vec(self, rhs: Self) -> Self { + Self(unsafe { dot3_into_f32x4(self.0, rhs.0) }) + } + + /// Computes the cross product of `self` and `rhs`. + #[inline] + pub fn cross(self, rhs: Self) -> Self { + let lhszxy = simd_swizzle!(self.0, [2, 0, 1, 1]); + let rhszxy = simd_swizzle!(rhs.0, [2, 0, 1, 1]); + let lhszxy_rhs = lhszxy * rhs.0; + let rhszxy_lhs = rhszxy * self.0; + let sub = lhszxy_rhs - rhszxy_lhs; + Self(simd_swizzle!(sub, [2, 0, 1, 1])) + } + + /// 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(self.0.simd_min(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(self.0.simd_max(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 = v.simd_min(simd_swizzle!(v, [2, 2, 1, 1])); + let v = v.simd_min(simd_swizzle!(v, [1, 0, 0, 0])); + v[0] + } + + /// 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 = v.simd_max(simd_swizzle!(v, [2, 2, 0, 0])); + let v = v.simd_max(simd_swizzle!(v, [1, 0, 0, 0])); + v[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 cmpeq(self, rhs: Self) -> BVec3A { + BVec3A(f32x4::simd_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::simd_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::simd_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::simd_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::simd_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::simd_lt(self.0, rhs.0)) + } + + /// Returns a vector containing the absolute value of each element of `self`. + #[inline] + pub fn abs(self) -> Self { + Self(self.0.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(self.0.signum()) + } + + /// Returns a bitmask with the lowest 3 bits set to the sign bits from the elements of `self`. + /// + /// A negative element results in a `1` bit and a positive element in a `0` bit. Element `x` goes + /// into the first lowest bit, element `y` into the second, etc. + #[inline] + pub fn is_negative_bitmask(self) -> u32 { + (self.0.is_sign_negative().to_bitmask() & 0x7) as u32 + } + + /// 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 { + f32x4::is_finite(self.0) + .bitor(mask32x4::from_array([false, false, false, true])) + .all() + } + + /// 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::is_nan(self.0)) + } + + /// Computes the length of `self`. + #[doc(alias = "magnitude")] + #[inline] + pub fn length(self) -> f32 { + let dot = dot3_in_x(self.0, self.0); + dot.sqrt()[0] + } + + /// 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 = dot3_in_x(self.0, self.0); + dot.sqrt().recip()[0] + } + + /// 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 = dot3_into_f32x4(self.0, self.0).sqrt(); + #[allow(clippy::let_and_return)] + let normalized = Self(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(self.0.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(self.0.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(self.0.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(self.0.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(self.0.mul_add(a.0, b.0)) + } + + /// 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(self.0 / rhs.0) + } +} + +impl DivAssign for Vec3A { + #[inline] + fn div_assign(&mut self, rhs: Self) { + self.0 /= rhs.0; + } +} + +impl Div for Vec3A { + type Output = Self; + #[inline] + fn div(self, rhs: f32) -> Self { + Self(self.0 / f32x4::splat(rhs)) + } +} + +impl DivAssign for Vec3A { + #[inline] + fn div_assign(&mut self, rhs: f32) { + self.0 /= f32x4::splat(rhs); + } +} + +impl Div for f32 { + type Output = Vec3A; + #[inline] + fn div(self, rhs: Vec3A) -> Vec3A { + Vec3A(f32x4::splat(self) / rhs.0) + } +} + +impl Mul for Vec3A { + type Output = Self; + #[inline] + fn mul(self, rhs: Self) -> Self { + Self(self.0 * rhs.0) + } +} + +impl MulAssign for Vec3A { + #[inline] + fn mul_assign(&mut self, rhs: Self) { + self.0 *= rhs.0; + } +} + +impl Mul for Vec3A { + type Output = Self; + #[inline] + fn mul(self, rhs: f32) -> Self { + Self(self.0 * f32x4::splat(rhs)) + } +} + +impl MulAssign for Vec3A { + #[inline] + fn mul_assign(&mut self, rhs: f32) { + self.0 *= f32x4::splat(rhs); + } +} + +impl Mul for f32 { + type Output = Vec3A; + #[inline] + fn mul(self, rhs: Vec3A) -> Vec3A { + Vec3A(f32x4::splat(self) * rhs.0) + } +} + +impl Add for Vec3A { + type Output = Self; + #[inline] + fn add(self, rhs: Self) -> Self { + Self(self.0 + rhs.0) + } +} + +impl AddAssign for Vec3A { + #[inline] + fn add_assign(&mut self, rhs: Self) { + self.0 += rhs.0; + } +} + +impl Add for Vec3A { + type Output = Self; + #[inline] + fn add(self, rhs: f32) -> Self { + Self(self.0 + f32x4::splat(rhs)) + } +} + +impl AddAssign for Vec3A { + #[inline] + fn add_assign(&mut self, rhs: f32) { + self.0 += f32x4::splat(rhs); + } +} + +impl Add for f32 { + type Output = Vec3A; + #[inline] + fn add(self, rhs: Vec3A) -> Vec3A { + Vec3A(f32x4::splat(self) + rhs.0) + } +} + +impl Sub for Vec3A { + type Output = Self; + #[inline] + fn sub(self, rhs: Self) -> Self { + Self(self.0 - rhs.0) + } +} + +impl SubAssign for Vec3A { + #[inline] + fn sub_assign(&mut self, rhs: Vec3A) { + self.0 -= rhs.0; + } +} + +impl Sub for Vec3A { + type Output = Self; + #[inline] + fn sub(self, rhs: f32) -> Self { + Self(self.0 - f32x4::splat(rhs)) + } +} + +impl SubAssign for Vec3A { + #[inline] + fn sub_assign(&mut self, rhs: f32) { + self.0 -= f32x4::splat(rhs); + } +} + +impl Sub for f32 { + type Output = Vec3A; + #[inline] + fn sub(self, rhs: Vec3A) -> Vec3A { + Vec3A(f32x4::splat(self) - rhs.0) + } +} + +impl Rem for Vec3A { + type Output = Self; + #[inline] + fn rem(self, rhs: Self) -> Self { + Self(self.0 % rhs.0) + } +} + +impl RemAssign for Vec3A { + #[inline] + fn rem_assign(&mut self, rhs: Self) { + self.0 %= rhs.0; + } +} + +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.0 %= f32x4::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 Sum for Vec3A { + #[inline] + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, Self::add) + } +} + +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 Product for Vec3A { + #[inline] + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ONE, Self::mul) + } +} + +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(-self.0) + } +} + +impl Index for Vec3A { + type Output = f32; + #[inline] + fn index(&self, index: usize) -> &Self::Output { + &self.0[index] + } +} + +impl IndexMut for Vec3A { + #[inline] + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + &mut self.0[index] + } +} + +#[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 f32x4 { + #[inline] + fn from(t: Vec3A) -> Self { + t.0 + } +} + +impl From for Vec3A { + #[inline] + fn from(t: f32x4) -> 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 { + unsafe { *(v.0.to_array().as_ptr() as *const Self) } + } +} + +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 { + unsafe { *(v.0.to_array().as_ptr() 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 for Vec3 { + #[inline] + fn from(v: Vec3A) -> Self { + unsafe { *(v.0.to_array().as_ptr() as *const Self) } + } +} + +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::Vec3; + #[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/coresimd/vec4.rs b/src/f32/coresimd/vec4.rs new file mode 100644 index 0000000..61b4903 --- /dev/null +++ b/src/f32/coresimd/vec4.rs @@ -0,0 +1,1009 @@ +// Generated from vec.rs.tera template. Edit the template, not the generated file. + +use crate::{coresimd::*, BVec4A, Vec2, Vec3, Vec3A}; + +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::iter::{Product, Sum}; +use core::{f32, ops::*}; + +use core::simd::*; +use std::simd::StdFloat; + +#[cfg(feature = "libm")] +#[allow(unused_imports)] +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 with SIMD support. +/// +/// This type uses 16 byte aligned SIMD vector type for storage. +#[derive(Clone, Copy)] +#[repr(transparent)] +pub struct Vec4(pub(crate) f32x4); + +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); + + /// A unit-length vector pointing along the positive X axis. + pub const X: Self = Self::new(1.0, 0.0, 0.0, 0.0); + + /// A unit-length vector pointing along the positive Y axis. + pub const Y: Self = Self::new(0.0, 1.0, 0.0, 0.0); + + /// A unit-length vector pointing along the positive Z axis. + pub const Z: Self = Self::new(0.0, 0.0, 1.0, 0.0); + + /// A unit-length vector pointing along the positive W axis. + pub const W: Self = Self::new(0.0, 0.0, 0.0, 1.0); + + /// A unit-length vector pointing along the negative X axis. + pub const NEG_X: Self = Self::new(-1.0, 0.0, 0.0, 0.0); + + /// A unit-length vector pointing along the negative Y axis. + pub const NEG_Y: Self = Self::new(0.0, -1.0, 0.0, 0.0); + + /// A unit-length vector pointing along the negative Z axis. + pub const NEG_Z: Self = Self::new(0.0, 0.0, -1.0, 0.0); + + /// A unit-length vector pointing along the negative W axis. + pub const NEG_W: Self = Self::new(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::from_array([x, y, z, w])) + } + + /// Creates a vector with all elements set to `v`. + #[inline] + pub const fn splat(v: f32) -> Self { + Self(Simd::from_array([v; 4])) + } + + /// 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(mask.0.select(if_true.0, if_false.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 4 values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 4 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 4 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 { + dot4(self.0, rhs.0) + } + + /// Returns a vector where every component is the dot product of `self` and `rhs`. + #[inline] + pub fn dot_into_vec(self, rhs: Self) -> Self { + Self(unsafe { dot4_into_f32x4(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(self.0.simd_min(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(self.0.simd_max(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 { + self.0.reduce_min() + } + + /// Returns the horizontal maximum of `self`. + /// + /// In other words this computes `max(x, y, ..)`. + #[inline] + pub fn max_element(self) -> f32 { + self.0.reduce_max() + } + + /// 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::simd_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::simd_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::simd_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::simd_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::simd_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::simd_lt(self.0, rhs.0)) + } + + /// Returns a vector containing the absolute value of each element of `self`. + #[inline] + pub fn abs(self) -> Self { + Self(self.0.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(self.0.signum()) + } + + /// Returns a bitmask with the lowest 4 bits set to the sign bits from the elements of `self`. + /// + /// A negative element results in a `1` bit and a positive element in a `0` bit. Element `x` goes + /// into the first lowest bit, element `y` into the second, etc. + #[inline] + pub fn is_negative_bitmask(self) -> u32 { + self.0.is_sign_negative().to_bitmask() as u32 + } + + /// 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 { + f32x4::is_finite(self.0).all() + } + + /// 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::is_nan(self.0)) + } + + /// Computes the length of `self`. + #[doc(alias = "magnitude")] + #[inline] + pub fn length(self) -> f32 { + let dot = dot4_in_x(self.0, self.0); + dot.sqrt()[0] + } + + /// 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 = dot4_in_x(self.0, self.0); + dot.sqrt().recip()[0] + } + + /// 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 = dot4_into_f32x4(self.0, self.0).sqrt(); + #[allow(clippy::let_and_return)] + let normalized = Self(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(self.0.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(self.0.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(self.0.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(self.0.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(self.0.mul_add(a.0, b.0)) + } + + /// 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(self.0 / rhs.0) + } +} + +impl DivAssign for Vec4 { + #[inline] + fn div_assign(&mut self, rhs: Self) { + self.0 /= rhs.0; + } +} + +impl Div for Vec4 { + type Output = Self; + #[inline] + fn div(self, rhs: f32) -> Self { + Self(self.0 / f32x4::splat(rhs)) + } +} + +impl DivAssign for Vec4 { + #[inline] + fn div_assign(&mut self, rhs: f32) { + self.0 /= f32x4::splat(rhs); + } +} + +impl Div for f32 { + type Output = Vec4; + #[inline] + fn div(self, rhs: Vec4) -> Vec4 { + Vec4(f32x4::splat(self) / rhs.0) + } +} + +impl Mul for Vec4 { + type Output = Self; + #[inline] + fn mul(self, rhs: Self) -> Self { + Self(self.0 * rhs.0) + } +} + +impl MulAssign for Vec4 { + #[inline] + fn mul_assign(&mut self, rhs: Self) { + self.0 *= rhs.0; + } +} + +impl Mul for Vec4 { + type Output = Self; + #[inline] + fn mul(self, rhs: f32) -> Self { + Self(self.0 * f32x4::splat(rhs)) + } +} + +impl MulAssign for Vec4 { + #[inline] + fn mul_assign(&mut self, rhs: f32) { + self.0 *= f32x4::splat(rhs); + } +} + +impl Mul for f32 { + type Output = Vec4; + #[inline] + fn mul(self, rhs: Vec4) -> Vec4 { + Vec4(f32x4::splat(self) * rhs.0) + } +} + +impl Add for Vec4 { + type Output = Self; + #[inline] + fn add(self, rhs: Self) -> Self { + Self(self.0 + rhs.0) + } +} + +impl AddAssign for Vec4 { + #[inline] + fn add_assign(&mut self, rhs: Self) { + self.0 += rhs.0; + } +} + +impl Add for Vec4 { + type Output = Self; + #[inline] + fn add(self, rhs: f32) -> Self { + Self(self.0 + f32x4::splat(rhs)) + } +} + +impl AddAssign for Vec4 { + #[inline] + fn add_assign(&mut self, rhs: f32) { + self.0 += f32x4::splat(rhs); + } +} + +impl Add for f32 { + type Output = Vec4; + #[inline] + fn add(self, rhs: Vec4) -> Vec4 { + Vec4(f32x4::splat(self) + rhs.0) + } +} + +impl Sub for Vec4 { + type Output = Self; + #[inline] + fn sub(self, rhs: Self) -> Self { + Self(self.0 - rhs.0) + } +} + +impl SubAssign for Vec4 { + #[inline] + fn sub_assign(&mut self, rhs: Vec4) { + self.0 -= rhs.0; + } +} + +impl Sub for Vec4 { + type Output = Self; + #[inline] + fn sub(self, rhs: f32) -> Self { + Self(self.0 - f32x4::splat(rhs)) + } +} + +impl SubAssign for Vec4 { + #[inline] + fn sub_assign(&mut self, rhs: f32) { + self.0 -= f32x4::splat(rhs); + } +} + +impl Sub for f32 { + type Output = Vec4; + #[inline] + fn sub(self, rhs: Vec4) -> Vec4 { + Vec4(f32x4::splat(self) - rhs.0) + } +} + +impl Rem for Vec4 { + type Output = Self; + #[inline] + fn rem(self, rhs: Self) -> Self { + Self(self.0 % rhs.0) + } +} + +impl RemAssign for Vec4 { + #[inline] + fn rem_assign(&mut self, rhs: Self) { + self.0 %= rhs.0; + } +} + +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.0 %= f32x4::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 Sum for Vec4 { + #[inline] + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, Self::add) + } +} + +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 Product for Vec4 { + #[inline] + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ONE, Self::mul) + } +} + +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(-self.0) + } +} + +impl Index for Vec4 { + type Output = f32; + #[inline] + fn index(&self, index: usize) -> &Self::Output { + &self.0[index] + } +} + +impl IndexMut for Vec4 { + #[inline] + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + &mut self.0[index] + } +} + +#[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 f32x4 { + #[inline] + fn from(t: Vec4) -> Self { + t.0 + } +} + +impl From for Vec4 { + #[inline] + fn from(t: f32x4) -> Self { + Self(t) + } +} + +impl From<[f32; 4]> for Vec4 { + #[inline] + fn from(a: [f32; 4]) -> Self { + Self(f32x4::from_array(a)) + } +} + +impl From for [f32; 4] { + #[inline] + fn from(v: Vec4) -> Self { + v.0.to_array() + } +} + +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 { + unsafe { *(v.0.to_array().as_ptr() 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::Vec4; + #[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/mat3.rs b/src/f32/mat3.rs new file mode 100644 index 0000000..6c2ed4d --- /dev/null +++ b/src/f32/mat3.rs @@ -0,0 +1,737 @@ +// Generated from mat.rs.tera 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(feature = "libm")] +#[allow(unused_imports)] +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)] +#[repr(C)] +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 const 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 const 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 const 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 4th 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`. + #[inline] + 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] + #[inline] + 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. + /// + /// # Panics + /// + /// Will panic if the 2nd row of `self` is not `(0, 0, 1)` when `glam_assert` is enabled. + #[inline] + pub fn transform_point2(&self, rhs: Vec2) -> Vec2 { + glam_assert!(self.row(2).abs_diff_eq(Vec3::Z, 1e-6)); + 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. + /// + /// # Panics + /// + /// Will panic if the 2nd row of `self` is not `(0, 0, 1)` when `glam_assert` is enabled. + #[inline] + pub fn transform_vector2(&self, rhs: Vec2) -> Vec2 { + glam_assert!(self.row(2).abs_diff_eq(Vec3::Z, 1e-6)); + 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 Sum for Mat3 { + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, Self::add) + } +} + +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 Product for Mat3 { + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::IDENTITY, Self::mul) + } +} + +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 0000000..24171e5 --- /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 0000000..9c4c253 --- /dev/null +++ b/src/f32/scalar/mat2.rs @@ -0,0 +1,458 @@ +// Generated from mat.rs.tera template. Edit the template, not the generated file. + +use crate::{swizzles::*, DMat2, Mat3, Mat3A, 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(feature = "libm")] +#[allow(unused_imports)] +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(align(16)) +)] +#[cfg_attr(feature = "cuda", repr(align(8)))] +#[repr(C)] +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 const 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 const 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 const 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 a 3x3 matrix, discarding the 2nd row and column. + #[inline] + pub fn from_mat3a(m: Mat3A) -> 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] + #[inline] + 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 Sum for Mat2 { + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, Self::add) + } +} + +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 Product for Mat2 { + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::IDENTITY, Self::mul) + } +} + +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 0000000..ea56981 --- /dev/null +++ b/src/f32/scalar/mat3a.rs @@ -0,0 +1,725 @@ +// Generated from mat.rs.tera 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(feature = "libm")] +#[allow(unused_imports)] +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)] +#[repr(C)] +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 const 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 const 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 const 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 4th 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`. + #[inline] + 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] + #[inline] + 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. + /// + /// # Panics + /// + /// Will panic if the 2nd row of `self` is not `(0, 0, 1)` when `glam_assert` is enabled. + #[inline] + pub fn transform_point2(&self, rhs: Vec2) -> Vec2 { + glam_assert!(self.row(2).abs_diff_eq(Vec3A::Z, 1e-6)); + 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. + /// + /// # Panics + /// + /// Will panic if the 2nd row of `self` is not `(0, 0, 1)` when `glam_assert` is enabled. + #[inline] + pub fn transform_vector2(&self, rhs: Vec2) -> Vec2 { + glam_assert!(self.row(2).abs_diff_eq(Vec3A::Z, 1e-6)); + 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 Sum for Mat3A { + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, Self::add) + } +} + +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 Product for Mat3A { + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::IDENTITY, Self::mul) + } +} + +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 0000000..78d7a52 --- /dev/null +++ b/src/f32/scalar/mat4.rs @@ -0,0 +1,1276 @@ +// Generated from mat.rs.tera template. Edit the template, not the generated file. + +use crate::{swizzles::*, DMat4, EulerRot, Mat3, Mat3A, 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(feature = "libm")] +#[allow(unused_imports)] +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(align(16)) +)] +#[repr(C)] +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 const 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 const 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 const 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, + ) + } + + #[inline] + 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 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_mat3a(m: Mat3A) -> 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) + } + + /// Creates a left-handed view matrix using a camera position, an up direction, and a facing + /// direction. + /// + /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=forward`. + #[inline] + pub fn look_to_lh(eye: Vec3, dir: Vec3, up: Vec3) -> Self { + Self::look_to_rh(eye, -dir, up) + } + + /// Creates a right-handed view matrix using a camera position, an up direction, and a facing + /// direction. + /// + /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=back`. + #[inline] + pub fn look_to_rh(eye: Vec3, dir: Vec3, up: Vec3) -> Self { + let f = dir.normalize(); + let s = f.cross(up).normalize(); + let u = s.cross(f); + + 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(-eye.dot(s), -eye.dot(u), eye.dot(f), 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_rh(eye, center.sub(eye), 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).abs_diff_eq(Vec4::W, 1e-6)); + 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).abs_diff_eq(Vec4::W, 1e-6)); + 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 Sum for Mat4 { + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, Self::add) + } +} + +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 Product for Mat4 { + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::IDENTITY, Self::mul) + } +} + +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 0000000..0b72e8f --- /dev/null +++ b/src/f32/scalar/quat.rs @@ -0,0 +1,872 @@ +// Generated from quat.rs.tera template. Edit the template, not the generated file. + +use crate::{ + euler::{EulerFromQuaternion, EulerRot, EulerToQuaternion}, + DQuat, FloatEx, Mat3, Mat3A, Mat4, Vec2, Vec3, Vec3A, Vec4, +}; + +#[cfg(feature = "libm")] +#[allow(unused_imports)] +use num_traits::Float; + +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::iter::{Product, Sum}; +use core::ops::{Add, 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(align(16)) +)] +#[cfg_attr(not(target_arch = "spirv"), repr(C))] +#[cfg_attr(target_arch = "spirv", repr(simd))] +pub struct Quat { + pub x: f32, + pub y: f32, + pub z: f32, + pub 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` + 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 SIMD aligned rotation matrix. + #[inline] + pub fn from_mat3a(mat: &Mat3A) -> Self { + Self::from_rotation_axes(mat.x_axis.into(), mat.y_axis.into(), mat.z_axis.into()) + } + + /// 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 Sum for Quat { + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, Self::add) + } +} + +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 Product for Quat { + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::IDENTITY, Self::mul) + } +} + +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] + } +} diff --git a/src/f32/scalar/vec3a.rs b/src/f32/scalar/vec3a.rs new file mode 100644 index 0000000..88a3c13 --- /dev/null +++ b/src/f32/scalar/vec3a.rs @@ -0,0 +1,1189 @@ +// Generated from vec.rs.tera 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(feature = "libm")] +#[allow(unused_imports)] +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, PartialEq)] +#[cfg_attr(not(target_arch = "spirv"), repr(align(16)))] +#[cfg_attr(not(target_arch = "spirv"), repr(C))] +#[cfg_attr(target_arch = "spirv", repr(simd))] +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); + + /// A unit-length vector pointing along the positive X axis. + pub const X: Self = Self::new(1.0, 0.0, 0.0); + + /// A unit-length vector pointing along the positive Y axis. + pub const Y: Self = Self::new(0.0, 1.0, 0.0); + + /// A unit-length vector pointing along the positive Z axis. + pub const Z: Self = Self::new(0.0, 0.0, 1.0); + + /// A unit-length vector pointing along the negative X axis. + pub const NEG_X: Self = Self::new(-1.0, 0.0, 0.0); + + /// A unit-length vector pointing along the negative Y axis. + pub const NEG_Y: Self = Self::new(0.0, -1.0, 0.0); + + /// A unit-length vector pointing along the negative Z axis. + pub const NEG_Z: Self = Self::new(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 3 values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 3 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 3 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) + } + + /// Returns a vector where every component is the dot product of `self` and `rhs`. + #[inline] + pub fn dot_into_vec(self, rhs: Self) -> Self { + Self::splat(self.dot(rhs)) + } + + /// 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 a bitmask with the lowest 3 bits set to the sign bits from the elements of `self`. + /// + /// A negative element results in a `1` bit and a positive element in a `0` bit. Element `x` goes + /// into the first lowest bit, element `y` into the second, etc. + #[inline] + pub fn is_negative_bitmask(self) -> u32 { + (self.x.is_sign_negative() as u32) + | (self.y.is_sign_negative() as u32) << 1 + | (self.z.is_sign_negative() as u32) << 2 + } + + /// 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 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 Sum for Vec3A { + #[inline] + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, Self::add) + } +} + +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 Product for Vec3A { + #[inline] + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ONE, Self::mul) + } +} + +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 for Vec3 { + #[inline] + fn from(v: Vec3A) -> 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 0000000..cf791cf --- /dev/null +++ b/src/f32/scalar/vec4.rs @@ -0,0 +1,1196 @@ +// Generated from vec.rs.tera 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(feature = "libm")] +#[allow(unused_imports)] +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, PartialEq)] +#[cfg_attr( + any( + not(any(feature = "scalar-math", target_arch = "spirv")), + feature = "cuda" + ), + repr(align(16)) +)] +#[cfg_attr(not(target_arch = "spirv"), repr(C))] +#[cfg_attr(target_arch = "spirv", repr(simd))] +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); + + /// A unit-length vector pointing along the positive X axis. + pub const X: Self = Self::new(1.0, 0.0, 0.0, 0.0); + + /// A unit-length vector pointing along the positive Y axis. + pub const Y: Self = Self::new(0.0, 1.0, 0.0, 0.0); + + /// A unit-length vector pointing along the positive Z axis. + pub const Z: Self = Self::new(0.0, 0.0, 1.0, 0.0); + + /// A unit-length vector pointing along the positive W axis. + pub const W: Self = Self::new(0.0, 0.0, 0.0, 1.0); + + /// A unit-length vector pointing along the negative X axis. + pub const NEG_X: Self = Self::new(-1.0, 0.0, 0.0, 0.0); + + /// A unit-length vector pointing along the negative Y axis. + pub const NEG_Y: Self = Self::new(0.0, -1.0, 0.0, 0.0); + + /// A unit-length vector pointing along the negative Z axis. + pub const NEG_Z: Self = Self::new(0.0, 0.0, -1.0, 0.0); + + /// A unit-length vector pointing along the negative W axis. + pub const NEG_W: Self = Self::new(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 4 values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 4 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 4 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 where every component is the dot product of `self` and `rhs`. + #[inline] + pub fn dot_into_vec(self, rhs: Self) -> Self { + Self::splat(self.dot(rhs)) + } + + /// 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 a bitmask with the lowest 4 bits set to the sign bits from the elements of `self`. + /// + /// A negative element results in a `1` bit and a positive element in a `0` bit. Element `x` goes + /// into the first lowest bit, element `y` into the second, etc. + #[inline] + pub fn is_negative_bitmask(self) -> u32 { + (self.x.is_sign_negative() as u32) + | (self.y.is_sign_negative() as u32) << 1 + | (self.z.is_sign_negative() as u32) << 2 + | (self.w.is_sign_negative() as u32) << 3 + } + + /// 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 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 Sum for Vec4 { + #[inline] + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, Self::add) + } +} + +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 Product for Vec4 { + #[inline] + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ONE, Self::mul) + } +} + +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 0000000..24171e5 --- /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 0000000..0222bdd --- /dev/null +++ b/src/f32/sse2/mat2.rs @@ -0,0 +1,505 @@ +// Generated from mat.rs.tera template. Edit the template, not the generated file. + +use crate::{swizzles::*, DMat2, Mat3, Mat3A, 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(feature = "libm")] +#[allow(unused_imports)] +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 const fn to_cols_array(&self) -> [f32; 4] { + unsafe { *(self as *const Self as *const [f32; 4]) } + } + + /// 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 const fn to_cols_array_2d(&self) -> [[f32; 2]; 2] { + unsafe { *(self as *const Self as *const [[f32; 2]; 2]) } + } + + /// Creates a 2x2 matrix with its diagonal set to `diagonal` and all other entries set to 0. + #[doc(alias = "scale")] + #[inline] + pub const 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 a 3x3 matrix, discarding the 2nd row and column. + #[inline] + pub fn from_mat3a(m: Mat3A) -> 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] + #[inline] + pub fn inverse(&self) -> Self { + unsafe { + const SIGN: __m128 = crate::sse2::m128_from_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 Sum for Mat2 { + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, Self::add) + } +} + +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 Product for Mat2 { + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::IDENTITY, Self::mul) + } +} + +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::Cols2; + #[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 0000000..14912dd --- /dev/null +++ b/src/f32/sse2/mat3a.rs @@ -0,0 +1,732 @@ +// Generated from mat.rs.tera 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(feature = "libm")] +#[allow(unused_imports)] +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)] +#[repr(C)] +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 const fn to_cols_array(&self) -> [f32; 9] { + let [x_axis_x, x_axis_y, x_axis_z] = self.x_axis.to_array(); + let [y_axis_x, y_axis_y, y_axis_z] = self.y_axis.to_array(); + let [z_axis_x, z_axis_y, z_axis_z] = self.z_axis.to_array(); + + [ + 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, + ] + } + + /// 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 const 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 const 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 4th 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`. + #[inline] + 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] + #[inline] + 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. + /// + /// # Panics + /// + /// Will panic if the 2nd row of `self` is not `(0, 0, 1)` when `glam_assert` is enabled. + #[inline] + pub fn transform_point2(&self, rhs: Vec2) -> Vec2 { + glam_assert!(self.row(2).abs_diff_eq(Vec3A::Z, 1e-6)); + 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. + /// + /// # Panics + /// + /// Will panic if the 2nd row of `self` is not `(0, 0, 1)` when `glam_assert` is enabled. + #[inline] + pub fn transform_vector2(&self, rhs: Vec2) -> Vec2 { + glam_assert!(self.row(2).abs_diff_eq(Vec3A::Z, 1e-6)); + 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 Sum for Mat3A { + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, Self::add) + } +} + +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 Product for Mat3A { + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::IDENTITY, Self::mul) + } +} + +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 0000000..aa69493 --- /dev/null +++ b/src/f32/sse2/mat4.rs @@ -0,0 +1,1371 @@ +// Generated from mat.rs.tera template. Edit the template, not the generated file. + +use crate::{sse2::*, swizzles::*, DMat4, EulerRot, Mat3, Mat3A, 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(feature = "libm")] +#[allow(unused_imports)] +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)] +#[repr(C)] +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 const fn to_cols_array(&self) -> [f32; 16] { + let [x_axis_x, x_axis_y, x_axis_z, x_axis_w] = self.x_axis.to_array(); + let [y_axis_x, y_axis_y, y_axis_z, y_axis_w] = self.y_axis.to_array(); + let [z_axis_x, z_axis_y, z_axis_z, z_axis_w] = self.z_axis.to_array(); + let [w_axis_x, w_axis_y, w_axis_z, w_axis_w] = self.w_axis.to_array(); + + [ + 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, + ] + } + + /// 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 const 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 const fn from_diagonal(diagonal: Vec4) -> Self { + // diagonal.x, diagonal.y etc can't be done in a const-context + let [x, y, z, w] = diagonal.to_array(); + Self::new( + x, 0.0, 0.0, 0.0, 0.0, y, 0.0, 0.0, 0.0, 0.0, z, 0.0, 0.0, 0.0, 0.0, w, + ) + } + + #[inline] + 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 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_mat3a(m: Mat3A) -> 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)); + + 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 = 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)), + } + } + } + + /// Creates a left-handed view matrix using a camera position, an up direction, and a facing + /// direction. + /// + /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=forward`. + #[inline] + pub fn look_to_lh(eye: Vec3, dir: Vec3, up: Vec3) -> Self { + Self::look_to_rh(eye, -dir, up) + } + + /// Creates a right-handed view matrix using a camera position, an up direction, and a facing + /// direction. + /// + /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=back`. + #[inline] + pub fn look_to_rh(eye: Vec3, dir: Vec3, up: Vec3) -> Self { + let f = dir.normalize(); + let s = f.cross(up).normalize(); + let u = s.cross(f); + + 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(-eye.dot(s), -eye.dot(u), eye.dot(f), 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_rh(eye, center.sub(eye), 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).abs_diff_eq(Vec4::W, 1e-6)); + 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).abs_diff_eq(Vec4::W, 1e-6)); + 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 { + glam_assert!(self.row(3).abs_diff_eq(Vec4::W, 1e-6)); + 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 { + glam_assert!(self.row(3).abs_diff_eq(Vec4::W, 1e-6)); + 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 Sum for Mat4 { + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, Self::add) + } +} + +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 Product for Mat4 { + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::IDENTITY, Self::mul) + } +} + +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 0000000..f7fbd8d --- /dev/null +++ b/src/f32/sse2/quat.rs @@ -0,0 +1,942 @@ +// Generated from quat.rs.tera template. Edit the template, not the generated file. + +use crate::{ + euler::{EulerFromQuaternion, EulerRot, EulerToQuaternion}, + sse2::*, + DQuat, FloatEx, Mat3, Mat3A, Mat4, Vec2, Vec3, Vec3A, Vec4, +}; + +#[cfg(feature = "libm")] +#[allow(unused_imports)] +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, DerefMut, 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` + 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 SIMD aligned rotation matrix. + #[inline] + pub fn from_mat3a(mat: &Mat3A) -> Self { + Self::from_rotation_axes(mat.x_axis.into(), mat.y_axis.into(), mat.z_axis.into()) + } + + /// 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 = m128_from_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 = m128_from_f32x4([-0.0; 4]); + let start = self.0; + let end = end.0; + unsafe { + let dot = 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 = 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 = m128_from_f32x4([1.0, -1.0, 1.0, -1.0]); + const CONTROL_ZWXY: __m128 = m128_from_f32x4([1.0, 1.0, -1.0, -1.0]); + const CONTROL_YXWZ: __m128 = m128_from_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 = m128_from_f32x4([2.0; 4]); + let w = _mm_shuffle_ps(self.0, self.0, 0b11_11_11_11); + let b = self.0; + let b2 = 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(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 Sum for Quat { + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, Self::add) + } +} + +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 Product for Quat { + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::IDENTITY, Self::mul) + } +} + +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 { + #[inline] + fn from(q: Quat) -> Self { + q.0 + } +} + +impl Deref for Quat { + type Target = crate::deref::Vec4; + #[inline] + fn deref(&self) -> &Self::Target { + unsafe { &*(self as *const Self).cast() } + } +} + +impl DerefMut for Quat { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { &mut *(self as *mut Self).cast() } + } +} diff --git a/src/f32/sse2/vec3a.rs b/src/f32/sse2/vec3a.rs new file mode 100644 index 0000000..7fa8a6a --- /dev/null +++ b/src/f32/sse2/vec3a.rs @@ -0,0 +1,1157 @@ +// Generated from vec.rs.tera template. Edit the template, not the generated file. + +use crate::{sse2::*, 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(feature = "libm")] +#[allow(unused_imports)] +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); + + /// A unit-length vector pointing along the positive X axis. + pub const X: Self = Self::new(1.0, 0.0, 0.0); + + /// A unit-length vector pointing along the positive Y axis. + pub const Y: Self = Self::new(0.0, 1.0, 0.0); + + /// A unit-length vector pointing along the positive Z axis. + pub const Z: Self = Self::new(0.0, 0.0, 1.0); + + /// A unit-length vector pointing along the negative X axis. + pub const NEG_X: Self = Self::new(-1.0, 0.0, 0.0); + + /// A unit-length vector pointing along the negative Y axis. + pub const NEG_Y: Self = Self::new(0.0, -1.0, 0.0); + + /// A unit-length vector pointing along the negative Z axis. + pub const NEG_Z: Self = Self::new(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 3 values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 3 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 3 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 { dot3(self.0, rhs.0) } + } + + /// Returns a vector where every component is the dot product of `self` and `rhs`. + #[inline] + pub fn dot_into_vec(self, rhs: Self) -> Self { + Self(unsafe { dot3_into_m128(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 { + unsafe { + let result = Self(_mm_or_ps(_mm_and_ps(self.0, Self::NEG_ONE.0), Self::ONE.0)); + let mask = self.is_nan_mask(); + Self::select(mask, self, result) + } + } + + /// Returns a bitmask with the lowest 3 bits set to the sign bits from the elements of `self`. + /// + /// A negative element results in a `1` bit and a positive element in a `0` bit. Element `x` goes + /// into the first lowest bit, element `y` into the second, etc. + #[inline] + pub fn is_negative_bitmask(self) -> u32 { + unsafe { (_mm_movemask_ps(self.0) as u32) & 0x7 } + } + + /// 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 = 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 = 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(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 { 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 { 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 { 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 { + Self(_mm_fmadd_ps(self.0, a.0, b.0)) + } + #[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 = 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 Sum for Vec3A { + #[inline] + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, Self::add) + } +} + +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 Product for Vec3A { + #[inline] + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ONE, Self::mul) + } +} + +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_xor_ps(_mm_set1_ps(-0.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 for Vec3 { + #[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<(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::Vec3; + #[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 0000000..0e0882c --- /dev/null +++ b/src/f32/sse2/vec4.rs @@ -0,0 +1,1078 @@ +// Generated from vec.rs.tera template. Edit the template, not the generated file. + +use crate::{sse2::*, 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(feature = "libm")] +#[allow(unused_imports)] +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); + + /// A unit-length vector pointing along the positive X axis. + pub const X: Self = Self::new(1.0, 0.0, 0.0, 0.0); + + /// A unit-length vector pointing along the positive Y axis. + pub const Y: Self = Self::new(0.0, 1.0, 0.0, 0.0); + + /// A unit-length vector pointing along the positive Z axis. + pub const Z: Self = Self::new(0.0, 0.0, 1.0, 0.0); + + /// A unit-length vector pointing along the positive W axis. + pub const W: Self = Self::new(0.0, 0.0, 0.0, 1.0); + + /// A unit-length vector pointing along the negative X axis. + pub const NEG_X: Self = Self::new(-1.0, 0.0, 0.0, 0.0); + + /// A unit-length vector pointing along the negative Y axis. + pub const NEG_Y: Self = Self::new(0.0, -1.0, 0.0, 0.0); + + /// A unit-length vector pointing along the negative Z axis. + pub const NEG_Z: Self = Self::new(0.0, 0.0, -1.0, 0.0); + + /// A unit-length vector pointing along the negative W axis. + pub const NEG_W: Self = Self::new(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 4 values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 4 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 4 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 { dot4(self.0, rhs.0) } + } + + /// Returns a vector where every component is the dot product of `self` and `rhs`. + #[inline] + pub fn dot_into_vec(self, rhs: Self) -> Self { + Self(unsafe { dot4_into_m128(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 { + unsafe { + let result = Self(_mm_or_ps(_mm_and_ps(self.0, Self::NEG_ONE.0), Self::ONE.0)); + let mask = self.is_nan_mask(); + Self::select(mask, self, result) + } + } + + /// Returns a bitmask with the lowest 4 bits set to the sign bits from the elements of `self`. + /// + /// A negative element results in a `1` bit and a positive element in a `0` bit. Element `x` goes + /// into the first lowest bit, element `y` into the second, etc. + #[inline] + pub fn is_negative_bitmask(self) -> u32 { + unsafe { _mm_movemask_ps(self.0) as u32 } + } + + /// 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 = 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 = 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(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 { 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 { 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 { 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 { + Self(_mm_fmadd_ps(self.0, a.0, b.0)) + } + #[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 = 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 Sum for Vec4 { + #[inline] + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, Self::add) + } +} + +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 Product for Vec4 { + #[inline] + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ONE, Self::mul) + } +} + +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_xor_ps(_mm_set1_ps(-0.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::Vec4; + #[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 0000000..16bd17d --- /dev/null +++ b/src/f32/vec2.rs @@ -0,0 +1,1047 @@ +// Generated from vec.rs.tera 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(feature = "libm")] +#[allow(unused_imports)] +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, PartialEq)] +#[cfg_attr(feature = "cuda", repr(align(8)))] +#[cfg_attr(not(target_arch = "spirv"), repr(C))] +#[cfg_attr(target_arch = "spirv", repr(simd))] +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); + + /// A unit-length vector pointing along the positive X axis. + pub const X: Self = Self::new(1.0, 0.0); + + /// A unit-length vector pointing along the positive Y axis. + pub const Y: Self = Self::new(0.0, 1.0); + + /// A unit-length vector pointing along the negative X axis. + pub const NEG_X: Self = Self::new(-1.0, 0.0); + + /// A unit-length vector pointing along the negative Y axis. + pub const NEG_Y: Self = Self::new(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 2 values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 2 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 2 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 where every component is the dot product of `self` and `rhs`. + #[inline] + pub fn dot_into_vec(self, rhs: Self) -> Self { + Self::splat(self.dot(rhs)) + } + + /// 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 a bitmask with the lowest 2 bits set to the sign bits from the elements of `self`. + /// + /// A negative element results in a `1` bit and a positive element in a `0` bit. Element `x` goes + /// into the first lowest bit, element `y` into the second, etc. + #[inline] + pub fn is_negative_bitmask(self) -> u32 { + (self.x.is_sign_negative() as u32) | (self.y.is_sign_negative() as u32) << 1 + } + + /// 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 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 Sum for Vec2 { + #[inline] + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, Self::add) + } +} + +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 Product for Vec2 { + #[inline] + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ONE, Self::mul) + } +} + +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 0000000..b049ed8 --- /dev/null +++ b/src/f32/vec3.rs @@ -0,0 +1,1151 @@ +// Generated from vec.rs.tera template. Edit the template, not the generated file. + +use crate::{BVec3, Vec2, Vec4}; + +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::iter::{Product, Sum}; +use core::{f32, ops::*}; + +#[cfg(feature = "libm")] +#[allow(unused_imports)] +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, PartialEq)] +#[cfg_attr(not(target_arch = "spirv"), repr(C))] +#[cfg_attr(target_arch = "spirv", repr(simd))] +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); + + /// A unit-length vector pointing along the positive X axis. + pub const X: Self = Self::new(1.0, 0.0, 0.0); + + /// A unit-length vector pointing along the positive Y axis. + pub const Y: Self = Self::new(0.0, 1.0, 0.0); + + /// A unit-length vector pointing along the positive Z axis. + pub const Z: Self = Self::new(0.0, 0.0, 1.0); + + /// A unit-length vector pointing along the negative X axis. + pub const NEG_X: Self = Self::new(-1.0, 0.0, 0.0); + + /// A unit-length vector pointing along the negative Y axis. + pub const NEG_Y: Self = Self::new(0.0, -1.0, 0.0); + + /// A unit-length vector pointing along the negative Z axis. + pub const NEG_Z: Self = Self::new(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 3 values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 3 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 3 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) + } + + /// Returns a vector where every component is the dot product of `self` and `rhs`. + #[inline] + pub fn dot_into_vec(self, rhs: Self) -> Self { + Self::splat(self.dot(rhs)) + } + + /// 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 a bitmask with the lowest 3 bits set to the sign bits from the elements of `self`. + /// + /// A negative element results in a `1` bit and a positive element in a `0` bit. Element `x` goes + /// into the first lowest bit, element `y` into the second, etc. + #[inline] + pub fn is_negative_bitmask(self) -> u32 { + (self.x.is_sign_negative() as u32) + | (self.y.is_sign_negative() as u32) << 1 + | (self.z.is_sign_negative() as u32) << 2 + } + + /// 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 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 Sum for Vec3 { + #[inline] + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, Self::add) + } +} + +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 Product for Vec3 { + #[inline] + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ONE, Self::mul) + } +} + +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<(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 0000000..24171e5 --- /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 0000000..b96ef73 --- /dev/null +++ b/src/f32/wasm32/mat2.rs @@ -0,0 +1,480 @@ +// Generated from mat.rs.tera template. Edit the template, not the generated file. + +use crate::{swizzles::*, DMat2, Mat3, Mat3A, 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(feature = "libm")] +#[allow(unused_imports)] +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 const fn to_cols_array(&self) -> [f32; 4] { + unsafe { *(self as *const Self as *const [f32; 4]) } + } + + /// 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 const fn to_cols_array_2d(&self) -> [[f32; 2]; 2] { + unsafe { *(self as *const Self as *const [[f32; 2]; 2]) } + } + + /// Creates a 2x2 matrix with its diagonal set to `diagonal` and all other entries set to 0. + #[doc(alias = "scale")] + #[inline] + pub const 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 a 3x3 matrix, discarding the 2nd row and column. + #[inline] + pub fn from_mat3a(m: Mat3A) -> 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] + #[inline] + pub fn inverse(&self) -> Self { + const SIGN: v128 = crate::wasm32::v128_from_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 Sum for Mat2 { + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, Self::add) + } +} + +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 Product for Mat2 { + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::IDENTITY, Self::mul) + } +} + +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::Cols2; + #[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 0000000..573ea1f --- /dev/null +++ b/src/f32/wasm32/mat3a.rs @@ -0,0 +1,727 @@ +// Generated from mat.rs.tera 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(feature = "libm")] +#[allow(unused_imports)] +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)] +#[repr(C)] +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 const fn to_cols_array(&self) -> [f32; 9] { + let [x_axis_x, x_axis_y, x_axis_z] = self.x_axis.to_array(); + let [y_axis_x, y_axis_y, y_axis_z] = self.y_axis.to_array(); + let [z_axis_x, z_axis_y, z_axis_z] = self.z_axis.to_array(); + + [ + 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, + ] + } + + /// 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 const 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 const 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 4th 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`. + #[inline] + 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] + #[inline] + 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. + /// + /// # Panics + /// + /// Will panic if the 2nd row of `self` is not `(0, 0, 1)` when `glam_assert` is enabled. + #[inline] + pub fn transform_point2(&self, rhs: Vec2) -> Vec2 { + glam_assert!(self.row(2).abs_diff_eq(Vec3A::Z, 1e-6)); + 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. + /// + /// # Panics + /// + /// Will panic if the 2nd row of `self` is not `(0, 0, 1)` when `glam_assert` is enabled. + #[inline] + pub fn transform_vector2(&self, rhs: Vec2) -> Vec2 { + glam_assert!(self.row(2).abs_diff_eq(Vec3A::Z, 1e-6)); + 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 Sum for Mat3A { + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, Self::add) + } +} + +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 Product for Mat3A { + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::IDENTITY, Self::mul) + } +} + +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 0000000..bdaeb29 --- /dev/null +++ b/src/f32/wasm32/mat4.rs @@ -0,0 +1,1362 @@ +// Generated from mat.rs.tera template. Edit the template, not the generated file. + +use crate::{swizzles::*, wasm32::*, DMat4, EulerRot, Mat3, Mat3A, 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(feature = "libm")] +#[allow(unused_imports)] +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)] +#[repr(C)] +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 const fn to_cols_array(&self) -> [f32; 16] { + let [x_axis_x, x_axis_y, x_axis_z, x_axis_w] = self.x_axis.to_array(); + let [y_axis_x, y_axis_y, y_axis_z, y_axis_w] = self.y_axis.to_array(); + let [z_axis_x, z_axis_y, z_axis_z, z_axis_w] = self.z_axis.to_array(); + let [w_axis_x, w_axis_y, w_axis_z, w_axis_w] = self.w_axis.to_array(); + + [ + 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, + ] + } + + /// 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 const 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 const fn from_diagonal(diagonal: Vec4) -> Self { + // diagonal.x, diagonal.y etc can't be done in a const-context + let [x, y, z, w] = diagonal.to_array(); + Self::new( + x, 0.0, 0.0, 0.0, 0.0, y, 0.0, 0.0, 0.0, 0.0, z, 0.0, 0.0, 0.0, 0.0, w, + ) + } + + #[inline] + 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 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_mat3a(m: Mat3A) -> 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)); + + 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 = 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)), + } + } + + /// Creates a left-handed view matrix using a camera position, an up direction, and a facing + /// direction. + /// + /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=forward`. + #[inline] + pub fn look_to_lh(eye: Vec3, dir: Vec3, up: Vec3) -> Self { + Self::look_to_rh(eye, -dir, up) + } + + /// Creates a right-handed view matrix using a camera position, an up direction, and a facing + /// direction. + /// + /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=back`. + #[inline] + pub fn look_to_rh(eye: Vec3, dir: Vec3, up: Vec3) -> Self { + let f = dir.normalize(); + let s = f.cross(up).normalize(); + let u = s.cross(f); + + 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(-eye.dot(s), -eye.dot(u), eye.dot(f), 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_rh(eye, center.sub(eye), 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).abs_diff_eq(Vec4::W, 1e-6)); + 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).abs_diff_eq(Vec4::W, 1e-6)); + 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 { + glam_assert!(self.row(3).abs_diff_eq(Vec4::W, 1e-6)); + 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 { + glam_assert!(self.row(3).abs_diff_eq(Vec4::W, 1e-6)); + 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 Sum for Mat4 { + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, Self::add) + } +} + +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 Product for Mat4 { + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::IDENTITY, Self::mul) + } +} + +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 0000000..75f9c16 --- /dev/null +++ b/src/f32/wasm32/quat.rs @@ -0,0 +1,932 @@ +// Generated from quat.rs.tera template. Edit the template, not the generated file. + +use crate::{ + euler::{EulerFromQuaternion, EulerRot, EulerToQuaternion}, + wasm32::*, + DQuat, FloatEx, Mat3, Mat3A, Mat4, Vec2, Vec3, Vec3A, Vec4, +}; + +#[cfg(feature = "libm")] +#[allow(unused_imports)] +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, DerefMut, 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` + 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 SIMD aligned rotation matrix. + #[inline] + pub fn from_mat3a(mat: &Mat3A) -> Self { + Self::from_rotation_axes(mat.x_axis.into(), mat.y_axis.into(), mat.z_axis.into()) + } + + /// 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 = v128_from_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 = v128_from_f32x4([-0.0; 4]); + let start = self.0; + let end = end.0; + let dot = 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 = v128_from_f32x4([1.0, -1.0, 1.0, -1.0]); + const CONTROL_ZWXY: v128 = v128_from_f32x4([1.0, 1.0, -1.0, -1.0]); + const CONTROL_YXWZ: v128 = v128_from_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 = v128_from_f32x4([2.0; 4]); + let w = i32x4_shuffle::<3, 3, 7, 7>(self.0, self.0); + let b = self.0; + let b2 = 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(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 Sum for Quat { + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, Self::add) + } +} + +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 Product for Quat { + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::IDENTITY, Self::mul) + } +} + +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 { + #[inline] + fn from(q: Quat) -> Self { + q.0 + } +} + +impl Deref for Quat { + type Target = crate::deref::Vec4; + #[inline] + fn deref(&self) -> &Self::Target { + unsafe { &*(self as *const Self).cast() } + } +} + +impl DerefMut for Quat { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { &mut *(self as *mut Self).cast() } + } +} diff --git a/src/f32/wasm32/vec3a.rs b/src/f32/wasm32/vec3a.rs new file mode 100644 index 0000000..85b3fe4 --- /dev/null +++ b/src/f32/wasm32/vec3a.rs @@ -0,0 +1,1107 @@ +// Generated from vec.rs.tera template. Edit the template, not the generated file. + +use crate::{wasm32::*, 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(feature = "libm")] +#[allow(unused_imports)] +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); + + /// A unit-length vector pointing along the positive X axis. + pub const X: Self = Self::new(1.0, 0.0, 0.0); + + /// A unit-length vector pointing along the positive Y axis. + pub const Y: Self = Self::new(0.0, 1.0, 0.0); + + /// A unit-length vector pointing along the positive Z axis. + pub const Z: Self = Self::new(0.0, 0.0, 1.0); + + /// A unit-length vector pointing along the negative X axis. + pub const NEG_X: Self = Self::new(-1.0, 0.0, 0.0); + + /// A unit-length vector pointing along the negative Y axis. + pub const NEG_Y: Self = Self::new(0.0, -1.0, 0.0); + + /// A unit-length vector pointing along the negative Z axis. + pub const NEG_Z: Self = Self::new(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 3 values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 3 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 3 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 { + dot3(self.0, rhs.0) + } + + /// Returns a vector where every component is the dot product of `self` and `rhs`. + #[inline] + pub fn dot_into_vec(self, rhs: Self) -> Self { + Self(unsafe { dot3_into_v128(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 { + unsafe { + let result = Self(v128_or(v128_and(self.0, Self::NEG_ONE.0), Self::ONE.0)); + let mask = self.is_nan_mask(); + Self::select(mask, self, result) + } + } + + /// Returns a bitmask with the lowest 3 bits set to the sign bits from the elements of `self`. + /// + /// A negative element results in a `1` bit and a positive element in a `0` bit. Element `x` goes + /// into the first lowest bit, element `y` into the second, etc. + #[inline] + pub fn is_negative_bitmask(self) -> u32 { + (u32x4_bitmask(self.0) & 0x7) as u32 + } + + /// 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 = 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 = 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(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 Sum for Vec3A { + #[inline] + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, Self::add) + } +} + +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 Product for Vec3A { + #[inline] + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ONE, Self::mul) + } +} + +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 { + unsafe { *(&v.0 as *const v128 as *const Self) } + } +} + +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 { + unsafe { *(&v.0 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 for Vec3 { + #[inline] + fn from(v: Vec3A) -> Self { + unsafe { *(&v.0 as *const v128 as *const Self) } + } +} + +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::Vec3; + #[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 0000000..ab53d7a --- /dev/null +++ b/src/f32/wasm32/vec4.rs @@ -0,0 +1,1041 @@ +// Generated from vec.rs.tera template. Edit the template, not the generated file. + +use crate::{wasm32::*, 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(feature = "libm")] +#[allow(unused_imports)] +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); + + /// A unit-length vector pointing along the positive X axis. + pub const X: Self = Self::new(1.0, 0.0, 0.0, 0.0); + + /// A unit-length vector pointing along the positive Y axis. + pub const Y: Self = Self::new(0.0, 1.0, 0.0, 0.0); + + /// A unit-length vector pointing along the positive Z axis. + pub const Z: Self = Self::new(0.0, 0.0, 1.0, 0.0); + + /// A unit-length vector pointing along the positive W axis. + pub const W: Self = Self::new(0.0, 0.0, 0.0, 1.0); + + /// A unit-length vector pointing along the negative X axis. + pub const NEG_X: Self = Self::new(-1.0, 0.0, 0.0, 0.0); + + /// A unit-length vector pointing along the negative Y axis. + pub const NEG_Y: Self = Self::new(0.0, -1.0, 0.0, 0.0); + + /// A unit-length vector pointing along the negative Z axis. + pub const NEG_Z: Self = Self::new(0.0, 0.0, -1.0, 0.0); + + /// A unit-length vector pointing along the negative W axis. + pub const NEG_W: Self = Self::new(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 4 values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 4 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 4 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 { + dot4(self.0, rhs.0) + } + + /// Returns a vector where every component is the dot product of `self` and `rhs`. + #[inline] + pub fn dot_into_vec(self, rhs: Self) -> Self { + Self(unsafe { dot4_into_v128(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 { + unsafe { + let result = Self(v128_or(v128_and(self.0, Self::NEG_ONE.0), Self::ONE.0)); + let mask = self.is_nan_mask(); + Self::select(mask, self, result) + } + } + + /// Returns a bitmask with the lowest 4 bits set to the sign bits from the elements of `self`. + /// + /// A negative element results in a `1` bit and a positive element in a `0` bit. Element `x` goes + /// into the first lowest bit, element `y` into the second, etc. + #[inline] + pub fn is_negative_bitmask(self) -> u32 { + u32x4_bitmask(self.0) as u32 + } + + /// 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 = 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 = 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(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 Sum for Vec4 { + #[inline] + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, Self::add) + } +} + +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 Product for Vec4 { + #[inline] + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ONE, Self::mul) + } +} + +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 { + unsafe { *(&v.0 as *const v128 as *const Self) } + } +} + +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 { + unsafe { *(&v.0 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::Vec4; + #[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 0000000..307cd1a --- /dev/null +++ b/src/f64.rs @@ -0,0 +1,99 @@ +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}; + +#[cfg(not(target_arch = "spirv"))] +mod test { + pub use super::*; + 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 { + #[cfg(not(target_arch = "spirv"))] + const_assert_eq!( + core::mem::align_of::(), + core::mem::align_of::() + ); + #[cfg(target_arch = "spirv")] + const_assert_eq!(32, core::mem::align_of::()); + const_assert_eq!(32, core::mem::size_of::()); + } + + mod const_test_dvec2 { + #[cfg(not(any(feature = "cuda", target_arch = "spirv")))] + const_assert_eq!( + core::mem::align_of::(), + core::mem::align_of::() + ); + #[cfg(any(feature = "cuda", target_arch = "spirv"))] + const_assert_eq!(16, core::mem::align_of::()); + const_assert_eq!(16, core::mem::size_of::()); + } + + mod const_test_dvec3 { + #[cfg(not(target_arch = "spirv"))] + const_assert_eq!( + core::mem::align_of::(), + core::mem::align_of::() + ); + #[cfg(target_arch = "spirv")] + const_assert_eq!(16, core::mem::align_of::()); + const_assert_eq!(24, core::mem::size_of::()); + } + + mod const_test_dvec4 { + #[cfg(not(any(feature = "cuda", target_arch = "spirv")))] + const_assert_eq!( + core::mem::align_of::(), + core::mem::align_of::() + ); + #[cfg(any(feature = "cuda", target_arch = "spirv"))] + 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 0000000..4e1d76a --- /dev/null +++ b/src/f64/daffine2.rs @@ -0,0 +1,359 @@ +// Generated from affine.rs.tera template. Edit the template, not the generated file. + +use crate::{DMat2, DMat3, DVec2}; +use core::ops::{Deref, DerefMut, Mul}; + +/// 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. + #[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. + #[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::Cols3; + #[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 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 0000000..a5f4535 --- /dev/null +++ b/src/f64/daffine3.rs @@ -0,0 +1,520 @@ +// Generated from affine.rs.tera template. Edit the template, not the generated file. + +use crate::{DMat3, DMat4, DQuat, DVec3}; +use core::ops::{Deref, DerefMut, Mul}; + +/// 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. + #[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. + #[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(feature = "libm")] + #[allow(unused_imports)] + use num_traits::Float; + + 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()) + } + + /// Creates a left-handed view transform using a camera position, an up direction, and a facing + /// direction. + /// + /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=forward`. + #[inline] + pub fn look_to_lh(eye: DVec3, dir: DVec3, up: DVec3) -> Self { + Self::look_to_rh(eye, -dir, up) + } + + /// Creates a right-handed view transform using a camera position, an up direction, and a facing + /// direction. + /// + /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=back`. + #[inline] + pub fn look_to_rh(eye: DVec3, dir: DVec3, up: DVec3) -> Self { + let f = dir.normalize(); + let s = f.cross(up).normalize(); + let u = s.cross(f); + + 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(-eye.dot(s), -eye.dot(u), eye.dot(f)), + } + } + + /// 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_rh(eye, center - eye, 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::Cols4; + #[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 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 0000000..bd52c8c --- /dev/null +++ b/src/f64/dmat2.rs @@ -0,0 +1,448 @@ +// Generated from mat.rs.tera 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(feature = "libm")] +#[allow(unused_imports)] +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)))] +#[repr(C)] +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 const 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 const 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 const 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] + #[inline] + 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 Sum for DMat2 { + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, Self::add) + } +} + +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 Product for DMat2 { + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::IDENTITY, Self::mul) + } +} + +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 0000000..600223c --- /dev/null +++ b/src/f64/dmat3.rs @@ -0,0 +1,716 @@ +// Generated from mat.rs.tera 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(feature = "libm")] +#[allow(unused_imports)] +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)] +#[repr(C)] +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 const 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 const 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 const 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 4th 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`. + #[inline] + 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] + #[inline] + 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. + /// + /// # Panics + /// + /// Will panic if the 2nd row of `self` is not `(0, 0, 1)` when `glam_assert` is enabled. + #[inline] + pub fn transform_point2(&self, rhs: DVec2) -> DVec2 { + glam_assert!(self.row(2).abs_diff_eq(DVec3::Z, 1e-6)); + 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. + /// + /// # Panics + /// + /// Will panic if the 2nd row of `self` is not `(0, 0, 1)` when `glam_assert` is enabled. + #[inline] + pub fn transform_vector2(&self, rhs: DVec2) -> DVec2 { + glam_assert!(self.row(2).abs_diff_eq(DVec3::Z, 1e-6)); + 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 Sum for DMat3 { + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, Self::add) + } +} + +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 Product for DMat3 { + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::IDENTITY, Self::mul) + } +} + +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 0000000..cc4283c --- /dev/null +++ b/src/f64/dmat4.rs @@ -0,0 +1,1243 @@ +// Generated from mat.rs.tera 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(feature = "libm")] +#[allow(unused_imports)] +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)))] +#[repr(C)] +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 const 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 const 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 const 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, + ) + } + + #[inline] + 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) + } + + /// Creates a left-handed view matrix using a camera position, an up direction, and a facing + /// direction. + /// + /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=forward`. + #[inline] + pub fn look_to_lh(eye: DVec3, dir: DVec3, up: DVec3) -> Self { + Self::look_to_rh(eye, -dir, up) + } + + /// Creates a right-handed view matrix using a camera position, an up direction, and a facing + /// direction. + /// + /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=back`. + #[inline] + pub fn look_to_rh(eye: DVec3, dir: DVec3, up: DVec3) -> Self { + let f = dir.normalize(); + let s = f.cross(up).normalize(); + let u = s.cross(f); + + 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(-eye.dot(s), -eye.dot(u), eye.dot(f), 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_rh(eye, center.sub(eye), 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).abs_diff_eq(DVec4::W, 1e-6)); + 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).abs_diff_eq(DVec4::W, 1e-6)); + 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 Sum for DMat4 { + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, Self::add) + } +} + +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 Product for DMat4 { + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::IDENTITY, Self::mul) + } +} + +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 0000000..6f89430 --- /dev/null +++ b/src/f64/dquat.rs @@ -0,0 +1,848 @@ +// Generated from quat.rs.tera template. Edit the template, not the generated file. + +use crate::{ + euler::{EulerFromQuaternion, EulerRot, EulerToQuaternion}, + DMat3, DMat4, DVec2, DVec3, DVec4, FloatEx, Quat, +}; + +#[cfg(feature = "libm")] +#[allow(unused_imports)] +use num_traits::Float; + +#[cfg(not(target_arch = "spirv"))] +use core::fmt; +use core::iter::{Product, Sum}; +use core::ops::{Add, 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)] +#[cfg_attr(not(target_arch = "spirv"), repr(C))] +#[cfg_attr(target_arch = "spirv", repr(simd))] +pub struct DQuat { + pub x: f64, + pub y: f64, + pub z: f64, + pub 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` + 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 Sum for DQuat { + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, Self::add) + } +} + +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 Product for DQuat { + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::IDENTITY, Self::mul) + } +} + +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] + } +} diff --git a/src/f64/dvec2.rs b/src/f64/dvec2.rs new file mode 100644 index 0000000..c20404b --- /dev/null +++ b/src/f64/dvec2.rs @@ -0,0 +1,1047 @@ +// Generated from vec.rs.tera 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(feature = "libm")] +#[allow(unused_imports)] +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, PartialEq)] +#[cfg_attr(feature = "cuda", repr(align(16)))] +#[cfg_attr(not(target_arch = "spirv"), repr(C))] +#[cfg_attr(target_arch = "spirv", repr(simd))] +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); + + /// A unit-length vector pointing along the positive X axis. + pub const X: Self = Self::new(1.0, 0.0); + + /// A unit-length vector pointing along the positive Y axis. + pub const Y: Self = Self::new(0.0, 1.0); + + /// A unit-length vector pointing along the negative X axis. + pub const NEG_X: Self = Self::new(-1.0, 0.0); + + /// A unit-length vector pointing along the negative Y axis. + pub const NEG_Y: Self = Self::new(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 2 values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 2 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 2 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 where every component is the dot product of `self` and `rhs`. + #[inline] + pub fn dot_into_vec(self, rhs: Self) -> Self { + Self::splat(self.dot(rhs)) + } + + /// 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 [`f64::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 a bitmask with the lowest 2 bits set to the sign bits from the elements of `self`. + /// + /// A negative element results in a `1` bit and a positive element in a `0` bit. Element `x` goes + /// into the first lowest bit, element `y` into the second, etc. + #[inline] + pub fn is_negative_bitmask(self) -> u32 { + (self.x.is_sign_negative() as u32) | (self.y.is_sign_negative() as u32) << 1 + } + + /// 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 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 Sum for DVec2 { + #[inline] + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, Self::add) + } +} + +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 Product for DVec2 { + #[inline] + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ONE, Self::mul) + } +} + +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 0000000..8cfaef8 --- /dev/null +++ b/src/f64/dvec3.rs @@ -0,0 +1,1157 @@ +// Generated from vec.rs.tera 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(feature = "libm")] +#[allow(unused_imports)] +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, PartialEq)] +#[cfg_attr(not(target_arch = "spirv"), repr(C))] +#[cfg_attr(target_arch = "spirv", repr(simd))] +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); + + /// A unit-length vector pointing along the positive X axis. + pub const X: Self = Self::new(1.0, 0.0, 0.0); + + /// A unit-length vector pointing along the positive Y axis. + pub const Y: Self = Self::new(0.0, 1.0, 0.0); + + /// A unit-length vector pointing along the positive Z axis. + pub const Z: Self = Self::new(0.0, 0.0, 1.0); + + /// A unit-length vector pointing along the negative X axis. + pub const NEG_X: Self = Self::new(-1.0, 0.0, 0.0); + + /// A unit-length vector pointing along the negative Y axis. + pub const NEG_Y: Self = Self::new(0.0, -1.0, 0.0); + + /// A unit-length vector pointing along the negative Z axis. + pub const NEG_Z: Self = Self::new(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 3 values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 3 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 3 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) + } + + /// Returns a vector where every component is the dot product of `self` and `rhs`. + #[inline] + pub fn dot_into_vec(self, rhs: Self) -> Self { + Self::splat(self.dot(rhs)) + } + + /// 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 [`f64::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 a bitmask with the lowest 3 bits set to the sign bits from the elements of `self`. + /// + /// A negative element results in a `1` bit and a positive element in a `0` bit. Element `x` goes + /// into the first lowest bit, element `y` into the second, etc. + #[inline] + pub fn is_negative_bitmask(self) -> u32 { + (self.x.is_sign_negative() as u32) + | (self.y.is_sign_negative() as u32) << 1 + | (self.z.is_sign_negative() as u32) << 2 + } + + /// 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 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 Sum for DVec3 { + #[inline] + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, Self::add) + } +} + +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 Product for DVec3 { + #[inline] + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ONE, Self::mul) + } +} + +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 0000000..62ccf4f --- /dev/null +++ b/src/f64/dvec4.rs @@ -0,0 +1,1174 @@ +// Generated from vec.rs.tera 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(feature = "libm")] +#[allow(unused_imports)] +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, PartialEq)] +#[cfg_attr(feature = "cuda", repr(align(16)))] +#[cfg_attr(not(target_arch = "spirv"), repr(C))] +#[cfg_attr(target_arch = "spirv", repr(simd))] +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); + + /// A unit-length vector pointing along the positive X axis. + pub const X: Self = Self::new(1.0, 0.0, 0.0, 0.0); + + /// A unit-length vector pointing along the positive Y axis. + pub const Y: Self = Self::new(0.0, 1.0, 0.0, 0.0); + + /// A unit-length vector pointing along the positive Z axis. + pub const Z: Self = Self::new(0.0, 0.0, 1.0, 0.0); + + /// A unit-length vector pointing along the positive W axis. + pub const W: Self = Self::new(0.0, 0.0, 0.0, 1.0); + + /// A unit-length vector pointing along the negative X axis. + pub const NEG_X: Self = Self::new(-1.0, 0.0, 0.0, 0.0); + + /// A unit-length vector pointing along the negative Y axis. + pub const NEG_Y: Self = Self::new(0.0, -1.0, 0.0, 0.0); + + /// A unit-length vector pointing along the negative Z axis. + pub const NEG_Z: Self = Self::new(0.0, 0.0, -1.0, 0.0); + + /// A unit-length vector pointing along the negative W axis. + pub const NEG_W: Self = Self::new(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 4 values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 4 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 4 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 where every component is the dot product of `self` and `rhs`. + #[inline] + pub fn dot_into_vec(self, rhs: Self) -> Self { + Self::splat(self.dot(rhs)) + } + + /// 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 [`f64::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 a bitmask with the lowest 4 bits set to the sign bits from the elements of `self`. + /// + /// A negative element results in a `1` bit and a positive element in a `0` bit. Element `x` goes + /// into the first lowest bit, element `y` into the second, etc. + #[inline] + pub fn is_negative_bitmask(self) -> u32 { + (self.x.is_sign_negative() as u32) + | (self.y.is_sign_negative() as u32) << 1 + | (self.z.is_sign_negative() as u32) << 2 + | (self.w.is_sign_negative() as u32) << 3 + } + + /// 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 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 Sum for DVec4 { + #[inline] + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, Self::add) + } +} + +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 Product for DVec4 { + #[inline] + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ONE, Self::mul) + } +} + +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/features.rs b/src/features.rs new file mode 100644 index 0000000..6d6436d --- /dev/null +++ b/src/features.rs @@ -0,0 +1,17 @@ +#[cfg(feature = "approx")] +pub mod impl_approx; + +#[cfg(feature = "bytemuck")] +pub mod impl_bytemuck; + +#[cfg(feature = "mint")] +pub mod impl_mint; + +#[cfg(feature = "rand")] +pub mod impl_rand; + +#[cfg(feature = "serde")] +pub mod impl_serde; + +#[cfg(feature = "rkyv")] +pub mod impl_rkyv; diff --git a/src/features/impl_serde.rs b/src/features/impl_serde.rs index c1f4a94..c3a44e0 100644 --- a/src/features/impl_serde.rs +++ b/src/features/impl_serde.rs @@ -46,7 +46,7 @@ macro_rules! impl_serde_vec2 { #[test] fn test_vec2_serde() { - let a = $vec2::new(1 as $t, 2 as $t); + let a = $vec2::new(V1, V2); let serialized = serde_json::to_string(&a).unwrap(); assert_eq!(SX2, serialized); let deserialized = serde_json::from_str(&serialized).unwrap(); @@ -116,7 +116,7 @@ macro_rules! impl_serde_vec3 { #[test] fn $test_name() { - let a = $vec3::new(1 as $t, 2 as $t, 3 as $t); + let a = $vec3::new(V1, V2, V3); let serialized = serde_json::to_string(&a).unwrap(); assert_eq!(SX3, serialized); let deserialized = serde_json::from_str(&serialized).unwrap(); @@ -189,7 +189,7 @@ macro_rules! impl_serde_vec4 { #[test] fn test_vec4_serde() { - let a = $vec4::new(1 as $t, 2 as $t, 3 as $t, 4 as $t); + let a = $vec4::new(V1, V2, V3, V4); let serialized = serde_json::to_string(&a).unwrap(); assert_eq!(SX4, serialized); let deserialized = serde_json::from_str(&serialized).unwrap(); @@ -710,6 +710,38 @@ macro_rules! impl_serde_float_types { }; } +#[cfg(test)] +mod test_f32 { + pub const V1: f32 = 1.0; + pub const V2: f32 = 2.0; + pub const V3: f32 = 3.0; + pub const V4: f32 = 4.0; +} + +#[cfg(test)] +mod test_f64 { + pub const V1: f64 = 1.0; + pub const V2: f64 = 2.0; + pub const V3: f64 = 3.0; + pub const V4: f64 = 4.0; +} + +#[cfg(test)] +mod test_i32 { + pub const V1: i32 = 1; + pub const V2: i32 = 2; + pub const V3: i32 = 3; + pub const V4: i32 = 4; +} + +#[cfg(test)] +mod test_u32 { + pub const V1: u32 = 1; + pub const V2: u32 = 2; + pub const V3: u32 = 3; + pub const V4: u32 = 4; +} + #[cfg(test)] mod test_float { pub const SX0: &str = "[]"; @@ -730,7 +762,184 @@ mod test_int { pub const SX5: &str = "[1,2,3,4,5]"; } +#[cfg(test)] +mod test_bool_mask { + pub const SX0: &str = "[]"; + pub const SX1: &str = "[true]"; + pub const SX2: &str = "[true,true]"; + pub const SX3: &str = "[true,true,true]"; + pub const SX4: &str = "[true,true,true,true]"; + pub const SX5: &str = "[true,true,true,true,true]"; + pub const V1: bool = true; + pub const V2: bool = true; + pub const V3: bool = true; + pub const V4: bool = true; +} + +mod bool { + #[cfg(test)] + use super::test_bool_mask::*; + use crate::{BVec2, BVec3, BVec4}; + #[cfg(not(feature = "scalar-math"))] + use crate::{BVec3A, BVec4A}; + use core::fmt; + use serde::{ + de::{self, Deserialize, Deserializer, SeqAccess, Visitor}, + ser::{Serialize, SerializeTupleStruct, Serializer}, + }; + + impl_serde_vec2!(bool, BVec2); + impl_serde_vec3!(bool, BVec3); + impl_serde_vec4!(bool, BVec4); + + #[cfg(not(feature = "scalar-math"))] + impl Serialize for BVec3A { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut state = serializer.serialize_tuple_struct("BVec3A", 3)?; + let a: [bool; 3] = (*self).into(); + state.serialize_field(&a[0])?; + state.serialize_field(&a[1])?; + state.serialize_field(&a[2])?; + state.end() + } + } + + #[cfg(not(feature = "scalar-math"))] + impl<'de> Deserialize<'de> for BVec3A { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct Vec3Visitor; + + impl<'de> Visitor<'de> for Vec3Visitor { + type Value = BVec3A; + + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str("struct BVec3A") + } + + fn visit_seq(self, mut seq: V) -> Result + where + V: SeqAccess<'de>, + { + let x = seq + .next_element()? + .ok_or_else(|| de::Error::invalid_length(0, &self))?; + let y = seq + .next_element()? + .ok_or_else(|| de::Error::invalid_length(1, &self))?; + let z = seq + .next_element()? + .ok_or_else(|| de::Error::invalid_length(2, &self))?; + Ok(BVec3A::new(x, y, z)) + } + } + + deserializer.deserialize_tuple_struct(stringify!($vec3), 3, Vec3Visitor) + } + } + + #[cfg(not(feature = "scalar-math"))] + #[test] + fn test_bvec3a_serde() { + let a = BVec3A::new(V1, V2, V3); + let serialized = serde_json::to_string(&a).unwrap(); + assert_eq!(SX3, serialized); + let deserialized = serde_json::from_str(&serialized).unwrap(); + assert_eq!(a, deserialized); + let deserialized = serde_json::from_str::(SX0); + assert!(deserialized.is_err()); + let deserialized = serde_json::from_str::(SX1); + assert!(deserialized.is_err()); + let deserialized = serde_json::from_str::(SX2); + assert!(deserialized.is_err()); + let deserialized = serde_json::from_str::(SX4); + assert!(deserialized.is_err()); + } + + #[cfg(not(feature = "scalar-math"))] + impl Serialize for BVec4A { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut state = serializer.serialize_tuple_struct(stringify!(BVec4A), 4)?; + let a: [bool; 4] = (*self).into(); + state.serialize_field(&a[0])?; + state.serialize_field(&a[1])?; + state.serialize_field(&a[2])?; + state.serialize_field(&a[2])?; + state.end() + } + } + + #[cfg(not(feature = "scalar-math"))] + impl<'de> Deserialize<'de> for BVec4A { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct Vec4Visitor; + + impl<'de> Visitor<'de> for Vec4Visitor { + type Value = BVec4A; + + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str(concat!("struct ", stringify!(BVec4A))) + } + + fn visit_seq(self, mut seq: V) -> Result + where + V: SeqAccess<'de>, + { + let x = seq + .next_element()? + .ok_or_else(|| de::Error::invalid_length(0, &self))?; + let y = seq + .next_element()? + .ok_or_else(|| de::Error::invalid_length(1, &self))?; + let z = seq + .next_element()? + .ok_or_else(|| de::Error::invalid_length(2, &self))?; + let w = seq + .next_element()? + .ok_or_else(|| de::Error::invalid_length(3, &self))?; + Ok(BVec4A::new(x, y, z, w)) + } + } + + deserializer.deserialize_tuple_struct(stringify!(BVec4A), 4, Vec4Visitor) + } + } + + #[cfg(not(feature = "scalar-math"))] + #[test] + fn test_bvec4a_serde() { + let a = BVec4A::new(V1, V2, V3, V4); + let serialized = serde_json::to_string(&a).unwrap(); + assert_eq!(SX4, serialized); + let deserialized = serde_json::from_str(&serialized).unwrap(); + assert_eq!(a, deserialized); + let deserialized = serde_json::from_str::(SX0); + assert!(deserialized.is_err()); + let deserialized = serde_json::from_str::(SX1); + assert!(deserialized.is_err()); + let deserialized = serde_json::from_str::(SX2); + assert!(deserialized.is_err()); + let deserialized = serde_json::from_str::(SX3); + assert!(deserialized.is_err()); + let deserialized = serde_json::from_str::(SX5); + assert!(deserialized.is_err()); + } +} + mod f32 { + #[cfg(test)] + use super::test_f32::*; #[cfg(test)] use super::test_float::*; use crate::{Affine2, Affine3A, Mat2, Mat3, Mat3A, Mat4, Quat, Vec2, Vec3, Vec3A, Vec4}; @@ -746,6 +955,8 @@ mod f32 { } mod f64 { + #[cfg(test)] + use super::test_f64::*; #[cfg(test)] use super::test_float::*; use crate::{DAffine2, DAffine3, DMat2, DMat3, DMat4, DQuat, DVec2, DVec3, DVec4}; @@ -761,6 +972,8 @@ mod f64 { } mod i32 { + #[cfg(test)] + use super::test_i32::*; #[cfg(test)] use super::test_int::*; use crate::{IVec2, IVec3, IVec4}; @@ -776,6 +989,8 @@ mod i32 { mod u32 { #[cfg(test)] use super::test_int::*; + #[cfg(test)] + use super::test_u32::*; use crate::{UVec2, UVec3, UVec4}; use core::fmt; use serde::{ diff --git a/src/features/mod.rs b/src/features/mod.rs deleted file mode 100644 index 6d6436d..0000000 --- a/src/features/mod.rs +++ /dev/null @@ -1,17 +0,0 @@ -#[cfg(feature = "approx")] -pub mod impl_approx; - -#[cfg(feature = "bytemuck")] -pub mod impl_bytemuck; - -#[cfg(feature = "mint")] -pub mod impl_mint; - -#[cfg(feature = "rand")] -pub mod impl_rand; - -#[cfg(feature = "serde")] -pub mod impl_serde; - -#[cfg(feature = "rkyv")] -pub mod impl_rkyv; diff --git a/src/float_ex.rs b/src/float_ex.rs new file mode 100644 index 0000000..d972015 --- /dev/null +++ b/src/float_ex.rs @@ -0,0 +1,51 @@ +#[cfg(feature = "libm")] +#[allow(unused_imports)] +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 0000000..313f56c --- /dev/null +++ b/src/i32.rs @@ -0,0 +1,42 @@ +mod ivec2; +mod ivec3; +mod ivec4; + +pub use ivec2::{ivec2, IVec2}; +pub use ivec3::{ivec3, IVec3}; +pub use ivec4::{ivec4, IVec4}; + +#[cfg(not(target_arch = "spirv"))] +mod test { + use super::*; + + 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 0000000..87b5122 --- /dev/null +++ b/src/i32/ivec2.rs @@ -0,0 +1,958 @@ +// Generated from vec.rs.tera 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. +#[cfg_attr(not(target_arch = "spirv"), derive(Hash))] +#[derive(Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "cuda", repr(align(8)))] +#[cfg_attr(not(target_arch = "spirv"), repr(C))] +#[cfg_attr(target_arch = "spirv", repr(simd))] +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); + + /// A unit-length vector pointing along the positive X axis. + pub const X: Self = Self::new(1, 0); + + /// A unit-length vector pointing along the positive Y axis. + pub const Y: Self = Self::new(0, 1); + + /// A unit-length vector pointing along the negative X axis. + pub const NEG_X: Self = Self::new(-1, 0); + + /// A unit-length vector pointing along the negative Y axis. + pub const NEG_Y: Self = Self::new(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 2 values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 2 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 2 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 where every component is the dot product of `self` and `rhs`. + #[inline] + pub fn dot_into_vec(self, rhs: Self) -> Self { + Self::splat(self.dot(rhs)) + } + + /// 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 [`i32::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 bitmask with the lowest 2 bits set to the sign bits from the elements of `self`. + /// + /// A negative element results in a `1` bit and a positive element in a `0` bit. Element `x` goes + /// into the first lowest bit, element `y` into the second, etc. + #[inline] + pub fn is_negative_bitmask(self) -> u32 { + (self.x.is_negative() as u32) | (self.y.is_negative() as u32) << 1 + } + + /// 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 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 Sum for IVec2 { + #[inline] + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, Self::add) + } +} + +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 Product for IVec2 { + #[inline] + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ONE, Self::mul) + } +} + +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 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 0000000..6ccd5f9 --- /dev/null +++ b/src/i32/ivec3.rs @@ -0,0 +1,1036 @@ +// Generated from vec.rs.tera 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. +#[cfg_attr(not(target_arch = "spirv"), derive(Hash))] +#[derive(Clone, Copy, PartialEq, Eq)] +#[cfg_attr(not(target_arch = "spirv"), repr(C))] +#[cfg_attr(target_arch = "spirv", repr(simd))] +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); + + /// A unit-length vector pointing along the positive X axis. + pub const X: Self = Self::new(1, 0, 0); + + /// A unit-length vector pointing along the positive Y axis. + pub const Y: Self = Self::new(0, 1, 0); + + /// A unit-length vector pointing along the positive Z axis. + pub const Z: Self = Self::new(0, 0, 1); + + /// A unit-length vector pointing along the negative X axis. + pub const NEG_X: Self = Self::new(-1, 0, 0); + + /// A unit-length vector pointing along the negative Y axis. + pub const NEG_Y: Self = Self::new(0, -1, 0); + + /// A unit-length vector pointing along the negative Z axis. + pub const NEG_Z: Self = Self::new(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 3 values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 3 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 3 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) + } + + /// Returns a vector where every component is the dot product of `self` and `rhs`. + #[inline] + pub fn dot_into_vec(self, rhs: Self) -> Self { + Self::splat(self.dot(rhs)) + } + + /// 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 [`i32::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(), + } + } + + /// Returns a bitmask with the lowest 3 bits set to the sign bits from the elements of `self`. + /// + /// A negative element results in a `1` bit and a positive element in a `0` bit. Element `x` goes + /// into the first lowest bit, element `y` into the second, etc. + #[inline] + pub fn is_negative_bitmask(self) -> u32 { + (self.x.is_negative() as u32) + | (self.y.is_negative() as u32) << 1 + | (self.z.is_negative() as u32) << 2 + } + + /// 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 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 Sum for IVec3 { + #[inline] + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, Self::add) + } +} + +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 Product for IVec3 { + #[inline] + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ONE, Self::mul) + } +} + +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 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 0000000..5d875b2 --- /dev/null +++ b/src/i32/ivec4.rs @@ -0,0 +1,1129 @@ +// Generated from vec.rs.tera 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. +#[cfg_attr(not(target_arch = "spirv"), derive(Hash))] +#[derive(Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "cuda", repr(align(16)))] +#[cfg_attr(not(target_arch = "spirv"), repr(C))] +#[cfg_attr(target_arch = "spirv", repr(simd))] +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); + + /// A unit-length vector pointing along the positive X axis. + pub const X: Self = Self::new(1, 0, 0, 0); + + /// A unit-length vector pointing along the positive Y axis. + pub const Y: Self = Self::new(0, 1, 0, 0); + + /// A unit-length vector pointing along the positive Z axis. + pub const Z: Self = Self::new(0, 0, 1, 0); + + /// A unit-length vector pointing along the positive W axis. + pub const W: Self = Self::new(0, 0, 0, 1); + + /// A unit-length vector pointing along the negative X axis. + pub const NEG_X: Self = Self::new(-1, 0, 0, 0); + + /// A unit-length vector pointing along the negative Y axis. + pub const NEG_Y: Self = Self::new(0, -1, 0, 0); + + /// A unit-length vector pointing along the negative Z axis. + pub const NEG_Z: Self = Self::new(0, 0, -1, 0); + + /// A unit-length vector pointing along the negative W axis. + pub const NEG_W: Self = Self::new(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 4 values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 4 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 4 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 where every component is the dot product of `self` and `rhs`. + #[inline] + pub fn dot_into_vec(self, rhs: Self) -> Self { + Self::splat(self.dot(rhs)) + } + + /// 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 [`i32::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(), + } + } + + /// Returns a bitmask with the lowest 4 bits set to the sign bits from the elements of `self`. + /// + /// A negative element results in a `1` bit and a positive element in a `0` bit. Element `x` goes + /// into the first lowest bit, element `y` into the second, etc. + #[inline] + pub fn is_negative_bitmask(self) -> u32 { + (self.x.is_negative() as u32) + | (self.y.is_negative() as u32) << 1 + | (self.z.is_negative() as u32) << 2 + | (self.w.is_negative() as u32) << 3 + } + + /// 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 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 Sum for IVec4 { + #[inline] + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, Self::add) + } +} + +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 Product for IVec4 { + #[inline] + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ONE, Self::mul) + } +} + +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 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 1e92a63..b26016c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -219,6 +219,11 @@ and benchmarks. * `num-traits` - required to compile `no_std`, will be included when enabling the `libm` feature * `rand` - implementations of `Distribution` trait for all `glam` types. +* `rkyv` - implementations of `Archive`, `Serialize` and `Deserialize` for all + `glam` types. Note that serialization is not interoperable with and without the + `scalar-math` feature. It should work between all other builds of `glam`. + Endian conversion is currently not supported +* `bytecheck` - to perform archive validation when using the `rkyv` feature * `serde` - implementations of `Serialize` and `Deserialize` for all `glam` types. Note that serialization should work between builds of `glam` with and without SIMD enabled * `scalar-math` - disables SIMD support and uses native alignment for all types. @@ -226,118 +231,93 @@ and benchmarks. passed to `glam` to help catch runtime errors. * `glam-assert` - adds assertions to all builds which check the validity of parameters passed to `glam` to help catch runtime errors. +* `cuda` - forces `glam` types to match expected cuda alignment +* `fast-math` - By default, glam attempts to provide bit-for-bit identical + results on all platforms. Using this feature will enable platform specific + optimizations that may not be identical to other platforms. **Intermediate + libraries should not use this feature and defer the decision to the final + binary build**. +* `core-simd` - enables SIMD support via the portable simd module. This is an + unstable feature which requires a nightly Rust toolchain and `std` support. ## 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.3")] +#![doc(html_root_url = "https://docs.rs/glam/0.22.0")] #![cfg_attr(not(feature = "std"), no_std)] -#![cfg_attr(target_arch = "spirv", feature(asm, register_attr, repr_simd))] +#![cfg_attr(target_arch = "spirv", feature(repr_simd))] #![deny( rust_2018_compatibility, rust_2018_idioms, future_incompatible, nonstandard_style )] -// This would require renaming a lot of stuff, disabling for now. -#![allow(clippy::upper_case_acronyms)] // clippy doesn't like `to_array(&self)` #![allow(clippy::wrong_self_convention)] +#![cfg_attr( + all(feature = "core-simd", not(feature = "scalar-math")), + feature(portable_simd) +)] #[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(any(feature = "core-simd", feature = "scalar-math")) +))] +mod sse2; + +#[cfg(all( + target_feature = "simd128", + not(any(feature = "core-simd", feature = "scalar-math")) +))] +mod wasm32; + +#[cfg(all(feature = "core-simd", not(feature = "scalar-math")))] +mod coresimd; -#[doc(hidden)] -pub use self::core::storage::{XY, XYZ, XYZW}; +#[cfg(all( + target_feature = "sse2", + not(any(feature = "core-simd", feature = "scalar-math")) +))] +use align16::Align16; + +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 721face..579a7a9 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -15,13 +15,8 @@ macro_rules! glam_assert { macro_rules! const_assert { ($x:expr $(,)?) => { - // 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); }; } @@ -30,455 +25,3 @@ macro_rules! const_assert_eq { const_assert!($x == $y); }; } - -#[macro_export] -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -macro_rules! const_m128 { - ($fx4:expr) => { - unsafe { $crate::cast::Vec4Cast { fx4: $fx4 }.m128 } - }; -} - -#[cfg(all(target_feature = "sse2", not(feature = "scalar-math")))] -macro_rules! const_f32x4 { - ($fx4:expr) => { - unsafe { $crate::cast::Vec4Cast { fx4: $fx4 }.m128 } - }; -} - -#[cfg(all(target_feature = "simd128", not(feature = "scalar-math")))] -macro_rules! const_f32x4 { - ($fx4:expr) => { - unsafe { $crate::cast::Vec4Cast { fx4: $fx4 }.v128 } - }; -} - -/// Creates a `Vec2` that can be used to initialize a constant value. -/// -/// ``` -/// use glam::{const_vec2, Vec2}; -/// const ONE: Vec2 = const_vec2!([1.0; 2]); -/// const X: Vec2 = const_vec2!([1.0, 0.0]); -/// ``` -#[macro_export] -macro_rules! const_vec2 { - ($fx2:expr) => { - unsafe { $crate::cast::Vec2Cast { fx2: $fx2 }.v2 } - }; -} - -/// Creates a `Vec3` that can be used to initialize a constant value. -/// -/// ``` -/// use glam::{const_vec3, Vec3}; -/// const ONE: Vec3 = const_vec3!([1.0; 3]); -/// const X: Vec3 = const_vec3!([1.0, 0.0, 0.0]); -/// ``` -#[macro_export] -macro_rules! const_vec3 { - ($fx3:expr) => { - unsafe { $crate::cast::Vec3Cast { fx3: $fx3 }.v3 } - }; -} - -/// Creates a `Vec3A` that can be used to initialize a constant value. -/// -/// ``` -/// use glam::{const_vec3a, Vec3A}; -/// const ONE: Vec3A = const_vec3a!([1.0; 3]); -/// const X: Vec3A = const_vec3a!([1.0, 0.0, 0.0]); -/// ``` -#[macro_export] -macro_rules! const_vec3a { - ($fx3:expr) => { - unsafe { - $crate::cast::Vec4Cast { - fx4: [$fx3[0], $fx3[1], $fx3[2], 0.0], - } - .v3a - } - }; -} - -/// Creates a `Vec4` that can be used to initialize a constant value. -/// -/// ``` -/// use glam::{const_vec4, Vec4}; -/// const ONE: Vec4 = const_vec4!([1.0; 4]); -/// const X: Vec4 = const_vec4!([1.0, 0.0, 0.0, 0.0]); -/// ``` -#[macro_export] -macro_rules! const_vec4 { - ($fx4:expr) => { - unsafe { $crate::cast::Vec4Cast { fx4: $fx4 }.v4 } - }; -} - -/// Creates a `Mat2` from two column vectors that can be used to initialize a constant value. -/// -/// ``` -/// use glam::{const_mat2, Mat2}; -/// const ZERO: Mat2 = const_mat2!([0.0; 4]); -/// const IDENTITY: Mat2 = const_mat2!([1.0, 0.0], [0.0, 1.0]); -/// ``` -#[macro_export] -macro_rules! const_mat2 { - ($col0:expr, $col1:expr) => { - unsafe { - $crate::cast::Mat2Cast { - v2x2: [$crate::const_vec2!($col0), $crate::const_vec2!($col1)], - } - .m2 - } - }; - ($fx4:expr) => { - $crate::const_mat2!( - $crate::cast::Vec4Cast { fx4: $fx4 }.fx2x2[0], - $crate::cast::Vec4Cast { fx4: $fx4 }.fx2x2[1] - ) - }; -} - -/// Creates a `Mat3` from three column vectors that can be used to initialize a constant value. -/// -/// ``` -/// use glam::{const_mat3, Mat3}; -/// 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]); -/// ``` -#[macro_export] -macro_rules! const_mat3 { - ($col0:expr, $col1:expr, $col2:expr) => { - unsafe { - $crate::cast::Mat3Cast { - v3x3: [ - $crate::const_vec3!($col0), - $crate::const_vec3!($col1), - $crate::const_vec3!($col2), - ], - } - .m3 - } - }; - ($fx9:expr) => { - $crate::const_mat3!( - $crate::cast::F32x9Cast { fx9: $fx9 }.fx3x3[0], - $crate::cast::F32x9Cast { fx9: $fx9 }.fx3x3[1], - $crate::cast::F32x9Cast { fx9: $fx9 }.fx3x3[2] - ) - }; -} - -/// Creates a `Mat3A` from three column vectors that can be used to initialize a constant value. -/// -/// ``` -/// use glam::{const_mat3a, Mat3A}; -/// 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]); -/// ``` -#[macro_export] -macro_rules! const_mat3a { - ($col0:expr, $col1:expr, $col2:expr) => { - unsafe { - $crate::cast::Mat3ACast { - v3x3: [ - $crate::const_vec3a!($col0), - $crate::const_vec3a!($col1), - $crate::const_vec3a!($col2), - ], - } - .m3 - } - }; - ($fx9:expr) => { - $crate::const_mat3a!( - $crate::cast::F32x9Cast { fx9: $fx9 }.fx3x3[0], - $crate::cast::F32x9Cast { fx9: $fx9 }.fx3x3[1], - $crate::cast::F32x9Cast { fx9: $fx9 }.fx3x3[2] - ) - }; -} - -/// Creates a `Mat4` from four column vectors that can be used to initialize a constant value. -/// -/// ``` -/// use glam::{const_mat4, Mat4}; -/// const ZERO: Mat4 = const_mat4!([0.0; 16]); -/// const IDENTITY: Mat4 = const_mat4!( -/// [1.0, 0.0, 0.0, 0.0], -/// [0.0, 1.0, 0.0, 0.0], -/// [0.0, 0.0, 1.0, 0.0], -/// [0.0, 0.0, 0.0, 1.0] -/// ); -/// ``` -#[macro_export] -macro_rules! const_mat4 { - ($col0:expr, $col1:expr, $col2:expr, $col3:expr) => { - unsafe { - $crate::cast::Mat4Cast { - v4x4: [ - $crate::const_vec4!($col0), - $crate::const_vec4!($col1), - $crate::const_vec4!($col2), - $crate::const_vec4!($col3), - ], - } - .m4 - } - }; - ($fx16:expr) => { - $crate::const_mat4!( - $crate::cast::F32x16Cast { fx16: $fx16 }.fx4x4[0], - $crate::cast::F32x16Cast { fx16: $fx16 }.fx4x4[1], - $crate::cast::F32x16Cast { fx16: $fx16 }.fx4x4[2], - $crate::cast::F32x16Cast { fx16: $fx16 }.fx4x4[3] - ) - }; -} - -/// Creates a `Quat` from `x`, `y`, `z` and `w` values that can be used to initialize a constant -/// value. -/// -/// ``` -/// use glam::{const_quat, Quat}; -/// const IDENTITY: Quat = const_quat!([0.0, 0.0, 0.0, 1.0]); -/// ``` -#[macro_export] -macro_rules! const_quat { - ($fx4:expr) => { - unsafe { $crate::cast::Vec4Cast { fx4: $fx4 }.q } - }; -} - -/// Creates a `DVec2` that can be used to initialize a constant value. -/// -/// ``` -/// use glam::{const_dvec2, DVec2}; -/// const ONE: DVec2 = const_dvec2!([1.0; 2]); -/// const X: DVec2 = const_dvec2!([1.0, 0.0]); -/// ``` -#[macro_export] -macro_rules! const_dvec2 { - ($fx2:expr) => { - unsafe { $crate::cast::DVec2Cast { fx2: $fx2 }.v2 } - }; -} - -/// Creates a `DVec3` that can be used to initialize a constant value. -/// -/// ``` -/// use glam::{const_dvec3, DVec3}; -/// const ONE: DVec3 = const_dvec3!([1.0; 3]); -/// const X: DVec3 = const_dvec3!([1.0, 0.0, 0.0]); -/// ``` -#[macro_export] -macro_rules! const_dvec3 { - ($fx3:expr) => { - unsafe { $crate::cast::DVec3Cast { fx3: $fx3 }.v3 } - }; -} - -/// Creates a `DVec4` that can be used to initialize a constant value. -/// -/// ``` -/// use glam::{const_dvec4, DVec4}; -/// const ONE: DVec4 = const_dvec4!([1.0; 4]); -/// const X: DVec4 = const_dvec4!([1.0, 0.0, 0.0, 0.0]); -/// ``` -#[macro_export] -macro_rules! const_dvec4 { - ($fx4:expr) => { - unsafe { $crate::cast::DVec4Cast { fx4: $fx4 }.v4 } - }; -} - -/// Creates a `DMat2` from two column vectors that can be used to initialize a constant value. -/// -/// ``` -/// use glam::{const_dmat2, DMat2}; -/// const ZERO: DMat2 = const_dmat2!([0.0; 4]); -/// const IDENTITY: DMat2 = const_dmat2!([1.0, 0.0], [0.0, 1.0]); -/// ``` -#[macro_export] -macro_rules! const_dmat2 { - ($col0:expr, $col1:expr) => { - unsafe { - $crate::cast::DMat2Cast { - v2x2: [$crate::const_dvec2!($col0), $crate::const_dvec2!($col1)], - } - .m2 - } - }; - ($fx4:expr) => { - $crate::const_dmat2!( - $crate::cast::DVec4Cast { fx4: $fx4 }.fx2x2[0], - $crate::cast::DVec4Cast { fx4: $fx4 }.fx2x2[1] - ) - }; -} - -/// Creates a `DMat3` from three column vectors that can be used to initialize a constant value. -/// -/// ``` -/// # #[macro_use] extern crate glam; -/// use glam::{const_dmat3, DMat3}; -/// 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]); -/// ``` -#[macro_export] -macro_rules! const_dmat3 { - ($col0:expr, $col1:expr, $col2:expr) => { - unsafe { - $crate::cast::DMat3Cast { - v3x3: [ - $crate::const_dvec3!($col0), - $crate::const_dvec3!($col1), - $crate::const_dvec3!($col2), - ], - } - .m3 - } - }; - ($fx9:expr) => { - $crate::const_dmat3!( - $crate::cast::F64x9Cast { fx9: $fx9 }.fx3x3[0], - $crate::cast::F64x9Cast { fx9: $fx9 }.fx3x3[1], - $crate::cast::F64x9Cast { fx9: $fx9 }.fx3x3[2] - ) - }; -} - -/// Creates a `DMat4` from four column vectors that can be used to initialize a constant value. -/// -/// ``` -/// use glam::{const_dmat4, DMat4}; -/// const ZERO: DMat4 = const_dmat4!([0.0; 16]); -/// const IDENTITY: DMat4 = const_dmat4!( -/// [1.0, 0.0, 0.0, 0.0], -/// [0.0, 1.0, 0.0, 0.0], -/// [0.0, 0.0, 1.0, 0.0], -/// [0.0, 0.0, 0.0, 1.0] -/// ); -/// ``` -#[macro_export] -macro_rules! const_dmat4 { - ($col0:expr, $col1:expr, $col2:expr, $col3:expr) => { - unsafe { - $crate::cast::DMat4Cast { - v4x4: [ - $crate::const_dvec4!($col0), - $crate::const_dvec4!($col1), - $crate::const_dvec4!($col2), - $crate::const_dvec4!($col3), - ], - } - .m4 - } - }; - ($fx16:expr) => { - $crate::const_dmat4!( - $crate::cast::F64x16Cast { fx16: $fx16 }.fx4x4[0], - $crate::cast::F64x16Cast { fx16: $fx16 }.fx4x4[1], - $crate::cast::F64x16Cast { fx16: $fx16 }.fx4x4[2], - $crate::cast::F64x16Cast { fx16: $fx16 }.fx4x4[3] - ) - }; -} - -/// Creates a `DQuat` from `x`, `y`, `z` and `w` values that can be used to initialize a constant -/// value. -/// -/// ``` -/// use glam::{const_dquat, DQuat}; -/// const IDENTITY: DQuat = const_dquat!([0.0, 0.0, 0.0, 1.0]); -/// ``` -#[macro_export] -macro_rules! const_dquat { - ($fx4:expr) => { - unsafe { $crate::cast::DVec4Cast { fx4: $fx4 }.q } - }; -} - -/// Creates a `IVec2` that can be used to initialize a constant value. -/// -/// ``` -/// use glam::{const_ivec2, IVec2}; -/// const ONE: IVec2 = const_ivec2!([1; 2]); -/// const X: IVec2 = const_ivec2!([1, 0]); -/// ``` -#[macro_export] -macro_rules! const_ivec2 { - ($ix2:expr) => { - unsafe { $crate::cast::IVec2Cast { ix2: $ix2 }.v2 } - }; -} - -/// Creates a `IVec3` that can be used to initialize a constant value. -/// -/// ``` -/// use glam::{const_ivec3, IVec3}; -/// const ONE: IVec3 = const_ivec3!([1; 3]); -/// const X: IVec3 = const_ivec3!([1, 0, 0]); -/// ``` -#[macro_export] -macro_rules! const_ivec3 { - ($ix3:expr) => { - unsafe { $crate::cast::IVec3Cast { ix3: $ix3 }.v3 } - }; -} - -/// Creates a `IVec4` that can be used to initialize a constant value. -/// -/// ``` -/// use glam::{const_ivec4, IVec4}; -/// const ONE: IVec4 = const_ivec4!([1; 4]); -/// const X: IVec4 = const_ivec4!([1, 0, 0, 0]); -/// ``` -#[macro_export] -macro_rules! const_ivec4 { - ($ix4:expr) => { - unsafe { $crate::cast::IVec4Cast { ix4: $ix4 }.v4 } - }; -} - -/// Creates a `UVec2` that can be used to initialize a constant value. -/// -/// ``` -/// use glam::{const_uvec2, UVec2}; -/// const ONE: UVec2 = const_uvec2!([1; 2]); -/// const X: UVec2 = const_uvec2!([1, 0]); -/// ``` -#[macro_export] -macro_rules! const_uvec2 { - ($ux2:expr) => { - unsafe { $crate::cast::UVec2Cast { ux2: $ux2 }.v2 } - }; -} - -/// Creates a `UVec3` that can be used to initialize a constant value. -/// -/// ``` -/// use glam::{const_uvec3, UVec3}; -/// const ONE: UVec3 = const_uvec3!([1; 3]); -/// const X: UVec3 = const_uvec3!([1, 0, 0]); -/// ``` -#[macro_export] -macro_rules! const_uvec3 { - ($ux3:expr) => { - unsafe { $crate::cast::UVec3Cast { ux3: $ux3 }.v3 } - }; -} - -/// Creates a `UVec4` that can be used to initialize a constant value. -/// -/// ``` -/// use glam::{const_uvec4, UVec4}; -/// const ONE: UVec4 = const_uvec4!([1; 4]); -/// const X: UVec4 = const_uvec4!([1, 0, 0, 0]); -/// ``` -#[macro_export] -macro_rules! const_uvec4 { - ($ux4:expr) => { - unsafe { $crate::cast::UVec4Cast { ux4: $ux4 }.v4 } - }; -} diff --git a/src/mat.rs b/src/mat.rs deleted file mode 100644 index b97e8ed..0000000 --- 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 36ced76..0000000 --- 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 564832a..0000000 --- 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 fab1b73..0000000 --- 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 135c942..0000000 --- a/src/quat.rs +++ /dev/null @@ -1,825 +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`. - /// - /// 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`. - /// - /// # 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/sse2.rs b/src/sse2.rs new file mode 100644 index 0000000..e1e6b74 --- /dev/null +++ b/src/sse2.rs @@ -0,0 +1,238 @@ +#[cfg(target_arch = "x86")] +use core::arch::x86::*; +#[cfg(target_arch = "x86_64")] +use core::arch::x86_64::*; + +union UnionCast { + u32x4: [u32; 4], + f32x4: [f32; 4], + m128: __m128, +} + +pub const fn m128_from_f32x4(f32x4: [f32; 4]) -> __m128 { + unsafe { UnionCast { f32x4 }.m128 } +} + +const fn m128_from_u32x4(u32x4: [u32; 4]) -> __m128 { + unsafe { UnionCast { u32x4 }.m128 } +} + +const PS_INV_SIGN_MASK: __m128 = m128_from_u32x4([!0x8000_0000; 4]); +const PS_SIGN_MASK: __m128 = m128_from_u32x4([0x8000_0000; 4]); +const PS_NO_FRACTION: __m128 = m128_from_f32x4([8388608.0; 4]); +const PS_NEGATIVE_ZERO: __m128 = m128_from_u32x4([0x8000_0000; 4]); +const PS_PI: __m128 = m128_from_f32x4([core::f32::consts::PI; 4]); +const PS_HALF_PI: __m128 = m128_from_f32x4([core::f32::consts::FRAC_PI_2; 4]); +const PS_SIN_COEFFICIENTS0: __m128 = + m128_from_f32x4([-0.16666667, 0.008_333_331, -0.00019840874, 2.752_556_2e-6]); +const PS_SIN_COEFFICIENTS1: __m128 = m128_from_f32x4([ + -2.388_985_9e-8, + -0.16665852, /*Est1*/ + 0.008_313_95, /*Est2*/ + -0.000_185_246_7, /*Est3*/ +]); +const PS_ONE: __m128 = m128_from_f32x4([1.0; 4]); +const PS_TWO_PI: __m128 = m128_from_f32x4([core::f32::consts::TAU; 4]); +const PS_RECIPROCAL_TWO_PI: __m128 = m128_from_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 dot3(lhs: __m128, rhs: __m128) -> f32 { + _mm_cvtss_f32(dot3_in_x(lhs, rhs)) +} + +#[inline] +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] +pub(crate) unsafe fn m128_floor(v: __m128) -> __m128 { + // Based on https://github.com/microsoft/DirectXMath `XMVectorFloor` + // To handle NAN, INF and numbers greater than 8388608, use masking + let test = _mm_and_si128(_mm_castps_si128(v), _mm_castps_si128(PS_INV_SIGN_MASK)); + let test = _mm_cmplt_epi32(test, _mm_castps_si128(PS_NO_FRACTION)); + // Truncate + let vint = _mm_cvttps_epi32(v); + let result = _mm_cvtepi32_ps(vint); + let larger = _mm_cmpgt_ps(result, v); + // 0 -> 0, 0xffffffff -> -1.0f + let larger = _mm_cvtepi32_ps(_mm_castps_si128(larger)); + let result = _mm_add_ps(result, larger); + // All numbers less than 8388608 will use the round to int + let result = _mm_and_ps(result, _mm_castsi128_ps(test)); + // All others, use the ORIGINAL value + let test = _mm_andnot_si128(test, _mm_castps_si128(v)); + _mm_or_ps(result, _mm_castsi128_ps(test)) +} + +#[inline] +pub(crate) unsafe fn m128_ceil(v: __m128) -> __m128 { + // Based on https://github.com/microsoft/DirectXMath `XMVectorCeil` + // To handle NAN, INF and numbers greater than 8388608, use masking + let test = _mm_and_si128(_mm_castps_si128(v), _mm_castps_si128(PS_INV_SIGN_MASK)); + let test = _mm_cmplt_epi32(test, _mm_castps_si128(PS_NO_FRACTION)); + // Truncate + let vint = _mm_cvttps_epi32(v); + let result = _mm_cvtepi32_ps(vint); + let smaller = _mm_cmplt_ps(result, v); + // 0 -> 0, 0xffffffff -> -1.0f + let smaller = _mm_cvtepi32_ps(_mm_castps_si128(smaller)); + let result = _mm_sub_ps(result, smaller); + // All numbers less than 8388608 will use the round to int + let result = _mm_and_ps(result, _mm_castsi128_ps(test)); + // All others, use the ORIGINAL value + let test = _mm_andnot_si128(test, _mm_castps_si128(v)); + _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 + // platform supports it. Otherwise this may break cross-platform determinism. + #[cfg(all(feature = "fast-math", target_feature = "fma"))] + { + _mm_fmadd_ps(a, b, c) + } + + #[cfg(any(not(feature = "fast-math"), not(target_feature = "fma")))] + { + _mm_add_ps(_mm_mul_ps(a, b), c) + } +} + +#[inline(always)] +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 { + // Based on https://github.com/microsoft/DirectXMath `XMVectorModAngles` + let v = _mm_mul_ps(angles, PS_RECIPROCAL_TWO_PI); + let v = m128_round(v); + m128_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) unsafe fn m128_sin(v: __m128) -> __m128 { + // Based on https://github.com/microsoft/DirectXMath `XMVectorSin` + + // 11-degree minimax approximation + + // Force the value within the bounds of pi + let mut x = m128_mod_angles(v); + + // Map in [-pi/2,pi/2] with sin(y) = sin(x). + let sign = _mm_and_ps(x, PS_NEGATIVE_ZERO); + // pi when x >= 0, -pi when x < 0 + let c = _mm_or_ps(PS_PI, sign); + // |x| + let absx = _mm_andnot_ps(sign, x); + let rflx = _mm_sub_ps(c, x); + let comp = _mm_cmple_ps(absx, PS_HALF_PI); + let select0 = _mm_and_ps(comp, x); + let select1 = _mm_andnot_ps(comp, rflx); + x = _mm_or_ps(select0, select1); + + let x2 = _mm_mul_ps(x, x); + + // Compute polynomial approximation + const SC1: __m128 = PS_SIN_COEFFICIENTS1; + let v_constants_b = _mm_shuffle_ps(SC1, SC1, 0b00_00_00_00); + + const SC0: __m128 = PS_SIN_COEFFICIENTS0; + let mut v_constants = _mm_shuffle_ps(SC0, SC0, 0b11_11_11_11); + let mut result = m128_mul_add(v_constants_b, x2, v_constants); + + v_constants = _mm_shuffle_ps(SC0, SC0, 0b10_10_10_10); + result = m128_mul_add(result, x2, v_constants); + + v_constants = _mm_shuffle_ps(SC0, SC0, 0b01_01_01_01); + result = m128_mul_add(result, x2, v_constants); + + v_constants = _mm_shuffle_ps(SC0, SC0, 0b00_00_00_00); + result = m128_mul_add(result, x2, v_constants); + + result = m128_mul_add(result, x2, PS_ONE); + result = _mm_mul_ps(result, x); + + result +} + +#[test] +fn test_sse2_m128_sin() { + 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 = Vec4(v); + let a_sin = a.sin(); + // dbg!((a, a_sin, v)); + assert!(v.abs_diff_eq(Vec4::splat(a_sin), 1e-6)); + } + + let mut a = -PI; + let end = PI; + let step = PI / 8192.0; + + while a <= end { + test_sse2_m128_sin_angle(a); + a += step; + } +} diff --git a/src/swizzles.rs b/src/swizzles.rs new file mode 100644 index 0000000..61a3391 --- /dev/null +++ b/src/swizzles.rs @@ -0,0 +1,42 @@ +mod dvec2_impl; +mod dvec3_impl; +mod dvec4_impl; + +mod ivec2_impl; +mod ivec3_impl; +mod ivec4_impl; + +mod uvec2_impl; +mod uvec3_impl; +mod uvec4_impl; + +mod vec2_impl; +mod vec3_impl; + +#[cfg(any( + not(any( + feature = "core-simd", + target_feature = "sse2", + target_feature = "simd128" + )), + feature = "scalar-math" +))] +mod scalar; + +#[cfg(all( + target_feature = "sse2", + not(any(feature = "core-simd", feature = "scalar-math")) +))] +mod sse2; + +#[cfg(all( + target_feature = "simd128", + not(any(feature = "core-simd", feature = "scalar-math")) +))] +mod wasm32; + +#[cfg(all(feature = "core-simd", not(feature = "scalar-math")))] +mod coresimd; + +mod vec_traits; +pub use vec_traits::*; diff --git a/src/swizzles/coresimd.rs b/src/swizzles/coresimd.rs new file mode 100644 index 0000000..10479c8 --- /dev/null +++ b/src/swizzles/coresimd.rs @@ -0,0 +1,2 @@ +mod vec3a_impl; +mod vec4_impl; diff --git a/src/swizzles/coresimd/vec3a_impl.rs b/src/swizzles/coresimd/vec3a_impl.rs new file mode 100644 index 0000000..5ea3a8d --- /dev/null +++ b/src/swizzles/coresimd/vec3a_impl.rs @@ -0,0 +1,625 @@ +// Generated from swizzle_impl.rs.tera template. Edit the template, not the generated file. + +#![allow(clippy::useless_conversion)] + +use crate::{Vec2, Vec3A, Vec3Swizzles, Vec4}; + +use core::simd::*; + +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(simd_swizzle!(self.0, [0, 0, 0, 0]).into()) + } + + #[inline] + fn xxy(self) -> Vec3A { + Vec3A(simd_swizzle!(self.0, [0, 0, 1, 0]).into()) + } + + #[inline] + fn xxz(self) -> Vec3A { + Vec3A(simd_swizzle!(self.0, [0, 0, 2, 0]).into()) + } + + #[inline] + fn xyx(self) -> Vec3A { + Vec3A(simd_swizzle!(self.0, [0, 1, 0, 0]).into()) + } + + #[inline] + fn xyy(self) -> Vec3A { + Vec3A(simd_swizzle!(self.0, [0, 1, 1, 0]).into()) + } + + #[inline] + fn xyz(self) -> Vec3A { + Vec3A(simd_swizzle!(self.0, [0, 1, 2, 0]).into()) + } + + #[inline] + fn xzx(self) -> Vec3A { + Vec3A(simd_swizzle!(self.0, [0, 2, 0, 0]).into()) + } + + #[inline] + fn xzy(self) -> Vec3A { + Vec3A(simd_swizzle!(self.0, [0, 2, 1, 0]).into()) + } + + #[inline] + fn xzz(self) -> Vec3A { + Vec3A(simd_swizzle!(self.0, [0, 2, 2, 0]).into()) + } + + #[inline] + fn yxx(self) -> Vec3A { + Vec3A(simd_swizzle!(self.0, [1, 0, 0, 0]).into()) + } + + #[inline] + fn yxy(self) -> Vec3A { + Vec3A(simd_swizzle!(self.0, [1, 0, 1, 0]).into()) + } + + #[inline] + fn yxz(self) -> Vec3A { + Vec3A(simd_swizzle!(self.0, [1, 0, 2, 0]).into()) + } + + #[inline] + fn yyx(self) -> Vec3A { + Vec3A(simd_swizzle!(self.0, [1, 1, 0, 0]).into()) + } + + #[inline] + fn yyy(self) -> Vec3A { + Vec3A(simd_swizzle!(self.0, [1, 1, 1, 0]).into()) + } + + #[inline] + fn yyz(self) -> Vec3A { + Vec3A(simd_swizzle!(self.0, [1, 1, 2, 0]).into()) + } + + #[inline] + fn yzx(self) -> Vec3A { + Vec3A(simd_swizzle!(self.0, [1, 2, 0, 0]).into()) + } + + #[inline] + fn yzy(self) -> Vec3A { + Vec3A(simd_swizzle!(self.0, [1, 2, 1, 0]).into()) + } + + #[inline] + fn yzz(self) -> Vec3A { + Vec3A(simd_swizzle!(self.0, [1, 2, 2, 0]).into()) + } + + #[inline] + fn zxx(self) -> Vec3A { + Vec3A(simd_swizzle!(self.0, [2, 0, 0, 0]).into()) + } + + #[inline] + fn zxy(self) -> Vec3A { + Vec3A(simd_swizzle!(self.0, [2, 0, 1, 0]).into()) + } + + #[inline] + fn zxz(self) -> Vec3A { + Vec3A(simd_swizzle!(self.0, [2, 0, 2, 0]).into()) + } + + #[inline] + fn zyx(self) -> Vec3A { + Vec3A(simd_swizzle!(self.0, [2, 1, 0, 0]).into()) + } + + #[inline] + fn zyy(self) -> Vec3A { + Vec3A(simd_swizzle!(self.0, [2, 1, 1, 0]).into()) + } + + #[inline] + fn zyz(self) -> Vec3A { + Vec3A(simd_swizzle!(self.0, [2, 1, 2, 0]).into()) + } + + #[inline] + fn zzx(self) -> Vec3A { + Vec3A(simd_swizzle!(self.0, [2, 2, 0, 0]).into()) + } + + #[inline] + fn zzy(self) -> Vec3A { + Vec3A(simd_swizzle!(self.0, [2, 2, 1, 0]).into()) + } + + #[inline] + fn zzz(self) -> Vec3A { + Vec3A(simd_swizzle!(self.0, [2, 2, 2, 0]).into()) + } + + #[inline] + fn xxxx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 0, 0, 0])) + } + + #[inline] + fn xxxy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 0, 0, 1])) + } + + #[inline] + fn xxxz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 0, 0, 2])) + } + + #[inline] + fn xxyx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 0, 1, 0])) + } + + #[inline] + fn xxyy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 0, 1, 1])) + } + + #[inline] + fn xxyz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 0, 1, 2])) + } + + #[inline] + fn xxzx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 0, 2, 0])) + } + + #[inline] + fn xxzy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 0, 2, 1])) + } + + #[inline] + fn xxzz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 0, 2, 2])) + } + + #[inline] + fn xyxx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 1, 0, 0])) + } + + #[inline] + fn xyxy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 1, 0, 1])) + } + + #[inline] + fn xyxz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 1, 0, 2])) + } + + #[inline] + fn xyyx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 1, 1, 0])) + } + + #[inline] + fn xyyy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 1, 1, 1])) + } + + #[inline] + fn xyyz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 1, 1, 2])) + } + + #[inline] + fn xyzx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 1, 2, 0])) + } + + #[inline] + fn xyzy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 1, 2, 1])) + } + + #[inline] + fn xyzz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 1, 2, 2])) + } + + #[inline] + fn xzxx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 2, 0, 0])) + } + + #[inline] + fn xzxy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 2, 0, 1])) + } + + #[inline] + fn xzxz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 2, 0, 2])) + } + + #[inline] + fn xzyx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 2, 1, 0])) + } + + #[inline] + fn xzyy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 2, 1, 1])) + } + + #[inline] + fn xzyz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 2, 1, 2])) + } + + #[inline] + fn xzzx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 2, 2, 0])) + } + + #[inline] + fn xzzy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 2, 2, 1])) + } + + #[inline] + fn xzzz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 2, 2, 2])) + } + + #[inline] + fn yxxx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 0, 0, 0])) + } + + #[inline] + fn yxxy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 0, 0, 1])) + } + + #[inline] + fn yxxz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 0, 0, 2])) + } + + #[inline] + fn yxyx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 0, 1, 0])) + } + + #[inline] + fn yxyy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 0, 1, 1])) + } + + #[inline] + fn yxyz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 0, 1, 2])) + } + + #[inline] + fn yxzx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 0, 2, 0])) + } + + #[inline] + fn yxzy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 0, 2, 1])) + } + + #[inline] + fn yxzz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 0, 2, 2])) + } + + #[inline] + fn yyxx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 1, 0, 0])) + } + + #[inline] + fn yyxy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 1, 0, 1])) + } + + #[inline] + fn yyxz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 1, 0, 2])) + } + + #[inline] + fn yyyx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 1, 1, 0])) + } + + #[inline] + fn yyyy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 1, 1, 1])) + } + + #[inline] + fn yyyz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 1, 1, 2])) + } + + #[inline] + fn yyzx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 1, 2, 0])) + } + + #[inline] + fn yyzy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 1, 2, 1])) + } + + #[inline] + fn yyzz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 1, 2, 2])) + } + + #[inline] + fn yzxx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 2, 0, 0])) + } + + #[inline] + fn yzxy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 2, 0, 1])) + } + + #[inline] + fn yzxz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 2, 0, 2])) + } + + #[inline] + fn yzyx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 2, 1, 0])) + } + + #[inline] + fn yzyy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 2, 1, 1])) + } + + #[inline] + fn yzyz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 2, 1, 2])) + } + + #[inline] + fn yzzx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 2, 2, 0])) + } + + #[inline] + fn yzzy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 2, 2, 1])) + } + + #[inline] + fn yzzz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 2, 2, 2])) + } + + #[inline] + fn zxxx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 0, 0, 0])) + } + + #[inline] + fn zxxy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 0, 0, 1])) + } + + #[inline] + fn zxxz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 0, 0, 2])) + } + + #[inline] + fn zxyx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 0, 1, 0])) + } + + #[inline] + fn zxyy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 0, 1, 1])) + } + + #[inline] + fn zxyz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 0, 1, 2])) + } + + #[inline] + fn zxzx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 0, 2, 0])) + } + + #[inline] + fn zxzy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 0, 2, 1])) + } + + #[inline] + fn zxzz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 0, 2, 2])) + } + + #[inline] + fn zyxx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 1, 0, 0])) + } + + #[inline] + fn zyxy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 1, 0, 1])) + } + + #[inline] + fn zyxz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 1, 0, 2])) + } + + #[inline] + fn zyyx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 1, 1, 0])) + } + + #[inline] + fn zyyy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 1, 1, 1])) + } + + #[inline] + fn zyyz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 1, 1, 2])) + } + + #[inline] + fn zyzx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 1, 2, 0])) + } + + #[inline] + fn zyzy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 1, 2, 1])) + } + + #[inline] + fn zyzz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 1, 2, 2])) + } + + #[inline] + fn zzxx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 2, 0, 0])) + } + + #[inline] + fn zzxy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 2, 0, 1])) + } + + #[inline] + fn zzxz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 2, 0, 2])) + } + + #[inline] + fn zzyx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 2, 1, 0])) + } + + #[inline] + fn zzyy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 2, 1, 1])) + } + + #[inline] + fn zzyz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 2, 1, 2])) + } + + #[inline] + fn zzzx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 2, 2, 0])) + } + + #[inline] + fn zzzy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 2, 2, 1])) + } + + #[inline] + fn zzzz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 2, 2, 2])) + } +} diff --git a/src/swizzles/coresimd/vec4_impl.rs b/src/swizzles/coresimd/vec4_impl.rs new file mode 100644 index 0000000..0c8649d --- /dev/null +++ b/src/swizzles/coresimd/vec4_impl.rs @@ -0,0 +1,1997 @@ +// Generated from swizzle_impl.rs.tera template. Edit the template, not the generated file. + +#![allow(clippy::useless_conversion)] + +use crate::{Vec2, Vec3, Vec4, Vec4Swizzles}; + +use core::simd::*; + +impl Vec4Swizzles for Vec4 { + type Vec2 = Vec2; + + type Vec3 = Vec3; + + #[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 xw(self) -> Vec2 { + Vec2 { + x: self.x, + y: self.w, + } + } + + #[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 yw(self) -> Vec2 { + Vec2 { + x: self.y, + y: self.w, + } + } + + #[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 zw(self) -> Vec2 { + Vec2 { + x: self.z, + y: self.w, + } + } + + #[inline] + fn wx(self) -> Vec2 { + Vec2 { + x: self.w, + y: self.x, + } + } + + #[inline] + fn wy(self) -> Vec2 { + Vec2 { + x: self.w, + y: self.y, + } + } + + #[inline] + fn wz(self) -> Vec2 { + Vec2 { + x: self.w, + y: self.z, + } + } + + #[inline] + fn ww(self) -> Vec2 { + Vec2 { + x: self.w, + y: self.w, + } + } + + #[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 xxw(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.x, + z: self.w, + } + } + + #[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 xyw(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.y, + z: self.w, + } + } + + #[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 xzw(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.z, + z: self.w, + } + } + + #[inline] + fn xwx(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.w, + z: self.x, + } + } + + #[inline] + fn xwy(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.w, + z: self.y, + } + } + + #[inline] + fn xwz(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.w, + z: self.z, + } + } + + #[inline] + fn xww(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.w, + z: self.w, + } + } + + #[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 yxw(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.x, + z: self.w, + } + } + + #[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 yyw(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.y, + z: self.w, + } + } + + #[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 yzw(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.z, + z: self.w, + } + } + + #[inline] + fn ywx(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.w, + z: self.x, + } + } + + #[inline] + fn ywy(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.w, + z: self.y, + } + } + + #[inline] + fn ywz(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.w, + z: self.z, + } + } + + #[inline] + fn yww(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.w, + z: self.w, + } + } + + #[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 zxw(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.x, + z: self.w, + } + } + + #[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 zyw(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.y, + z: self.w, + } + } + + #[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 zzw(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.z, + z: self.w, + } + } + + #[inline] + fn zwx(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.w, + z: self.x, + } + } + + #[inline] + fn zwy(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.w, + z: self.y, + } + } + + #[inline] + fn zwz(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.w, + z: self.z, + } + } + + #[inline] + fn zww(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.w, + z: self.w, + } + } + + #[inline] + fn wxx(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.x, + z: self.x, + } + } + + #[inline] + fn wxy(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.x, + z: self.y, + } + } + + #[inline] + fn wxz(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.x, + z: self.z, + } + } + + #[inline] + fn wxw(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.x, + z: self.w, + } + } + + #[inline] + fn wyx(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.y, + z: self.x, + } + } + + #[inline] + fn wyy(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.y, + z: self.y, + } + } + + #[inline] + fn wyz(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.y, + z: self.z, + } + } + + #[inline] + fn wyw(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.y, + z: self.w, + } + } + + #[inline] + fn wzx(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.z, + z: self.x, + } + } + + #[inline] + fn wzy(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.z, + z: self.y, + } + } + + #[inline] + fn wzz(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.z, + z: self.z, + } + } + + #[inline] + fn wzw(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.z, + z: self.w, + } + } + + #[inline] + fn wwx(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.w, + z: self.x, + } + } + + #[inline] + fn wwy(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.w, + z: self.y, + } + } + + #[inline] + fn wwz(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.w, + z: self.z, + } + } + + #[inline] + fn www(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.w, + z: self.w, + } + } + + #[inline] + fn xxxx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 0, 0, 0])) + } + + #[inline] + fn xxxy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 0, 0, 1])) + } + + #[inline] + fn xxxz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 0, 0, 2])) + } + + #[inline] + fn xxxw(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 0, 0, 3])) + } + + #[inline] + fn xxyx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 0, 1, 0])) + } + + #[inline] + fn xxyy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 0, 1, 1])) + } + + #[inline] + fn xxyz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 0, 1, 2])) + } + + #[inline] + fn xxyw(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 0, 1, 3])) + } + + #[inline] + fn xxzx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 0, 2, 0])) + } + + #[inline] + fn xxzy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 0, 2, 1])) + } + + #[inline] + fn xxzz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 0, 2, 2])) + } + + #[inline] + fn xxzw(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 0, 2, 3])) + } + + #[inline] + fn xxwx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 0, 3, 0])) + } + + #[inline] + fn xxwy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 0, 3, 1])) + } + + #[inline] + fn xxwz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 0, 3, 2])) + } + + #[inline] + fn xxww(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 0, 3, 3])) + } + + #[inline] + fn xyxx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 1, 0, 0])) + } + + #[inline] + fn xyxy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 1, 0, 1])) + } + + #[inline] + fn xyxz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 1, 0, 2])) + } + + #[inline] + fn xyxw(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 1, 0, 3])) + } + + #[inline] + fn xyyx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 1, 1, 0])) + } + + #[inline] + fn xyyy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 1, 1, 1])) + } + + #[inline] + fn xyyz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 1, 1, 2])) + } + + #[inline] + fn xyyw(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 1, 1, 3])) + } + + #[inline] + fn xyzx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 1, 2, 0])) + } + + #[inline] + fn xyzy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 1, 2, 1])) + } + + #[inline] + fn xyzz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 1, 2, 2])) + } + + #[inline] + fn xyzw(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 1, 2, 3])) + } + + #[inline] + fn xywx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 1, 3, 0])) + } + + #[inline] + fn xywy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 1, 3, 1])) + } + + #[inline] + fn xywz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 1, 3, 2])) + } + + #[inline] + fn xyww(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 1, 3, 3])) + } + + #[inline] + fn xzxx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 2, 0, 0])) + } + + #[inline] + fn xzxy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 2, 0, 1])) + } + + #[inline] + fn xzxz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 2, 0, 2])) + } + + #[inline] + fn xzxw(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 2, 0, 3])) + } + + #[inline] + fn xzyx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 2, 1, 0])) + } + + #[inline] + fn xzyy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 2, 1, 1])) + } + + #[inline] + fn xzyz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 2, 1, 2])) + } + + #[inline] + fn xzyw(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 2, 1, 3])) + } + + #[inline] + fn xzzx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 2, 2, 0])) + } + + #[inline] + fn xzzy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 2, 2, 1])) + } + + #[inline] + fn xzzz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 2, 2, 2])) + } + + #[inline] + fn xzzw(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 2, 2, 3])) + } + + #[inline] + fn xzwx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 2, 3, 0])) + } + + #[inline] + fn xzwy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 2, 3, 1])) + } + + #[inline] + fn xzwz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 2, 3, 2])) + } + + #[inline] + fn xzww(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 2, 3, 3])) + } + + #[inline] + fn xwxx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 3, 0, 0])) + } + + #[inline] + fn xwxy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 3, 0, 1])) + } + + #[inline] + fn xwxz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 3, 0, 2])) + } + + #[inline] + fn xwxw(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 3, 0, 3])) + } + + #[inline] + fn xwyx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 3, 1, 0])) + } + + #[inline] + fn xwyy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 3, 1, 1])) + } + + #[inline] + fn xwyz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 3, 1, 2])) + } + + #[inline] + fn xwyw(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 3, 1, 3])) + } + + #[inline] + fn xwzx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 3, 2, 0])) + } + + #[inline] + fn xwzy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 3, 2, 1])) + } + + #[inline] + fn xwzz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 3, 2, 2])) + } + + #[inline] + fn xwzw(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 3, 2, 3])) + } + + #[inline] + fn xwwx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 3, 3, 0])) + } + + #[inline] + fn xwwy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 3, 3, 1])) + } + + #[inline] + fn xwwz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 3, 3, 2])) + } + + #[inline] + fn xwww(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [0, 3, 3, 3])) + } + + #[inline] + fn yxxx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 0, 0, 0])) + } + + #[inline] + fn yxxy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 0, 0, 1])) + } + + #[inline] + fn yxxz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 0, 0, 2])) + } + + #[inline] + fn yxxw(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 0, 0, 3])) + } + + #[inline] + fn yxyx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 0, 1, 0])) + } + + #[inline] + fn yxyy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 0, 1, 1])) + } + + #[inline] + fn yxyz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 0, 1, 2])) + } + + #[inline] + fn yxyw(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 0, 1, 3])) + } + + #[inline] + fn yxzx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 0, 2, 0])) + } + + #[inline] + fn yxzy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 0, 2, 1])) + } + + #[inline] + fn yxzz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 0, 2, 2])) + } + + #[inline] + fn yxzw(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 0, 2, 3])) + } + + #[inline] + fn yxwx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 0, 3, 0])) + } + + #[inline] + fn yxwy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 0, 3, 1])) + } + + #[inline] + fn yxwz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 0, 3, 2])) + } + + #[inline] + fn yxww(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 0, 3, 3])) + } + + #[inline] + fn yyxx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 1, 0, 0])) + } + + #[inline] + fn yyxy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 1, 0, 1])) + } + + #[inline] + fn yyxz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 1, 0, 2])) + } + + #[inline] + fn yyxw(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 1, 0, 3])) + } + + #[inline] + fn yyyx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 1, 1, 0])) + } + + #[inline] + fn yyyy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 1, 1, 1])) + } + + #[inline] + fn yyyz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 1, 1, 2])) + } + + #[inline] + fn yyyw(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 1, 1, 3])) + } + + #[inline] + fn yyzx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 1, 2, 0])) + } + + #[inline] + fn yyzy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 1, 2, 1])) + } + + #[inline] + fn yyzz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 1, 2, 2])) + } + + #[inline] + fn yyzw(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 1, 2, 3])) + } + + #[inline] + fn yywx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 1, 3, 0])) + } + + #[inline] + fn yywy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 1, 3, 1])) + } + + #[inline] + fn yywz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 1, 3, 2])) + } + + #[inline] + fn yyww(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 1, 3, 3])) + } + + #[inline] + fn yzxx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 2, 0, 0])) + } + + #[inline] + fn yzxy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 2, 0, 1])) + } + + #[inline] + fn yzxz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 2, 0, 2])) + } + + #[inline] + fn yzxw(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 2, 0, 3])) + } + + #[inline] + fn yzyx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 2, 1, 0])) + } + + #[inline] + fn yzyy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 2, 1, 1])) + } + + #[inline] + fn yzyz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 2, 1, 2])) + } + + #[inline] + fn yzyw(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 2, 1, 3])) + } + + #[inline] + fn yzzx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 2, 2, 0])) + } + + #[inline] + fn yzzy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 2, 2, 1])) + } + + #[inline] + fn yzzz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 2, 2, 2])) + } + + #[inline] + fn yzzw(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 2, 2, 3])) + } + + #[inline] + fn yzwx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 2, 3, 0])) + } + + #[inline] + fn yzwy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 2, 3, 1])) + } + + #[inline] + fn yzwz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 2, 3, 2])) + } + + #[inline] + fn yzww(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 2, 3, 3])) + } + + #[inline] + fn ywxx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 3, 0, 0])) + } + + #[inline] + fn ywxy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 3, 0, 1])) + } + + #[inline] + fn ywxz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 3, 0, 2])) + } + + #[inline] + fn ywxw(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 3, 0, 3])) + } + + #[inline] + fn ywyx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 3, 1, 0])) + } + + #[inline] + fn ywyy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 3, 1, 1])) + } + + #[inline] + fn ywyz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 3, 1, 2])) + } + + #[inline] + fn ywyw(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 3, 1, 3])) + } + + #[inline] + fn ywzx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 3, 2, 0])) + } + + #[inline] + fn ywzy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 3, 2, 1])) + } + + #[inline] + fn ywzz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 3, 2, 2])) + } + + #[inline] + fn ywzw(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 3, 2, 3])) + } + + #[inline] + fn ywwx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 3, 3, 0])) + } + + #[inline] + fn ywwy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 3, 3, 1])) + } + + #[inline] + fn ywwz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 3, 3, 2])) + } + + #[inline] + fn ywww(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [1, 3, 3, 3])) + } + + #[inline] + fn zxxx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 0, 0, 0])) + } + + #[inline] + fn zxxy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 0, 0, 1])) + } + + #[inline] + fn zxxz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 0, 0, 2])) + } + + #[inline] + fn zxxw(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 0, 0, 3])) + } + + #[inline] + fn zxyx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 0, 1, 0])) + } + + #[inline] + fn zxyy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 0, 1, 1])) + } + + #[inline] + fn zxyz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 0, 1, 2])) + } + + #[inline] + fn zxyw(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 0, 1, 3])) + } + + #[inline] + fn zxzx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 0, 2, 0])) + } + + #[inline] + fn zxzy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 0, 2, 1])) + } + + #[inline] + fn zxzz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 0, 2, 2])) + } + + #[inline] + fn zxzw(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 0, 2, 3])) + } + + #[inline] + fn zxwx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 0, 3, 0])) + } + + #[inline] + fn zxwy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 0, 3, 1])) + } + + #[inline] + fn zxwz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 0, 3, 2])) + } + + #[inline] + fn zxww(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 0, 3, 3])) + } + + #[inline] + fn zyxx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 1, 0, 0])) + } + + #[inline] + fn zyxy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 1, 0, 1])) + } + + #[inline] + fn zyxz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 1, 0, 2])) + } + + #[inline] + fn zyxw(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 1, 0, 3])) + } + + #[inline] + fn zyyx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 1, 1, 0])) + } + + #[inline] + fn zyyy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 1, 1, 1])) + } + + #[inline] + fn zyyz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 1, 1, 2])) + } + + #[inline] + fn zyyw(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 1, 1, 3])) + } + + #[inline] + fn zyzx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 1, 2, 0])) + } + + #[inline] + fn zyzy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 1, 2, 1])) + } + + #[inline] + fn zyzz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 1, 2, 2])) + } + + #[inline] + fn zyzw(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 1, 2, 3])) + } + + #[inline] + fn zywx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 1, 3, 0])) + } + + #[inline] + fn zywy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 1, 3, 1])) + } + + #[inline] + fn zywz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 1, 3, 2])) + } + + #[inline] + fn zyww(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 1, 3, 3])) + } + + #[inline] + fn zzxx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 2, 0, 0])) + } + + #[inline] + fn zzxy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 2, 0, 1])) + } + + #[inline] + fn zzxz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 2, 0, 2])) + } + + #[inline] + fn zzxw(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 2, 0, 3])) + } + + #[inline] + fn zzyx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 2, 1, 0])) + } + + #[inline] + fn zzyy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 2, 1, 1])) + } + + #[inline] + fn zzyz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 2, 1, 2])) + } + + #[inline] + fn zzyw(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 2, 1, 3])) + } + + #[inline] + fn zzzx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 2, 2, 0])) + } + + #[inline] + fn zzzy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 2, 2, 1])) + } + + #[inline] + fn zzzz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 2, 2, 2])) + } + + #[inline] + fn zzzw(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 2, 2, 3])) + } + + #[inline] + fn zzwx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 2, 3, 0])) + } + + #[inline] + fn zzwy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 2, 3, 1])) + } + + #[inline] + fn zzwz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 2, 3, 2])) + } + + #[inline] + fn zzww(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 2, 3, 3])) + } + + #[inline] + fn zwxx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 3, 0, 0])) + } + + #[inline] + fn zwxy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 3, 0, 1])) + } + + #[inline] + fn zwxz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 3, 0, 2])) + } + + #[inline] + fn zwxw(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 3, 0, 3])) + } + + #[inline] + fn zwyx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 3, 1, 0])) + } + + #[inline] + fn zwyy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 3, 1, 1])) + } + + #[inline] + fn zwyz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 3, 1, 2])) + } + + #[inline] + fn zwyw(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 3, 1, 3])) + } + + #[inline] + fn zwzx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 3, 2, 0])) + } + + #[inline] + fn zwzy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 3, 2, 1])) + } + + #[inline] + fn zwzz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 3, 2, 2])) + } + + #[inline] + fn zwzw(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 3, 2, 3])) + } + + #[inline] + fn zwwx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 3, 3, 0])) + } + + #[inline] + fn zwwy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 3, 3, 1])) + } + + #[inline] + fn zwwz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 3, 3, 2])) + } + + #[inline] + fn zwww(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [2, 3, 3, 3])) + } + + #[inline] + fn wxxx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 0, 0, 0])) + } + + #[inline] + fn wxxy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 0, 0, 1])) + } + + #[inline] + fn wxxz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 0, 0, 2])) + } + + #[inline] + fn wxxw(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 0, 0, 3])) + } + + #[inline] + fn wxyx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 0, 1, 0])) + } + + #[inline] + fn wxyy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 0, 1, 1])) + } + + #[inline] + fn wxyz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 0, 1, 2])) + } + + #[inline] + fn wxyw(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 0, 1, 3])) + } + + #[inline] + fn wxzx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 0, 2, 0])) + } + + #[inline] + fn wxzy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 0, 2, 1])) + } + + #[inline] + fn wxzz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 0, 2, 2])) + } + + #[inline] + fn wxzw(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 0, 2, 3])) + } + + #[inline] + fn wxwx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 0, 3, 0])) + } + + #[inline] + fn wxwy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 0, 3, 1])) + } + + #[inline] + fn wxwz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 0, 3, 2])) + } + + #[inline] + fn wxww(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 0, 3, 3])) + } + + #[inline] + fn wyxx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 1, 0, 0])) + } + + #[inline] + fn wyxy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 1, 0, 1])) + } + + #[inline] + fn wyxz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 1, 0, 2])) + } + + #[inline] + fn wyxw(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 1, 0, 3])) + } + + #[inline] + fn wyyx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 1, 1, 0])) + } + + #[inline] + fn wyyy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 1, 1, 1])) + } + + #[inline] + fn wyyz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 1, 1, 2])) + } + + #[inline] + fn wyyw(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 1, 1, 3])) + } + + #[inline] + fn wyzx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 1, 2, 0])) + } + + #[inline] + fn wyzy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 1, 2, 1])) + } + + #[inline] + fn wyzz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 1, 2, 2])) + } + + #[inline] + fn wyzw(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 1, 2, 3])) + } + + #[inline] + fn wywx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 1, 3, 0])) + } + + #[inline] + fn wywy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 1, 3, 1])) + } + + #[inline] + fn wywz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 1, 3, 2])) + } + + #[inline] + fn wyww(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 1, 3, 3])) + } + + #[inline] + fn wzxx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 2, 0, 0])) + } + + #[inline] + fn wzxy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 2, 0, 1])) + } + + #[inline] + fn wzxz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 2, 0, 2])) + } + + #[inline] + fn wzxw(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 2, 0, 3])) + } + + #[inline] + fn wzyx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 2, 1, 0])) + } + + #[inline] + fn wzyy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 2, 1, 1])) + } + + #[inline] + fn wzyz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 2, 1, 2])) + } + + #[inline] + fn wzyw(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 2, 1, 3])) + } + + #[inline] + fn wzzx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 2, 2, 0])) + } + + #[inline] + fn wzzy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 2, 2, 1])) + } + + #[inline] + fn wzzz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 2, 2, 2])) + } + + #[inline] + fn wzzw(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 2, 2, 3])) + } + + #[inline] + fn wzwx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 2, 3, 0])) + } + + #[inline] + fn wzwy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 2, 3, 1])) + } + + #[inline] + fn wzwz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 2, 3, 2])) + } + + #[inline] + fn wzww(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 2, 3, 3])) + } + + #[inline] + fn wwxx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 3, 0, 0])) + } + + #[inline] + fn wwxy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 3, 0, 1])) + } + + #[inline] + fn wwxz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 3, 0, 2])) + } + + #[inline] + fn wwxw(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 3, 0, 3])) + } + + #[inline] + fn wwyx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 3, 1, 0])) + } + + #[inline] + fn wwyy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 3, 1, 1])) + } + + #[inline] + fn wwyz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 3, 1, 2])) + } + + #[inline] + fn wwyw(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 3, 1, 3])) + } + + #[inline] + fn wwzx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 3, 2, 0])) + } + + #[inline] + fn wwzy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 3, 2, 1])) + } + + #[inline] + fn wwzz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 3, 2, 2])) + } + + #[inline] + fn wwzw(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 3, 2, 3])) + } + + #[inline] + fn wwwx(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 3, 3, 0])) + } + + #[inline] + fn wwwy(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 3, 3, 1])) + } + + #[inline] + fn wwwz(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 3, 3, 2])) + } + + #[inline] + fn wwww(self) -> Vec4 { + Vec4(simd_swizzle!(self.0, [3, 3, 3, 3])) + } +} diff --git a/src/swizzles/dvec2_impl.rs b/src/swizzles/dvec2_impl.rs new file mode 100644 index 0000000..dbf6dc3 --- /dev/null +++ b/src/swizzles/dvec2_impl.rs @@ -0,0 +1,193 @@ +// Generated from swizzle_impl.rs.tera template. Edit the template, not the generated file. + +use crate::{DVec2, DVec3, DVec4, Vec2Swizzles}; + +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) + } +} diff --git a/src/swizzles/dvec2_impl_scalar.rs b/src/swizzles/dvec2_impl_scalar.rs deleted file mode 100644 index 1cb65e9..0000000 --- a/src/swizzles/dvec2_impl_scalar.rs +++ /dev/null @@ -1,118 +0,0 @@ -// Generated by swizzlegen. Do not edit. - -use super::Vec2Swizzles; -use crate::{DVec2, DVec3, DVec4}; - -impl Vec2Swizzles for DVec2 { - type Vec3 = DVec3; - type Vec4 = DVec4; - - #[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.rs b/src/swizzles/dvec3_impl.rs new file mode 100644 index 0000000..0ea0cd4 --- /dev/null +++ b/src/swizzles/dvec3_impl.rs @@ -0,0 +1,729 @@ +// Generated from swizzle_impl.rs.tera template. Edit the template, not the generated file. + +use crate::{DVec2, DVec3, DVec4, Vec3Swizzles}; + +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) + } +} diff --git a/src/swizzles/dvec3_impl_scalar.rs b/src/swizzles/dvec3_impl_scalar.rs deleted file mode 100644 index 53fab09..0000000 --- a/src/swizzles/dvec3_impl_scalar.rs +++ /dev/null @@ -1,474 +0,0 @@ -// Generated by swizzlegen. Do not edit. - -use super::Vec3Swizzles; -use crate::{DVec2, DVec3, DVec4}; - -impl Vec3Swizzles for DVec3 { - type Vec2 = DVec2; - type Vec4 = DVec4; - - #[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.rs b/src/swizzles/dvec4_impl.rs new file mode 100644 index 0000000..b791ad5 --- /dev/null +++ b/src/swizzles/dvec4_impl.rs @@ -0,0 +1,1993 @@ +// Generated from swizzle_impl.rs.tera template. Edit the template, not the generated file. + +use crate::{DVec2, DVec3, DVec4, Vec4Swizzles}; + +impl Vec4Swizzles for DVec4 { + type Vec2 = DVec2; + + type Vec3 = DVec3; + + #[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 xw(self) -> DVec2 { + DVec2 { + x: self.x, + y: self.w, + } + } + + #[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 yw(self) -> DVec2 { + DVec2 { + x: self.y, + y: self.w, + } + } + + #[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 zw(self) -> DVec2 { + DVec2 { + x: self.z, + y: self.w, + } + } + + #[inline] + fn wx(self) -> DVec2 { + DVec2 { + x: self.w, + y: self.x, + } + } + + #[inline] + fn wy(self) -> DVec2 { + DVec2 { + x: self.w, + y: self.y, + } + } + + #[inline] + fn wz(self) -> DVec2 { + DVec2 { + x: self.w, + y: self.z, + } + } + + #[inline] + fn ww(self) -> DVec2 { + DVec2 { + x: self.w, + y: self.w, + } + } + + #[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 xxw(self) -> DVec3 { + DVec3 { + x: self.x, + y: self.x, + z: self.w, + } + } + + #[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 xyw(self) -> DVec3 { + DVec3 { + x: self.x, + y: self.y, + z: self.w, + } + } + + #[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 xzw(self) -> DVec3 { + DVec3 { + x: self.x, + y: self.z, + z: self.w, + } + } + + #[inline] + fn xwx(self) -> DVec3 { + DVec3 { + x: self.x, + y: self.w, + z: self.x, + } + } + + #[inline] + fn xwy(self) -> DVec3 { + DVec3 { + x: self.x, + y: self.w, + z: self.y, + } + } + + #[inline] + fn xwz(self) -> DVec3 { + DVec3 { + x: self.x, + y: self.w, + z: self.z, + } + } + + #[inline] + fn xww(self) -> DVec3 { + DVec3 { + x: self.x, + y: self.w, + z: self.w, + } + } + + #[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 yxw(self) -> DVec3 { + DVec3 { + x: self.y, + y: self.x, + z: self.w, + } + } + + #[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 yyw(self) -> DVec3 { + DVec3 { + x: self.y, + y: self.y, + z: self.w, + } + } + + #[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 yzw(self) -> DVec3 { + DVec3 { + x: self.y, + y: self.z, + z: self.w, + } + } + + #[inline] + fn ywx(self) -> DVec3 { + DVec3 { + x: self.y, + y: self.w, + z: self.x, + } + } + + #[inline] + fn ywy(self) -> DVec3 { + DVec3 { + x: self.y, + y: self.w, + z: self.y, + } + } + + #[inline] + fn ywz(self) -> DVec3 { + DVec3 { + x: self.y, + y: self.w, + z: self.z, + } + } + + #[inline] + fn yww(self) -> DVec3 { + DVec3 { + x: self.y, + y: self.w, + z: self.w, + } + } + + #[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 zxw(self) -> DVec3 { + DVec3 { + x: self.z, + y: self.x, + z: self.w, + } + } + + #[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 zyw(self) -> DVec3 { + DVec3 { + x: self.z, + y: self.y, + z: self.w, + } + } + + #[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 zzw(self) -> DVec3 { + DVec3 { + x: self.z, + y: self.z, + z: self.w, + } + } + + #[inline] + fn zwx(self) -> DVec3 { + DVec3 { + x: self.z, + y: self.w, + z: self.x, + } + } + + #[inline] + fn zwy(self) -> DVec3 { + DVec3 { + x: self.z, + y: self.w, + z: self.y, + } + } + + #[inline] + fn zwz(self) -> DVec3 { + DVec3 { + x: self.z, + y: self.w, + z: self.z, + } + } + + #[inline] + fn zww(self) -> DVec3 { + DVec3 { + x: self.z, + y: self.w, + z: self.w, + } + } + + #[inline] + fn wxx(self) -> DVec3 { + DVec3 { + x: self.w, + y: self.x, + z: self.x, + } + } + + #[inline] + fn wxy(self) -> DVec3 { + DVec3 { + x: self.w, + y: self.x, + z: self.y, + } + } + + #[inline] + fn wxz(self) -> DVec3 { + DVec3 { + x: self.w, + y: self.x, + z: self.z, + } + } + + #[inline] + fn wxw(self) -> DVec3 { + DVec3 { + x: self.w, + y: self.x, + z: self.w, + } + } + + #[inline] + fn wyx(self) -> DVec3 { + DVec3 { + x: self.w, + y: self.y, + z: self.x, + } + } + + #[inline] + fn wyy(self) -> DVec3 { + DVec3 { + x: self.w, + y: self.y, + z: self.y, + } + } + + #[inline] + fn wyz(self) -> DVec3 { + DVec3 { + x: self.w, + y: self.y, + z: self.z, + } + } + + #[inline] + fn wyw(self) -> DVec3 { + DVec3 { + x: self.w, + y: self.y, + z: self.w, + } + } + + #[inline] + fn wzx(self) -> DVec3 { + DVec3 { + x: self.w, + y: self.z, + z: self.x, + } + } + + #[inline] + fn wzy(self) -> DVec3 { + DVec3 { + x: self.w, + y: self.z, + z: self.y, + } + } + + #[inline] + fn wzz(self) -> DVec3 { + DVec3 { + x: self.w, + y: self.z, + z: self.z, + } + } + + #[inline] + fn wzw(self) -> DVec3 { + DVec3 { + x: self.w, + y: self.z, + z: self.w, + } + } + + #[inline] + fn wwx(self) -> DVec3 { + DVec3 { + x: self.w, + y: self.w, + z: self.x, + } + } + + #[inline] + fn wwy(self) -> DVec3 { + DVec3 { + x: self.w, + y: self.w, + z: self.y, + } + } + + #[inline] + fn wwz(self) -> DVec3 { + DVec3 { + x: self.w, + y: self.w, + z: self.z, + } + } + + #[inline] + fn www(self) -> DVec3 { + DVec3 { + x: self.w, + y: self.w, + z: self.w, + } + } + + #[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 xxxw(self) -> DVec4 { + DVec4::new(self.x, self.x, self.x, self.w) + } + + #[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 xxyw(self) -> DVec4 { + DVec4::new(self.x, self.x, self.y, self.w) + } + + #[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 xxzw(self) -> DVec4 { + DVec4::new(self.x, self.x, self.z, self.w) + } + + #[inline] + fn xxwx(self) -> DVec4 { + DVec4::new(self.x, self.x, self.w, self.x) + } + + #[inline] + fn xxwy(self) -> DVec4 { + DVec4::new(self.x, self.x, self.w, self.y) + } + + #[inline] + fn xxwz(self) -> DVec4 { + DVec4::new(self.x, self.x, self.w, self.z) + } + + #[inline] + fn xxww(self) -> DVec4 { + DVec4::new(self.x, self.x, self.w, self.w) + } + + #[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 xyxw(self) -> DVec4 { + DVec4::new(self.x, self.y, self.x, self.w) + } + + #[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 xyyw(self) -> DVec4 { + DVec4::new(self.x, self.y, self.y, self.w) + } + + #[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 xyzw(self) -> DVec4 { + DVec4::new(self.x, self.y, self.z, self.w) + } + + #[inline] + fn xywx(self) -> DVec4 { + DVec4::new(self.x, self.y, self.w, self.x) + } + + #[inline] + fn xywy(self) -> DVec4 { + DVec4::new(self.x, self.y, self.w, self.y) + } + + #[inline] + fn xywz(self) -> DVec4 { + DVec4::new(self.x, self.y, self.w, self.z) + } + + #[inline] + fn xyww(self) -> DVec4 { + DVec4::new(self.x, self.y, self.w, self.w) + } + + #[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 xzxw(self) -> DVec4 { + DVec4::new(self.x, self.z, self.x, self.w) + } + + #[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 xzyw(self) -> DVec4 { + DVec4::new(self.x, self.z, self.y, self.w) + } + + #[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 xzzw(self) -> DVec4 { + DVec4::new(self.x, self.z, self.z, self.w) + } + + #[inline] + fn xzwx(self) -> DVec4 { + DVec4::new(self.x, self.z, self.w, self.x) + } + + #[inline] + fn xzwy(self) -> DVec4 { + DVec4::new(self.x, self.z, self.w, self.y) + } + + #[inline] + fn xzwz(self) -> DVec4 { + DVec4::new(self.x, self.z, self.w, self.z) + } + + #[inline] + fn xzww(self) -> DVec4 { + DVec4::new(self.x, self.z, self.w, self.w) + } + + #[inline] + fn xwxx(self) -> DVec4 { + DVec4::new(self.x, self.w, self.x, self.x) + } + + #[inline] + fn xwxy(self) -> DVec4 { + DVec4::new(self.x, self.w, self.x, self.y) + } + + #[inline] + fn xwxz(self) -> DVec4 { + DVec4::new(self.x, self.w, self.x, self.z) + } + + #[inline] + fn xwxw(self) -> DVec4 { + DVec4::new(self.x, self.w, self.x, self.w) + } + + #[inline] + fn xwyx(self) -> DVec4 { + DVec4::new(self.x, self.w, self.y, self.x) + } + + #[inline] + fn xwyy(self) -> DVec4 { + DVec4::new(self.x, self.w, self.y, self.y) + } + + #[inline] + fn xwyz(self) -> DVec4 { + DVec4::new(self.x, self.w, self.y, self.z) + } + + #[inline] + fn xwyw(self) -> DVec4 { + DVec4::new(self.x, self.w, self.y, self.w) + } + + #[inline] + fn xwzx(self) -> DVec4 { + DVec4::new(self.x, self.w, self.z, self.x) + } + + #[inline] + fn xwzy(self) -> DVec4 { + DVec4::new(self.x, self.w, self.z, self.y) + } + + #[inline] + fn xwzz(self) -> DVec4 { + DVec4::new(self.x, self.w, self.z, self.z) + } + + #[inline] + fn xwzw(self) -> DVec4 { + DVec4::new(self.x, self.w, self.z, self.w) + } + + #[inline] + fn xwwx(self) -> DVec4 { + DVec4::new(self.x, self.w, self.w, self.x) + } + + #[inline] + fn xwwy(self) -> DVec4 { + DVec4::new(self.x, self.w, self.w, self.y) + } + + #[inline] + fn xwwz(self) -> DVec4 { + DVec4::new(self.x, self.w, self.w, self.z) + } + + #[inline] + fn xwww(self) -> DVec4 { + DVec4::new(self.x, self.w, self.w, self.w) + } + + #[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 yxxw(self) -> DVec4 { + DVec4::new(self.y, self.x, self.x, self.w) + } + + #[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 yxyw(self) -> DVec4 { + DVec4::new(self.y, self.x, self.y, self.w) + } + + #[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 yxzw(self) -> DVec4 { + DVec4::new(self.y, self.x, self.z, self.w) + } + + #[inline] + fn yxwx(self) -> DVec4 { + DVec4::new(self.y, self.x, self.w, self.x) + } + + #[inline] + fn yxwy(self) -> DVec4 { + DVec4::new(self.y, self.x, self.w, self.y) + } + + #[inline] + fn yxwz(self) -> DVec4 { + DVec4::new(self.y, self.x, self.w, self.z) + } + + #[inline] + fn yxww(self) -> DVec4 { + DVec4::new(self.y, self.x, self.w, self.w) + } + + #[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 yyxw(self) -> DVec4 { + DVec4::new(self.y, self.y, self.x, self.w) + } + + #[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 yyyw(self) -> DVec4 { + DVec4::new(self.y, self.y, self.y, self.w) + } + + #[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 yyzw(self) -> DVec4 { + DVec4::new(self.y, self.y, self.z, self.w) + } + + #[inline] + fn yywx(self) -> DVec4 { + DVec4::new(self.y, self.y, self.w, self.x) + } + + #[inline] + fn yywy(self) -> DVec4 { + DVec4::new(self.y, self.y, self.w, self.y) + } + + #[inline] + fn yywz(self) -> DVec4 { + DVec4::new(self.y, self.y, self.w, self.z) + } + + #[inline] + fn yyww(self) -> DVec4 { + DVec4::new(self.y, self.y, self.w, self.w) + } + + #[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 yzxw(self) -> DVec4 { + DVec4::new(self.y, self.z, self.x, self.w) + } + + #[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 yzyw(self) -> DVec4 { + DVec4::new(self.y, self.z, self.y, self.w) + } + + #[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 yzzw(self) -> DVec4 { + DVec4::new(self.y, self.z, self.z, self.w) + } + + #[inline] + fn yzwx(self) -> DVec4 { + DVec4::new(self.y, self.z, self.w, self.x) + } + + #[inline] + fn yzwy(self) -> DVec4 { + DVec4::new(self.y, self.z, self.w, self.y) + } + + #[inline] + fn yzwz(self) -> DVec4 { + DVec4::new(self.y, self.z, self.w, self.z) + } + + #[inline] + fn yzww(self) -> DVec4 { + DVec4::new(self.y, self.z, self.w, self.w) + } + + #[inline] + fn ywxx(self) -> DVec4 { + DVec4::new(self.y, self.w, self.x, self.x) + } + + #[inline] + fn ywxy(self) -> DVec4 { + DVec4::new(self.y, self.w, self.x, self.y) + } + + #[inline] + fn ywxz(self) -> DVec4 { + DVec4::new(self.y, self.w, self.x, self.z) + } + + #[inline] + fn ywxw(self) -> DVec4 { + DVec4::new(self.y, self.w, self.x, self.w) + } + + #[inline] + fn ywyx(self) -> DVec4 { + DVec4::new(self.y, self.w, self.y, self.x) + } + + #[inline] + fn ywyy(self) -> DVec4 { + DVec4::new(self.y, self.w, self.y, self.y) + } + + #[inline] + fn ywyz(self) -> DVec4 { + DVec4::new(self.y, self.w, self.y, self.z) + } + + #[inline] + fn ywyw(self) -> DVec4 { + DVec4::new(self.y, self.w, self.y, self.w) + } + + #[inline] + fn ywzx(self) -> DVec4 { + DVec4::new(self.y, self.w, self.z, self.x) + } + + #[inline] + fn ywzy(self) -> DVec4 { + DVec4::new(self.y, self.w, self.z, self.y) + } + + #[inline] + fn ywzz(self) -> DVec4 { + DVec4::new(self.y, self.w, self.z, self.z) + } + + #[inline] + fn ywzw(self) -> DVec4 { + DVec4::new(self.y, self.w, self.z, self.w) + } + + #[inline] + fn ywwx(self) -> DVec4 { + DVec4::new(self.y, self.w, self.w, self.x) + } + + #[inline] + fn ywwy(self) -> DVec4 { + DVec4::new(self.y, self.w, self.w, self.y) + } + + #[inline] + fn ywwz(self) -> DVec4 { + DVec4::new(self.y, self.w, self.w, self.z) + } + + #[inline] + fn ywww(self) -> DVec4 { + DVec4::new(self.y, self.w, self.w, self.w) + } + + #[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 zxxw(self) -> DVec4 { + DVec4::new(self.z, self.x, self.x, self.w) + } + + #[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 zxyw(self) -> DVec4 { + DVec4::new(self.z, self.x, self.y, self.w) + } + + #[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 zxzw(self) -> DVec4 { + DVec4::new(self.z, self.x, self.z, self.w) + } + + #[inline] + fn zxwx(self) -> DVec4 { + DVec4::new(self.z, self.x, self.w, self.x) + } + + #[inline] + fn zxwy(self) -> DVec4 { + DVec4::new(self.z, self.x, self.w, self.y) + } + + #[inline] + fn zxwz(self) -> DVec4 { + DVec4::new(self.z, self.x, self.w, self.z) + } + + #[inline] + fn zxww(self) -> DVec4 { + DVec4::new(self.z, self.x, self.w, self.w) + } + + #[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 zyxw(self) -> DVec4 { + DVec4::new(self.z, self.y, self.x, self.w) + } + + #[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 zyyw(self) -> DVec4 { + DVec4::new(self.z, self.y, self.y, self.w) + } + + #[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 zyzw(self) -> DVec4 { + DVec4::new(self.z, self.y, self.z, self.w) + } + + #[inline] + fn zywx(self) -> DVec4 { + DVec4::new(self.z, self.y, self.w, self.x) + } + + #[inline] + fn zywy(self) -> DVec4 { + DVec4::new(self.z, self.y, self.w, self.y) + } + + #[inline] + fn zywz(self) -> DVec4 { + DVec4::new(self.z, self.y, self.w, self.z) + } + + #[inline] + fn zyww(self) -> DVec4 { + DVec4::new(self.z, self.y, self.w, self.w) + } + + #[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 zzxw(self) -> DVec4 { + DVec4::new(self.z, self.z, self.x, self.w) + } + + #[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 zzyw(self) -> DVec4 { + DVec4::new(self.z, self.z, self.y, self.w) + } + + #[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 zzzw(self) -> DVec4 { + DVec4::new(self.z, self.z, self.z, self.w) + } + + #[inline] + fn zzwx(self) -> DVec4 { + DVec4::new(self.z, self.z, self.w, self.x) + } + + #[inline] + fn zzwy(self) -> DVec4 { + DVec4::new(self.z, self.z, self.w, self.y) + } + + #[inline] + fn zzwz(self) -> DVec4 { + DVec4::new(self.z, self.z, self.w, self.z) + } + + #[inline] + fn zzww(self) -> DVec4 { + DVec4::new(self.z, self.z, self.w, self.w) + } + + #[inline] + fn zwxx(self) -> DVec4 { + DVec4::new(self.z, self.w, self.x, self.x) + } + + #[inline] + fn zwxy(self) -> DVec4 { + DVec4::new(self.z, self.w, self.x, self.y) + } + + #[inline] + fn zwxz(self) -> DVec4 { + DVec4::new(self.z, self.w, self.x, self.z) + } + + #[inline] + fn zwxw(self) -> DVec4 { + DVec4::new(self.z, self.w, self.x, self.w) + } + + #[inline] + fn zwyx(self) -> DVec4 { + DVec4::new(self.z, self.w, self.y, self.x) + } + + #[inline] + fn zwyy(self) -> DVec4 { + DVec4::new(self.z, self.w, self.y, self.y) + } + + #[inline] + fn zwyz(self) -> DVec4 { + DVec4::new(self.z, self.w, self.y, self.z) + } + + #[inline] + fn zwyw(self) -> DVec4 { + DVec4::new(self.z, self.w, self.y, self.w) + } + + #[inline] + fn zwzx(self) -> DVec4 { + DVec4::new(self.z, self.w, self.z, self.x) + } + + #[inline] + fn zwzy(self) -> DVec4 { + DVec4::new(self.z, self.w, self.z, self.y) + } + + #[inline] + fn zwzz(self) -> DVec4 { + DVec4::new(self.z, self.w, self.z, self.z) + } + + #[inline] + fn zwzw(self) -> DVec4 { + DVec4::new(self.z, self.w, self.z, self.w) + } + + #[inline] + fn zwwx(self) -> DVec4 { + DVec4::new(self.z, self.w, self.w, self.x) + } + + #[inline] + fn zwwy(self) -> DVec4 { + DVec4::new(self.z, self.w, self.w, self.y) + } + + #[inline] + fn zwwz(self) -> DVec4 { + DVec4::new(self.z, self.w, self.w, self.z) + } + + #[inline] + fn zwww(self) -> DVec4 { + DVec4::new(self.z, self.w, self.w, self.w) + } + + #[inline] + fn wxxx(self) -> DVec4 { + DVec4::new(self.w, self.x, self.x, self.x) + } + + #[inline] + fn wxxy(self) -> DVec4 { + DVec4::new(self.w, self.x, self.x, self.y) + } + + #[inline] + fn wxxz(self) -> DVec4 { + DVec4::new(self.w, self.x, self.x, self.z) + } + + #[inline] + fn wxxw(self) -> DVec4 { + DVec4::new(self.w, self.x, self.x, self.w) + } + + #[inline] + fn wxyx(self) -> DVec4 { + DVec4::new(self.w, self.x, self.y, self.x) + } + + #[inline] + fn wxyy(self) -> DVec4 { + DVec4::new(self.w, self.x, self.y, self.y) + } + + #[inline] + fn wxyz(self) -> DVec4 { + DVec4::new(self.w, self.x, self.y, self.z) + } + + #[inline] + fn wxyw(self) -> DVec4 { + DVec4::new(self.w, self.x, self.y, self.w) + } + + #[inline] + fn wxzx(self) -> DVec4 { + DVec4::new(self.w, self.x, self.z, self.x) + } + + #[inline] + fn wxzy(self) -> DVec4 { + DVec4::new(self.w, self.x, self.z, self.y) + } + + #[inline] + fn wxzz(self) -> DVec4 { + DVec4::new(self.w, self.x, self.z, self.z) + } + + #[inline] + fn wxzw(self) -> DVec4 { + DVec4::new(self.w, self.x, self.z, self.w) + } + + #[inline] + fn wxwx(self) -> DVec4 { + DVec4::new(self.w, self.x, self.w, self.x) + } + + #[inline] + fn wxwy(self) -> DVec4 { + DVec4::new(self.w, self.x, self.w, self.y) + } + + #[inline] + fn wxwz(self) -> DVec4 { + DVec4::new(self.w, self.x, self.w, self.z) + } + + #[inline] + fn wxww(self) -> DVec4 { + DVec4::new(self.w, self.x, self.w, self.w) + } + + #[inline] + fn wyxx(self) -> DVec4 { + DVec4::new(self.w, self.y, self.x, self.x) + } + + #[inline] + fn wyxy(self) -> DVec4 { + DVec4::new(self.w, self.y, self.x, self.y) + } + + #[inline] + fn wyxz(self) -> DVec4 { + DVec4::new(self.w, self.y, self.x, self.z) + } + + #[inline] + fn wyxw(self) -> DVec4 { + DVec4::new(self.w, self.y, self.x, self.w) + } + + #[inline] + fn wyyx(self) -> DVec4 { + DVec4::new(self.w, self.y, self.y, self.x) + } + + #[inline] + fn wyyy(self) -> DVec4 { + DVec4::new(self.w, self.y, self.y, self.y) + } + + #[inline] + fn wyyz(self) -> DVec4 { + DVec4::new(self.w, self.y, self.y, self.z) + } + + #[inline] + fn wyyw(self) -> DVec4 { + DVec4::new(self.w, self.y, self.y, self.w) + } + + #[inline] + fn wyzx(self) -> DVec4 { + DVec4::new(self.w, self.y, self.z, self.x) + } + + #[inline] + fn wyzy(self) -> DVec4 { + DVec4::new(self.w, self.y, self.z, self.y) + } + + #[inline] + fn wyzz(self) -> DVec4 { + DVec4::new(self.w, self.y, self.z, self.z) + } + + #[inline] + fn wyzw(self) -> DVec4 { + DVec4::new(self.w, self.y, self.z, self.w) + } + + #[inline] + fn wywx(self) -> DVec4 { + DVec4::new(self.w, self.y, self.w, self.x) + } + + #[inline] + fn wywy(self) -> DVec4 { + DVec4::new(self.w, self.y, self.w, self.y) + } + + #[inline] + fn wywz(self) -> DVec4 { + DVec4::new(self.w, self.y, self.w, self.z) + } + + #[inline] + fn wyww(self) -> DVec4 { + DVec4::new(self.w, self.y, self.w, self.w) + } + + #[inline] + fn wzxx(self) -> DVec4 { + DVec4::new(self.w, self.z, self.x, self.x) + } + + #[inline] + fn wzxy(self) -> DVec4 { + DVec4::new(self.w, self.z, self.x, self.y) + } + + #[inline] + fn wzxz(self) -> DVec4 { + DVec4::new(self.w, self.z, self.x, self.z) + } + + #[inline] + fn wzxw(self) -> DVec4 { + DVec4::new(self.w, self.z, self.x, self.w) + } + + #[inline] + fn wzyx(self) -> DVec4 { + DVec4::new(self.w, self.z, self.y, self.x) + } + + #[inline] + fn wzyy(self) -> DVec4 { + DVec4::new(self.w, self.z, self.y, self.y) + } + + #[inline] + fn wzyz(self) -> DVec4 { + DVec4::new(self.w, self.z, self.y, self.z) + } + + #[inline] + fn wzyw(self) -> DVec4 { + DVec4::new(self.w, self.z, self.y, self.w) + } + + #[inline] + fn wzzx(self) -> DVec4 { + DVec4::new(self.w, self.z, self.z, self.x) + } + + #[inline] + fn wzzy(self) -> DVec4 { + DVec4::new(self.w, self.z, self.z, self.y) + } + + #[inline] + fn wzzz(self) -> DVec4 { + DVec4::new(self.w, self.z, self.z, self.z) + } + + #[inline] + fn wzzw(self) -> DVec4 { + DVec4::new(self.w, self.z, self.z, self.w) + } + + #[inline] + fn wzwx(self) -> DVec4 { + DVec4::new(self.w, self.z, self.w, self.x) + } + + #[inline] + fn wzwy(self) -> DVec4 { + DVec4::new(self.w, self.z, self.w, self.y) + } + + #[inline] + fn wzwz(self) -> DVec4 { + DVec4::new(self.w, self.z, self.w, self.z) + } + + #[inline] + fn wzww(self) -> DVec4 { + DVec4::new(self.w, self.z, self.w, self.w) + } + + #[inline] + fn wwxx(self) -> DVec4 { + DVec4::new(self.w, self.w, self.x, self.x) + } + + #[inline] + fn wwxy(self) -> DVec4 { + DVec4::new(self.w, self.w, self.x, self.y) + } + + #[inline] + fn wwxz(self) -> DVec4 { + DVec4::new(self.w, self.w, self.x, self.z) + } + + #[inline] + fn wwxw(self) -> DVec4 { + DVec4::new(self.w, self.w, self.x, self.w) + } + + #[inline] + fn wwyx(self) -> DVec4 { + DVec4::new(self.w, self.w, self.y, self.x) + } + + #[inline] + fn wwyy(self) -> DVec4 { + DVec4::new(self.w, self.w, self.y, self.y) + } + + #[inline] + fn wwyz(self) -> DVec4 { + DVec4::new(self.w, self.w, self.y, self.z) + } + + #[inline] + fn wwyw(self) -> DVec4 { + DVec4::new(self.w, self.w, self.y, self.w) + } + + #[inline] + fn wwzx(self) -> DVec4 { + DVec4::new(self.w, self.w, self.z, self.x) + } + + #[inline] + fn wwzy(self) -> DVec4 { + DVec4::new(self.w, self.w, self.z, self.y) + } + + #[inline] + fn wwzz(self) -> DVec4 { + DVec4::new(self.w, self.w, self.z, self.z) + } + + #[inline] + fn wwzw(self) -> DVec4 { + DVec4::new(self.w, self.w, self.z, self.w) + } + + #[inline] + fn wwwx(self) -> DVec4 { + DVec4::new(self.w, self.w, self.w, self.x) + } + + #[inline] + fn wwwy(self) -> DVec4 { + DVec4::new(self.w, self.w, self.w, self.y) + } + + #[inline] + fn wwwz(self) -> DVec4 { + DVec4::new(self.w, self.w, self.w, self.z) + } + + #[inline] + fn wwww(self) -> DVec4 { + DVec4::new(self.w, self.w, self.w, self.w) + } +} diff --git a/src/swizzles/dvec4_impl_scalar.rs b/src/swizzles/dvec4_impl_scalar.rs deleted file mode 100644 index 4b6740b..0000000 --- a/src/swizzles/dvec4_impl_scalar.rs +++ /dev/null @@ -1,1350 +0,0 @@ -// Generated by swizzlegen. Do not edit. - -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) - } - #[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 xxxw(self) -> DVec4 { - DVec4::new(self.x, self.x, self.x, self.w) - } - #[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 xxyw(self) -> DVec4 { - DVec4::new(self.x, self.x, self.y, self.w) - } - #[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 xxzw(self) -> DVec4 { - DVec4::new(self.x, self.x, self.z, self.w) - } - #[inline] - fn xxwx(self) -> DVec4 { - DVec4::new(self.x, self.x, self.w, self.x) - } - #[inline] - fn xxwy(self) -> DVec4 { - DVec4::new(self.x, self.x, self.w, self.y) - } - #[inline] - fn xxwz(self) -> DVec4 { - DVec4::new(self.x, self.x, self.w, self.z) - } - #[inline] - fn xxww(self) -> DVec4 { - DVec4::new(self.x, self.x, self.w, self.w) - } - #[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 xyxw(self) -> DVec4 { - DVec4::new(self.x, self.y, self.x, self.w) - } - #[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 xyyw(self) -> DVec4 { - DVec4::new(self.x, self.y, self.y, self.w) - } - #[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 xywx(self) -> DVec4 { - DVec4::new(self.x, self.y, self.w, self.x) - } - #[inline] - fn xywy(self) -> DVec4 { - DVec4::new(self.x, self.y, self.w, self.y) - } - #[inline] - fn xywz(self) -> DVec4 { - DVec4::new(self.x, self.y, self.w, self.z) - } - #[inline] - fn xyww(self) -> DVec4 { - DVec4::new(self.x, self.y, self.w, self.w) - } - #[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 xzxw(self) -> DVec4 { - DVec4::new(self.x, self.z, self.x, self.w) - } - #[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 xzyw(self) -> DVec4 { - DVec4::new(self.x, self.z, self.y, self.w) - } - #[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 xzzw(self) -> DVec4 { - DVec4::new(self.x, self.z, self.z, self.w) - } - #[inline] - fn xzwx(self) -> DVec4 { - DVec4::new(self.x, self.z, self.w, self.x) - } - #[inline] - fn xzwy(self) -> DVec4 { - DVec4::new(self.x, self.z, self.w, self.y) - } - #[inline] - fn xzwz(self) -> DVec4 { - DVec4::new(self.x, self.z, self.w, self.z) - } - #[inline] - fn xzww(self) -> DVec4 { - DVec4::new(self.x, self.z, self.w, self.w) - } - #[inline] - fn xwxx(self) -> DVec4 { - DVec4::new(self.x, self.w, self.x, self.x) - } - #[inline] - fn xwxy(self) -> DVec4 { - DVec4::new(self.x, self.w, self.x, self.y) - } - #[inline] - fn xwxz(self) -> DVec4 { - DVec4::new(self.x, self.w, self.x, self.z) - } - #[inline] - fn xwxw(self) -> DVec4 { - DVec4::new(self.x, self.w, self.x, self.w) - } - #[inline] - fn xwyx(self) -> DVec4 { - DVec4::new(self.x, self.w, self.y, self.x) - } - #[inline] - fn xwyy(self) -> DVec4 { - DVec4::new(self.x, self.w, self.y, self.y) - } - #[inline] - fn xwyz(self) -> DVec4 { - DVec4::new(self.x, self.w, self.y, self.z) - } - #[inline] - fn xwyw(self) -> DVec4 { - DVec4::new(self.x, self.w, self.y, self.w) - } - #[inline] - fn xwzx(self) -> DVec4 { - DVec4::new(self.x, self.w, self.z, self.x) - } - #[inline] - fn xwzy(self) -> DVec4 { - DVec4::new(self.x, self.w, self.z, self.y) - } - #[inline] - fn xwzz(self) -> DVec4 { - DVec4::new(self.x, self.w, self.z, self.z) - } - #[inline] - fn xwzw(self) -> DVec4 { - DVec4::new(self.x, self.w, self.z, self.w) - } - #[inline] - fn xwwx(self) -> DVec4 { - DVec4::new(self.x, self.w, self.w, self.x) - } - #[inline] - fn xwwy(self) -> DVec4 { - DVec4::new(self.x, self.w, self.w, self.y) - } - #[inline] - fn xwwz(self) -> DVec4 { - DVec4::new(self.x, self.w, self.w, self.z) - } - #[inline] - fn xwww(self) -> DVec4 { - DVec4::new(self.x, self.w, self.w, self.w) - } - #[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 yxxw(self) -> DVec4 { - DVec4::new(self.y, self.x, self.x, self.w) - } - #[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 yxyw(self) -> DVec4 { - DVec4::new(self.y, self.x, self.y, self.w) - } - #[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 yxzw(self) -> DVec4 { - DVec4::new(self.y, self.x, self.z, self.w) - } - #[inline] - fn yxwx(self) -> DVec4 { - DVec4::new(self.y, self.x, self.w, self.x) - } - #[inline] - fn yxwy(self) -> DVec4 { - DVec4::new(self.y, self.x, self.w, self.y) - } - #[inline] - fn yxwz(self) -> DVec4 { - DVec4::new(self.y, self.x, self.w, self.z) - } - #[inline] - fn yxww(self) -> DVec4 { - DVec4::new(self.y, self.x, self.w, self.w) - } - #[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 yyxw(self) -> DVec4 { - DVec4::new(self.y, self.y, self.x, self.w) - } - #[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 yyyw(self) -> DVec4 { - DVec4::new(self.y, self.y, self.y, self.w) - } - #[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 yyzw(self) -> DVec4 { - DVec4::new(self.y, self.y, self.z, self.w) - } - #[inline] - fn yywx(self) -> DVec4 { - DVec4::new(self.y, self.y, self.w, self.x) - } - #[inline] - fn yywy(self) -> DVec4 { - DVec4::new(self.y, self.y, self.w, self.y) - } - #[inline] - fn yywz(self) -> DVec4 { - DVec4::new(self.y, self.y, self.w, self.z) - } - #[inline] - fn yyww(self) -> DVec4 { - DVec4::new(self.y, self.y, self.w, self.w) - } - #[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 yzxw(self) -> DVec4 { - DVec4::new(self.y, self.z, self.x, self.w) - } - #[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 yzyw(self) -> DVec4 { - DVec4::new(self.y, self.z, self.y, self.w) - } - #[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 yzzw(self) -> DVec4 { - DVec4::new(self.y, self.z, self.z, self.w) - } - #[inline] - fn yzwx(self) -> DVec4 { - DVec4::new(self.y, self.z, self.w, self.x) - } - #[inline] - fn yzwy(self) -> DVec4 { - DVec4::new(self.y, self.z, self.w, self.y) - } - #[inline] - fn yzwz(self) -> DVec4 { - DVec4::new(self.y, self.z, self.w, self.z) - } - #[inline] - fn yzww(self) -> DVec4 { - DVec4::new(self.y, self.z, self.w, self.w) - } - #[inline] - fn ywxx(self) -> DVec4 { - DVec4::new(self.y, self.w, self.x, self.x) - } - #[inline] - fn ywxy(self) -> DVec4 { - DVec4::new(self.y, self.w, self.x, self.y) - } - #[inline] - fn ywxz(self) -> DVec4 { - DVec4::new(self.y, self.w, self.x, self.z) - } - #[inline] - fn ywxw(self) -> DVec4 { - DVec4::new(self.y, self.w, self.x, self.w) - } - #[inline] - fn ywyx(self) -> DVec4 { - DVec4::new(self.y, self.w, self.y, self.x) - } - #[inline] - fn ywyy(self) -> DVec4 { - DVec4::new(self.y, self.w, self.y, self.y) - } - #[inline] - fn ywyz(self) -> DVec4 { - DVec4::new(self.y, self.w, self.y, self.z) - } - #[inline] - fn ywyw(self) -> DVec4 { - DVec4::new(self.y, self.w, self.y, self.w) - } - #[inline] - fn ywzx(self) -> DVec4 { - DVec4::new(self.y, self.w, self.z, self.x) - } - #[inline] - fn ywzy(self) -> DVec4 { - DVec4::new(self.y, self.w, self.z, self.y) - } - #[inline] - fn ywzz(self) -> DVec4 { - DVec4::new(self.y, self.w, self.z, self.z) - } - #[inline] - fn ywzw(self) -> DVec4 { - DVec4::new(self.y, self.w, self.z, self.w) - } - #[inline] - fn ywwx(self) -> DVec4 { - DVec4::new(self.y, self.w, self.w, self.x) - } - #[inline] - fn ywwy(self) -> DVec4 { - DVec4::new(self.y, self.w, self.w, self.y) - } - #[inline] - fn ywwz(self) -> DVec4 { - DVec4::new(self.y, self.w, self.w, self.z) - } - #[inline] - fn ywww(self) -> DVec4 { - DVec4::new(self.y, self.w, self.w, self.w) - } - #[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 zxxw(self) -> DVec4 { - DVec4::new(self.z, self.x, self.x, self.w) - } - #[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 zxyw(self) -> DVec4 { - DVec4::new(self.z, self.x, self.y, self.w) - } - #[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 zxzw(self) -> DVec4 { - DVec4::new(self.z, self.x, self.z, self.w) - } - #[inline] - fn zxwx(self) -> DVec4 { - DVec4::new(self.z, self.x, self.w, self.x) - } - #[inline] - fn zxwy(self) -> DVec4 { - DVec4::new(self.z, self.x, self.w, self.y) - } - #[inline] - fn zxwz(self) -> DVec4 { - DVec4::new(self.z, self.x, self.w, self.z) - } - #[inline] - fn zxww(self) -> DVec4 { - DVec4::new(self.z, self.x, self.w, self.w) - } - #[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 zyxw(self) -> DVec4 { - DVec4::new(self.z, self.y, self.x, self.w) - } - #[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 zyyw(self) -> DVec4 { - DVec4::new(self.z, self.y, self.y, self.w) - } - #[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 zyzw(self) -> DVec4 { - DVec4::new(self.z, self.y, self.z, self.w) - } - #[inline] - fn zywx(self) -> DVec4 { - DVec4::new(self.z, self.y, self.w, self.x) - } - #[inline] - fn zywy(self) -> DVec4 { - DVec4::new(self.z, self.y, self.w, self.y) - } - #[inline] - fn zywz(self) -> DVec4 { - DVec4::new(self.z, self.y, self.w, self.z) - } - #[inline] - fn zyww(self) -> DVec4 { - DVec4::new(self.z, self.y, self.w, self.w) - } - #[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 zzxw(self) -> DVec4 { - DVec4::new(self.z, self.z, self.x, self.w) - } - #[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 zzyw(self) -> DVec4 { - DVec4::new(self.z, self.z, self.y, self.w) - } - #[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 zzzw(self) -> DVec4 { - DVec4::new(self.z, self.z, self.z, self.w) - } - #[inline] - fn zzwx(self) -> DVec4 { - DVec4::new(self.z, self.z, self.w, self.x) - } - #[inline] - fn zzwy(self) -> DVec4 { - DVec4::new(self.z, self.z, self.w, self.y) - } - #[inline] - fn zzwz(self) -> DVec4 { - DVec4::new(self.z, self.z, self.w, self.z) - } - #[inline] - fn zzww(self) -> DVec4 { - DVec4::new(self.z, self.z, self.w, self.w) - } - #[inline] - fn zwxx(self) -> DVec4 { - DVec4::new(self.z, self.w, self.x, self.x) - } - #[inline] - fn zwxy(self) -> DVec4 { - DVec4::new(self.z, self.w, self.x, self.y) - } - #[inline] - fn zwxz(self) -> DVec4 { - DVec4::new(self.z, self.w, self.x, self.z) - } - #[inline] - fn zwxw(self) -> DVec4 { - DVec4::new(self.z, self.w, self.x, self.w) - } - #[inline] - fn zwyx(self) -> DVec4 { - DVec4::new(self.z, self.w, self.y, self.x) - } - #[inline] - fn zwyy(self) -> DVec4 { - DVec4::new(self.z, self.w, self.y, self.y) - } - #[inline] - fn zwyz(self) -> DVec4 { - DVec4::new(self.z, self.w, self.y, self.z) - } - #[inline] - fn zwyw(self) -> DVec4 { - DVec4::new(self.z, self.w, self.y, self.w) - } - #[inline] - fn zwzx(self) -> DVec4 { - DVec4::new(self.z, self.w, self.z, self.x) - } - #[inline] - fn zwzy(self) -> DVec4 { - DVec4::new(self.z, self.w, self.z, self.y) - } - #[inline] - fn zwzz(self) -> DVec4 { - DVec4::new(self.z, self.w, self.z, self.z) - } - #[inline] - fn zwzw(self) -> DVec4 { - DVec4::new(self.z, self.w, self.z, self.w) - } - #[inline] - fn zwwx(self) -> DVec4 { - DVec4::new(self.z, self.w, self.w, self.x) - } - #[inline] - fn zwwy(self) -> DVec4 { - DVec4::new(self.z, self.w, self.w, self.y) - } - #[inline] - fn zwwz(self) -> DVec4 { - DVec4::new(self.z, self.w, self.w, self.z) - } - #[inline] - fn zwww(self) -> DVec4 { - DVec4::new(self.z, self.w, self.w, self.w) - } - #[inline] - fn wxxx(self) -> DVec4 { - DVec4::new(self.w, self.x, self.x, self.x) - } - #[inline] - fn wxxy(self) -> DVec4 { - DVec4::new(self.w, self.x, self.x, self.y) - } - #[inline] - fn wxxz(self) -> DVec4 { - DVec4::new(self.w, self.x, self.x, self.z) - } - #[inline] - fn wxxw(self) -> DVec4 { - DVec4::new(self.w, self.x, self.x, self.w) - } - #[inline] - fn wxyx(self) -> DVec4 { - DVec4::new(self.w, self.x, self.y, self.x) - } - #[inline] - fn wxyy(self) -> DVec4 { - DVec4::new(self.w, self.x, self.y, self.y) - } - #[inline] - fn wxyz(self) -> DVec4 { - DVec4::new(self.w, self.x, self.y, self.z) - } - #[inline] - fn wxyw(self) -> DVec4 { - DVec4::new(self.w, self.x, self.y, self.w) - } - #[inline] - fn wxzx(self) -> DVec4 { - DVec4::new(self.w, self.x, self.z, self.x) - } - #[inline] - fn wxzy(self) -> DVec4 { - DVec4::new(self.w, self.x, self.z, self.y) - } - #[inline] - fn wxzz(self) -> DVec4 { - DVec4::new(self.w, self.x, self.z, self.z) - } - #[inline] - fn wxzw(self) -> DVec4 { - DVec4::new(self.w, self.x, self.z, self.w) - } - #[inline] - fn wxwx(self) -> DVec4 { - DVec4::new(self.w, self.x, self.w, self.x) - } - #[inline] - fn wxwy(self) -> DVec4 { - DVec4::new(self.w, self.x, self.w, self.y) - } - #[inline] - fn wxwz(self) -> DVec4 { - DVec4::new(self.w, self.x, self.w, self.z) - } - #[inline] - fn wxww(self) -> DVec4 { - DVec4::new(self.w, self.x, self.w, self.w) - } - #[inline] - fn wyxx(self) -> DVec4 { - DVec4::new(self.w, self.y, self.x, self.x) - } - #[inline] - fn wyxy(self) -> DVec4 { - DVec4::new(self.w, self.y, self.x, self.y) - } - #[inline] - fn wyxz(self) -> DVec4 { - DVec4::new(self.w, self.y, self.x, self.z) - } - #[inline] - fn wyxw(self) -> DVec4 { - DVec4::new(self.w, self.y, self.x, self.w) - } - #[inline] - fn wyyx(self) -> DVec4 { - DVec4::new(self.w, self.y, self.y, self.x) - } - #[inline] - fn wyyy(self) -> DVec4 { - DVec4::new(self.w, self.y, self.y, self.y) - } - #[inline] - fn wyyz(self) -> DVec4 { - DVec4::new(self.w, self.y, self.y, self.z) - } - #[inline] - fn wyyw(self) -> DVec4 { - DVec4::new(self.w, self.y, self.y, self.w) - } - #[inline] - fn wyzx(self) -> DVec4 { - DVec4::new(self.w, self.y, self.z, self.x) - } - #[inline] - fn wyzy(self) -> DVec4 { - DVec4::new(self.w, self.y, self.z, self.y) - } - #[inline] - fn wyzz(self) -> DVec4 { - DVec4::new(self.w, self.y, self.z, self.z) - } - #[inline] - fn wyzw(self) -> DVec4 { - DVec4::new(self.w, self.y, self.z, self.w) - } - #[inline] - fn wywx(self) -> DVec4 { - DVec4::new(self.w, self.y, self.w, self.x) - } - #[inline] - fn wywy(self) -> DVec4 { - DVec4::new(self.w, self.y, self.w, self.y) - } - #[inline] - fn wywz(self) -> DVec4 { - DVec4::new(self.w, self.y, self.w, self.z) - } - #[inline] - fn wyww(self) -> DVec4 { - DVec4::new(self.w, self.y, self.w, self.w) - } - #[inline] - fn wzxx(self) -> DVec4 { - DVec4::new(self.w, self.z, self.x, self.x) - } - #[inline] - fn wzxy(self) -> DVec4 { - DVec4::new(self.w, self.z, self.x, self.y) - } - #[inline] - fn wzxz(self) -> DVec4 { - DVec4::new(self.w, self.z, self.x, self.z) - } - #[inline] - fn wzxw(self) -> DVec4 { - DVec4::new(self.w, self.z, self.x, self.w) - } - #[inline] - fn wzyx(self) -> DVec4 { - DVec4::new(self.w, self.z, self.y, self.x) - } - #[inline] - fn wzyy(self) -> DVec4 { - DVec4::new(self.w, self.z, self.y, self.y) - } - #[inline] - fn wzyz(self) -> DVec4 { - DVec4::new(self.w, self.z, self.y, self.z) - } - #[inline] - fn wzyw(self) -> DVec4 { - DVec4::new(self.w, self.z, self.y, self.w) - } - #[inline] - fn wzzx(self) -> DVec4 { - DVec4::new(self.w, self.z, self.z, self.x) - } - #[inline] - fn wzzy(self) -> DVec4 { - DVec4::new(self.w, self.z, self.z, self.y) - } - #[inline] - fn wzzz(self) -> DVec4 { - DVec4::new(self.w, self.z, self.z, self.z) - } - #[inline] - fn wzzw(self) -> DVec4 { - DVec4::new(self.w, self.z, self.z, self.w) - } - #[inline] - fn wzwx(self) -> DVec4 { - DVec4::new(self.w, self.z, self.w, self.x) - } - #[inline] - fn wzwy(self) -> DVec4 { - DVec4::new(self.w, self.z, self.w, self.y) - } - #[inline] - fn wzwz(self) -> DVec4 { - DVec4::new(self.w, self.z, self.w, self.z) - } - #[inline] - fn wzww(self) -> DVec4 { - DVec4::new(self.w, self.z, self.w, self.w) - } - #[inline] - fn wwxx(self) -> DVec4 { - DVec4::new(self.w, self.w, self.x, self.x) - } - #[inline] - fn wwxy(self) -> DVec4 { - DVec4::new(self.w, self.w, self.x, self.y) - } - #[inline] - fn wwxz(self) -> DVec4 { - DVec4::new(self.w, self.w, self.x, self.z) - } - #[inline] - fn wwxw(self) -> DVec4 { - DVec4::new(self.w, self.w, self.x, self.w) - } - #[inline] - fn wwyx(self) -> DVec4 { - DVec4::new(self.w, self.w, self.y, self.x) - } - #[inline] - fn wwyy(self) -> DVec4 { - DVec4::new(self.w, self.w, self.y, self.y) - } - #[inline] - fn wwyz(self) -> DVec4 { - DVec4::new(self.w, self.w, self.y, self.z) - } - #[inline] - fn wwyw(self) -> DVec4 { - DVec4::new(self.w, self.w, self.y, self.w) - } - #[inline] - fn wwzx(self) -> DVec4 { - DVec4::new(self.w, self.w, self.z, self.x) - } - #[inline] - fn wwzy(self) -> DVec4 { - DVec4::new(self.w, self.w, self.z, self.y) - } - #[inline] - fn wwzz(self) -> DVec4 { - DVec4::new(self.w, self.w, self.z, self.z) - } - #[inline] - fn wwzw(self) -> DVec4 { - DVec4::new(self.w, self.w, self.z, self.w) - } - #[inline] - fn wwwx(self) -> DVec4 { - DVec4::new(self.w, self.w, self.w, self.x) - } - #[inline] - fn wwwy(self) -> DVec4 { - DVec4::new(self.w, self.w, self.w, self.y) - } - #[inline] - fn wwwz(self) -> DVec4 { - DVec4::new(self.w, self.w, self.w, self.z) - } - #[inline] - fn wwww(self) -> DVec4 { - DVec4::new(self.w, self.w, self.w, self.w) - } - #[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 xxz(self) -> DVec3 { - DVec3::new(self.x, self.x, self.z) - } - #[inline] - fn xxw(self) -> DVec3 { - DVec3::new(self.x, self.x, self.w) - } - #[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 xyz(self) -> DVec3 { - DVec3::new(self.x, self.y, self.z) - } - #[inline] - fn xyw(self) -> DVec3 { - DVec3::new(self.x, self.y, self.w) - } - #[inline] - fn xzx(self) -> DVec3 { - DVec3::new(self.x, self.z, self.x) - } - #[inline] - fn xzy(self) -> DVec3 { - DVec3::new(self.x, self.z, self.y) - } - #[inline] - fn xzz(self) -> DVec3 { - DVec3::new(self.x, self.z, self.z) - } - #[inline] - fn xzw(self) -> DVec3 { - DVec3::new(self.x, self.z, self.w) - } - #[inline] - fn xwx(self) -> DVec3 { - DVec3::new(self.x, self.w, self.x) - } - #[inline] - fn xwy(self) -> DVec3 { - DVec3::new(self.x, self.w, self.y) - } - #[inline] - fn xwz(self) -> DVec3 { - DVec3::new(self.x, self.w, self.z) - } - #[inline] - fn xww(self) -> DVec3 { - DVec3::new(self.x, self.w, self.w) - } - #[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 yxz(self) -> DVec3 { - DVec3::new(self.y, self.x, self.z) - } - #[inline] - fn yxw(self) -> DVec3 { - DVec3::new(self.y, self.x, self.w) - } - #[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 yyz(self) -> DVec3 { - DVec3::new(self.y, self.y, self.z) - } - #[inline] - fn yyw(self) -> DVec3 { - DVec3::new(self.y, self.y, self.w) - } - #[inline] - fn yzx(self) -> DVec3 { - DVec3::new(self.y, self.z, self.x) - } - #[inline] - fn yzy(self) -> DVec3 { - DVec3::new(self.y, self.z, self.y) - } - #[inline] - fn yzz(self) -> DVec3 { - DVec3::new(self.y, self.z, self.z) - } - #[inline] - fn yzw(self) -> DVec3 { - DVec3::new(self.y, self.z, self.w) - } - #[inline] - fn ywx(self) -> DVec3 { - DVec3::new(self.y, self.w, self.x) - } - #[inline] - fn ywy(self) -> DVec3 { - DVec3::new(self.y, self.w, self.y) - } - #[inline] - fn ywz(self) -> DVec3 { - DVec3::new(self.y, self.w, self.z) - } - #[inline] - fn yww(self) -> DVec3 { - DVec3::new(self.y, self.w, self.w) - } - #[inline] - fn zxx(self) -> DVec3 { - DVec3::new(self.z, self.x, self.x) - } - #[inline] - fn zxy(self) -> DVec3 { - DVec3::new(self.z, self.x, self.y) - } - #[inline] - fn zxz(self) -> DVec3 { - DVec3::new(self.z, self.x, self.z) - } - #[inline] - fn zxw(self) -> DVec3 { - DVec3::new(self.z, self.x, self.w) - } - #[inline] - fn zyx(self) -> DVec3 { - DVec3::new(self.z, self.y, self.x) - } - #[inline] - fn zyy(self) -> DVec3 { - DVec3::new(self.z, self.y, self.y) - } - #[inline] - fn zyz(self) -> DVec3 { - DVec3::new(self.z, self.y, self.z) - } - #[inline] - fn zyw(self) -> DVec3 { - DVec3::new(self.z, self.y, self.w) - } - #[inline] - fn zzx(self) -> DVec3 { - DVec3::new(self.z, self.z, self.x) - } - #[inline] - fn zzy(self) -> DVec3 { - DVec3::new(self.z, self.z, self.y) - } - #[inline] - fn zzz(self) -> DVec3 { - DVec3::new(self.z, self.z, self.z) - } - #[inline] - fn zzw(self) -> DVec3 { - DVec3::new(self.z, self.z, self.w) - } - #[inline] - fn zwx(self) -> DVec3 { - DVec3::new(self.z, self.w, self.x) - } - #[inline] - fn zwy(self) -> DVec3 { - DVec3::new(self.z, self.w, self.y) - } - #[inline] - fn zwz(self) -> DVec3 { - DVec3::new(self.z, self.w, self.z) - } - #[inline] - fn zww(self) -> DVec3 { - DVec3::new(self.z, self.w, self.w) - } - #[inline] - fn wxx(self) -> DVec3 { - DVec3::new(self.w, self.x, self.x) - } - #[inline] - fn wxy(self) -> DVec3 { - DVec3::new(self.w, self.x, self.y) - } - #[inline] - fn wxz(self) -> DVec3 { - DVec3::new(self.w, self.x, self.z) - } - #[inline] - fn wxw(self) -> DVec3 { - DVec3::new(self.w, self.x, self.w) - } - #[inline] - fn wyx(self) -> DVec3 { - DVec3::new(self.w, self.y, self.x) - } - #[inline] - fn wyy(self) -> DVec3 { - DVec3::new(self.w, self.y, self.y) - } - #[inline] - fn wyz(self) -> DVec3 { - DVec3::new(self.w, self.y, self.z) - } - #[inline] - fn wyw(self) -> DVec3 { - DVec3::new(self.w, self.y, self.w) - } - #[inline] - fn wzx(self) -> DVec3 { - DVec3::new(self.w, self.z, self.x) - } - #[inline] - fn wzy(self) -> DVec3 { - DVec3::new(self.w, self.z, self.y) - } - #[inline] - fn wzz(self) -> DVec3 { - DVec3::new(self.w, self.z, self.z) - } - #[inline] - fn wzw(self) -> DVec3 { - DVec3::new(self.w, self.z, self.w) - } - #[inline] - fn wwx(self) -> DVec3 { - DVec3::new(self.w, self.w, self.x) - } - #[inline] - fn wwy(self) -> DVec3 { - DVec3::new(self.w, self.w, self.y) - } - #[inline] - fn wwz(self) -> DVec3 { - DVec3::new(self.w, self.w, self.z) - } - #[inline] - fn www(self) -> DVec3 { - DVec3::new(self.w, self.w, self.w) - } - #[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 xw(self) -> DVec2 { - DVec2::new(self.x, self.w) - } - #[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 yw(self) -> DVec2 { - DVec2::new(self.y, self.w) - } - #[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) - } - #[inline] - fn zw(self) -> DVec2 { - DVec2::new(self.z, self.w) - } - #[inline] - fn wx(self) -> DVec2 { - DVec2::new(self.w, self.x) - } - #[inline] - fn wy(self) -> DVec2 { - DVec2::new(self.w, self.y) - } - #[inline] - fn wz(self) -> DVec2 { - DVec2::new(self.w, self.z) - } - #[inline] - fn ww(self) -> DVec2 { - DVec2::new(self.w, self.w) - } -} diff --git a/src/swizzles/ivec2_impl.rs b/src/swizzles/ivec2_impl.rs new file mode 100644 index 0000000..701b72c --- /dev/null +++ b/src/swizzles/ivec2_impl.rs @@ -0,0 +1,193 @@ +// Generated from swizzle_impl.rs.tera template. Edit the template, not the generated file. + +use crate::{IVec2, IVec3, IVec4, Vec2Swizzles}; + +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) + } +} diff --git a/src/swizzles/ivec2_impl_scalar.rs b/src/swizzles/ivec2_impl_scalar.rs deleted file mode 100644 index 26702c8..0000000 --- a/src/swizzles/ivec2_impl_scalar.rs +++ /dev/null @@ -1,118 +0,0 @@ -// Generated by swizzlegen. Do not edit. - -use super::Vec2Swizzles; -use crate::{IVec2, IVec3, IVec4}; - -impl Vec2Swizzles for IVec2 { - type Vec3 = IVec3; - type Vec4 = IVec4; - - #[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.rs b/src/swizzles/ivec3_impl.rs new file mode 100644 index 0000000..03d5f43 --- /dev/null +++ b/src/swizzles/ivec3_impl.rs @@ -0,0 +1,729 @@ +// Generated from swizzle_impl.rs.tera template. Edit the template, not the generated file. + +use crate::{IVec2, IVec3, IVec4, Vec3Swizzles}; + +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) + } +} diff --git a/src/swizzles/ivec3_impl_scalar.rs b/src/swizzles/ivec3_impl_scalar.rs deleted file mode 100644 index 799e5d8..0000000 --- a/src/swizzles/ivec3_impl_scalar.rs +++ /dev/null @@ -1,474 +0,0 @@ -// Generated by swizzlegen. Do not edit. - -use super::Vec3Swizzles; -use crate::{IVec2, IVec3, IVec4}; - -impl Vec3Swizzles for IVec3 { - type Vec2 = IVec2; - type Vec4 = IVec4; - - #[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.rs b/src/swizzles/ivec4_impl.rs new file mode 100644 index 0000000..c2845e8 --- /dev/null +++ b/src/swizzles/ivec4_impl.rs @@ -0,0 +1,1993 @@ +// Generated from swizzle_impl.rs.tera template. Edit the template, not the generated file. + +use crate::{IVec2, IVec3, IVec4, Vec4Swizzles}; + +impl Vec4Swizzles for IVec4 { + type Vec2 = IVec2; + + type Vec3 = IVec3; + + #[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 xw(self) -> IVec2 { + IVec2 { + x: self.x, + y: self.w, + } + } + + #[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 yw(self) -> IVec2 { + IVec2 { + x: self.y, + y: self.w, + } + } + + #[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 zw(self) -> IVec2 { + IVec2 { + x: self.z, + y: self.w, + } + } + + #[inline] + fn wx(self) -> IVec2 { + IVec2 { + x: self.w, + y: self.x, + } + } + + #[inline] + fn wy(self) -> IVec2 { + IVec2 { + x: self.w, + y: self.y, + } + } + + #[inline] + fn wz(self) -> IVec2 { + IVec2 { + x: self.w, + y: self.z, + } + } + + #[inline] + fn ww(self) -> IVec2 { + IVec2 { + x: self.w, + y: self.w, + } + } + + #[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 xxw(self) -> IVec3 { + IVec3 { + x: self.x, + y: self.x, + z: self.w, + } + } + + #[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 xyw(self) -> IVec3 { + IVec3 { + x: self.x, + y: self.y, + z: self.w, + } + } + + #[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 xzw(self) -> IVec3 { + IVec3 { + x: self.x, + y: self.z, + z: self.w, + } + } + + #[inline] + fn xwx(self) -> IVec3 { + IVec3 { + x: self.x, + y: self.w, + z: self.x, + } + } + + #[inline] + fn xwy(self) -> IVec3 { + IVec3 { + x: self.x, + y: self.w, + z: self.y, + } + } + + #[inline] + fn xwz(self) -> IVec3 { + IVec3 { + x: self.x, + y: self.w, + z: self.z, + } + } + + #[inline] + fn xww(self) -> IVec3 { + IVec3 { + x: self.x, + y: self.w, + z: self.w, + } + } + + #[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 yxw(self) -> IVec3 { + IVec3 { + x: self.y, + y: self.x, + z: self.w, + } + } + + #[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 yyw(self) -> IVec3 { + IVec3 { + x: self.y, + y: self.y, + z: self.w, + } + } + + #[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 yzw(self) -> IVec3 { + IVec3 { + x: self.y, + y: self.z, + z: self.w, + } + } + + #[inline] + fn ywx(self) -> IVec3 { + IVec3 { + x: self.y, + y: self.w, + z: self.x, + } + } + + #[inline] + fn ywy(self) -> IVec3 { + IVec3 { + x: self.y, + y: self.w, + z: self.y, + } + } + + #[inline] + fn ywz(self) -> IVec3 { + IVec3 { + x: self.y, + y: self.w, + z: self.z, + } + } + + #[inline] + fn yww(self) -> IVec3 { + IVec3 { + x: self.y, + y: self.w, + z: self.w, + } + } + + #[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 zxw(self) -> IVec3 { + IVec3 { + x: self.z, + y: self.x, + z: self.w, + } + } + + #[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 zyw(self) -> IVec3 { + IVec3 { + x: self.z, + y: self.y, + z: self.w, + } + } + + #[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 zzw(self) -> IVec3 { + IVec3 { + x: self.z, + y: self.z, + z: self.w, + } + } + + #[inline] + fn zwx(self) -> IVec3 { + IVec3 { + x: self.z, + y: self.w, + z: self.x, + } + } + + #[inline] + fn zwy(self) -> IVec3 { + IVec3 { + x: self.z, + y: self.w, + z: self.y, + } + } + + #[inline] + fn zwz(self) -> IVec3 { + IVec3 { + x: self.z, + y: self.w, + z: self.z, + } + } + + #[inline] + fn zww(self) -> IVec3 { + IVec3 { + x: self.z, + y: self.w, + z: self.w, + } + } + + #[inline] + fn wxx(self) -> IVec3 { + IVec3 { + x: self.w, + y: self.x, + z: self.x, + } + } + + #[inline] + fn wxy(self) -> IVec3 { + IVec3 { + x: self.w, + y: self.x, + z: self.y, + } + } + + #[inline] + fn wxz(self) -> IVec3 { + IVec3 { + x: self.w, + y: self.x, + z: self.z, + } + } + + #[inline] + fn wxw(self) -> IVec3 { + IVec3 { + x: self.w, + y: self.x, + z: self.w, + } + } + + #[inline] + fn wyx(self) -> IVec3 { + IVec3 { + x: self.w, + y: self.y, + z: self.x, + } + } + + #[inline] + fn wyy(self) -> IVec3 { + IVec3 { + x: self.w, + y: self.y, + z: self.y, + } + } + + #[inline] + fn wyz(self) -> IVec3 { + IVec3 { + x: self.w, + y: self.y, + z: self.z, + } + } + + #[inline] + fn wyw(self) -> IVec3 { + IVec3 { + x: self.w, + y: self.y, + z: self.w, + } + } + + #[inline] + fn wzx(self) -> IVec3 { + IVec3 { + x: self.w, + y: self.z, + z: self.x, + } + } + + #[inline] + fn wzy(self) -> IVec3 { + IVec3 { + x: self.w, + y: self.z, + z: self.y, + } + } + + #[inline] + fn wzz(self) -> IVec3 { + IVec3 { + x: self.w, + y: self.z, + z: self.z, + } + } + + #[inline] + fn wzw(self) -> IVec3 { + IVec3 { + x: self.w, + y: self.z, + z: self.w, + } + } + + #[inline] + fn wwx(self) -> IVec3 { + IVec3 { + x: self.w, + y: self.w, + z: self.x, + } + } + + #[inline] + fn wwy(self) -> IVec3 { + IVec3 { + x: self.w, + y: self.w, + z: self.y, + } + } + + #[inline] + fn wwz(self) -> IVec3 { + IVec3 { + x: self.w, + y: self.w, + z: self.z, + } + } + + #[inline] + fn www(self) -> IVec3 { + IVec3 { + x: self.w, + y: self.w, + z: self.w, + } + } + + #[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 xxxw(self) -> IVec4 { + IVec4::new(self.x, self.x, self.x, self.w) + } + + #[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 xxyw(self) -> IVec4 { + IVec4::new(self.x, self.x, self.y, self.w) + } + + #[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 xxzw(self) -> IVec4 { + IVec4::new(self.x, self.x, self.z, self.w) + } + + #[inline] + fn xxwx(self) -> IVec4 { + IVec4::new(self.x, self.x, self.w, self.x) + } + + #[inline] + fn xxwy(self) -> IVec4 { + IVec4::new(self.x, self.x, self.w, self.y) + } + + #[inline] + fn xxwz(self) -> IVec4 { + IVec4::new(self.x, self.x, self.w, self.z) + } + + #[inline] + fn xxww(self) -> IVec4 { + IVec4::new(self.x, self.x, self.w, self.w) + } + + #[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 xyxw(self) -> IVec4 { + IVec4::new(self.x, self.y, self.x, self.w) + } + + #[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 xyyw(self) -> IVec4 { + IVec4::new(self.x, self.y, self.y, self.w) + } + + #[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 xyzw(self) -> IVec4 { + IVec4::new(self.x, self.y, self.z, self.w) + } + + #[inline] + fn xywx(self) -> IVec4 { + IVec4::new(self.x, self.y, self.w, self.x) + } + + #[inline] + fn xywy(self) -> IVec4 { + IVec4::new(self.x, self.y, self.w, self.y) + } + + #[inline] + fn xywz(self) -> IVec4 { + IVec4::new(self.x, self.y, self.w, self.z) + } + + #[inline] + fn xyww(self) -> IVec4 { + IVec4::new(self.x, self.y, self.w, self.w) + } + + #[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 xzxw(self) -> IVec4 { + IVec4::new(self.x, self.z, self.x, self.w) + } + + #[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 xzyw(self) -> IVec4 { + IVec4::new(self.x, self.z, self.y, self.w) + } + + #[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 xzzw(self) -> IVec4 { + IVec4::new(self.x, self.z, self.z, self.w) + } + + #[inline] + fn xzwx(self) -> IVec4 { + IVec4::new(self.x, self.z, self.w, self.x) + } + + #[inline] + fn xzwy(self) -> IVec4 { + IVec4::new(self.x, self.z, self.w, self.y) + } + + #[inline] + fn xzwz(self) -> IVec4 { + IVec4::new(self.x, self.z, self.w, self.z) + } + + #[inline] + fn xzww(self) -> IVec4 { + IVec4::new(self.x, self.z, self.w, self.w) + } + + #[inline] + fn xwxx(self) -> IVec4 { + IVec4::new(self.x, self.w, self.x, self.x) + } + + #[inline] + fn xwxy(self) -> IVec4 { + IVec4::new(self.x, self.w, self.x, self.y) + } + + #[inline] + fn xwxz(self) -> IVec4 { + IVec4::new(self.x, self.w, self.x, self.z) + } + + #[inline] + fn xwxw(self) -> IVec4 { + IVec4::new(self.x, self.w, self.x, self.w) + } + + #[inline] + fn xwyx(self) -> IVec4 { + IVec4::new(self.x, self.w, self.y, self.x) + } + + #[inline] + fn xwyy(self) -> IVec4 { + IVec4::new(self.x, self.w, self.y, self.y) + } + + #[inline] + fn xwyz(self) -> IVec4 { + IVec4::new(self.x, self.w, self.y, self.z) + } + + #[inline] + fn xwyw(self) -> IVec4 { + IVec4::new(self.x, self.w, self.y, self.w) + } + + #[inline] + fn xwzx(self) -> IVec4 { + IVec4::new(self.x, self.w, self.z, self.x) + } + + #[inline] + fn xwzy(self) -> IVec4 { + IVec4::new(self.x, self.w, self.z, self.y) + } + + #[inline] + fn xwzz(self) -> IVec4 { + IVec4::new(self.x, self.w, self.z, self.z) + } + + #[inline] + fn xwzw(self) -> IVec4 { + IVec4::new(self.x, self.w, self.z, self.w) + } + + #[inline] + fn xwwx(self) -> IVec4 { + IVec4::new(self.x, self.w, self.w, self.x) + } + + #[inline] + fn xwwy(self) -> IVec4 { + IVec4::new(self.x, self.w, self.w, self.y) + } + + #[inline] + fn xwwz(self) -> IVec4 { + IVec4::new(self.x, self.w, self.w, self.z) + } + + #[inline] + fn xwww(self) -> IVec4 { + IVec4::new(self.x, self.w, self.w, self.w) + } + + #[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 yxxw(self) -> IVec4 { + IVec4::new(self.y, self.x, self.x, self.w) + } + + #[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 yxyw(self) -> IVec4 { + IVec4::new(self.y, self.x, self.y, self.w) + } + + #[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 yxzw(self) -> IVec4 { + IVec4::new(self.y, self.x, self.z, self.w) + } + + #[inline] + fn yxwx(self) -> IVec4 { + IVec4::new(self.y, self.x, self.w, self.x) + } + + #[inline] + fn yxwy(self) -> IVec4 { + IVec4::new(self.y, self.x, self.w, self.y) + } + + #[inline] + fn yxwz(self) -> IVec4 { + IVec4::new(self.y, self.x, self.w, self.z) + } + + #[inline] + fn yxww(self) -> IVec4 { + IVec4::new(self.y, self.x, self.w, self.w) + } + + #[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 yyxw(self) -> IVec4 { + IVec4::new(self.y, self.y, self.x, self.w) + } + + #[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 yyyw(self) -> IVec4 { + IVec4::new(self.y, self.y, self.y, self.w) + } + + #[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 yyzw(self) -> IVec4 { + IVec4::new(self.y, self.y, self.z, self.w) + } + + #[inline] + fn yywx(self) -> IVec4 { + IVec4::new(self.y, self.y, self.w, self.x) + } + + #[inline] + fn yywy(self) -> IVec4 { + IVec4::new(self.y, self.y, self.w, self.y) + } + + #[inline] + fn yywz(self) -> IVec4 { + IVec4::new(self.y, self.y, self.w, self.z) + } + + #[inline] + fn yyww(self) -> IVec4 { + IVec4::new(self.y, self.y, self.w, self.w) + } + + #[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 yzxw(self) -> IVec4 { + IVec4::new(self.y, self.z, self.x, self.w) + } + + #[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 yzyw(self) -> IVec4 { + IVec4::new(self.y, self.z, self.y, self.w) + } + + #[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 yzzw(self) -> IVec4 { + IVec4::new(self.y, self.z, self.z, self.w) + } + + #[inline] + fn yzwx(self) -> IVec4 { + IVec4::new(self.y, self.z, self.w, self.x) + } + + #[inline] + fn yzwy(self) -> IVec4 { + IVec4::new(self.y, self.z, self.w, self.y) + } + + #[inline] + fn yzwz(self) -> IVec4 { + IVec4::new(self.y, self.z, self.w, self.z) + } + + #[inline] + fn yzww(self) -> IVec4 { + IVec4::new(self.y, self.z, self.w, self.w) + } + + #[inline] + fn ywxx(self) -> IVec4 { + IVec4::new(self.y, self.w, self.x, self.x) + } + + #[inline] + fn ywxy(self) -> IVec4 { + IVec4::new(self.y, self.w, self.x, self.y) + } + + #[inline] + fn ywxz(self) -> IVec4 { + IVec4::new(self.y, self.w, self.x, self.z) + } + + #[inline] + fn ywxw(self) -> IVec4 { + IVec4::new(self.y, self.w, self.x, self.w) + } + + #[inline] + fn ywyx(self) -> IVec4 { + IVec4::new(self.y, self.w, self.y, self.x) + } + + #[inline] + fn ywyy(self) -> IVec4 { + IVec4::new(self.y, self.w, self.y, self.y) + } + + #[inline] + fn ywyz(self) -> IVec4 { + IVec4::new(self.y, self.w, self.y, self.z) + } + + #[inline] + fn ywyw(self) -> IVec4 { + IVec4::new(self.y, self.w, self.y, self.w) + } + + #[inline] + fn ywzx(self) -> IVec4 { + IVec4::new(self.y, self.w, self.z, self.x) + } + + #[inline] + fn ywzy(self) -> IVec4 { + IVec4::new(self.y, self.w, self.z, self.y) + } + + #[inline] + fn ywzz(self) -> IVec4 { + IVec4::new(self.y, self.w, self.z, self.z) + } + + #[inline] + fn ywzw(self) -> IVec4 { + IVec4::new(self.y, self.w, self.z, self.w) + } + + #[inline] + fn ywwx(self) -> IVec4 { + IVec4::new(self.y, self.w, self.w, self.x) + } + + #[inline] + fn ywwy(self) -> IVec4 { + IVec4::new(self.y, self.w, self.w, self.y) + } + + #[inline] + fn ywwz(self) -> IVec4 { + IVec4::new(self.y, self.w, self.w, self.z) + } + + #[inline] + fn ywww(self) -> IVec4 { + IVec4::new(self.y, self.w, self.w, self.w) + } + + #[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 zxxw(self) -> IVec4 { + IVec4::new(self.z, self.x, self.x, self.w) + } + + #[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 zxyw(self) -> IVec4 { + IVec4::new(self.z, self.x, self.y, self.w) + } + + #[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 zxzw(self) -> IVec4 { + IVec4::new(self.z, self.x, self.z, self.w) + } + + #[inline] + fn zxwx(self) -> IVec4 { + IVec4::new(self.z, self.x, self.w, self.x) + } + + #[inline] + fn zxwy(self) -> IVec4 { + IVec4::new(self.z, self.x, self.w, self.y) + } + + #[inline] + fn zxwz(self) -> IVec4 { + IVec4::new(self.z, self.x, self.w, self.z) + } + + #[inline] + fn zxww(self) -> IVec4 { + IVec4::new(self.z, self.x, self.w, self.w) + } + + #[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 zyxw(self) -> IVec4 { + IVec4::new(self.z, self.y, self.x, self.w) + } + + #[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 zyyw(self) -> IVec4 { + IVec4::new(self.z, self.y, self.y, self.w) + } + + #[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 zyzw(self) -> IVec4 { + IVec4::new(self.z, self.y, self.z, self.w) + } + + #[inline] + fn zywx(self) -> IVec4 { + IVec4::new(self.z, self.y, self.w, self.x) + } + + #[inline] + fn zywy(self) -> IVec4 { + IVec4::new(self.z, self.y, self.w, self.y) + } + + #[inline] + fn zywz(self) -> IVec4 { + IVec4::new(self.z, self.y, self.w, self.z) + } + + #[inline] + fn zyww(self) -> IVec4 { + IVec4::new(self.z, self.y, self.w, self.w) + } + + #[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 zzxw(self) -> IVec4 { + IVec4::new(self.z, self.z, self.x, self.w) + } + + #[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 zzyw(self) -> IVec4 { + IVec4::new(self.z, self.z, self.y, self.w) + } + + #[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 zzzw(self) -> IVec4 { + IVec4::new(self.z, self.z, self.z, self.w) + } + + #[inline] + fn zzwx(self) -> IVec4 { + IVec4::new(self.z, self.z, self.w, self.x) + } + + #[inline] + fn zzwy(self) -> IVec4 { + IVec4::new(self.z, self.z, self.w, self.y) + } + + #[inline] + fn zzwz(self) -> IVec4 { + IVec4::new(self.z, self.z, self.w, self.z) + } + + #[inline] + fn zzww(self) -> IVec4 { + IVec4::new(self.z, self.z, self.w, self.w) + } + + #[inline] + fn zwxx(self) -> IVec4 { + IVec4::new(self.z, self.w, self.x, self.x) + } + + #[inline] + fn zwxy(self) -> IVec4 { + IVec4::new(self.z, self.w, self.x, self.y) + } + + #[inline] + fn zwxz(self) -> IVec4 { + IVec4::new(self.z, self.w, self.x, self.z) + } + + #[inline] + fn zwxw(self) -> IVec4 { + IVec4::new(self.z, self.w, self.x, self.w) + } + + #[inline] + fn zwyx(self) -> IVec4 { + IVec4::new(self.z, self.w, self.y, self.x) + } + + #[inline] + fn zwyy(self) -> IVec4 { + IVec4::new(self.z, self.w, self.y, self.y) + } + + #[inline] + fn zwyz(self) -> IVec4 { + IVec4::new(self.z, self.w, self.y, self.z) + } + + #[inline] + fn zwyw(self) -> IVec4 { + IVec4::new(self.z, self.w, self.y, self.w) + } + + #[inline] + fn zwzx(self) -> IVec4 { + IVec4::new(self.z, self.w, self.z, self.x) + } + + #[inline] + fn zwzy(self) -> IVec4 { + IVec4::new(self.z, self.w, self.z, self.y) + } + + #[inline] + fn zwzz(self) -> IVec4 { + IVec4::new(self.z, self.w, self.z, self.z) + } + + #[inline] + fn zwzw(self) -> IVec4 { + IVec4::new(self.z, self.w, self.z, self.w) + } + + #[inline] + fn zwwx(self) -> IVec4 { + IVec4::new(self.z, self.w, self.w, self.x) + } + + #[inline] + fn zwwy(self) -> IVec4 { + IVec4::new(self.z, self.w, self.w, self.y) + } + + #[inline] + fn zwwz(self) -> IVec4 { + IVec4::new(self.z, self.w, self.w, self.z) + } + + #[inline] + fn zwww(self) -> IVec4 { + IVec4::new(self.z, self.w, self.w, self.w) + } + + #[inline] + fn wxxx(self) -> IVec4 { + IVec4::new(self.w, self.x, self.x, self.x) + } + + #[inline] + fn wxxy(self) -> IVec4 { + IVec4::new(self.w, self.x, self.x, self.y) + } + + #[inline] + fn wxxz(self) -> IVec4 { + IVec4::new(self.w, self.x, self.x, self.z) + } + + #[inline] + fn wxxw(self) -> IVec4 { + IVec4::new(self.w, self.x, self.x, self.w) + } + + #[inline] + fn wxyx(self) -> IVec4 { + IVec4::new(self.w, self.x, self.y, self.x) + } + + #[inline] + fn wxyy(self) -> IVec4 { + IVec4::new(self.w, self.x, self.y, self.y) + } + + #[inline] + fn wxyz(self) -> IVec4 { + IVec4::new(self.w, self.x, self.y, self.z) + } + + #[inline] + fn wxyw(self) -> IVec4 { + IVec4::new(self.w, self.x, self.y, self.w) + } + + #[inline] + fn wxzx(self) -> IVec4 { + IVec4::new(self.w, self.x, self.z, self.x) + } + + #[inline] + fn wxzy(self) -> IVec4 { + IVec4::new(self.w, self.x, self.z, self.y) + } + + #[inline] + fn wxzz(self) -> IVec4 { + IVec4::new(self.w, self.x, self.z, self.z) + } + + #[inline] + fn wxzw(self) -> IVec4 { + IVec4::new(self.w, self.x, self.z, self.w) + } + + #[inline] + fn wxwx(self) -> IVec4 { + IVec4::new(self.w, self.x, self.w, self.x) + } + + #[inline] + fn wxwy(self) -> IVec4 { + IVec4::new(self.w, self.x, self.w, self.y) + } + + #[inline] + fn wxwz(self) -> IVec4 { + IVec4::new(self.w, self.x, self.w, self.z) + } + + #[inline] + fn wxww(self) -> IVec4 { + IVec4::new(self.w, self.x, self.w, self.w) + } + + #[inline] + fn wyxx(self) -> IVec4 { + IVec4::new(self.w, self.y, self.x, self.x) + } + + #[inline] + fn wyxy(self) -> IVec4 { + IVec4::new(self.w, self.y, self.x, self.y) + } + + #[inline] + fn wyxz(self) -> IVec4 { + IVec4::new(self.w, self.y, self.x, self.z) + } + + #[inline] + fn wyxw(self) -> IVec4 { + IVec4::new(self.w, self.y, self.x, self.w) + } + + #[inline] + fn wyyx(self) -> IVec4 { + IVec4::new(self.w, self.y, self.y, self.x) + } + + #[inline] + fn wyyy(self) -> IVec4 { + IVec4::new(self.w, self.y, self.y, self.y) + } + + #[inline] + fn wyyz(self) -> IVec4 { + IVec4::new(self.w, self.y, self.y, self.z) + } + + #[inline] + fn wyyw(self) -> IVec4 { + IVec4::new(self.w, self.y, self.y, self.w) + } + + #[inline] + fn wyzx(self) -> IVec4 { + IVec4::new(self.w, self.y, self.z, self.x) + } + + #[inline] + fn wyzy(self) -> IVec4 { + IVec4::new(self.w, self.y, self.z, self.y) + } + + #[inline] + fn wyzz(self) -> IVec4 { + IVec4::new(self.w, self.y, self.z, self.z) + } + + #[inline] + fn wyzw(self) -> IVec4 { + IVec4::new(self.w, self.y, self.z, self.w) + } + + #[inline] + fn wywx(self) -> IVec4 { + IVec4::new(self.w, self.y, self.w, self.x) + } + + #[inline] + fn wywy(self) -> IVec4 { + IVec4::new(self.w, self.y, self.w, self.y) + } + + #[inline] + fn wywz(self) -> IVec4 { + IVec4::new(self.w, self.y, self.w, self.z) + } + + #[inline] + fn wyww(self) -> IVec4 { + IVec4::new(self.w, self.y, self.w, self.w) + } + + #[inline] + fn wzxx(self) -> IVec4 { + IVec4::new(self.w, self.z, self.x, self.x) + } + + #[inline] + fn wzxy(self) -> IVec4 { + IVec4::new(self.w, self.z, self.x, self.y) + } + + #[inline] + fn wzxz(self) -> IVec4 { + IVec4::new(self.w, self.z, self.x, self.z) + } + + #[inline] + fn wzxw(self) -> IVec4 { + IVec4::new(self.w, self.z, self.x, self.w) + } + + #[inline] + fn wzyx(self) -> IVec4 { + IVec4::new(self.w, self.z, self.y, self.x) + } + + #[inline] + fn wzyy(self) -> IVec4 { + IVec4::new(self.w, self.z, self.y, self.y) + } + + #[inline] + fn wzyz(self) -> IVec4 { + IVec4::new(self.w, self.z, self.y, self.z) + } + + #[inline] + fn wzyw(self) -> IVec4 { + IVec4::new(self.w, self.z, self.y, self.w) + } + + #[inline] + fn wzzx(self) -> IVec4 { + IVec4::new(self.w, self.z, self.z, self.x) + } + + #[inline] + fn wzzy(self) -> IVec4 { + IVec4::new(self.w, self.z, self.z, self.y) + } + + #[inline] + fn wzzz(self) -> IVec4 { + IVec4::new(self.w, self.z, self.z, self.z) + } + + #[inline] + fn wzzw(self) -> IVec4 { + IVec4::new(self.w, self.z, self.z, self.w) + } + + #[inline] + fn wzwx(self) -> IVec4 { + IVec4::new(self.w, self.z, self.w, self.x) + } + + #[inline] + fn wzwy(self) -> IVec4 { + IVec4::new(self.w, self.z, self.w, self.y) + } + + #[inline] + fn wzwz(self) -> IVec4 { + IVec4::new(self.w, self.z, self.w, self.z) + } + + #[inline] + fn wzww(self) -> IVec4 { + IVec4::new(self.w, self.z, self.w, self.w) + } + + #[inline] + fn wwxx(self) -> IVec4 { + IVec4::new(self.w, self.w, self.x, self.x) + } + + #[inline] + fn wwxy(self) -> IVec4 { + IVec4::new(self.w, self.w, self.x, self.y) + } + + #[inline] + fn wwxz(self) -> IVec4 { + IVec4::new(self.w, self.w, self.x, self.z) + } + + #[inline] + fn wwxw(self) -> IVec4 { + IVec4::new(self.w, self.w, self.x, self.w) + } + + #[inline] + fn wwyx(self) -> IVec4 { + IVec4::new(self.w, self.w, self.y, self.x) + } + + #[inline] + fn wwyy(self) -> IVec4 { + IVec4::new(self.w, self.w, self.y, self.y) + } + + #[inline] + fn wwyz(self) -> IVec4 { + IVec4::new(self.w, self.w, self.y, self.z) + } + + #[inline] + fn wwyw(self) -> IVec4 { + IVec4::new(self.w, self.w, self.y, self.w) + } + + #[inline] + fn wwzx(self) -> IVec4 { + IVec4::new(self.w, self.w, self.z, self.x) + } + + #[inline] + fn wwzy(self) -> IVec4 { + IVec4::new(self.w, self.w, self.z, self.y) + } + + #[inline] + fn wwzz(self) -> IVec4 { + IVec4::new(self.w, self.w, self.z, self.z) + } + + #[inline] + fn wwzw(self) -> IVec4 { + IVec4::new(self.w, self.w, self.z, self.w) + } + + #[inline] + fn wwwx(self) -> IVec4 { + IVec4::new(self.w, self.w, self.w, self.x) + } + + #[inline] + fn wwwy(self) -> IVec4 { + IVec4::new(self.w, self.w, self.w, self.y) + } + + #[inline] + fn wwwz(self) -> IVec4 { + IVec4::new(self.w, self.w, self.w, self.z) + } + + #[inline] + fn wwww(self) -> IVec4 { + IVec4::new(self.w, self.w, self.w, self.w) + } +} diff --git a/src/swizzles/ivec4_impl_scalar.rs b/src/swizzles/ivec4_impl_scalar.rs deleted file mode 100644 index a4985af..0000000 --- a/src/swizzles/ivec4_impl_scalar.rs +++ /dev/null @@ -1,1350 +0,0 @@ -// Generated by swizzlegen. Do not edit. - -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) - } - #[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 xxxw(self) -> IVec4 { - IVec4::new(self.x, self.x, self.x, self.w) - } - #[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 xxyw(self) -> IVec4 { - IVec4::new(self.x, self.x, self.y, self.w) - } - #[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 xxzw(self) -> IVec4 { - IVec4::new(self.x, self.x, self.z, self.w) - } - #[inline] - fn xxwx(self) -> IVec4 { - IVec4::new(self.x, self.x, self.w, self.x) - } - #[inline] - fn xxwy(self) -> IVec4 { - IVec4::new(self.x, self.x, self.w, self.y) - } - #[inline] - fn xxwz(self) -> IVec4 { - IVec4::new(self.x, self.x, self.w, self.z) - } - #[inline] - fn xxww(self) -> IVec4 { - IVec4::new(self.x, self.x, self.w, self.w) - } - #[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 xyxw(self) -> IVec4 { - IVec4::new(self.x, self.y, self.x, self.w) - } - #[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 xyyw(self) -> IVec4 { - IVec4::new(self.x, self.y, self.y, self.w) - } - #[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 xywx(self) -> IVec4 { - IVec4::new(self.x, self.y, self.w, self.x) - } - #[inline] - fn xywy(self) -> IVec4 { - IVec4::new(self.x, self.y, self.w, self.y) - } - #[inline] - fn xywz(self) -> IVec4 { - IVec4::new(self.x, self.y, self.w, self.z) - } - #[inline] - fn xyww(self) -> IVec4 { - IVec4::new(self.x, self.y, self.w, self.w) - } - #[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 xzxw(self) -> IVec4 { - IVec4::new(self.x, self.z, self.x, self.w) - } - #[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 xzyw(self) -> IVec4 { - IVec4::new(self.x, self.z, self.y, self.w) - } - #[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 xzzw(self) -> IVec4 { - IVec4::new(self.x, self.z, self.z, self.w) - } - #[inline] - fn xzwx(self) -> IVec4 { - IVec4::new(self.x, self.z, self.w, self.x) - } - #[inline] - fn xzwy(self) -> IVec4 { - IVec4::new(self.x, self.z, self.w, self.y) - } - #[inline] - fn xzwz(self) -> IVec4 { - IVec4::new(self.x, self.z, self.w, self.z) - } - #[inline] - fn xzww(self) -> IVec4 { - IVec4::new(self.x, self.z, self.w, self.w) - } - #[inline] - fn xwxx(self) -> IVec4 { - IVec4::new(self.x, self.w, self.x, self.x) - } - #[inline] - fn xwxy(self) -> IVec4 { - IVec4::new(self.x, self.w, self.x, self.y) - } - #[inline] - fn xwxz(self) -> IVec4 { - IVec4::new(self.x, self.w, self.x, self.z) - } - #[inline] - fn xwxw(self) -> IVec4 { - IVec4::new(self.x, self.w, self.x, self.w) - } - #[inline] - fn xwyx(self) -> IVec4 { - IVec4::new(self.x, self.w, self.y, self.x) - } - #[inline] - fn xwyy(self) -> IVec4 { - IVec4::new(self.x, self.w, self.y, self.y) - } - #[inline] - fn xwyz(self) -> IVec4 { - IVec4::new(self.x, self.w, self.y, self.z) - } - #[inline] - fn xwyw(self) -> IVec4 { - IVec4::new(self.x, self.w, self.y, self.w) - } - #[inline] - fn xwzx(self) -> IVec4 { - IVec4::new(self.x, self.w, self.z, self.x) - } - #[inline] - fn xwzy(self) -> IVec4 { - IVec4::new(self.x, self.w, self.z, self.y) - } - #[inline] - fn xwzz(self) -> IVec4 { - IVec4::new(self.x, self.w, self.z, self.z) - } - #[inline] - fn xwzw(self) -> IVec4 { - IVec4::new(self.x, self.w, self.z, self.w) - } - #[inline] - fn xwwx(self) -> IVec4 { - IVec4::new(self.x, self.w, self.w, self.x) - } - #[inline] - fn xwwy(self) -> IVec4 { - IVec4::new(self.x, self.w, self.w, self.y) - } - #[inline] - fn xwwz(self) -> IVec4 { - IVec4::new(self.x, self.w, self.w, self.z) - } - #[inline] - fn xwww(self) -> IVec4 { - IVec4::new(self.x, self.w, self.w, self.w) - } - #[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 yxxw(self) -> IVec4 { - IVec4::new(self.y, self.x, self.x, self.w) - } - #[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 yxyw(self) -> IVec4 { - IVec4::new(self.y, self.x, self.y, self.w) - } - #[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 yxzw(self) -> IVec4 { - IVec4::new(self.y, self.x, self.z, self.w) - } - #[inline] - fn yxwx(self) -> IVec4 { - IVec4::new(self.y, self.x, self.w, self.x) - } - #[inline] - fn yxwy(self) -> IVec4 { - IVec4::new(self.y, self.x, self.w, self.y) - } - #[inline] - fn yxwz(self) -> IVec4 { - IVec4::new(self.y, self.x, self.w, self.z) - } - #[inline] - fn yxww(self) -> IVec4 { - IVec4::new(self.y, self.x, self.w, self.w) - } - #[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 yyxw(self) -> IVec4 { - IVec4::new(self.y, self.y, self.x, self.w) - } - #[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 yyyw(self) -> IVec4 { - IVec4::new(self.y, self.y, self.y, self.w) - } - #[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 yyzw(self) -> IVec4 { - IVec4::new(self.y, self.y, self.z, self.w) - } - #[inline] - fn yywx(self) -> IVec4 { - IVec4::new(self.y, self.y, self.w, self.x) - } - #[inline] - fn yywy(self) -> IVec4 { - IVec4::new(self.y, self.y, self.w, self.y) - } - #[inline] - fn yywz(self) -> IVec4 { - IVec4::new(self.y, self.y, self.w, self.z) - } - #[inline] - fn yyww(self) -> IVec4 { - IVec4::new(self.y, self.y, self.w, self.w) - } - #[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 yzxw(self) -> IVec4 { - IVec4::new(self.y, self.z, self.x, self.w) - } - #[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 yzyw(self) -> IVec4 { - IVec4::new(self.y, self.z, self.y, self.w) - } - #[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 yzzw(self) -> IVec4 { - IVec4::new(self.y, self.z, self.z, self.w) - } - #[inline] - fn yzwx(self) -> IVec4 { - IVec4::new(self.y, self.z, self.w, self.x) - } - #[inline] - fn yzwy(self) -> IVec4 { - IVec4::new(self.y, self.z, self.w, self.y) - } - #[inline] - fn yzwz(self) -> IVec4 { - IVec4::new(self.y, self.z, self.w, self.z) - } - #[inline] - fn yzww(self) -> IVec4 { - IVec4::new(self.y, self.z, self.w, self.w) - } - #[inline] - fn ywxx(self) -> IVec4 { - IVec4::new(self.y, self.w, self.x, self.x) - } - #[inline] - fn ywxy(self) -> IVec4 { - IVec4::new(self.y, self.w, self.x, self.y) - } - #[inline] - fn ywxz(self) -> IVec4 { - IVec4::new(self.y, self.w, self.x, self.z) - } - #[inline] - fn ywxw(self) -> IVec4 { - IVec4::new(self.y, self.w, self.x, self.w) - } - #[inline] - fn ywyx(self) -> IVec4 { - IVec4::new(self.y, self.w, self.y, self.x) - } - #[inline] - fn ywyy(self) -> IVec4 { - IVec4::new(self.y, self.w, self.y, self.y) - } - #[inline] - fn ywyz(self) -> IVec4 { - IVec4::new(self.y, self.w, self.y, self.z) - } - #[inline] - fn ywyw(self) -> IVec4 { - IVec4::new(self.y, self.w, self.y, self.w) - } - #[inline] - fn ywzx(self) -> IVec4 { - IVec4::new(self.y, self.w, self.z, self.x) - } - #[inline] - fn ywzy(self) -> IVec4 { - IVec4::new(self.y, self.w, self.z, self.y) - } - #[inline] - fn ywzz(self) -> IVec4 { - IVec4::new(self.y, self.w, self.z, self.z) - } - #[inline] - fn ywzw(self) -> IVec4 { - IVec4::new(self.y, self.w, self.z, self.w) - } - #[inline] - fn ywwx(self) -> IVec4 { - IVec4::new(self.y, self.w, self.w, self.x) - } - #[inline] - fn ywwy(self) -> IVec4 { - IVec4::new(self.y, self.w, self.w, self.y) - } - #[inline] - fn ywwz(self) -> IVec4 { - IVec4::new(self.y, self.w, self.w, self.z) - } - #[inline] - fn ywww(self) -> IVec4 { - IVec4::new(self.y, self.w, self.w, self.w) - } - #[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 zxxw(self) -> IVec4 { - IVec4::new(self.z, self.x, self.x, self.w) - } - #[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 zxyw(self) -> IVec4 { - IVec4::new(self.z, self.x, self.y, self.w) - } - #[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 zxzw(self) -> IVec4 { - IVec4::new(self.z, self.x, self.z, self.w) - } - #[inline] - fn zxwx(self) -> IVec4 { - IVec4::new(self.z, self.x, self.w, self.x) - } - #[inline] - fn zxwy(self) -> IVec4 { - IVec4::new(self.z, self.x, self.w, self.y) - } - #[inline] - fn zxwz(self) -> IVec4 { - IVec4::new(self.z, self.x, self.w, self.z) - } - #[inline] - fn zxww(self) -> IVec4 { - IVec4::new(self.z, self.x, self.w, self.w) - } - #[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 zyxw(self) -> IVec4 { - IVec4::new(self.z, self.y, self.x, self.w) - } - #[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 zyyw(self) -> IVec4 { - IVec4::new(self.z, self.y, self.y, self.w) - } - #[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 zyzw(self) -> IVec4 { - IVec4::new(self.z, self.y, self.z, self.w) - } - #[inline] - fn zywx(self) -> IVec4 { - IVec4::new(self.z, self.y, self.w, self.x) - } - #[inline] - fn zywy(self) -> IVec4 { - IVec4::new(self.z, self.y, self.w, self.y) - } - #[inline] - fn zywz(self) -> IVec4 { - IVec4::new(self.z, self.y, self.w, self.z) - } - #[inline] - fn zyww(self) -> IVec4 { - IVec4::new(self.z, self.y, self.w, self.w) - } - #[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 zzxw(self) -> IVec4 { - IVec4::new(self.z, self.z, self.x, self.w) - } - #[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 zzyw(self) -> IVec4 { - IVec4::new(self.z, self.z, self.y, self.w) - } - #[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 zzzw(self) -> IVec4 { - IVec4::new(self.z, self.z, self.z, self.w) - } - #[inline] - fn zzwx(self) -> IVec4 { - IVec4::new(self.z, self.z, self.w, self.x) - } - #[inline] - fn zzwy(self) -> IVec4 { - IVec4::new(self.z, self.z, self.w, self.y) - } - #[inline] - fn zzwz(self) -> IVec4 { - IVec4::new(self.z, self.z, self.w, self.z) - } - #[inline] - fn zzww(self) -> IVec4 { - IVec4::new(self.z, self.z, self.w, self.w) - } - #[inline] - fn zwxx(self) -> IVec4 { - IVec4::new(self.z, self.w, self.x, self.x) - } - #[inline] - fn zwxy(self) -> IVec4 { - IVec4::new(self.z, self.w, self.x, self.y) - } - #[inline] - fn zwxz(self) -> IVec4 { - IVec4::new(self.z, self.w, self.x, self.z) - } - #[inline] - fn zwxw(self) -> IVec4 { - IVec4::new(self.z, self.w, self.x, self.w) - } - #[inline] - fn zwyx(self) -> IVec4 { - IVec4::new(self.z, self.w, self.y, self.x) - } - #[inline] - fn zwyy(self) -> IVec4 { - IVec4::new(self.z, self.w, self.y, self.y) - } - #[inline] - fn zwyz(self) -> IVec4 { - IVec4::new(self.z, self.w, self.y, self.z) - } - #[inline] - fn zwyw(self) -> IVec4 { - IVec4::new(self.z, self.w, self.y, self.w) - } - #[inline] - fn zwzx(self) -> IVec4 { - IVec4::new(self.z, self.w, self.z, self.x) - } - #[inline] - fn zwzy(self) -> IVec4 { - IVec4::new(self.z, self.w, self.z, self.y) - } - #[inline] - fn zwzz(self) -> IVec4 { - IVec4::new(self.z, self.w, self.z, self.z) - } - #[inline] - fn zwzw(self) -> IVec4 { - IVec4::new(self.z, self.w, self.z, self.w) - } - #[inline] - fn zwwx(self) -> IVec4 { - IVec4::new(self.z, self.w, self.w, self.x) - } - #[inline] - fn zwwy(self) -> IVec4 { - IVec4::new(self.z, self.w, self.w, self.y) - } - #[inline] - fn zwwz(self) -> IVec4 { - IVec4::new(self.z, self.w, self.w, self.z) - } - #[inline] - fn zwww(self) -> IVec4 { - IVec4::new(self.z, self.w, self.w, self.w) - } - #[inline] - fn wxxx(self) -> IVec4 { - IVec4::new(self.w, self.x, self.x, self.x) - } - #[inline] - fn wxxy(self) -> IVec4 { - IVec4::new(self.w, self.x, self.x, self.y) - } - #[inline] - fn wxxz(self) -> IVec4 { - IVec4::new(self.w, self.x, self.x, self.z) - } - #[inline] - fn wxxw(self) -> IVec4 { - IVec4::new(self.w, self.x, self.x, self.w) - } - #[inline] - fn wxyx(self) -> IVec4 { - IVec4::new(self.w, self.x, self.y, self.x) - } - #[inline] - fn wxyy(self) -> IVec4 { - IVec4::new(self.w, self.x, self.y, self.y) - } - #[inline] - fn wxyz(self) -> IVec4 { - IVec4::new(self.w, self.x, self.y, self.z) - } - #[inline] - fn wxyw(self) -> IVec4 { - IVec4::new(self.w, self.x, self.y, self.w) - } - #[inline] - fn wxzx(self) -> IVec4 { - IVec4::new(self.w, self.x, self.z, self.x) - } - #[inline] - fn wxzy(self) -> IVec4 { - IVec4::new(self.w, self.x, self.z, self.y) - } - #[inline] - fn wxzz(self) -> IVec4 { - IVec4::new(self.w, self.x, self.z, self.z) - } - #[inline] - fn wxzw(self) -> IVec4 { - IVec4::new(self.w, self.x, self.z, self.w) - } - #[inline] - fn wxwx(self) -> IVec4 { - IVec4::new(self.w, self.x, self.w, self.x) - } - #[inline] - fn wxwy(self) -> IVec4 { - IVec4::new(self.w, self.x, self.w, self.y) - } - #[inline] - fn wxwz(self) -> IVec4 { - IVec4::new(self.w, self.x, self.w, self.z) - } - #[inline] - fn wxww(self) -> IVec4 { - IVec4::new(self.w, self.x, self.w, self.w) - } - #[inline] - fn wyxx(self) -> IVec4 { - IVec4::new(self.w, self.y, self.x, self.x) - } - #[inline] - fn wyxy(self) -> IVec4 { - IVec4::new(self.w, self.y, self.x, self.y) - } - #[inline] - fn wyxz(self) -> IVec4 { - IVec4::new(self.w, self.y, self.x, self.z) - } - #[inline] - fn wyxw(self) -> IVec4 { - IVec4::new(self.w, self.y, self.x, self.w) - } - #[inline] - fn wyyx(self) -> IVec4 { - IVec4::new(self.w, self.y, self.y, self.x) - } - #[inline] - fn wyyy(self) -> IVec4 { - IVec4::new(self.w, self.y, self.y, self.y) - } - #[inline] - fn wyyz(self) -> IVec4 { - IVec4::new(self.w, self.y, self.y, self.z) - } - #[inline] - fn wyyw(self) -> IVec4 { - IVec4::new(self.w, self.y, self.y, self.w) - } - #[inline] - fn wyzx(self) -> IVec4 { - IVec4::new(self.w, self.y, self.z, self.x) - } - #[inline] - fn wyzy(self) -> IVec4 { - IVec4::new(self.w, self.y, self.z, self.y) - } - #[inline] - fn wyzz(self) -> IVec4 { - IVec4::new(self.w, self.y, self.z, self.z) - } - #[inline] - fn wyzw(self) -> IVec4 { - IVec4::new(self.w, self.y, self.z, self.w) - } - #[inline] - fn wywx(self) -> IVec4 { - IVec4::new(self.w, self.y, self.w, self.x) - } - #[inline] - fn wywy(self) -> IVec4 { - IVec4::new(self.w, self.y, self.w, self.y) - } - #[inline] - fn wywz(self) -> IVec4 { - IVec4::new(self.w, self.y, self.w, self.z) - } - #[inline] - fn wyww(self) -> IVec4 { - IVec4::new(self.w, self.y, self.w, self.w) - } - #[inline] - fn wzxx(self) -> IVec4 { - IVec4::new(self.w, self.z, self.x, self.x) - } - #[inline] - fn wzxy(self) -> IVec4 { - IVec4::new(self.w, self.z, self.x, self.y) - } - #[inline] - fn wzxz(self) -> IVec4 { - IVec4::new(self.w, self.z, self.x, self.z) - } - #[inline] - fn wzxw(self) -> IVec4 { - IVec4::new(self.w, self.z, self.x, self.w) - } - #[inline] - fn wzyx(self) -> IVec4 { - IVec4::new(self.w, self.z, self.y, self.x) - } - #[inline] - fn wzyy(self) -> IVec4 { - IVec4::new(self.w, self.z, self.y, self.y) - } - #[inline] - fn wzyz(self) -> IVec4 { - IVec4::new(self.w, self.z, self.y, self.z) - } - #[inline] - fn wzyw(self) -> IVec4 { - IVec4::new(self.w, self.z, self.y, self.w) - } - #[inline] - fn wzzx(self) -> IVec4 { - IVec4::new(self.w, self.z, self.z, self.x) - } - #[inline] - fn wzzy(self) -> IVec4 { - IVec4::new(self.w, self.z, self.z, self.y) - } - #[inline] - fn wzzz(self) -> IVec4 { - IVec4::new(self.w, self.z, self.z, self.z) - } - #[inline] - fn wzzw(self) -> IVec4 { - IVec4::new(self.w, self.z, self.z, self.w) - } - #[inline] - fn wzwx(self) -> IVec4 { - IVec4::new(self.w, self.z, self.w, self.x) - } - #[inline] - fn wzwy(self) -> IVec4 { - IVec4::new(self.w, self.z, self.w, self.y) - } - #[inline] - fn wzwz(self) -> IVec4 { - IVec4::new(self.w, self.z, self.w, self.z) - } - #[inline] - fn wzww(self) -> IVec4 { - IVec4::new(self.w, self.z, self.w, self.w) - } - #[inline] - fn wwxx(self) -> IVec4 { - IVec4::new(self.w, self.w, self.x, self.x) - } - #[inline] - fn wwxy(self) -> IVec4 { - IVec4::new(self.w, self.w, self.x, self.y) - } - #[inline] - fn wwxz(self) -> IVec4 { - IVec4::new(self.w, self.w, self.x, self.z) - } - #[inline] - fn wwxw(self) -> IVec4 { - IVec4::new(self.w, self.w, self.x, self.w) - } - #[inline] - fn wwyx(self) -> IVec4 { - IVec4::new(self.w, self.w, self.y, self.x) - } - #[inline] - fn wwyy(self) -> IVec4 { - IVec4::new(self.w, self.w, self.y, self.y) - } - #[inline] - fn wwyz(self) -> IVec4 { - IVec4::new(self.w, self.w, self.y, self.z) - } - #[inline] - fn wwyw(self) -> IVec4 { - IVec4::new(self.w, self.w, self.y, self.w) - } - #[inline] - fn wwzx(self) -> IVec4 { - IVec4::new(self.w, self.w, self.z, self.x) - } - #[inline] - fn wwzy(self) -> IVec4 { - IVec4::new(self.w, self.w, self.z, self.y) - } - #[inline] - fn wwzz(self) -> IVec4 { - IVec4::new(self.w, self.w, self.z, self.z) - } - #[inline] - fn wwzw(self) -> IVec4 { - IVec4::new(self.w, self.w, self.z, self.w) - } - #[inline] - fn wwwx(self) -> IVec4 { - IVec4::new(self.w, self.w, self.w, self.x) - } - #[inline] - fn wwwy(self) -> IVec4 { - IVec4::new(self.w, self.w, self.w, self.y) - } - #[inline] - fn wwwz(self) -> IVec4 { - IVec4::new(self.w, self.w, self.w, self.z) - } - #[inline] - fn wwww(self) -> IVec4 { - IVec4::new(self.w, self.w, self.w, self.w) - } - #[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 xxz(self) -> IVec3 { - IVec3::new(self.x, self.x, self.z) - } - #[inline] - fn xxw(self) -> IVec3 { - IVec3::new(self.x, self.x, self.w) - } - #[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 xyz(self) -> IVec3 { - IVec3::new(self.x, self.y, self.z) - } - #[inline] - fn xyw(self) -> IVec3 { - IVec3::new(self.x, self.y, self.w) - } - #[inline] - fn xzx(self) -> IVec3 { - IVec3::new(self.x, self.z, self.x) - } - #[inline] - fn xzy(self) -> IVec3 { - IVec3::new(self.x, self.z, self.y) - } - #[inline] - fn xzz(self) -> IVec3 { - IVec3::new(self.x, self.z, self.z) - } - #[inline] - fn xzw(self) -> IVec3 { - IVec3::new(self.x, self.z, self.w) - } - #[inline] - fn xwx(self) -> IVec3 { - IVec3::new(self.x, self.w, self.x) - } - #[inline] - fn xwy(self) -> IVec3 { - IVec3::new(self.x, self.w, self.y) - } - #[inline] - fn xwz(self) -> IVec3 { - IVec3::new(self.x, self.w, self.z) - } - #[inline] - fn xww(self) -> IVec3 { - IVec3::new(self.x, self.w, self.w) - } - #[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 yxz(self) -> IVec3 { - IVec3::new(self.y, self.x, self.z) - } - #[inline] - fn yxw(self) -> IVec3 { - IVec3::new(self.y, self.x, self.w) - } - #[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 yyz(self) -> IVec3 { - IVec3::new(self.y, self.y, self.z) - } - #[inline] - fn yyw(self) -> IVec3 { - IVec3::new(self.y, self.y, self.w) - } - #[inline] - fn yzx(self) -> IVec3 { - IVec3::new(self.y, self.z, self.x) - } - #[inline] - fn yzy(self) -> IVec3 { - IVec3::new(self.y, self.z, self.y) - } - #[inline] - fn yzz(self) -> IVec3 { - IVec3::new(self.y, self.z, self.z) - } - #[inline] - fn yzw(self) -> IVec3 { - IVec3::new(self.y, self.z, self.w) - } - #[inline] - fn ywx(self) -> IVec3 { - IVec3::new(self.y, self.w, self.x) - } - #[inline] - fn ywy(self) -> IVec3 { - IVec3::new(self.y, self.w, self.y) - } - #[inline] - fn ywz(self) -> IVec3 { - IVec3::new(self.y, self.w, self.z) - } - #[inline] - fn yww(self) -> IVec3 { - IVec3::new(self.y, self.w, self.w) - } - #[inline] - fn zxx(self) -> IVec3 { - IVec3::new(self.z, self.x, self.x) - } - #[inline] - fn zxy(self) -> IVec3 { - IVec3::new(self.z, self.x, self.y) - } - #[inline] - fn zxz(self) -> IVec3 { - IVec3::new(self.z, self.x, self.z) - } - #[inline] - fn zxw(self) -> IVec3 { - IVec3::new(self.z, self.x, self.w) - } - #[inline] - fn zyx(self) -> IVec3 { - IVec3::new(self.z, self.y, self.x) - } - #[inline] - fn zyy(self) -> IVec3 { - IVec3::new(self.z, self.y, self.y) - } - #[inline] - fn zyz(self) -> IVec3 { - IVec3::new(self.z, self.y, self.z) - } - #[inline] - fn zyw(self) -> IVec3 { - IVec3::new(self.z, self.y, self.w) - } - #[inline] - fn zzx(self) -> IVec3 { - IVec3::new(self.z, self.z, self.x) - } - #[inline] - fn zzy(self) -> IVec3 { - IVec3::new(self.z, self.z, self.y) - } - #[inline] - fn zzz(self) -> IVec3 { - IVec3::new(self.z, self.z, self.z) - } - #[inline] - fn zzw(self) -> IVec3 { - IVec3::new(self.z, self.z, self.w) - } - #[inline] - fn zwx(self) -> IVec3 { - IVec3::new(self.z, self.w, self.x) - } - #[inline] - fn zwy(self) -> IVec3 { - IVec3::new(self.z, self.w, self.y) - } - #[inline] - fn zwz(self) -> IVec3 { - IVec3::new(self.z, self.w, self.z) - } - #[inline] - fn zww(self) -> IVec3 { - IVec3::new(self.z, self.w, self.w) - } - #[inline] - fn wxx(self) -> IVec3 { - IVec3::new(self.w, self.x, self.x) - } - #[inline] - fn wxy(self) -> IVec3 { - IVec3::new(self.w, self.x, self.y) - } - #[inline] - fn wxz(self) -> IVec3 { - IVec3::new(self.w, self.x, self.z) - } - #[inline] - fn wxw(self) -> IVec3 { - IVec3::new(self.w, self.x, self.w) - } - #[inline] - fn wyx(self) -> IVec3 { - IVec3::new(self.w, self.y, self.x) - } - #[inline] - fn wyy(self) -> IVec3 { - IVec3::new(self.w, self.y, self.y) - } - #[inline] - fn wyz(self) -> IVec3 { - IVec3::new(self.w, self.y, self.z) - } - #[inline] - fn wyw(self) -> IVec3 { - IVec3::new(self.w, self.y, self.w) - } - #[inline] - fn wzx(self) -> IVec3 { - IVec3::new(self.w, self.z, self.x) - } - #[inline] - fn wzy(self) -> IVec3 { - IVec3::new(self.w, self.z, self.y) - } - #[inline] - fn wzz(self) -> IVec3 { - IVec3::new(self.w, self.z, self.z) - } - #[inline] - fn wzw(self) -> IVec3 { - IVec3::new(self.w, self.z, self.w) - } - #[inline] - fn wwx(self) -> IVec3 { - IVec3::new(self.w, self.w, self.x) - } - #[inline] - fn wwy(self) -> IVec3 { - IVec3::new(self.w, self.w, self.y) - } - #[inline] - fn wwz(self) -> IVec3 { - IVec3::new(self.w, self.w, self.z) - } - #[inline] - fn www(self) -> IVec3 { - IVec3::new(self.w, self.w, self.w) - } - #[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 xw(self) -> IVec2 { - IVec2::new(self.x, self.w) - } - #[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 yw(self) -> IVec2 { - IVec2::new(self.y, self.w) - } - #[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) - } - #[inline] - fn zw(self) -> IVec2 { - IVec2::new(self.z, self.w) - } - #[inline] - fn wx(self) -> IVec2 { - IVec2::new(self.w, self.x) - } - #[inline] - fn wy(self) -> IVec2 { - IVec2::new(self.w, self.y) - } - #[inline] - fn wz(self) -> IVec2 { - IVec2::new(self.w, self.z) - } - #[inline] - fn ww(self) -> IVec2 { - IVec2::new(self.w, self.w) - } -} diff --git a/src/swizzles/mod.rs b/src/swizzles/mod.rs deleted file mode 100644 index d1dff7a..0000000 --- a/src/swizzles/mod.rs +++ /dev/null @@ -1,35 +0,0 @@ -mod dvec2_impl_scalar; -mod dvec3_impl_scalar; -mod dvec4_impl_scalar; - -mod ivec2_impl_scalar; -mod ivec3_impl_scalar; -mod ivec4_impl_scalar; - -mod uvec2_impl_scalar; -mod uvec3_impl_scalar; -mod uvec4_impl_scalar; - -mod vec2_impl_scalar; -mod vec3_impl_scalar; -#[cfg(any( - not(any(target_feature = "sse2", target_feature = "simd128")), - feature = "scalar-math" -))] -mod vec3a_impl_scalar; -#[cfg(all(target_feature = "sse2", not(feature = "scalar-math")))] -mod vec3a_impl_sse2; -#[cfg(all(target_feature = "simd128", not(feature = "scalar-math")))] -mod vec3a_impl_wasm32; -#[cfg(any( - not(any(target_feature = "sse2", target_feature = "simd128")), - feature = "scalar-math" -))] -mod vec4_impl_scalar; -#[cfg(all(target_feature = "sse2", not(feature = "scalar-math")))] -mod vec4_impl_sse2; -#[cfg(all(target_feature = "simd128", not(feature = "scalar-math")))] -mod vec4_impl_wasm32; -mod vec_traits; - -pub use vec_traits::*; diff --git a/src/swizzles/scalar.rs b/src/swizzles/scalar.rs new file mode 100644 index 0000000..10479c8 --- /dev/null +++ b/src/swizzles/scalar.rs @@ -0,0 +1,2 @@ +mod vec3a_impl; +mod vec4_impl; diff --git a/src/swizzles/scalar/vec3a_impl.rs b/src/swizzles/scalar/vec3a_impl.rs new file mode 100644 index 0000000..8ac0a41 --- /dev/null +++ b/src/swizzles/scalar/vec3a_impl.rs @@ -0,0 +1,729 @@ +// Generated from swizzle_impl.rs.tera template. Edit the template, not the generated file. + +use crate::{Vec2, Vec3A, Vec3Swizzles, 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) + } +} diff --git a/src/swizzles/scalar/vec4_impl.rs b/src/swizzles/scalar/vec4_impl.rs new file mode 100644 index 0000000..03a8e6c --- /dev/null +++ b/src/swizzles/scalar/vec4_impl.rs @@ -0,0 +1,1993 @@ +// Generated from swizzle_impl.rs.tera template. Edit the template, not the generated file. + +use crate::{Vec2, Vec3, Vec4, Vec4Swizzles}; + +impl Vec4Swizzles for Vec4 { + type Vec2 = Vec2; + + type Vec3 = Vec3; + + #[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 xw(self) -> Vec2 { + Vec2 { + x: self.x, + y: self.w, + } + } + + #[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 yw(self) -> Vec2 { + Vec2 { + x: self.y, + y: self.w, + } + } + + #[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 zw(self) -> Vec2 { + Vec2 { + x: self.z, + y: self.w, + } + } + + #[inline] + fn wx(self) -> Vec2 { + Vec2 { + x: self.w, + y: self.x, + } + } + + #[inline] + fn wy(self) -> Vec2 { + Vec2 { + x: self.w, + y: self.y, + } + } + + #[inline] + fn wz(self) -> Vec2 { + Vec2 { + x: self.w, + y: self.z, + } + } + + #[inline] + fn ww(self) -> Vec2 { + Vec2 { + x: self.w, + y: self.w, + } + } + + #[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 xxw(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.x, + z: self.w, + } + } + + #[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 xyw(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.y, + z: self.w, + } + } + + #[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 xzw(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.z, + z: self.w, + } + } + + #[inline] + fn xwx(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.w, + z: self.x, + } + } + + #[inline] + fn xwy(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.w, + z: self.y, + } + } + + #[inline] + fn xwz(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.w, + z: self.z, + } + } + + #[inline] + fn xww(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.w, + z: self.w, + } + } + + #[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 yxw(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.x, + z: self.w, + } + } + + #[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 yyw(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.y, + z: self.w, + } + } + + #[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 yzw(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.z, + z: self.w, + } + } + + #[inline] + fn ywx(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.w, + z: self.x, + } + } + + #[inline] + fn ywy(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.w, + z: self.y, + } + } + + #[inline] + fn ywz(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.w, + z: self.z, + } + } + + #[inline] + fn yww(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.w, + z: self.w, + } + } + + #[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 zxw(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.x, + z: self.w, + } + } + + #[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 zyw(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.y, + z: self.w, + } + } + + #[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 zzw(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.z, + z: self.w, + } + } + + #[inline] + fn zwx(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.w, + z: self.x, + } + } + + #[inline] + fn zwy(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.w, + z: self.y, + } + } + + #[inline] + fn zwz(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.w, + z: self.z, + } + } + + #[inline] + fn zww(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.w, + z: self.w, + } + } + + #[inline] + fn wxx(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.x, + z: self.x, + } + } + + #[inline] + fn wxy(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.x, + z: self.y, + } + } + + #[inline] + fn wxz(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.x, + z: self.z, + } + } + + #[inline] + fn wxw(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.x, + z: self.w, + } + } + + #[inline] + fn wyx(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.y, + z: self.x, + } + } + + #[inline] + fn wyy(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.y, + z: self.y, + } + } + + #[inline] + fn wyz(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.y, + z: self.z, + } + } + + #[inline] + fn wyw(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.y, + z: self.w, + } + } + + #[inline] + fn wzx(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.z, + z: self.x, + } + } + + #[inline] + fn wzy(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.z, + z: self.y, + } + } + + #[inline] + fn wzz(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.z, + z: self.z, + } + } + + #[inline] + fn wzw(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.z, + z: self.w, + } + } + + #[inline] + fn wwx(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.w, + z: self.x, + } + } + + #[inline] + fn wwy(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.w, + z: self.y, + } + } + + #[inline] + fn wwz(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.w, + z: self.z, + } + } + + #[inline] + fn www(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.w, + z: self.w, + } + } + + #[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 xxxw(self) -> Vec4 { + Vec4::new(self.x, self.x, self.x, self.w) + } + + #[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 xxyw(self) -> Vec4 { + Vec4::new(self.x, self.x, self.y, self.w) + } + + #[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 xxzw(self) -> Vec4 { + Vec4::new(self.x, self.x, self.z, self.w) + } + + #[inline] + fn xxwx(self) -> Vec4 { + Vec4::new(self.x, self.x, self.w, self.x) + } + + #[inline] + fn xxwy(self) -> Vec4 { + Vec4::new(self.x, self.x, self.w, self.y) + } + + #[inline] + fn xxwz(self) -> Vec4 { + Vec4::new(self.x, self.x, self.w, self.z) + } + + #[inline] + fn xxww(self) -> Vec4 { + Vec4::new(self.x, self.x, self.w, self.w) + } + + #[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 xyxw(self) -> Vec4 { + Vec4::new(self.x, self.y, self.x, self.w) + } + + #[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 xyyw(self) -> Vec4 { + Vec4::new(self.x, self.y, self.y, self.w) + } + + #[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 xyzw(self) -> Vec4 { + Vec4::new(self.x, self.y, self.z, self.w) + } + + #[inline] + fn xywx(self) -> Vec4 { + Vec4::new(self.x, self.y, self.w, self.x) + } + + #[inline] + fn xywy(self) -> Vec4 { + Vec4::new(self.x, self.y, self.w, self.y) + } + + #[inline] + fn xywz(self) -> Vec4 { + Vec4::new(self.x, self.y, self.w, self.z) + } + + #[inline] + fn xyww(self) -> Vec4 { + Vec4::new(self.x, self.y, self.w, self.w) + } + + #[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 xzxw(self) -> Vec4 { + Vec4::new(self.x, self.z, self.x, self.w) + } + + #[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 xzyw(self) -> Vec4 { + Vec4::new(self.x, self.z, self.y, self.w) + } + + #[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 xzzw(self) -> Vec4 { + Vec4::new(self.x, self.z, self.z, self.w) + } + + #[inline] + fn xzwx(self) -> Vec4 { + Vec4::new(self.x, self.z, self.w, self.x) + } + + #[inline] + fn xzwy(self) -> Vec4 { + Vec4::new(self.x, self.z, self.w, self.y) + } + + #[inline] + fn xzwz(self) -> Vec4 { + Vec4::new(self.x, self.z, self.w, self.z) + } + + #[inline] + fn xzww(self) -> Vec4 { + Vec4::new(self.x, self.z, self.w, self.w) + } + + #[inline] + fn xwxx(self) -> Vec4 { + Vec4::new(self.x, self.w, self.x, self.x) + } + + #[inline] + fn xwxy(self) -> Vec4 { + Vec4::new(self.x, self.w, self.x, self.y) + } + + #[inline] + fn xwxz(self) -> Vec4 { + Vec4::new(self.x, self.w, self.x, self.z) + } + + #[inline] + fn xwxw(self) -> Vec4 { + Vec4::new(self.x, self.w, self.x, self.w) + } + + #[inline] + fn xwyx(self) -> Vec4 { + Vec4::new(self.x, self.w, self.y, self.x) + } + + #[inline] + fn xwyy(self) -> Vec4 { + Vec4::new(self.x, self.w, self.y, self.y) + } + + #[inline] + fn xwyz(self) -> Vec4 { + Vec4::new(self.x, self.w, self.y, self.z) + } + + #[inline] + fn xwyw(self) -> Vec4 { + Vec4::new(self.x, self.w, self.y, self.w) + } + + #[inline] + fn xwzx(self) -> Vec4 { + Vec4::new(self.x, self.w, self.z, self.x) + } + + #[inline] + fn xwzy(self) -> Vec4 { + Vec4::new(self.x, self.w, self.z, self.y) + } + + #[inline] + fn xwzz(self) -> Vec4 { + Vec4::new(self.x, self.w, self.z, self.z) + } + + #[inline] + fn xwzw(self) -> Vec4 { + Vec4::new(self.x, self.w, self.z, self.w) + } + + #[inline] + fn xwwx(self) -> Vec4 { + Vec4::new(self.x, self.w, self.w, self.x) + } + + #[inline] + fn xwwy(self) -> Vec4 { + Vec4::new(self.x, self.w, self.w, self.y) + } + + #[inline] + fn xwwz(self) -> Vec4 { + Vec4::new(self.x, self.w, self.w, self.z) + } + + #[inline] + fn xwww(self) -> Vec4 { + Vec4::new(self.x, self.w, self.w, self.w) + } + + #[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 yxxw(self) -> Vec4 { + Vec4::new(self.y, self.x, self.x, self.w) + } + + #[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 yxyw(self) -> Vec4 { + Vec4::new(self.y, self.x, self.y, self.w) + } + + #[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 yxzw(self) -> Vec4 { + Vec4::new(self.y, self.x, self.z, self.w) + } + + #[inline] + fn yxwx(self) -> Vec4 { + Vec4::new(self.y, self.x, self.w, self.x) + } + + #[inline] + fn yxwy(self) -> Vec4 { + Vec4::new(self.y, self.x, self.w, self.y) + } + + #[inline] + fn yxwz(self) -> Vec4 { + Vec4::new(self.y, self.x, self.w, self.z) + } + + #[inline] + fn yxww(self) -> Vec4 { + Vec4::new(self.y, self.x, self.w, self.w) + } + + #[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 yyxw(self) -> Vec4 { + Vec4::new(self.y, self.y, self.x, self.w) + } + + #[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 yyyw(self) -> Vec4 { + Vec4::new(self.y, self.y, self.y, self.w) + } + + #[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 yyzw(self) -> Vec4 { + Vec4::new(self.y, self.y, self.z, self.w) + } + + #[inline] + fn yywx(self) -> Vec4 { + Vec4::new(self.y, self.y, self.w, self.x) + } + + #[inline] + fn yywy(self) -> Vec4 { + Vec4::new(self.y, self.y, self.w, self.y) + } + + #[inline] + fn yywz(self) -> Vec4 { + Vec4::new(self.y, self.y, self.w, self.z) + } + + #[inline] + fn yyww(self) -> Vec4 { + Vec4::new(self.y, self.y, self.w, self.w) + } + + #[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 yzxw(self) -> Vec4 { + Vec4::new(self.y, self.z, self.x, self.w) + } + + #[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 yzyw(self) -> Vec4 { + Vec4::new(self.y, self.z, self.y, self.w) + } + + #[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 yzzw(self) -> Vec4 { + Vec4::new(self.y, self.z, self.z, self.w) + } + + #[inline] + fn yzwx(self) -> Vec4 { + Vec4::new(self.y, self.z, self.w, self.x) + } + + #[inline] + fn yzwy(self) -> Vec4 { + Vec4::new(self.y, self.z, self.w, self.y) + } + + #[inline] + fn yzwz(self) -> Vec4 { + Vec4::new(self.y, self.z, self.w, self.z) + } + + #[inline] + fn yzww(self) -> Vec4 { + Vec4::new(self.y, self.z, self.w, self.w) + } + + #[inline] + fn ywxx(self) -> Vec4 { + Vec4::new(self.y, self.w, self.x, self.x) + } + + #[inline] + fn ywxy(self) -> Vec4 { + Vec4::new(self.y, self.w, self.x, self.y) + } + + #[inline] + fn ywxz(self) -> Vec4 { + Vec4::new(self.y, self.w, self.x, self.z) + } + + #[inline] + fn ywxw(self) -> Vec4 { + Vec4::new(self.y, self.w, self.x, self.w) + } + + #[inline] + fn ywyx(self) -> Vec4 { + Vec4::new(self.y, self.w, self.y, self.x) + } + + #[inline] + fn ywyy(self) -> Vec4 { + Vec4::new(self.y, self.w, self.y, self.y) + } + + #[inline] + fn ywyz(self) -> Vec4 { + Vec4::new(self.y, self.w, self.y, self.z) + } + + #[inline] + fn ywyw(self) -> Vec4 { + Vec4::new(self.y, self.w, self.y, self.w) + } + + #[inline] + fn ywzx(self) -> Vec4 { + Vec4::new(self.y, self.w, self.z, self.x) + } + + #[inline] + fn ywzy(self) -> Vec4 { + Vec4::new(self.y, self.w, self.z, self.y) + } + + #[inline] + fn ywzz(self) -> Vec4 { + Vec4::new(self.y, self.w, self.z, self.z) + } + + #[inline] + fn ywzw(self) -> Vec4 { + Vec4::new(self.y, self.w, self.z, self.w) + } + + #[inline] + fn ywwx(self) -> Vec4 { + Vec4::new(self.y, self.w, self.w, self.x) + } + + #[inline] + fn ywwy(self) -> Vec4 { + Vec4::new(self.y, self.w, self.w, self.y) + } + + #[inline] + fn ywwz(self) -> Vec4 { + Vec4::new(self.y, self.w, self.w, self.z) + } + + #[inline] + fn ywww(self) -> Vec4 { + Vec4::new(self.y, self.w, self.w, self.w) + } + + #[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 zxxw(self) -> Vec4 { + Vec4::new(self.z, self.x, self.x, self.w) + } + + #[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 zxyw(self) -> Vec4 { + Vec4::new(self.z, self.x, self.y, self.w) + } + + #[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 zxzw(self) -> Vec4 { + Vec4::new(self.z, self.x, self.z, self.w) + } + + #[inline] + fn zxwx(self) -> Vec4 { + Vec4::new(self.z, self.x, self.w, self.x) + } + + #[inline] + fn zxwy(self) -> Vec4 { + Vec4::new(self.z, self.x, self.w, self.y) + } + + #[inline] + fn zxwz(self) -> Vec4 { + Vec4::new(self.z, self.x, self.w, self.z) + } + + #[inline] + fn zxww(self) -> Vec4 { + Vec4::new(self.z, self.x, self.w, self.w) + } + + #[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 zyxw(self) -> Vec4 { + Vec4::new(self.z, self.y, self.x, self.w) + } + + #[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 zyyw(self) -> Vec4 { + Vec4::new(self.z, self.y, self.y, self.w) + } + + #[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 zyzw(self) -> Vec4 { + Vec4::new(self.z, self.y, self.z, self.w) + } + + #[inline] + fn zywx(self) -> Vec4 { + Vec4::new(self.z, self.y, self.w, self.x) + } + + #[inline] + fn zywy(self) -> Vec4 { + Vec4::new(self.z, self.y, self.w, self.y) + } + + #[inline] + fn zywz(self) -> Vec4 { + Vec4::new(self.z, self.y, self.w, self.z) + } + + #[inline] + fn zyww(self) -> Vec4 { + Vec4::new(self.z, self.y, self.w, self.w) + } + + #[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 zzxw(self) -> Vec4 { + Vec4::new(self.z, self.z, self.x, self.w) + } + + #[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 zzyw(self) -> Vec4 { + Vec4::new(self.z, self.z, self.y, self.w) + } + + #[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 zzzw(self) -> Vec4 { + Vec4::new(self.z, self.z, self.z, self.w) + } + + #[inline] + fn zzwx(self) -> Vec4 { + Vec4::new(self.z, self.z, self.w, self.x) + } + + #[inline] + fn zzwy(self) -> Vec4 { + Vec4::new(self.z, self.z, self.w, self.y) + } + + #[inline] + fn zzwz(self) -> Vec4 { + Vec4::new(self.z, self.z, self.w, self.z) + } + + #[inline] + fn zzww(self) -> Vec4 { + Vec4::new(self.z, self.z, self.w, self.w) + } + + #[inline] + fn zwxx(self) -> Vec4 { + Vec4::new(self.z, self.w, self.x, self.x) + } + + #[inline] + fn zwxy(self) -> Vec4 { + Vec4::new(self.z, self.w, self.x, self.y) + } + + #[inline] + fn zwxz(self) -> Vec4 { + Vec4::new(self.z, self.w, self.x, self.z) + } + + #[inline] + fn zwxw(self) -> Vec4 { + Vec4::new(self.z, self.w, self.x, self.w) + } + + #[inline] + fn zwyx(self) -> Vec4 { + Vec4::new(self.z, self.w, self.y, self.x) + } + + #[inline] + fn zwyy(self) -> Vec4 { + Vec4::new(self.z, self.w, self.y, self.y) + } + + #[inline] + fn zwyz(self) -> Vec4 { + Vec4::new(self.z, self.w, self.y, self.z) + } + + #[inline] + fn zwyw(self) -> Vec4 { + Vec4::new(self.z, self.w, self.y, self.w) + } + + #[inline] + fn zwzx(self) -> Vec4 { + Vec4::new(self.z, self.w, self.z, self.x) + } + + #[inline] + fn zwzy(self) -> Vec4 { + Vec4::new(self.z, self.w, self.z, self.y) + } + + #[inline] + fn zwzz(self) -> Vec4 { + Vec4::new(self.z, self.w, self.z, self.z) + } + + #[inline] + fn zwzw(self) -> Vec4 { + Vec4::new(self.z, self.w, self.z, self.w) + } + + #[inline] + fn zwwx(self) -> Vec4 { + Vec4::new(self.z, self.w, self.w, self.x) + } + + #[inline] + fn zwwy(self) -> Vec4 { + Vec4::new(self.z, self.w, self.w, self.y) + } + + #[inline] + fn zwwz(self) -> Vec4 { + Vec4::new(self.z, self.w, self.w, self.z) + } + + #[inline] + fn zwww(self) -> Vec4 { + Vec4::new(self.z, self.w, self.w, self.w) + } + + #[inline] + fn wxxx(self) -> Vec4 { + Vec4::new(self.w, self.x, self.x, self.x) + } + + #[inline] + fn wxxy(self) -> Vec4 { + Vec4::new(self.w, self.x, self.x, self.y) + } + + #[inline] + fn wxxz(self) -> Vec4 { + Vec4::new(self.w, self.x, self.x, self.z) + } + + #[inline] + fn wxxw(self) -> Vec4 { + Vec4::new(self.w, self.x, self.x, self.w) + } + + #[inline] + fn wxyx(self) -> Vec4 { + Vec4::new(self.w, self.x, self.y, self.x) + } + + #[inline] + fn wxyy(self) -> Vec4 { + Vec4::new(self.w, self.x, self.y, self.y) + } + + #[inline] + fn wxyz(self) -> Vec4 { + Vec4::new(self.w, self.x, self.y, self.z) + } + + #[inline] + fn wxyw(self) -> Vec4 { + Vec4::new(self.w, self.x, self.y, self.w) + } + + #[inline] + fn wxzx(self) -> Vec4 { + Vec4::new(self.w, self.x, self.z, self.x) + } + + #[inline] + fn wxzy(self) -> Vec4 { + Vec4::new(self.w, self.x, self.z, self.y) + } + + #[inline] + fn wxzz(self) -> Vec4 { + Vec4::new(self.w, self.x, self.z, self.z) + } + + #[inline] + fn wxzw(self) -> Vec4 { + Vec4::new(self.w, self.x, self.z, self.w) + } + + #[inline] + fn wxwx(self) -> Vec4 { + Vec4::new(self.w, self.x, self.w, self.x) + } + + #[inline] + fn wxwy(self) -> Vec4 { + Vec4::new(self.w, self.x, self.w, self.y) + } + + #[inline] + fn wxwz(self) -> Vec4 { + Vec4::new(self.w, self.x, self.w, self.z) + } + + #[inline] + fn wxww(self) -> Vec4 { + Vec4::new(self.w, self.x, self.w, self.w) + } + + #[inline] + fn wyxx(self) -> Vec4 { + Vec4::new(self.w, self.y, self.x, self.x) + } + + #[inline] + fn wyxy(self) -> Vec4 { + Vec4::new(self.w, self.y, self.x, self.y) + } + + #[inline] + fn wyxz(self) -> Vec4 { + Vec4::new(self.w, self.y, self.x, self.z) + } + + #[inline] + fn wyxw(self) -> Vec4 { + Vec4::new(self.w, self.y, self.x, self.w) + } + + #[inline] + fn wyyx(self) -> Vec4 { + Vec4::new(self.w, self.y, self.y, self.x) + } + + #[inline] + fn wyyy(self) -> Vec4 { + Vec4::new(self.w, self.y, self.y, self.y) + } + + #[inline] + fn wyyz(self) -> Vec4 { + Vec4::new(self.w, self.y, self.y, self.z) + } + + #[inline] + fn wyyw(self) -> Vec4 { + Vec4::new(self.w, self.y, self.y, self.w) + } + + #[inline] + fn wyzx(self) -> Vec4 { + Vec4::new(self.w, self.y, self.z, self.x) + } + + #[inline] + fn wyzy(self) -> Vec4 { + Vec4::new(self.w, self.y, self.z, self.y) + } + + #[inline] + fn wyzz(self) -> Vec4 { + Vec4::new(self.w, self.y, self.z, self.z) + } + + #[inline] + fn wyzw(self) -> Vec4 { + Vec4::new(self.w, self.y, self.z, self.w) + } + + #[inline] + fn wywx(self) -> Vec4 { + Vec4::new(self.w, self.y, self.w, self.x) + } + + #[inline] + fn wywy(self) -> Vec4 { + Vec4::new(self.w, self.y, self.w, self.y) + } + + #[inline] + fn wywz(self) -> Vec4 { + Vec4::new(self.w, self.y, self.w, self.z) + } + + #[inline] + fn wyww(self) -> Vec4 { + Vec4::new(self.w, self.y, self.w, self.w) + } + + #[inline] + fn wzxx(self) -> Vec4 { + Vec4::new(self.w, self.z, self.x, self.x) + } + + #[inline] + fn wzxy(self) -> Vec4 { + Vec4::new(self.w, self.z, self.x, self.y) + } + + #[inline] + fn wzxz(self) -> Vec4 { + Vec4::new(self.w, self.z, self.x, self.z) + } + + #[inline] + fn wzxw(self) -> Vec4 { + Vec4::new(self.w, self.z, self.x, self.w) + } + + #[inline] + fn wzyx(self) -> Vec4 { + Vec4::new(self.w, self.z, self.y, self.x) + } + + #[inline] + fn wzyy(self) -> Vec4 { + Vec4::new(self.w, self.z, self.y, self.y) + } + + #[inline] + fn wzyz(self) -> Vec4 { + Vec4::new(self.w, self.z, self.y, self.z) + } + + #[inline] + fn wzyw(self) -> Vec4 { + Vec4::new(self.w, self.z, self.y, self.w) + } + + #[inline] + fn wzzx(self) -> Vec4 { + Vec4::new(self.w, self.z, self.z, self.x) + } + + #[inline] + fn wzzy(self) -> Vec4 { + Vec4::new(self.w, self.z, self.z, self.y) + } + + #[inline] + fn wzzz(self) -> Vec4 { + Vec4::new(self.w, self.z, self.z, self.z) + } + + #[inline] + fn wzzw(self) -> Vec4 { + Vec4::new(self.w, self.z, self.z, self.w) + } + + #[inline] + fn wzwx(self) -> Vec4 { + Vec4::new(self.w, self.z, self.w, self.x) + } + + #[inline] + fn wzwy(self) -> Vec4 { + Vec4::new(self.w, self.z, self.w, self.y) + } + + #[inline] + fn wzwz(self) -> Vec4 { + Vec4::new(self.w, self.z, self.w, self.z) + } + + #[inline] + fn wzww(self) -> Vec4 { + Vec4::new(self.w, self.z, self.w, self.w) + } + + #[inline] + fn wwxx(self) -> Vec4 { + Vec4::new(self.w, self.w, self.x, self.x) + } + + #[inline] + fn wwxy(self) -> Vec4 { + Vec4::new(self.w, self.w, self.x, self.y) + } + + #[inline] + fn wwxz(self) -> Vec4 { + Vec4::new(self.w, self.w, self.x, self.z) + } + + #[inline] + fn wwxw(self) -> Vec4 { + Vec4::new(self.w, self.w, self.x, self.w) + } + + #[inline] + fn wwyx(self) -> Vec4 { + Vec4::new(self.w, self.w, self.y, self.x) + } + + #[inline] + fn wwyy(self) -> Vec4 { + Vec4::new(self.w, self.w, self.y, self.y) + } + + #[inline] + fn wwyz(self) -> Vec4 { + Vec4::new(self.w, self.w, self.y, self.z) + } + + #[inline] + fn wwyw(self) -> Vec4 { + Vec4::new(self.w, self.w, self.y, self.w) + } + + #[inline] + fn wwzx(self) -> Vec4 { + Vec4::new(self.w, self.w, self.z, self.x) + } + + #[inline] + fn wwzy(self) -> Vec4 { + Vec4::new(self.w, self.w, self.z, self.y) + } + + #[inline] + fn wwzz(self) -> Vec4 { + Vec4::new(self.w, self.w, self.z, self.z) + } + + #[inline] + fn wwzw(self) -> Vec4 { + Vec4::new(self.w, self.w, self.z, self.w) + } + + #[inline] + fn wwwx(self) -> Vec4 { + Vec4::new(self.w, self.w, self.w, self.x) + } + + #[inline] + fn wwwy(self) -> Vec4 { + Vec4::new(self.w, self.w, self.w, self.y) + } + + #[inline] + fn wwwz(self) -> Vec4 { + Vec4::new(self.w, self.w, self.w, self.z) + } + + #[inline] + fn wwww(self) -> Vec4 { + Vec4::new(self.w, self.w, self.w, self.w) + } +} diff --git a/src/swizzles/sse2.rs b/src/swizzles/sse2.rs new file mode 100644 index 0000000..10479c8 --- /dev/null +++ b/src/swizzles/sse2.rs @@ -0,0 +1,2 @@ +mod vec3a_impl; +mod vec4_impl; diff --git a/src/swizzles/sse2/vec3a_impl.rs b/src/swizzles/sse2/vec3a_impl.rs new file mode 100644 index 0000000..da70b6f --- /dev/null +++ b/src/swizzles/sse2/vec3a_impl.rs @@ -0,0 +1,628 @@ +// Generated from swizzle_impl.rs.tera template. Edit the template, not the generated file. + +#![allow(clippy::useless_conversion)] + +use crate::{Vec2, Vec3A, Vec3Swizzles, Vec4}; + +#[cfg(target_arch = "x86")] +use core::arch::x86::*; +#[cfg(target_arch = "x86_64")] +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 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_00_00) }) + } + + #[inline] + fn xxxy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_00_00_00) }) + } + + #[inline] + fn xxxz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_00_00_00) }) + } + + #[inline] + fn xxyx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_00_00) }) + } + + #[inline] + fn xxyy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_01_00_00) }) + } + + #[inline] + fn xxyz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_01_00_00) }) + } + + #[inline] + fn xxzx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_00_00) }) + } + + #[inline] + fn xxzy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_10_00_00) }) + } + + #[inline] + fn xxzz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_10_00_00) }) + } + + #[inline] + fn xyxx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_01_00) }) + } + + #[inline] + fn xyxy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_00_01_00) }) + } + + #[inline] + fn xyxz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_00_01_00) }) + } + + #[inline] + fn xyyx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_01_00) }) + } + + #[inline] + fn xyyy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_01_01_00) }) + } + + #[inline] + fn xyyz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_01_01_00) }) + } + + #[inline] + fn xyzx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_01_00) }) + } + + #[inline] + fn xyzy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_10_01_00) }) + } + + #[inline] + fn xyzz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_10_01_00) }) + } + + #[inline] + fn xzxx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_10_00) }) + } + + #[inline] + fn xzxy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_00_10_00) }) + } + + #[inline] + fn xzxz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_00_10_00) }) + } + + #[inline] + fn xzyx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_10_00) }) + } + + #[inline] + fn xzyy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_01_10_00) }) + } + + #[inline] + fn xzyz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_01_10_00) }) + } + + #[inline] + fn xzzx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_10_00) }) + } + + #[inline] + fn xzzy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_10_10_00) }) + } + + #[inline] + fn xzzz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_10_10_00) }) + } + + #[inline] + fn yxxx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_00_01) }) + } + + #[inline] + fn yxxy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_00_00_01) }) + } + + #[inline] + fn yxxz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_00_00_01) }) + } + + #[inline] + fn yxyx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_00_01) }) + } + + #[inline] + fn yxyy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_01_00_01) }) + } + + #[inline] + fn yxyz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_01_00_01) }) + } + + #[inline] + fn yxzx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_00_01) }) + } + + #[inline] + fn yxzy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_10_00_01) }) + } + + #[inline] + fn yxzz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_10_00_01) }) + } + + #[inline] + fn yyxx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_01_01) }) + } + + #[inline] + fn yyxy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_00_01_01) }) + } + + #[inline] + fn yyxz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_00_01_01) }) + } + + #[inline] + fn yyyx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_01_01) }) + } + + #[inline] + fn yyyy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_01_01_01) }) + } + + #[inline] + fn yyyz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_01_01_01) }) + } + + #[inline] + fn yyzx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_01_01) }) + } + + #[inline] + fn yyzy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_10_01_01) }) + } + + #[inline] + fn yyzz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_10_01_01) }) + } + + #[inline] + fn yzxx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_10_01) }) + } + + #[inline] + fn yzxy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_00_10_01) }) + } + + #[inline] + fn yzxz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_00_10_01) }) + } + + #[inline] + fn yzyx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_10_01) }) + } + + #[inline] + fn yzyy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_01_10_01) }) + } + + #[inline] + fn yzyz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_01_10_01) }) + } + + #[inline] + fn yzzx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_10_01) }) + } + + #[inline] + fn yzzy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_10_10_01) }) + } + + #[inline] + fn yzzz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_10_10_01) }) + } + + #[inline] + fn zxxx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_00_10) }) + } + + #[inline] + fn zxxy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_00_00_10) }) + } + + #[inline] + fn zxxz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_00_00_10) }) + } + + #[inline] + fn zxyx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_00_10) }) + } + + #[inline] + fn zxyy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_01_00_10) }) + } + + #[inline] + fn zxyz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_01_00_10) }) + } + + #[inline] + fn zxzx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_00_10) }) + } + + #[inline] + fn zxzy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_10_00_10) }) + } + + #[inline] + fn zxzz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_10_00_10) }) + } + + #[inline] + fn zyxx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_01_10) }) + } + + #[inline] + fn zyxy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_00_01_10) }) + } + + #[inline] + fn zyxz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_00_01_10) }) + } + + #[inline] + fn zyyx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_01_10) }) + } + + #[inline] + fn zyyy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_01_01_10) }) + } + + #[inline] + fn zyyz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_01_01_10) }) + } + + #[inline] + fn zyzx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_01_10) }) + } + + #[inline] + fn zyzy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_10_01_10) }) + } + + #[inline] + fn zyzz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_10_01_10) }) + } + + #[inline] + fn zzxx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_10_10) }) + } + + #[inline] + fn zzxy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_00_10_10) }) + } + + #[inline] + fn zzxz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_00_10_10) }) + } + + #[inline] + fn zzyx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_10_10) }) + } + + #[inline] + fn zzyy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_01_10_10) }) + } + + #[inline] + fn zzyz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_01_10_10) }) + } + + #[inline] + fn zzzx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_10_10) }) + } + + #[inline] + fn zzzy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_10_10_10) }) + } + + #[inline] + fn zzzz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_10_10_10) }) + } +} diff --git a/src/swizzles/sse2/vec4_impl.rs b/src/swizzles/sse2/vec4_impl.rs new file mode 100644 index 0000000..9ca3a3d --- /dev/null +++ b/src/swizzles/sse2/vec4_impl.rs @@ -0,0 +1,2000 @@ +// Generated from swizzle_impl.rs.tera template. Edit the template, not the generated file. + +#![allow(clippy::useless_conversion)] + +use crate::{Vec2, Vec3, Vec4, Vec4Swizzles}; + +#[cfg(target_arch = "x86")] +use core::arch::x86::*; +#[cfg(target_arch = "x86_64")] +use core::arch::x86_64::*; + +impl Vec4Swizzles for Vec4 { + type Vec2 = Vec2; + + type Vec3 = Vec3; + + #[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 xw(self) -> Vec2 { + Vec2 { + x: self.x, + y: self.w, + } + } + + #[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 yw(self) -> Vec2 { + Vec2 { + x: self.y, + y: self.w, + } + } + + #[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 zw(self) -> Vec2 { + Vec2 { + x: self.z, + y: self.w, + } + } + + #[inline] + fn wx(self) -> Vec2 { + Vec2 { + x: self.w, + y: self.x, + } + } + + #[inline] + fn wy(self) -> Vec2 { + Vec2 { + x: self.w, + y: self.y, + } + } + + #[inline] + fn wz(self) -> Vec2 { + Vec2 { + x: self.w, + y: self.z, + } + } + + #[inline] + fn ww(self) -> Vec2 { + Vec2 { + x: self.w, + y: self.w, + } + } + + #[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 xxw(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.x, + z: self.w, + } + } + + #[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 xyw(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.y, + z: self.w, + } + } + + #[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 xzw(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.z, + z: self.w, + } + } + + #[inline] + fn xwx(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.w, + z: self.x, + } + } + + #[inline] + fn xwy(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.w, + z: self.y, + } + } + + #[inline] + fn xwz(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.w, + z: self.z, + } + } + + #[inline] + fn xww(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.w, + z: self.w, + } + } + + #[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 yxw(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.x, + z: self.w, + } + } + + #[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 yyw(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.y, + z: self.w, + } + } + + #[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 yzw(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.z, + z: self.w, + } + } + + #[inline] + fn ywx(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.w, + z: self.x, + } + } + + #[inline] + fn ywy(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.w, + z: self.y, + } + } + + #[inline] + fn ywz(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.w, + z: self.z, + } + } + + #[inline] + fn yww(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.w, + z: self.w, + } + } + + #[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 zxw(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.x, + z: self.w, + } + } + + #[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 zyw(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.y, + z: self.w, + } + } + + #[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 zzw(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.z, + z: self.w, + } + } + + #[inline] + fn zwx(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.w, + z: self.x, + } + } + + #[inline] + fn zwy(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.w, + z: self.y, + } + } + + #[inline] + fn zwz(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.w, + z: self.z, + } + } + + #[inline] + fn zww(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.w, + z: self.w, + } + } + + #[inline] + fn wxx(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.x, + z: self.x, + } + } + + #[inline] + fn wxy(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.x, + z: self.y, + } + } + + #[inline] + fn wxz(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.x, + z: self.z, + } + } + + #[inline] + fn wxw(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.x, + z: self.w, + } + } + + #[inline] + fn wyx(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.y, + z: self.x, + } + } + + #[inline] + fn wyy(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.y, + z: self.y, + } + } + + #[inline] + fn wyz(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.y, + z: self.z, + } + } + + #[inline] + fn wyw(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.y, + z: self.w, + } + } + + #[inline] + fn wzx(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.z, + z: self.x, + } + } + + #[inline] + fn wzy(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.z, + z: self.y, + } + } + + #[inline] + fn wzz(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.z, + z: self.z, + } + } + + #[inline] + fn wzw(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.z, + z: self.w, + } + } + + #[inline] + fn wwx(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.w, + z: self.x, + } + } + + #[inline] + fn wwy(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.w, + z: self.y, + } + } + + #[inline] + fn wwz(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.w, + z: self.z, + } + } + + #[inline] + fn www(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.w, + z: self.w, + } + } + + #[inline] + fn xxxx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_00_00) }) + } + + #[inline] + fn xxxy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_00_00_00) }) + } + + #[inline] + fn xxxz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_00_00_00) }) + } + + #[inline] + fn xxxw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_00_00_00) }) + } + + #[inline] + fn xxyx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_00_00) }) + } + + #[inline] + fn xxyy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_01_00_00) }) + } + + #[inline] + fn xxyz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_01_00_00) }) + } + + #[inline] + fn xxyw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_01_00_00) }) + } + + #[inline] + fn xxzx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_00_00) }) + } + + #[inline] + fn xxzy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_10_00_00) }) + } + + #[inline] + fn xxzz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_10_00_00) }) + } + + #[inline] + fn xxzw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_10_00_00) }) + } + + #[inline] + fn xxwx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_11_00_00) }) + } + + #[inline] + fn xxwy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_11_00_00) }) + } + + #[inline] + fn xxwz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_11_00_00) }) + } + + #[inline] + fn xxww(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_11_00_00) }) + } + + #[inline] + fn xyxx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_01_00) }) + } + + #[inline] + fn xyxy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_00_01_00) }) + } + + #[inline] + fn xyxz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_00_01_00) }) + } + + #[inline] + fn xyxw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_00_01_00) }) + } + + #[inline] + fn xyyx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_01_00) }) + } + + #[inline] + fn xyyy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_01_01_00) }) + } + + #[inline] + fn xyyz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_01_01_00) }) + } + + #[inline] + fn xyyw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_01_01_00) }) + } + + #[inline] + fn xyzx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_01_00) }) + } + + #[inline] + fn xyzy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_10_01_00) }) + } + + #[inline] + fn xyzz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_10_01_00) }) + } + + #[inline] + fn xyzw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_10_01_00) }) + } + + #[inline] + fn xywx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_11_01_00) }) + } + + #[inline] + fn xywy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_11_01_00) }) + } + + #[inline] + fn xywz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_11_01_00) }) + } + + #[inline] + fn xyww(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_11_01_00) }) + } + + #[inline] + fn xzxx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_10_00) }) + } + + #[inline] + fn xzxy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_00_10_00) }) + } + + #[inline] + fn xzxz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_00_10_00) }) + } + + #[inline] + fn xzxw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_00_10_00) }) + } + + #[inline] + fn xzyx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_10_00) }) + } + + #[inline] + fn xzyy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_01_10_00) }) + } + + #[inline] + fn xzyz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_01_10_00) }) + } + + #[inline] + fn xzyw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_01_10_00) }) + } + + #[inline] + fn xzzx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_10_00) }) + } + + #[inline] + fn xzzy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_10_10_00) }) + } + + #[inline] + fn xzzz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_10_10_00) }) + } + + #[inline] + fn xzzw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_10_10_00) }) + } + + #[inline] + fn xzwx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_11_10_00) }) + } + + #[inline] + fn xzwy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_11_10_00) }) + } + + #[inline] + fn xzwz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_11_10_00) }) + } + + #[inline] + fn xzww(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_11_10_00) }) + } + + #[inline] + fn xwxx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_11_00) }) + } + + #[inline] + fn xwxy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_00_11_00) }) + } + + #[inline] + fn xwxz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_00_11_00) }) + } + + #[inline] + fn xwxw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_00_11_00) }) + } + + #[inline] + fn xwyx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_11_00) }) + } + + #[inline] + fn xwyy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_01_11_00) }) + } + + #[inline] + fn xwyz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_01_11_00) }) + } + + #[inline] + fn xwyw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_01_11_00) }) + } + + #[inline] + fn xwzx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_11_00) }) + } + + #[inline] + fn xwzy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_10_11_00) }) + } + + #[inline] + fn xwzz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_10_11_00) }) + } + + #[inline] + fn xwzw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_10_11_00) }) + } + + #[inline] + fn xwwx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_11_11_00) }) + } + + #[inline] + fn xwwy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_11_11_00) }) + } + + #[inline] + fn xwwz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_11_11_00) }) + } + + #[inline] + fn xwww(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_11_11_00) }) + } + + #[inline] + fn yxxx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_00_01) }) + } + + #[inline] + fn yxxy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_00_00_01) }) + } + + #[inline] + fn yxxz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_00_00_01) }) + } + + #[inline] + fn yxxw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_00_00_01) }) + } + + #[inline] + fn yxyx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_00_01) }) + } + + #[inline] + fn yxyy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_01_00_01) }) + } + + #[inline] + fn yxyz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_01_00_01) }) + } + + #[inline] + fn yxyw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_01_00_01) }) + } + + #[inline] + fn yxzx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_00_01) }) + } + + #[inline] + fn yxzy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_10_00_01) }) + } + + #[inline] + fn yxzz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_10_00_01) }) + } + + #[inline] + fn yxzw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_10_00_01) }) + } + + #[inline] + fn yxwx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_11_00_01) }) + } + + #[inline] + fn yxwy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_11_00_01) }) + } + + #[inline] + fn yxwz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_11_00_01) }) + } + + #[inline] + fn yxww(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_11_00_01) }) + } + + #[inline] + fn yyxx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_01_01) }) + } + + #[inline] + fn yyxy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_00_01_01) }) + } + + #[inline] + fn yyxz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_00_01_01) }) + } + + #[inline] + fn yyxw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_00_01_01) }) + } + + #[inline] + fn yyyx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_01_01) }) + } + + #[inline] + fn yyyy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_01_01_01) }) + } + + #[inline] + fn yyyz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_01_01_01) }) + } + + #[inline] + fn yyyw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_01_01_01) }) + } + + #[inline] + fn yyzx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_01_01) }) + } + + #[inline] + fn yyzy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_10_01_01) }) + } + + #[inline] + fn yyzz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_10_01_01) }) + } + + #[inline] + fn yyzw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_10_01_01) }) + } + + #[inline] + fn yywx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_11_01_01) }) + } + + #[inline] + fn yywy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_11_01_01) }) + } + + #[inline] + fn yywz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_11_01_01) }) + } + + #[inline] + fn yyww(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_11_01_01) }) + } + + #[inline] + fn yzxx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_10_01) }) + } + + #[inline] + fn yzxy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_00_10_01) }) + } + + #[inline] + fn yzxz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_00_10_01) }) + } + + #[inline] + fn yzxw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_00_10_01) }) + } + + #[inline] + fn yzyx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_10_01) }) + } + + #[inline] + fn yzyy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_01_10_01) }) + } + + #[inline] + fn yzyz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_01_10_01) }) + } + + #[inline] + fn yzyw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_01_10_01) }) + } + + #[inline] + fn yzzx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_10_01) }) + } + + #[inline] + fn yzzy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_10_10_01) }) + } + + #[inline] + fn yzzz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_10_10_01) }) + } + + #[inline] + fn yzzw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_10_10_01) }) + } + + #[inline] + fn yzwx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_11_10_01) }) + } + + #[inline] + fn yzwy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_11_10_01) }) + } + + #[inline] + fn yzwz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_11_10_01) }) + } + + #[inline] + fn yzww(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_11_10_01) }) + } + + #[inline] + fn ywxx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_11_01) }) + } + + #[inline] + fn ywxy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_00_11_01) }) + } + + #[inline] + fn ywxz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_00_11_01) }) + } + + #[inline] + fn ywxw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_00_11_01) }) + } + + #[inline] + fn ywyx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_11_01) }) + } + + #[inline] + fn ywyy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_01_11_01) }) + } + + #[inline] + fn ywyz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_01_11_01) }) + } + + #[inline] + fn ywyw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_01_11_01) }) + } + + #[inline] + fn ywzx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_11_01) }) + } + + #[inline] + fn ywzy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_10_11_01) }) + } + + #[inline] + fn ywzz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_10_11_01) }) + } + + #[inline] + fn ywzw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_10_11_01) }) + } + + #[inline] + fn ywwx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_11_11_01) }) + } + + #[inline] + fn ywwy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_11_11_01) }) + } + + #[inline] + fn ywwz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_11_11_01) }) + } + + #[inline] + fn ywww(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_11_11_01) }) + } + + #[inline] + fn zxxx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_00_10) }) + } + + #[inline] + fn zxxy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_00_00_10) }) + } + + #[inline] + fn zxxz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_00_00_10) }) + } + + #[inline] + fn zxxw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_00_00_10) }) + } + + #[inline] + fn zxyx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_00_10) }) + } + + #[inline] + fn zxyy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_01_00_10) }) + } + + #[inline] + fn zxyz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_01_00_10) }) + } + + #[inline] + fn zxyw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_01_00_10) }) + } + + #[inline] + fn zxzx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_00_10) }) + } + + #[inline] + fn zxzy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_10_00_10) }) + } + + #[inline] + fn zxzz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_10_00_10) }) + } + + #[inline] + fn zxzw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_10_00_10) }) + } + + #[inline] + fn zxwx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_11_00_10) }) + } + + #[inline] + fn zxwy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_11_00_10) }) + } + + #[inline] + fn zxwz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_11_00_10) }) + } + + #[inline] + fn zxww(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_11_00_10) }) + } + + #[inline] + fn zyxx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_01_10) }) + } + + #[inline] + fn zyxy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_00_01_10) }) + } + + #[inline] + fn zyxz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_00_01_10) }) + } + + #[inline] + fn zyxw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_00_01_10) }) + } + + #[inline] + fn zyyx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_01_10) }) + } + + #[inline] + fn zyyy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_01_01_10) }) + } + + #[inline] + fn zyyz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_01_01_10) }) + } + + #[inline] + fn zyyw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_01_01_10) }) + } + + #[inline] + fn zyzx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_01_10) }) + } + + #[inline] + fn zyzy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_10_01_10) }) + } + + #[inline] + fn zyzz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_10_01_10) }) + } + + #[inline] + fn zyzw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_10_01_10) }) + } + + #[inline] + fn zywx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_11_01_10) }) + } + + #[inline] + fn zywy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_11_01_10) }) + } + + #[inline] + fn zywz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_11_01_10) }) + } + + #[inline] + fn zyww(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_11_01_10) }) + } + + #[inline] + fn zzxx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_10_10) }) + } + + #[inline] + fn zzxy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_00_10_10) }) + } + + #[inline] + fn zzxz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_00_10_10) }) + } + + #[inline] + fn zzxw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_00_10_10) }) + } + + #[inline] + fn zzyx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_10_10) }) + } + + #[inline] + fn zzyy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_01_10_10) }) + } + + #[inline] + fn zzyz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_01_10_10) }) + } + + #[inline] + fn zzyw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_01_10_10) }) + } + + #[inline] + fn zzzx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_10_10) }) + } + + #[inline] + fn zzzy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_10_10_10) }) + } + + #[inline] + fn zzzz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_10_10_10) }) + } + + #[inline] + fn zzzw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_10_10_10) }) + } + + #[inline] + fn zzwx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_11_10_10) }) + } + + #[inline] + fn zzwy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_11_10_10) }) + } + + #[inline] + fn zzwz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_11_10_10) }) + } + + #[inline] + fn zzww(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_11_10_10) }) + } + + #[inline] + fn zwxx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_11_10) }) + } + + #[inline] + fn zwxy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_00_11_10) }) + } + + #[inline] + fn zwxz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_00_11_10) }) + } + + #[inline] + fn zwxw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_00_11_10) }) + } + + #[inline] + fn zwyx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_11_10) }) + } + + #[inline] + fn zwyy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_01_11_10) }) + } + + #[inline] + fn zwyz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_01_11_10) }) + } + + #[inline] + fn zwyw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_01_11_10) }) + } + + #[inline] + fn zwzx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_11_10) }) + } + + #[inline] + fn zwzy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_10_11_10) }) + } + + #[inline] + fn zwzz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_10_11_10) }) + } + + #[inline] + fn zwzw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_10_11_10) }) + } + + #[inline] + fn zwwx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_11_11_10) }) + } + + #[inline] + fn zwwy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_11_11_10) }) + } + + #[inline] + fn zwwz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_11_11_10) }) + } + + #[inline] + fn zwww(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_11_11_10) }) + } + + #[inline] + fn wxxx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_00_11) }) + } + + #[inline] + fn wxxy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_00_00_11) }) + } + + #[inline] + fn wxxz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_00_00_11) }) + } + + #[inline] + fn wxxw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_00_00_11) }) + } + + #[inline] + fn wxyx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_00_11) }) + } + + #[inline] + fn wxyy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_01_00_11) }) + } + + #[inline] + fn wxyz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_01_00_11) }) + } + + #[inline] + fn wxyw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_01_00_11) }) + } + + #[inline] + fn wxzx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_00_11) }) + } + + #[inline] + fn wxzy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_10_00_11) }) + } + + #[inline] + fn wxzz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_10_00_11) }) + } + + #[inline] + fn wxzw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_10_00_11) }) + } + + #[inline] + fn wxwx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_11_00_11) }) + } + + #[inline] + fn wxwy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_11_00_11) }) + } + + #[inline] + fn wxwz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_11_00_11) }) + } + + #[inline] + fn wxww(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_11_00_11) }) + } + + #[inline] + fn wyxx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_01_11) }) + } + + #[inline] + fn wyxy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_00_01_11) }) + } + + #[inline] + fn wyxz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_00_01_11) }) + } + + #[inline] + fn wyxw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_00_01_11) }) + } + + #[inline] + fn wyyx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_01_11) }) + } + + #[inline] + fn wyyy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_01_01_11) }) + } + + #[inline] + fn wyyz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_01_01_11) }) + } + + #[inline] + fn wyyw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_01_01_11) }) + } + + #[inline] + fn wyzx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_01_11) }) + } + + #[inline] + fn wyzy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_10_01_11) }) + } + + #[inline] + fn wyzz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_10_01_11) }) + } + + #[inline] + fn wyzw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_10_01_11) }) + } + + #[inline] + fn wywx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_11_01_11) }) + } + + #[inline] + fn wywy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_11_01_11) }) + } + + #[inline] + fn wywz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_11_01_11) }) + } + + #[inline] + fn wyww(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_11_01_11) }) + } + + #[inline] + fn wzxx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_10_11) }) + } + + #[inline] + fn wzxy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_00_10_11) }) + } + + #[inline] + fn wzxz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_00_10_11) }) + } + + #[inline] + fn wzxw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_00_10_11) }) + } + + #[inline] + fn wzyx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_10_11) }) + } + + #[inline] + fn wzyy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_01_10_11) }) + } + + #[inline] + fn wzyz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_01_10_11) }) + } + + #[inline] + fn wzyw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_01_10_11) }) + } + + #[inline] + fn wzzx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_10_11) }) + } + + #[inline] + fn wzzy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_10_10_11) }) + } + + #[inline] + fn wzzz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_10_10_11) }) + } + + #[inline] + fn wzzw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_10_10_11) }) + } + + #[inline] + fn wzwx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_11_10_11) }) + } + + #[inline] + fn wzwy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_11_10_11) }) + } + + #[inline] + fn wzwz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_11_10_11) }) + } + + #[inline] + fn wzww(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_11_10_11) }) + } + + #[inline] + fn wwxx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_11_11) }) + } + + #[inline] + fn wwxy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_00_11_11) }) + } + + #[inline] + fn wwxz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_00_11_11) }) + } + + #[inline] + fn wwxw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_00_11_11) }) + } + + #[inline] + fn wwyx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_01_11_11) }) + } + + #[inline] + fn wwyy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_01_11_11) }) + } + + #[inline] + fn wwyz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_01_11_11) }) + } + + #[inline] + fn wwyw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_01_11_11) }) + } + + #[inline] + fn wwzx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_11_11) }) + } + + #[inline] + fn wwzy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_10_11_11) }) + } + + #[inline] + fn wwzz(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b10_10_11_11) }) + } + + #[inline] + fn wwzw(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_10_11_11) }) + } + + #[inline] + fn wwwx(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_11_11_11) }) + } + + #[inline] + fn wwwy(self) -> Vec4 { + Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b01_11_11_11) }) + } + + #[inline] + 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/uvec2_impl.rs b/src/swizzles/uvec2_impl.rs new file mode 100644 index 0000000..16ddf21 --- /dev/null +++ b/src/swizzles/uvec2_impl.rs @@ -0,0 +1,193 @@ +// Generated from swizzle_impl.rs.tera template. Edit the template, not the generated file. + +use crate::{UVec2, UVec3, UVec4, Vec2Swizzles}; + +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) + } +} diff --git a/src/swizzles/uvec2_impl_scalar.rs b/src/swizzles/uvec2_impl_scalar.rs deleted file mode 100644 index 60ba857..0000000 --- a/src/swizzles/uvec2_impl_scalar.rs +++ /dev/null @@ -1,118 +0,0 @@ -// Generated by swizzlegen. Do not edit. - -use super::Vec2Swizzles; -use crate::{UVec2, UVec3, UVec4}; - -impl Vec2Swizzles for UVec2 { - type Vec3 = UVec3; - type Vec4 = UVec4; - - #[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.rs b/src/swizzles/uvec3_impl.rs new file mode 100644 index 0000000..75afb5c --- /dev/null +++ b/src/swizzles/uvec3_impl.rs @@ -0,0 +1,729 @@ +// Generated from swizzle_impl.rs.tera template. Edit the template, not the generated file. + +use crate::{UVec2, UVec3, UVec4, Vec3Swizzles}; + +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) + } +} diff --git a/src/swizzles/uvec3_impl_scalar.rs b/src/swizzles/uvec3_impl_scalar.rs deleted file mode 100644 index 5158e07..0000000 --- a/src/swizzles/uvec3_impl_scalar.rs +++ /dev/null @@ -1,474 +0,0 @@ -// Generated by swizzlegen. Do not edit. - -use super::Vec3Swizzles; -use crate::{UVec2, UVec3, UVec4}; - -impl Vec3Swizzles for UVec3 { - type Vec2 = UVec2; - type Vec4 = UVec4; - - #[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.rs b/src/swizzles/uvec4_impl.rs new file mode 100644 index 0000000..6d43573 --- /dev/null +++ b/src/swizzles/uvec4_impl.rs @@ -0,0 +1,1993 @@ +// Generated from swizzle_impl.rs.tera template. Edit the template, not the generated file. + +use crate::{UVec2, UVec3, UVec4, Vec4Swizzles}; + +impl Vec4Swizzles for UVec4 { + type Vec2 = UVec2; + + type Vec3 = UVec3; + + #[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 xw(self) -> UVec2 { + UVec2 { + x: self.x, + y: self.w, + } + } + + #[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 yw(self) -> UVec2 { + UVec2 { + x: self.y, + y: self.w, + } + } + + #[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 zw(self) -> UVec2 { + UVec2 { + x: self.z, + y: self.w, + } + } + + #[inline] + fn wx(self) -> UVec2 { + UVec2 { + x: self.w, + y: self.x, + } + } + + #[inline] + fn wy(self) -> UVec2 { + UVec2 { + x: self.w, + y: self.y, + } + } + + #[inline] + fn wz(self) -> UVec2 { + UVec2 { + x: self.w, + y: self.z, + } + } + + #[inline] + fn ww(self) -> UVec2 { + UVec2 { + x: self.w, + y: self.w, + } + } + + #[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 xxw(self) -> UVec3 { + UVec3 { + x: self.x, + y: self.x, + z: self.w, + } + } + + #[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 xyw(self) -> UVec3 { + UVec3 { + x: self.x, + y: self.y, + z: self.w, + } + } + + #[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 xzw(self) -> UVec3 { + UVec3 { + x: self.x, + y: self.z, + z: self.w, + } + } + + #[inline] + fn xwx(self) -> UVec3 { + UVec3 { + x: self.x, + y: self.w, + z: self.x, + } + } + + #[inline] + fn xwy(self) -> UVec3 { + UVec3 { + x: self.x, + y: self.w, + z: self.y, + } + } + + #[inline] + fn xwz(self) -> UVec3 { + UVec3 { + x: self.x, + y: self.w, + z: self.z, + } + } + + #[inline] + fn xww(self) -> UVec3 { + UVec3 { + x: self.x, + y: self.w, + z: self.w, + } + } + + #[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 yxw(self) -> UVec3 { + UVec3 { + x: self.y, + y: self.x, + z: self.w, + } + } + + #[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 yyw(self) -> UVec3 { + UVec3 { + x: self.y, + y: self.y, + z: self.w, + } + } + + #[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 yzw(self) -> UVec3 { + UVec3 { + x: self.y, + y: self.z, + z: self.w, + } + } + + #[inline] + fn ywx(self) -> UVec3 { + UVec3 { + x: self.y, + y: self.w, + z: self.x, + } + } + + #[inline] + fn ywy(self) -> UVec3 { + UVec3 { + x: self.y, + y: self.w, + z: self.y, + } + } + + #[inline] + fn ywz(self) -> UVec3 { + UVec3 { + x: self.y, + y: self.w, + z: self.z, + } + } + + #[inline] + fn yww(self) -> UVec3 { + UVec3 { + x: self.y, + y: self.w, + z: self.w, + } + } + + #[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 zxw(self) -> UVec3 { + UVec3 { + x: self.z, + y: self.x, + z: self.w, + } + } + + #[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 zyw(self) -> UVec3 { + UVec3 { + x: self.z, + y: self.y, + z: self.w, + } + } + + #[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 zzw(self) -> UVec3 { + UVec3 { + x: self.z, + y: self.z, + z: self.w, + } + } + + #[inline] + fn zwx(self) -> UVec3 { + UVec3 { + x: self.z, + y: self.w, + z: self.x, + } + } + + #[inline] + fn zwy(self) -> UVec3 { + UVec3 { + x: self.z, + y: self.w, + z: self.y, + } + } + + #[inline] + fn zwz(self) -> UVec3 { + UVec3 { + x: self.z, + y: self.w, + z: self.z, + } + } + + #[inline] + fn zww(self) -> UVec3 { + UVec3 { + x: self.z, + y: self.w, + z: self.w, + } + } + + #[inline] + fn wxx(self) -> UVec3 { + UVec3 { + x: self.w, + y: self.x, + z: self.x, + } + } + + #[inline] + fn wxy(self) -> UVec3 { + UVec3 { + x: self.w, + y: self.x, + z: self.y, + } + } + + #[inline] + fn wxz(self) -> UVec3 { + UVec3 { + x: self.w, + y: self.x, + z: self.z, + } + } + + #[inline] + fn wxw(self) -> UVec3 { + UVec3 { + x: self.w, + y: self.x, + z: self.w, + } + } + + #[inline] + fn wyx(self) -> UVec3 { + UVec3 { + x: self.w, + y: self.y, + z: self.x, + } + } + + #[inline] + fn wyy(self) -> UVec3 { + UVec3 { + x: self.w, + y: self.y, + z: self.y, + } + } + + #[inline] + fn wyz(self) -> UVec3 { + UVec3 { + x: self.w, + y: self.y, + z: self.z, + } + } + + #[inline] + fn wyw(self) -> UVec3 { + UVec3 { + x: self.w, + y: self.y, + z: self.w, + } + } + + #[inline] + fn wzx(self) -> UVec3 { + UVec3 { + x: self.w, + y: self.z, + z: self.x, + } + } + + #[inline] + fn wzy(self) -> UVec3 { + UVec3 { + x: self.w, + y: self.z, + z: self.y, + } + } + + #[inline] + fn wzz(self) -> UVec3 { + UVec3 { + x: self.w, + y: self.z, + z: self.z, + } + } + + #[inline] + fn wzw(self) -> UVec3 { + UVec3 { + x: self.w, + y: self.z, + z: self.w, + } + } + + #[inline] + fn wwx(self) -> UVec3 { + UVec3 { + x: self.w, + y: self.w, + z: self.x, + } + } + + #[inline] + fn wwy(self) -> UVec3 { + UVec3 { + x: self.w, + y: self.w, + z: self.y, + } + } + + #[inline] + fn wwz(self) -> UVec3 { + UVec3 { + x: self.w, + y: self.w, + z: self.z, + } + } + + #[inline] + fn www(self) -> UVec3 { + UVec3 { + x: self.w, + y: self.w, + z: self.w, + } + } + + #[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 xxxw(self) -> UVec4 { + UVec4::new(self.x, self.x, self.x, self.w) + } + + #[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 xxyw(self) -> UVec4 { + UVec4::new(self.x, self.x, self.y, self.w) + } + + #[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 xxzw(self) -> UVec4 { + UVec4::new(self.x, self.x, self.z, self.w) + } + + #[inline] + fn xxwx(self) -> UVec4 { + UVec4::new(self.x, self.x, self.w, self.x) + } + + #[inline] + fn xxwy(self) -> UVec4 { + UVec4::new(self.x, self.x, self.w, self.y) + } + + #[inline] + fn xxwz(self) -> UVec4 { + UVec4::new(self.x, self.x, self.w, self.z) + } + + #[inline] + fn xxww(self) -> UVec4 { + UVec4::new(self.x, self.x, self.w, self.w) + } + + #[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 xyxw(self) -> UVec4 { + UVec4::new(self.x, self.y, self.x, self.w) + } + + #[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 xyyw(self) -> UVec4 { + UVec4::new(self.x, self.y, self.y, self.w) + } + + #[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 xyzw(self) -> UVec4 { + UVec4::new(self.x, self.y, self.z, self.w) + } + + #[inline] + fn xywx(self) -> UVec4 { + UVec4::new(self.x, self.y, self.w, self.x) + } + + #[inline] + fn xywy(self) -> UVec4 { + UVec4::new(self.x, self.y, self.w, self.y) + } + + #[inline] + fn xywz(self) -> UVec4 { + UVec4::new(self.x, self.y, self.w, self.z) + } + + #[inline] + fn xyww(self) -> UVec4 { + UVec4::new(self.x, self.y, self.w, self.w) + } + + #[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 xzxw(self) -> UVec4 { + UVec4::new(self.x, self.z, self.x, self.w) + } + + #[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 xzyw(self) -> UVec4 { + UVec4::new(self.x, self.z, self.y, self.w) + } + + #[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 xzzw(self) -> UVec4 { + UVec4::new(self.x, self.z, self.z, self.w) + } + + #[inline] + fn xzwx(self) -> UVec4 { + UVec4::new(self.x, self.z, self.w, self.x) + } + + #[inline] + fn xzwy(self) -> UVec4 { + UVec4::new(self.x, self.z, self.w, self.y) + } + + #[inline] + fn xzwz(self) -> UVec4 { + UVec4::new(self.x, self.z, self.w, self.z) + } + + #[inline] + fn xzww(self) -> UVec4 { + UVec4::new(self.x, self.z, self.w, self.w) + } + + #[inline] + fn xwxx(self) -> UVec4 { + UVec4::new(self.x, self.w, self.x, self.x) + } + + #[inline] + fn xwxy(self) -> UVec4 { + UVec4::new(self.x, self.w, self.x, self.y) + } + + #[inline] + fn xwxz(self) -> UVec4 { + UVec4::new(self.x, self.w, self.x, self.z) + } + + #[inline] + fn xwxw(self) -> UVec4 { + UVec4::new(self.x, self.w, self.x, self.w) + } + + #[inline] + fn xwyx(self) -> UVec4 { + UVec4::new(self.x, self.w, self.y, self.x) + } + + #[inline] + fn xwyy(self) -> UVec4 { + UVec4::new(self.x, self.w, self.y, self.y) + } + + #[inline] + fn xwyz(self) -> UVec4 { + UVec4::new(self.x, self.w, self.y, self.z) + } + + #[inline] + fn xwyw(self) -> UVec4 { + UVec4::new(self.x, self.w, self.y, self.w) + } + + #[inline] + fn xwzx(self) -> UVec4 { + UVec4::new(self.x, self.w, self.z, self.x) + } + + #[inline] + fn xwzy(self) -> UVec4 { + UVec4::new(self.x, self.w, self.z, self.y) + } + + #[inline] + fn xwzz(self) -> UVec4 { + UVec4::new(self.x, self.w, self.z, self.z) + } + + #[inline] + fn xwzw(self) -> UVec4 { + UVec4::new(self.x, self.w, self.z, self.w) + } + + #[inline] + fn xwwx(self) -> UVec4 { + UVec4::new(self.x, self.w, self.w, self.x) + } + + #[inline] + fn xwwy(self) -> UVec4 { + UVec4::new(self.x, self.w, self.w, self.y) + } + + #[inline] + fn xwwz(self) -> UVec4 { + UVec4::new(self.x, self.w, self.w, self.z) + } + + #[inline] + fn xwww(self) -> UVec4 { + UVec4::new(self.x, self.w, self.w, self.w) + } + + #[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 yxxw(self) -> UVec4 { + UVec4::new(self.y, self.x, self.x, self.w) + } + + #[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 yxyw(self) -> UVec4 { + UVec4::new(self.y, self.x, self.y, self.w) + } + + #[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 yxzw(self) -> UVec4 { + UVec4::new(self.y, self.x, self.z, self.w) + } + + #[inline] + fn yxwx(self) -> UVec4 { + UVec4::new(self.y, self.x, self.w, self.x) + } + + #[inline] + fn yxwy(self) -> UVec4 { + UVec4::new(self.y, self.x, self.w, self.y) + } + + #[inline] + fn yxwz(self) -> UVec4 { + UVec4::new(self.y, self.x, self.w, self.z) + } + + #[inline] + fn yxww(self) -> UVec4 { + UVec4::new(self.y, self.x, self.w, self.w) + } + + #[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 yyxw(self) -> UVec4 { + UVec4::new(self.y, self.y, self.x, self.w) + } + + #[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 yyyw(self) -> UVec4 { + UVec4::new(self.y, self.y, self.y, self.w) + } + + #[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 yyzw(self) -> UVec4 { + UVec4::new(self.y, self.y, self.z, self.w) + } + + #[inline] + fn yywx(self) -> UVec4 { + UVec4::new(self.y, self.y, self.w, self.x) + } + + #[inline] + fn yywy(self) -> UVec4 { + UVec4::new(self.y, self.y, self.w, self.y) + } + + #[inline] + fn yywz(self) -> UVec4 { + UVec4::new(self.y, self.y, self.w, self.z) + } + + #[inline] + fn yyww(self) -> UVec4 { + UVec4::new(self.y, self.y, self.w, self.w) + } + + #[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 yzxw(self) -> UVec4 { + UVec4::new(self.y, self.z, self.x, self.w) + } + + #[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 yzyw(self) -> UVec4 { + UVec4::new(self.y, self.z, self.y, self.w) + } + + #[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 yzzw(self) -> UVec4 { + UVec4::new(self.y, self.z, self.z, self.w) + } + + #[inline] + fn yzwx(self) -> UVec4 { + UVec4::new(self.y, self.z, self.w, self.x) + } + + #[inline] + fn yzwy(self) -> UVec4 { + UVec4::new(self.y, self.z, self.w, self.y) + } + + #[inline] + fn yzwz(self) -> UVec4 { + UVec4::new(self.y, self.z, self.w, self.z) + } + + #[inline] + fn yzww(self) -> UVec4 { + UVec4::new(self.y, self.z, self.w, self.w) + } + + #[inline] + fn ywxx(self) -> UVec4 { + UVec4::new(self.y, self.w, self.x, self.x) + } + + #[inline] + fn ywxy(self) -> UVec4 { + UVec4::new(self.y, self.w, self.x, self.y) + } + + #[inline] + fn ywxz(self) -> UVec4 { + UVec4::new(self.y, self.w, self.x, self.z) + } + + #[inline] + fn ywxw(self) -> UVec4 { + UVec4::new(self.y, self.w, self.x, self.w) + } + + #[inline] + fn ywyx(self) -> UVec4 { + UVec4::new(self.y, self.w, self.y, self.x) + } + + #[inline] + fn ywyy(self) -> UVec4 { + UVec4::new(self.y, self.w, self.y, self.y) + } + + #[inline] + fn ywyz(self) -> UVec4 { + UVec4::new(self.y, self.w, self.y, self.z) + } + + #[inline] + fn ywyw(self) -> UVec4 { + UVec4::new(self.y, self.w, self.y, self.w) + } + + #[inline] + fn ywzx(self) -> UVec4 { + UVec4::new(self.y, self.w, self.z, self.x) + } + + #[inline] + fn ywzy(self) -> UVec4 { + UVec4::new(self.y, self.w, self.z, self.y) + } + + #[inline] + fn ywzz(self) -> UVec4 { + UVec4::new(self.y, self.w, self.z, self.z) + } + + #[inline] + fn ywzw(self) -> UVec4 { + UVec4::new(self.y, self.w, self.z, self.w) + } + + #[inline] + fn ywwx(self) -> UVec4 { + UVec4::new(self.y, self.w, self.w, self.x) + } + + #[inline] + fn ywwy(self) -> UVec4 { + UVec4::new(self.y, self.w, self.w, self.y) + } + + #[inline] + fn ywwz(self) -> UVec4 { + UVec4::new(self.y, self.w, self.w, self.z) + } + + #[inline] + fn ywww(self) -> UVec4 { + UVec4::new(self.y, self.w, self.w, self.w) + } + + #[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 zxxw(self) -> UVec4 { + UVec4::new(self.z, self.x, self.x, self.w) + } + + #[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 zxyw(self) -> UVec4 { + UVec4::new(self.z, self.x, self.y, self.w) + } + + #[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 zxzw(self) -> UVec4 { + UVec4::new(self.z, self.x, self.z, self.w) + } + + #[inline] + fn zxwx(self) -> UVec4 { + UVec4::new(self.z, self.x, self.w, self.x) + } + + #[inline] + fn zxwy(self) -> UVec4 { + UVec4::new(self.z, self.x, self.w, self.y) + } + + #[inline] + fn zxwz(self) -> UVec4 { + UVec4::new(self.z, self.x, self.w, self.z) + } + + #[inline] + fn zxww(self) -> UVec4 { + UVec4::new(self.z, self.x, self.w, self.w) + } + + #[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 zyxw(self) -> UVec4 { + UVec4::new(self.z, self.y, self.x, self.w) + } + + #[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 zyyw(self) -> UVec4 { + UVec4::new(self.z, self.y, self.y, self.w) + } + + #[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 zyzw(self) -> UVec4 { + UVec4::new(self.z, self.y, self.z, self.w) + } + + #[inline] + fn zywx(self) -> UVec4 { + UVec4::new(self.z, self.y, self.w, self.x) + } + + #[inline] + fn zywy(self) -> UVec4 { + UVec4::new(self.z, self.y, self.w, self.y) + } + + #[inline] + fn zywz(self) -> UVec4 { + UVec4::new(self.z, self.y, self.w, self.z) + } + + #[inline] + fn zyww(self) -> UVec4 { + UVec4::new(self.z, self.y, self.w, self.w) + } + + #[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 zzxw(self) -> UVec4 { + UVec4::new(self.z, self.z, self.x, self.w) + } + + #[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 zzyw(self) -> UVec4 { + UVec4::new(self.z, self.z, self.y, self.w) + } + + #[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 zzzw(self) -> UVec4 { + UVec4::new(self.z, self.z, self.z, self.w) + } + + #[inline] + fn zzwx(self) -> UVec4 { + UVec4::new(self.z, self.z, self.w, self.x) + } + + #[inline] + fn zzwy(self) -> UVec4 { + UVec4::new(self.z, self.z, self.w, self.y) + } + + #[inline] + fn zzwz(self) -> UVec4 { + UVec4::new(self.z, self.z, self.w, self.z) + } + + #[inline] + fn zzww(self) -> UVec4 { + UVec4::new(self.z, self.z, self.w, self.w) + } + + #[inline] + fn zwxx(self) -> UVec4 { + UVec4::new(self.z, self.w, self.x, self.x) + } + + #[inline] + fn zwxy(self) -> UVec4 { + UVec4::new(self.z, self.w, self.x, self.y) + } + + #[inline] + fn zwxz(self) -> UVec4 { + UVec4::new(self.z, self.w, self.x, self.z) + } + + #[inline] + fn zwxw(self) -> UVec4 { + UVec4::new(self.z, self.w, self.x, self.w) + } + + #[inline] + fn zwyx(self) -> UVec4 { + UVec4::new(self.z, self.w, self.y, self.x) + } + + #[inline] + fn zwyy(self) -> UVec4 { + UVec4::new(self.z, self.w, self.y, self.y) + } + + #[inline] + fn zwyz(self) -> UVec4 { + UVec4::new(self.z, self.w, self.y, self.z) + } + + #[inline] + fn zwyw(self) -> UVec4 { + UVec4::new(self.z, self.w, self.y, self.w) + } + + #[inline] + fn zwzx(self) -> UVec4 { + UVec4::new(self.z, self.w, self.z, self.x) + } + + #[inline] + fn zwzy(self) -> UVec4 { + UVec4::new(self.z, self.w, self.z, self.y) + } + + #[inline] + fn zwzz(self) -> UVec4 { + UVec4::new(self.z, self.w, self.z, self.z) + } + + #[inline] + fn zwzw(self) -> UVec4 { + UVec4::new(self.z, self.w, self.z, self.w) + } + + #[inline] + fn zwwx(self) -> UVec4 { + UVec4::new(self.z, self.w, self.w, self.x) + } + + #[inline] + fn zwwy(self) -> UVec4 { + UVec4::new(self.z, self.w, self.w, self.y) + } + + #[inline] + fn zwwz(self) -> UVec4 { + UVec4::new(self.z, self.w, self.w, self.z) + } + + #[inline] + fn zwww(self) -> UVec4 { + UVec4::new(self.z, self.w, self.w, self.w) + } + + #[inline] + fn wxxx(self) -> UVec4 { + UVec4::new(self.w, self.x, self.x, self.x) + } + + #[inline] + fn wxxy(self) -> UVec4 { + UVec4::new(self.w, self.x, self.x, self.y) + } + + #[inline] + fn wxxz(self) -> UVec4 { + UVec4::new(self.w, self.x, self.x, self.z) + } + + #[inline] + fn wxxw(self) -> UVec4 { + UVec4::new(self.w, self.x, self.x, self.w) + } + + #[inline] + fn wxyx(self) -> UVec4 { + UVec4::new(self.w, self.x, self.y, self.x) + } + + #[inline] + fn wxyy(self) -> UVec4 { + UVec4::new(self.w, self.x, self.y, self.y) + } + + #[inline] + fn wxyz(self) -> UVec4 { + UVec4::new(self.w, self.x, self.y, self.z) + } + + #[inline] + fn wxyw(self) -> UVec4 { + UVec4::new(self.w, self.x, self.y, self.w) + } + + #[inline] + fn wxzx(self) -> UVec4 { + UVec4::new(self.w, self.x, self.z, self.x) + } + + #[inline] + fn wxzy(self) -> UVec4 { + UVec4::new(self.w, self.x, self.z, self.y) + } + + #[inline] + fn wxzz(self) -> UVec4 { + UVec4::new(self.w, self.x, self.z, self.z) + } + + #[inline] + fn wxzw(self) -> UVec4 { + UVec4::new(self.w, self.x, self.z, self.w) + } + + #[inline] + fn wxwx(self) -> UVec4 { + UVec4::new(self.w, self.x, self.w, self.x) + } + + #[inline] + fn wxwy(self) -> UVec4 { + UVec4::new(self.w, self.x, self.w, self.y) + } + + #[inline] + fn wxwz(self) -> UVec4 { + UVec4::new(self.w, self.x, self.w, self.z) + } + + #[inline] + fn wxww(self) -> UVec4 { + UVec4::new(self.w, self.x, self.w, self.w) + } + + #[inline] + fn wyxx(self) -> UVec4 { + UVec4::new(self.w, self.y, self.x, self.x) + } + + #[inline] + fn wyxy(self) -> UVec4 { + UVec4::new(self.w, self.y, self.x, self.y) + } + + #[inline] + fn wyxz(self) -> UVec4 { + UVec4::new(self.w, self.y, self.x, self.z) + } + + #[inline] + fn wyxw(self) -> UVec4 { + UVec4::new(self.w, self.y, self.x, self.w) + } + + #[inline] + fn wyyx(self) -> UVec4 { + UVec4::new(self.w, self.y, self.y, self.x) + } + + #[inline] + fn wyyy(self) -> UVec4 { + UVec4::new(self.w, self.y, self.y, self.y) + } + + #[inline] + fn wyyz(self) -> UVec4 { + UVec4::new(self.w, self.y, self.y, self.z) + } + + #[inline] + fn wyyw(self) -> UVec4 { + UVec4::new(self.w, self.y, self.y, self.w) + } + + #[inline] + fn wyzx(self) -> UVec4 { + UVec4::new(self.w, self.y, self.z, self.x) + } + + #[inline] + fn wyzy(self) -> UVec4 { + UVec4::new(self.w, self.y, self.z, self.y) + } + + #[inline] + fn wyzz(self) -> UVec4 { + UVec4::new(self.w, self.y, self.z, self.z) + } + + #[inline] + fn wyzw(self) -> UVec4 { + UVec4::new(self.w, self.y, self.z, self.w) + } + + #[inline] + fn wywx(self) -> UVec4 { + UVec4::new(self.w, self.y, self.w, self.x) + } + + #[inline] + fn wywy(self) -> UVec4 { + UVec4::new(self.w, self.y, self.w, self.y) + } + + #[inline] + fn wywz(self) -> UVec4 { + UVec4::new(self.w, self.y, self.w, self.z) + } + + #[inline] + fn wyww(self) -> UVec4 { + UVec4::new(self.w, self.y, self.w, self.w) + } + + #[inline] + fn wzxx(self) -> UVec4 { + UVec4::new(self.w, self.z, self.x, self.x) + } + + #[inline] + fn wzxy(self) -> UVec4 { + UVec4::new(self.w, self.z, self.x, self.y) + } + + #[inline] + fn wzxz(self) -> UVec4 { + UVec4::new(self.w, self.z, self.x, self.z) + } + + #[inline] + fn wzxw(self) -> UVec4 { + UVec4::new(self.w, self.z, self.x, self.w) + } + + #[inline] + fn wzyx(self) -> UVec4 { + UVec4::new(self.w, self.z, self.y, self.x) + } + + #[inline] + fn wzyy(self) -> UVec4 { + UVec4::new(self.w, self.z, self.y, self.y) + } + + #[inline] + fn wzyz(self) -> UVec4 { + UVec4::new(self.w, self.z, self.y, self.z) + } + + #[inline] + fn wzyw(self) -> UVec4 { + UVec4::new(self.w, self.z, self.y, self.w) + } + + #[inline] + fn wzzx(self) -> UVec4 { + UVec4::new(self.w, self.z, self.z, self.x) + } + + #[inline] + fn wzzy(self) -> UVec4 { + UVec4::new(self.w, self.z, self.z, self.y) + } + + #[inline] + fn wzzz(self) -> UVec4 { + UVec4::new(self.w, self.z, self.z, self.z) + } + + #[inline] + fn wzzw(self) -> UVec4 { + UVec4::new(self.w, self.z, self.z, self.w) + } + + #[inline] + fn wzwx(self) -> UVec4 { + UVec4::new(self.w, self.z, self.w, self.x) + } + + #[inline] + fn wzwy(self) -> UVec4 { + UVec4::new(self.w, self.z, self.w, self.y) + } + + #[inline] + fn wzwz(self) -> UVec4 { + UVec4::new(self.w, self.z, self.w, self.z) + } + + #[inline] + fn wzww(self) -> UVec4 { + UVec4::new(self.w, self.z, self.w, self.w) + } + + #[inline] + fn wwxx(self) -> UVec4 { + UVec4::new(self.w, self.w, self.x, self.x) + } + + #[inline] + fn wwxy(self) -> UVec4 { + UVec4::new(self.w, self.w, self.x, self.y) + } + + #[inline] + fn wwxz(self) -> UVec4 { + UVec4::new(self.w, self.w, self.x, self.z) + } + + #[inline] + fn wwxw(self) -> UVec4 { + UVec4::new(self.w, self.w, self.x, self.w) + } + + #[inline] + fn wwyx(self) -> UVec4 { + UVec4::new(self.w, self.w, self.y, self.x) + } + + #[inline] + fn wwyy(self) -> UVec4 { + UVec4::new(self.w, self.w, self.y, self.y) + } + + #[inline] + fn wwyz(self) -> UVec4 { + UVec4::new(self.w, self.w, self.y, self.z) + } + + #[inline] + fn wwyw(self) -> UVec4 { + UVec4::new(self.w, self.w, self.y, self.w) + } + + #[inline] + fn wwzx(self) -> UVec4 { + UVec4::new(self.w, self.w, self.z, self.x) + } + + #[inline] + fn wwzy(self) -> UVec4 { + UVec4::new(self.w, self.w, self.z, self.y) + } + + #[inline] + fn wwzz(self) -> UVec4 { + UVec4::new(self.w, self.w, self.z, self.z) + } + + #[inline] + fn wwzw(self) -> UVec4 { + UVec4::new(self.w, self.w, self.z, self.w) + } + + #[inline] + fn wwwx(self) -> UVec4 { + UVec4::new(self.w, self.w, self.w, self.x) + } + + #[inline] + fn wwwy(self) -> UVec4 { + UVec4::new(self.w, self.w, self.w, self.y) + } + + #[inline] + fn wwwz(self) -> UVec4 { + UVec4::new(self.w, self.w, self.w, self.z) + } + + #[inline] + fn wwww(self) -> UVec4 { + UVec4::new(self.w, self.w, self.w, self.w) + } +} diff --git a/src/swizzles/uvec4_impl_scalar.rs b/src/swizzles/uvec4_impl_scalar.rs deleted file mode 100644 index be4824c..0000000 --- a/src/swizzles/uvec4_impl_scalar.rs +++ /dev/null @@ -1,1350 +0,0 @@ -// Generated by swizzlegen. Do not edit. - -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) - } - #[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 xxxw(self) -> UVec4 { - UVec4::new(self.x, self.x, self.x, self.w) - } - #[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 xxyw(self) -> UVec4 { - UVec4::new(self.x, self.x, self.y, self.w) - } - #[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 xxzw(self) -> UVec4 { - UVec4::new(self.x, self.x, self.z, self.w) - } - #[inline] - fn xxwx(self) -> UVec4 { - UVec4::new(self.x, self.x, self.w, self.x) - } - #[inline] - fn xxwy(self) -> UVec4 { - UVec4::new(self.x, self.x, self.w, self.y) - } - #[inline] - fn xxwz(self) -> UVec4 { - UVec4::new(self.x, self.x, self.w, self.z) - } - #[inline] - fn xxww(self) -> UVec4 { - UVec4::new(self.x, self.x, self.w, self.w) - } - #[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 xyxw(self) -> UVec4 { - UVec4::new(self.x, self.y, self.x, self.w) - } - #[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 xyyw(self) -> UVec4 { - UVec4::new(self.x, self.y, self.y, self.w) - } - #[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 xywx(self) -> UVec4 { - UVec4::new(self.x, self.y, self.w, self.x) - } - #[inline] - fn xywy(self) -> UVec4 { - UVec4::new(self.x, self.y, self.w, self.y) - } - #[inline] - fn xywz(self) -> UVec4 { - UVec4::new(self.x, self.y, self.w, self.z) - } - #[inline] - fn xyww(self) -> UVec4 { - UVec4::new(self.x, self.y, self.w, self.w) - } - #[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 xzxw(self) -> UVec4 { - UVec4::new(self.x, self.z, self.x, self.w) - } - #[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 xzyw(self) -> UVec4 { - UVec4::new(self.x, self.z, self.y, self.w) - } - #[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 xzzw(self) -> UVec4 { - UVec4::new(self.x, self.z, self.z, self.w) - } - #[inline] - fn xzwx(self) -> UVec4 { - UVec4::new(self.x, self.z, self.w, self.x) - } - #[inline] - fn xzwy(self) -> UVec4 { - UVec4::new(self.x, self.z, self.w, self.y) - } - #[inline] - fn xzwz(self) -> UVec4 { - UVec4::new(self.x, self.z, self.w, self.z) - } - #[inline] - fn xzww(self) -> UVec4 { - UVec4::new(self.x, self.z, self.w, self.w) - } - #[inline] - fn xwxx(self) -> UVec4 { - UVec4::new(self.x, self.w, self.x, self.x) - } - #[inline] - fn xwxy(self) -> UVec4 { - UVec4::new(self.x, self.w, self.x, self.y) - } - #[inline] - fn xwxz(self) -> UVec4 { - UVec4::new(self.x, self.w, self.x, self.z) - } - #[inline] - fn xwxw(self) -> UVec4 { - UVec4::new(self.x, self.w, self.x, self.w) - } - #[inline] - fn xwyx(self) -> UVec4 { - UVec4::new(self.x, self.w, self.y, self.x) - } - #[inline] - fn xwyy(self) -> UVec4 { - UVec4::new(self.x, self.w, self.y, self.y) - } - #[inline] - fn xwyz(self) -> UVec4 { - UVec4::new(self.x, self.w, self.y, self.z) - } - #[inline] - fn xwyw(self) -> UVec4 { - UVec4::new(self.x, self.w, self.y, self.w) - } - #[inline] - fn xwzx(self) -> UVec4 { - UVec4::new(self.x, self.w, self.z, self.x) - } - #[inline] - fn xwzy(self) -> UVec4 { - UVec4::new(self.x, self.w, self.z, self.y) - } - #[inline] - fn xwzz(self) -> UVec4 { - UVec4::new(self.x, self.w, self.z, self.z) - } - #[inline] - fn xwzw(self) -> UVec4 { - UVec4::new(self.x, self.w, self.z, self.w) - } - #[inline] - fn xwwx(self) -> UVec4 { - UVec4::new(self.x, self.w, self.w, self.x) - } - #[inline] - fn xwwy(self) -> UVec4 { - UVec4::new(self.x, self.w, self.w, self.y) - } - #[inline] - fn xwwz(self) -> UVec4 { - UVec4::new(self.x, self.w, self.w, self.z) - } - #[inline] - fn xwww(self) -> UVec4 { - UVec4::new(self.x, self.w, self.w, self.w) - } - #[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 yxxw(self) -> UVec4 { - UVec4::new(self.y, self.x, self.x, self.w) - } - #[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 yxyw(self) -> UVec4 { - UVec4::new(self.y, self.x, self.y, self.w) - } - #[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 yxzw(self) -> UVec4 { - UVec4::new(self.y, self.x, self.z, self.w) - } - #[inline] - fn yxwx(self) -> UVec4 { - UVec4::new(self.y, self.x, self.w, self.x) - } - #[inline] - fn yxwy(self) -> UVec4 { - UVec4::new(self.y, self.x, self.w, self.y) - } - #[inline] - fn yxwz(self) -> UVec4 { - UVec4::new(self.y, self.x, self.w, self.z) - } - #[inline] - fn yxww(self) -> UVec4 { - UVec4::new(self.y, self.x, self.w, self.w) - } - #[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 yyxw(self) -> UVec4 { - UVec4::new(self.y, self.y, self.x, self.w) - } - #[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 yyyw(self) -> UVec4 { - UVec4::new(self.y, self.y, self.y, self.w) - } - #[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 yyzw(self) -> UVec4 { - UVec4::new(self.y, self.y, self.z, self.w) - } - #[inline] - fn yywx(self) -> UVec4 { - UVec4::new(self.y, self.y, self.w, self.x) - } - #[inline] - fn yywy(self) -> UVec4 { - UVec4::new(self.y, self.y, self.w, self.y) - } - #[inline] - fn yywz(self) -> UVec4 { - UVec4::new(self.y, self.y, self.w, self.z) - } - #[inline] - fn yyww(self) -> UVec4 { - UVec4::new(self.y, self.y, self.w, self.w) - } - #[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 yzxw(self) -> UVec4 { - UVec4::new(self.y, self.z, self.x, self.w) - } - #[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 yzyw(self) -> UVec4 { - UVec4::new(self.y, self.z, self.y, self.w) - } - #[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 yzzw(self) -> UVec4 { - UVec4::new(self.y, self.z, self.z, self.w) - } - #[inline] - fn yzwx(self) -> UVec4 { - UVec4::new(self.y, self.z, self.w, self.x) - } - #[inline] - fn yzwy(self) -> UVec4 { - UVec4::new(self.y, self.z, self.w, self.y) - } - #[inline] - fn yzwz(self) -> UVec4 { - UVec4::new(self.y, self.z, self.w, self.z) - } - #[inline] - fn yzww(self) -> UVec4 { - UVec4::new(self.y, self.z, self.w, self.w) - } - #[inline] - fn ywxx(self) -> UVec4 { - UVec4::new(self.y, self.w, self.x, self.x) - } - #[inline] - fn ywxy(self) -> UVec4 { - UVec4::new(self.y, self.w, self.x, self.y) - } - #[inline] - fn ywxz(self) -> UVec4 { - UVec4::new(self.y, self.w, self.x, self.z) - } - #[inline] - fn ywxw(self) -> UVec4 { - UVec4::new(self.y, self.w, self.x, self.w) - } - #[inline] - fn ywyx(self) -> UVec4 { - UVec4::new(self.y, self.w, self.y, self.x) - } - #[inline] - fn ywyy(self) -> UVec4 { - UVec4::new(self.y, self.w, self.y, self.y) - } - #[inline] - fn ywyz(self) -> UVec4 { - UVec4::new(self.y, self.w, self.y, self.z) - } - #[inline] - fn ywyw(self) -> UVec4 { - UVec4::new(self.y, self.w, self.y, self.w) - } - #[inline] - fn ywzx(self) -> UVec4 { - UVec4::new(self.y, self.w, self.z, self.x) - } - #[inline] - fn ywzy(self) -> UVec4 { - UVec4::new(self.y, self.w, self.z, self.y) - } - #[inline] - fn ywzz(self) -> UVec4 { - UVec4::new(self.y, self.w, self.z, self.z) - } - #[inline] - fn ywzw(self) -> UVec4 { - UVec4::new(self.y, self.w, self.z, self.w) - } - #[inline] - fn ywwx(self) -> UVec4 { - UVec4::new(self.y, self.w, self.w, self.x) - } - #[inline] - fn ywwy(self) -> UVec4 { - UVec4::new(self.y, self.w, self.w, self.y) - } - #[inline] - fn ywwz(self) -> UVec4 { - UVec4::new(self.y, self.w, self.w, self.z) - } - #[inline] - fn ywww(self) -> UVec4 { - UVec4::new(self.y, self.w, self.w, self.w) - } - #[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 zxxw(self) -> UVec4 { - UVec4::new(self.z, self.x, self.x, self.w) - } - #[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 zxyw(self) -> UVec4 { - UVec4::new(self.z, self.x, self.y, self.w) - } - #[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 zxzw(self) -> UVec4 { - UVec4::new(self.z, self.x, self.z, self.w) - } - #[inline] - fn zxwx(self) -> UVec4 { - UVec4::new(self.z, self.x, self.w, self.x) - } - #[inline] - fn zxwy(self) -> UVec4 { - UVec4::new(self.z, self.x, self.w, self.y) - } - #[inline] - fn zxwz(self) -> UVec4 { - UVec4::new(self.z, self.x, self.w, self.z) - } - #[inline] - fn zxww(self) -> UVec4 { - UVec4::new(self.z, self.x, self.w, self.w) - } - #[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 zyxw(self) -> UVec4 { - UVec4::new(self.z, self.y, self.x, self.w) - } - #[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 zyyw(self) -> UVec4 { - UVec4::new(self.z, self.y, self.y, self.w) - } - #[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 zyzw(self) -> UVec4 { - UVec4::new(self.z, self.y, self.z, self.w) - } - #[inline] - fn zywx(self) -> UVec4 { - UVec4::new(self.z, self.y, self.w, self.x) - } - #[inline] - fn zywy(self) -> UVec4 { - UVec4::new(self.z, self.y, self.w, self.y) - } - #[inline] - fn zywz(self) -> UVec4 { - UVec4::new(self.z, self.y, self.w, self.z) - } - #[inline] - fn zyww(self) -> UVec4 { - UVec4::new(self.z, self.y, self.w, self.w) - } - #[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 zzxw(self) -> UVec4 { - UVec4::new(self.z, self.z, self.x, self.w) - } - #[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 zzyw(self) -> UVec4 { - UVec4::new(self.z, self.z, self.y, self.w) - } - #[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 zzzw(self) -> UVec4 { - UVec4::new(self.z, self.z, self.z, self.w) - } - #[inline] - fn zzwx(self) -> UVec4 { - UVec4::new(self.z, self.z, self.w, self.x) - } - #[inline] - fn zzwy(self) -> UVec4 { - UVec4::new(self.z, self.z, self.w, self.y) - } - #[inline] - fn zzwz(self) -> UVec4 { - UVec4::new(self.z, self.z, self.w, self.z) - } - #[inline] - fn zzww(self) -> UVec4 { - UVec4::new(self.z, self.z, self.w, self.w) - } - #[inline] - fn zwxx(self) -> UVec4 { - UVec4::new(self.z, self.w, self.x, self.x) - } - #[inline] - fn zwxy(self) -> UVec4 { - UVec4::new(self.z, self.w, self.x, self.y) - } - #[inline] - fn zwxz(self) -> UVec4 { - UVec4::new(self.z, self.w, self.x, self.z) - } - #[inline] - fn zwxw(self) -> UVec4 { - UVec4::new(self.z, self.w, self.x, self.w) - } - #[inline] - fn zwyx(self) -> UVec4 { - UVec4::new(self.z, self.w, self.y, self.x) - } - #[inline] - fn zwyy(self) -> UVec4 { - UVec4::new(self.z, self.w, self.y, self.y) - } - #[inline] - fn zwyz(self) -> UVec4 { - UVec4::new(self.z, self.w, self.y, self.z) - } - #[inline] - fn zwyw(self) -> UVec4 { - UVec4::new(self.z, self.w, self.y, self.w) - } - #[inline] - fn zwzx(self) -> UVec4 { - UVec4::new(self.z, self.w, self.z, self.x) - } - #[inline] - fn zwzy(self) -> UVec4 { - UVec4::new(self.z, self.w, self.z, self.y) - } - #[inline] - fn zwzz(self) -> UVec4 { - UVec4::new(self.z, self.w, self.z, self.z) - } - #[inline] - fn zwzw(self) -> UVec4 { - UVec4::new(self.z, self.w, self.z, self.w) - } - #[inline] - fn zwwx(self) -> UVec4 { - UVec4::new(self.z, self.w, self.w, self.x) - } - #[inline] - fn zwwy(self) -> UVec4 { - UVec4::new(self.z, self.w, self.w, self.y) - } - #[inline] - fn zwwz(self) -> UVec4 { - UVec4::new(self.z, self.w, self.w, self.z) - } - #[inline] - fn zwww(self) -> UVec4 { - UVec4::new(self.z, self.w, self.w, self.w) - } - #[inline] - fn wxxx(self) -> UVec4 { - UVec4::new(self.w, self.x, self.x, self.x) - } - #[inline] - fn wxxy(self) -> UVec4 { - UVec4::new(self.w, self.x, self.x, self.y) - } - #[inline] - fn wxxz(self) -> UVec4 { - UVec4::new(self.w, self.x, self.x, self.z) - } - #[inline] - fn wxxw(self) -> UVec4 { - UVec4::new(self.w, self.x, self.x, self.w) - } - #[inline] - fn wxyx(self) -> UVec4 { - UVec4::new(self.w, self.x, self.y, self.x) - } - #[inline] - fn wxyy(self) -> UVec4 { - UVec4::new(self.w, self.x, self.y, self.y) - } - #[inline] - fn wxyz(self) -> UVec4 { - UVec4::new(self.w, self.x, self.y, self.z) - } - #[inline] - fn wxyw(self) -> UVec4 { - UVec4::new(self.w, self.x, self.y, self.w) - } - #[inline] - fn wxzx(self) -> UVec4 { - UVec4::new(self.w, self.x, self.z, self.x) - } - #[inline] - fn wxzy(self) -> UVec4 { - UVec4::new(self.w, self.x, self.z, self.y) - } - #[inline] - fn wxzz(self) -> UVec4 { - UVec4::new(self.w, self.x, self.z, self.z) - } - #[inline] - fn wxzw(self) -> UVec4 { - UVec4::new(self.w, self.x, self.z, self.w) - } - #[inline] - fn wxwx(self) -> UVec4 { - UVec4::new(self.w, self.x, self.w, self.x) - } - #[inline] - fn wxwy(self) -> UVec4 { - UVec4::new(self.w, self.x, self.w, self.y) - } - #[inline] - fn wxwz(self) -> UVec4 { - UVec4::new(self.w, self.x, self.w, self.z) - } - #[inline] - fn wxww(self) -> UVec4 { - UVec4::new(self.w, self.x, self.w, self.w) - } - #[inline] - fn wyxx(self) -> UVec4 { - UVec4::new(self.w, self.y, self.x, self.x) - } - #[inline] - fn wyxy(self) -> UVec4 { - UVec4::new(self.w, self.y, self.x, self.y) - } - #[inline] - fn wyxz(self) -> UVec4 { - UVec4::new(self.w, self.y, self.x, self.z) - } - #[inline] - fn wyxw(self) -> UVec4 { - UVec4::new(self.w, self.y, self.x, self.w) - } - #[inline] - fn wyyx(self) -> UVec4 { - UVec4::new(self.w, self.y, self.y, self.x) - } - #[inline] - fn wyyy(self) -> UVec4 { - UVec4::new(self.w, self.y, self.y, self.y) - } - #[inline] - fn wyyz(self) -> UVec4 { - UVec4::new(self.w, self.y, self.y, self.z) - } - #[inline] - fn wyyw(self) -> UVec4 { - UVec4::new(self.w, self.y, self.y, self.w) - } - #[inline] - fn wyzx(self) -> UVec4 { - UVec4::new(self.w, self.y, self.z, self.x) - } - #[inline] - fn wyzy(self) -> UVec4 { - UVec4::new(self.w, self.y, self.z, self.y) - } - #[inline] - fn wyzz(self) -> UVec4 { - UVec4::new(self.w, self.y, self.z, self.z) - } - #[inline] - fn wyzw(self) -> UVec4 { - UVec4::new(self.w, self.y, self.z, self.w) - } - #[inline] - fn wywx(self) -> UVec4 { - UVec4::new(self.w, self.y, self.w, self.x) - } - #[inline] - fn wywy(self) -> UVec4 { - UVec4::new(self.w, self.y, self.w, self.y) - } - #[inline] - fn wywz(self) -> UVec4 { - UVec4::new(self.w, self.y, self.w, self.z) - } - #[inline] - fn wyww(self) -> UVec4 { - UVec4::new(self.w, self.y, self.w, self.w) - } - #[inline] - fn wzxx(self) -> UVec4 { - UVec4::new(self.w, self.z, self.x, self.x) - } - #[inline] - fn wzxy(self) -> UVec4 { - UVec4::new(self.w, self.z, self.x, self.y) - } - #[inline] - fn wzxz(self) -> UVec4 { - UVec4::new(self.w, self.z, self.x, self.z) - } - #[inline] - fn wzxw(self) -> UVec4 { - UVec4::new(self.w, self.z, self.x, self.w) - } - #[inline] - fn wzyx(self) -> UVec4 { - UVec4::new(self.w, self.z, self.y, self.x) - } - #[inline] - fn wzyy(self) -> UVec4 { - UVec4::new(self.w, self.z, self.y, self.y) - } - #[inline] - fn wzyz(self) -> UVec4 { - UVec4::new(self.w, self.z, self.y, self.z) - } - #[inline] - fn wzyw(self) -> UVec4 { - UVec4::new(self.w, self.z, self.y, self.w) - } - #[inline] - fn wzzx(self) -> UVec4 { - UVec4::new(self.w, self.z, self.z, self.x) - } - #[inline] - fn wzzy(self) -> UVec4 { - UVec4::new(self.w, self.z, self.z, self.y) - } - #[inline] - fn wzzz(self) -> UVec4 { - UVec4::new(self.w, self.z, self.z, self.z) - } - #[inline] - fn wzzw(self) -> UVec4 { - UVec4::new(self.w, self.z, self.z, self.w) - } - #[inline] - fn wzwx(self) -> UVec4 { - UVec4::new(self.w, self.z, self.w, self.x) - } - #[inline] - fn wzwy(self) -> UVec4 { - UVec4::new(self.w, self.z, self.w, self.y) - } - #[inline] - fn wzwz(self) -> UVec4 { - UVec4::new(self.w, self.z, self.w, self.z) - } - #[inline] - fn wzww(self) -> UVec4 { - UVec4::new(self.w, self.z, self.w, self.w) - } - #[inline] - fn wwxx(self) -> UVec4 { - UVec4::new(self.w, self.w, self.x, self.x) - } - #[inline] - fn wwxy(self) -> UVec4 { - UVec4::new(self.w, self.w, self.x, self.y) - } - #[inline] - fn wwxz(self) -> UVec4 { - UVec4::new(self.w, self.w, self.x, self.z) - } - #[inline] - fn wwxw(self) -> UVec4 { - UVec4::new(self.w, self.w, self.x, self.w) - } - #[inline] - fn wwyx(self) -> UVec4 { - UVec4::new(self.w, self.w, self.y, self.x) - } - #[inline] - fn wwyy(self) -> UVec4 { - UVec4::new(self.w, self.w, self.y, self.y) - } - #[inline] - fn wwyz(self) -> UVec4 { - UVec4::new(self.w, self.w, self.y, self.z) - } - #[inline] - fn wwyw(self) -> UVec4 { - UVec4::new(self.w, self.w, self.y, self.w) - } - #[inline] - fn wwzx(self) -> UVec4 { - UVec4::new(self.w, self.w, self.z, self.x) - } - #[inline] - fn wwzy(self) -> UVec4 { - UVec4::new(self.w, self.w, self.z, self.y) - } - #[inline] - fn wwzz(self) -> UVec4 { - UVec4::new(self.w, self.w, self.z, self.z) - } - #[inline] - fn wwzw(self) -> UVec4 { - UVec4::new(self.w, self.w, self.z, self.w) - } - #[inline] - fn wwwx(self) -> UVec4 { - UVec4::new(self.w, self.w, self.w, self.x) - } - #[inline] - fn wwwy(self) -> UVec4 { - UVec4::new(self.w, self.w, self.w, self.y) - } - #[inline] - fn wwwz(self) -> UVec4 { - UVec4::new(self.w, self.w, self.w, self.z) - } - #[inline] - fn wwww(self) -> UVec4 { - UVec4::new(self.w, self.w, self.w, self.w) - } - #[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 xxz(self) -> UVec3 { - UVec3::new(self.x, self.x, self.z) - } - #[inline] - fn xxw(self) -> UVec3 { - UVec3::new(self.x, self.x, self.w) - } - #[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 xyz(self) -> UVec3 { - UVec3::new(self.x, self.y, self.z) - } - #[inline] - fn xyw(self) -> UVec3 { - UVec3::new(self.x, self.y, self.w) - } - #[inline] - fn xzx(self) -> UVec3 { - UVec3::new(self.x, self.z, self.x) - } - #[inline] - fn xzy(self) -> UVec3 { - UVec3::new(self.x, self.z, self.y) - } - #[inline] - fn xzz(self) -> UVec3 { - UVec3::new(self.x, self.z, self.z) - } - #[inline] - fn xzw(self) -> UVec3 { - UVec3::new(self.x, self.z, self.w) - } - #[inline] - fn xwx(self) -> UVec3 { - UVec3::new(self.x, self.w, self.x) - } - #[inline] - fn xwy(self) -> UVec3 { - UVec3::new(self.x, self.w, self.y) - } - #[inline] - fn xwz(self) -> UVec3 { - UVec3::new(self.x, self.w, self.z) - } - #[inline] - fn xww(self) -> UVec3 { - UVec3::new(self.x, self.w, self.w) - } - #[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 yxz(self) -> UVec3 { - UVec3::new(self.y, self.x, self.z) - } - #[inline] - fn yxw(self) -> UVec3 { - UVec3::new(self.y, self.x, self.w) - } - #[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 yyz(self) -> UVec3 { - UVec3::new(self.y, self.y, self.z) - } - #[inline] - fn yyw(self) -> UVec3 { - UVec3::new(self.y, self.y, self.w) - } - #[inline] - fn yzx(self) -> UVec3 { - UVec3::new(self.y, self.z, self.x) - } - #[inline] - fn yzy(self) -> UVec3 { - UVec3::new(self.y, self.z, self.y) - } - #[inline] - fn yzz(self) -> UVec3 { - UVec3::new(self.y, self.z, self.z) - } - #[inline] - fn yzw(self) -> UVec3 { - UVec3::new(self.y, self.z, self.w) - } - #[inline] - fn ywx(self) -> UVec3 { - UVec3::new(self.y, self.w, self.x) - } - #[inline] - fn ywy(self) -> UVec3 { - UVec3::new(self.y, self.w, self.y) - } - #[inline] - fn ywz(self) -> UVec3 { - UVec3::new(self.y, self.w, self.z) - } - #[inline] - fn yww(self) -> UVec3 { - UVec3::new(self.y, self.w, self.w) - } - #[inline] - fn zxx(self) -> UVec3 { - UVec3::new(self.z, self.x, self.x) - } - #[inline] - fn zxy(self) -> UVec3 { - UVec3::new(self.z, self.x, self.y) - } - #[inline] - fn zxz(self) -> UVec3 { - UVec3::new(self.z, self.x, self.z) - } - #[inline] - fn zxw(self) -> UVec3 { - UVec3::new(self.z, self.x, self.w) - } - #[inline] - fn zyx(self) -> UVec3 { - UVec3::new(self.z, self.y, self.x) - } - #[inline] - fn zyy(self) -> UVec3 { - UVec3::new(self.z, self.y, self.y) - } - #[inline] - fn zyz(self) -> UVec3 { - UVec3::new(self.z, self.y, self.z) - } - #[inline] - fn zyw(self) -> UVec3 { - UVec3::new(self.z, self.y, self.w) - } - #[inline] - fn zzx(self) -> UVec3 { - UVec3::new(self.z, self.z, self.x) - } - #[inline] - fn zzy(self) -> UVec3 { - UVec3::new(self.z, self.z, self.y) - } - #[inline] - fn zzz(self) -> UVec3 { - UVec3::new(self.z, self.z, self.z) - } - #[inline] - fn zzw(self) -> UVec3 { - UVec3::new(self.z, self.z, self.w) - } - #[inline] - fn zwx(self) -> UVec3 { - UVec3::new(self.z, self.w, self.x) - } - #[inline] - fn zwy(self) -> UVec3 { - UVec3::new(self.z, self.w, self.y) - } - #[inline] - fn zwz(self) -> UVec3 { - UVec3::new(self.z, self.w, self.z) - } - #[inline] - fn zww(self) -> UVec3 { - UVec3::new(self.z, self.w, self.w) - } - #[inline] - fn wxx(self) -> UVec3 { - UVec3::new(self.w, self.x, self.x) - } - #[inline] - fn wxy(self) -> UVec3 { - UVec3::new(self.w, self.x, self.y) - } - #[inline] - fn wxz(self) -> UVec3 { - UVec3::new(self.w, self.x, self.z) - } - #[inline] - fn wxw(self) -> UVec3 { - UVec3::new(self.w, self.x, self.w) - } - #[inline] - fn wyx(self) -> UVec3 { - UVec3::new(self.w, self.y, self.x) - } - #[inline] - fn wyy(self) -> UVec3 { - UVec3::new(self.w, self.y, self.y) - } - #[inline] - fn wyz(self) -> UVec3 { - UVec3::new(self.w, self.y, self.z) - } - #[inline] - fn wyw(self) -> UVec3 { - UVec3::new(self.w, self.y, self.w) - } - #[inline] - fn wzx(self) -> UVec3 { - UVec3::new(self.w, self.z, self.x) - } - #[inline] - fn wzy(self) -> UVec3 { - UVec3::new(self.w, self.z, self.y) - } - #[inline] - fn wzz(self) -> UVec3 { - UVec3::new(self.w, self.z, self.z) - } - #[inline] - fn wzw(self) -> UVec3 { - UVec3::new(self.w, self.z, self.w) - } - #[inline] - fn wwx(self) -> UVec3 { - UVec3::new(self.w, self.w, self.x) - } - #[inline] - fn wwy(self) -> UVec3 { - UVec3::new(self.w, self.w, self.y) - } - #[inline] - fn wwz(self) -> UVec3 { - UVec3::new(self.w, self.w, self.z) - } - #[inline] - fn www(self) -> UVec3 { - UVec3::new(self.w, self.w, self.w) - } - #[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 xw(self) -> UVec2 { - UVec2::new(self.x, self.w) - } - #[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 yw(self) -> UVec2 { - UVec2::new(self.y, self.w) - } - #[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) - } - #[inline] - fn zw(self) -> UVec2 { - UVec2::new(self.z, self.w) - } - #[inline] - fn wx(self) -> UVec2 { - UVec2::new(self.w, self.x) - } - #[inline] - fn wy(self) -> UVec2 { - UVec2::new(self.w, self.y) - } - #[inline] - fn wz(self) -> UVec2 { - UVec2::new(self.w, self.z) - } - #[inline] - fn ww(self) -> UVec2 { - UVec2::new(self.w, self.w) - } -} diff --git a/src/swizzles/vec2_impl.rs b/src/swizzles/vec2_impl.rs new file mode 100644 index 0000000..4842194 --- /dev/null +++ b/src/swizzles/vec2_impl.rs @@ -0,0 +1,193 @@ +// Generated from swizzle_impl.rs.tera template. Edit the template, not the generated file. + +use crate::{Vec2, Vec2Swizzles, 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) + } +} diff --git a/src/swizzles/vec2_impl_scalar.rs b/src/swizzles/vec2_impl_scalar.rs deleted file mode 100644 index 9968553..0000000 --- a/src/swizzles/vec2_impl_scalar.rs +++ /dev/null @@ -1,118 +0,0 @@ -// Generated by swizzlegen. Do not edit. - -use super::Vec2Swizzles; -use crate::{Vec2, Vec3, Vec4}; - -impl Vec2Swizzles for Vec2 { - type Vec3 = Vec3; - type Vec4 = Vec4; - - #[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.rs b/src/swizzles/vec3_impl.rs new file mode 100644 index 0000000..e60e8e1 --- /dev/null +++ b/src/swizzles/vec3_impl.rs @@ -0,0 +1,729 @@ +// Generated from swizzle_impl.rs.tera template. Edit the template, not the generated file. + +use crate::{Vec2, Vec3, Vec3Swizzles, 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) + } +} diff --git a/src/swizzles/vec3_impl_scalar.rs b/src/swizzles/vec3_impl_scalar.rs deleted file mode 100644 index 83d7418..0000000 --- a/src/swizzles/vec3_impl_scalar.rs +++ /dev/null @@ -1,474 +0,0 @@ -// Generated by swizzlegen. Do not edit. - -use super::Vec3Swizzles; -use crate::{Vec2, Vec3, Vec4}; - -impl Vec3Swizzles for Vec3 { - type Vec2 = Vec2; - type Vec4 = Vec4; - - #[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 deleted file mode 100644 index a1aaac3..0000000 --- a/src/swizzles/vec3a_impl_scalar.rs +++ /dev/null @@ -1,474 +0,0 @@ -// Generated by swizzlegen. Do not edit. - -use super::Vec3Swizzles; -use crate::{Vec2, Vec3A, Vec4}; - -impl Vec3Swizzles for Vec3A { - type Vec2 = Vec2; - type Vec4 = Vec4; - - #[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 deleted file mode 100644 index 275ad70..0000000 --- a/src/swizzles/vec3a_impl_sse2.rs +++ /dev/null @@ -1,479 +0,0 @@ -// Generated by swizzlegen. Do not edit. - -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::*; - -impl Vec3Swizzles for Vec3A { - type Vec2 = Vec2; - type Vec4 = Vec4; - - #[inline] - fn xxxx(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn xxxz(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn xxyy(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn xxzx(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn xxzz(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn xyxy(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn xyyx(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn xyyz(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn xyzy(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn xzxx(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn xzxz(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn xzyy(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn xzzx(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn xzzz(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn yxxy(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn yxyx(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn yxyz(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn yxzy(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn yyxx(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn yyxz(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn yyyy(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn yyzx(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn yyzz(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn yzxy(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn yzyx(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn yzyz(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn yzzy(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn zxxx(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn zxxz(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn zxyy(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn zxzx(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn zxzz(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn zyxy(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn zyyx(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn zyyz(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn zyzy(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn zzxx(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn zzxz(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn zzyy(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn zzzx(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[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))) } - } -} diff --git a/src/swizzles/vec3a_impl_wasm32.rs b/src/swizzles/vec3a_impl_wasm32.rs deleted file mode 100644 index fa5e01a..0000000 --- a/src/swizzles/vec3a_impl_wasm32.rs +++ /dev/null @@ -1,476 +0,0 @@ -// Generated by swizzlegen. Do not edit. - -use super::Vec3Swizzles; -use crate::{Vec2, Vec3A, Vec4, XY}; - -use core::arch::wasm32::*; - -impl Vec3Swizzles for Vec3A { - type Vec2 = Vec2; - type Vec4 = Vec4; - - #[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 deleted file mode 100644 index 19f97a7..0000000 --- a/src/swizzles/vec4_impl_scalar.rs +++ /dev/null @@ -1,1350 +0,0 @@ -// Generated by swizzlegen. Do not edit. - -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) - } - #[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 xxxw(self) -> Vec4 { - Vec4::new(self.x, self.x, self.x, self.w) - } - #[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 xxyw(self) -> Vec4 { - Vec4::new(self.x, self.x, self.y, self.w) - } - #[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 xxzw(self) -> Vec4 { - Vec4::new(self.x, self.x, self.z, self.w) - } - #[inline] - fn xxwx(self) -> Vec4 { - Vec4::new(self.x, self.x, self.w, self.x) - } - #[inline] - fn xxwy(self) -> Vec4 { - Vec4::new(self.x, self.x, self.w, self.y) - } - #[inline] - fn xxwz(self) -> Vec4 { - Vec4::new(self.x, self.x, self.w, self.z) - } - #[inline] - fn xxww(self) -> Vec4 { - Vec4::new(self.x, self.x, self.w, self.w) - } - #[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 xyxw(self) -> Vec4 { - Vec4::new(self.x, self.y, self.x, self.w) - } - #[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 xyyw(self) -> Vec4 { - Vec4::new(self.x, self.y, self.y, self.w) - } - #[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 xywx(self) -> Vec4 { - Vec4::new(self.x, self.y, self.w, self.x) - } - #[inline] - fn xywy(self) -> Vec4 { - Vec4::new(self.x, self.y, self.w, self.y) - } - #[inline] - fn xywz(self) -> Vec4 { - Vec4::new(self.x, self.y, self.w, self.z) - } - #[inline] - fn xyww(self) -> Vec4 { - Vec4::new(self.x, self.y, self.w, self.w) - } - #[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 xzxw(self) -> Vec4 { - Vec4::new(self.x, self.z, self.x, self.w) - } - #[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 xzyw(self) -> Vec4 { - Vec4::new(self.x, self.z, self.y, self.w) - } - #[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 xzzw(self) -> Vec4 { - Vec4::new(self.x, self.z, self.z, self.w) - } - #[inline] - fn xzwx(self) -> Vec4 { - Vec4::new(self.x, self.z, self.w, self.x) - } - #[inline] - fn xzwy(self) -> Vec4 { - Vec4::new(self.x, self.z, self.w, self.y) - } - #[inline] - fn xzwz(self) -> Vec4 { - Vec4::new(self.x, self.z, self.w, self.z) - } - #[inline] - fn xzww(self) -> Vec4 { - Vec4::new(self.x, self.z, self.w, self.w) - } - #[inline] - fn xwxx(self) -> Vec4 { - Vec4::new(self.x, self.w, self.x, self.x) - } - #[inline] - fn xwxy(self) -> Vec4 { - Vec4::new(self.x, self.w, self.x, self.y) - } - #[inline] - fn xwxz(self) -> Vec4 { - Vec4::new(self.x, self.w, self.x, self.z) - } - #[inline] - fn xwxw(self) -> Vec4 { - Vec4::new(self.x, self.w, self.x, self.w) - } - #[inline] - fn xwyx(self) -> Vec4 { - Vec4::new(self.x, self.w, self.y, self.x) - } - #[inline] - fn xwyy(self) -> Vec4 { - Vec4::new(self.x, self.w, self.y, self.y) - } - #[inline] - fn xwyz(self) -> Vec4 { - Vec4::new(self.x, self.w, self.y, self.z) - } - #[inline] - fn xwyw(self) -> Vec4 { - Vec4::new(self.x, self.w, self.y, self.w) - } - #[inline] - fn xwzx(self) -> Vec4 { - Vec4::new(self.x, self.w, self.z, self.x) - } - #[inline] - fn xwzy(self) -> Vec4 { - Vec4::new(self.x, self.w, self.z, self.y) - } - #[inline] - fn xwzz(self) -> Vec4 { - Vec4::new(self.x, self.w, self.z, self.z) - } - #[inline] - fn xwzw(self) -> Vec4 { - Vec4::new(self.x, self.w, self.z, self.w) - } - #[inline] - fn xwwx(self) -> Vec4 { - Vec4::new(self.x, self.w, self.w, self.x) - } - #[inline] - fn xwwy(self) -> Vec4 { - Vec4::new(self.x, self.w, self.w, self.y) - } - #[inline] - fn xwwz(self) -> Vec4 { - Vec4::new(self.x, self.w, self.w, self.z) - } - #[inline] - fn xwww(self) -> Vec4 { - Vec4::new(self.x, self.w, self.w, self.w) - } - #[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 yxxw(self) -> Vec4 { - Vec4::new(self.y, self.x, self.x, self.w) - } - #[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 yxyw(self) -> Vec4 { - Vec4::new(self.y, self.x, self.y, self.w) - } - #[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 yxzw(self) -> Vec4 { - Vec4::new(self.y, self.x, self.z, self.w) - } - #[inline] - fn yxwx(self) -> Vec4 { - Vec4::new(self.y, self.x, self.w, self.x) - } - #[inline] - fn yxwy(self) -> Vec4 { - Vec4::new(self.y, self.x, self.w, self.y) - } - #[inline] - fn yxwz(self) -> Vec4 { - Vec4::new(self.y, self.x, self.w, self.z) - } - #[inline] - fn yxww(self) -> Vec4 { - Vec4::new(self.y, self.x, self.w, self.w) - } - #[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 yyxw(self) -> Vec4 { - Vec4::new(self.y, self.y, self.x, self.w) - } - #[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 yyyw(self) -> Vec4 { - Vec4::new(self.y, self.y, self.y, self.w) - } - #[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 yyzw(self) -> Vec4 { - Vec4::new(self.y, self.y, self.z, self.w) - } - #[inline] - fn yywx(self) -> Vec4 { - Vec4::new(self.y, self.y, self.w, self.x) - } - #[inline] - fn yywy(self) -> Vec4 { - Vec4::new(self.y, self.y, self.w, self.y) - } - #[inline] - fn yywz(self) -> Vec4 { - Vec4::new(self.y, self.y, self.w, self.z) - } - #[inline] - fn yyww(self) -> Vec4 { - Vec4::new(self.y, self.y, self.w, self.w) - } - #[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 yzxw(self) -> Vec4 { - Vec4::new(self.y, self.z, self.x, self.w) - } - #[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 yzyw(self) -> Vec4 { - Vec4::new(self.y, self.z, self.y, self.w) - } - #[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 yzzw(self) -> Vec4 { - Vec4::new(self.y, self.z, self.z, self.w) - } - #[inline] - fn yzwx(self) -> Vec4 { - Vec4::new(self.y, self.z, self.w, self.x) - } - #[inline] - fn yzwy(self) -> Vec4 { - Vec4::new(self.y, self.z, self.w, self.y) - } - #[inline] - fn yzwz(self) -> Vec4 { - Vec4::new(self.y, self.z, self.w, self.z) - } - #[inline] - fn yzww(self) -> Vec4 { - Vec4::new(self.y, self.z, self.w, self.w) - } - #[inline] - fn ywxx(self) -> Vec4 { - Vec4::new(self.y, self.w, self.x, self.x) - } - #[inline] - fn ywxy(self) -> Vec4 { - Vec4::new(self.y, self.w, self.x, self.y) - } - #[inline] - fn ywxz(self) -> Vec4 { - Vec4::new(self.y, self.w, self.x, self.z) - } - #[inline] - fn ywxw(self) -> Vec4 { - Vec4::new(self.y, self.w, self.x, self.w) - } - #[inline] - fn ywyx(self) -> Vec4 { - Vec4::new(self.y, self.w, self.y, self.x) - } - #[inline] - fn ywyy(self) -> Vec4 { - Vec4::new(self.y, self.w, self.y, self.y) - } - #[inline] - fn ywyz(self) -> Vec4 { - Vec4::new(self.y, self.w, self.y, self.z) - } - #[inline] - fn ywyw(self) -> Vec4 { - Vec4::new(self.y, self.w, self.y, self.w) - } - #[inline] - fn ywzx(self) -> Vec4 { - Vec4::new(self.y, self.w, self.z, self.x) - } - #[inline] - fn ywzy(self) -> Vec4 { - Vec4::new(self.y, self.w, self.z, self.y) - } - #[inline] - fn ywzz(self) -> Vec4 { - Vec4::new(self.y, self.w, self.z, self.z) - } - #[inline] - fn ywzw(self) -> Vec4 { - Vec4::new(self.y, self.w, self.z, self.w) - } - #[inline] - fn ywwx(self) -> Vec4 { - Vec4::new(self.y, self.w, self.w, self.x) - } - #[inline] - fn ywwy(self) -> Vec4 { - Vec4::new(self.y, self.w, self.w, self.y) - } - #[inline] - fn ywwz(self) -> Vec4 { - Vec4::new(self.y, self.w, self.w, self.z) - } - #[inline] - fn ywww(self) -> Vec4 { - Vec4::new(self.y, self.w, self.w, self.w) - } - #[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 zxxw(self) -> Vec4 { - Vec4::new(self.z, self.x, self.x, self.w) - } - #[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 zxyw(self) -> Vec4 { - Vec4::new(self.z, self.x, self.y, self.w) - } - #[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 zxzw(self) -> Vec4 { - Vec4::new(self.z, self.x, self.z, self.w) - } - #[inline] - fn zxwx(self) -> Vec4 { - Vec4::new(self.z, self.x, self.w, self.x) - } - #[inline] - fn zxwy(self) -> Vec4 { - Vec4::new(self.z, self.x, self.w, self.y) - } - #[inline] - fn zxwz(self) -> Vec4 { - Vec4::new(self.z, self.x, self.w, self.z) - } - #[inline] - fn zxww(self) -> Vec4 { - Vec4::new(self.z, self.x, self.w, self.w) - } - #[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 zyxw(self) -> Vec4 { - Vec4::new(self.z, self.y, self.x, self.w) - } - #[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 zyyw(self) -> Vec4 { - Vec4::new(self.z, self.y, self.y, self.w) - } - #[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 zyzw(self) -> Vec4 { - Vec4::new(self.z, self.y, self.z, self.w) - } - #[inline] - fn zywx(self) -> Vec4 { - Vec4::new(self.z, self.y, self.w, self.x) - } - #[inline] - fn zywy(self) -> Vec4 { - Vec4::new(self.z, self.y, self.w, self.y) - } - #[inline] - fn zywz(self) -> Vec4 { - Vec4::new(self.z, self.y, self.w, self.z) - } - #[inline] - fn zyww(self) -> Vec4 { - Vec4::new(self.z, self.y, self.w, self.w) - } - #[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 zzxw(self) -> Vec4 { - Vec4::new(self.z, self.z, self.x, self.w) - } - #[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 zzyw(self) -> Vec4 { - Vec4::new(self.z, self.z, self.y, self.w) - } - #[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 zzzw(self) -> Vec4 { - Vec4::new(self.z, self.z, self.z, self.w) - } - #[inline] - fn zzwx(self) -> Vec4 { - Vec4::new(self.z, self.z, self.w, self.x) - } - #[inline] - fn zzwy(self) -> Vec4 { - Vec4::new(self.z, self.z, self.w, self.y) - } - #[inline] - fn zzwz(self) -> Vec4 { - Vec4::new(self.z, self.z, self.w, self.z) - } - #[inline] - fn zzww(self) -> Vec4 { - Vec4::new(self.z, self.z, self.w, self.w) - } - #[inline] - fn zwxx(self) -> Vec4 { - Vec4::new(self.z, self.w, self.x, self.x) - } - #[inline] - fn zwxy(self) -> Vec4 { - Vec4::new(self.z, self.w, self.x, self.y) - } - #[inline] - fn zwxz(self) -> Vec4 { - Vec4::new(self.z, self.w, self.x, self.z) - } - #[inline] - fn zwxw(self) -> Vec4 { - Vec4::new(self.z, self.w, self.x, self.w) - } - #[inline] - fn zwyx(self) -> Vec4 { - Vec4::new(self.z, self.w, self.y, self.x) - } - #[inline] - fn zwyy(self) -> Vec4 { - Vec4::new(self.z, self.w, self.y, self.y) - } - #[inline] - fn zwyz(self) -> Vec4 { - Vec4::new(self.z, self.w, self.y, self.z) - } - #[inline] - fn zwyw(self) -> Vec4 { - Vec4::new(self.z, self.w, self.y, self.w) - } - #[inline] - fn zwzx(self) -> Vec4 { - Vec4::new(self.z, self.w, self.z, self.x) - } - #[inline] - fn zwzy(self) -> Vec4 { - Vec4::new(self.z, self.w, self.z, self.y) - } - #[inline] - fn zwzz(self) -> Vec4 { - Vec4::new(self.z, self.w, self.z, self.z) - } - #[inline] - fn zwzw(self) -> Vec4 { - Vec4::new(self.z, self.w, self.z, self.w) - } - #[inline] - fn zwwx(self) -> Vec4 { - Vec4::new(self.z, self.w, self.w, self.x) - } - #[inline] - fn zwwy(self) -> Vec4 { - Vec4::new(self.z, self.w, self.w, self.y) - } - #[inline] - fn zwwz(self) -> Vec4 { - Vec4::new(self.z, self.w, self.w, self.z) - } - #[inline] - fn zwww(self) -> Vec4 { - Vec4::new(self.z, self.w, self.w, self.w) - } - #[inline] - fn wxxx(self) -> Vec4 { - Vec4::new(self.w, self.x, self.x, self.x) - } - #[inline] - fn wxxy(self) -> Vec4 { - Vec4::new(self.w, self.x, self.x, self.y) - } - #[inline] - fn wxxz(self) -> Vec4 { - Vec4::new(self.w, self.x, self.x, self.z) - } - #[inline] - fn wxxw(self) -> Vec4 { - Vec4::new(self.w, self.x, self.x, self.w) - } - #[inline] - fn wxyx(self) -> Vec4 { - Vec4::new(self.w, self.x, self.y, self.x) - } - #[inline] - fn wxyy(self) -> Vec4 { - Vec4::new(self.w, self.x, self.y, self.y) - } - #[inline] - fn wxyz(self) -> Vec4 { - Vec4::new(self.w, self.x, self.y, self.z) - } - #[inline] - fn wxyw(self) -> Vec4 { - Vec4::new(self.w, self.x, self.y, self.w) - } - #[inline] - fn wxzx(self) -> Vec4 { - Vec4::new(self.w, self.x, self.z, self.x) - } - #[inline] - fn wxzy(self) -> Vec4 { - Vec4::new(self.w, self.x, self.z, self.y) - } - #[inline] - fn wxzz(self) -> Vec4 { - Vec4::new(self.w, self.x, self.z, self.z) - } - #[inline] - fn wxzw(self) -> Vec4 { - Vec4::new(self.w, self.x, self.z, self.w) - } - #[inline] - fn wxwx(self) -> Vec4 { - Vec4::new(self.w, self.x, self.w, self.x) - } - #[inline] - fn wxwy(self) -> Vec4 { - Vec4::new(self.w, self.x, self.w, self.y) - } - #[inline] - fn wxwz(self) -> Vec4 { - Vec4::new(self.w, self.x, self.w, self.z) - } - #[inline] - fn wxww(self) -> Vec4 { - Vec4::new(self.w, self.x, self.w, self.w) - } - #[inline] - fn wyxx(self) -> Vec4 { - Vec4::new(self.w, self.y, self.x, self.x) - } - #[inline] - fn wyxy(self) -> Vec4 { - Vec4::new(self.w, self.y, self.x, self.y) - } - #[inline] - fn wyxz(self) -> Vec4 { - Vec4::new(self.w, self.y, self.x, self.z) - } - #[inline] - fn wyxw(self) -> Vec4 { - Vec4::new(self.w, self.y, self.x, self.w) - } - #[inline] - fn wyyx(self) -> Vec4 { - Vec4::new(self.w, self.y, self.y, self.x) - } - #[inline] - fn wyyy(self) -> Vec4 { - Vec4::new(self.w, self.y, self.y, self.y) - } - #[inline] - fn wyyz(self) -> Vec4 { - Vec4::new(self.w, self.y, self.y, self.z) - } - #[inline] - fn wyyw(self) -> Vec4 { - Vec4::new(self.w, self.y, self.y, self.w) - } - #[inline] - fn wyzx(self) -> Vec4 { - Vec4::new(self.w, self.y, self.z, self.x) - } - #[inline] - fn wyzy(self) -> Vec4 { - Vec4::new(self.w, self.y, self.z, self.y) - } - #[inline] - fn wyzz(self) -> Vec4 { - Vec4::new(self.w, self.y, self.z, self.z) - } - #[inline] - fn wyzw(self) -> Vec4 { - Vec4::new(self.w, self.y, self.z, self.w) - } - #[inline] - fn wywx(self) -> Vec4 { - Vec4::new(self.w, self.y, self.w, self.x) - } - #[inline] - fn wywy(self) -> Vec4 { - Vec4::new(self.w, self.y, self.w, self.y) - } - #[inline] - fn wywz(self) -> Vec4 { - Vec4::new(self.w, self.y, self.w, self.z) - } - #[inline] - fn wyww(self) -> Vec4 { - Vec4::new(self.w, self.y, self.w, self.w) - } - #[inline] - fn wzxx(self) -> Vec4 { - Vec4::new(self.w, self.z, self.x, self.x) - } - #[inline] - fn wzxy(self) -> Vec4 { - Vec4::new(self.w, self.z, self.x, self.y) - } - #[inline] - fn wzxz(self) -> Vec4 { - Vec4::new(self.w, self.z, self.x, self.z) - } - #[inline] - fn wzxw(self) -> Vec4 { - Vec4::new(self.w, self.z, self.x, self.w) - } - #[inline] - fn wzyx(self) -> Vec4 { - Vec4::new(self.w, self.z, self.y, self.x) - } - #[inline] - fn wzyy(self) -> Vec4 { - Vec4::new(self.w, self.z, self.y, self.y) - } - #[inline] - fn wzyz(self) -> Vec4 { - Vec4::new(self.w, self.z, self.y, self.z) - } - #[inline] - fn wzyw(self) -> Vec4 { - Vec4::new(self.w, self.z, self.y, self.w) - } - #[inline] - fn wzzx(self) -> Vec4 { - Vec4::new(self.w, self.z, self.z, self.x) - } - #[inline] - fn wzzy(self) -> Vec4 { - Vec4::new(self.w, self.z, self.z, self.y) - } - #[inline] - fn wzzz(self) -> Vec4 { - Vec4::new(self.w, self.z, self.z, self.z) - } - #[inline] - fn wzzw(self) -> Vec4 { - Vec4::new(self.w, self.z, self.z, self.w) - } - #[inline] - fn wzwx(self) -> Vec4 { - Vec4::new(self.w, self.z, self.w, self.x) - } - #[inline] - fn wzwy(self) -> Vec4 { - Vec4::new(self.w, self.z, self.w, self.y) - } - #[inline] - fn wzwz(self) -> Vec4 { - Vec4::new(self.w, self.z, self.w, self.z) - } - #[inline] - fn wzww(self) -> Vec4 { - Vec4::new(self.w, self.z, self.w, self.w) - } - #[inline] - fn wwxx(self) -> Vec4 { - Vec4::new(self.w, self.w, self.x, self.x) - } - #[inline] - fn wwxy(self) -> Vec4 { - Vec4::new(self.w, self.w, self.x, self.y) - } - #[inline] - fn wwxz(self) -> Vec4 { - Vec4::new(self.w, self.w, self.x, self.z) - } - #[inline] - fn wwxw(self) -> Vec4 { - Vec4::new(self.w, self.w, self.x, self.w) - } - #[inline] - fn wwyx(self) -> Vec4 { - Vec4::new(self.w, self.w, self.y, self.x) - } - #[inline] - fn wwyy(self) -> Vec4 { - Vec4::new(self.w, self.w, self.y, self.y) - } - #[inline] - fn wwyz(self) -> Vec4 { - Vec4::new(self.w, self.w, self.y, self.z) - } - #[inline] - fn wwyw(self) -> Vec4 { - Vec4::new(self.w, self.w, self.y, self.w) - } - #[inline] - fn wwzx(self) -> Vec4 { - Vec4::new(self.w, self.w, self.z, self.x) - } - #[inline] - fn wwzy(self) -> Vec4 { - Vec4::new(self.w, self.w, self.z, self.y) - } - #[inline] - fn wwzz(self) -> Vec4 { - Vec4::new(self.w, self.w, self.z, self.z) - } - #[inline] - fn wwzw(self) -> Vec4 { - Vec4::new(self.w, self.w, self.z, self.w) - } - #[inline] - fn wwwx(self) -> Vec4 { - Vec4::new(self.w, self.w, self.w, self.x) - } - #[inline] - fn wwwy(self) -> Vec4 { - Vec4::new(self.w, self.w, self.w, self.y) - } - #[inline] - fn wwwz(self) -> Vec4 { - Vec4::new(self.w, self.w, self.w, self.z) - } - #[inline] - fn wwww(self) -> Vec4 { - Vec4::new(self.w, self.w, self.w, self.w) - } - #[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 xxz(self) -> Vec3 { - Vec3::new(self.x, self.x, self.z) - } - #[inline] - fn xxw(self) -> Vec3 { - Vec3::new(self.x, self.x, self.w) - } - #[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 xyz(self) -> Vec3 { - Vec3::new(self.x, self.y, self.z) - } - #[inline] - fn xyw(self) -> Vec3 { - Vec3::new(self.x, self.y, self.w) - } - #[inline] - fn xzx(self) -> Vec3 { - Vec3::new(self.x, self.z, self.x) - } - #[inline] - fn xzy(self) -> Vec3 { - Vec3::new(self.x, self.z, self.y) - } - #[inline] - fn xzz(self) -> Vec3 { - Vec3::new(self.x, self.z, self.z) - } - #[inline] - fn xzw(self) -> Vec3 { - Vec3::new(self.x, self.z, self.w) - } - #[inline] - fn xwx(self) -> Vec3 { - Vec3::new(self.x, self.w, self.x) - } - #[inline] - fn xwy(self) -> Vec3 { - Vec3::new(self.x, self.w, self.y) - } - #[inline] - fn xwz(self) -> Vec3 { - Vec3::new(self.x, self.w, self.z) - } - #[inline] - fn xww(self) -> Vec3 { - Vec3::new(self.x, self.w, self.w) - } - #[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 yxz(self) -> Vec3 { - Vec3::new(self.y, self.x, self.z) - } - #[inline] - fn yxw(self) -> Vec3 { - Vec3::new(self.y, self.x, self.w) - } - #[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 yyz(self) -> Vec3 { - Vec3::new(self.y, self.y, self.z) - } - #[inline] - fn yyw(self) -> Vec3 { - Vec3::new(self.y, self.y, self.w) - } - #[inline] - fn yzx(self) -> Vec3 { - Vec3::new(self.y, self.z, self.x) - } - #[inline] - fn yzy(self) -> Vec3 { - Vec3::new(self.y, self.z, self.y) - } - #[inline] - fn yzz(self) -> Vec3 { - Vec3::new(self.y, self.z, self.z) - } - #[inline] - fn yzw(self) -> Vec3 { - Vec3::new(self.y, self.z, self.w) - } - #[inline] - fn ywx(self) -> Vec3 { - Vec3::new(self.y, self.w, self.x) - } - #[inline] - fn ywy(self) -> Vec3 { - Vec3::new(self.y, self.w, self.y) - } - #[inline] - fn ywz(self) -> Vec3 { - Vec3::new(self.y, self.w, self.z) - } - #[inline] - fn yww(self) -> Vec3 { - Vec3::new(self.y, self.w, self.w) - } - #[inline] - fn zxx(self) -> Vec3 { - Vec3::new(self.z, self.x, self.x) - } - #[inline] - fn zxy(self) -> Vec3 { - Vec3::new(self.z, self.x, self.y) - } - #[inline] - fn zxz(self) -> Vec3 { - Vec3::new(self.z, self.x, self.z) - } - #[inline] - fn zxw(self) -> Vec3 { - Vec3::new(self.z, self.x, self.w) - } - #[inline] - fn zyx(self) -> Vec3 { - Vec3::new(self.z, self.y, self.x) - } - #[inline] - fn zyy(self) -> Vec3 { - Vec3::new(self.z, self.y, self.y) - } - #[inline] - fn zyz(self) -> Vec3 { - Vec3::new(self.z, self.y, self.z) - } - #[inline] - fn zyw(self) -> Vec3 { - Vec3::new(self.z, self.y, self.w) - } - #[inline] - fn zzx(self) -> Vec3 { - Vec3::new(self.z, self.z, self.x) - } - #[inline] - fn zzy(self) -> Vec3 { - Vec3::new(self.z, self.z, self.y) - } - #[inline] - fn zzz(self) -> Vec3 { - Vec3::new(self.z, self.z, self.z) - } - #[inline] - fn zzw(self) -> Vec3 { - Vec3::new(self.z, self.z, self.w) - } - #[inline] - fn zwx(self) -> Vec3 { - Vec3::new(self.z, self.w, self.x) - } - #[inline] - fn zwy(self) -> Vec3 { - Vec3::new(self.z, self.w, self.y) - } - #[inline] - fn zwz(self) -> Vec3 { - Vec3::new(self.z, self.w, self.z) - } - #[inline] - fn zww(self) -> Vec3 { - Vec3::new(self.z, self.w, self.w) - } - #[inline] - fn wxx(self) -> Vec3 { - Vec3::new(self.w, self.x, self.x) - } - #[inline] - fn wxy(self) -> Vec3 { - Vec3::new(self.w, self.x, self.y) - } - #[inline] - fn wxz(self) -> Vec3 { - Vec3::new(self.w, self.x, self.z) - } - #[inline] - fn wxw(self) -> Vec3 { - Vec3::new(self.w, self.x, self.w) - } - #[inline] - fn wyx(self) -> Vec3 { - Vec3::new(self.w, self.y, self.x) - } - #[inline] - fn wyy(self) -> Vec3 { - Vec3::new(self.w, self.y, self.y) - } - #[inline] - fn wyz(self) -> Vec3 { - Vec3::new(self.w, self.y, self.z) - } - #[inline] - fn wyw(self) -> Vec3 { - Vec3::new(self.w, self.y, self.w) - } - #[inline] - fn wzx(self) -> Vec3 { - Vec3::new(self.w, self.z, self.x) - } - #[inline] - fn wzy(self) -> Vec3 { - Vec3::new(self.w, self.z, self.y) - } - #[inline] - fn wzz(self) -> Vec3 { - Vec3::new(self.w, self.z, self.z) - } - #[inline] - fn wzw(self) -> Vec3 { - Vec3::new(self.w, self.z, self.w) - } - #[inline] - fn wwx(self) -> Vec3 { - Vec3::new(self.w, self.w, self.x) - } - #[inline] - fn wwy(self) -> Vec3 { - Vec3::new(self.w, self.w, self.y) - } - #[inline] - fn wwz(self) -> Vec3 { - Vec3::new(self.w, self.w, self.z) - } - #[inline] - fn www(self) -> Vec3 { - Vec3::new(self.w, self.w, self.w) - } - #[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 xw(self) -> Vec2 { - Vec2::new(self.x, self.w) - } - #[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 yw(self) -> Vec2 { - Vec2::new(self.y, self.w) - } - #[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) - } - #[inline] - fn zw(self) -> Vec2 { - Vec2::new(self.z, self.w) - } - #[inline] - fn wx(self) -> Vec2 { - Vec2::new(self.w, self.x) - } - #[inline] - fn wy(self) -> Vec2 { - Vec2::new(self.w, self.y) - } - #[inline] - fn wz(self) -> Vec2 { - Vec2::new(self.w, self.z) - } - #[inline] - fn ww(self) -> Vec2 { - Vec2::new(self.w, self.w) - } -} diff --git a/src/swizzles/vec4_impl_sse2.rs b/src/swizzles/vec4_impl_sse2.rs deleted file mode 100644 index ac8d942..0000000 --- a/src/swizzles/vec4_impl_sse2.rs +++ /dev/null @@ -1,1355 +0,0 @@ -// Generated by swizzlegen. Do not edit. - -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::*; - -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)) } - } - #[inline] - fn xxxy(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn xxxw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_00_00_00)) } - } - #[inline] - fn xxyx(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn xxyz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_01_00_00)) } - } - #[inline] - fn xxyw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_01_00_00)) } - } - #[inline] - fn xxzx(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn xxzz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_10_00_00)) } - } - #[inline] - fn xxzw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_10_00_00)) } - } - #[inline] - fn xxwx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_11_00_00)) } - } - #[inline] - fn xxwy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_11_00_00)) } - } - #[inline] - fn xxwz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_11_00_00)) } - } - #[inline] - fn xxww(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_11_00_00)) } - } - #[inline] - fn xyxx(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn xyxz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_00_01_00)) } - } - #[inline] - fn xyxw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_00_01_00)) } - } - #[inline] - fn xyyx(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn xyyz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_01_01_00)) } - } - #[inline] - fn xyyw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_01_01_00)) } - } - #[inline] - fn xyzx(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn xyzz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_10_01_00)) } - } - #[inline] - fn xywx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_11_01_00)) } - } - #[inline] - fn xywy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_11_01_00)) } - } - #[inline] - fn xywz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_11_01_00)) } - } - #[inline] - fn xyww(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_11_01_00)) } - } - #[inline] - fn xzxx(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn xzxz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_00_10_00)) } - } - #[inline] - fn xzxw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_00_10_00)) } - } - #[inline] - fn xzyx(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn xzyz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_01_10_00)) } - } - #[inline] - fn xzyw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_01_10_00)) } - } - #[inline] - fn xzzx(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn xzzz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_10_10_00)) } - } - #[inline] - fn xzzw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_10_10_00)) } - } - #[inline] - fn xzwx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_11_10_00)) } - } - #[inline] - fn xzwy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_11_10_00)) } - } - #[inline] - fn xzwz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_11_10_00)) } - } - #[inline] - fn xzww(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_11_10_00)) } - } - #[inline] - fn xwxx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_00_11_00)) } - } - #[inline] - fn xwxy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_00_11_00)) } - } - #[inline] - fn xwxz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_00_11_00)) } - } - #[inline] - fn xwxw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_00_11_00)) } - } - #[inline] - fn xwyx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_01_11_00)) } - } - #[inline] - fn xwyy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_01_11_00)) } - } - #[inline] - fn xwyz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_01_11_00)) } - } - #[inline] - fn xwyw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_01_11_00)) } - } - #[inline] - fn xwzx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_10_11_00)) } - } - #[inline] - fn xwzy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_10_11_00)) } - } - #[inline] - fn xwzz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_10_11_00)) } - } - #[inline] - fn xwzw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_10_11_00)) } - } - #[inline] - fn xwwx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_11_11_00)) } - } - #[inline] - fn xwwy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_11_11_00)) } - } - #[inline] - fn xwwz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_11_11_00)) } - } - #[inline] - fn xwww(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_11_11_00)) } - } - #[inline] - fn yxxx(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn yxxz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_00_00_01)) } - } - #[inline] - fn yxxw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_00_00_01)) } - } - #[inline] - fn yxyx(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn yxyz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_01_00_01)) } - } - #[inline] - fn yxyw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_01_00_01)) } - } - #[inline] - fn yxzx(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn yxzz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_10_00_01)) } - } - #[inline] - fn yxzw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_10_00_01)) } - } - #[inline] - fn yxwx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_11_00_01)) } - } - #[inline] - fn yxwy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_11_00_01)) } - } - #[inline] - fn yxwz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_11_00_01)) } - } - #[inline] - fn yxww(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_11_00_01)) } - } - #[inline] - fn yyxx(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn yyxz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_00_01_01)) } - } - #[inline] - fn yyxw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_00_01_01)) } - } - #[inline] - fn yyyx(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn yyyz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_01_01_01)) } - } - #[inline] - fn yyyw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_01_01_01)) } - } - #[inline] - fn yyzx(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn yyzz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_10_01_01)) } - } - #[inline] - fn yyzw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_10_01_01)) } - } - #[inline] - fn yywx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_11_01_01)) } - } - #[inline] - fn yywy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_11_01_01)) } - } - #[inline] - fn yywz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_11_01_01)) } - } - #[inline] - fn yyww(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_11_01_01)) } - } - #[inline] - fn yzxx(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn yzxz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_00_10_01)) } - } - #[inline] - fn yzxw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_00_10_01)) } - } - #[inline] - fn yzyx(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn yzyz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_01_10_01)) } - } - #[inline] - fn yzyw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_01_10_01)) } - } - #[inline] - fn yzzx(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn yzzz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_10_10_01)) } - } - #[inline] - fn yzzw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_10_10_01)) } - } - #[inline] - fn yzwx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_11_10_01)) } - } - #[inline] - fn yzwy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_11_10_01)) } - } - #[inline] - fn yzwz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_11_10_01)) } - } - #[inline] - fn yzww(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_11_10_01)) } - } - #[inline] - fn ywxx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_00_11_01)) } - } - #[inline] - fn ywxy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_00_11_01)) } - } - #[inline] - fn ywxz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_00_11_01)) } - } - #[inline] - fn ywxw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_00_11_01)) } - } - #[inline] - fn ywyx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_01_11_01)) } - } - #[inline] - fn ywyy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_01_11_01)) } - } - #[inline] - fn ywyz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_01_11_01)) } - } - #[inline] - fn ywyw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_01_11_01)) } - } - #[inline] - fn ywzx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_10_11_01)) } - } - #[inline] - fn ywzy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_10_11_01)) } - } - #[inline] - fn ywzz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_10_11_01)) } - } - #[inline] - fn ywzw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_10_11_01)) } - } - #[inline] - fn ywwx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_11_11_01)) } - } - #[inline] - fn ywwy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_11_11_01)) } - } - #[inline] - fn ywwz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_11_11_01)) } - } - #[inline] - fn ywww(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_11_11_01)) } - } - #[inline] - fn zxxx(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn zxxz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_00_00_10)) } - } - #[inline] - fn zxxw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_00_00_10)) } - } - #[inline] - fn zxyx(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn zxyz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_01_00_10)) } - } - #[inline] - fn zxyw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_01_00_10)) } - } - #[inline] - fn zxzx(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn zxzz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_10_00_10)) } - } - #[inline] - fn zxzw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_10_00_10)) } - } - #[inline] - fn zxwx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_11_00_10)) } - } - #[inline] - fn zxwy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_11_00_10)) } - } - #[inline] - fn zxwz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_11_00_10)) } - } - #[inline] - fn zxww(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_11_00_10)) } - } - #[inline] - fn zyxx(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn zyxz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_00_01_10)) } - } - #[inline] - fn zyxw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_00_01_10)) } - } - #[inline] - fn zyyx(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn zyyz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_01_01_10)) } - } - #[inline] - fn zyyw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_01_01_10)) } - } - #[inline] - fn zyzx(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn zyzz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_10_01_10)) } - } - #[inline] - fn zyzw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_10_01_10)) } - } - #[inline] - fn zywx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_11_01_10)) } - } - #[inline] - fn zywy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_11_01_10)) } - } - #[inline] - fn zywz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_11_01_10)) } - } - #[inline] - fn zyww(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_11_01_10)) } - } - #[inline] - fn zzxx(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn zzxz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_00_10_10)) } - } - #[inline] - fn zzxw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_00_10_10)) } - } - #[inline] - fn zzyx(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn zzyz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_01_10_10)) } - } - #[inline] - fn zzyw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_01_10_10)) } - } - #[inline] - fn zzzx(self) -> Vec4 { - unsafe { Vec4(_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)) } - } - #[inline] - fn zzzz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_10_10_10)) } - } - #[inline] - fn zzzw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_10_10_10)) } - } - #[inline] - fn zzwx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_11_10_10)) } - } - #[inline] - fn zzwy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_11_10_10)) } - } - #[inline] - fn zzwz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_11_10_10)) } - } - #[inline] - fn zzww(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_11_10_10)) } - } - #[inline] - fn zwxx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_00_11_10)) } - } - #[inline] - fn zwxy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_00_11_10)) } - } - #[inline] - fn zwxz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_00_11_10)) } - } - #[inline] - fn zwxw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_00_11_10)) } - } - #[inline] - fn zwyx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_01_11_10)) } - } - #[inline] - fn zwyy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_01_11_10)) } - } - #[inline] - fn zwyz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_01_11_10)) } - } - #[inline] - fn zwyw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_01_11_10)) } - } - #[inline] - fn zwzx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_10_11_10)) } - } - #[inline] - fn zwzy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_10_11_10)) } - } - #[inline] - fn zwzz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_10_11_10)) } - } - #[inline] - fn zwzw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_10_11_10)) } - } - #[inline] - fn zwwx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_11_11_10)) } - } - #[inline] - fn zwwy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_11_11_10)) } - } - #[inline] - fn zwwz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_11_11_10)) } - } - #[inline] - fn zwww(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_11_11_10)) } - } - #[inline] - fn wxxx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_00_00_11)) } - } - #[inline] - fn wxxy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_00_00_11)) } - } - #[inline] - fn wxxz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_00_00_11)) } - } - #[inline] - fn wxxw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_00_00_11)) } - } - #[inline] - fn wxyx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_01_00_11)) } - } - #[inline] - fn wxyy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_01_00_11)) } - } - #[inline] - fn wxyz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_01_00_11)) } - } - #[inline] - fn wxyw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_01_00_11)) } - } - #[inline] - fn wxzx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_10_00_11)) } - } - #[inline] - fn wxzy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_10_00_11)) } - } - #[inline] - fn wxzz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_10_00_11)) } - } - #[inline] - fn wxzw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_10_00_11)) } - } - #[inline] - fn wxwx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_11_00_11)) } - } - #[inline] - fn wxwy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_11_00_11)) } - } - #[inline] - fn wxwz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_11_00_11)) } - } - #[inline] - fn wxww(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_11_00_11)) } - } - #[inline] - fn wyxx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_00_01_11)) } - } - #[inline] - fn wyxy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_00_01_11)) } - } - #[inline] - fn wyxz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_00_01_11)) } - } - #[inline] - fn wyxw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_00_01_11)) } - } - #[inline] - fn wyyx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_01_01_11)) } - } - #[inline] - fn wyyy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_01_01_11)) } - } - #[inline] - fn wyyz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_01_01_11)) } - } - #[inline] - fn wyyw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_01_01_11)) } - } - #[inline] - fn wyzx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_10_01_11)) } - } - #[inline] - fn wyzy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_10_01_11)) } - } - #[inline] - fn wyzz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_10_01_11)) } - } - #[inline] - fn wyzw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_10_01_11)) } - } - #[inline] - fn wywx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_11_01_11)) } - } - #[inline] - fn wywy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_11_01_11)) } - } - #[inline] - fn wywz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_11_01_11)) } - } - #[inline] - fn wyww(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_11_01_11)) } - } - #[inline] - fn wzxx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_00_10_11)) } - } - #[inline] - fn wzxy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_00_10_11)) } - } - #[inline] - fn wzxz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_00_10_11)) } - } - #[inline] - fn wzxw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_00_10_11)) } - } - #[inline] - fn wzyx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_01_10_11)) } - } - #[inline] - fn wzyy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_01_10_11)) } - } - #[inline] - fn wzyz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_01_10_11)) } - } - #[inline] - fn wzyw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_01_10_11)) } - } - #[inline] - fn wzzx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_10_10_11)) } - } - #[inline] - fn wzzy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_10_10_11)) } - } - #[inline] - fn wzzz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_10_10_11)) } - } - #[inline] - fn wzzw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_10_10_11)) } - } - #[inline] - fn wzwx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_11_10_11)) } - } - #[inline] - fn wzwy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_11_10_11)) } - } - #[inline] - fn wzwz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_11_10_11)) } - } - #[inline] - fn wzww(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_11_10_11)) } - } - #[inline] - fn wwxx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_00_11_11)) } - } - #[inline] - fn wwxy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_00_11_11)) } - } - #[inline] - fn wwxz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_00_11_11)) } - } - #[inline] - fn wwxw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_00_11_11)) } - } - #[inline] - fn wwyx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_01_11_11)) } - } - #[inline] - fn wwyy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_01_11_11)) } - } - #[inline] - fn wwyz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_01_11_11)) } - } - #[inline] - fn wwyw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_01_11_11)) } - } - #[inline] - fn wwzx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_10_11_11)) } - } - #[inline] - fn wwzy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_10_11_11)) } - } - #[inline] - fn wwzz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_10_11_11)) } - } - #[inline] - fn wwzw(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_10_11_11)) } - } - #[inline] - fn wwwx(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b00_11_11_11)) } - } - #[inline] - fn wwwy(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b01_11_11_11)) } - } - #[inline] - fn wwwz(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b10_11_11_11)) } - } - #[inline] - fn wwww(self) -> Vec4 { - unsafe { Vec4(_mm_shuffle_ps(self.0, self.0, 0b11_11_11_11)) } - } - #[inline] - fn xxx(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_00_00))) } - } - #[inline] - fn xxy(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_01_00_00))) } - } - #[inline] - fn xxz(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_10_00_00))) } - } - #[inline] - fn xxw(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_11_00_00))) } - } - #[inline] - fn xyx(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_01_00))) } - } - #[inline] - fn xyy(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_01_01_00))) } - } - #[inline] - fn xyz(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_10_01_00))) } - } - #[inline] - fn xyw(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_11_01_00))) } - } - #[inline] - fn xzx(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_10_00))) } - } - #[inline] - fn xzy(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_01_10_00))) } - } - #[inline] - fn xzz(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_10_10_00))) } - } - #[inline] - fn xzw(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_11_10_00))) } - } - #[inline] - fn xwx(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_11_00))) } - } - #[inline] - fn xwy(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_01_11_00))) } - } - #[inline] - fn xwz(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_10_11_00))) } - } - #[inline] - fn xww(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_11_11_00))) } - } - #[inline] - fn yxx(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_00_01))) } - } - #[inline] - fn yxy(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_01_00_01))) } - } - #[inline] - fn yxz(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_10_00_01))) } - } - #[inline] - fn yxw(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_11_00_01))) } - } - #[inline] - fn yyx(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_01_01))) } - } - #[inline] - fn yyy(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_01_01_01))) } - } - #[inline] - fn yyz(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_10_01_01))) } - } - #[inline] - fn yyw(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_11_01_01))) } - } - #[inline] - fn yzx(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_10_01))) } - } - #[inline] - fn yzy(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_01_10_01))) } - } - #[inline] - fn yzz(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_10_10_01))) } - } - #[inline] - fn yzw(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_11_10_01))) } - } - #[inline] - fn ywx(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_11_01))) } - } - #[inline] - fn ywy(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_01_11_01))) } - } - #[inline] - fn ywz(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_10_11_01))) } - } - #[inline] - fn yww(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_11_11_01))) } - } - #[inline] - fn zxx(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_00_10))) } - } - #[inline] - fn zxy(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_01_00_10))) } - } - #[inline] - fn zxz(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_10_00_10))) } - } - #[inline] - fn zxw(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_11_00_10))) } - } - #[inline] - fn zyx(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_01_10))) } - } - #[inline] - fn zyy(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_01_01_10))) } - } - #[inline] - fn zyz(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_10_01_10))) } - } - #[inline] - fn zyw(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_11_01_10))) } - } - #[inline] - fn zzx(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_10_10))) } - } - #[inline] - fn zzy(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_01_10_10))) } - } - #[inline] - fn zzz(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_10_10_10))) } - } - #[inline] - fn zzw(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_11_10_10))) } - } - #[inline] - fn zwx(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_11_10))) } - } - #[inline] - fn zwy(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_01_11_10))) } - } - #[inline] - fn zwz(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_10_11_10))) } - } - #[inline] - fn zww(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_11_11_10))) } - } - #[inline] - fn wxx(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_00_11))) } - } - #[inline] - fn wxy(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_01_00_11))) } - } - #[inline] - fn wxz(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_10_00_11))) } - } - #[inline] - fn wxw(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_11_00_11))) } - } - #[inline] - fn wyx(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_01_11))) } - } - #[inline] - fn wyy(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_01_01_11))) } - } - #[inline] - fn wyz(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_10_01_11))) } - } - #[inline] - fn wyw(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_11_01_11))) } - } - #[inline] - fn wzx(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_10_11))) } - } - #[inline] - fn wzy(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_01_10_11))) } - } - #[inline] - fn wzz(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_10_10_11))) } - } - #[inline] - fn wzw(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_11_10_11))) } - } - #[inline] - fn wwx(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_11_11))) } - } - #[inline] - fn wwy(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_01_11_11))) } - } - #[inline] - fn wwz(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_10_11_11))) } - } - #[inline] - fn www(self) -> Vec3 { - unsafe { Vec3(XYZ::from(_mm_shuffle_ps(self.0, self.0, 0b00_11_11_11))) } - } - #[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 xw(self) -> Vec2 { - unsafe { Vec2(XY::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_11_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 yw(self) -> Vec2 { - unsafe { Vec2(XY::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_11_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))) } - } - #[inline] - fn zw(self) -> Vec2 { - unsafe { Vec2(XY::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_11_10))) } - } - #[inline] - fn wx(self) -> Vec2 { - unsafe { Vec2(XY::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_00_11))) } - } - #[inline] - fn wy(self) -> Vec2 { - unsafe { Vec2(XY::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_01_11))) } - } - #[inline] - fn wz(self) -> Vec2 { - unsafe { Vec2(XY::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_10_11))) } - } - #[inline] - fn ww(self) -> Vec2 { - unsafe { Vec2(XY::from(_mm_shuffle_ps(self.0, self.0, 0b00_00_11_11))) } - } -} diff --git a/src/swizzles/vec4_impl_wasm32.rs b/src/swizzles/vec4_impl_wasm32.rs deleted file mode 100644 index 46c7a22..0000000 --- a/src/swizzles/vec4_impl_wasm32.rs +++ /dev/null @@ -1,1352 +0,0 @@ -// Generated by swizzlegen. Do not edit. - -use super::Vec4Swizzles; -use crate::{Vec2, Vec3, Vec4, XY, XYZ}; - -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)) - } - #[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 xxxw(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 0, 4, 7>(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 xxyw(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 0, 5, 7>(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 xxzw(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 0, 6, 7>(self.0, self.0)) - } - #[inline] - fn xxwx(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 0, 7, 4>(self.0, self.0)) - } - #[inline] - fn xxwy(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 0, 7, 5>(self.0, self.0)) - } - #[inline] - fn xxwz(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 0, 7, 6>(self.0, self.0)) - } - #[inline] - fn xxww(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 0, 7, 7>(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 xyxw(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 1, 4, 7>(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 xyyw(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 1, 5, 7>(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 xywx(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 1, 7, 4>(self.0, self.0)) - } - #[inline] - fn xywy(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 1, 7, 5>(self.0, self.0)) - } - #[inline] - fn xywz(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 1, 7, 6>(self.0, self.0)) - } - #[inline] - fn xyww(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 1, 7, 7>(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 xzxw(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 2, 4, 7>(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 xzyw(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 2, 5, 7>(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 xzzw(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 2, 6, 7>(self.0, self.0)) - } - #[inline] - fn xzwx(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 2, 7, 4>(self.0, self.0)) - } - #[inline] - fn xzwy(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 2, 7, 5>(self.0, self.0)) - } - #[inline] - fn xzwz(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 2, 7, 6>(self.0, self.0)) - } - #[inline] - fn xzww(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 2, 7, 7>(self.0, self.0)) - } - #[inline] - fn xwxx(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 3, 4, 4>(self.0, self.0)) - } - #[inline] - fn xwxy(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 3, 4, 5>(self.0, self.0)) - } - #[inline] - fn xwxz(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 3, 4, 6>(self.0, self.0)) - } - #[inline] - fn xwxw(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 3, 4, 7>(self.0, self.0)) - } - #[inline] - fn xwyx(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 3, 5, 4>(self.0, self.0)) - } - #[inline] - fn xwyy(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 3, 5, 5>(self.0, self.0)) - } - #[inline] - fn xwyz(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 3, 5, 6>(self.0, self.0)) - } - #[inline] - fn xwyw(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 3, 5, 7>(self.0, self.0)) - } - #[inline] - fn xwzx(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 3, 6, 4>(self.0, self.0)) - } - #[inline] - fn xwzy(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 3, 6, 5>(self.0, self.0)) - } - #[inline] - fn xwzz(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 3, 6, 6>(self.0, self.0)) - } - #[inline] - fn xwzw(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 3, 6, 7>(self.0, self.0)) - } - #[inline] - fn xwwx(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 3, 7, 4>(self.0, self.0)) - } - #[inline] - fn xwwy(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 3, 7, 5>(self.0, self.0)) - } - #[inline] - fn xwwz(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 3, 7, 6>(self.0, self.0)) - } - #[inline] - fn xwww(self) -> Vec4 { - Vec4(i32x4_shuffle::<0, 3, 7, 7>(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 yxxw(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 0, 4, 7>(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 yxyw(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 0, 5, 7>(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 yxzw(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 0, 6, 7>(self.0, self.0)) - } - #[inline] - fn yxwx(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 0, 7, 4>(self.0, self.0)) - } - #[inline] - fn yxwy(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 0, 7, 5>(self.0, self.0)) - } - #[inline] - fn yxwz(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 0, 7, 6>(self.0, self.0)) - } - #[inline] - fn yxww(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 0, 7, 7>(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 yyxw(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 1, 4, 7>(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 yyyw(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 1, 5, 7>(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 yyzw(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 1, 6, 7>(self.0, self.0)) - } - #[inline] - fn yywx(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 1, 7, 4>(self.0, self.0)) - } - #[inline] - fn yywy(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 1, 7, 5>(self.0, self.0)) - } - #[inline] - fn yywz(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 1, 7, 6>(self.0, self.0)) - } - #[inline] - fn yyww(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 1, 7, 7>(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 yzxw(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 2, 4, 7>(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 yzyw(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 2, 5, 7>(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 yzzw(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 2, 6, 7>(self.0, self.0)) - } - #[inline] - fn yzwx(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 2, 7, 4>(self.0, self.0)) - } - #[inline] - fn yzwy(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 2, 7, 5>(self.0, self.0)) - } - #[inline] - fn yzwz(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 2, 7, 6>(self.0, self.0)) - } - #[inline] - fn yzww(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 2, 7, 7>(self.0, self.0)) - } - #[inline] - fn ywxx(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 3, 4, 4>(self.0, self.0)) - } - #[inline] - fn ywxy(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 3, 4, 5>(self.0, self.0)) - } - #[inline] - fn ywxz(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 3, 4, 6>(self.0, self.0)) - } - #[inline] - fn ywxw(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 3, 4, 7>(self.0, self.0)) - } - #[inline] - fn ywyx(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 3, 5, 4>(self.0, self.0)) - } - #[inline] - fn ywyy(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 3, 5, 5>(self.0, self.0)) - } - #[inline] - fn ywyz(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 3, 5, 6>(self.0, self.0)) - } - #[inline] - fn ywyw(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 3, 5, 7>(self.0, self.0)) - } - #[inline] - fn ywzx(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 3, 6, 4>(self.0, self.0)) - } - #[inline] - fn ywzy(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 3, 6, 5>(self.0, self.0)) - } - #[inline] - fn ywzz(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 3, 6, 6>(self.0, self.0)) - } - #[inline] - fn ywzw(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 3, 6, 7>(self.0, self.0)) - } - #[inline] - fn ywwx(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 3, 7, 4>(self.0, self.0)) - } - #[inline] - fn ywwy(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 3, 7, 5>(self.0, self.0)) - } - #[inline] - fn ywwz(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 3, 7, 6>(self.0, self.0)) - } - #[inline] - fn ywww(self) -> Vec4 { - Vec4(i32x4_shuffle::<1, 3, 7, 7>(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 zxxw(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 0, 4, 7>(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 zxyw(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 0, 5, 7>(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 zxzw(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 0, 6, 7>(self.0, self.0)) - } - #[inline] - fn zxwx(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 0, 7, 4>(self.0, self.0)) - } - #[inline] - fn zxwy(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 0, 7, 5>(self.0, self.0)) - } - #[inline] - fn zxwz(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 0, 7, 6>(self.0, self.0)) - } - #[inline] - fn zxww(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 0, 7, 7>(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 zyxw(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 1, 4, 7>(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 zyyw(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 1, 5, 7>(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 zyzw(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 1, 6, 7>(self.0, self.0)) - } - #[inline] - fn zywx(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 1, 7, 4>(self.0, self.0)) - } - #[inline] - fn zywy(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 1, 7, 5>(self.0, self.0)) - } - #[inline] - fn zywz(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 1, 7, 6>(self.0, self.0)) - } - #[inline] - fn zyww(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 1, 7, 7>(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 zzxw(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 2, 4, 7>(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 zzyw(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 2, 5, 7>(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 zzzw(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 2, 6, 7>(self.0, self.0)) - } - #[inline] - fn zzwx(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 2, 7, 4>(self.0, self.0)) - } - #[inline] - fn zzwy(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 2, 7, 5>(self.0, self.0)) - } - #[inline] - fn zzwz(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 2, 7, 6>(self.0, self.0)) - } - #[inline] - fn zzww(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 2, 7, 7>(self.0, self.0)) - } - #[inline] - fn zwxx(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 3, 4, 4>(self.0, self.0)) - } - #[inline] - fn zwxy(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 3, 4, 5>(self.0, self.0)) - } - #[inline] - fn zwxz(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 3, 4, 6>(self.0, self.0)) - } - #[inline] - fn zwxw(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 3, 4, 7>(self.0, self.0)) - } - #[inline] - fn zwyx(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 3, 5, 4>(self.0, self.0)) - } - #[inline] - fn zwyy(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 3, 5, 5>(self.0, self.0)) - } - #[inline] - fn zwyz(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 3, 5, 6>(self.0, self.0)) - } - #[inline] - fn zwyw(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 3, 5, 7>(self.0, self.0)) - } - #[inline] - fn zwzx(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 3, 6, 4>(self.0, self.0)) - } - #[inline] - fn zwzy(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 3, 6, 5>(self.0, self.0)) - } - #[inline] - fn zwzz(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 3, 6, 6>(self.0, self.0)) - } - #[inline] - fn zwzw(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 3, 6, 7>(self.0, self.0)) - } - #[inline] - fn zwwx(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 3, 7, 4>(self.0, self.0)) - } - #[inline] - fn zwwy(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 3, 7, 5>(self.0, self.0)) - } - #[inline] - fn zwwz(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 3, 7, 6>(self.0, self.0)) - } - #[inline] - fn zwww(self) -> Vec4 { - Vec4(i32x4_shuffle::<2, 3, 7, 7>(self.0, self.0)) - } - #[inline] - fn wxxx(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 0, 4, 4>(self.0, self.0)) - } - #[inline] - fn wxxy(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 0, 4, 5>(self.0, self.0)) - } - #[inline] - fn wxxz(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 0, 4, 6>(self.0, self.0)) - } - #[inline] - fn wxxw(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 0, 4, 7>(self.0, self.0)) - } - #[inline] - fn wxyx(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 0, 5, 4>(self.0, self.0)) - } - #[inline] - fn wxyy(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 0, 5, 5>(self.0, self.0)) - } - #[inline] - fn wxyz(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 0, 5, 6>(self.0, self.0)) - } - #[inline] - fn wxyw(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 0, 5, 7>(self.0, self.0)) - } - #[inline] - fn wxzx(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 0, 6, 4>(self.0, self.0)) - } - #[inline] - fn wxzy(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 0, 6, 5>(self.0, self.0)) - } - #[inline] - fn wxzz(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 0, 6, 6>(self.0, self.0)) - } - #[inline] - fn wxzw(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 0, 6, 7>(self.0, self.0)) - } - #[inline] - fn wxwx(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 0, 7, 4>(self.0, self.0)) - } - #[inline] - fn wxwy(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 0, 7, 5>(self.0, self.0)) - } - #[inline] - fn wxwz(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 0, 7, 6>(self.0, self.0)) - } - #[inline] - fn wxww(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 0, 7, 7>(self.0, self.0)) - } - #[inline] - fn wyxx(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 1, 4, 4>(self.0, self.0)) - } - #[inline] - fn wyxy(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 1, 4, 5>(self.0, self.0)) - } - #[inline] - fn wyxz(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 1, 4, 6>(self.0, self.0)) - } - #[inline] - fn wyxw(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 1, 4, 7>(self.0, self.0)) - } - #[inline] - fn wyyx(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 1, 5, 4>(self.0, self.0)) - } - #[inline] - fn wyyy(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 1, 5, 5>(self.0, self.0)) - } - #[inline] - fn wyyz(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 1, 5, 6>(self.0, self.0)) - } - #[inline] - fn wyyw(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 1, 5, 7>(self.0, self.0)) - } - #[inline] - fn wyzx(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 1, 6, 4>(self.0, self.0)) - } - #[inline] - fn wyzy(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 1, 6, 5>(self.0, self.0)) - } - #[inline] - fn wyzz(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 1, 6, 6>(self.0, self.0)) - } - #[inline] - fn wyzw(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 1, 6, 7>(self.0, self.0)) - } - #[inline] - fn wywx(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 1, 7, 4>(self.0, self.0)) - } - #[inline] - fn wywy(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 1, 7, 5>(self.0, self.0)) - } - #[inline] - fn wywz(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 1, 7, 6>(self.0, self.0)) - } - #[inline] - fn wyww(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 1, 7, 7>(self.0, self.0)) - } - #[inline] - fn wzxx(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 2, 4, 4>(self.0, self.0)) - } - #[inline] - fn wzxy(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 2, 4, 5>(self.0, self.0)) - } - #[inline] - fn wzxz(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 2, 4, 6>(self.0, self.0)) - } - #[inline] - fn wzxw(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 2, 4, 7>(self.0, self.0)) - } - #[inline] - fn wzyx(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 2, 5, 4>(self.0, self.0)) - } - #[inline] - fn wzyy(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 2, 5, 5>(self.0, self.0)) - } - #[inline] - fn wzyz(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 2, 5, 6>(self.0, self.0)) - } - #[inline] - fn wzyw(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 2, 5, 7>(self.0, self.0)) - } - #[inline] - fn wzzx(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 2, 6, 4>(self.0, self.0)) - } - #[inline] - fn wzzy(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 2, 6, 5>(self.0, self.0)) - } - #[inline] - fn wzzz(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 2, 6, 6>(self.0, self.0)) - } - #[inline] - fn wzzw(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 2, 6, 7>(self.0, self.0)) - } - #[inline] - fn wzwx(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 2, 7, 4>(self.0, self.0)) - } - #[inline] - fn wzwy(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 2, 7, 5>(self.0, self.0)) - } - #[inline] - fn wzwz(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 2, 7, 6>(self.0, self.0)) - } - #[inline] - fn wzww(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 2, 7, 7>(self.0, self.0)) - } - #[inline] - fn wwxx(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 3, 4, 4>(self.0, self.0)) - } - #[inline] - fn wwxy(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 3, 4, 5>(self.0, self.0)) - } - #[inline] - fn wwxz(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 3, 4, 6>(self.0, self.0)) - } - #[inline] - fn wwxw(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 3, 4, 7>(self.0, self.0)) - } - #[inline] - fn wwyx(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 3, 5, 4>(self.0, self.0)) - } - #[inline] - fn wwyy(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 3, 5, 5>(self.0, self.0)) - } - #[inline] - fn wwyz(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 3, 5, 6>(self.0, self.0)) - } - #[inline] - fn wwyw(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 3, 5, 7>(self.0, self.0)) - } - #[inline] - fn wwzx(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 3, 6, 4>(self.0, self.0)) - } - #[inline] - fn wwzy(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 3, 6, 5>(self.0, self.0)) - } - #[inline] - fn wwzz(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 3, 6, 6>(self.0, self.0)) - } - #[inline] - fn wwzw(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 3, 6, 7>(self.0, self.0)) - } - #[inline] - fn wwwx(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 3, 7, 4>(self.0, self.0)) - } - #[inline] - fn wwwy(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 3, 7, 5>(self.0, self.0)) - } - #[inline] - fn wwwz(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 3, 7, 6>(self.0, self.0)) - } - #[inline] - fn wwww(self) -> Vec4 { - Vec4(i32x4_shuffle::<3, 3, 7, 7>(self.0, self.0)) - } - #[inline] - fn xxx(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<0, 0, 4, 4>(self.0, self.0))) - } - #[inline] - fn xxy(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<0, 0, 5, 4>(self.0, self.0))) - } - #[inline] - fn xxz(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<0, 0, 6, 4>(self.0, self.0))) - } - #[inline] - fn xxw(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<0, 0, 7, 4>(self.0, self.0))) - } - #[inline] - fn xyx(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<0, 1, 4, 4>(self.0, self.0))) - } - #[inline] - fn xyy(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<0, 1, 5, 4>(self.0, self.0))) - } - #[inline] - fn xyz(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<0, 1, 6, 4>(self.0, self.0))) - } - #[inline] - fn xyw(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<0, 1, 7, 4>(self.0, self.0))) - } - #[inline] - fn xzx(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<0, 2, 4, 4>(self.0, self.0))) - } - #[inline] - fn xzy(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<0, 2, 5, 4>(self.0, self.0))) - } - #[inline] - fn xzz(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<0, 2, 6, 4>(self.0, self.0))) - } - #[inline] - fn xzw(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<0, 2, 7, 4>(self.0, self.0))) - } - #[inline] - fn xwx(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<0, 3, 4, 4>(self.0, self.0))) - } - #[inline] - fn xwy(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<0, 3, 5, 4>(self.0, self.0))) - } - #[inline] - fn xwz(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<0, 3, 6, 4>(self.0, self.0))) - } - #[inline] - fn xww(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<0, 3, 7, 4>(self.0, self.0))) - } - #[inline] - fn yxx(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<1, 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))) - } - #[inline] - fn yxz(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<1, 0, 6, 4>(self.0, self.0))) - } - #[inline] - fn yxw(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<1, 0, 7, 4>(self.0, self.0))) - } - #[inline] - fn yyx(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<1, 1, 4, 4>(self.0, self.0))) - } - #[inline] - fn yyy(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<1, 1, 5, 4>(self.0, self.0))) - } - #[inline] - fn yyz(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<1, 1, 6, 4>(self.0, self.0))) - } - #[inline] - fn yyw(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<1, 1, 7, 4>(self.0, self.0))) - } - #[inline] - fn yzx(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<1, 2, 4, 4>(self.0, self.0))) - } - #[inline] - fn yzy(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<1, 2, 5, 4>(self.0, self.0))) - } - #[inline] - fn yzz(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<1, 2, 6, 4>(self.0, self.0))) - } - #[inline] - fn yzw(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<1, 2, 7, 4>(self.0, self.0))) - } - #[inline] - fn ywx(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<1, 3, 4, 4>(self.0, self.0))) - } - #[inline] - fn ywy(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<1, 3, 5, 4>(self.0, self.0))) - } - #[inline] - fn ywz(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<1, 3, 6, 4>(self.0, self.0))) - } - #[inline] - fn yww(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<1, 3, 7, 4>(self.0, self.0))) - } - #[inline] - fn zxx(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<2, 0, 4, 4>(self.0, self.0))) - } - #[inline] - fn zxy(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<2, 0, 5, 4>(self.0, self.0))) - } - #[inline] - fn zxz(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<2, 0, 6, 4>(self.0, self.0))) - } - #[inline] - fn zxw(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<2, 0, 7, 4>(self.0, self.0))) - } - #[inline] - fn zyx(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<2, 1, 4, 4>(self.0, self.0))) - } - #[inline] - fn zyy(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<2, 1, 5, 4>(self.0, self.0))) - } - #[inline] - fn zyz(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<2, 1, 6, 4>(self.0, self.0))) - } - #[inline] - fn zyw(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<2, 1, 7, 4>(self.0, self.0))) - } - #[inline] - fn zzx(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<2, 2, 4, 4>(self.0, self.0))) - } - #[inline] - fn zzy(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<2, 2, 5, 4>(self.0, self.0))) - } - #[inline] - fn zzz(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<2, 2, 6, 4>(self.0, self.0))) - } - #[inline] - fn zzw(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<2, 2, 7, 4>(self.0, self.0))) - } - #[inline] - fn zwx(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<2, 3, 4, 4>(self.0, self.0))) - } - #[inline] - fn zwy(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<2, 3, 5, 4>(self.0, self.0))) - } - #[inline] - fn zwz(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<2, 3, 6, 4>(self.0, self.0))) - } - #[inline] - fn zww(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<2, 3, 7, 4>(self.0, self.0))) - } - #[inline] - fn wxx(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<3, 0, 4, 4>(self.0, self.0))) - } - #[inline] - fn wxy(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<3, 0, 5, 4>(self.0, self.0))) - } - #[inline] - fn wxz(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<3, 0, 6, 4>(self.0, self.0))) - } - #[inline] - fn wxw(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<3, 0, 7, 4>(self.0, self.0))) - } - #[inline] - fn wyx(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<3, 1, 4, 4>(self.0, self.0))) - } - #[inline] - fn wyy(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<3, 1, 5, 4>(self.0, self.0))) - } - #[inline] - fn wyz(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<3, 1, 6, 4>(self.0, self.0))) - } - #[inline] - fn wyw(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<3, 1, 7, 4>(self.0, self.0))) - } - #[inline] - fn wzx(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<3, 2, 4, 4>(self.0, self.0))) - } - #[inline] - fn wzy(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<3, 2, 5, 4>(self.0, self.0))) - } - #[inline] - fn wzz(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<3, 2, 6, 4>(self.0, self.0))) - } - #[inline] - fn wzw(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<3, 2, 7, 4>(self.0, self.0))) - } - #[inline] - fn wwx(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<3, 3, 4, 4>(self.0, self.0))) - } - #[inline] - fn wwy(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<3, 3, 5, 4>(self.0, self.0))) - } - #[inline] - fn wwz(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<3, 3, 6, 4>(self.0, self.0))) - } - #[inline] - fn www(self) -> Vec3 { - Vec3(XYZ::from(i32x4_shuffle::<3, 3, 7, 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 xw(self) -> Vec2 { - Vec2(XY::from(i32x4_shuffle::<0, 3, 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 yw(self) -> Vec2 { - Vec2(XY::from(i32x4_shuffle::<1, 3, 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))) - } - #[inline] - fn zw(self) -> Vec2 { - Vec2(XY::from(i32x4_shuffle::<2, 3, 4, 4>(self.0, self.0))) - } - #[inline] - fn wx(self) -> Vec2 { - Vec2(XY::from(i32x4_shuffle::<3, 0, 4, 4>(self.0, self.0))) - } - #[inline] - fn wy(self) -> Vec2 { - Vec2(XY::from(i32x4_shuffle::<3, 1, 4, 4>(self.0, self.0))) - } - #[inline] - fn wz(self) -> Vec2 { - Vec2(XY::from(i32x4_shuffle::<3, 2, 4, 4>(self.0, self.0))) - } - #[inline] - fn ww(self) -> Vec2 { - Vec2(XY::from(i32x4_shuffle::<3, 3, 4, 4>(self.0, self.0))) - } -} diff --git a/src/swizzles/vec_traits.rs b/src/swizzles/vec_traits.rs index fc9bb4a..3b95433 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.tera 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/swizzles/wasm32.rs b/src/swizzles/wasm32.rs new file mode 100644 index 0000000..10479c8 --- /dev/null +++ b/src/swizzles/wasm32.rs @@ -0,0 +1,2 @@ +mod vec3a_impl; +mod vec4_impl; diff --git a/src/swizzles/wasm32/vec3a_impl.rs b/src/swizzles/wasm32/vec3a_impl.rs new file mode 100644 index 0000000..978f494 --- /dev/null +++ b/src/swizzles/wasm32/vec3a_impl.rs @@ -0,0 +1,625 @@ +// Generated from swizzle_impl.rs.tera template. Edit the template, not the generated file. + +#![allow(clippy::useless_conversion)] + +use crate::{Vec2, Vec3A, Vec3Swizzles, 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)) + } +} diff --git a/src/swizzles/wasm32/vec4_impl.rs b/src/swizzles/wasm32/vec4_impl.rs new file mode 100644 index 0000000..73ff28f --- /dev/null +++ b/src/swizzles/wasm32/vec4_impl.rs @@ -0,0 +1,1997 @@ +// Generated from swizzle_impl.rs.tera template. Edit the template, not the generated file. + +#![allow(clippy::useless_conversion)] + +use crate::{Vec2, Vec3, Vec4, Vec4Swizzles}; + +use core::arch::wasm32::*; + +impl Vec4Swizzles for Vec4 { + type Vec2 = Vec2; + + type Vec3 = Vec3; + + #[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 xw(self) -> Vec2 { + Vec2 { + x: self.x, + y: self.w, + } + } + + #[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 yw(self) -> Vec2 { + Vec2 { + x: self.y, + y: self.w, + } + } + + #[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 zw(self) -> Vec2 { + Vec2 { + x: self.z, + y: self.w, + } + } + + #[inline] + fn wx(self) -> Vec2 { + Vec2 { + x: self.w, + y: self.x, + } + } + + #[inline] + fn wy(self) -> Vec2 { + Vec2 { + x: self.w, + y: self.y, + } + } + + #[inline] + fn wz(self) -> Vec2 { + Vec2 { + x: self.w, + y: self.z, + } + } + + #[inline] + fn ww(self) -> Vec2 { + Vec2 { + x: self.w, + y: self.w, + } + } + + #[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 xxw(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.x, + z: self.w, + } + } + + #[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 xyw(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.y, + z: self.w, + } + } + + #[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 xzw(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.z, + z: self.w, + } + } + + #[inline] + fn xwx(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.w, + z: self.x, + } + } + + #[inline] + fn xwy(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.w, + z: self.y, + } + } + + #[inline] + fn xwz(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.w, + z: self.z, + } + } + + #[inline] + fn xww(self) -> Vec3 { + Vec3 { + x: self.x, + y: self.w, + z: self.w, + } + } + + #[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 yxw(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.x, + z: self.w, + } + } + + #[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 yyw(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.y, + z: self.w, + } + } + + #[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 yzw(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.z, + z: self.w, + } + } + + #[inline] + fn ywx(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.w, + z: self.x, + } + } + + #[inline] + fn ywy(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.w, + z: self.y, + } + } + + #[inline] + fn ywz(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.w, + z: self.z, + } + } + + #[inline] + fn yww(self) -> Vec3 { + Vec3 { + x: self.y, + y: self.w, + z: self.w, + } + } + + #[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 zxw(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.x, + z: self.w, + } + } + + #[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 zyw(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.y, + z: self.w, + } + } + + #[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 zzw(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.z, + z: self.w, + } + } + + #[inline] + fn zwx(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.w, + z: self.x, + } + } + + #[inline] + fn zwy(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.w, + z: self.y, + } + } + + #[inline] + fn zwz(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.w, + z: self.z, + } + } + + #[inline] + fn zww(self) -> Vec3 { + Vec3 { + x: self.z, + y: self.w, + z: self.w, + } + } + + #[inline] + fn wxx(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.x, + z: self.x, + } + } + + #[inline] + fn wxy(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.x, + z: self.y, + } + } + + #[inline] + fn wxz(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.x, + z: self.z, + } + } + + #[inline] + fn wxw(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.x, + z: self.w, + } + } + + #[inline] + fn wyx(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.y, + z: self.x, + } + } + + #[inline] + fn wyy(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.y, + z: self.y, + } + } + + #[inline] + fn wyz(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.y, + z: self.z, + } + } + + #[inline] + fn wyw(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.y, + z: self.w, + } + } + + #[inline] + fn wzx(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.z, + z: self.x, + } + } + + #[inline] + fn wzy(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.z, + z: self.y, + } + } + + #[inline] + fn wzz(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.z, + z: self.z, + } + } + + #[inline] + fn wzw(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.z, + z: self.w, + } + } + + #[inline] + fn wwx(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.w, + z: self.x, + } + } + + #[inline] + fn wwy(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.w, + z: self.y, + } + } + + #[inline] + fn wwz(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.w, + z: self.z, + } + } + + #[inline] + fn www(self) -> Vec3 { + Vec3 { + x: self.w, + y: self.w, + z: self.w, + } + } + + #[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 xxxw(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 0, 4, 7>(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 xxyw(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 0, 5, 7>(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 xxzw(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 0, 6, 7>(self.0, self.0)) + } + + #[inline] + fn xxwx(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 0, 7, 4>(self.0, self.0)) + } + + #[inline] + fn xxwy(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 0, 7, 5>(self.0, self.0)) + } + + #[inline] + fn xxwz(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 0, 7, 6>(self.0, self.0)) + } + + #[inline] + fn xxww(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 0, 7, 7>(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 xyxw(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 1, 4, 7>(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 xyyw(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 1, 5, 7>(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 xyzw(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 1, 6, 7>(self.0, self.0)) + } + + #[inline] + fn xywx(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 1, 7, 4>(self.0, self.0)) + } + + #[inline] + fn xywy(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 1, 7, 5>(self.0, self.0)) + } + + #[inline] + fn xywz(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 1, 7, 6>(self.0, self.0)) + } + + #[inline] + fn xyww(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 1, 7, 7>(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 xzxw(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 2, 4, 7>(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 xzyw(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 2, 5, 7>(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 xzzw(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 2, 6, 7>(self.0, self.0)) + } + + #[inline] + fn xzwx(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 2, 7, 4>(self.0, self.0)) + } + + #[inline] + fn xzwy(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 2, 7, 5>(self.0, self.0)) + } + + #[inline] + fn xzwz(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 2, 7, 6>(self.0, self.0)) + } + + #[inline] + fn xzww(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 2, 7, 7>(self.0, self.0)) + } + + #[inline] + fn xwxx(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 3, 4, 4>(self.0, self.0)) + } + + #[inline] + fn xwxy(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 3, 4, 5>(self.0, self.0)) + } + + #[inline] + fn xwxz(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 3, 4, 6>(self.0, self.0)) + } + + #[inline] + fn xwxw(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 3, 4, 7>(self.0, self.0)) + } + + #[inline] + fn xwyx(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 3, 5, 4>(self.0, self.0)) + } + + #[inline] + fn xwyy(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 3, 5, 5>(self.0, self.0)) + } + + #[inline] + fn xwyz(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 3, 5, 6>(self.0, self.0)) + } + + #[inline] + fn xwyw(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 3, 5, 7>(self.0, self.0)) + } + + #[inline] + fn xwzx(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 3, 6, 4>(self.0, self.0)) + } + + #[inline] + fn xwzy(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 3, 6, 5>(self.0, self.0)) + } + + #[inline] + fn xwzz(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 3, 6, 6>(self.0, self.0)) + } + + #[inline] + fn xwzw(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 3, 6, 7>(self.0, self.0)) + } + + #[inline] + fn xwwx(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 3, 7, 4>(self.0, self.0)) + } + + #[inline] + fn xwwy(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 3, 7, 5>(self.0, self.0)) + } + + #[inline] + fn xwwz(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 3, 7, 6>(self.0, self.0)) + } + + #[inline] + fn xwww(self) -> Vec4 { + Vec4(i32x4_shuffle::<0, 3, 7, 7>(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 yxxw(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 0, 4, 7>(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 yxyw(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 0, 5, 7>(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 yxzw(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 0, 6, 7>(self.0, self.0)) + } + + #[inline] + fn yxwx(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 0, 7, 4>(self.0, self.0)) + } + + #[inline] + fn yxwy(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 0, 7, 5>(self.0, self.0)) + } + + #[inline] + fn yxwz(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 0, 7, 6>(self.0, self.0)) + } + + #[inline] + fn yxww(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 0, 7, 7>(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 yyxw(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 1, 4, 7>(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 yyyw(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 1, 5, 7>(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 yyzw(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 1, 6, 7>(self.0, self.0)) + } + + #[inline] + fn yywx(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 1, 7, 4>(self.0, self.0)) + } + + #[inline] + fn yywy(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 1, 7, 5>(self.0, self.0)) + } + + #[inline] + fn yywz(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 1, 7, 6>(self.0, self.0)) + } + + #[inline] + fn yyww(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 1, 7, 7>(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 yzxw(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 2, 4, 7>(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 yzyw(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 2, 5, 7>(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 yzzw(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 2, 6, 7>(self.0, self.0)) + } + + #[inline] + fn yzwx(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 2, 7, 4>(self.0, self.0)) + } + + #[inline] + fn yzwy(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 2, 7, 5>(self.0, self.0)) + } + + #[inline] + fn yzwz(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 2, 7, 6>(self.0, self.0)) + } + + #[inline] + fn yzww(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 2, 7, 7>(self.0, self.0)) + } + + #[inline] + fn ywxx(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 3, 4, 4>(self.0, self.0)) + } + + #[inline] + fn ywxy(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 3, 4, 5>(self.0, self.0)) + } + + #[inline] + fn ywxz(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 3, 4, 6>(self.0, self.0)) + } + + #[inline] + fn ywxw(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 3, 4, 7>(self.0, self.0)) + } + + #[inline] + fn ywyx(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 3, 5, 4>(self.0, self.0)) + } + + #[inline] + fn ywyy(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 3, 5, 5>(self.0, self.0)) + } + + #[inline] + fn ywyz(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 3, 5, 6>(self.0, self.0)) + } + + #[inline] + fn ywyw(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 3, 5, 7>(self.0, self.0)) + } + + #[inline] + fn ywzx(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 3, 6, 4>(self.0, self.0)) + } + + #[inline] + fn ywzy(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 3, 6, 5>(self.0, self.0)) + } + + #[inline] + fn ywzz(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 3, 6, 6>(self.0, self.0)) + } + + #[inline] + fn ywzw(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 3, 6, 7>(self.0, self.0)) + } + + #[inline] + fn ywwx(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 3, 7, 4>(self.0, self.0)) + } + + #[inline] + fn ywwy(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 3, 7, 5>(self.0, self.0)) + } + + #[inline] + fn ywwz(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 3, 7, 6>(self.0, self.0)) + } + + #[inline] + fn ywww(self) -> Vec4 { + Vec4(i32x4_shuffle::<1, 3, 7, 7>(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 zxxw(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 0, 4, 7>(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 zxyw(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 0, 5, 7>(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 zxzw(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 0, 6, 7>(self.0, self.0)) + } + + #[inline] + fn zxwx(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 0, 7, 4>(self.0, self.0)) + } + + #[inline] + fn zxwy(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 0, 7, 5>(self.0, self.0)) + } + + #[inline] + fn zxwz(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 0, 7, 6>(self.0, self.0)) + } + + #[inline] + fn zxww(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 0, 7, 7>(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 zyxw(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 1, 4, 7>(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 zyyw(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 1, 5, 7>(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 zyzw(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 1, 6, 7>(self.0, self.0)) + } + + #[inline] + fn zywx(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 1, 7, 4>(self.0, self.0)) + } + + #[inline] + fn zywy(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 1, 7, 5>(self.0, self.0)) + } + + #[inline] + fn zywz(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 1, 7, 6>(self.0, self.0)) + } + + #[inline] + fn zyww(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 1, 7, 7>(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 zzxw(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 2, 4, 7>(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 zzyw(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 2, 5, 7>(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 zzzw(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 2, 6, 7>(self.0, self.0)) + } + + #[inline] + fn zzwx(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 2, 7, 4>(self.0, self.0)) + } + + #[inline] + fn zzwy(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 2, 7, 5>(self.0, self.0)) + } + + #[inline] + fn zzwz(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 2, 7, 6>(self.0, self.0)) + } + + #[inline] + fn zzww(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 2, 7, 7>(self.0, self.0)) + } + + #[inline] + fn zwxx(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 3, 4, 4>(self.0, self.0)) + } + + #[inline] + fn zwxy(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 3, 4, 5>(self.0, self.0)) + } + + #[inline] + fn zwxz(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 3, 4, 6>(self.0, self.0)) + } + + #[inline] + fn zwxw(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 3, 4, 7>(self.0, self.0)) + } + + #[inline] + fn zwyx(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 3, 5, 4>(self.0, self.0)) + } + + #[inline] + fn zwyy(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 3, 5, 5>(self.0, self.0)) + } + + #[inline] + fn zwyz(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 3, 5, 6>(self.0, self.0)) + } + + #[inline] + fn zwyw(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 3, 5, 7>(self.0, self.0)) + } + + #[inline] + fn zwzx(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 3, 6, 4>(self.0, self.0)) + } + + #[inline] + fn zwzy(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 3, 6, 5>(self.0, self.0)) + } + + #[inline] + fn zwzz(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 3, 6, 6>(self.0, self.0)) + } + + #[inline] + fn zwzw(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 3, 6, 7>(self.0, self.0)) + } + + #[inline] + fn zwwx(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 3, 7, 4>(self.0, self.0)) + } + + #[inline] + fn zwwy(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 3, 7, 5>(self.0, self.0)) + } + + #[inline] + fn zwwz(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 3, 7, 6>(self.0, self.0)) + } + + #[inline] + fn zwww(self) -> Vec4 { + Vec4(i32x4_shuffle::<2, 3, 7, 7>(self.0, self.0)) + } + + #[inline] + fn wxxx(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 0, 4, 4>(self.0, self.0)) + } + + #[inline] + fn wxxy(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 0, 4, 5>(self.0, self.0)) + } + + #[inline] + fn wxxz(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 0, 4, 6>(self.0, self.0)) + } + + #[inline] + fn wxxw(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 0, 4, 7>(self.0, self.0)) + } + + #[inline] + fn wxyx(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 0, 5, 4>(self.0, self.0)) + } + + #[inline] + fn wxyy(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 0, 5, 5>(self.0, self.0)) + } + + #[inline] + fn wxyz(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 0, 5, 6>(self.0, self.0)) + } + + #[inline] + fn wxyw(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 0, 5, 7>(self.0, self.0)) + } + + #[inline] + fn wxzx(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 0, 6, 4>(self.0, self.0)) + } + + #[inline] + fn wxzy(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 0, 6, 5>(self.0, self.0)) + } + + #[inline] + fn wxzz(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 0, 6, 6>(self.0, self.0)) + } + + #[inline] + fn wxzw(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 0, 6, 7>(self.0, self.0)) + } + + #[inline] + fn wxwx(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 0, 7, 4>(self.0, self.0)) + } + + #[inline] + fn wxwy(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 0, 7, 5>(self.0, self.0)) + } + + #[inline] + fn wxwz(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 0, 7, 6>(self.0, self.0)) + } + + #[inline] + fn wxww(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 0, 7, 7>(self.0, self.0)) + } + + #[inline] + fn wyxx(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 1, 4, 4>(self.0, self.0)) + } + + #[inline] + fn wyxy(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 1, 4, 5>(self.0, self.0)) + } + + #[inline] + fn wyxz(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 1, 4, 6>(self.0, self.0)) + } + + #[inline] + fn wyxw(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 1, 4, 7>(self.0, self.0)) + } + + #[inline] + fn wyyx(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 1, 5, 4>(self.0, self.0)) + } + + #[inline] + fn wyyy(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 1, 5, 5>(self.0, self.0)) + } + + #[inline] + fn wyyz(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 1, 5, 6>(self.0, self.0)) + } + + #[inline] + fn wyyw(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 1, 5, 7>(self.0, self.0)) + } + + #[inline] + fn wyzx(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 1, 6, 4>(self.0, self.0)) + } + + #[inline] + fn wyzy(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 1, 6, 5>(self.0, self.0)) + } + + #[inline] + fn wyzz(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 1, 6, 6>(self.0, self.0)) + } + + #[inline] + fn wyzw(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 1, 6, 7>(self.0, self.0)) + } + + #[inline] + fn wywx(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 1, 7, 4>(self.0, self.0)) + } + + #[inline] + fn wywy(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 1, 7, 5>(self.0, self.0)) + } + + #[inline] + fn wywz(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 1, 7, 6>(self.0, self.0)) + } + + #[inline] + fn wyww(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 1, 7, 7>(self.0, self.0)) + } + + #[inline] + fn wzxx(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 2, 4, 4>(self.0, self.0)) + } + + #[inline] + fn wzxy(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 2, 4, 5>(self.0, self.0)) + } + + #[inline] + fn wzxz(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 2, 4, 6>(self.0, self.0)) + } + + #[inline] + fn wzxw(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 2, 4, 7>(self.0, self.0)) + } + + #[inline] + fn wzyx(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 2, 5, 4>(self.0, self.0)) + } + + #[inline] + fn wzyy(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 2, 5, 5>(self.0, self.0)) + } + + #[inline] + fn wzyz(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 2, 5, 6>(self.0, self.0)) + } + + #[inline] + fn wzyw(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 2, 5, 7>(self.0, self.0)) + } + + #[inline] + fn wzzx(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 2, 6, 4>(self.0, self.0)) + } + + #[inline] + fn wzzy(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 2, 6, 5>(self.0, self.0)) + } + + #[inline] + fn wzzz(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 2, 6, 6>(self.0, self.0)) + } + + #[inline] + fn wzzw(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 2, 6, 7>(self.0, self.0)) + } + + #[inline] + fn wzwx(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 2, 7, 4>(self.0, self.0)) + } + + #[inline] + fn wzwy(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 2, 7, 5>(self.0, self.0)) + } + + #[inline] + fn wzwz(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 2, 7, 6>(self.0, self.0)) + } + + #[inline] + fn wzww(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 2, 7, 7>(self.0, self.0)) + } + + #[inline] + fn wwxx(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 3, 4, 4>(self.0, self.0)) + } + + #[inline] + fn wwxy(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 3, 4, 5>(self.0, self.0)) + } + + #[inline] + fn wwxz(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 3, 4, 6>(self.0, self.0)) + } + + #[inline] + fn wwxw(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 3, 4, 7>(self.0, self.0)) + } + + #[inline] + fn wwyx(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 3, 5, 4>(self.0, self.0)) + } + + #[inline] + fn wwyy(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 3, 5, 5>(self.0, self.0)) + } + + #[inline] + fn wwyz(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 3, 5, 6>(self.0, self.0)) + } + + #[inline] + fn wwyw(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 3, 5, 7>(self.0, self.0)) + } + + #[inline] + fn wwzx(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 3, 6, 4>(self.0, self.0)) + } + + #[inline] + fn wwzy(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 3, 6, 5>(self.0, self.0)) + } + + #[inline] + fn wwzz(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 3, 6, 6>(self.0, self.0)) + } + + #[inline] + fn wwzw(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 3, 6, 7>(self.0, self.0)) + } + + #[inline] + fn wwwx(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 3, 7, 4>(self.0, self.0)) + } + + #[inline] + fn wwwy(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 3, 7, 5>(self.0, self.0)) + } + + #[inline] + fn wwwz(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 3, 7, 6>(self.0, self.0)) + } + + #[inline] + fn wwww(self) -> Vec4 { + Vec4(i32x4_shuffle::<3, 3, 7, 7>(self.0, self.0)) + } +} diff --git a/src/transform.rs b/src/transform.rs deleted file mode 100644 index d7b1b66..0000000 --- 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 0000000..3538c3e --- /dev/null +++ b/src/u32.rs @@ -0,0 +1,41 @@ +mod uvec2; +mod uvec3; +mod uvec4; + +pub use uvec2::{uvec2, UVec2}; +pub use uvec3::{uvec3, UVec3}; +pub use uvec4::{uvec4, UVec4}; + +#[cfg(not(target_arch = "spirv"))] +mod test { + use super::*; + 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 0000000..d0c838e --- /dev/null +++ b/src/u32/uvec2.rs @@ -0,0 +1,876 @@ +// Generated from vec.rs.tera 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. +#[cfg_attr(not(target_arch = "spirv"), derive(Hash))] +#[derive(Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "cuda", repr(align(8)))] +#[cfg_attr(not(target_arch = "spirv"), repr(C))] +#[cfg_attr(target_arch = "spirv", repr(simd))] +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); + + /// A unit-length vector pointing along the positive X axis. + pub const X: Self = Self::new(1, 0); + + /// A unit-length vector pointing along the positive Y axis. + pub const Y: Self = Self::new(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 2 values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 2 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 2 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 where every component is the dot product of `self` and `rhs`. + #[inline] + pub fn dot_into_vec(self, rhs: Self) -> Self { + Self::splat(self.dot(rhs)) + } + + /// 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 [`u32::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 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 Sum for UVec2 { + #[inline] + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, Self::add) + } +} + +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 Product for UVec2 { + #[inline] + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ONE, Self::mul) + } +} + +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 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 0000000..040b482 --- /dev/null +++ b/src/u32/uvec3.rs @@ -0,0 +1,977 @@ +// Generated from vec.rs.tera 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. +#[cfg_attr(not(target_arch = "spirv"), derive(Hash))] +#[derive(Clone, Copy, PartialEq, Eq)] +#[cfg_attr(not(target_arch = "spirv"), repr(C))] +#[cfg_attr(target_arch = "spirv", repr(simd))] +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); + + /// A unit-length vector pointing along the positive X axis. + pub const X: Self = Self::new(1, 0, 0); + + /// A unit-length vector pointing along the positive Y axis. + pub const Y: Self = Self::new(0, 1, 0); + + /// A unit-length vector pointing along the positive Z axis. + pub const Z: Self = Self::new(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 3 values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 3 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 3 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) + } + + /// Returns a vector where every component is the dot product of `self` and `rhs`. + #[inline] + pub fn dot_into_vec(self, rhs: Self) -> Self { + Self::splat(self.dot(rhs)) + } + + /// 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 [`u32::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 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 Sum for UVec3 { + #[inline] + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, Self::add) + } +} + +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 Product for UVec3 { + #[inline] + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ONE, Self::mul) + } +} + +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 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 0000000..e6c43a3 --- /dev/null +++ b/src/u32/uvec4.rs @@ -0,0 +1,1063 @@ +// Generated from vec.rs.tera 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. +#[cfg_attr(not(target_arch = "spirv"), derive(Hash))] +#[derive(Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "cuda", repr(align(16)))] +#[cfg_attr(not(target_arch = "spirv"), repr(C))] +#[cfg_attr(target_arch = "spirv", repr(simd))] +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); + + /// A unit-length vector pointing along the positive X axis. + pub const X: Self = Self::new(1, 0, 0, 0); + + /// A unit-length vector pointing along the positive Y axis. + pub const Y: Self = Self::new(0, 1, 0, 0); + + /// A unit-length vector pointing along the positive Z axis. + pub const Z: Self = Self::new(0, 0, 1, 0); + + /// A unit-length vector pointing along the positive W axis. + pub const W: Self = Self::new(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 4 values in `slice`. + /// + /// # Panics + /// + /// Panics if `slice` is less than 4 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 4 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 where every component is the dot product of `self` and `rhs`. + #[inline] + pub fn dot_into_vec(self, rhs: Self) -> Self { + Self::splat(self.dot(rhs)) + } + + /// 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 [`u32::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 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 Sum for UVec4 { + #[inline] + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ZERO, Self::add) + } +} + +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 Product for UVec4 { + #[inline] + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::ONE, Self::mul) + } +} + +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 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 3c5a226..0000000 --- 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.max(other.x), self.y.max(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 98ffa38..0000000 --- a/src/vec2.rs +++ /dev/null @@ -1,317 +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) - } - }; -} - -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); - - /// 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 56978d3..0000000 --- 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 9f12b89..0000000 --- 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 882ead3..0000000 --- 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 0000000..dbeac6a --- /dev/null +++ b/src/wasm32.rs @@ -0,0 +1,47 @@ +use core::arch::wasm32::*; + +pub const fn v128_from_f32x4(a: [f32; 4]) -> v128 { + f32x4(a[0], a[1], a[2], a[3]) +} + +/// 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/tests/affine2.rs b/tests/affine2.rs index 35424a1..e547dbb 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 *= 0.0; + b.y_axis *= 0.0; + b.z_axis *= 0.0; + assert_eq!($affine2::ZERO, 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), @@ -97,13 +149,12 @@ macro_rules! impl_affine2_tests { glam_test!(test_affine2_ops, { let m0 = $affine2::from_cols_array_2d(&MATRIX2D); - let m0x2 = $affine2::from_cols_array_2d(&[[2.0, 4.0], [6.0, 8.0], [10.0, 12.0]]); - assert_eq!(m0x2, m0 * 2.0); - assert_eq!(m0x2, 2.0 * m0); - assert_eq!(m0x2, m0 + m0); - 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 +163,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 +198,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 +228,21 @@ mod affine2 { } }); - impl_affine2_tests!(f32, Affine2, Vec2); + glam_test!(test_affine2_from_mat3a, { + use glam::Mat3A; + let m = Mat3A::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_mat3a(m); + assert_eq!(MATRIX2D, a.to_cols_array_2d()); + + assert_eq!(m, Mat3A::from(a)); + }); + + 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 +272,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 06fd7ca..86d5a53 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 *= 0.0; + b.y_axis *= 0.0; + b.z_axis *= 0.0; + b.w_axis *= 0.0; + assert_eq!($affine3::ZERO, 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) }); }); @@ -158,7 +233,7 @@ macro_rules! impl_affine3_tests { assert_approx_eq!( in_mat, $affine3::from_scale_rotation_translation(out_scale, out_rotation, out_translation), - 1e-6 + 1e-5 ); // negative scale @@ -196,9 +271,17 @@ macro_rules! impl_affine3_tests { let eye = $vec3::new(0.0, 0.0, -5.0); let center = $vec3::new(0.0, 0.0, 0.0); let up = $vec3::new(1.0, 0.0, 0.0); + + let point = $vec3::new(1.0, 0.0, 0.0); + let lh = $affine3::look_at_lh(eye, center, up); let rh = $affine3::look_at_rh(eye, center, up); - let point = $vec3::new(1.0, 0.0, 0.0); + assert_approx_eq!(lh.transform_point3(point), $vec3::new(0.0, 1.0, 5.0)); + assert_approx_eq!(rh.transform_point3(point), $vec3::new(0.0, 1.0, -5.0)); + + let dir = center - eye; + let lh = $affine3::look_to_lh(eye, dir, up); + let rh = $affine3::look_to_rh(eye, dir, up); assert_approx_eq!(lh.transform_point3(point), $vec3::new(0.0, 1.0, 5.0)); assert_approx_eq!(rh.transform_point3(point), $vec3::new(0.0, 1.0, -5.0)); @@ -208,18 +291,12 @@ macro_rules! impl_affine3_tests { glam_test!(test_affine3_ops, { let m0 = $affine3::from_cols_array_2d(&MATRIX2D); - let m0x2 = $affine3::from_cols_array_2d(&[ - [2.0, 4.0, 6.0], - [8.0, 10.0, 12.0], - [14.0, 16.0, 18.0], - [20.0, 22.0, 24.0], - ]); - assert_eq!(m0x2, m0 * 2.0); - assert_eq!(m0x2, 2.0 * m0); - assert_eq!(m0x2, m0 + m0); - 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 +308,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 +348,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 +387,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 +414,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 f6cab9e..dc4de53 100644 --- a/tests/euler.rs +++ b/tests/euler.rs @@ -1,14 +1,12 @@ #[macro_use] mod support; -use glam::{DQuat, Quat}; - /// Helper to calculate the inner angle in the range [0, 2*PI) trait AngleDiff { type Output; fn angle_diff(self, other: Self) -> Self::Output; } -#[macro_export] + macro_rules! impl_angle_diff { ($t:ty, $pi:expr) => { impl AngleDiff for $t { @@ -29,7 +27,6 @@ macro_rules! impl_angle_diff { impl_angle_diff!(f32, std::f32::consts::PI); impl_angle_diff!(f64, std::f64::consts::PI); -#[macro_export] macro_rules! assert_approx_angle { ($a:expr, $b:expr, $eps:expr) => {{ let (a, b) = ($a, $b); @@ -47,42 +44,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) => { glam_test!($name, { @@ -122,48 +83,6 @@ macro_rules! impl_3axis_test { }; } -#[macro_export] -macro_rules! impl_2axis_test { - ($name:ident, $t:ty, $quat:ident, $euler:path, $U:path, $V:path, $W:path, $vec:ident) => { - glam_test!($name, { - #[allow(deprecated)] - let euler = $euler; - assert!($U == $W); // First and last axis must be different for three axis - for u in (-176..=176).step_by(44) { - for v in (-176..=176).step_by(44) { - for w in (-176..=176).step_by(44) { - let u1 = (u as $t).to_radians(); - let v1 = (v as $t).to_radians(); - let w1 = (w as $t).to_radians(); - - let q1: $quat = ($quat::from_axis_angle($U, u1) - * $quat::from_axis_angle($V, v1) - * $quat::from_axis_angle($W, w1)) - .normalize(); - - // Test if the rotation is the expected - let q2 = $quat::from_euler(euler, u1, v1, w1).normalize(); - assert_approx_eq!(q1, q2, 1e-5); - - // Test angle reconstruction - let (u2, v2, w2) = q1.to_euler(euler); - let _q3 = $quat::from_euler(euler, u2, v2, w2).normalize(); - - // Disabled tests, since no generic tests for ambiguous results in the two-axis results... - // assert_approx_angle!(u1, u2, 1e-4 as $t); - // assert_approx_angle!(v1, v2, 1e-4 as $t); - // assert_approx_angle!(w1, w2, 1e-4 as $t); - - // assert_approx_eq!(q1 * $vec::X, q3 * $vec::X, 1e-4); - // assert_approx_eq!(q1 * $vec::Y, q3 * $vec::Y, 1e-4); - // assert_approx_eq!(q1 * $vec::Z, q3 * $vec::Z, 1e-4); - } - } - } - }); - }; -} - macro_rules! impl_all_quat_tests_three_axis { ($t:ty, $q:ident, $v:ident) => { impl_3axis_test!(test_euler_zyx, $t, $q, ER::ZYX, $v::Z, $v::Y, $v::X, $v); @@ -175,17 +94,6 @@ macro_rules! impl_all_quat_tests_three_axis { }; } -macro_rules! impl_all_quat_tests_two_axis { - ($t:ty, $q:ident, $v:ident) => { - impl_2axis_test!(test_euler_zyz, $t, $q, ER::ZYZ, $v::Z, $v::Y, $v::Z, $v); - impl_2axis_test!(test_euler_zxz, $t, $q, ER::ZXZ, $v::Z, $v::X, $v::Z, $v); - impl_2axis_test!(test_euler_yxy, $t, $q, ER::YXY, $v::Y, $v::X, $v::Y, $v); - impl_2axis_test!(test_euler_yzy, $t, $q, ER::YZY, $v::Y, $v::Z, $v::Y, $v); - impl_2axis_test!(test_euler_xyx, $t, $q, ER::XYX, $v::X, $v::Y, $v::X, $v); - impl_2axis_test!(test_euler_xzx, $t, $q, ER::XZX, $v::X, $v::Z, $v::X, $v); - }; -} - mod euler { use super::AngleDiff; use glam::*; @@ -195,15 +103,11 @@ mod euler { use super::*; impl_all_quat_tests_three_axis!(f32, Quat, Vec3); - - impl_all_quat_tests_two_axis!(f32, Quat, Vec3); } mod dquat { use super::*; impl_all_quat_tests_three_axis!(f64, DQuat, DVec3); - - impl_all_quat_tests_two_axis!(f64, DQuat, DVec3); } } diff --git a/tests/mat2.rs b/tests/mat2.rs index 860f25a..a19eb7d 100644 --- a/tests/mat2.rs +++ b/tests/mat2.rs @@ -2,18 +2,21 @@ mod support; macro_rules! impl_mat2_tests { - ($t:ident, $const_new:ident, $newmat2:ident, $mat2:ident, $mat3:ident, $newvec2:ident, $vec2:ident) => { + ($t:ident, $newmat2:ident, $mat2:ident, $mat3:ident, $newvec2:ident, $vec2:ident) => { const IDENTITY: [[$t; 2]; 2] = [[1.0, 0.0], [0.0, 1.0]]; 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 = $const_new!([0.0; 4]); - const M1: $mat2 = $const_new!([1.0, 2.0, 3.0, 4.0]); - 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); - assert_eq!($mat2::from_cols_array(&[1.0, 2.0, 3.0, 4.0]), M2); + 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_mat2_identity, { @@ -23,6 +26,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 +190,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(); @@ -200,11 +203,13 @@ macro_rules! impl_mat2_tests { glam_test!(test_sum, { let id = $mat2::IDENTITY; assert_eq!(vec![id, id].iter().sum::<$mat2>(), id + id); + assert_eq!(vec![id, id].into_iter().sum::<$mat2>(), id + id); }); glam_test!(test_product, { let two = $mat2::IDENTITY + $mat2::IDENTITY; assert_eq!(vec![two, two].iter().product::<$mat2>(), two * two); + assert_eq!(vec![two, two].into_iter().product::<$mat2>(), two * two); }); glam_test!(test_mat2_is_finite, { @@ -219,9 +224,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; - use glam::{const_mat2, mat2, swizzles::*, vec2, Mat2, Mat3, Vec2}; + use glam::{mat2, swizzles::*, vec2, Mat2, Mat3, Vec2}; glam_test!(test_align, { use std::mem; @@ -233,6 +252,13 @@ mod mat2 { } }); + glam_test!(test_from_mat3a, { + use glam::Mat3A; + let m3 = Mat3A::from_cols_array_2d(&[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]]); + let m2 = Mat2::from_mat3a(m3); + assert_eq!(Mat2::from_cols_array_2d(&[[1.0, 2.0], [4.0, 5.0]]), m2); + }); + glam_test!(test_as, { use glam::DMat2; assert_eq!( @@ -245,12 +271,13 @@ mod mat2 { ); }); - impl_mat2_tests!(f32, const_mat2, mat2, Mat2, Mat3, vec2, Vec2); + impl_mat2_tests!(f32, mat2, Mat2, Mat3, vec2, Vec2); + impl_as_ref_tests!(Mat2); } mod dmat2 { use super::support::deg; - use glam::{const_dmat2, dmat2, dvec2, swizzles::*, DMat2, DMat3, DVec2}; + use glam::{dmat2, dvec2, swizzles::*, DMat2, DMat3, DVec2}; glam_test!(test_align, { use std::mem; @@ -258,5 +285,6 @@ mod dmat2 { assert_eq!(mem::align_of::(), mem::align_of::()); }); - impl_mat2_tests!(f64, const_dmat2, dmat2, DMat2, DMat3, dvec2, DVec2); + impl_mat2_tests!(f64, dmat2, DMat2, DMat3, dvec2, DVec2); + impl_as_ref_tests!(DMat2); } diff --git a/tests/mat3.rs b/tests/mat3.rs index 0f015df..baf1e42 100644 --- a/tests/mat3.rs +++ b/tests/mat3.rs @@ -2,7 +2,7 @@ mod support; macro_rules! impl_mat3_tests { - ($t:ident, $const_new:ident, $newmat3:ident, $mat3:ident, $mat2:ident, $mat4:ident, $quat:ident, $newvec3:ident, $vec3:ident, $vec2:ident) => { + ($t:ident, $newmat3:ident, $mat3:ident, $mat2:ident, $mat4:ident, $quat:ident, $newvec3:ident, $vec3:ident, $vec2:ident) => { use core::$t::INFINITY; use core::$t::NAN; use core::$t::NEG_INFINITY; @@ -11,19 +11,20 @@ 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 = $const_new!([0.0; 9]); - const M1: $mat3 = $const_new!([1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]); - 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!( - $mat3::from_cols_array(&[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]), - M1 - ); - assert_eq!( - $mat3::from_cols_array(&[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]), - M2 + 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_mat3_identity, { @@ -40,6 +41,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 +329,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(); @@ -341,11 +342,13 @@ macro_rules! impl_mat3_tests { glam_test!(test_sum, { let id = $mat3::IDENTITY; assert_eq!(vec![id, id].iter().sum::<$mat3>(), id + id); + assert_eq!(vec![id, id].into_iter().sum::<$mat3>(), id + id); }); glam_test!(test_product, { let two = $mat3::IDENTITY + $mat3::IDENTITY; assert_eq!(vec![two, two].iter().product::<$mat3>(), two * two); + assert_eq!(vec![two, two].into_iter().product::<$mat3>(), two * two); }); glam_test!(test_mat3_is_finite, { @@ -357,11 +360,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; - use glam::{ - const_mat3, mat3, swizzles::*, vec3, vec3a, Mat2, Mat3, Mat4, Quat, Vec2, Vec3, Vec3A, - }; + use glam::{mat3, swizzles::*, vec3, vec3a, Mat2, Mat3, Mat4, Quat, Vec2, Vec3, Vec3A}; glam_test!(test_align, { use std::mem; @@ -387,14 +402,13 @@ mod mat3 { ); }); - impl_mat3_tests!(f32, const_mat3, mat3, Mat3, Mat2, Mat4, Quat, vec3, Vec3, Vec2); + impl_mat3_tests!(f32, mat3, Mat3, Mat2, Mat4, Quat, vec3, Vec3, Vec2); + impl_as_ref_tests!(Mat3); } mod mat3a { use super::support::deg; - use glam::{ - const_mat3a, mat3a, swizzles::*, vec3a, Mat2, Mat3A, Mat4, Quat, Vec2, Vec3, Vec3A, - }; + use glam::{mat3a, swizzles::*, vec3a, Mat2, Mat3A, Mat4, Quat, Vec2, Vec3, Vec3A}; glam_test!(test_align, { use std::mem; @@ -416,23 +430,12 @@ mod mat3a { ); }); - impl_mat3_tests!( - f32, - const_mat3a, - mat3a, - Mat3A, - Mat2, - Mat4, - Quat, - vec3a, - Vec3, - Vec2 - ); + impl_mat3_tests!(f32, mat3a, Mat3A, Mat2, Mat4, Quat, vec3a, Vec3, Vec2); } mod dmat3 { use super::support::deg; - use glam::{const_dmat3, dmat3, dvec3, swizzles::*, DMat2, DMat3, DMat4, DQuat, DVec2, DVec3}; + use glam::{dmat3, dvec3, swizzles::*, DMat2, DMat3, DMat4, DQuat, DVec2, DVec3}; glam_test!(test_align, { use std::mem; @@ -440,16 +443,6 @@ mod dmat3 { assert_eq!(mem::align_of::(), mem::align_of::()); }); - impl_mat3_tests!( - f64, - const_dmat3, - dmat3, - DMat3, - DMat2, - DMat4, - DQuat, - dvec3, - DVec3, - DVec2 - ); + impl_mat3_tests!(f64, dmat3, DMat3, DMat2, DMat4, DQuat, dvec3, DVec3, DVec2); + impl_as_ref_tests!(DMat3); } diff --git a/tests/mat4.rs b/tests/mat4.rs index 85d670d..164bdd6 100644 --- a/tests/mat4.rs +++ b/tests/mat4.rs @@ -2,7 +2,7 @@ mod support; macro_rules! impl_mat4_tests { - ($t:ident, $const_new:ident, $newmat4:ident, $newvec4:ident, $newvec3:ident, $mat4:ident, $mat3:ident, $quat:ident, $vec4:ident, $vec3:ident) => { + ($t:ident, $newmat4:ident, $newvec4:ident, $newvec3:ident, $mat4:ident, $mat3:ident, $quat:ident, $vec4:ident, $vec3:ident) => { use core::$t::INFINITY; use core::$t::NAN; use core::$t::NEG_INFINITY; @@ -20,37 +20,23 @@ 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 = $const_new!([0.0; 16]); - 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 - ]); - const M2: $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] - ); - assert_eq!($mat4::ZERO, M0); - assert_eq!( - $mat4::from_cols_array_2d(&[ - [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] - ]), - M1 - ); - assert_eq!( - $mat4::from_cols_array_2d(&[ - [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] - ]), - M2 + 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_mat4_identity, { @@ -68,6 +54,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, { @@ -403,7 +390,7 @@ macro_rules! impl_mat4_tests { assert_approx_eq!( in_mat, $mat4::from_scale_rotation_translation(out_scale, out_rotation, out_translation), - 1e-6 + 1e-5 ); // negative scale @@ -455,9 +442,17 @@ macro_rules! impl_mat4_tests { let eye = $vec3::new(0.0, 0.0, -5.0); let center = $vec3::new(0.0, 0.0, 0.0); let up = $vec3::new(1.0, 0.0, 0.0); + + let point = $vec3::new(1.0, 0.0, 0.0); + let lh = $mat4::look_at_lh(eye, center, up); let rh = $mat4::look_at_rh(eye, center, up); - let point = $vec3::new(1.0, 0.0, 0.0); + assert_approx_eq!(lh.transform_point3(point), $vec3::new(0.0, 1.0, 5.0)); + assert_approx_eq!(rh.transform_point3(point), $vec3::new(0.0, 1.0, -5.0)); + + let dir = center - eye; + let lh = $mat4::look_to_lh(eye, dir, up); + let rh = $mat4::look_to_rh(eye, dir, up); assert_approx_eq!(lh.transform_point3(point), $vec3::new(0.0, 1.0, 5.0)); assert_approx_eq!(rh.transform_point3(point), $vec3::new(0.0, 1.0, -5.0)); @@ -482,11 +477,11 @@ macro_rules! impl_mat4_tests { let original = $vec3::new(5.0, 5.0, 15.0); let projected = projection * original.extend(1.0); - assert_approx_eq!($vec4::new(2.5, 5.0, 15.0, 15.0), projected); + assert_approx_eq!($vec4::new(2.5, 5.0, 15.0, 15.0), projected, 1e-6); let original = $vec3::new(5.0, 5.0, 5.0); let projected = projection * original.extend(1.0); - assert_approx_eq!($vec4::new(2.5, 5.0, 0.0, 5.0), projected); + assert_approx_eq!($vec4::new(2.5, 5.0, 0.0, 5.0), projected, 1e-6); should_glam_assert!({ $mat4::perspective_lh(0.0, 1.0, 1.0, 0.0) }); should_glam_assert!({ $mat4::perspective_lh(0.0, 1.0, 0.0, 1.0) }); @@ -497,11 +492,11 @@ macro_rules! impl_mat4_tests { let original = $vec3::new(5.0, 5.0, 15.0); let projected = projection * original.extend(1.0); - assert_approx_eq!($vec4::new(2.5, 5.0, 10.0, 15.0), projected); + assert_approx_eq!($vec4::new(2.5, 5.0, 10.0, 15.0), projected, 1e-6); let original = $vec3::new(5.0, 5.0, 5.0); let projected = projection * original.extend(1.0); - assert_approx_eq!($vec4::new(2.5, 5.0, 0.0, 5.0), projected); + assert_approx_eq!($vec4::new(2.5, 5.0, 0.0, 5.0), projected, 1e-6); should_glam_assert!({ $mat4::perspective_infinite_lh(0.0, 1.0, 0.0) }); }); @@ -511,11 +506,11 @@ macro_rules! impl_mat4_tests { let original = $vec3::new(5.0, 5.0, 15.0); let projected = projection * original.extend(1.0); - assert_approx_eq!($vec4::new(2.5, 5.0, 5.0, 15.0), projected); + assert_approx_eq!($vec4::new(2.5, 5.0, 5.0, 15.0), projected, 1e-6); let original = $vec3::new(5.0, 5.0, 5.0); let projected = projection * original.extend(1.0); - assert_approx_eq!($vec4::new(2.5, 5.0, 5.0, 5.0), projected); + assert_approx_eq!($vec4::new(2.5, 5.0, 5.0, 5.0), projected, 1e-6); should_glam_assert!({ $mat4::perspective_infinite_reverse_lh(0.0, 1.0, 0.0) }); }); @@ -525,11 +520,11 @@ macro_rules! impl_mat4_tests { let original = $vec3::new(5.0, 5.0, 15.0); let projected = projection * original.extend(1.0); - assert_approx_eq!($vec4::new(2.5, 5.0, -30.0, -15.0), projected); + assert_approx_eq!($vec4::new(2.5, 5.0, -30.0, -15.0), projected, 1e-6); let original = $vec3::new(5.0, 5.0, 5.0); let projected = projection * original.extend(1.0); - assert_approx_eq!($vec4::new(2.5, 5.0, -15.0, -5.0), projected); + assert_approx_eq!($vec4::new(2.5, 5.0, -15.0, -5.0), projected, 1e-6); should_glam_assert!({ $mat4::perspective_rh(0.0, 1.0, 1.0, 0.0) }); should_glam_assert!({ $mat4::perspective_rh(0.0, 1.0, 0.0, 1.0) }); @@ -640,10 +635,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(); @@ -657,11 +648,13 @@ macro_rules! impl_mat4_tests { glam_test!(test_sum, { let id = $mat4::IDENTITY; assert_eq!(vec![id, id].iter().sum::<$mat4>(), id + id); + assert_eq!(vec![id, id].into_iter().sum::<$mat4>(), id + id); }); glam_test!(test_product, { let two = $mat4::IDENTITY + $mat4::IDENTITY; assert_eq!(vec![two, two].iter().product::<$mat4>(), two * two); + assert_eq!(vec![two, two].into_iter().product::<$mat4>(), two * two); }); glam_test!(test_mat4_is_finite, { @@ -673,9 +666,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; - use glam::{const_mat4, mat4, swizzles::*, vec3, vec4, Mat3, Mat4, Quat, Vec3, Vec4}; + use glam::{mat4, swizzles::*, vec3, vec4, Mat3, Mat4, Quat, Vec3, Vec4}; glam_test!(test_align, { use std::mem; @@ -683,6 +690,21 @@ mod mat4 { assert_eq!(64, mem::size_of::()); }); + glam_test!(test_from_mat3a, { + use glam::Mat3A; + let m3 = Mat3A::from_cols_array_2d(&[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]]); + let m4 = Mat4::from_mat3a(m3); + assert_eq!( + 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], + [0.0, 0.0, 0.0, 1.0] + ]), + m4 + ); + }); + glam_test!(test_as, { use glam::DMat4; assert_eq!( @@ -717,12 +739,13 @@ mod mat4 { ); }); - impl_mat4_tests!(f32, const_mat4, mat4, vec4, vec3, Mat4, Mat3, Quat, Vec4, Vec3); + impl_mat4_tests!(f32, mat4, vec4, vec3, Mat4, Mat3, Quat, Vec4, Vec3); + impl_as_ref_tests!(Mat4); } mod dmat4 { use super::support::deg; - use glam::{const_dmat4, dmat4, dvec3, dvec4, swizzles::*, DMat3, DMat4, DQuat, DVec3, DVec4}; + use glam::{dmat4, dvec3, dvec4, swizzles::*, DMat3, DMat4, DQuat, DVec3, DVec4}; glam_test!(test_align, { use std::mem; @@ -730,16 +753,6 @@ mod dmat4 { assert_eq!(128, mem::size_of::()); }); - impl_mat4_tests!( - f64, - const_dmat4, - dmat4, - dvec4, - dvec3, - DMat4, - DMat3, - DQuat, - DVec4, - DVec3 - ); + impl_mat4_tests!(f64, dmat4, dvec4, dvec3, DMat4, DMat3, DQuat, DVec4, DVec3); + impl_as_ref_tests!(DMat4); } diff --git a/tests/quat.rs b/tests/quat.rs index 831bf0f..1a6f6e3 100644 --- a/tests/quat.rs +++ b/tests/quat.rs @@ -1,15 +1,19 @@ +#![allow(clippy::excessive_precision)] + #[macro_use] mod support; macro_rules! impl_quat_tests { - ($t:ident, $const_new:ident, $new:ident, $mat3:ident, $mat4:ident, $quat:ident, $vec2:ident, $vec3:ident, $vec4:ident) => { + ($t:ident, $new:ident, $mat3:ident, $mat4:ident, $quat:ident, $vec2:ident, $vec3:ident, $vec4:ident) => { use core::$t::INFINITY; use core::$t::NAN; 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]); + 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()); }); glam_test!(test_nan, { @@ -32,6 +36,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, { @@ -79,7 +85,7 @@ macro_rules! impl_quat_tests { assert!(x0.is_normalized()); let (axis, angle) = x0.to_axis_angle(); assert_approx_eq!(axis, $vec3::X); - assert_approx_eq!(angle, pitch); + assert_approx_eq!(angle, pitch, 1e-6); let x1 = $quat::from_euler(EulerRot::YXZ, zero, pitch, zero); assert_approx_eq!(x0, x1); let x2 = $quat::from_axis_angle($vec3::X, pitch); @@ -128,6 +134,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) }); }); @@ -280,15 +290,45 @@ macro_rules! impl_quat_tests { while s <= 1.0 { let q0 = $quat::from_rotation_y(deg(0.0)); let q1 = $quat::from_rotation_y(deg(90.0)); - assert_approx_eq!( - $quat::from_rotation_y(deg(s * 90.0)), - q0.slerp(q1, s), - 1.0e-3 - ); + let result = q0.slerp(q1, s); + assert_approx_eq!($quat::from_rotation_y(deg(s * 90.0)), result, 1.0e-3); + assert!(result.is_normalized()); s += step; } }); + glam_test!(test_slerp_tau, { + let q1 = $quat::IDENTITY; + let q2 = $quat::from_rotation_x(core::$t::consts::TAU); + let s = q1.slerp(q2, 1.); + assert!(s.is_finite()); + assert!(s.is_normalized()); + }); + + glam_test!(test_slerp_negative_tau, { + let q1 = $quat::IDENTITY; + let q2 = $quat::from_rotation_x(-core::$t::consts::TAU); + let s = q1.slerp(q2, 1.); + assert!(s.is_finite()); + assert!(s.is_normalized()); + }); + + glam_test!(test_slerp_pi, { + let q1 = $quat::IDENTITY; + let q2 = $quat::from_rotation_x(core::$t::consts::PI); + let s = q1.slerp(q2, 1.); + assert!(s.is_finite()); + assert!(s.is_normalized()); + }); + + glam_test!(test_slerp_negative_pi, { + let q1 = $quat::IDENTITY; + let q2 = $quat::from_rotation_x(-core::$t::consts::PI); + let s = q1.slerp(q2, 1.); + assert!(s.is_finite()); + assert!(s.is_normalized()); + }); + glam_test!(test_fmt, { let a = $quat::IDENTITY; assert_eq!( @@ -368,11 +408,13 @@ macro_rules! impl_quat_tests { glam_test!(test_sum, { let two = $new(2.0, 2.0, 2.0, 2.0); assert_eq!(vec![two, two].iter().sum::<$quat>(), two + two); + assert_eq!(vec![two, two].into_iter().sum::<$quat>(), two + two); }); glam_test!(test_product, { let two = $new(2.0, 2.0, 2.0, 2.0).normalize(); assert_eq!(vec![two, two].iter().product::<$quat>(), two * two); + assert_eq!(vec![two, two].into_iter().product::<$quat>(), two * two); }); glam_test!(test_is_finite, { @@ -471,7 +513,7 @@ macro_rules! impl_quat_tests { mod quat { use crate::support::{deg, rad}; use core::ops::Neg; - use glam::{const_quat, quat, EulerRot, Mat3, Mat4, Quat, Vec2, Vec3, Vec3A, Vec4}; + use glam::{quat, EulerRot, Mat3, Mat4, Quat, Vec2, Vec3, Vec3A, Vec4}; glam_test!(test_align, { use std::mem; @@ -544,6 +586,16 @@ mod quat { assert_approx_eq!(-Vec3A::X, mrzx.mul_vec3a(Vec3A::Y)); }); + glam_test!(test_from_mat3a, { + use glam::Mat3A; + let yaw = deg(30.0); + let y0 = Quat::from_rotation_y(yaw); + let y1 = Quat::from_mat3a(&Mat3A::from_rotation_y(yaw)); + assert_approx_eq!(y0, y1); + let y2 = Quat::from_mat3a(&Mat3A::from_quat(y0)); + assert_approx_eq!(y0, y2); + }); + glam_test!(test_as, { use glam::DQuat; assert_approx_eq!( @@ -556,13 +608,13 @@ mod quat { ); }); - impl_quat_tests!(f32, const_quat, quat, Mat3, Mat4, Quat, Vec2, Vec3, Vec4); + impl_quat_tests!(f32, quat, Mat3, Mat4, Quat, Vec2, Vec3, Vec4); } mod dquat { use crate::support::{deg, rad}; use core::ops::Neg; - use glam::{const_dquat, dquat, DMat3, DMat4, DQuat, DVec2, DVec3, DVec4, EulerRot}; + use glam::{dquat, DMat3, DMat4, DQuat, DVec2, DVec3, DVec4, EulerRot}; glam_test!(test_align, { use std::mem; @@ -570,15 +622,5 @@ mod dquat { assert_eq!(mem::align_of::(), mem::align_of::()); }); - impl_quat_tests!( - f64, - const_dquat, - dquat, - DMat3, - DMat4, - DQuat, - DVec2, - DVec3, - DVec4 - ); + impl_quat_tests!(f64, dquat, DMat3, DMat4, DQuat, DVec2, DVec3, DVec4); } diff --git a/tests/support.rs b/tests/support.rs new file mode 100644 index 0000000..08000e9 --- /dev/null +++ b/tests/support.rs @@ -0,0 +1,281 @@ +#[path = "support/macros.rs"] +#[macro_use] +mod macros; + +#[cfg(target_arch = "wasm32")] +wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); + +use glam::{ + DMat2, DMat3, DMat4, DQuat, DVec2, DVec3, DVec4, Mat2, Mat3, Mat3A, Mat4, Quat, Vec2, Vec3, + Vec3A, Vec4, +}; + +pub trait Deg { + fn to_radians(self) -> Self; +} + +impl Deg for f32 { + fn to_radians(self) -> f32 { + f32::to_radians(self) + } +} + +impl Deg for f64 { + fn to_radians(self) -> f64 { + f64::to_radians(self) + } +} + +/// Helper function for migrating away from `glam::angle::deg`. +#[allow(dead_code)] +#[inline] +pub fn deg(angle: T) -> T { + angle.to_radians() +} + +/// Helper function for migrating away from `glam::angle::rad`. +#[allow(dead_code)] +#[inline] +pub fn rad(angle: T) -> T { + angle +} + +/// Trait used by the `assert_approx_eq` macro for floating point comparisons. +pub trait FloatCompare { + /// Return true if the absolute difference between `self` and `other` is + /// less then or equal to `max_abs_diff`. + fn approx_eq(&self, other: &Rhs, max_abs_diff: f32) -> bool; + /// Returns the absolute difference of `self` and `other` which is printed + /// if `assert_approx_eq` fails. + fn abs_diff(&self, other: &Rhs) -> Rhs; +} + +impl FloatCompare for f32 { + #[inline] + fn approx_eq(&self, other: &f32, max_abs_diff: f32) -> bool { + (self - other).abs() <= max_abs_diff + } + #[inline] + fn abs_diff(&self, other: &f32) -> f32 { + (self - other).abs() + } +} + +impl FloatCompare for f64 { + #[inline] + fn approx_eq(&self, other: &f64, max_abs_diff: f32) -> bool { + (self - other).abs() <= max_abs_diff as f64 + } + #[inline] + fn abs_diff(&self, other: &f64) -> f64 { + (self - other).abs() + } +} + +impl FloatCompare for Mat2 { + #[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_cols( + (self.x_axis - other.x_axis).abs(), + (self.y_axis - other.y_axis).abs(), + ) + } +} + +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) + } + #[inline] + fn abs_diff(&self, other: &Self) -> Self { + Self::from_cols( + (self.x_axis - other.x_axis).abs(), + (self.y_axis - other.y_axis).abs(), + ) + } +} + +impl FloatCompare for Mat3 { + #[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_cols( + (self.x_axis - other.x_axis).abs(), + (self.y_axis - other.y_axis).abs(), + (self.z_axis - other.z_axis).abs(), + ) + } +} + +impl FloatCompare for Mat3A { + #[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_cols( + (self.x_axis - other.x_axis).abs(), + (self.y_axis - other.y_axis).abs(), + (self.z_axis - other.z_axis).abs(), + ) + } +} + +impl FloatCompare for DMat3 { + #[inline] + fn approx_eq(&self, other: &Self, max_abs_diff: f32) -> bool { + self.abs_diff_eq(*other, max_abs_diff as f64) + } + #[inline] + fn abs_diff(&self, other: &Self) -> Self { + Self::from_cols( + (self.x_axis - other.x_axis).abs(), + (self.y_axis - other.y_axis).abs(), + (self.z_axis - other.z_axis).abs(), + ) + } +} + +impl FloatCompare for DMat4 { + #[inline] + fn approx_eq(&self, other: &Self, max_abs_diff: f32) -> bool { + self.abs_diff_eq(*other, max_abs_diff as f64) + } + #[inline] + fn abs_diff(&self, other: &Self) -> Self { + Self::from_cols( + (self.x_axis - other.x_axis).abs(), + (self.y_axis - other.y_axis).abs(), + (self.z_axis - other.z_axis).abs(), + (self.w_axis - other.w_axis).abs(), + ) + } +} + +impl FloatCompare for Mat4 { + #[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_cols( + (self.x_axis - other.x_axis).abs(), + (self.y_axis - other.y_axis).abs(), + (self.z_axis - other.z_axis).abs(), + (self.w_axis - other.w_axis).abs(), + ) + } +} + +impl FloatCompare for Quat { + #[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 { + let a: Vec4 = (*self).into(); + let b: Vec4 = (*other).into(); + Quat::from_vec4((a - b).abs()) + } +} + +impl FloatCompare for Vec2 { + #[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 - *other).abs() + } +} + +impl FloatCompare for Vec3 { + #[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 - *other).abs() + } +} + +impl FloatCompare for Vec3A { + #[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 - *other).abs() + } +} + +impl FloatCompare for Vec4 { + #[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 - *other).abs() + } +} + +impl FloatCompare for DQuat { + #[inline] + fn approx_eq(&self, other: &Self, max_abs_diff: f32) -> bool { + self.abs_diff_eq(*other, max_abs_diff as f64) + } + #[inline] + fn abs_diff(&self, other: &Self) -> Self { + let a: DVec4 = (*self).into(); + let b: DVec4 = (*other).into(); + DQuat::from_vec4((a - b).abs()) + } +} + +impl FloatCompare for DVec2 { + #[inline] + fn approx_eq(&self, other: &Self, max_abs_diff: f32) -> bool { + self.abs_diff_eq(*other, max_abs_diff as f64) + } + #[inline] + fn abs_diff(&self, other: &Self) -> Self { + (*self - *other).abs() + } +} + +impl FloatCompare for DVec3 { + #[inline] + fn approx_eq(&self, other: &Self, max_abs_diff: f32) -> bool { + self.abs_diff_eq(*other, max_abs_diff as f64) + } + #[inline] + fn abs_diff(&self, other: &Self) -> Self { + (*self - *other).abs() + } +} + +impl FloatCompare for DVec4 { + #[inline] + fn approx_eq(&self, other: &Self, max_abs_diff: f32) -> bool { + self.abs_diff_eq(*other, max_abs_diff as f64) + } + #[inline] + fn abs_diff(&self, other: &Self) -> Self { + (*self - *other).abs() + } +} diff --git a/tests/support/macros.rs b/tests/support/macros.rs index 01adc4b..9801902 100644 --- a/tests/support/macros.rs +++ b/tests/support/macros.rs @@ -29,7 +29,7 @@ macro_rules! should_glam_assert { macro_rules! assert_approx_eq { ($a:expr, $b:expr) => {{ #[allow(unused_imports)] - use crate::support::FloatCompare; + use $crate::support::FloatCompare; let eps = core::f32::EPSILON; let (a, b) = (&$a, &$b); assert!( @@ -43,7 +43,7 @@ macro_rules! assert_approx_eq { ); }}; ($a:expr, $b:expr, $eps:expr) => {{ - use crate::support::FloatCompare; + use $crate::support::FloatCompare; let (a, b) = (&$a, &$b); let eps = $eps; assert!( diff --git a/tests/support/mod.rs b/tests/support/mod.rs deleted file mode 100644 index 865aa5e..0000000 --- a/tests/support/mod.rs +++ /dev/null @@ -1,280 +0,0 @@ -#[macro_use] -mod macros; - -#[cfg(target_arch = "wasm32")] -wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); - -use glam::{ - DMat2, DMat3, DMat4, DQuat, DVec2, DVec3, DVec4, Mat2, Mat3, Mat3A, Mat4, Quat, Vec2, Vec3, - Vec3A, Vec4, -}; - -pub trait Deg { - fn to_radians(self) -> Self; -} - -impl Deg for f32 { - fn to_radians(self) -> f32 { - f32::to_radians(self) - } -} - -impl Deg for f64 { - fn to_radians(self) -> f64 { - f64::to_radians(self) - } -} - -/// Helper function for migrating away from `glam::angle::deg`. -#[allow(dead_code)] -#[inline] -pub fn deg(angle: T) -> T { - angle.to_radians() -} - -/// Helper function for migrating away from `glam::angle::rad`. -#[allow(dead_code)] -#[inline] -pub fn rad(angle: T) -> T { - angle -} - -/// Trait used by the `assert_approx_eq` macro for floating point comparisons. -pub trait FloatCompare { - /// Return true if the absolute difference between `self` and `other` is - /// less then or equal to `max_abs_diff`. - fn approx_eq(&self, other: &Rhs, max_abs_diff: f32) -> bool; - /// Returns the absolute difference of `self` and `other` which is printed - /// if `assert_approx_eq` fails. - fn abs_diff(&self, other: &Rhs) -> Rhs; -} - -impl FloatCompare for f32 { - #[inline] - fn approx_eq(&self, other: &f32, max_abs_diff: f32) -> bool { - (self - other).abs() <= max_abs_diff - } - #[inline] - fn abs_diff(&self, other: &f32) -> f32 { - (self - other).abs() - } -} - -impl FloatCompare for f64 { - #[inline] - fn approx_eq(&self, other: &f64, max_abs_diff: f32) -> bool { - (self - other).abs() <= max_abs_diff as f64 - } - #[inline] - fn abs_diff(&self, other: &f64) -> f64 { - (self - other).abs() - } -} - -impl FloatCompare for Mat2 { - #[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_cols( - (self.x_axis - other.x_axis).abs(), - (self.y_axis - other.y_axis).abs(), - ) - } -} - -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) - } - #[inline] - fn abs_diff(&self, other: &Self) -> Self { - Self::from_cols( - (self.x_axis - other.x_axis).abs(), - (self.y_axis - other.y_axis).abs(), - ) - } -} - -impl FloatCompare for Mat3 { - #[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_cols( - (self.x_axis - other.x_axis).abs(), - (self.y_axis - other.y_axis).abs(), - (self.z_axis - other.z_axis).abs(), - ) - } -} - -impl FloatCompare for Mat3A { - #[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_cols( - (self.x_axis - other.x_axis).abs(), - (self.y_axis - other.y_axis).abs(), - (self.z_axis - other.z_axis).abs(), - ) - } -} - -impl FloatCompare for DMat3 { - #[inline] - fn approx_eq(&self, other: &Self, max_abs_diff: f32) -> bool { - self.abs_diff_eq(*other, max_abs_diff as f64) - } - #[inline] - fn abs_diff(&self, other: &Self) -> Self { - Self::from_cols( - (self.x_axis - other.x_axis).abs(), - (self.y_axis - other.y_axis).abs(), - (self.z_axis - other.z_axis).abs(), - ) - } -} - -impl FloatCompare for DMat4 { - #[inline] - fn approx_eq(&self, other: &Self, max_abs_diff: f32) -> bool { - self.abs_diff_eq(*other, max_abs_diff as f64) - } - #[inline] - fn abs_diff(&self, other: &Self) -> Self { - Self::from_cols( - (self.x_axis - other.x_axis).abs(), - (self.y_axis - other.y_axis).abs(), - (self.z_axis - other.z_axis).abs(), - (self.w_axis - other.w_axis).abs(), - ) - } -} - -impl FloatCompare for Mat4 { - #[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_cols( - (self.x_axis - other.x_axis).abs(), - (self.y_axis - other.y_axis).abs(), - (self.z_axis - other.z_axis).abs(), - (self.w_axis - other.w_axis).abs(), - ) - } -} - -impl FloatCompare for Quat { - #[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 { - let a: Vec4 = (*self).into(); - let b: Vec4 = (*other).into(); - Quat::from_vec4((a - b).abs()) - } -} - -impl FloatCompare for Vec2 { - #[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 - *other).abs() - } -} - -impl FloatCompare for Vec3 { - #[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 - *other).abs() - } -} - -impl FloatCompare for Vec3A { - #[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 - *other).abs() - } -} - -impl FloatCompare for Vec4 { - #[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 - *other).abs() - } -} - -impl FloatCompare for DQuat { - #[inline] - fn approx_eq(&self, other: &Self, max_abs_diff: f32) -> bool { - self.abs_diff_eq(*other, max_abs_diff as f64) - } - #[inline] - fn abs_diff(&self, other: &Self) -> Self { - let a: DVec4 = (*self).into(); - let b: DVec4 = (*other).into(); - DQuat::from_vec4((a - b).abs()) - } -} - -impl FloatCompare for DVec2 { - #[inline] - fn approx_eq(&self, other: &Self, max_abs_diff: f32) -> bool { - self.abs_diff_eq(*other, max_abs_diff as f64) - } - #[inline] - fn abs_diff(&self, other: &Self) -> Self { - (*self - *other).abs() - } -} - -impl FloatCompare for DVec3 { - #[inline] - fn approx_eq(&self, other: &Self, max_abs_diff: f32) -> bool { - self.abs_diff_eq(*other, max_abs_diff as f64) - } - #[inline] - fn abs_diff(&self, other: &Self) -> Self { - (*self - *other).abs() - } -} - -impl FloatCompare for DVec4 { - #[inline] - fn approx_eq(&self, other: &Self, max_abs_diff: f32) -> bool { - self.abs_diff_eq(*other, max_abs_diff as f64) - } - #[inline] - fn abs_diff(&self, other: &Self) -> Self { - (*self - *other).abs() - } -} diff --git a/tests/transform.rs b/tests/transform.rs deleted file mode 100644 index e7f7715..0000000 --- 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 0d0b798..8ebdd62 100644 --- a/tests/vec2.rs +++ b/tests/vec2.rs @@ -1,11 +1,24 @@ +#![allow(clippy::excessive_precision)] + #[macro_use] mod support; macro_rules! impl_vec2_tests { - ($t:ty, $const_new:ident, $new:ident, $vec2:ident, $vec3:ident, $mask:ident) => { + ($t:ty, $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]); + 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()); + }); + + glam_test!(test_vec2_consts, { + assert_eq!($vec2::ZERO, $new(0 as $t, 0 as $t)); + assert_eq!($vec2::ONE, $new(1 as $t, 1 as $t)); + assert_eq!($vec2::X, $new(1 as $t, 0 as $t)); + assert_eq!($vec2::Y, $new(0 as $t, 1 as $t)); }); glam_test!(test_new, { @@ -23,6 +36,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 +56,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 +105,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 +125,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; @@ -139,9 +182,10 @@ macro_rules! impl_vec2_tests { }); glam_test!(test_hmin_hmax, { - let a = $new(1 as $t, 2 as $t); - assert_eq!(1 as $t, a.min_element()); - assert_eq!(2 as $t, a.max_element()); + assert_eq!(1 as $t, $new(1 as $t, 2 as $t).min_element()); + assert_eq!(1 as $t, $new(2 as $t, 1 as $t).min_element()); + assert_eq!(2 as $t, $new(1 as $t, 2 as $t).max_element()); + assert_eq!(2 as $t, $new(2 as $t, 1 as $t).max_element()); }); glam_test!(test_eq, { @@ -195,21 +239,37 @@ 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_splat, { + assert_eq!($mask::splat(false), $mask::new(false, false)); + assert_eq!($mask::splat(true), $mask::new(true, true)); + }); + glam_test!(test_mask_bitmask, { assert_eq!($mask::new(false, false).bitmask(), 0b00); assert_eq!($mask::new(true, false).bitmask(), 0b01); @@ -298,6 +358,29 @@ macro_rules! impl_vec2_tests { assert_eq!(mask.bitmask(), 0b11); }); + glam_test!(test_mask_xor, { + assert_eq!( + ($mask::new(false, false) ^ $mask::new(false, false)).bitmask(), + 0b00, + ); + assert_eq!( + ($mask::new(false, false) ^ $mask::new(false, true)).bitmask(), + 0b10, + ); + assert_eq!( + ($mask::new(true, false) ^ $mask::new(false, true)).bitmask(), + 0b11, + ); + assert_eq!( + ($mask::new(true, true) ^ $mask::new(true, true)).bitmask(), + 0b00, + ); + + let mut mask = $mask::new(false, true); + mask ^= $mask::new(true, false); + assert_eq!(mask.bitmask(), 0b11); + }); + glam_test!(test_mask_not, { assert_eq!((!$mask::new(false, false)).bitmask(), 0b11); assert_eq!((!$mask::new(true, false)).bitmask(), 0b10); @@ -366,18 +449,20 @@ macro_rules! impl_vec2_tests { glam_test!(test_sum, { let one = $vec2::ONE; assert_eq!(vec![one, one].iter().sum::<$vec2>(), one + one); + assert_eq!(vec![one, one].into_iter().sum::<$vec2>(), one + one); }); glam_test!(test_product, { let two = $vec2::new(2 as $t, 2 as $t); assert_eq!(vec![two, two].iter().product::<$vec2>(), two * two); + assert_eq!(vec![two, two].into_iter().product::<$vec2>(), two * two); }); }; } macro_rules! impl_vec2_signed_tests { - ($t:ident, $const_new:ident, $new:ident, $vec2:ident, $vec3:ident, $mask:ident) => { - impl_vec2_tests!($t, $const_new, $new, $vec2, $vec3, $mask); + ($t:ident, $new:ident, $vec2:ident, $vec3:ident, $mask:ident) => { + impl_vec2_tests!($t, $new, $vec2, $vec3, $mask); glam_test!(test_dot_signed, { let x = $new(1 as $t, 0 as $t); @@ -390,6 +475,26 @@ macro_rules! impl_vec2_signed_tests { glam_test!(test_neg, { let a = $new(1 as $t, 2 as $t); assert_eq!($new(-1 as $t, -2 as $t), (-a)); + assert_eq!($new(-0.0 as $t, -0.0 as $t), -$new(0.0 as $t, 0.0 as $t)); + assert_eq!($new(0.0 as $t, -0.0 as $t), -$new(-0.0 as $t, 0.0 as $t)); + }); + + glam_test!(test_perp, { + let v1 = $vec2::new(1 as $t, 2 as $t); + let v2 = $vec2::new(1 as $t, 1 as $t); + let v1_perp = $vec2::new(-2 as $t, 1 as $t); + + assert_eq!(v1_perp, v1.perp()); + assert_eq!(v1.perp().dot(v1), 0 as $t); + assert_eq!(v2.perp().dot(v2), 0 as $t); + assert_eq!(v1.perp().dot(v2), v1.perp_dot(v2)); + }); + + glam_test!(test_rotate, { + assert_eq!( + $vec2::new(0 as $t, 1 as $t).rotate($vec2::new(1 as $t, 1 as $t)), + $vec2::new(-1 as $t, 1 as $t) + ); }); }; } @@ -426,21 +531,14 @@ macro_rules! impl_vec2_eq_hash_tests { } macro_rules! impl_vec2_float_tests { - ($t:ident, $const_new:ident, $new:ident, $vec2:ident, $vec3:ident, $mask:ident, $mat2:ident) => { - impl_vec2_signed_tests!($t, $const_new, $new, $vec2, $vec3, $mask); + ($t:ident, $new:ident, $vec2:ident, $vec3:ident, $mask:ident) => { + impl_vec2_signed_tests!($t, $new, $vec2, $vec3, $mask); impl_vec_float_normalize_tests!($t, $vec2); use core::$t::INFINITY; use core::$t::NAN; use core::$t::NEG_INFINITY; - glam_test!(test_vec2_consts, { - assert_eq!($vec2::ZERO, $new(0 as $t, 0 as $t)); - assert_eq!($vec2::ONE, $new(1 as $t, 1 as $t)); - assert_eq!($vec2::X, $new(1 as $t, 0 as $t)); - assert_eq!($vec2::Y, $new(0 as $t, 1 as $t)); - }); - glam_test!(test_vec2_nan, { assert!($vec2::NAN.is_nan()); assert!(!$vec2::NAN.is_finite()); @@ -460,6 +558,7 @@ macro_rules! impl_vec2_float_tests { assert_eq!(13.0, (-5.0 * x).distance(12.0 * y)); assert_eq!(x, (2.0 * x).normalize()); assert_eq!(1.0 * 3.0 + 2.0 * 4.0, $new(1.0, 2.0).dot($new(3.0, 4.0))); + assert_eq!($new(8.0, 8.0), $new(1.0, 2.0).dot_into_vec($new(4.0, 2.0))); assert_eq!(2.0 * 2.0 + 3.0 * 3.0, $new(2.0, 3.0).length_squared()); assert_eq!( (2.0 as $t * 2.0 + 3.0 * 3.0).sqrt(), @@ -494,23 +593,9 @@ macro_rules! impl_vec2_float_tests { should_glam_assert!({ $vec2::ONE.reject_from_normalized($vec2::ONE) }); }); - glam_test!(test_perp, { - let v1 = $vec2::new(1.0, 2.0); - let v2 = $vec2::new(1.0, 1.0); - let v1_perp = $vec2::new(-2.0, 1.0); - let rot90 = $mat2::from_angle($t::to_radians(90.0)); - - assert_eq!(v1_perp, v1.perp()); - assert_eq!(v1.perp().dot(v1), 0.0); - assert_eq!(v2.perp().dot(v2), 0.0); - assert_eq!(v1.perp().dot(v2), v1.perp_dot(v2)); - - assert_approx_eq!(v1.perp(), rot90 * v1); - }); - glam_test!(test_sign, { assert_eq!($vec2::ZERO.signum(), $vec2::ONE); - assert_eq!(-$vec2::ZERO.signum(), -$vec2::ONE); + assert_eq!((-$vec2::ZERO).signum(), -$vec2::ONE); assert_eq!($vec2::ONE.signum(), $vec2::ONE); assert_eq!((-$vec2::ONE).signum(), -$vec2::ONE); assert_eq!($vec2::splat(INFINITY).signum(), $vec2::ONE); @@ -518,6 +603,17 @@ macro_rules! impl_vec2_float_tests { assert!($vec2::splat(NAN).signum().is_nan_mask().all()); }); + glam_test!(test_is_negative_bitmask, { + assert_eq!($vec2::ZERO.is_negative_bitmask(), 0b00); + assert_eq!((-$vec2::ZERO).is_negative_bitmask(), 0b11); + assert_eq!($vec2::ONE.is_negative_bitmask(), 0b00); + assert_eq!((-$vec2::ONE).is_negative_bitmask(), 0b11); + assert_eq!($vec2::new(-0.1, 0.2).is_negative_bitmask(), 0b01); + assert_eq!($vec2::new(0.8, 0.3).is_negative_bitmask(), 0b00); + assert_eq!($vec2::new(0.3, -0.4).is_negative_bitmask(), 0b10); + assert_eq!($vec2::new(-0.2, -0.6).is_negative_bitmask(), 0b11); + }); + glam_test!(test_abs, { assert_eq!($vec2::ZERO.abs(), $vec2::ZERO); assert_eq!($vec2::ONE.abs(), $vec2::ONE); @@ -596,7 +692,7 @@ macro_rules! impl_vec2_float_tests { }); glam_test!(test_exp, { - assert_eq!( + assert_approx_eq!( $vec2::new(1.0, 2.0).exp(), $vec2::new((1.0 as $t).exp(), (2.0 as $t).exp()) ); @@ -671,6 +767,22 @@ macro_rules! impl_vec2_float_tests { $vec2::new(-0.5, 1.0) ); }); + + glam_test!(test_from_angle, { + assert_approx_eq!($vec2::from_angle(0.0), $vec2::new(1.0, 0.0)); + assert_approx_eq!( + $vec2::from_angle(core::$t::consts::FRAC_PI_2), + $vec2::new(0.0, 1.0) + ); + assert_approx_eq!( + $vec2::from_angle(core::$t::consts::PI), + $vec2::new(-1.0, 0.0) + ); + assert_approx_eq!( + $vec2::from_angle(-core::$t::consts::FRAC_PI_2), + $vec2::new(0.0, -1.0) + ); + }); }; } @@ -800,7 +912,7 @@ macro_rules! impl_vec2_bit_op_tests { } mod vec2 { - use glam::{const_vec2, vec2, BVec2, Mat2, Vec2, Vec3}; + use glam::{vec2, BVec2, Vec2, Vec3}; glam_test!(test_align, { use core::mem; @@ -832,11 +944,11 @@ mod vec2 { assert_eq!(Vec2::new(1.0, 2.0), UVec2::new(1, 2).as_vec2()); }); - impl_vec2_float_tests!(f32, const_vec2, vec2, Vec2, Vec3, BVec2, Mat2); + impl_vec2_float_tests!(f32, vec2, Vec2, Vec3, BVec2); } mod dvec2 { - use glam::{const_dvec2, dvec2, BVec2, DMat2, DVec2, DVec3}; + use glam::{dvec2, BVec2, DVec2, DVec3}; glam_test!(test_align, { use core::mem; @@ -849,11 +961,11 @@ mod dvec2 { assert_eq!(1, mem::align_of::()); }); - impl_vec2_float_tests!(f64, const_dvec2, dvec2, DVec2, DVec3, BVec2, DMat2); + impl_vec2_float_tests!(f64, dvec2, DVec2, DVec3, BVec2); } mod ivec2 { - use glam::{const_ivec2, ivec2, BVec2, IVec2, IVec3, UVec2}; + use glam::{ivec2, BVec2, IVec2, IVec3, UVec2}; glam_test!(test_align, { use core::mem; @@ -866,7 +978,7 @@ mod ivec2 { assert_eq!(1, mem::align_of::()); }); - impl_vec2_signed_tests!(i32, const_ivec2, ivec2, IVec2, IVec3, BVec2); + impl_vec2_signed_tests!(i32, ivec2, IVec2, IVec3, BVec2); impl_vec2_eq_hash_tests!(i32, ivec2); impl_vec2_scalar_shift_op_tests!(IVec2, -2, 2); @@ -877,7 +989,7 @@ mod ivec2 { } mod uvec2 { - use glam::{const_uvec2, uvec2, BVec2, IVec2, UVec2, UVec3}; + use glam::{uvec2, BVec2, IVec2, UVec2, UVec3}; glam_test!(test_align, { use core::mem; @@ -890,7 +1002,7 @@ mod uvec2 { assert_eq!(1, mem::align_of::()); }); - impl_vec2_tests!(u32, const_uvec2, uvec2, UVec2, UVec3, BVec2); + impl_vec2_tests!(u32, uvec2, UVec2, UVec3, BVec2); impl_vec2_eq_hash_tests!(u32, uvec2); impl_vec2_scalar_shift_op_tests!(UVec2, 0, 2); diff --git a/tests/vec3.rs b/tests/vec3.rs index 4b2e047..fae8858 100644 --- a/tests/vec3.rs +++ b/tests/vec3.rs @@ -1,11 +1,25 @@ +#![allow(clippy::excessive_precision)] + #[macro_use] mod support; macro_rules! impl_vec3_tests { - ($t:ident, $const_new:ident, $new:ident, $vec3:ident, $mask:ident) => { + ($t: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]); + 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()); + }); + + glam_test!(test_vec3_consts, { + assert_eq!($vec3::ZERO, $new(0 as $t, 0 as $t, 0 as $t)); + assert_eq!($vec3::ONE, $new(1 as $t, 1 as $t, 1 as $t)); + assert_eq!($vec3::X, $new(1 as $t, 0 as $t, 0 as $t)); + assert_eq!($vec3::Y, $new(0 as $t, 1 as $t, 0 as $t)); + assert_eq!($vec3::Z, $new(0 as $t, 0 as $t, 1 as $t)); }); glam_test!(test_new, { @@ -24,6 +38,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 +59,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 +121,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 +141,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; @@ -153,9 +198,12 @@ macro_rules! impl_vec3_tests { }); glam_test!(test_hmin_hmax, { - let a = $new(2 as $t, 3 as $t, 1 as $t); - assert_eq!(1 as $t, a.min_element()); - assert_eq!(3 as $t, a.max_element()); + assert_eq!(1 as $t, $new(1 as $t, 2 as $t, 3 as $t).min_element()); + assert_eq!(1 as $t, $new(3 as $t, 1 as $t, 2 as $t).min_element()); + assert_eq!(1 as $t, $new(2 as $t, 3 as $t, 1 as $t).min_element()); + assert_eq!(3 as $t, $new(1 as $t, 2 as $t, 3 as $t).max_element()); + assert_eq!(3 as $t, $new(3 as $t, 1 as $t, 2 as $t).max_element()); + assert_eq!(3 as $t, $new(2 as $t, 3 as $t, 1 as $t).max_element()); }); glam_test!(test_eq, { @@ -211,17 +259,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] @@ -248,6 +286,38 @@ 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_splat, { + assert_eq!($mask::splat(false), $mask::new(false, false, false)); + assert_eq!($mask::splat(true), $mask::new(true, true, true)); + }); + glam_test!(test_mask_bitmask, { assert_eq!($mask::new(false, false, false).bitmask(), 0b000); assert_eq!($mask::new(true, false, false).bitmask(), 0b001); @@ -338,6 +408,29 @@ macro_rules! impl_vec3_tests { assert_eq!(mask.bitmask(), 0b011); }); + glam_test!(test_mask_xor, { + assert_eq!( + ($mask::new(false, false, false) ^ $mask::new(false, false, false)).bitmask(), + 0b000, + ); + assert_eq!( + ($mask::new(true, true, true) ^ $mask::new(true, true, true)).bitmask(), + 0b000, + ); + assert_eq!( + ($mask::new(true, false, true) ^ $mask::new(false, true, false)).bitmask(), + 0b111, + ); + assert_eq!( + ($mask::new(true, false, true) ^ $mask::new(true, false, true)).bitmask(), + 0b000, + ); + + let mut mask = $mask::new(true, true, false); + mask ^= $mask::new(true, false, false); + assert_eq!(mask.bitmask(), 0b010); + }); + glam_test!(test_mask_not, { assert_eq!((!$mask::new(false, false, false)).bitmask(), 0b111); assert_eq!((!$mask::new(true, true, true)).bitmask(), 0b000); @@ -348,11 +441,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]"); @@ -409,22 +502,32 @@ macro_rules! impl_vec3_tests { glam_test!(test_sum, { let one = $vec3::ONE; assert_eq!(vec![one, one].iter().sum::<$vec3>(), one + one); + assert_eq!(vec![one, one].into_iter().sum::<$vec3>(), one + one); }); glam_test!(test_product, { let two = $vec3::new(2 as $t, 2 as $t, 2 as $t); assert_eq!(vec![two, two].iter().product::<$vec3>(), two * two); + assert_eq!(vec![two, two].into_iter().product::<$vec3>(), two * two); }); }; } macro_rules! impl_vec3_signed_tests { - ($t:ident, $const_new:ident, $new:ident, $vec3:ident, $mask:ident) => { - impl_vec3_tests!($t, $const_new, $new, $vec3, $mask); + ($t:ident, $new:ident, $vec3:ident, $mask:ident) => { + impl_vec3_tests!($t, $new, $vec3, $mask); glam_test!(test_neg, { let a = $new(1 as $t, 2 as $t, 3 as $t); assert_eq!((-1 as $t, -2 as $t, -3 as $t), (-a).into()); + assert_eq!( + $new(-0.0 as $t, -0.0 as $t, -0.0 as $t), + -$new(0.0 as $t, 0.0 as $t, 0.0 as $t) + ); + assert_eq!( + $new(0.0 as $t, -0.0 as $t, -0.0 as $t), + -$new(-0.0 as $t, 0.0 as $t, 0.0 as $t) + ); }); glam_test!(test_dot_signed, { @@ -470,8 +573,8 @@ macro_rules! impl_vec3_eq_hash_tests { } macro_rules! impl_vec3_float_tests { - ($t:ident, $const_new:ident, $new:ident, $vec3:ident, $mask:ident) => { - impl_vec3_signed_tests!($t, $const_new, $new, $vec3, $mask); + ($t:ident, $new:ident, $vec3:ident, $mask:ident) => { + impl_vec3_signed_tests!($t, $new, $vec3, $mask); impl_vec_float_normalize_tests!($t, $vec3); use core::$t::INFINITY; @@ -483,14 +586,6 @@ macro_rules! impl_vec3_float_tests { assert!(!$vec3::NAN.is_finite()); }); - glam_test!(test_vec3_consts, { - assert_eq!($vec3::ZERO, $new(0 as $t, 0 as $t, 0 as $t)); - assert_eq!($vec3::ONE, $new(1 as $t, 1 as $t, 1 as $t)); - assert_eq!($vec3::X, $new(1 as $t, 0 as $t, 0 as $t)); - assert_eq!($vec3::Y, $new(0 as $t, 1 as $t, 0 as $t)); - assert_eq!($vec3::Z, $new(0 as $t, 0 as $t, 1 as $t)); - }); - glam_test!(test_funcs, { let x = $new(1.0, 0.0, 0.0); let y = $new(0.0, 1.0, 0.0); @@ -513,6 +608,10 @@ macro_rules! impl_vec3_float_tests { 1.0 * 4.0 + 2.0 * 5.0 + 3.0 * 6.0, $new(1.0, 2.0, 3.0).dot($new(4.0, 5.0, 6.0)) ); + assert_eq!( + $new(14.0, 14.0, 14.0), + $new(0.0, 4.0, 6.0).dot_into_vec($new(3.0, 2.0, 1.0)) + ); assert_eq!( 2.0 * 2.0 + 3.0 * 3.0 + 4.0 * 4.0, $new(2.0, 3.0, 4.0).length_squared() @@ -558,7 +657,7 @@ macro_rules! impl_vec3_float_tests { glam_test!(test_signum, { assert_eq!($vec3::ZERO.signum(), $vec3::ONE); - assert_eq!(-$vec3::ZERO.signum(), -$vec3::ONE); + assert_eq!((-$vec3::ZERO).signum(), -$vec3::ONE); assert_eq!($vec3::ONE.signum(), $vec3::ONE); assert_eq!((-$vec3::ONE).signum(), -$vec3::ONE); assert_eq!($vec3::splat(INFINITY).signum(), $vec3::ONE); @@ -566,6 +665,18 @@ macro_rules! impl_vec3_float_tests { assert!($vec3::splat(NAN).signum().is_nan_mask().all()); }); + glam_test!(test_is_negative_bitmask, { + assert_eq!($vec3::ZERO.is_negative_bitmask(), 0b000); + assert_eq!((-$vec3::ZERO).is_negative_bitmask(), 0b111); + assert_eq!($vec3::ONE.is_negative_bitmask(), 0b000); + assert_eq!((-$vec3::ONE).is_negative_bitmask(), 0b111); + assert_eq!($vec3::new(-0.1, 0.2, 0.3).is_negative_bitmask(), 0b001); + assert_eq!($vec3::new(0.8, 0.3, 0.1).is_negative_bitmask(), 0b000); + assert_eq!($vec3::new(0.1, 0.5, -0.3).is_negative_bitmask(), 0b100); + assert_eq!($vec3::new(0.3, -0.4, 0.1).is_negative_bitmask(), 0b010); + assert_eq!($vec3::new(-0.2, 0.6, -0.5).is_negative_bitmask(), 0b101); + }); + glam_test!(test_abs, { assert_eq!($vec3::ZERO.abs(), $vec3::ZERO); assert_eq!($vec3::ONE.abs(), $vec3::ONE); @@ -656,7 +767,7 @@ macro_rules! impl_vec3_float_tests { }); glam_test!(test_exp, { - assert_eq!( + assert_approx_eq!( $vec3::new(1.0, 2.0, 3.0).exp(), $vec3::new((1.0 as $t).exp(), (2.0 as $t).exp(), (3.0 as $t).exp()) ); @@ -901,7 +1012,7 @@ macro_rules! impl_vec3_bit_op_tests { } mod vec3 { - use glam::{const_vec3, vec3, BVec3, Vec3}; + use glam::{vec3, BVec3, Vec3}; glam_test!(test_align, { use std::mem; @@ -967,26 +1078,32 @@ mod vec3 { assert_eq!(Vec3A::new(1.0, 2.0, 3.0), UVec3::new(1, 2, 3).as_vec3a()); }); - impl_vec3_float_tests!(f32, const_vec3, vec3, Vec3, BVec3); + impl_vec3_float_tests!(f32, vec3, Vec3, BVec3); } mod vec3a { - use glam::{const_vec3a, vec3a, BVec3A, Vec3A, Vec4}; + #[cfg(any( + not(any(target_feature = "sse2", target_feature = "simd128")), + feature = "scalar-math" + ))] + use glam::BVec3; + #[cfg(not(feature = "scalar-math"))] + use glam::BVec3A; + use glam::{vec3a, Vec3A, Vec4}; glam_test!(test_align, { use std::mem; assert_eq!(16, mem::size_of::()); assert_eq!(16, mem::align_of::()); - if cfg!(all( - any(target_feature = "sse2", target_feature = "simd128"), - not(feature = "scalar-math") - )) { + #[cfg(not(feature = "scalar-math"))] + { assert_eq!(16, mem::size_of::()); assert_eq!(16, mem::align_of::()); - } else { - // BVec3A aliases BVec3 - assert_eq!(3, mem::size_of::()); - assert_eq!(1, mem::align_of::()); + } + #[cfg(feature = "scalar-math")] + { + assert_eq!(3, mem::size_of::()); + assert_eq!(1, mem::align_of::()); } }); @@ -1001,7 +1118,10 @@ mod vec3a { assert!(b.cmpeq(Vec3A::splat(1.0)).all()); }); - #[cfg(all(target_feature = "sse2", not(feature = "scalar-math")))] + #[cfg(all( + target_feature = "sse2", + not(any(feature = "core-simd", feature = "scalar-math")) + ))] #[test] fn test_m128() { #[cfg(target_arch = "x86")] @@ -1042,11 +1162,21 @@ mod vec3a { assert_eq!(v2.min_element(), 2.0); }); - impl_vec3_float_tests!(f32, const_vec3a, vec3a, Vec3A, BVec3A); + #[cfg(all( + any(target_feature = "sse2", target_feature = "simd128"), + not(feature = "scalar-math") + ))] + impl_vec3_float_tests!(f32, vec3a, Vec3A, BVec3A); + + #[cfg(any( + not(any(target_feature = "sse2", target_feature = "simd128")), + feature = "scalar-math" + ))] + impl_vec3_float_tests!(f32, vec3a, Vec3A, BVec3); } mod dvec3 { - use glam::{const_dvec3, dvec3, BVec3, DVec3}; + use glam::{dvec3, BVec3, DVec3}; glam_test!(test_align, { use std::mem; @@ -1056,11 +1186,11 @@ mod dvec3 { assert_eq!(1, mem::align_of::()); }); - impl_vec3_float_tests!(f64, const_dvec3, dvec3, DVec3, BVec3); + impl_vec3_float_tests!(f64, dvec3, DVec3, BVec3); } mod ivec3 { - use glam::{const_ivec3, ivec3, BVec3, IVec3, UVec3}; + use glam::{ivec3, BVec3, IVec3, UVec3}; glam_test!(test_align, { use std::mem; @@ -1070,7 +1200,7 @@ mod ivec3 { assert_eq!(1, mem::align_of::()); }); - impl_vec3_signed_tests!(i32, const_ivec3, ivec3, IVec3, BVec3); + impl_vec3_signed_tests!(i32, ivec3, IVec3, BVec3); impl_vec3_eq_hash_tests!(i32, ivec3); impl_vec3_scalar_shift_op_tests!(IVec3, -2, 2); @@ -1081,7 +1211,7 @@ mod ivec3 { } mod uvec3 { - use glam::{const_uvec3, uvec3, BVec3, IVec3, UVec3}; + use glam::{uvec3, BVec3, IVec3, UVec3}; glam_test!(test_align, { use std::mem; @@ -1091,7 +1221,7 @@ mod uvec3 { assert_eq!(1, mem::align_of::()); }); - impl_vec3_tests!(u32, const_uvec3, uvec3, UVec3, BVec3); + impl_vec3_tests!(u32, uvec3, UVec3, BVec3); impl_vec3_eq_hash_tests!(u32, uvec3); impl_vec3_scalar_shift_op_tests!(UVec3, 0, 2); diff --git a/tests/vec4.rs b/tests/vec4.rs index 2683348..47f4fa8 100644 --- a/tests/vec4.rs +++ b/tests/vec4.rs @@ -1,11 +1,17 @@ +#![allow(clippy::excessive_precision)] + #[macro_use] mod support; macro_rules! impl_vec4_tests { - ($t:ident, $const_new:ident, $new:ident, $vec4:ident, $vec3:ident, $vec2:ident, $mask:ident) => { + ($t: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]); + 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()); }); glam_test!(test_vec4_consts, { @@ -34,6 +40,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 +88,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 +151,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 +171,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; @@ -193,9 +228,38 @@ macro_rules! impl_vec4_tests { }); glam_test!(test_hmin_hmax, { - let a = $new(3 as $t, 4 as $t, 1 as $t, 2 as $t); - assert_eq!(1 as $t, a.min_element()); - assert_eq!(4 as $t, a.max_element()); + assert_eq!( + 1 as $t, + $new(1 as $t, 2 as $t, 3 as $t, 4 as $t).min_element() + ); + assert_eq!( + 1 as $t, + $new(4 as $t, 1 as $t, 2 as $t, 3 as $t).min_element() + ); + assert_eq!( + 1 as $t, + $new(3 as $t, 4 as $t, 1 as $t, 2 as $t).min_element() + ); + assert_eq!( + 1 as $t, + $new(2 as $t, 3 as $t, 4 as $t, 1 as $t).min_element() + ); + assert_eq!( + 4 as $t, + $new(1 as $t, 2 as $t, 3 as $t, 4 as $t).max_element() + ); + assert_eq!( + 4 as $t, + $new(4 as $t, 1 as $t, 2 as $t, 3 as $t).max_element() + ); + assert_eq!( + 4 as $t, + $new(3 as $t, 4 as $t, 1 as $t, 2 as $t).max_element() + ); + assert_eq!( + 4 as $t, + $new(2 as $t, 3 as $t, 4 as $t, 1 as $t).max_element() + ); assert_eq!( 3 as $t, $new(1 as $t, 2 as $t, 3 as $t, 4 as $t) @@ -265,35 +329,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] @@ -320,6 +356,38 @@ 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_splat, { + assert_eq!($mask::splat(false), $mask::new(false, false, false, false)); + assert_eq!($mask::splat(true), $mask::new(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); @@ -418,6 +486,32 @@ macro_rules! impl_vec4_tests { assert_eq!(mask.bitmask(), 0b0111); }); + glam_test!(test_mask_xor, { + assert_eq!( + ($mask::new(false, false, false, false) ^ $mask::new(false, false, false, false)) + .bitmask(), + 0b0000, + ); + assert_eq!( + ($mask::new(true, true, true, true) ^ $mask::new(true, true, true, true)).bitmask(), + 0b0000, + ); + assert_eq!( + ($mask::new(true, false, true, false) ^ $mask::new(false, true, false, true)) + .bitmask(), + 0b1111, + ); + assert_eq!( + ($mask::new(true, false, true, false) ^ $mask::new(true, false, true, false)) + .bitmask(), + 0b0000, + ); + + let mut mask = $mask::new(true, true, false, false); + mask ^= $mask::new(true, false, true, false); + assert_eq!(mask.bitmask(), 0b0110); + }); + glam_test!(test_mask_not, { assert_eq!((!$mask::new(false, false, false, false)).bitmask(), 0b1111); assert_eq!((!$mask::new(true, true, true, true)).bitmask(), 0b0000); @@ -429,10 +523,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, { @@ -483,22 +577,32 @@ macro_rules! impl_vec4_tests { glam_test!(test_sum, { let one = $vec4::ONE; assert_eq!(vec![one, one].iter().sum::<$vec4>(), one + one); + assert_eq!(vec![one, one].into_iter().sum::<$vec4>(), one + one); }); glam_test!(test_product, { let two = $vec4::new(2 as $t, 2 as $t, 2 as $t, 2 as $t); assert_eq!(vec![two, two].iter().product::<$vec4>(), two * two); + assert_eq!(vec![two, two].into_iter().product::<$vec4>(), two * two); }); }; } macro_rules! impl_vec4_signed_tests { - ($t:ident, $const_new:ident, $new:ident, $vec4:ident, $vec3:ident, $vec2:ident, $mask:ident) => { - impl_vec4_tests!($t, $const_new, $new, $vec4, $vec3, $vec2, $mask); + ($t:ident, $new:ident, $vec4:ident, $vec3:ident, $vec2:ident, $mask:ident) => { + impl_vec4_tests!($t, $new, $vec4, $vec3, $vec2, $mask); glam_test!(test_neg, { let a = $new(1 as $t, 2 as $t, 3 as $t, 4 as $t); assert_eq!((-1 as $t, -2 as $t, -3 as $t, -4 as $t), (-a).into()); + assert_eq!( + $new(-0.0 as $t, -0.0 as $t, -0.0 as $t, -0.0 as $t), + -$new(0.0 as $t, 0.0 as $t, 0.0 as $t, 0.0 as $t) + ); + assert_eq!( + $new(0.0 as $t, -0.0 as $t, -0.0 as $t, -0.0 as $t), + -$new(-0.0 as $t, 0.0 as $t, 0.0 as $t, 0.0 as $t) + ); }); glam_test!(test_dot_signed, { @@ -546,8 +650,8 @@ macro_rules! impl_vec4_eq_hash_tests { } macro_rules! impl_vec4_float_tests { - ($t:ident, $const_new:ident, $new:ident, $vec4:ident, $vec3:ident, $vec2:ident, $mask:ident) => { - impl_vec4_signed_tests!($t, $const_new, $new, $vec4, $vec3, $vec2, $mask); + ($t:ident, $new:ident, $vec4:ident, $vec3:ident, $vec2:ident, $mask:ident) => { + impl_vec4_signed_tests!($t, $new, $vec4, $vec3, $vec2, $mask); impl_vec_float_normalize_tests!($t, $vec4); use core::$t::INFINITY; @@ -582,6 +686,10 @@ macro_rules! impl_vec4_float_tests { 1.0 * 5.0 + 2.0 * 6.0 + 3.0 * 7.0 + 4.0 * 8.0, $new(1.0, 2.0, 3.0, 4.0).dot($new(5.0, 6.0, 7.0, 8.0)) ); + assert_eq!( + $new(28.0, 28.0, 28.0, 28.0), + $new(0.0, 5.0, 3.0, 6.0).dot_into_vec($new(7.0, 2.0, 4.0, 1.0)) + ); assert_eq!( 2.0 * 2.0 + 3.0 * 3.0 + 4.0 * 4.0 + 5.0 * 5.0, $new(2.0, 3.0, 4.0, 5.0).length_squared() @@ -631,7 +739,7 @@ macro_rules! impl_vec4_float_tests { glam_test!(test_signum, { assert_eq!($vec4::ZERO.signum(), $vec4::ONE); - assert_eq!(-$vec4::ZERO.signum(), -$vec4::ONE); + assert_eq!((-$vec4::ZERO).signum(), -$vec4::ONE); assert_eq!($vec4::ONE.signum(), $vec4::ONE); assert_eq!((-$vec4::ONE).signum(), -$vec4::ONE); assert_eq!($vec4::splat(INFINITY).signum(), $vec4::ONE); @@ -639,6 +747,33 @@ macro_rules! impl_vec4_float_tests { assert!($vec4::splat(NAN).signum().is_nan_mask().all()); }); + glam_test!(test_is_negative_bitmask, { + assert_eq!($vec4::ZERO.is_negative_bitmask(), 0b0000); + assert_eq!((-$vec4::ZERO).is_negative_bitmask(), 0b1111); + assert_eq!($vec4::ONE.is_negative_bitmask(), 0b0000); + assert_eq!((-$vec4::ONE).is_negative_bitmask(), 0b1111); + assert_eq!( + $vec4::new(-0.1, 0.2, 0.3, -0.4).is_negative_bitmask(), + 0b1001 + ); + assert_eq!( + $vec4::new(0.8, 0.3, 0.1, -0.0).is_negative_bitmask(), + 0b1000 + ); + assert_eq!( + $vec4::new(0.1, 0.5, -0.3, 0.7).is_negative_bitmask(), + 0b0100 + ); + assert_eq!( + $vec4::new(0.3, -0.4, 0.1, 0.6).is_negative_bitmask(), + 0b0010 + ); + assert_eq!( + $vec4::new(0.2, -0.6, 0.5, -0.3).is_negative_bitmask(), + 0b1010 + ); + }); + glam_test!(test_abs, { assert_eq!($vec4::ZERO.abs(), $vec4::ZERO); assert_eq!($vec4::ONE.abs(), $vec4::ONE); @@ -729,14 +864,15 @@ macro_rules! impl_vec4_float_tests { }); glam_test!(test_exp, { - assert_eq!( + assert_approx_eq!( $vec4::new(1.0, 2.0, 3.0, 4.0).exp(), $vec4::new( (1.0 as $t).exp(), (2.0 as $t).exp(), (3.0 as $t).exp(), (4.0 as $t).exp() - ) + ), + 1e-5 ); }); @@ -966,19 +1102,14 @@ 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; + use glam::BVec4; + #[cfg(not(feature = "scalar-math"))] + use glam::BVec4A; + use glam::{vec4, Vec2, Vec3, Vec4}; glam_test!(test_align, { use std::mem; @@ -988,19 +1119,22 @@ mod vec4 { } else { assert_eq!(4, mem::align_of::()); } - if cfg!(all( - any(target_feature = "sse2", target_feature = "simd128"), - not(feature = "scalar-math") - )) { - 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::()); + #[cfg(not(feature = "scalar-math"))] + { + assert_eq!(16, mem::size_of::()); + assert_eq!(16, mem::align_of::()); + } + #[cfg(feature = "scalar-math")] + { + assert_eq!(4, mem::size_of::()); + assert_eq!(1, mem::align_of::()); } }); - #[cfg(all(target_feature = "sse2", not(feature = "scalar-math")))] + #[cfg(all( + target_feature = "sse2", + not(any(feature = "core-simd", feature = "scalar-math")) + ))] #[test] fn test_m128() { #[cfg(target_arch = "x86")] @@ -1024,7 +1158,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 { @@ -1094,11 +1228,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, vec4, Vec4, Vec3, Vec2, BVec4A); + + #[cfg(any( + not(any(target_feature = "sse2", target_feature = "simd128")), + feature = "scalar-math" + ))] + impl_vec4_float_tests!(f32, vec4, Vec4, Vec3, Vec2, BVec4); } mod dvec4 { - use glam::{const_dvec4, dvec4, BVec4, DVec2, DVec3, DVec4}; + use glam::{dvec4, BVec4, DVec2, DVec3, DVec4}; glam_test!(test_align, { use std::mem; @@ -1111,11 +1255,11 @@ mod dvec4 { assert_eq!(1, mem::align_of::()); }); - impl_vec4_float_tests!(f64, const_dvec4, dvec4, DVec4, DVec3, DVec2, BVec4); + impl_vec4_float_tests!(f64, dvec4, DVec4, DVec3, DVec2, BVec4); } mod ivec4 { - use glam::{const_ivec4, ivec4, BVec4, IVec2, IVec3, IVec4, UVec4}; + use glam::{ivec4, BVec4, IVec2, IVec3, IVec4, UVec4}; glam_test!(test_align, { use std::mem; @@ -1128,7 +1272,7 @@ mod ivec4 { assert_eq!(1, mem::align_of::()); }); - impl_vec4_signed_tests!(i32, const_ivec4, ivec4, IVec4, IVec3, IVec2, BVec4); + impl_vec4_signed_tests!(i32, ivec4, IVec4, IVec3, IVec2, BVec4); impl_vec4_eq_hash_tests!(i32, ivec4); impl_vec4_scalar_shift_op_tests!(IVec4, -2, 2); @@ -1139,7 +1283,7 @@ mod ivec4 { } mod uvec4 { - use glam::{const_uvec4, uvec4, BVec4, IVec4, UVec2, UVec3, UVec4}; + use glam::{uvec4, BVec4, IVec4, UVec2, UVec3, UVec4}; glam_test!(test_align, { use std::mem; @@ -1152,7 +1296,7 @@ mod uvec4 { assert_eq!(1, mem::align_of::()); }); - impl_vec4_tests!(u32, const_uvec4, uvec4, UVec4, UVec3, UVec2, BVec4); + impl_vec4_tests!(u32, uvec4, UVec4, UVec3, UVec2, BVec4); impl_vec4_eq_hash_tests!(u32, uvec4); impl_vec4_scalar_shift_op_tests!(UVec4, 0, 2); -- cgit v1.2.3