aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTreehugger Robot <treehugger-gerrit@google.com>2022-12-12 13:27:53 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2022-12-12 13:27:53 +0000
commit04eeeb9e46d0fd779e6f739d90e5330ebcfb7f58 (patch)
treeaf51ebf0e56625a7fe174ee113efa37eafc17a7a
parent5fe573973beb85bd164579b626cbf587ad54c3a6 (diff)
parent422fefb4294d524d8b7c8529ec8c82c14920138d (diff)
downloadglam-04eeeb9e46d0fd779e6f739d90e5330ebcfb7f58.tar.gz
Merge "Upgrade glam to 0.22.0" am: 422fefb429
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/glam/+/2337863 Change-Id: I62841e523fbcffd42bb2fa7759e1ff5c605d32d6 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--.gitattributes1
-rw-r--r--.github/workflows/ci.yml23
-rw-r--r--.github/workflows/coverage.yml4
-rw-r--r--.tarpaulin.toml8
-rw-r--r--ARCHITECTURE.md151
-rw-r--r--Android.bp10
-rw-r--r--CHANGELOG.md158
-rw-r--r--CONTRIBUTING.md5
-rw-r--r--Cargo.toml31
-rw-r--r--Cargo.toml.orig24
-rw-r--r--METADATA13
-rw-r--r--README.md30
-rw-r--r--benches/support.rs (renamed from benches/support/mod.rs)0
-rw-r--r--benches/transform.rs132
-rw-r--r--benches/vec3.rs2
-rwxr-xr-xbuild_all_msrv.sh8
-rwxr-xr-xbuild_and_test_features.sh19
-rw-r--r--clippy.toml2
-rw-r--r--deny.toml13
-rw-r--r--src/affine2.rs519
-rw-r--r--src/affine3.rs631
-rw-r--r--src/align16.rs27
-rw-r--r--src/bool.rs100
-rw-r--r--src/bool/bvec2.rs168
-rw-r--r--src/bool/bvec3.rs184
-rw-r--r--src/bool/bvec4.rs191
-rw-r--r--src/bool/coresimd.rs2
-rw-r--r--src/bool/coresimd/bvec3a.rs204
-rw-r--r--src/bool/coresimd/bvec4a.rs216
-rw-r--r--src/bool/scalar.rs2
-rw-r--r--src/bool/scalar/bvec3a.rs188
-rw-r--r--src/bool/scalar/bvec4a.rs196
-rw-r--r--src/bool/sse2.rs2
-rw-r--r--src/bool/sse2/bvec3a.rs207
-rw-r--r--src/bool/sse2/bvec4a.rs219
-rw-r--r--src/bool/wasm32.rs2
-rw-r--r--src/bool/wasm32/bvec3a.rs199
-rw-r--r--src/bool/wasm32/bvec4a.rs206
-rw-r--r--src/cast.rs167
-rw-r--r--src/core/mod.rs18
-rw-r--r--src/core/scalar/mask.rs452
-rw-r--r--src/core/scalar/matrix.rs285
-rw-r--r--src/core/scalar/mod.rs4
-rw-r--r--src/core/scalar/quaternion.rs87
-rw-r--r--src/core/scalar/vector.rs1465
-rw-r--r--src/core/sse2/matrix.rs558
-rw-r--r--src/core/sse2/mod.rs4
-rw-r--r--src/core/sse2/quaternion.rs135
-rw-r--r--src/core/sse2/vector.rs871
-rw-r--r--src/core/storage.rs128
-rw-r--r--src/core/traits/matrix.rs985
-rw-r--r--src/core/traits/mod.rs5
-rw-r--r--src/core/traits/projection.rs164
-rw-r--r--src/core/traits/quaternion.rs140
-rw-r--r--src/core/traits/scalar.rs434
-rw-r--r--src/core/traits/vector.rs854
-rw-r--r--src/core/wasm32/float.rs113
-rw-r--r--src/core/wasm32/matrix.rs532
-rw-r--r--src/core/wasm32/mod.rs4
-rw-r--r--src/core/wasm32/quaternion.rs130
-rw-r--r--src/core/wasm32/vector.rs812
-rw-r--r--src/coresimd.rs57
-rw-r--r--src/deref.rs50
-rw-r--r--src/euler.rs140
-rw-r--r--src/f32.rs165
-rw-r--r--src/f32/affine2.rs398
-rw-r--r--src/f32/affine3a.rs531
-rw-r--r--src/f32/coresimd.rs6
-rw-r--r--src/f32/coresimd/mat2.rs478
-rw-r--r--src/f32/coresimd/mat3a.rs747
-rw-r--r--src/f32/coresimd/mat4.rs1506
-rw-r--r--src/f32/coresimd/quat.rs917
-rw-r--r--src/f32/coresimd/vec3a.rs1086
-rw-r--r--src/f32/coresimd/vec4.rs1009
-rw-r--r--src/f32/mat3.rs737
-rw-r--r--src/f32/scalar.rs6
-rw-r--r--src/f32/scalar/mat2.rs458
-rw-r--r--src/f32/scalar/mat3a.rs725
-rw-r--r--src/f32/scalar/mat4.rs1276
-rw-r--r--src/f32/scalar/quat.rs872
-rw-r--r--src/f32/scalar/vec3a.rs1189
-rw-r--r--src/f32/scalar/vec4.rs1196
-rw-r--r--src/f32/sse2.rs6
-rw-r--r--src/f32/sse2/mat2.rs505
-rw-r--r--src/f32/sse2/mat3a.rs732
-rw-r--r--src/f32/sse2/mat4.rs1371
-rw-r--r--src/f32/sse2/quat.rs942
-rw-r--r--src/f32/sse2/vec3a.rs1157
-rw-r--r--src/f32/sse2/vec4.rs1078
-rw-r--r--src/f32/vec2.rs1047
-rw-r--r--src/f32/vec3.rs1151
-rw-r--r--src/f32/wasm32.rs6
-rw-r--r--src/f32/wasm32/mat2.rs480
-rw-r--r--src/f32/wasm32/mat3a.rs727
-rw-r--r--src/f32/wasm32/mat4.rs1362
-rw-r--r--src/f32/wasm32/quat.rs932
-rw-r--r--src/f32/wasm32/vec3a.rs1107
-rw-r--r--src/f32/wasm32/vec4.rs1041
-rw-r--r--src/f64.rs99
-rw-r--r--src/f64/daffine2.rs359
-rw-r--r--src/f64/daffine3.rs520
-rw-r--r--src/f64/dmat2.rs448
-rw-r--r--src/f64/dmat3.rs716
-rw-r--r--src/f64/dmat4.rs1243
-rw-r--r--src/f64/dquat.rs848
-rw-r--r--src/f64/dvec2.rs1047
-rw-r--r--src/f64/dvec3.rs1157
-rw-r--r--src/f64/dvec4.rs1174
-rw-r--r--src/features.rs (renamed from src/features/mod.rs)0
-rw-r--r--src/features/impl_serde.rs221
-rw-r--r--src/float_ex.rs51
-rw-r--r--src/i32.rs42
-rw-r--r--src/i32/ivec2.rs958
-rw-r--r--src/i32/ivec3.rs1036
-rw-r--r--src/i32/ivec4.rs1129
-rw-r--r--src/lib.rs118
-rw-r--r--src/macros.rs459
-rw-r--r--src/mat.rs114
-rw-r--r--src/mat2.rs398
-rw-r--r--src/mat3.rs596
-rw-r--r--src/mat4.rs890
-rw-r--r--src/quat.rs825
-rw-r--r--src/sse2.rs (renamed from src/core/sse2/float.rs)206
-rw-r--r--src/swizzles.rs42
-rw-r--r--src/swizzles/coresimd.rs2
-rw-r--r--src/swizzles/coresimd/vec3a_impl.rs625
-rw-r--r--src/swizzles/coresimd/vec4_impl.rs1997
-rw-r--r--src/swizzles/dvec2_impl.rs (renamed from src/swizzles/dvec2_impl_scalar.rs)169
-rw-r--r--src/swizzles/dvec3_impl.rs (renamed from src/swizzles/dvec3_impl_scalar.rs)541
-rw-r--r--src/swizzles/dvec4_impl.rs (renamed from src/swizzles/dvec4_impl_scalar.rs)1289
-rw-r--r--src/swizzles/ivec2_impl.rs (renamed from src/swizzles/ivec2_impl_scalar.rs)169
-rw-r--r--src/swizzles/ivec3_impl.rs (renamed from src/swizzles/ivec3_impl_scalar.rs)541
-rw-r--r--src/swizzles/ivec4_impl.rs (renamed from src/swizzles/ivec4_impl_scalar.rs)1289
-rw-r--r--src/swizzles/mod.rs35
-rw-r--r--src/swizzles/scalar.rs2
-rw-r--r--src/swizzles/scalar/vec3a_impl.rs (renamed from src/swizzles/vec3a_impl_scalar.rs)541
-rw-r--r--src/swizzles/scalar/vec4_impl.rs (renamed from src/swizzles/vec4_impl_scalar.rs)1289
-rw-r--r--src/swizzles/sse2.rs2
-rw-r--r--src/swizzles/sse2/vec3a_impl.rs628
-rw-r--r--src/swizzles/sse2/vec4_impl.rs2000
-rw-r--r--src/swizzles/uvec2_impl.rs (renamed from src/swizzles/uvec2_impl_scalar.rs)169
-rw-r--r--src/swizzles/uvec3_impl.rs (renamed from src/swizzles/uvec3_impl_scalar.rs)541
-rw-r--r--src/swizzles/uvec4_impl.rs (renamed from src/swizzles/uvec4_impl_scalar.rs)1289
-rw-r--r--src/swizzles/vec2_impl.rs (renamed from src/swizzles/vec2_impl_scalar.rs)169
-rw-r--r--src/swizzles/vec3_impl.rs (renamed from src/swizzles/vec3_impl_scalar.rs)541
-rw-r--r--src/swizzles/vec3a_impl_sse2.rs479
-rw-r--r--src/swizzles/vec4_impl_sse2.rs1355
-rw-r--r--src/swizzles/vec_traits.rs736
-rw-r--r--src/swizzles/wasm32.rs2
-rw-r--r--src/swizzles/wasm32/vec3a_impl.rs (renamed from src/swizzles/vec3a_impl_wasm32.rs)435
-rw-r--r--src/swizzles/wasm32/vec4_impl.rs (renamed from src/swizzles/vec4_impl_wasm32.rs)1291
-rw-r--r--src/transform.rs432
-rw-r--r--src/u32.rs41
-rw-r--r--src/u32/uvec2.rs876
-rw-r--r--src/u32/uvec3.rs977
-rw-r--r--src/u32/uvec4.rs1063
-rw-r--r--src/vec.rs1029
-rw-r--r--src/vec2.rs317
-rw-r--r--src/vec3.rs454
-rw-r--r--src/vec4.rs434
-rw-r--r--src/vec_mask.rs460
-rw-r--r--src/wasm32.rs47
-rw-r--r--tests/affine2.rs81
-rw-r--r--tests/affine3.rs114
-rw-r--r--tests/euler.rs98
-rw-r--r--tests/mat2.rs52
-rw-r--r--tests/mat3.rs83
-rw-r--r--tests/mat4.rs131
-rw-r--r--tests/quat.rs88
-rw-r--r--tests/support.rs (renamed from tests/support/mod.rs)5
-rw-r--r--tests/support/macros.rs4
-rw-r--r--tests/transform.rs129
-rw-r--r--tests/vec2.rs214
-rw-r--r--tests/vec3.rs242
-rw-r--r--tests/vec4.rs298
175 files changed, 58330 insertions, 21798 deletions
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<f32>` 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<T>`
+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<T>` 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<T>` 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<T>` 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<Self>` and `Product<Self>` 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 <cameron.hart@gmail.com>"]
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"
@@ -53,11 +63,6 @@ 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 <cameron.hart@gmail.com>"]
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}
@@ -96,11 +97,6 @@ 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/mod.rs b/benches/support.rs
index 3fe5dd7..3fe5dd7 100644
--- a/benches/support/mod.rs
+++ b/benches/support.rs
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<I>(iter: I) -> Self
- where
- I: Iterator<Item = &'a Self>,
- {
- iter.fold(Self::IDENTITY, |a, &b| a * b)
- }
- }
- };
-}
-
-type TransformF32 = Mat2;
-type TranslateF32 = Vec2;
-type DerefTargetF32 = Columns3<crate::Vec2>;
-
-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<Affine2> 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<Mat3A> for Affine2 {
- type Output = Mat3A;
-
- #[inline(always)]
- fn mul(self, other: Mat3A) -> Self::Output {
- Mat3A::from(self) * other
- }
-}
-
-impl Mul<Affine2> 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<DVec2>;
-
-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::<super::Vec2>(),
- core::mem::align_of::<super::Affine2>()
- );
- const_assert_eq!(24, core::mem::size_of::<super::Affine2>());
-}
-
-#[cfg(not(any(feature = "scalar-math", target_arch = "spirv")))]
-mod const_test_affine2 {
- const_assert_eq!(16, core::mem::align_of::<super::Affine2>());
- const_assert_eq!(32, core::mem::size_of::<super::Affine2>());
-}
-
-mod const_test_daffine2 {
- const_assert_eq!(
- core::mem::align_of::<super::DVec2>(),
- core::mem::align_of::<super::DAffine2>()
- );
- const_assert_eq!(48, core::mem::size_of::<super::DAffine2>());
-}
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<I>(iter: I) -> Self
- where
- I: Iterator<Item = &'a Self>,
- {
- iter.fold(Self::IDENTITY, |a, &b| a * b)
- }
- }
- };
-}
-
-type DerefTargetF32 = Columns4<crate::Vec3A>;
-
-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<DVec3>;
-
-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::<super::Vec3A>(),
- core::mem::align_of::<super::Affine3A>()
- );
- const_assert_eq!(64, core::mem::size_of::<super::Affine3A>());
-}
-
-mod const_test_daffine3 {
- const_assert_eq!(
- core::mem::align_of::<super::DVec3>(),
- core::mem::align_of::<super::DAffine3>()
- );
- const_assert_eq!(96, core::mem::size_of::<super::DAffine3>());
-}
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<T>(pub T);
+
+impl<T> Align16<T> {
+ #[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::<f32>(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::<super::BVec2>());
+ const_assert_eq!(2, core::mem::size_of::<super::BVec2>());
+}
+
+mod const_test_bvec3 {
+ const_assert_eq!(1, core::mem::align_of::<super::BVec3>());
+ const_assert_eq!(3, core::mem::size_of::<super::BVec3>());
+}
+
+mod const_test_bvec4 {
+ const_assert_eq!(1, core::mem::align_of::<super::BVec4>());
+ const_assert_eq!(4, core::mem::size_of::<super::BVec4>());
+}
+
+#[cfg(not(feature = "scalar-math"))]
+mod const_test_bvec3a {
+ const_assert_eq!(16, core::mem::align_of::<super::BVec3A>());
+ const_assert_eq!(16, core::mem::size_of::<super::BVec3A>());
+}
+
+#[cfg(not(feature = "scalar-math"))]
+mod const_test_bvec4a {
+ const_assert_eq!(16, core::mem::align_of::<super::BVec4A>());
+ const_assert_eq!(16, core::mem::size_of::<super::BVec4A>());
+}
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<BVec2> for [bool; 2] {
+ #[inline]
+ fn from(mask: BVec2) -> Self {
+ mask.into_bool_array()
+ }
+}
+
+impl From<BVec2> 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<BVec3> for [bool; 3] {
+ #[inline]
+ fn from(mask: BVec3) -> Self {
+ mask.into_bool_array()
+ }
+}
+
+impl From<BVec3> 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<BVec4> for [bool; 4] {
+ #[inline]
+ fn from(mask: BVec4) -> Self {
+ mask.into_bool_array()
+ }
+}
+
+impl From<BVec4> 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<H: core::hash::Hasher>(&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<BVec3A> 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<BVec3A> for [bool; 3] {
+ #[inline]
+ fn from(mask: BVec3A) -> Self {
+ mask.into_bool_array()
+ }
+}
+
+impl From<BVec3A> 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<H: core::hash::Hasher>(&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<BVec4A> 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<BVec4A> for [bool; 4] {
+ #[inline]
+ fn from(mask: BVec4A) -> Self {
+ mask.into_bool_array()
+ }
+}
+
+impl From<BVec4A> 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<BVec3A> for [bool; 3] {
+ #[inline]
+ fn from(mask: BVec3A) -> Self {
+ mask.into_bool_array()
+ }
+}
+
+impl From<BVec3A> 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<BVec4A> for [bool; 4] {
+ #[inline]
+ fn from(mask: BVec4A) -> Self {
+ mask.into_bool_array()
+ }
+}
+
+impl From<BVec4A> 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<H: core::hash::Hasher>(&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<BVec3A> 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<BVec3A> for [bool; 3] {
+ #[inline]
+ fn from(mask: BVec3A) -> Self {
+ mask.into_bool_array()
+ }
+}
+
+impl From<BVec3A> 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<H: core::hash::Hasher>(&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<BVec4A> 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<BVec4A> for [bool; 4] {
+ #[inline]
+ fn from(mask: BVec4A) -> Self {
+ mask.into_bool_array()
+ }
+}
+
+impl From<BVec4A> 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<H: core::hash::Hasher>(&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<BVec3A> 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<BVec3A> for [bool; 3] {
+ #[inline]
+ fn from(mask: BVec3A) -> Self {
+ mask.into_bool_array()
+ }
+}
+
+impl From<BVec3A> 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<H: core::hash::Hasher>(&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<BVec4A> 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<BVec4A> for [bool; 4] {
+ #[inline]
+ fn from(mask: BVec4A) -> Self {
+ mask.into_bool_array()
+ }
+}
+
+impl From<BVec4A> 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<u32> {
- const FALSE: Self = Self { x: 0, y: 0 };
-}
-
-impl MaskVectorConst for XYZ<u32> {
- const FALSE: Self = Self { x: 0, y: 0, z: 0 };
-}
-
-impl MaskVectorConst for XYZW<u32> {
- const FALSE: Self = Self {
- x: 0,
- y: 0,
- z: 0,
- w: 0,
- };
-}
-
-impl MaskVector for XY<u32> {
- #[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<u32> {
- #[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<u32> {
- #[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<u32> {
- #[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<u32> {
- #[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<u32> {
- #[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<bool> {
- const FALSE: Self = Self { x: false, y: false };
-}
-
-impl MaskVectorConst for XYZ<bool> {
- const FALSE: Self = Self {
- x: false,
- y: false,
- z: false,
- };
-}
-
-impl MaskVectorConst for XYZW<bool> {
- const FALSE: Self = Self {
- x: false,
- y: false,
- z: false,
- w: false,
- };
-}
-
-impl MaskVector for XY<bool> {
- #[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<bool> {
- #[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<bool> {
- #[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<bool> {
- #[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<bool> {
- #[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<bool> {
- #[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<T: NumEx> MatrixConst for Columns2<XY<T>> {
- 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<T: NanConstEx> NanConstEx for Columns2<XY<T>> {
- const NAN: Self = Self {
- x_axis: XY::NAN,
- y_axis: XY::NAN,
- };
-}
-
-impl<T: NumEx> Matrix<T> for Columns2<XY<T>> {}
-
-impl<T: NumEx> Matrix2x2<T, XY<T>> for Columns2<XY<T>> {
- #[inline(always)]
- fn from_cols(x_axis: XY<T>, y_axis: XY<T>) -> Self {
- Self { x_axis, y_axis }
- }
-
- #[inline(always)]
- fn x_axis(&self) -> &XY<T> {
- &self.x_axis
- }
-
- #[inline(always)]
- fn y_axis(&self) -> &XY<T> {
- &self.y_axis
- }
-}
-
-impl<T: FloatEx> FloatMatrix2x2<T, XY<T>> for Columns2<XY<T>> {}
-
-impl<T: NumEx> MatrixConst for Columns3<XYZ<T>> {
- 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<T: NanConstEx> NanConstEx for Columns3<XYZ<T>> {
- const NAN: Self = Self {
- x_axis: XYZ::NAN,
- y_axis: XYZ::NAN,
- z_axis: XYZ::NAN,
- };
-}
-
-impl<T: NumEx> Matrix<T> for Columns3<XYZ<T>> {}
-
-impl<T: NumEx> Matrix3x3<T, XYZ<T>> for Columns3<XYZ<T>> {
- #[inline(always)]
- fn from_cols(x_axis: XYZ<T>, y_axis: XYZ<T>, z_axis: XYZ<T>) -> Self {
- Self {
- x_axis,
- y_axis,
- z_axis,
- }
- }
-
- #[inline(always)]
- fn x_axis(&self) -> &XYZ<T> {
- &self.x_axis
- }
-
- #[inline(always)]
- fn y_axis(&self) -> &XYZ<T> {
- &self.y_axis
- }
-
- #[inline(always)]
- fn z_axis(&self) -> &XYZ<T> {
- &self.z_axis
- }
-
- #[inline]
- fn mul_vector(&self, other: XYZ<T>) -> XYZ<T> {
- // 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<T: FloatEx> FloatMatrix3x3<T, XYZ<T>> for Columns3<XYZ<T>> {
- #[inline]
- fn transform_point2(&self, other: XY<T>) -> XY<T> {
- // 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<T>) -> XY<T> {
- // 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<XYZF32A16> {
- 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<XYZF32A16> {
- const NAN: Self = Self {
- x_axis: XYZF32A16::NAN,
- y_axis: XYZF32A16::NAN,
- z_axis: XYZF32A16::NAN,
- };
-}
-
-impl Matrix<f32> for Columns3<XYZF32A16> {}
-
-impl Matrix3x3<f32, XYZF32A16> for Columns3<XYZF32A16> {
- #[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<f32, XYZF32A16> for Columns3<XYZF32A16> {
- #[inline]
- fn transform_point2(&self, other: XY<f32>) -> XY<f32> {
- // 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<f32>) -> XY<f32> {
- // 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<T: NumEx> MatrixConst for Columns4<XYZW<T>> {
- 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<T: NanConstEx> NanConstEx for Columns4<XYZW<T>> {
- const NAN: Self = Self {
- x_axis: XYZW::NAN,
- y_axis: XYZW::NAN,
- z_axis: XYZW::NAN,
- w_axis: XYZW::NAN,
- };
-}
-
-impl<T: NumEx> Matrix<T> for Columns4<XYZW<T>> {}
-
-impl<T: NumEx> Matrix4x4<T, XYZW<T>> for Columns4<XYZW<T>> {
- #[rustfmt::skip]
- #[inline(always)]
- fn from_cols(x_axis: XYZW<T>, y_axis: XYZW<T>, z_axis: XYZW<T>, w_axis: XYZW<T>) -> Self {
- Self { x_axis, y_axis, z_axis, w_axis }
- }
-
- #[inline(always)]
- fn x_axis(&self) -> &XYZW<T> {
- &self.x_axis
- }
-
- #[inline(always)]
- fn y_axis(&self) -> &XYZW<T> {
- &self.y_axis
- }
-
- #[inline(always)]
- fn z_axis(&self) -> &XYZW<T> {
- &self.z_axis
- }
-
- #[inline(always)]
- fn w_axis(&self) -> &XYZW<T> {
- &self.w_axis
- }
-}
-
-impl<T: FloatEx> FloatMatrix4x4<T, XYZW<T>> for Columns4<XYZW<T>> {
- type SIMDVector3 = XYZ<T>;
-
- #[inline(always)]
- fn transform_float4_as_point3(&self, other: XYZ<T>) -> XYZ<T> {
- self.transform_point3(other)
- }
-
- #[inline(always)]
- fn transform_float4_as_vector3(&self, other: XYZ<T>) -> XYZ<T> {
- self.transform_vector3(other)
- }
-
- #[inline(always)]
- fn project_float4_as_point3(&self, other: XYZ<T>) -> XYZ<T> {
- self.project_point3(other)
- }
-}
-
-impl<T: FloatEx> ProjectionMatrix<T, XYZW<T>> for Columns4<XYZW<T>> {}
-
-impl From<Columns3<XYZ<f32>>> for Columns3<XYZF32A16> {
- fn from(v: Columns3<XYZ<f32>>) -> Columns3<XYZF32A16> {
- Self {
- x_axis: v.x_axis.into(),
- y_axis: v.y_axis.into(),
- z_axis: v.z_axis.into(),
- }
- }
-}
-
-impl From<Columns3<XYZF32A16>> for Columns3<XYZ<f32>> {
- fn from(v: Columns3<XYZF32A16>) -> Columns3<XYZ<f32>> {
- 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<T: FloatEx> Quaternion<T> for XYZW<T> {
- // fallback
- type SIMDVector3 = XYZ<T>;
-
- #[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<T>) -> XYZ<T> {
- 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<T>) -> XYZ<T> {
- 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<T: NumEx> VectorConst for XY<T> {
- const ZERO: Self = Self {
- x: <T as NumConstEx>::ZERO,
- y: <T as NumConstEx>::ZERO,
- };
- const ONE: Self = Self {
- x: <T as NumConstEx>::ONE,
- y: <T as NumConstEx>::ONE,
- };
-}
-
-impl<T: NanConstEx> NanConstEx for XY<T> {
- const NAN: Self = Self {
- x: <T as NanConstEx>::NAN,
- y: <T as NanConstEx>::NAN,
- };
-}
-
-impl<T: NumEx> Vector2Const for XY<T> {
- const X: Self = Self {
- x: <T as NumConstEx>::ONE,
- y: <T as NumConstEx>::ZERO,
- };
- const Y: Self = Self {
- x: <T as NumConstEx>::ZERO,
- y: <T as NumConstEx>::ONE,
- };
-}
-
-impl<T: NumEx> VectorConst for XYZ<T> {
- const ZERO: Self = Self {
- x: <T as NumConstEx>::ZERO,
- y: <T as NumConstEx>::ZERO,
- z: <T as NumConstEx>::ZERO,
- };
- const ONE: Self = Self {
- x: <T as NumConstEx>::ONE,
- y: <T as NumConstEx>::ONE,
- z: <T as NumConstEx>::ONE,
- };
-}
-
-impl<T: NanConstEx> NanConstEx for XYZ<T> {
- const NAN: Self = Self {
- x: <T as NanConstEx>::NAN,
- y: <T as NanConstEx>::NAN,
- z: <T as NanConstEx>::NAN,
- };
-}
-
-impl<T: NumEx> Vector3Const for XYZ<T> {
- const X: Self = Self {
- x: <T as NumConstEx>::ONE,
- y: <T as NumConstEx>::ZERO,
- z: <T as NumConstEx>::ZERO,
- };
- const Y: Self = Self {
- x: <T as NumConstEx>::ZERO,
- y: <T as NumConstEx>::ONE,
- z: <T as NumConstEx>::ZERO,
- };
- const Z: Self = Self {
- x: <T as NumConstEx>::ZERO,
- y: <T as NumConstEx>::ZERO,
- z: <T as NumConstEx>::ONE,
- };
-}
-
-impl<T: NumEx> VectorConst for XYZW<T> {
- const ZERO: Self = Self {
- x: <T as NumConstEx>::ZERO,
- y: <T as NumConstEx>::ZERO,
- z: <T as NumConstEx>::ZERO,
- w: <T as NumConstEx>::ZERO,
- };
- const ONE: Self = Self {
- x: <T as NumConstEx>::ONE,
- y: <T as NumConstEx>::ONE,
- z: <T as NumConstEx>::ONE,
- w: <T as NumConstEx>::ONE,
- };
-}
-
-impl<T: NanConstEx> NanConstEx for XYZW<T> {
- const NAN: Self = Self {
- x: <T as NanConstEx>::NAN,
- y: <T as NanConstEx>::NAN,
- z: <T as NanConstEx>::NAN,
- w: <T as NanConstEx>::NAN,
- };
-}
-
-impl<T: NumEx> Vector4Const for XYZW<T> {
- const X: Self = Self {
- x: <T as NumConstEx>::ONE,
- y: <T as NumConstEx>::ZERO,
- z: <T as NumConstEx>::ZERO,
- w: <T as NumConstEx>::ZERO,
- };
- const Y: Self = Self {
- x: <T as NumConstEx>::ZERO,
- y: <T as NumConstEx>::ONE,
- z: <T as NumConstEx>::ZERO,
- w: <T as NumConstEx>::ZERO,
- };
- const Z: Self = Self {
- x: <T as NumConstEx>::ZERO,
- y: <T as NumConstEx>::ZERO,
- z: <T as NumConstEx>::ONE,
- w: <T as NumConstEx>::ZERO,
- };
- const W: Self = Self {
- x: <T as NumConstEx>::ZERO,
- y: <T as NumConstEx>::ZERO,
- z: <T as NumConstEx>::ZERO,
- w: <T as NumConstEx>::ONE,
- };
-}
-
-impl<T: NumEx> Vector<T> for XY<T> {
- type Mask = XY<bool>;
-
- #[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<T: NumEx> Vector<T> for XYZ<T> {
- type Mask = XYZ<bool>;
-
- #[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<T: NumEx> Vector<T> for XYZW<T> {
- type Mask = XYZW<bool>;
-
- #[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<T: NumEx> Vector2<T> for XY<T> {
- #[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<T> {
- self
- }
-
- #[inline(always)]
- fn as_mut_xy(&mut self) -> &mut XY<T> {
- 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<T: NumEx> Vector3<T> for XYZ<T> {
- #[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<T> {
- self
- }
-
- #[inline(always)]
- fn as_mut_xyz(&mut self) -> &mut XYZ<T> {
- 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<T: NumEx> Vector4<T> for XYZW<T> {
- #[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<T> {
- self
- }
-
- #[inline(always)]
- fn as_mut_xyzw(&mut self) -> &mut XYZW<T> {
- 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<T: SignedEx> SignedVector<T> for XY<T> {
- #[inline]
- fn neg(self) -> Self {
- Self {
- x: self.x.neg(),
- y: self.y.neg(),
- }
- }
-}
-
-impl<T: SignedEx> SignedVector2<T> for XY<T> {}
-
-impl<T: SignedEx> SignedVector<T> for XYZ<T> {
- #[inline]
- fn neg(self) -> Self {
- Self {
- x: self.x.neg(),
- y: self.y.neg(),
- z: self.z.neg(),
- }
- }
-}
-
-impl<T: SignedEx> SignedVector<T> for XYZW<T> {
- #[inline]
- fn neg(self) -> Self {
- Self {
- x: self.x.neg(),
- y: self.y.neg(),
- z: self.z.neg(),
- w: self.w.neg(),
- }
- }
-}
-
-impl<T: SignedEx> SignedVector3<T> for XYZ<T> {}
-impl<T: SignedEx> SignedVector4<T> for XYZW<T> {}
-
-impl<T: FloatEx> FloatVector2<T> for XY<T> {}
-impl<T: FloatEx> FloatVector3<T> for XYZ<T> {}
-impl<T: FloatEx> FloatVector4<T> for XYZW<T> {}
-
-impl<T> From<XYZ<T>> for XY<T> {
- #[inline(always)]
- fn from(v: XYZ<T>) -> Self {
- Self { x: v.x, y: v.y }
- }
-}
-
-impl<T> From<XYZW<T>> for XY<T> {
- #[inline(always)]
- fn from(v: XYZW<T>) -> Self {
- Self { x: v.x, y: v.y }
- }
-}
-
-impl<T> From<XYZW<T>> for XYZ<T> {
- #[inline(always)]
- fn from(v: XYZW<T>) -> 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<f32> for XYZF32A16 {
- type Mask = XYZ<bool>;
-
- #[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<f32> 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<f32> {
- unsafe { &*(self as *const Self).cast() }
- }
-
- #[inline(always)]
- fn as_mut_xyz(&mut self) -> &mut XYZ<f32> {
- 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<f32> for XYZF32A16 {
- #[inline(always)]
- fn neg(self) -> Self {
- XYZ::neg(self.into()).into()
- }
-}
-
-impl SignedVector3<f32> for XYZF32A16 {}
-impl FloatVector3<f32> for XYZF32A16 {}
-
-// 2D bitwise and shifting
-
-impl<T, Rhs> ScalarShiftOps<Rhs> for XY<T>
-where
- T: IntegerShiftOps<Rhs>,
- 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<T> ScalarBitOps<T> for XY<T>
-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<T, Rhs> VectorShiftOps<XY<Rhs>> for XY<T>
-where
- T: Copy + IntegerShiftOps<Rhs>,
-{
- #[inline(always)]
- fn vector_shl(self, rhs: XY<Rhs>) -> Self {
- Self {
- x: self.x << rhs.x,
- y: self.y << rhs.y,
- }
- }
-
- #[inline(always)]
- fn vector_shr(self, rhs: XY<Rhs>) -> Self {
- Self {
- x: self.x >> rhs.x,
- y: self.y >> rhs.y,
- }
- }
-}
-
-impl<T> VectorBitOps<XY<T>> for XY<T>
-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<T, Rhs> ScalarShiftOps<Rhs> for XYZ<T>
-where
- T: IntegerShiftOps<Rhs>,
- 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<T> ScalarBitOps<T> for XYZ<T>
-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<T, Rhs> VectorShiftOps<XYZ<Rhs>> for XYZ<T>
-where
- T: Copy + IntegerShiftOps<Rhs>,
-{
- #[inline(always)]
- fn vector_shl(self, rhs: XYZ<Rhs>) -> 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<Rhs>) -> Self {
- Self {
- x: self.x >> rhs.x,
- y: self.y >> rhs.y,
- z: self.z >> rhs.z,
- }
- }
-}
-
-impl<T> VectorBitOps<XYZ<T>> for XYZ<T>
-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<T, Rhs> ScalarShiftOps<Rhs> for XYZW<T>
-where
- T: IntegerShiftOps<Rhs>,
- 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<T> ScalarBitOps<T> for XYZW<T>
-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<T, Rhs> VectorShiftOps<XYZW<Rhs>> for XYZW<T>
-where
- T: Copy + IntegerShiftOps<Rhs>,
-{
- #[inline(always)]
- fn vector_shl(self, rhs: XYZW<Rhs>) -> 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<Rhs>) -> Self {
- Self {
- x: self.x >> rhs.x,
- y: self.y >> rhs.y,
- z: self.z >> rhs.z,
- w: self.w >> rhs.w,
- }
- }
-}
-
-impl<T> VectorBitOps<XYZW<T>> for XYZW<T>
-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/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<f32> for __m128 {}
-
-impl Matrix2x2<f32, XY<f32>> 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<f32>, y_axis: XY<f32>) -> Self {
- Matrix2x2::new(x_axis.x, x_axis.y, y_axis.x, y_axis.y)
- }
-
- #[inline(always)]
- fn x_axis(&self) -> &XY<f32> {
- unsafe { &(*(self as *const Self).cast::<Columns2<XY<f32>>>()).x_axis }
- }
-
- #[inline(always)]
- fn y_axis(&self) -> &XY<f32> {
- unsafe { &(*(self as *const Self).cast::<Columns2<XY<f32>>>()).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<f32>) -> XY<f32> {
- 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<Align16<XY<f32>>> = 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<f32, XY<f32>> 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<f32> for Columns3<__m128> {}
-
-impl Matrix3x3<f32, __m128> 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<f32, __m128> for Columns3<__m128> {
- #[inline]
- fn transform_point2(&self, other: XY<f32>) -> XY<f32> {
- 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<f32>) -> XY<f32> {
- 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<f32> for Columns4<__m128> {}
-
-impl Matrix4x4<f32, __m128> 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<f32, __m128> 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<f32>) -> XYZ<f32> {
- 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<f32>) -> XYZ<f32> {
- 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<f32, __m128> for Columns4<__m128> {}
-
-impl From<Columns3<XYZ<f32>>> for Columns3<__m128> {
- #[inline(always)]
- fn from(v: Columns3<XYZ<f32>>) -> Columns3<__m128> {
- Self {
- x_axis: v.x_axis.into(),
- y_axis: v.y_axis.into(),
- z_axis: v.z_axis.into(),
- }
- }
-}
-
-impl From<Columns3<__m128>> for Columns3<XYZ<f32>> {
- #[inline(always)]
- fn from(v: Columns3<__m128>) -> Columns3<XYZ<f32>> {
- 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<f32> 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<f32>) -> XYZ<f32> {
- 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<f32> 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<f32> 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<f32> {
- unsafe { &*(self as *const Self).cast() }
- }
-
- #[inline(always)]
- fn as_mut_xyz(&mut self) -> &mut XYZ<f32> {
- unsafe { &mut *(self as *mut Self).cast() }
- }
-
- #[inline(always)]
- fn into_xy(self) -> XY<f32> {
- let mut out: MaybeUninit<Align16<XY<f32>>> = MaybeUninit::uninit();
- unsafe {
- _mm_store_ps(out.as_mut_ptr().cast(), self);
- out.assume_init().0
- }
- }
-
- #[inline]
- fn into_xyzw(self, w: f32) -> XYZW<f32> {
- 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<Align16<[f32; 3]>> = 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<Align16<(f32, f32, f32)>> = 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<f32> 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<f32> {
- unsafe { &*(self as *const Self).cast() }
- }
-
- #[inline(always)]
- fn as_mut_xyzw(&mut self) -> &mut XYZW<f32> {
- unsafe { &mut *(self as *mut Self).cast() }
- }
-
- #[inline(always)]
- fn into_xy(self) -> XY<f32> {
- let mut out: MaybeUninit<Align16<XY<f32>>> = MaybeUninit::uninit();
- unsafe {
- _mm_store_ps(out.as_mut_ptr().cast(), self);
- out.assume_init().0
- }
- }
-
- #[inline(always)]
- fn into_xyz(self) -> XYZ<f32> {
- let mut out: MaybeUninit<Align16<XYZ<f32>>> = 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<Align16<[f32; 4]>> = 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<Align16<(f32, f32, f32, f32)>> = 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<f32> for __m128 {
- #[inline(always)]
- fn neg(self) -> Self {
- unsafe { _mm_sub_ps(Self::ZERO, self) }
- }
-}
-
-impl SignedVector3<f32> 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<f32> 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<f32> 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<f32> 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<XYZW<f32>> for __m128 {
- #[inline(always)]
- fn from(v: XYZW<f32>) -> __m128 {
- unsafe { _mm_set_ps(v.w, v.z, v.y, v.x) }
- }
-}
-
-impl From<XYZ<f32>> for __m128 {
- #[inline(always)]
- fn from(v: XYZ<f32>) -> __m128 {
- unsafe { _mm_set_ps(v.z, v.z, v.y, v.x) }
- }
-}
-
-impl From<XY<f32>> for __m128 {
- #[inline(always)]
- fn from(v: XY<f32>) -> __m128 {
- unsafe { _mm_set_ps(v.y, v.y, v.y, v.x) }
- }
-}
-
-impl From<__m128> for XYZW<f32> {
- #[inline(always)]
- fn from(v: __m128) -> XYZW<f32> {
- let mut out: MaybeUninit<Align16<XYZW<f32>>> = MaybeUninit::uninit();
- unsafe {
- _mm_store_ps(out.as_mut_ptr().cast(), v);
- out.assume_init().0
- }
- }
-}
-
-impl From<__m128> for XYZ<f32> {
- #[inline(always)]
- fn from(v: __m128) -> XYZ<f32> {
- let mut out: MaybeUninit<Align16<XYZ<f32>>> = MaybeUninit::uninit();
- unsafe {
- _mm_store_ps(out.as_mut_ptr().cast(), v);
- out.assume_init().0
- }
- }
-}
-
-impl From<__m128> for XY<f32> {
- #[inline(always)]
- fn from(v: __m128) -> XY<f32> {
- let mut out: MaybeUninit<Align16<XY<f32>>> = 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<T> {
- 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<T> {
- 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<T> {
- 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<V> {
- 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<V> {
- 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<V> {
- 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<f32>` 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<XYZW<f32>> for XYZF32A16 {
- #[inline(always)]
- fn from(v: XYZW<f32>) -> Self {
- Self {
- x: v.x,
- y: v.y,
- z: v.z,
- }
- }
-}
-
-impl From<XYZ<f32>> for XYZF32A16 {
- #[inline(always)]
- fn from(v: XYZ<f32>) -> Self {
- Self {
- x: v.x,
- y: v.y,
- z: v.z,
- }
- }
-}
-
-impl From<XYZF32A16> for XYZ<f32> {
- #[inline(always)]
- fn from(v: XYZF32A16) -> Self {
- Self {
- x: v.x,
- y: v.y,
- z: v.z,
- }
- }
-}
-
-impl From<XYZF32A16> for XY<f32> {
- #[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<T>(pub T);
-
-impl<T> Align16<T> {
- #[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::<f32>(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<T: NumEx>: Sized + Copy + Clone {}
-
-/// 2x2 Matrix trait for all types of T
-pub trait Matrix2x2<T: NumEx, V2: Vector2<T>>: Matrix<T> {
- #[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<T>) -> 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<T: FloatEx, V2: FloatVector2<T>>: Matrix2x2<T, V2> {
- #[inline]
- fn abs_diff_eq(&self, other: &Self, max_abs_diff: T) -> bool
- where
- <V2 as Vector<T>>::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<T: NumEx, V3: Vector3<T>>: Matrix<T> {
- 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<T>) -> 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<T>) -> Self {
- // Do not panic as long as any component is non-zero
- glam_assert!(scale.cmpne(XY::<T>::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<T>) -> 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<T: FloatEx, V3: FloatVector3<T>>: Matrix3x3<T, V3> {
- #[inline]
- fn abs_diff_eq(&self, other: &Self, max_abs_diff: T) -> bool
- where
- <V3 as Vector<T>>::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<T>, angle: T, translation: XY<T>) -> 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<T>, 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<T>) -> Self {
- glam_assert!(rotation.is_normalized());
- let x2 = rotation.x + rotation.x;
- let y2 = rotation.y + rotation.y;
- let z2 = rotation.z + rotation.z;
- let xx = rotation.x * x2;
- let xy = rotation.x * y2;
- let xz = rotation.x * z2;
- let yy = rotation.y * y2;
- let yz = rotation.y * z2;
- let zz = rotation.z * z2;
- let wx = rotation.w * x2;
- let wy = rotation.w * y2;
- let wz = rotation.w * z2;
-
- Self::from_cols(
- 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<T>) -> XY<T>;
- fn transform_vector2(&self, other: XY<T>) -> XY<T>;
-
- #[inline]
- fn inverse(&self) -> Self
- where
- <V3 as Vector<T>>::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<T: NumEx, V4: Vector4<T>>: Matrix<T> {
- 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<T>) -> 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<T>) -> Self {
- // Do not panic as long as any component is non-zero
- glam_assert!(scale.cmpne(XYZ::<T>::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<T>) -> 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<T: FloatEx, V4: FloatVector4<T> + Quaternion<T>>:
- Matrix4x4<T, V4>
-{
- // Vector3 represented by a SIMD type if available
- type SIMDVector3;
-
- #[inline]
- fn abs_diff_eq(&self, other: &Self, max_abs_diff: T) -> bool
- where
- <V4 as Vector<T>>::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<T>, V4, XYZ<T>) {
- let det = self.determinant();
- glam_assert!(det != T::ZERO);
-
- let scale: XYZ<T> = Vector3::new(
- self.x_axis().length() * det.signum(),
- self.y_axis().length(),
- self.z_axis().length(),
- );
-
- glam_assert!(scale.cmpne(XYZ::<T>::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<T>, rotation: V4, translation: XYZ<T>) -> 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<T>) -> 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<T>, 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<T>, dir: XYZ<T>, up: XYZ<T>) -> 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<T>, center: XYZ<T>, up: XYZ<T>) -> Self {
- glam_assert!(up.is_normalized());
- Self::look_to_lh(eye, center.sub(eye), up)
- }
-
- #[inline]
- fn look_at_rh(eye: XYZ<T>, center: XYZ<T>, up: XYZ<T>) -> Self {
- glam_assert!(up.is_normalized());
- Self::look_to_lh(eye, eye.sub(center), up)
- }
-
- #[inline]
- fn transform_point3(&self, other: XYZ<T>) -> XYZ<T> {
- 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<T>) -> XYZ<T> {
- 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<T>) -> XYZ<T> {
- 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<T: FloatEx, V4: FloatVector4<T> + Quaternion<T>>:
- FloatMatrix4x4<T, V4>
-{
- /// Creates a right-handed perspective projection matrix with [-1,1] depth range.
- /// This is the same as the OpenGL [`gluPerspective`] function.
- /// [`gluPerspective`]: <https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluPerspective.xml>
- 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`]: <https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glOrtho.xml>
- 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<T: FloatEx>: FloatVector4<T> {
- type SIMDVector3;
-
- #[inline]
- fn from_axis_angle(axis: XYZ<T>, 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<T>, y_axis: XYZ<T>, z_axis: XYZ<T>) -> 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>, 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<T>) -> XYZ<T>;
- 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<Output = Self> {
- fn abs(self) -> Self;
- fn signum(self) -> Self;
-}
-
-#[cfg(not(feature = "libm"))]
-pub trait Float: Num + Copy + core::ops::Neg<Output = Self> {
- 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<Output = Self>
- + Div<Output = Self>
- + Mul<Output = Self>
- + Sub<Output = Self>
- + Rem<Output = Self>
-{
- 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<Rhs>: Sized + Shl<Rhs, Output = Self> + Shr<Rhs, Output = Self> {}
-
-pub trait IntegerBitOps:
- Sized + Not<Output = Self> + BitAnd<Output = Self> + BitOr<Output = Self> + BitXor<Output = Self>
-{
-}
-
-impl IntegerShiftOps<i8> for i32 {}
-impl IntegerShiftOps<i16> for i32 {}
-impl IntegerShiftOps<i32> for i32 {}
-impl IntegerShiftOps<u8> for i32 {}
-impl IntegerShiftOps<u16> for i32 {}
-impl IntegerShiftOps<u32> for i32 {}
-
-impl IntegerShiftOps<i8> for u32 {}
-impl IntegerShiftOps<i16> for u32 {}
-impl IntegerShiftOps<i32> for u32 {}
-impl IntegerShiftOps<u8> for u32 {}
-impl IntegerShiftOps<u16> for u32 {}
-impl IntegerShiftOps<u32> 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<T>: 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<T>: Vector<T> + Vector2Const
-where
- T: Copy + Mul<Output = T> + Sub<Output = T> + Add<Output = T>,
-{
- fn new(x: T, y: T) -> Self;
- fn x(self) -> T;
- fn y(self) -> T;
-
- fn as_ref_xy(&self) -> &XY<T>;
- fn as_mut_xy(&mut self) -> &mut XY<T>;
-
- // 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<T> {
- XYZ {
- x: self.x(),
- y: self.y(),
- z,
- }
- }
-
- #[inline(always)]
- fn into_xyzw(self, z: T, w: T) -> XYZW<T> {
- 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<T>: Vector<T> + Vector3Const
-where
- T: Copy + Mul<Output = T> + Sub<Output = T> + Add<Output = T>,
-{
- 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<T>;
- fn as_mut_xyz(&mut self) -> &mut XYZ<T>;
-
- 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<T>, z: T) -> Self {
- Self::new(v2.x, v2.y, z)
- }
-
- #[inline(always)]
- fn from_xyzw(v4: XYZW<T>) -> Self {
- Self::new(v4.x, v4.y, v4.z)
- }
-
- #[inline(always)]
- fn into_xy(self) -> XY<T> {
- XY {
- x: self.x(),
- y: self.y(),
- }
- }
-
- #[inline(always)]
- fn into_xyzw(self, w: T) -> XYZW<T> {
- 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<T>: Vector<T> + Vector4Const
-where
- T: Copy + Mul<Output = T> + Sub<Output = T> + Add<Output = T>,
-{
- 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<T>;
- fn as_mut_xyzw(&mut self) -> &mut XYZW<T>;
-
- 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<T>, z: T, w: T) -> Self {
- Self::new(v2.x, v2.y, z, w)
- }
-
- #[inline(always)]
- fn from_xyz(v3: XYZ<T>, w: T) -> Self {
- Self::new(v3.x, v3.y, v3.z, w)
- }
-
- #[inline(always)]
- fn into_xy(self) -> XY<T> {
- XY {
- x: self.x(),
- y: self.y(),
- }
- }
-
- #[inline(always)]
- fn into_xyz(self) -> XYZ<T> {
- 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<T: SignedEx>: Vector<T> {
- fn neg(self) -> Self;
-}
-
-/// Vector methods specific to 2D vectors of signed types.
-pub trait SignedVector2<T: SignedEx>: SignedVector<T> + Vector2<T> {
- #[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<T: SignedEx>: SignedVector<T> + Vector3<T> {
- #[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<T: SignedEx>: SignedVector<T> + Vector4<T> {
- #[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<T: FloatEx>: SignedVector2<T> {
- #[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
- <Self as Vector<T>>::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
- <Self as Vector<T>>::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<T: FloatEx>: SignedVector3<T> {
- #[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
- <Self as Vector<T>>::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
- <Self as Vector<T>>::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<T: FloatEx>: SignedVector4<T> {
- #[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
- <Self as Vector<T>>::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
- <Self as Vector<T>>::Mask: MaskVector4,
- {
- self.sub(other).abs().cmple(Self::splat(max_abs_diff)).all()
- }
-}
-
-pub trait ScalarShiftOps<Rhs> {
- fn scalar_shl(self, rhs: Rhs) -> Self;
- fn scalar_shr(self, rhs: Rhs) -> Self;
-}
-
-pub trait VectorShiftOps<Rhs> {
- fn vector_shl(self, rhs: Rhs) -> Self;
- fn vector_shr(self, rhs: Rhs) -> Self;
-}
-
-pub trait ScalarBitOps<Rhs> {
- fn scalar_bitand(self, rhs: Rhs) -> Self;
- fn scalar_bitor(self, rhs: Rhs) -> Self;
- fn scalar_bitxor(self, rhs: Rhs) -> Self;
-}
-
-pub trait VectorBitOps<Rhs> {
- 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<f32> for v128 {}
-
-impl Matrix2x2<f32, XY<f32>> 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<f32>, y_axis: XY<f32>) -> Self {
- Matrix2x2::new(x_axis.x, x_axis.y, y_axis.x, y_axis.y)
- }
-
- #[inline(always)]
- fn x_axis(&self) -> &XY<f32> {
- unsafe { &(*(self as *const Self as *const Columns2<XY<f32>>)).x_axis }
- }
-
- #[inline(always)]
- fn y_axis(&self) -> &XY<f32> {
- unsafe { &(*(self as *const Self as *const Columns2<XY<f32>>)).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<f32>) -> XY<f32> {
- 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<v128> = MaybeUninit::uninit();
- unsafe {
- v128_store(out.as_mut_ptr(), result);
- *(&out.assume_init() as *const v128 as *const XY<f32>)
- }
- }
-
- #[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<f32, XY<f32>> 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<v128> {
- const ZERO: Columns3<v128> = Columns3 {
- x_axis: VectorConst::ZERO,
- y_axis: VectorConst::ZERO,
- z_axis: VectorConst::ZERO,
- };
- const IDENTITY: Columns3<v128> = Columns3 {
- x_axis: v128::X,
- y_axis: v128::Y,
- z_axis: v128::Z,
- };
-}
-
-impl NanConstEx for Columns3<v128> {
- const NAN: Columns3<v128> = Columns3 {
- x_axis: v128::NAN,
- y_axis: v128::NAN,
- z_axis: v128::NAN,
- };
-}
-
-impl Matrix<f32> for Columns3<v128> {}
-
-impl Matrix3x3<f32, v128> for Columns3<v128> {
- #[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<f32, v128> for Columns3<v128> {
- #[inline]
- fn transform_point2(&self, other: XY<f32>) -> XY<f32> {
- 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<f32>) -> XY<f32> {
- 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<v128> {
- const ZERO: Columns4<v128> = Columns4 {
- x_axis: VectorConst::ZERO,
- y_axis: VectorConst::ZERO,
- z_axis: VectorConst::ZERO,
- w_axis: VectorConst::ZERO,
- };
- const IDENTITY: Columns4<v128> = Columns4 {
- x_axis: v128::X,
- y_axis: v128::Y,
- z_axis: v128::Z,
- w_axis: v128::W,
- };
-}
-
-impl NanConstEx for Columns4<v128> {
- const NAN: Columns4<v128> = Columns4 {
- x_axis: v128::NAN,
- y_axis: v128::NAN,
- z_axis: v128::NAN,
- w_axis: v128::NAN,
- };
-}
-
-impl Matrix<f32> for Columns4<v128> {}
-
-impl Matrix4x4<f32, v128> for Columns4<v128> {
- #[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<f32, v128> for Columns4<v128> {
- 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<f32>) -> XYZ<f32> {
- 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<f32>) -> XYZ<f32> {
- 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<f32, v128> for Columns4<v128> {}
-
-impl From<Columns3<XYZ<f32>>> for Columns3<v128> {
- #[inline(always)]
- fn from(v: Columns3<XYZ<f32>>) -> Columns3<v128> {
- Self {
- x_axis: v.x_axis.into(),
- y_axis: v.y_axis.into(),
- z_axis: v.z_axis.into(),
- }
- }
-}
-
-impl From<Columns3<v128>> for Columns3<XYZ<f32>> {
- #[inline(always)]
- fn from(v: Columns3<v128>) -> Columns3<XYZ<f32>> {
- 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<f32> 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<f32>) -> XYZ<f32> {
- 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<f32> 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<f32> 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<f32> {
- unsafe { &*(self as *const Self as *const XYZ<f32>) }
- }
-
- #[inline(always)]
- fn as_mut_xyz(&mut self) -> &mut XYZ<f32> {
- unsafe { &mut *(self as *mut Self as *mut XYZ<f32>) }
- }
-
- #[inline(always)]
- fn into_xy(self) -> XY<f32> {
- XY {
- x: f32x4_extract_lane::<0>(self),
- y: f32x4_extract_lane::<1>(self),
- }
- }
-
- #[inline]
- fn into_xyzw(self, w: f32) -> XYZW<f32> {
- let v = f32x4_replace_lane::<3>(self, w);
- unsafe { *(&v as *const v128 as *const XYZW<f32>) }
- }
-
- #[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<v128> = 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<v128> = 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<f32> 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<f32> {
- unsafe { &*(self as *const Self as *const XYZW<f32>) }
- }
-
- #[inline(always)]
- fn as_mut_xyzw(&mut self) -> &mut XYZW<f32> {
- unsafe { &mut *(self as *mut Self as *mut XYZW<f32>) }
- }
-
- #[inline(always)]
- fn into_xy(self) -> XY<f32> {
- XY {
- x: f32x4_extract_lane::<0>(self),
- y: f32x4_extract_lane::<1>(self),
- }
- }
-
- #[inline(always)]
- fn into_xyz(self) -> XYZ<f32> {
- 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<v128> = 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<v128> = 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<f32> for v128 {
- #[inline(always)]
- fn neg(self) -> Self {
- f32x4_neg(self)
- }
-}
-
-impl SignedVector3<f32> 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<f32> 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<f32> 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<f32> 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<XYZW<f32>> for v128 {
- #[inline(always)]
- fn from(v: XYZW<f32>) -> v128 {
- f32x4(v.x, v.y, v.z, v.w)
- }
-}
-
-impl From<XYZ<f32>> for v128 {
- #[inline(always)]
- fn from(v: XYZ<f32>) -> v128 {
- f32x4(v.x, v.y, v.z, v.z)
- }
-}
-
-impl From<XY<f32>> for v128 {
- #[inline(always)]
- fn from(v: XY<f32>) -> v128 {
- f32x4(v.x, v.y, v.y, v.y)
- }
-}
-
-impl From<v128> for XYZW<f32> {
- #[inline(always)]
- fn from(v: v128) -> XYZW<f32> {
- let mut out: MaybeUninit<v128> = MaybeUninit::uninit();
- unsafe {
- v128_store(out.as_mut_ptr(), v);
- *(&out.assume_init() as *const v128 as *const XYZW<f32>)
- }
- }
-}
-
-impl From<v128> for XYZ<f32> {
- #[inline(always)]
- fn from(v: v128) -> XYZ<f32> {
- let mut out: MaybeUninit<v128> = MaybeUninit::uninit();
- unsafe {
- v128_store(out.as_mut_ptr(), v);
- *(&out.assume_init() as *const v128 as *const XYZ<f32>)
- }
- }
-}
-
-impl From<v128> for XY<f32> {
- #[inline(always)]
- fn from(v: v128) -> XY<f32> {
- let mut out: MaybeUninit<v128> = MaybeUninit::uninit();
- unsafe {
- v128_store(out.as_mut_ptr(), v);
- *(&out.assume_init() as *const v128 as *const XY<f32>)
- }
- }
-}
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<T> {
+ 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<T> {
+ 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<T> {
+ 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<V> {
+ 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<V> {
+ 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<V> {
+ 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<Q: Copy>: Sized + Copy {
- type Output: FloatEx;
+pub(crate) trait EulerFromQuaternion<Q: Copy>: 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<Q: Copy>: Sized + Copy {
}
/// Conversion from euler angles to quaternion.
-pub trait EulerToQuaternion<T>: Copy {
+pub(crate) trait EulerToQuaternion<T>: 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<T>: Copy {
/// Adds a atan2 that handles the negative zero case.
/// Basically forces positive zero in the x-argument for atan2.
-pub trait Atan2Fixed<T = Self> {
+pub(crate) trait Atan2Fixed<T = Self> {
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<T: FloatEx>(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::<super::Vec2>(),
+ core::mem::align_of::<super::Affine2>()
+ );
+ const_assert_eq!(24, core::mem::size_of::<super::Affine2>());
+ }
+
+ #[cfg(not(feature = "scalar-math"))]
+ mod const_test_affine2 {
+ const_assert_eq!(16, core::mem::align_of::<super::Affine2>());
+ const_assert_eq!(32, core::mem::size_of::<super::Affine2>());
+ }
+
+ mod const_test_mat2 {
+ #[cfg(feature = "scalar-math")]
+ const_assert_eq!(
+ core::mem::align_of::<super::Vec2>(),
+ core::mem::align_of::<super::Mat2>()
+ );
+ #[cfg(not(any(feature = "scalar-math", target_arch = "spirv")))]
+ const_assert_eq!(16, core::mem::align_of::<super::Mat2>());
+ const_assert_eq!(16, core::mem::size_of::<super::Mat2>());
+ }
+
+ mod const_test_mat3 {
+ const_assert_eq!(
+ core::mem::align_of::<f32>(),
+ core::mem::align_of::<super::Mat3>()
+ );
+ const_assert_eq!(36, core::mem::size_of::<super::Mat3>());
+ }
+
+ mod const_test_mat3a {
+ const_assert_eq!(16, core::mem::align_of::<super::Mat3A>());
+ const_assert_eq!(48, core::mem::size_of::<super::Mat3A>());
+ }
+
+ mod const_test_mat4 {
+ const_assert_eq!(
+ core::mem::align_of::<super::Vec4>(),
+ core::mem::align_of::<super::Mat4>()
+ );
+ const_assert_eq!(64, core::mem::size_of::<super::Mat4>());
+ }
+
+ mod const_test_quat {
+ #[cfg(feature = "scalar-math")]
+ const_assert_eq!(
+ core::mem::align_of::<f32>(),
+ core::mem::align_of::<super::Quat>()
+ );
+ #[cfg(not(any(feature = "scalar-math", target_arch = "spirv")))]
+ const_assert_eq!(16, core::mem::align_of::<super::Quat>());
+ const_assert_eq!(16, core::mem::size_of::<super::Quat>());
+ }
+
+ mod const_test_vec2 {
+ #[cfg(not(feature = "cuda"))]
+ const_assert_eq!(
+ core::mem::align_of::<f32>(),
+ core::mem::align_of::<super::Vec2>()
+ );
+ #[cfg(feature = "cuda")]
+ const_assert_eq!(8, core::mem::align_of::<super::Vec2>());
+ const_assert_eq!(8, core::mem::size_of::<super::Vec2>());
+ }
+
+ mod const_test_vec3 {
+ const_assert_eq!(
+ core::mem::align_of::<f32>(),
+ core::mem::align_of::<super::Vec3>()
+ );
+ const_assert_eq!(12, core::mem::size_of::<super::Vec3>());
+ }
+
+ mod const_test_vec3a {
+ const_assert_eq!(16, core::mem::align_of::<super::Vec3A>());
+ const_assert_eq!(16, core::mem::size_of::<super::Vec3A>());
+ }
+
+ mod const_test_vec4 {
+ #[cfg(all(feature = "scalar-math", not(feature = "cuda")))]
+ const_assert_eq!(
+ core::mem::align_of::<f32>(),
+ core::mem::align_of::<super::Vec4>()
+ );
+ #[cfg(not(feature = "scalar-math"))]
+ const_assert_eq!(16, core::mem::align_of::<super::Vec4>());
+ const_assert_eq!(16, core::mem::size_of::<super::Vec4>());
+ }
+}
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<Vec2>;
+ #[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<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ 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<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<Mat3> for Affine2 {
+ type Output = Mat3;
+
+ #[inline]
+ fn mul(self, rhs: Mat3) -> Self::Output {
+ Mat3::from(self) * rhs
+ }
+}
+
+impl Mul<Affine2> for Mat3 {
+ type Output = Mat3;
+
+ #[inline]
+ fn mul(self, rhs: Affine2) -> Self::Output {
+ self * Mat3::from(rhs)
+ }
+}
+
+impl From<Affine2> 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<Mat3A> for Affine2 {
+ type Output = Mat3A;
+
+ #[inline]
+ fn mul(self, rhs: Mat3A) -> Self::Output {
+ Mat3A::from(self) * rhs
+ }
+}
+
+impl Mul<Affine2> 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<Vec3A>;
+ #[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<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ 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<Affine3A> 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<Mat4> for Affine3A {
+ type Output = Mat4;
+
+ #[inline]
+ fn mul(self, rhs: Mat4) -> Self::Output {
+ Mat4::from(self) * rhs
+ }
+}
+
+impl Mul<Affine3A> 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<Mat2> for Mat2 {
+ type Output = Self;
+ #[inline]
+ fn add(self, rhs: Self) -> Self::Output {
+ self.add_mat2(&rhs)
+ }
+}
+
+impl AddAssign<Mat2> for Mat2 {
+ #[inline]
+ fn add_assign(&mut self, rhs: Self) {
+ *self = self.add_mat2(&rhs);
+ }
+}
+
+impl Sub<Mat2> for Mat2 {
+ type Output = Self;
+ #[inline]
+ fn sub(self, rhs: Self) -> Self::Output {
+ self.sub_mat2(&rhs)
+ }
+}
+
+impl SubAssign<Mat2> 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<Mat2> for Mat2 {
+ type Output = Self;
+ #[inline]
+ fn mul(self, rhs: Self) -> Self::Output {
+ self.mul_mat2(&rhs)
+ }
+}
+
+impl MulAssign<Mat2> for Mat2 {
+ #[inline]
+ fn mul_assign(&mut self, rhs: Self) {
+ *self = self.mul_mat2(&rhs);
+ }
+}
+
+impl Mul<Vec2> for Mat2 {
+ type Output = Vec2;
+ #[inline]
+ fn mul(self, rhs: Vec2) -> Self::Output {
+ self.mul_vec2(rhs)
+ }
+}
+
+impl Mul<Mat2> for f32 {
+ type Output = Mat2;
+ #[inline]
+ fn mul(self, rhs: Mat2) -> Self::Output {
+ rhs.mul_scalar(self)
+ }
+}
+
+impl Mul<f32> for Mat2 {
+ type Output = Self;
+ #[inline]
+ fn mul(self, rhs: f32) -> Self::Output {
+ self.mul_scalar(rhs)
+ }
+}
+
+impl MulAssign<f32> for Mat2 {
+ #[inline]
+ fn mul_assign(&mut self, rhs: f32) {
+ *self = self.mul_scalar(rhs);
+ }
+}
+
+impl Sum<Self> for Mat2 {
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ZERO, Self::add)
+ }
+}
+
+impl<'a> Sum<&'a Self> for Mat2 {
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+ }
+}
+
+impl Product for Mat2 {
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::IDENTITY, Self::mul)
+ }
+}
+
+impl<'a> Product<&'a Self> for Mat2 {
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ 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<Vec2>;
+ #[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<Mat3A> for Mat3A {
+ type Output = Self;
+ #[inline]
+ fn add(self, rhs: Self) -> Self::Output {
+ self.add_mat3(&rhs)
+ }
+}
+
+impl AddAssign<Mat3A> for Mat3A {
+ #[inline]
+ fn add_assign(&mut self, rhs: Self) {
+ *self = self.add_mat3(&rhs);
+ }
+}
+
+impl Sub<Mat3A> for Mat3A {
+ type Output = Self;
+ #[inline]
+ fn sub(self, rhs: Self) -> Self::Output {
+ self.sub_mat3(&rhs)
+ }
+}
+
+impl SubAssign<Mat3A> 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<Mat3A> for Mat3A {
+ type Output = Self;
+ #[inline]
+ fn mul(self, rhs: Self) -> Self::Output {
+ self.mul_mat3(&rhs)
+ }
+}
+
+impl MulAssign<Mat3A> for Mat3A {
+ #[inline]
+ fn mul_assign(&mut self, rhs: Self) {
+ *self = self.mul_mat3(&rhs);
+ }
+}
+
+impl Mul<Vec3A> for Mat3A {
+ type Output = Vec3A;
+ #[inline]
+ fn mul(self, rhs: Vec3A) -> Self::Output {
+ self.mul_vec3a(rhs)
+ }
+}
+
+impl Mul<Mat3A> for f32 {
+ type Output = Mat3A;
+ #[inline]
+ fn mul(self, rhs: Mat3A) -> Self::Output {
+ rhs.mul_scalar(self)
+ }
+}
+
+impl Mul<f32> for Mat3A {
+ type Output = Self;
+ #[inline]
+ fn mul(self, rhs: f32) -> Self::Output {
+ self.mul_scalar(rhs)
+ }
+}
+
+impl MulAssign<f32> for Mat3A {
+ #[inline]
+ fn mul_assign(&mut self, rhs: f32) {
+ *self = self.mul_scalar(rhs);
+ }
+}
+
+impl Mul<Vec3> for Mat3A {
+ type Output = Vec3;
+ #[inline]
+ fn mul(self, rhs: Vec3) -> Vec3 {
+ self.mul_vec3a(rhs.into()).into()
+ }
+}
+
+impl From<Mat3> 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<Self> for Mat3A {
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ZERO, Self::add)
+ }
+}
+
+impl<'a> Sum<&'a Self> for Mat3A {
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+ }
+}
+
+impl Product for Mat3A {
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::IDENTITY, Self::mul)
+ }
+}
+
+impl<'a> Product<&'a Self> for Mat3A {
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ 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 <https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluPerspective.xml>
+ #[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
+ /// <https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glOrtho.xml>
+ #[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<Mat4> for Mat4 {
+ type Output = Self;
+ #[inline]
+ fn add(self, rhs: Self) -> Self::Output {
+ self.add_mat4(&rhs)
+ }
+}
+
+impl AddAssign<Mat4> for Mat4 {
+ #[inline]
+ fn add_assign(&mut self, rhs: Self) {
+ *self = self.add_mat4(&rhs);
+ }
+}
+
+impl Sub<Mat4> for Mat4 {
+ type Output = Self;
+ #[inline]
+ fn sub(self, rhs: Self) -> Self::Output {
+ self.sub_mat4(&rhs)
+ }
+}
+
+impl SubAssign<Mat4> 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<Mat4> for Mat4 {
+ type Output = Self;
+ #[inline]
+ fn mul(self, rhs: Self) -> Self::Output {
+ self.mul_mat4(&rhs)
+ }
+}
+
+impl MulAssign<Mat4> for Mat4 {
+ #[inline]
+ fn mul_assign(&mut self, rhs: Self) {
+ *self = self.mul_mat4(&rhs);
+ }
+}
+
+impl Mul<Vec4> for Mat4 {
+ type Output = Vec4;
+ #[inline]
+ fn mul(self, rhs: Vec4) -> Self::Output {
+ self.mul_vec4(rhs)
+ }
+}
+
+impl Mul<Mat4> for f32 {
+ type Output = Mat4;
+ #[inline]
+ fn mul(self, rhs: Mat4) -> Self::Output {
+ rhs.mul_scalar(self)
+ }
+}
+
+impl Mul<f32> for Mat4 {
+ type Output = Self;
+ #[inline]
+ fn mul(self, rhs: f32) -> Self::Output {
+ self.mul_scalar(rhs)
+ }
+}
+
+impl MulAssign<f32> for Mat4 {
+ #[inline]
+ fn mul_assign(&mut self, rhs: f32) {
+ *self = self.mul_scalar(rhs);
+ }
+}
+
+impl Sum<Self> for Mat4 {
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ZERO, Self::add)
+ }
+}
+
+impl<'a> Sum<&'a Self> for Mat4 {
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+ }
+}
+
+impl Product for Mat4 {
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::IDENTITY, Self::mul)
+ }
+}
+
+impl<'a> Product<&'a Self> for Mat4 {
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ 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<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, rhs: Self) -> Self {
+ Self::from_vec4(Vec4::from(self) + Vec4::from(rhs))
+ }
+}
+
+impl Sub<Quat> 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<f32> 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<f32> 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<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 `rhs` are not normalized when `glam_assert` is enabled.
+ #[inline]
+ fn mul(self, rhs: Self) -> Self {
+ self.mul_quat(rhs)
+ }
+}
+
+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 `rhs` are not normalized when `glam_assert` is enabled.
+ #[inline]
+ fn mul_assign(&mut self, rhs: Self) {
+ *self = self.mul_quat(rhs);
+ }
+}
+
+impl Mul<Vec3> 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<Self> for Quat {
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ZERO, Self::add)
+ }
+}
+
+impl<'a> Sum<&'a Self> for Quat {
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+ }
+}
+
+impl Product for Quat {
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::IDENTITY, Self::mul)
+ }
+}
+
+impl<'a> Product<&'a Self> for Quat {
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ iter.fold(Self::IDENTITY, |a, &b| Self::mul(a, b))
+ }
+}
+
+impl Mul<Vec3A> for Quat {
+ type Output = Vec3A;
+ #[inline]
+ fn mul(self, rhs: Vec3A) -> Self::Output {
+ self.mul_vec3a(rhs)
+ }
+}
+
+impl From<Quat> for Vec4 {
+ #[inline]
+ fn from(q: Quat) -> Self {
+ Self(q.0)
+ }
+}
+
+impl From<Quat> for (f32, f32, f32, f32) {
+ #[inline]
+ fn from(q: Quat) -> Self {
+ Vec4::from(q).into()
+ }
+}
+
+impl From<Quat> for [f32; 4] {
+ #[inline]
+ fn from(q: Quat) -> Self {
+ Vec4::from(q).into()
+ }
+}
+
+impl From<Quat> for f32x4 {
+ #[inline]
+ fn from(q: Quat) -> Self {
+ q.0
+ }
+}
+
+impl Deref for Quat {
+ type Target = crate::deref::Vec4<f32>;
+ #[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<Self> {
+ 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<Vec3A> for Vec3A {
+ type Output = Self;
+ #[inline]
+ fn div(self, rhs: Self) -> Self {
+ Self(self.0 / rhs.0)
+ }
+}
+
+impl DivAssign<Vec3A> for Vec3A {
+ #[inline]
+ fn div_assign(&mut self, rhs: Self) {
+ self.0 /= rhs.0;
+ }
+}
+
+impl Div<f32> for Vec3A {
+ type Output = Self;
+ #[inline]
+ fn div(self, rhs: f32) -> Self {
+ Self(self.0 / f32x4::splat(rhs))
+ }
+}
+
+impl DivAssign<f32> for Vec3A {
+ #[inline]
+ fn div_assign(&mut self, rhs: f32) {
+ self.0 /= f32x4::splat(rhs);
+ }
+}
+
+impl Div<Vec3A> for f32 {
+ type Output = Vec3A;
+ #[inline]
+ fn div(self, rhs: Vec3A) -> Vec3A {
+ Vec3A(f32x4::splat(self) / rhs.0)
+ }
+}
+
+impl Mul<Vec3A> for Vec3A {
+ type Output = Self;
+ #[inline]
+ fn mul(self, rhs: Self) -> Self {
+ Self(self.0 * rhs.0)
+ }
+}
+
+impl MulAssign<Vec3A> for Vec3A {
+ #[inline]
+ fn mul_assign(&mut self, rhs: Self) {
+ self.0 *= rhs.0;
+ }
+}
+
+impl Mul<f32> for Vec3A {
+ type Output = Self;
+ #[inline]
+ fn mul(self, rhs: f32) -> Self {
+ Self(self.0 * f32x4::splat(rhs))
+ }
+}
+
+impl MulAssign<f32> for Vec3A {
+ #[inline]
+ fn mul_assign(&mut self, rhs: f32) {
+ self.0 *= f32x4::splat(rhs);
+ }
+}
+
+impl Mul<Vec3A> for f32 {
+ type Output = Vec3A;
+ #[inline]
+ fn mul(self, rhs: Vec3A) -> Vec3A {
+ Vec3A(f32x4::splat(self) * rhs.0)
+ }
+}
+
+impl Add<Vec3A> for Vec3A {
+ type Output = Self;
+ #[inline]
+ fn add(self, rhs: Self) -> Self {
+ Self(self.0 + rhs.0)
+ }
+}
+
+impl AddAssign<Vec3A> for Vec3A {
+ #[inline]
+ fn add_assign(&mut self, rhs: Self) {
+ self.0 += rhs.0;
+ }
+}
+
+impl Add<f32> for Vec3A {
+ type Output = Self;
+ #[inline]
+ fn add(self, rhs: f32) -> Self {
+ Self(self.0 + f32x4::splat(rhs))
+ }
+}
+
+impl AddAssign<f32> for Vec3A {
+ #[inline]
+ fn add_assign(&mut self, rhs: f32) {
+ self.0 += f32x4::splat(rhs);
+ }
+}
+
+impl Add<Vec3A> for f32 {
+ type Output = Vec3A;
+ #[inline]
+ fn add(self, rhs: Vec3A) -> Vec3A {
+ Vec3A(f32x4::splat(self) + rhs.0)
+ }
+}
+
+impl Sub<Vec3A> for Vec3A {
+ type Output = Self;
+ #[inline]
+ fn sub(self, rhs: Self) -> Self {
+ Self(self.0 - rhs.0)
+ }
+}
+
+impl SubAssign<Vec3A> for Vec3A {
+ #[inline]
+ fn sub_assign(&mut self, rhs: Vec3A) {
+ self.0 -= rhs.0;
+ }
+}
+
+impl Sub<f32> for Vec3A {
+ type Output = Self;
+ #[inline]
+ fn sub(self, rhs: f32) -> Self {
+ Self(self.0 - f32x4::splat(rhs))
+ }
+}
+
+impl SubAssign<f32> for Vec3A {
+ #[inline]
+ fn sub_assign(&mut self, rhs: f32) {
+ self.0 -= f32x4::splat(rhs);
+ }
+}
+
+impl Sub<Vec3A> for f32 {
+ type Output = Vec3A;
+ #[inline]
+ fn sub(self, rhs: Vec3A) -> Vec3A {
+ Vec3A(f32x4::splat(self) - rhs.0)
+ }
+}
+
+impl Rem<Vec3A> for Vec3A {
+ type Output = Self;
+ #[inline]
+ fn rem(self, rhs: Self) -> Self {
+ Self(self.0 % rhs.0)
+ }
+}
+
+impl RemAssign<Vec3A> for Vec3A {
+ #[inline]
+ fn rem_assign(&mut self, rhs: Self) {
+ self.0 %= rhs.0;
+ }
+}
+
+impl Rem<f32> for Vec3A {
+ type Output = Self;
+ #[inline]
+ fn rem(self, rhs: f32) -> Self {
+ self.rem(Self::splat(rhs))
+ }
+}
+
+impl RemAssign<f32> for Vec3A {
+ #[inline]
+ fn rem_assign(&mut self, rhs: f32) {
+ self.0 %= f32x4::splat(rhs);
+ }
+}
+
+impl Rem<Vec3A> 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<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ZERO, Self::add)
+ }
+}
+
+impl<'a> Sum<&'a Self> for Vec3A {
+ #[inline]
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+ }
+}
+
+impl Product for Vec3A {
+ #[inline]
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ONE, Self::mul)
+ }
+}
+
+impl<'a> Product<&'a Self> for Vec3A {
+ #[inline]
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ 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<usize> for Vec3A {
+ type Output = f32;
+ #[inline]
+ fn index(&self, index: usize) -> &Self::Output {
+ &self.0[index]
+ }
+}
+
+impl IndexMut<usize> 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<Vec3A> for f32x4 {
+ #[inline]
+ fn from(t: Vec3A) -> Self {
+ t.0
+ }
+}
+
+impl From<f32x4> 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<Vec3A> 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<Vec3A> for (f32, f32, f32) {
+ #[inline]
+ fn from(v: Vec3A) -> Self {
+ unsafe { *(v.0.to_array().as_ptr() as *const Self) }
+ }
+}
+
+impl From<Vec3> for Vec3A {
+ #[inline]
+ fn from(v: Vec3) -> Self {
+ Self::new(v.x, v.y, v.z)
+ }
+}
+
+impl From<Vec4> 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<Vec3A> 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<f32>;
+ #[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<Self> {
+ 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<Vec4> for Vec4 {
+ type Output = Self;
+ #[inline]
+ fn div(self, rhs: Self) -> Self {
+ Self(self.0 / rhs.0)
+ }
+}
+
+impl DivAssign<Vec4> for Vec4 {
+ #[inline]
+ fn div_assign(&mut self, rhs: Self) {
+ self.0 /= rhs.0;
+ }
+}
+
+impl Div<f32> for Vec4 {
+ type Output = Self;
+ #[inline]
+ fn div(self, rhs: f32) -> Self {
+ Self(self.0 / f32x4::splat(rhs))
+ }
+}
+
+impl DivAssign<f32> for Vec4 {
+ #[inline]
+ fn div_assign(&mut self, rhs: f32) {
+ self.0 /= f32x4::splat(rhs);
+ }
+}
+
+impl Div<Vec4> for f32 {
+ type Output = Vec4;
+ #[inline]
+ fn div(self, rhs: Vec4) -> Vec4 {
+ Vec4(f32x4::splat(self) / rhs.0)
+ }
+}
+
+impl Mul<Vec4> for Vec4 {
+ type Output = Self;
+ #[inline]
+ fn mul(self, rhs: Self) -> Self {
+ Self(self.0 * rhs.0)
+ }
+}
+
+impl MulAssign<Vec4> for Vec4 {
+ #[inline]
+ fn mul_assign(&mut self, rhs: Self) {
+ self.0 *= rhs.0;
+ }
+}
+
+impl Mul<f32> for Vec4 {
+ type Output = Self;
+ #[inline]
+ fn mul(self, rhs: f32) -> Self {
+ Self(self.0 * f32x4::splat(rhs))
+ }
+}
+
+impl MulAssign<f32> for Vec4 {
+ #[inline]
+ fn mul_assign(&mut self, rhs: f32) {
+ self.0 *= f32x4::splat(rhs);
+ }
+}
+
+impl Mul<Vec4> for f32 {
+ type Output = Vec4;
+ #[inline]
+ fn mul(self, rhs: Vec4) -> Vec4 {
+ Vec4(f32x4::splat(self) * rhs.0)
+ }
+}
+
+impl Add<Vec4> for Vec4 {
+ type Output = Self;
+ #[inline]
+ fn add(self, rhs: Self) -> Self {
+ Self(self.0 + rhs.0)
+ }
+}
+
+impl AddAssign<Vec4> for Vec4 {
+ #[inline]
+ fn add_assign(&mut self, rhs: Self) {
+ self.0 += rhs.0;
+ }
+}
+
+impl Add<f32> for Vec4 {
+ type Output = Self;
+ #[inline]
+ fn add(self, rhs: f32) -> Self {
+ Self(self.0 + f32x4::splat(rhs))
+ }
+}
+
+impl AddAssign<f32> for Vec4 {
+ #[inline]
+ fn add_assign(&mut self, rhs: f32) {
+ self.0 += f32x4::splat(rhs);
+ }
+}
+
+impl Add<Vec4> for f32 {
+ type Output = Vec4;
+ #[inline]
+ fn add(self, rhs: Vec4) -> Vec4 {
+ Vec4(f32x4::splat(self) + rhs.0)
+ }
+}
+
+impl Sub<Vec4> for Vec4 {
+ type Output = Self;
+ #[inline]
+ fn sub(self, rhs: Self) -> Self {
+ Self(self.0 - rhs.0)
+ }
+}
+
+impl SubAssign<Vec4> for Vec4 {
+ #[inline]
+ fn sub_assign(&mut self, rhs: Vec4) {
+ self.0 -= rhs.0;
+ }
+}
+
+impl Sub<f32> for Vec4 {
+ type Output = Self;
+ #[inline]
+ fn sub(self, rhs: f32) -> Self {
+ Self(self.0 - f32x4::splat(rhs))
+ }
+}
+
+impl SubAssign<f32> for Vec4 {
+ #[inline]
+ fn sub_assign(&mut self, rhs: f32) {
+ self.0 -= f32x4::splat(rhs);
+ }
+}
+
+impl Sub<Vec4> for f32 {
+ type Output = Vec4;
+ #[inline]
+ fn sub(self, rhs: Vec4) -> Vec4 {
+ Vec4(f32x4::splat(self) - rhs.0)
+ }
+}
+
+impl Rem<Vec4> for Vec4 {
+ type Output = Self;
+ #[inline]
+ fn rem(self, rhs: Self) -> Self {
+ Self(self.0 % rhs.0)
+ }
+}
+
+impl RemAssign<Vec4> for Vec4 {
+ #[inline]
+ fn rem_assign(&mut self, rhs: Self) {
+ self.0 %= rhs.0;
+ }
+}
+
+impl Rem<f32> for Vec4 {
+ type Output = Self;
+ #[inline]
+ fn rem(self, rhs: f32) -> Self {
+ self.rem(Self::splat(rhs))
+ }
+}
+
+impl RemAssign<f32> for Vec4 {
+ #[inline]
+ fn rem_assign(&mut self, rhs: f32) {
+ self.0 %= f32x4::splat(rhs);
+ }
+}
+
+impl Rem<Vec4> 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<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ZERO, Self::add)
+ }
+}
+
+impl<'a> Sum<&'a Self> for Vec4 {
+ #[inline]
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+ }
+}
+
+impl Product for Vec4 {
+ #[inline]
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ONE, Self::mul)
+ }
+}
+
+impl<'a> Product<&'a Self> for Vec4 {
+ #[inline]
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ 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<usize> for Vec4 {
+ type Output = f32;
+ #[inline]
+ fn index(&self, index: usize) -> &Self::Output {
+ &self.0[index]
+ }
+}
+
+impl IndexMut<usize> 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<Vec4> for f32x4 {
+ #[inline]
+ fn from(t: Vec4) -> Self {
+ t.0
+ }
+}
+
+impl From<f32x4> 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<Vec4> 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<Vec4> 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<f32>;
+ #[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<Mat3> for Mat3 {
+ type Output = Self;
+ #[inline]
+ fn add(self, rhs: Self) -> Self::Output {
+ self.add_mat3(&rhs)
+ }
+}
+
+impl AddAssign<Mat3> for Mat3 {
+ #[inline]
+ fn add_assign(&mut self, rhs: Self) {
+ *self = self.add_mat3(&rhs);
+ }
+}
+
+impl Sub<Mat3> for Mat3 {
+ type Output = Self;
+ #[inline]
+ fn sub(self, rhs: Self) -> Self::Output {
+ self.sub_mat3(&rhs)
+ }
+}
+
+impl SubAssign<Mat3> 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<Mat3> for Mat3 {
+ type Output = Self;
+ #[inline]
+ fn mul(self, rhs: Self) -> Self::Output {
+ self.mul_mat3(&rhs)
+ }
+}
+
+impl MulAssign<Mat3> for Mat3 {
+ #[inline]
+ fn mul_assign(&mut self, rhs: Self) {
+ *self = self.mul_mat3(&rhs);
+ }
+}
+
+impl Mul<Vec3> for Mat3 {
+ type Output = Vec3;
+ #[inline]
+ fn mul(self, rhs: Vec3) -> Self::Output {
+ self.mul_vec3(rhs)
+ }
+}
+
+impl Mul<Mat3> for f32 {
+ type Output = Mat3;
+ #[inline]
+ fn mul(self, rhs: Mat3) -> Self::Output {
+ rhs.mul_scalar(self)
+ }
+}
+
+impl Mul<f32> for Mat3 {
+ type Output = Self;
+ #[inline]
+ fn mul(self, rhs: f32) -> Self::Output {
+ self.mul_scalar(rhs)
+ }
+}
+
+impl MulAssign<f32> for Mat3 {
+ #[inline]
+ fn mul_assign(&mut self, rhs: f32) {
+ *self = self.mul_scalar(rhs);
+ }
+}
+
+impl Mul<Vec3A> for Mat3 {
+ type Output = Vec3A;
+ #[inline]
+ fn mul(self, rhs: Vec3A) -> Vec3A {
+ self.mul_vec3a(rhs)
+ }
+}
+
+impl From<Mat3A> 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<Self> for Mat3 {
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ZERO, Self::add)
+ }
+}
+
+impl<'a> Sum<&'a Self> for Mat3 {
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+ }
+}
+
+impl Product for Mat3 {
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::IDENTITY, Self::mul)
+ }
+}
+
+impl<'a> Product<&'a Self> for Mat3 {
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ 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<Mat2> for Mat2 {
+ type Output = Self;
+ #[inline]
+ fn add(self, rhs: Self) -> Self::Output {
+ self.add_mat2(&rhs)
+ }
+}
+
+impl AddAssign<Mat2> for Mat2 {
+ #[inline]
+ fn add_assign(&mut self, rhs: Self) {
+ *self = self.add_mat2(&rhs);
+ }
+}
+
+impl Sub<Mat2> for Mat2 {
+ type Output = Self;
+ #[inline]
+ fn sub(self, rhs: Self) -> Self::Output {
+ self.sub_mat2(&rhs)
+ }
+}
+
+impl SubAssign<Mat2> 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<Mat2> for Mat2 {
+ type Output = Self;
+ #[inline]
+ fn mul(self, rhs: Self) -> Self::Output {
+ self.mul_mat2(&rhs)
+ }
+}
+
+impl MulAssign<Mat2> for Mat2 {
+ #[inline]
+ fn mul_assign(&mut self, rhs: Self) {
+ *self = self.mul_mat2(&rhs);
+ }
+}
+
+impl Mul<Vec2> for Mat2 {
+ type Output = Vec2;
+ #[inline]
+ fn mul(self, rhs: Vec2) -> Self::Output {
+ self.mul_vec2(rhs)
+ }
+}
+
+impl Mul<Mat2> for f32 {
+ type Output = Mat2;
+ #[inline]
+ fn mul(self, rhs: Mat2) -> Self::Output {
+ rhs.mul_scalar(self)
+ }
+}
+
+impl Mul<f32> for Mat2 {
+ type Output = Self;
+ #[inline]
+ fn mul(self, rhs: f32) -> Self::Output {
+ self.mul_scalar(rhs)
+ }
+}
+
+impl MulAssign<f32> for Mat2 {
+ #[inline]
+ fn mul_assign(&mut self, rhs: f32) {
+ *self = self.mul_scalar(rhs);
+ }
+}
+
+impl Sum<Self> for Mat2 {
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ZERO, Self::add)
+ }
+}
+
+impl<'a> Sum<&'a Self> for Mat2 {
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+ }
+}
+
+impl Product for Mat2 {
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::IDENTITY, Self::mul)
+ }
+}
+
+impl<'a> Product<&'a Self> for Mat2 {
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ 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<Mat3A> for Mat3A {
+ type Output = Self;
+ #[inline]
+ fn add(self, rhs: Self) -> Self::Output {
+ self.add_mat3(&rhs)
+ }
+}
+
+impl AddAssign<Mat3A> for Mat3A {
+ #[inline]
+ fn add_assign(&mut self, rhs: Self) {
+ *self = self.add_mat3(&rhs);
+ }
+}
+
+impl Sub<Mat3A> for Mat3A {
+ type Output = Self;
+ #[inline]
+ fn sub(self, rhs: Self) -> Self::Output {
+ self.sub_mat3(&rhs)
+ }
+}
+
+impl SubAssign<Mat3A> 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<Mat3A> for Mat3A {
+ type Output = Self;
+ #[inline]
+ fn mul(self, rhs: Self) -> Self::Output {
+ self.mul_mat3(&rhs)
+ }
+}
+
+impl MulAssign<Mat3A> for Mat3A {
+ #[inline]
+ fn mul_assign(&mut self, rhs: Self) {
+ *self = self.mul_mat3(&rhs);
+ }
+}
+
+impl Mul<Vec3A> for Mat3A {
+ type Output = Vec3A;
+ #[inline]
+ fn mul(self, rhs: Vec3A) -> Self::Output {
+ self.mul_vec3a(rhs)
+ }
+}
+
+impl Mul<Mat3A> for f32 {
+ type Output = Mat3A;
+ #[inline]
+ fn mul(self, rhs: Mat3A) -> Self::Output {
+ rhs.mul_scalar(self)
+ }
+}
+
+impl Mul<f32> for Mat3A {
+ type Output = Self;
+ #[inline]
+ fn mul(self, rhs: f32) -> Self::Output {
+ self.mul_scalar(rhs)
+ }
+}
+
+impl MulAssign<f32> for Mat3A {
+ #[inline]
+ fn mul_assign(&mut self, rhs: f32) {
+ *self = self.mul_scalar(rhs);
+ }
+}
+
+impl Mul<Vec3> for Mat3A {
+ type Output = Vec3;
+ #[inline]
+ fn mul(self, rhs: Vec3) -> Vec3 {
+ self.mul_vec3a(rhs.into()).into()
+ }
+}
+
+impl From<Mat3> 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<Self> for Mat3A {
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ZERO, Self::add)
+ }
+}
+
+impl<'a> Sum<&'a Self> for Mat3A {
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+ }
+}
+
+impl Product for Mat3A {
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::IDENTITY, Self::mul)
+ }
+}
+
+impl<'a> Product<&'a Self> for Mat3A {
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ 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 <https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluPerspective.xml>
+ #[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
+ /// <https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glOrtho.xml>
+ #[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<Mat4> for Mat4 {
+ type Output = Self;
+ #[inline]
+ fn add(self, rhs: Self) -> Self::Output {
+ self.add_mat4(&rhs)
+ }
+}
+
+impl AddAssign<Mat4> for Mat4 {
+ #[inline]
+ fn add_assign(&mut self, rhs: Self) {
+ *self = self.add_mat4(&rhs);
+ }
+}
+
+impl Sub<Mat4> for Mat4 {
+ type Output = Self;
+ #[inline]
+ fn sub(self, rhs: Self) -> Self::Output {
+ self.sub_mat4(&rhs)
+ }
+}
+
+impl SubAssign<Mat4> 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<Mat4> for Mat4 {
+ type Output = Self;
+ #[inline]
+ fn mul(self, rhs: Self) -> Self::Output {
+ self.mul_mat4(&rhs)
+ }
+}
+
+impl MulAssign<Mat4> for Mat4 {
+ #[inline]
+ fn mul_assign(&mut self, rhs: Self) {
+ *self = self.mul_mat4(&rhs);
+ }
+}
+
+impl Mul<Vec4> for Mat4 {
+ type Output = Vec4;
+ #[inline]
+ fn mul(self, rhs: Vec4) -> Self::Output {
+ self.mul_vec4(rhs)
+ }
+}
+
+impl Mul<Mat4> for f32 {
+ type Output = Mat4;
+ #[inline]
+ fn mul(self, rhs: Mat4) -> Self::Output {
+ rhs.mul_scalar(self)
+ }
+}
+
+impl Mul<f32> for Mat4 {
+ type Output = Self;
+ #[inline]
+ fn mul(self, rhs: f32) -> Self::Output {
+ self.mul_scalar(rhs)
+ }
+}
+
+impl MulAssign<f32> for Mat4 {
+ #[inline]
+ fn mul_assign(&mut self, rhs: f32) {
+ *self = self.mul_scalar(rhs);
+ }
+}
+
+impl Sum<Self> for Mat4 {
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ZERO, Self::add)
+ }
+}
+
+impl<'a> Sum<&'a Self> for Mat4 {
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+ }
+}
+
+impl Product for Mat4 {
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::IDENTITY, Self::mul)
+ }
+}
+
+impl<'a> Product<&'a Self> for Mat4 {
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ 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<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, rhs: Self) -> Self {
+ Self::from_vec4(Vec4::from(self) + Vec4::from(rhs))
+ }
+}
+
+impl Sub<Quat> 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<f32> 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<f32> 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<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 `rhs` are not normalized when `glam_assert` is enabled.
+ #[inline]
+ fn mul(self, rhs: Self) -> Self {
+ self.mul_quat(rhs)
+ }
+}
+
+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 `rhs` are not normalized when `glam_assert` is enabled.
+ #[inline]
+ fn mul_assign(&mut self, rhs: Self) {
+ *self = self.mul_quat(rhs);
+ }
+}
+
+impl Mul<Vec3> 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<Self> for Quat {
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ZERO, Self::add)
+ }
+}
+
+impl<'a> Sum<&'a Self> for Quat {
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+ }
+}
+
+impl Product for Quat {
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::IDENTITY, Self::mul)
+ }
+}
+
+impl<'a> Product<&'a Self> for Quat {
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ iter.fold(Self::IDENTITY, |a, &b| Self::mul(a, b))
+ }
+}
+
+impl Mul<Vec3A> for Quat {
+ type Output = Vec3A;
+ #[inline]
+ fn mul(self, rhs: Vec3A) -> Self::Output {
+ self.mul_vec3a(rhs)
+ }
+}
+
+impl From<Quat> for Vec4 {
+ #[inline]
+ fn from(q: Quat) -> Self {
+ Self::new(q.x, q.y, q.z, q.w)
+ }
+}
+
+impl From<Quat> for (f32, f32, f32, f32) {
+ #[inline]
+ fn from(q: Quat) -> Self {
+ (q.x, q.y, q.z, q.w)
+ }
+}
+
+impl From<Quat> 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<Self> {
+ 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<Vec3A> 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<Vec3A> 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<f32> 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<f32> 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<Vec3A> 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<Vec3A> 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<Vec3A> 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<f32> 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<f32> 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<Vec3A> 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<Vec3A> 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<Vec3A> 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<f32> 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<f32> 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<Vec3A> 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<Vec3A> 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<Vec3A> 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<f32> 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<f32> 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<Vec3A> 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<Vec3A> 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<Vec3A> 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<f32> 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<f32> 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<Vec3A> 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<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ZERO, Self::add)
+ }
+}
+
+impl<'a> Sum<&'a Self> for Vec3A {
+ #[inline]
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+ }
+}
+
+impl Product for Vec3A {
+ #[inline]
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ONE, Self::mul)
+ }
+}
+
+impl<'a> Product<&'a Self> for Vec3A {
+ #[inline]
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ 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<usize> 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<usize> 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<Vec3A> 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<Vec3A> for (f32, f32, f32) {
+ #[inline]
+ fn from(v: Vec3A) -> Self {
+ (v.x, v.y, v.z)
+ }
+}
+
+impl From<Vec3> for Vec3A {
+ #[inline]
+ fn from(v: Vec3) -> Self {
+ Self::new(v.x, v.y, v.z)
+ }
+}
+
+impl From<Vec4> 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<Vec3A> 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<Self> {
+ 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<Vec4> 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<Vec4> 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<f32> 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<f32> 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<Vec4> 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<Vec4> 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<Vec4> 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<f32> 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<f32> 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<Vec4> 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<Vec4> 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<Vec4> 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<f32> 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<f32> 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<Vec4> 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<Vec4> 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<Vec4> 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<f32> 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<f32> 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<Vec4> 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<Vec4> 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<Vec4> 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<f32> 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<f32> 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<Vec4> 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<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ZERO, Self::add)
+ }
+}
+
+impl<'a> Sum<&'a Self> for Vec4 {
+ #[inline]
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+ }
+}
+
+impl Product for Vec4 {
+ #[inline]
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ONE, Self::mul)
+ }
+}
+
+impl<'a> Product<&'a Self> for Vec4 {
+ #[inline]
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ 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<usize> 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<usize> 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<Vec4> 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<Vec4> 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<Align16<Vec2>> = 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<Mat2> for Mat2 {
+ type Output = Self;
+ #[inline]
+ fn add(self, rhs: Self) -> Self::Output {
+ self.add_mat2(&rhs)
+ }
+}
+
+impl AddAssign<Mat2> for Mat2 {
+ #[inline]
+ fn add_assign(&mut self, rhs: Self) {
+ *self = self.add_mat2(&rhs);
+ }
+}
+
+impl Sub<Mat2> for Mat2 {
+ type Output = Self;
+ #[inline]
+ fn sub(self, rhs: Self) -> Self::Output {
+ self.sub_mat2(&rhs)
+ }
+}
+
+impl SubAssign<Mat2> 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<Mat2> for Mat2 {
+ type Output = Self;
+ #[inline]
+ fn mul(self, rhs: Self) -> Self::Output {
+ self.mul_mat2(&rhs)
+ }
+}
+
+impl MulAssign<Mat2> for Mat2 {
+ #[inline]
+ fn mul_assign(&mut self, rhs: Self) {
+ *self = self.mul_mat2(&rhs);
+ }
+}
+
+impl Mul<Vec2> for Mat2 {
+ type Output = Vec2;
+ #[inline]
+ fn mul(self, rhs: Vec2) -> Self::Output {
+ self.mul_vec2(rhs)
+ }
+}
+
+impl Mul<Mat2> for f32 {
+ type Output = Mat2;
+ #[inline]
+ fn mul(self, rhs: Mat2) -> Self::Output {
+ rhs.mul_scalar(self)
+ }
+}
+
+impl Mul<f32> for Mat2 {
+ type Output = Self;
+ #[inline]
+ fn mul(self, rhs: f32) -> Self::Output {
+ self.mul_scalar(rhs)
+ }
+}
+
+impl MulAssign<f32> for Mat2 {
+ #[inline]
+ fn mul_assign(&mut self, rhs: f32) {
+ *self = self.mul_scalar(rhs);
+ }
+}
+
+impl Sum<Self> for Mat2 {
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ZERO, Self::add)
+ }
+}
+
+impl<'a> Sum<&'a Self> for Mat2 {
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+ }
+}
+
+impl Product for Mat2 {
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::IDENTITY, Self::mul)
+ }
+}
+
+impl<'a> Product<&'a Self> for Mat2 {
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ 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<Vec2>;
+ #[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<Mat3A> for Mat3A {
+ type Output = Self;
+ #[inline]
+ fn add(self, rhs: Self) -> Self::Output {
+ self.add_mat3(&rhs)
+ }
+}
+
+impl AddAssign<Mat3A> for Mat3A {
+ #[inline]
+ fn add_assign(&mut self, rhs: Self) {
+ *self = self.add_mat3(&rhs);
+ }
+}
+
+impl Sub<Mat3A> for Mat3A {
+ type Output = Self;
+ #[inline]
+ fn sub(self, rhs: Self) -> Self::Output {
+ self.sub_mat3(&rhs)
+ }
+}
+
+impl SubAssign<Mat3A> 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<Mat3A> for Mat3A {
+ type Output = Self;
+ #[inline]
+ fn mul(self, rhs: Self) -> Self::Output {
+ self.mul_mat3(&rhs)
+ }
+}
+
+impl MulAssign<Mat3A> for Mat3A {
+ #[inline]
+ fn mul_assign(&mut self, rhs: Self) {
+ *self = self.mul_mat3(&rhs);
+ }
+}
+
+impl Mul<Vec3A> for Mat3A {
+ type Output = Vec3A;
+ #[inline]
+ fn mul(self, rhs: Vec3A) -> Self::Output {
+ self.mul_vec3a(rhs)
+ }
+}
+
+impl Mul<Mat3A> for f32 {
+ type Output = Mat3A;
+ #[inline]
+ fn mul(self, rhs: Mat3A) -> Self::Output {
+ rhs.mul_scalar(self)
+ }
+}
+
+impl Mul<f32> for Mat3A {
+ type Output = Self;
+ #[inline]
+ fn mul(self, rhs: f32) -> Self::Output {
+ self.mul_scalar(rhs)
+ }
+}
+
+impl MulAssign<f32> for Mat3A {
+ #[inline]
+ fn mul_assign(&mut self, rhs: f32) {
+ *self = self.mul_scalar(rhs);
+ }
+}
+
+impl Mul<Vec3> for Mat3A {
+ type Output = Vec3;
+ #[inline]
+ fn mul(self, rhs: Vec3) -> Vec3 {
+ self.mul_vec3a(rhs.into()).into()
+ }
+}
+
+impl From<Mat3> 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<Self> for Mat3A {
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ZERO, Self::add)
+ }
+}
+
+impl<'a> Sum<&'a Self> for Mat3A {
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+ }
+}
+
+impl Product for Mat3A {
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::IDENTITY, Self::mul)
+ }
+}
+
+impl<'a> Product<&'a Self> for Mat3A {
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ 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 <https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluPerspective.xml>
+ #[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
+ /// <https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glOrtho.xml>
+ #[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<Mat4> for Mat4 {
+ type Output = Self;
+ #[inline]
+ fn add(self, rhs: Self) -> Self::Output {
+ self.add_mat4(&rhs)
+ }
+}
+
+impl AddAssign<Mat4> for Mat4 {
+ #[inline]
+ fn add_assign(&mut self, rhs: Self) {
+ *self = self.add_mat4(&rhs);
+ }
+}
+
+impl Sub<Mat4> for Mat4 {
+ type Output = Self;
+ #[inline]
+ fn sub(self, rhs: Self) -> Self::Output {
+ self.sub_mat4(&rhs)
+ }
+}
+
+impl SubAssign<Mat4> 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<Mat4> for Mat4 {
+ type Output = Self;
+ #[inline]
+ fn mul(self, rhs: Self) -> Self::Output {
+ self.mul_mat4(&rhs)
+ }
+}
+
+impl MulAssign<Mat4> for Mat4 {
+ #[inline]
+ fn mul_assign(&mut self, rhs: Self) {
+ *self = self.mul_mat4(&rhs);
+ }
+}
+
+impl Mul<Vec4> for Mat4 {
+ type Output = Vec4;
+ #[inline]
+ fn mul(self, rhs: Vec4) -> Self::Output {
+ self.mul_vec4(rhs)
+ }
+}
+
+impl Mul<Mat4> for f32 {
+ type Output = Mat4;
+ #[inline]
+ fn mul(self, rhs: Mat4) -> Self::Output {
+ rhs.mul_scalar(self)
+ }
+}
+
+impl Mul<f32> for Mat4 {
+ type Output = Self;
+ #[inline]
+ fn mul(self, rhs: f32) -> Self::Output {
+ self.mul_scalar(rhs)
+ }
+}
+
+impl MulAssign<f32> for Mat4 {
+ #[inline]
+ fn mul_assign(&mut self, rhs: f32) {
+ *self = self.mul_scalar(rhs);
+ }
+}
+
+impl Sum<Self> for Mat4 {
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ZERO, Self::add)
+ }
+}
+
+impl<'a> Sum<&'a Self> for Mat4 {
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+ }
+}
+
+impl Product for Mat4 {
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::IDENTITY, Self::mul)
+ }
+}
+
+impl<'a> Product<&'a Self> for Mat4 {
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ 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<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, rhs: Self) -> Self {
+ Self::from_vec4(Vec4::from(self) + Vec4::from(rhs))
+ }
+}
+
+impl Sub<Quat> 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<f32> 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<f32> 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<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 `rhs` are not normalized when `glam_assert` is enabled.
+ #[inline]
+ fn mul(self, rhs: Self) -> Self {
+ self.mul_quat(rhs)
+ }
+}
+
+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 `rhs` are not normalized when `glam_assert` is enabled.
+ #[inline]
+ fn mul_assign(&mut self, rhs: Self) {
+ *self = self.mul_quat(rhs);
+ }
+}
+
+impl Mul<Vec3> 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<Self> for Quat {
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ZERO, Self::add)
+ }
+}
+
+impl<'a> Sum<&'a Self> for Quat {
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+ }
+}
+
+impl Product for Quat {
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::IDENTITY, Self::mul)
+ }
+}
+
+impl<'a> Product<&'a Self> for Quat {
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ iter.fold(Self::IDENTITY, |a, &b| Self::mul(a, b))
+ }
+}
+
+impl Mul<Vec3A> for Quat {
+ type Output = Vec3A;
+ #[inline]
+ fn mul(self, rhs: Vec3A) -> Self::Output {
+ self.mul_vec3a(rhs)
+ }
+}
+
+impl From<Quat> for Vec4 {
+ #[inline]
+ fn from(q: Quat) -> Self {
+ Self(q.0)
+ }
+}
+
+impl From<Quat> for (f32, f32, f32, f32) {
+ #[inline]
+ fn from(q: Quat) -> Self {
+ Vec4::from(q).into()
+ }
+}
+
+impl From<Quat> for [f32; 4] {
+ #[inline]
+ fn from(q: Quat) -> Self {
+ Vec4::from(q).into()
+ }
+}
+
+impl From<Quat> for __m128 {
+ #[inline]
+ fn from(q: Quat) -> Self {
+ q.0
+ }
+}
+
+impl Deref for Quat {
+ type Target = crate::deref::Vec4<f32>;
+ #[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<Self> {
+ 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<Vec3A> for Vec3A {
+ type Output = Self;
+ #[inline]
+ fn div(self, rhs: Self) -> Self {
+ Self(unsafe { _mm_div_ps(self.0, rhs.0) })
+ }
+}
+
+impl DivAssign<Vec3A> for Vec3A {
+ #[inline]
+ fn div_assign(&mut self, rhs: Self) {
+ self.0 = unsafe { _mm_div_ps(self.0, rhs.0) };
+ }
+}
+
+impl Div<f32> 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<f32> for Vec3A {
+ #[inline]
+ fn div_assign(&mut self, rhs: f32) {
+ self.0 = unsafe { _mm_div_ps(self.0, _mm_set1_ps(rhs)) };
+ }
+}
+
+impl Div<Vec3A> 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<Vec3A> for Vec3A {
+ type Output = Self;
+ #[inline]
+ fn mul(self, rhs: Self) -> Self {
+ Self(unsafe { _mm_mul_ps(self.0, rhs.0) })
+ }
+}
+
+impl MulAssign<Vec3A> for Vec3A {
+ #[inline]
+ fn mul_assign(&mut self, rhs: Self) {
+ self.0 = unsafe { _mm_mul_ps(self.0, rhs.0) };
+ }
+}
+
+impl Mul<f32> 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<f32> for Vec3A {
+ #[inline]
+ fn mul_assign(&mut self, rhs: f32) {
+ self.0 = unsafe { _mm_mul_ps(self.0, _mm_set1_ps(rhs)) };
+ }
+}
+
+impl Mul<Vec3A> 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<Vec3A> for Vec3A {
+ type Output = Self;
+ #[inline]
+ fn add(self, rhs: Self) -> Self {
+ Self(unsafe { _mm_add_ps(self.0, rhs.0) })
+ }
+}
+
+impl AddAssign<Vec3A> for Vec3A {
+ #[inline]
+ fn add_assign(&mut self, rhs: Self) {
+ self.0 = unsafe { _mm_add_ps(self.0, rhs.0) };
+ }
+}
+
+impl Add<f32> 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<f32> for Vec3A {
+ #[inline]
+ fn add_assign(&mut self, rhs: f32) {
+ self.0 = unsafe { _mm_add_ps(self.0, _mm_set1_ps(rhs)) };
+ }
+}
+
+impl Add<Vec3A> 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<Vec3A> for Vec3A {
+ type Output = Self;
+ #[inline]
+ fn sub(self, rhs: Self) -> Self {
+ Self(unsafe { _mm_sub_ps(self.0, rhs.0) })
+ }
+}
+
+impl SubAssign<Vec3A> for Vec3A {
+ #[inline]
+ fn sub_assign(&mut self, rhs: Vec3A) {
+ self.0 = unsafe { _mm_sub_ps(self.0, rhs.0) };
+ }
+}
+
+impl Sub<f32> 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<f32> for Vec3A {
+ #[inline]
+ fn sub_assign(&mut self, rhs: f32) {
+ self.0 = unsafe { _mm_sub_ps(self.0, _mm_set1_ps(rhs)) };
+ }
+}
+
+impl Sub<Vec3A> 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<Vec3A> 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<Vec3A> for Vec3A {
+ #[inline]
+ fn rem_assign(&mut self, rhs: Self) {
+ *self = self.rem(rhs);
+ }
+}
+
+impl Rem<f32> for Vec3A {
+ type Output = Self;
+ #[inline]
+ fn rem(self, rhs: f32) -> Self {
+ self.rem(Self::splat(rhs))
+ }
+}
+
+impl RemAssign<f32> for Vec3A {
+ #[inline]
+ fn rem_assign(&mut self, rhs: f32) {
+ *self = self.rem(Self::splat(rhs));
+ }
+}
+
+impl Rem<Vec3A> 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<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ZERO, Self::add)
+ }
+}
+
+impl<'a> Sum<&'a Self> for Vec3A {
+ #[inline]
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+ }
+}
+
+impl Product for Vec3A {
+ #[inline]
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ONE, Self::mul)
+ }
+}
+
+impl<'a> Product<&'a Self> for Vec3A {
+ #[inline]
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ 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<usize> 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<usize> 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<Vec3A> 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<Vec3A> for [f32; 3] {
+ #[inline]
+ fn from(v: Vec3A) -> Self {
+ use crate::Align16;
+ use core::mem::MaybeUninit;
+ let mut out: MaybeUninit<Align16<Self>> = 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<Vec3A> for (f32, f32, f32) {
+ #[inline]
+ fn from(v: Vec3A) -> Self {
+ use crate::Align16;
+ use core::mem::MaybeUninit;
+ let mut out: MaybeUninit<Align16<Self>> = MaybeUninit::uninit();
+ unsafe {
+ _mm_store_ps(out.as_mut_ptr().cast(), v.0);
+ out.assume_init().0
+ }
+ }
+}
+
+impl From<Vec3> for Vec3A {
+ #[inline]
+ fn from(v: Vec3) -> Self {
+ Self::new(v.x, v.y, v.z)
+ }
+}
+
+impl From<Vec4> 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<Vec3A> for Vec3 {
+ #[inline]
+ fn from(v: Vec3A) -> Self {
+ use crate::Align16;
+ use core::mem::MaybeUninit;
+ let mut out: MaybeUninit<Align16<Self>> = 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<f32>;
+ #[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<Self> {
+ 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<Vec4> for Vec4 {
+ type Output = Self;
+ #[inline]
+ fn div(self, rhs: Self) -> Self {
+ Self(unsafe { _mm_div_ps(self.0, rhs.0) })
+ }
+}
+
+impl DivAssign<Vec4> for Vec4 {
+ #[inline]
+ fn div_assign(&mut self, rhs: Self) {
+ self.0 = unsafe { _mm_div_ps(self.0, rhs.0) };
+ }
+}
+
+impl Div<f32> 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<f32> for Vec4 {
+ #[inline]
+ fn div_assign(&mut self, rhs: f32) {
+ self.0 = unsafe { _mm_div_ps(self.0, _mm_set1_ps(rhs)) };
+ }
+}
+
+impl Div<Vec4> 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<Vec4> for Vec4 {
+ type Output = Self;
+ #[inline]
+ fn mul(self, rhs: Self) -> Self {
+ Self(unsafe { _mm_mul_ps(self.0, rhs.0) })
+ }
+}
+
+impl MulAssign<Vec4> for Vec4 {
+ #[inline]
+ fn mul_assign(&mut self, rhs: Self) {
+ self.0 = unsafe { _mm_mul_ps(self.0, rhs.0) };
+ }
+}
+
+impl Mul<f32> 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<f32> for Vec4 {
+ #[inline]
+ fn mul_assign(&mut self, rhs: f32) {
+ self.0 = unsafe { _mm_mul_ps(self.0, _mm_set1_ps(rhs)) };
+ }
+}
+
+impl Mul<Vec4> 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<Vec4> for Vec4 {
+ type Output = Self;
+ #[inline]
+ fn add(self, rhs: Self) -> Self {
+ Self(unsafe { _mm_add_ps(self.0, rhs.0) })
+ }
+}
+
+impl AddAssign<Vec4> for Vec4 {
+ #[inline]
+ fn add_assign(&mut self, rhs: Self) {
+ self.0 = unsafe { _mm_add_ps(self.0, rhs.0) };
+ }
+}
+
+impl Add<f32> 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<f32> for Vec4 {
+ #[inline]
+ fn add_assign(&mut self, rhs: f32) {
+ self.0 = unsafe { _mm_add_ps(self.0, _mm_set1_ps(rhs)) };
+ }
+}
+
+impl Add<Vec4> 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<Vec4> for Vec4 {
+ type Output = Self;
+ #[inline]
+ fn sub(self, rhs: Self) -> Self {
+ Self(unsafe { _mm_sub_ps(self.0, rhs.0) })
+ }
+}
+
+impl SubAssign<Vec4> for Vec4 {
+ #[inline]
+ fn sub_assign(&mut self, rhs: Vec4) {
+ self.0 = unsafe { _mm_sub_ps(self.0, rhs.0) };
+ }
+}
+
+impl Sub<f32> 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<f32> for Vec4 {
+ #[inline]
+ fn sub_assign(&mut self, rhs: f32) {
+ self.0 = unsafe { _mm_sub_ps(self.0, _mm_set1_ps(rhs)) };
+ }
+}
+
+impl Sub<Vec4> 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<Vec4> 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<Vec4> for Vec4 {
+ #[inline]
+ fn rem_assign(&mut self, rhs: Self) {
+ *self = self.rem(rhs);
+ }
+}
+
+impl Rem<f32> for Vec4 {
+ type Output = Self;
+ #[inline]
+ fn rem(self, rhs: f32) -> Self {
+ self.rem(Self::splat(rhs))
+ }
+}
+
+impl RemAssign<f32> for Vec4 {
+ #[inline]
+ fn rem_assign(&mut self, rhs: f32) {
+ *self = self.rem(Self::splat(rhs));
+ }
+}
+
+impl Rem<Vec4> 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<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ZERO, Self::add)
+ }
+}
+
+impl<'a> Sum<&'a Self> for Vec4 {
+ #[inline]
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+ }
+}
+
+impl Product for Vec4 {
+ #[inline]
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ONE, Self::mul)
+ }
+}
+
+impl<'a> Product<&'a Self> for Vec4 {
+ #[inline]
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ 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<usize> 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<usize> 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<Vec4> 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<Vec4> for [f32; 4] {
+ #[inline]
+ fn from(v: Vec4) -> Self {
+ use crate::Align16;
+ use core::mem::MaybeUninit;
+ let mut out: MaybeUninit<Align16<Self>> = 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<Vec4> for (f32, f32, f32, f32) {
+ #[inline]
+ fn from(v: Vec4) -> Self {
+ use crate::Align16;
+ use core::mem::MaybeUninit;
+ let mut out: MaybeUninit<Align16<Self>> = 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<f32>;
+ #[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<Self> {
+ 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<Vec2> 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<Vec2> for Vec2 {
+ #[inline]
+ fn div_assign(&mut self, rhs: Self) {
+ self.x.div_assign(rhs.x);
+ self.y.div_assign(rhs.y);
+ }
+}
+
+impl Div<f32> 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<f32> for Vec2 {
+ #[inline]
+ fn div_assign(&mut self, rhs: f32) {
+ self.x.div_assign(rhs);
+ self.y.div_assign(rhs);
+ }
+}
+
+impl Div<Vec2> 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<Vec2> 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<Vec2> for Vec2 {
+ #[inline]
+ fn mul_assign(&mut self, rhs: Self) {
+ self.x.mul_assign(rhs.x);
+ self.y.mul_assign(rhs.y);
+ }
+}
+
+impl Mul<f32> 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<f32> for Vec2 {
+ #[inline]
+ fn mul_assign(&mut self, rhs: f32) {
+ self.x.mul_assign(rhs);
+ self.y.mul_assign(rhs);
+ }
+}
+
+impl Mul<Vec2> 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<Vec2> 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<Vec2> for Vec2 {
+ #[inline]
+ fn add_assign(&mut self, rhs: Self) {
+ self.x.add_assign(rhs.x);
+ self.y.add_assign(rhs.y);
+ }
+}
+
+impl Add<f32> 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<f32> for Vec2 {
+ #[inline]
+ fn add_assign(&mut self, rhs: f32) {
+ self.x.add_assign(rhs);
+ self.y.add_assign(rhs);
+ }
+}
+
+impl Add<Vec2> 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<Vec2> 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<Vec2> for Vec2 {
+ #[inline]
+ fn sub_assign(&mut self, rhs: Vec2) {
+ self.x.sub_assign(rhs.x);
+ self.y.sub_assign(rhs.y);
+ }
+}
+
+impl Sub<f32> 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<f32> for Vec2 {
+ #[inline]
+ fn sub_assign(&mut self, rhs: f32) {
+ self.x.sub_assign(rhs);
+ self.y.sub_assign(rhs);
+ }
+}
+
+impl Sub<Vec2> 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<Vec2> 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<Vec2> for Vec2 {
+ #[inline]
+ fn rem_assign(&mut self, rhs: Self) {
+ self.x.rem_assign(rhs.x);
+ self.y.rem_assign(rhs.y);
+ }
+}
+
+impl Rem<f32> 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<f32> for Vec2 {
+ #[inline]
+ fn rem_assign(&mut self, rhs: f32) {
+ self.x.rem_assign(rhs);
+ self.y.rem_assign(rhs);
+ }
+}
+
+impl Rem<Vec2> 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<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ZERO, Self::add)
+ }
+}
+
+impl<'a> Sum<&'a Self> for Vec2 {
+ #[inline]
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+ }
+}
+
+impl Product for Vec2 {
+ #[inline]
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ONE, Self::mul)
+ }
+}
+
+impl<'a> Product<&'a Self> for Vec2 {
+ #[inline]
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ 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<usize> 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<usize> 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<Vec2> 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<Vec2> 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<Self> {
+ 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<Vec3> 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<Vec3> 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<f32> 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<f32> 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<Vec3> 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<Vec3> 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<Vec3> 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<f32> 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<f32> 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<Vec3> 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<Vec3> 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<Vec3> 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<f32> 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<f32> 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<Vec3> 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<Vec3> 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<Vec3> 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<f32> 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<f32> 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<Vec3> 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<Vec3> 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<Vec3> 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<f32> 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<f32> 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<Vec3> 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<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ZERO, Self::add)
+ }
+}
+
+impl<'a> Sum<&'a Self> for Vec3 {
+ #[inline]
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+ }
+}
+
+impl Product for Vec3 {
+ #[inline]
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ONE, Self::mul)
+ }
+}
+
+impl<'a> Product<&'a Self> for Vec3 {
+ #[inline]
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ 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<usize> 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<usize> 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<Vec3> 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<Vec3> 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<v128> = 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<Mat2> for Mat2 {
+ type Output = Self;
+ #[inline]
+ fn add(self, rhs: Self) -> Self::Output {
+ self.add_mat2(&rhs)
+ }
+}
+
+impl AddAssign<Mat2> for Mat2 {
+ #[inline]
+ fn add_assign(&mut self, rhs: Self) {
+ *self = self.add_mat2(&rhs);
+ }
+}
+
+impl Sub<Mat2> for Mat2 {
+ type Output = Self;
+ #[inline]
+ fn sub(self, rhs: Self) -> Self::Output {
+ self.sub_mat2(&rhs)
+ }
+}
+
+impl SubAssign<Mat2> 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<Mat2> for Mat2 {
+ type Output = Self;
+ #[inline]
+ fn mul(self, rhs: Self) -> Self::Output {
+ self.mul_mat2(&rhs)
+ }
+}
+
+impl MulAssign<Mat2> for Mat2 {
+ #[inline]
+ fn mul_assign(&mut self, rhs: Self) {
+ *self = self.mul_mat2(&rhs);
+ }
+}
+
+impl Mul<Vec2> for Mat2 {
+ type Output = Vec2;
+ #[inline]
+ fn mul(self, rhs: Vec2) -> Self::Output {
+ self.mul_vec2(rhs)
+ }
+}
+
+impl Mul<Mat2> for f32 {
+ type Output = Mat2;
+ #[inline]
+ fn mul(self, rhs: Mat2) -> Self::Output {
+ rhs.mul_scalar(self)
+ }
+}
+
+impl Mul<f32> for Mat2 {
+ type Output = Self;
+ #[inline]
+ fn mul(self, rhs: f32) -> Self::Output {
+ self.mul_scalar(rhs)
+ }
+}
+
+impl MulAssign<f32> for Mat2 {
+ #[inline]
+ fn mul_assign(&mut self, rhs: f32) {
+ *self = self.mul_scalar(rhs);
+ }
+}
+
+impl Sum<Self> for Mat2 {
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ZERO, Self::add)
+ }
+}
+
+impl<'a> Sum<&'a Self> for Mat2 {
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+ }
+}
+
+impl Product for Mat2 {
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::IDENTITY, Self::mul)
+ }
+}
+
+impl<'a> Product<&'a Self> for Mat2 {
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ 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<Vec2>;
+ #[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<Mat3A> for Mat3A {
+ type Output = Self;
+ #[inline]
+ fn add(self, rhs: Self) -> Self::Output {
+ self.add_mat3(&rhs)
+ }
+}
+
+impl AddAssign<Mat3A> for Mat3A {
+ #[inline]
+ fn add_assign(&mut self, rhs: Self) {
+ *self = self.add_mat3(&rhs);
+ }
+}
+
+impl Sub<Mat3A> for Mat3A {
+ type Output = Self;
+ #[inline]
+ fn sub(self, rhs: Self) -> Self::Output {
+ self.sub_mat3(&rhs)
+ }
+}
+
+impl SubAssign<Mat3A> 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<Mat3A> for Mat3A {
+ type Output = Self;
+ #[inline]
+ fn mul(self, rhs: Self) -> Self::Output {
+ self.mul_mat3(&rhs)
+ }
+}
+
+impl MulAssign<Mat3A> for Mat3A {
+ #[inline]
+ fn mul_assign(&mut self, rhs: Self) {
+ *self = self.mul_mat3(&rhs);
+ }
+}
+
+impl Mul<Vec3A> for Mat3A {
+ type Output = Vec3A;
+ #[inline]
+ fn mul(self, rhs: Vec3A) -> Self::Output {
+ self.mul_vec3a(rhs)
+ }
+}
+
+impl Mul<Mat3A> for f32 {
+ type Output = Mat3A;
+ #[inline]
+ fn mul(self, rhs: Mat3A) -> Self::Output {
+ rhs.mul_scalar(self)
+ }
+}
+
+impl Mul<f32> for Mat3A {
+ type Output = Self;
+ #[inline]
+ fn mul(self, rhs: f32) -> Self::Output {
+ self.mul_scalar(rhs)
+ }
+}
+
+impl MulAssign<f32> for Mat3A {
+ #[inline]
+ fn mul_assign(&mut self, rhs: f32) {
+ *self = self.mul_scalar(rhs);
+ }
+}
+
+impl Mul<Vec3> for Mat3A {
+ type Output = Vec3;
+ #[inline]
+ fn mul(self, rhs: Vec3) -> Vec3 {
+ self.mul_vec3a(rhs.into()).into()
+ }
+}
+
+impl From<Mat3> 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<Self> for Mat3A {
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ZERO, Self::add)
+ }
+}
+
+impl<'a> Sum<&'a Self> for Mat3A {
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+ }
+}
+
+impl Product for Mat3A {
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::IDENTITY, Self::mul)
+ }
+}
+
+impl<'a> Product<&'a Self> for Mat3A {
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ 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 <https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluPerspective.xml>
+ #[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
+ /// <https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glOrtho.xml>
+ #[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<Mat4> for Mat4 {
+ type Output = Self;
+ #[inline]
+ fn add(self, rhs: Self) -> Self::Output {
+ self.add_mat4(&rhs)
+ }
+}
+
+impl AddAssign<Mat4> for Mat4 {
+ #[inline]
+ fn add_assign(&mut self, rhs: Self) {
+ *self = self.add_mat4(&rhs);
+ }
+}
+
+impl Sub<Mat4> for Mat4 {
+ type Output = Self;
+ #[inline]
+ fn sub(self, rhs: Self) -> Self::Output {
+ self.sub_mat4(&rhs)
+ }
+}
+
+impl SubAssign<Mat4> 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<Mat4> for Mat4 {
+ type Output = Self;
+ #[inline]
+ fn mul(self, rhs: Self) -> Self::Output {
+ self.mul_mat4(&rhs)
+ }
+}
+
+impl MulAssign<Mat4> for Mat4 {
+ #[inline]
+ fn mul_assign(&mut self, rhs: Self) {
+ *self = self.mul_mat4(&rhs);
+ }
+}
+
+impl Mul<Vec4> for Mat4 {
+ type Output = Vec4;
+ #[inline]
+ fn mul(self, rhs: Vec4) -> Self::Output {
+ self.mul_vec4(rhs)
+ }
+}
+
+impl Mul<Mat4> for f32 {
+ type Output = Mat4;
+ #[inline]
+ fn mul(self, rhs: Mat4) -> Self::Output {
+ rhs.mul_scalar(self)
+ }
+}
+
+impl Mul<f32> for Mat4 {
+ type Output = Self;
+ #[inline]
+ fn mul(self, rhs: f32) -> Self::Output {
+ self.mul_scalar(rhs)
+ }
+}
+
+impl MulAssign<f32> for Mat4 {
+ #[inline]
+ fn mul_assign(&mut self, rhs: f32) {
+ *self = self.mul_scalar(rhs);
+ }
+}
+
+impl Sum<Self> for Mat4 {
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ZERO, Self::add)
+ }
+}
+
+impl<'a> Sum<&'a Self> for Mat4 {
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+ }
+}
+
+impl Product for Mat4 {
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::IDENTITY, Self::mul)
+ }
+}
+
+impl<'a> Product<&'a Self> for Mat4 {
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ 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<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, rhs: Self) -> Self {
+ Self::from_vec4(Vec4::from(self) + Vec4::from(rhs))
+ }
+}
+
+impl Sub<Quat> 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<f32> 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<f32> 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<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 `rhs` are not normalized when `glam_assert` is enabled.
+ #[inline]
+ fn mul(self, rhs: Self) -> Self {
+ self.mul_quat(rhs)
+ }
+}
+
+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 `rhs` are not normalized when `glam_assert` is enabled.
+ #[inline]
+ fn mul_assign(&mut self, rhs: Self) {
+ *self = self.mul_quat(rhs);
+ }
+}
+
+impl Mul<Vec3> 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<Self> for Quat {
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ZERO, Self::add)
+ }
+}
+
+impl<'a> Sum<&'a Self> for Quat {
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+ }
+}
+
+impl Product for Quat {
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::IDENTITY, Self::mul)
+ }
+}
+
+impl<'a> Product<&'a Self> for Quat {
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ iter.fold(Self::IDENTITY, |a, &b| Self::mul(a, b))
+ }
+}
+
+impl Mul<Vec3A> for Quat {
+ type Output = Vec3A;
+ #[inline]
+ fn mul(self, rhs: Vec3A) -> Self::Output {
+ self.mul_vec3a(rhs)
+ }
+}
+
+impl From<Quat> for Vec4 {
+ #[inline]
+ fn from(q: Quat) -> Self {
+ Self(q.0)
+ }
+}
+
+impl From<Quat> for (f32, f32, f32, f32) {
+ #[inline]
+ fn from(q: Quat) -> Self {
+ Vec4::from(q).into()
+ }
+}
+
+impl From<Quat> for [f32; 4] {
+ #[inline]
+ fn from(q: Quat) -> Self {
+ Vec4::from(q).into()
+ }
+}
+
+impl From<Quat> for v128 {
+ #[inline]
+ fn from(q: Quat) -> Self {
+ q.0
+ }
+}
+
+impl Deref for Quat {
+ type Target = crate::deref::Vec4<f32>;
+ #[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<Self> {
+ 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<Vec3A> for Vec3A {
+ type Output = Self;
+ #[inline]
+ fn div(self, rhs: Self) -> Self {
+ Self(f32x4_div(self.0, rhs.0))
+ }
+}
+
+impl DivAssign<Vec3A> for Vec3A {
+ #[inline]
+ fn div_assign(&mut self, rhs: Self) {
+ self.0 = f32x4_div(self.0, rhs.0);
+ }
+}
+
+impl Div<f32> for Vec3A {
+ type Output = Self;
+ #[inline]
+ fn div(self, rhs: f32) -> Self {
+ Self(f32x4_div(self.0, f32x4_splat(rhs)))
+ }
+}
+
+impl DivAssign<f32> for Vec3A {
+ #[inline]
+ fn div_assign(&mut self, rhs: f32) {
+ self.0 = f32x4_div(self.0, f32x4_splat(rhs))
+ }
+}
+
+impl Div<Vec3A> for f32 {
+ type Output = Vec3A;
+ #[inline]
+ fn div(self, rhs: Vec3A) -> Vec3A {
+ Vec3A(f32x4_div(f32x4_splat(self), rhs.0))
+ }
+}
+
+impl Mul<Vec3A> for Vec3A {
+ type Output = Self;
+ #[inline]
+ fn mul(self, rhs: Self) -> Self {
+ Self(f32x4_mul(self.0, rhs.0))
+ }
+}
+
+impl MulAssign<Vec3A> for Vec3A {
+ #[inline]
+ fn mul_assign(&mut self, rhs: Self) {
+ self.0 = f32x4_mul(self.0, rhs.0);
+ }
+}
+
+impl Mul<f32> for Vec3A {
+ type Output = Self;
+ #[inline]
+ fn mul(self, rhs: f32) -> Self {
+ Self(f32x4_mul(self.0, f32x4_splat(rhs)))
+ }
+}
+
+impl MulAssign<f32> for Vec3A {
+ #[inline]
+ fn mul_assign(&mut self, rhs: f32) {
+ self.0 = f32x4_mul(self.0, f32x4_splat(rhs))
+ }
+}
+
+impl Mul<Vec3A> for f32 {
+ type Output = Vec3A;
+ #[inline]
+ fn mul(self, rhs: Vec3A) -> Vec3A {
+ Vec3A(f32x4_mul(f32x4_splat(self), rhs.0))
+ }
+}
+
+impl Add<Vec3A> for Vec3A {
+ type Output = Self;
+ #[inline]
+ fn add(self, rhs: Self) -> Self {
+ Self(f32x4_add(self.0, rhs.0))
+ }
+}
+
+impl AddAssign<Vec3A> for Vec3A {
+ #[inline]
+ fn add_assign(&mut self, rhs: Self) {
+ self.0 = f32x4_add(self.0, rhs.0);
+ }
+}
+
+impl Add<f32> for Vec3A {
+ type Output = Self;
+ #[inline]
+ fn add(self, rhs: f32) -> Self {
+ Self(f32x4_add(self.0, f32x4_splat(rhs)))
+ }
+}
+
+impl AddAssign<f32> for Vec3A {
+ #[inline]
+ fn add_assign(&mut self, rhs: f32) {
+ self.0 = f32x4_add(self.0, f32x4_splat(rhs));
+ }
+}
+
+impl Add<Vec3A> for f32 {
+ type Output = Vec3A;
+ #[inline]
+ fn add(self, rhs: Vec3A) -> Vec3A {
+ Vec3A(f32x4_add(f32x4_splat(self), rhs.0))
+ }
+}
+
+impl Sub<Vec3A> for Vec3A {
+ type Output = Self;
+ #[inline]
+ fn sub(self, rhs: Self) -> Self {
+ Self(f32x4_sub(self.0, rhs.0))
+ }
+}
+
+impl SubAssign<Vec3A> for Vec3A {
+ #[inline]
+ fn sub_assign(&mut self, rhs: Vec3A) {
+ self.0 = f32x4_sub(self.0, rhs.0);
+ }
+}
+
+impl Sub<f32> for Vec3A {
+ type Output = Self;
+ #[inline]
+ fn sub(self, rhs: f32) -> Self {
+ Self(f32x4_sub(self.0, f32x4_splat(rhs)))
+ }
+}
+
+impl SubAssign<f32> for Vec3A {
+ #[inline]
+ fn sub_assign(&mut self, rhs: f32) {
+ self.0 = f32x4_sub(self.0, f32x4_splat(rhs))
+ }
+}
+
+impl Sub<Vec3A> for f32 {
+ type Output = Vec3A;
+ #[inline]
+ fn sub(self, rhs: Vec3A) -> Vec3A {
+ Vec3A(f32x4_sub(f32x4_splat(self), rhs.0))
+ }
+}
+
+impl Rem<Vec3A> 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<Vec3A> for Vec3A {
+ #[inline]
+ fn rem_assign(&mut self, rhs: Self) {
+ *self = self.rem(rhs);
+ }
+}
+
+impl Rem<f32> for Vec3A {
+ type Output = Self;
+ #[inline]
+ fn rem(self, rhs: f32) -> Self {
+ self.rem(Self::splat(rhs))
+ }
+}
+
+impl RemAssign<f32> for Vec3A {
+ #[inline]
+ fn rem_assign(&mut self, rhs: f32) {
+ *self = self.rem(Self::splat(rhs));
+ }
+}
+
+impl Rem<Vec3A> 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<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ZERO, Self::add)
+ }
+}
+
+impl<'a> Sum<&'a Self> for Vec3A {
+ #[inline]
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+ }
+}
+
+impl Product for Vec3A {
+ #[inline]
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ONE, Self::mul)
+ }
+}
+
+impl<'a> Product<&'a Self> for Vec3A {
+ #[inline]
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ 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<usize> 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<usize> 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<Vec3A> for v128 {
+ #[inline]
+ fn from(t: Vec3A) -> Self {
+ t.0
+ }
+}
+
+impl From<v128> 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<Vec3A> 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<Vec3A> for (f32, f32, f32) {
+ #[inline]
+ fn from(v: Vec3A) -> Self {
+ unsafe { *(&v.0 as *const v128 as *const Self) }
+ }
+}
+
+impl From<Vec3> for Vec3A {
+ #[inline]
+ fn from(v: Vec3) -> Self {
+ Self::new(v.x, v.y, v.z)
+ }
+}
+
+impl From<Vec4> 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<Vec3A> 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<f32>;
+ #[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<Self> {
+ 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<Vec4> for Vec4 {
+ type Output = Self;
+ #[inline]
+ fn div(self, rhs: Self) -> Self {
+ Self(f32x4_div(self.0, rhs.0))
+ }
+}
+
+impl DivAssign<Vec4> for Vec4 {
+ #[inline]
+ fn div_assign(&mut self, rhs: Self) {
+ self.0 = f32x4_div(self.0, rhs.0);
+ }
+}
+
+impl Div<f32> for Vec4 {
+ type Output = Self;
+ #[inline]
+ fn div(self, rhs: f32) -> Self {
+ Self(f32x4_div(self.0, f32x4_splat(rhs)))
+ }
+}
+
+impl DivAssign<f32> for Vec4 {
+ #[inline]
+ fn div_assign(&mut self, rhs: f32) {
+ self.0 = f32x4_div(self.0, f32x4_splat(rhs))
+ }
+}
+
+impl Div<Vec4> for f32 {
+ type Output = Vec4;
+ #[inline]
+ fn div(self, rhs: Vec4) -> Vec4 {
+ Vec4(f32x4_div(f32x4_splat(self), rhs.0))
+ }
+}
+
+impl Mul<Vec4> for Vec4 {
+ type Output = Self;
+ #[inline]
+ fn mul(self, rhs: Self) -> Self {
+ Self(f32x4_mul(self.0, rhs.0))
+ }
+}
+
+impl MulAssign<Vec4> for Vec4 {
+ #[inline]
+ fn mul_assign(&mut self, rhs: Self) {
+ self.0 = f32x4_mul(self.0, rhs.0);
+ }
+}
+
+impl Mul<f32> for Vec4 {
+ type Output = Self;
+ #[inline]
+ fn mul(self, rhs: f32) -> Self {
+ Self(f32x4_mul(self.0, f32x4_splat(rhs)))
+ }
+}
+
+impl MulAssign<f32> for Vec4 {
+ #[inline]
+ fn mul_assign(&mut self, rhs: f32) {
+ self.0 = f32x4_mul(self.0, f32x4_splat(rhs))
+ }
+}
+
+impl Mul<Vec4> for f32 {
+ type Output = Vec4;
+ #[inline]
+ fn mul(self, rhs: Vec4) -> Vec4 {
+ Vec4(f32x4_mul(f32x4_splat(self), rhs.0))
+ }
+}
+
+impl Add<Vec4> for Vec4 {
+ type Output = Self;
+ #[inline]
+ fn add(self, rhs: Self) -> Self {
+ Self(f32x4_add(self.0, rhs.0))
+ }
+}
+
+impl AddAssign<Vec4> for Vec4 {
+ #[inline]
+ fn add_assign(&mut self, rhs: Self) {
+ self.0 = f32x4_add(self.0, rhs.0);
+ }
+}
+
+impl Add<f32> for Vec4 {
+ type Output = Self;
+ #[inline]
+ fn add(self, rhs: f32) -> Self {
+ Self(f32x4_add(self.0, f32x4_splat(rhs)))
+ }
+}
+
+impl AddAssign<f32> for Vec4 {
+ #[inline]
+ fn add_assign(&mut self, rhs: f32) {
+ self.0 = f32x4_add(self.0, f32x4_splat(rhs));
+ }
+}
+
+impl Add<Vec4> for f32 {
+ type Output = Vec4;
+ #[inline]
+ fn add(self, rhs: Vec4) -> Vec4 {
+ Vec4(f32x4_add(f32x4_splat(self), rhs.0))
+ }
+}
+
+impl Sub<Vec4> for Vec4 {
+ type Output = Self;
+ #[inline]
+ fn sub(self, rhs: Self) -> Self {
+ Self(f32x4_sub(self.0, rhs.0))
+ }
+}
+
+impl SubAssign<Vec4> for Vec4 {
+ #[inline]
+ fn sub_assign(&mut self, rhs: Vec4) {
+ self.0 = f32x4_sub(self.0, rhs.0);
+ }
+}
+
+impl Sub<f32> for Vec4 {
+ type Output = Self;
+ #[inline]
+ fn sub(self, rhs: f32) -> Self {
+ Self(f32x4_sub(self.0, f32x4_splat(rhs)))
+ }
+}
+
+impl SubAssign<f32> for Vec4 {
+ #[inline]
+ fn sub_assign(&mut self, rhs: f32) {
+ self.0 = f32x4_sub(self.0, f32x4_splat(rhs))
+ }
+}
+
+impl Sub<Vec4> for f32 {
+ type Output = Vec4;
+ #[inline]
+ fn sub(self, rhs: Vec4) -> Vec4 {
+ Vec4(f32x4_sub(f32x4_splat(self), rhs.0))
+ }
+}
+
+impl Rem<Vec4> 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<Vec4> for Vec4 {
+ #[inline]
+ fn rem_assign(&mut self, rhs: Self) {
+ *self = self.rem(rhs);
+ }
+}
+
+impl Rem<f32> for Vec4 {
+ type Output = Self;
+ #[inline]
+ fn rem(self, rhs: f32) -> Self {
+ self.rem(Self::splat(rhs))
+ }
+}
+
+impl RemAssign<f32> for Vec4 {
+ #[inline]
+ fn rem_assign(&mut self, rhs: f32) {
+ *self = self.rem(Self::splat(rhs));
+ }
+}
+
+impl Rem<Vec4> 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<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ZERO, Self::add)
+ }
+}
+
+impl<'a> Sum<&'a Self> for Vec4 {
+ #[inline]
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+ }
+}
+
+impl Product for Vec4 {
+ #[inline]
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ONE, Self::mul)
+ }
+}
+
+impl<'a> Product<&'a Self> for Vec4 {
+ #[inline]
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ 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<usize> 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<usize> 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<Vec4> for v128 {
+ #[inline]
+ fn from(t: Vec4) -> Self {
+ t.0
+ }
+}
+
+impl From<v128> 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<Vec4> 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<Vec4> 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<f32>;
+ #[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::<super::DVec2>(),
+ core::mem::align_of::<super::DAffine2>()
+ );
+ const_assert_eq!(48, core::mem::size_of::<super::DAffine2>());
+ }
+
+ mod const_test_dmat2 {
+ const_assert_eq!(
+ core::mem::align_of::<super::DVec2>(),
+ core::mem::align_of::<super::DMat2>()
+ );
+ const_assert_eq!(32, core::mem::size_of::<super::DMat2>());
+ }
+
+ mod const_test_dmat3 {
+ const_assert_eq!(
+ core::mem::align_of::<f64>(),
+ core::mem::align_of::<super::DMat3>()
+ );
+ const_assert_eq!(72, core::mem::size_of::<super::DMat3>());
+ }
+
+ mod const_test_dmat4 {
+ const_assert_eq!(
+ core::mem::align_of::<super::DVec4>(),
+ core::mem::align_of::<super::DMat4>()
+ );
+ const_assert_eq!(128, core::mem::size_of::<super::DMat4>());
+ }
+
+ mod const_test_dquat {
+ #[cfg(not(target_arch = "spirv"))]
+ const_assert_eq!(
+ core::mem::align_of::<f64>(),
+ core::mem::align_of::<super::DQuat>()
+ );
+ #[cfg(target_arch = "spirv")]
+ const_assert_eq!(32, core::mem::align_of::<super::DQuat>());
+ const_assert_eq!(32, core::mem::size_of::<super::DQuat>());
+ }
+
+ mod const_test_dvec2 {
+ #[cfg(not(any(feature = "cuda", target_arch = "spirv")))]
+ const_assert_eq!(
+ core::mem::align_of::<f64>(),
+ core::mem::align_of::<super::DVec2>()
+ );
+ #[cfg(any(feature = "cuda", target_arch = "spirv"))]
+ const_assert_eq!(16, core::mem::align_of::<super::DVec2>());
+ const_assert_eq!(16, core::mem::size_of::<super::DVec2>());
+ }
+
+ mod const_test_dvec3 {
+ #[cfg(not(target_arch = "spirv"))]
+ const_assert_eq!(
+ core::mem::align_of::<f64>(),
+ core::mem::align_of::<super::DVec3>()
+ );
+ #[cfg(target_arch = "spirv")]
+ const_assert_eq!(16, core::mem::align_of::<super::DVec3>());
+ const_assert_eq!(24, core::mem::size_of::<super::DVec3>());
+ }
+
+ mod const_test_dvec4 {
+ #[cfg(not(any(feature = "cuda", target_arch = "spirv")))]
+ const_assert_eq!(
+ core::mem::align_of::<f64>(),
+ core::mem::align_of::<super::DVec4>()
+ );
+ #[cfg(any(feature = "cuda", target_arch = "spirv"))]
+ const_assert_eq!(16, core::mem::align_of::<super::DVec4>());
+ const_assert_eq!(32, core::mem::size_of::<super::DVec4>());
+ }
+}
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<DVec2>;
+ #[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<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ 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<DAffine2> 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<DMat3> for DAffine2 {
+ type Output = DMat3;
+
+ #[inline]
+ fn mul(self, rhs: DMat3) -> Self::Output {
+ DMat3::from(self) * rhs
+ }
+}
+
+impl Mul<DAffine2> 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<DVec3>;
+ #[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<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ 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<DAffine3> 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<DMat4> for DAffine3 {
+ type Output = DMat4;
+
+ #[inline]
+ fn mul(self, rhs: DMat4) -> Self::Output {
+ DMat4::from(self) * rhs
+ }
+}
+
+impl Mul<DAffine3> 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<DMat2> for DMat2 {
+ type Output = Self;
+ #[inline]
+ fn add(self, rhs: Self) -> Self::Output {
+ self.add_mat2(&rhs)
+ }
+}
+
+impl AddAssign<DMat2> for DMat2 {
+ #[inline]
+ fn add_assign(&mut self, rhs: Self) {
+ *self = self.add_mat2(&rhs);
+ }
+}
+
+impl Sub<DMat2> for DMat2 {
+ type Output = Self;
+ #[inline]
+ fn sub(self, rhs: Self) -> Self::Output {
+ self.sub_mat2(&rhs)
+ }
+}
+
+impl SubAssign<DMat2> 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<DMat2> for DMat2 {
+ type Output = Self;
+ #[inline]
+ fn mul(self, rhs: Self) -> Self::Output {
+ self.mul_mat2(&rhs)
+ }
+}
+
+impl MulAssign<DMat2> for DMat2 {
+ #[inline]
+ fn mul_assign(&mut self, rhs: Self) {
+ *self = self.mul_mat2(&rhs);
+ }
+}
+
+impl Mul<DVec2> for DMat2 {
+ type Output = DVec2;
+ #[inline]
+ fn mul(self, rhs: DVec2) -> Self::Output {
+ self.mul_vec2(rhs)
+ }
+}
+
+impl Mul<DMat2> for f64 {
+ type Output = DMat2;
+ #[inline]
+ fn mul(self, rhs: DMat2) -> Self::Output {
+ rhs.mul_scalar(self)
+ }
+}
+
+impl Mul<f64> for DMat2 {
+ type Output = Self;
+ #[inline]
+ fn mul(self, rhs: f64) -> Self::Output {
+ self.mul_scalar(rhs)
+ }
+}
+
+impl MulAssign<f64> for DMat2 {
+ #[inline]
+ fn mul_assign(&mut self, rhs: f64) {
+ *self = self.mul_scalar(rhs);
+ }
+}
+
+impl Sum<Self> for DMat2 {
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ZERO, Self::add)
+ }
+}
+
+impl<'a> Sum<&'a Self> for DMat2 {
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+ }
+}
+
+impl Product for DMat2 {
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::IDENTITY, Self::mul)
+ }
+}
+
+impl<'a> Product<&'a Self> for DMat2 {
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ 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<DMat3> for DMat3 {
+ type Output = Self;
+ #[inline]
+ fn add(self, rhs: Self) -> Self::Output {
+ self.add_mat3(&rhs)
+ }
+}
+
+impl AddAssign<DMat3> for DMat3 {
+ #[inline]
+ fn add_assign(&mut self, rhs: Self) {
+ *self = self.add_mat3(&rhs);
+ }
+}
+
+impl Sub<DMat3> for DMat3 {
+ type Output = Self;
+ #[inline]
+ fn sub(self, rhs: Self) -> Self::Output {
+ self.sub_mat3(&rhs)
+ }
+}
+
+impl SubAssign<DMat3> 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<DMat3> for DMat3 {
+ type Output = Self;
+ #[inline]
+ fn mul(self, rhs: Self) -> Self::Output {
+ self.mul_mat3(&rhs)
+ }
+}
+
+impl MulAssign<DMat3> for DMat3 {
+ #[inline]
+ fn mul_assign(&mut self, rhs: Self) {
+ *self = self.mul_mat3(&rhs);
+ }
+}
+
+impl Mul<DVec3> for DMat3 {
+ type Output = DVec3;
+ #[inline]
+ fn mul(self, rhs: DVec3) -> Self::Output {
+ self.mul_vec3(rhs)
+ }
+}
+
+impl Mul<DMat3> for f64 {
+ type Output = DMat3;
+ #[inline]
+ fn mul(self, rhs: DMat3) -> Self::Output {
+ rhs.mul_scalar(self)
+ }
+}
+
+impl Mul<f64> for DMat3 {
+ type Output = Self;
+ #[inline]
+ fn mul(self, rhs: f64) -> Self::Output {
+ self.mul_scalar(rhs)
+ }
+}
+
+impl MulAssign<f64> for DMat3 {
+ #[inline]
+ fn mul_assign(&mut self, rhs: f64) {
+ *self = self.mul_scalar(rhs);
+ }
+}
+
+impl Sum<Self> for DMat3 {
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ZERO, Self::add)
+ }
+}
+
+impl<'a> Sum<&'a Self> for DMat3 {
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+ }
+}
+
+impl Product for DMat3 {
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::IDENTITY, Self::mul)
+ }
+}
+
+impl<'a> Product<&'a Self> for DMat3 {
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ 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 <https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluPerspective.xml>
+ #[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
+ /// <https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glOrtho.xml>
+ #[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<DMat4> for DMat4 {
+ type Output = Self;
+ #[inline]
+ fn add(self, rhs: Self) -> Self::Output {
+ self.add_mat4(&rhs)
+ }
+}
+
+impl AddAssign<DMat4> for DMat4 {
+ #[inline]
+ fn add_assign(&mut self, rhs: Self) {
+ *self = self.add_mat4(&rhs);
+ }
+}
+
+impl Sub<DMat4> for DMat4 {
+ type Output = Self;
+ #[inline]
+ fn sub(self, rhs: Self) -> Self::Output {
+ self.sub_mat4(&rhs)
+ }
+}
+
+impl SubAssign<DMat4> 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<DMat4> for DMat4 {
+ type Output = Self;
+ #[inline]
+ fn mul(self, rhs: Self) -> Self::Output {
+ self.mul_mat4(&rhs)
+ }
+}
+
+impl MulAssign<DMat4> for DMat4 {
+ #[inline]
+ fn mul_assign(&mut self, rhs: Self) {
+ *self = self.mul_mat4(&rhs);
+ }
+}
+
+impl Mul<DVec4> for DMat4 {
+ type Output = DVec4;
+ #[inline]
+ fn mul(self, rhs: DVec4) -> Self::Output {
+ self.mul_vec4(rhs)
+ }
+}
+
+impl Mul<DMat4> for f64 {
+ type Output = DMat4;
+ #[inline]
+ fn mul(self, rhs: DMat4) -> Self::Output {
+ rhs.mul_scalar(self)
+ }
+}
+
+impl Mul<f64> for DMat4 {
+ type Output = Self;
+ #[inline]
+ fn mul(self, rhs: f64) -> Self::Output {
+ self.mul_scalar(rhs)
+ }
+}
+
+impl MulAssign<f64> for DMat4 {
+ #[inline]
+ fn mul_assign(&mut self, rhs: f64) {
+ *self = self.mul_scalar(rhs);
+ }
+}
+
+impl Sum<Self> for DMat4 {
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ZERO, Self::add)
+ }
+}
+
+impl<'a> Sum<&'a Self> for DMat4 {
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+ }
+}
+
+impl Product for DMat4 {
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::IDENTITY, Self::mul)
+ }
+}
+
+impl<'a> Product<&'a Self> for DMat4 {
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ 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<DQuat> 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<DQuat> 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<f64> 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<f64> 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<DQuat> 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<DQuat> 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<DVec3> 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<Self> for DQuat {
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ZERO, Self::add)
+ }
+}
+
+impl<'a> Sum<&'a Self> for DQuat {
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+ }
+}
+
+impl Product for DQuat {
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::IDENTITY, Self::mul)
+ }
+}
+
+impl<'a> Product<&'a Self> for DQuat {
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ iter.fold(Self::IDENTITY, |a, &b| Self::mul(a, b))
+ }
+}
+
+impl From<DQuat> for DVec4 {
+ #[inline]
+ fn from(q: DQuat) -> Self {
+ Self::new(q.x, q.y, q.z, q.w)
+ }
+}
+
+impl From<DQuat> for (f64, f64, f64, f64) {
+ #[inline]
+ fn from(q: DQuat) -> Self {
+ (q.x, q.y, q.z, q.w)
+ }
+}
+
+impl From<DQuat> 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<Self> {
+ 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<DVec2> 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<DVec2> for DVec2 {
+ #[inline]
+ fn div_assign(&mut self, rhs: Self) {
+ self.x.div_assign(rhs.x);
+ self.y.div_assign(rhs.y);
+ }
+}
+
+impl Div<f64> 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<f64> for DVec2 {
+ #[inline]
+ fn div_assign(&mut self, rhs: f64) {
+ self.x.div_assign(rhs);
+ self.y.div_assign(rhs);
+ }
+}
+
+impl Div<DVec2> 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<DVec2> 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<DVec2> for DVec2 {
+ #[inline]
+ fn mul_assign(&mut self, rhs: Self) {
+ self.x.mul_assign(rhs.x);
+ self.y.mul_assign(rhs.y);
+ }
+}
+
+impl Mul<f64> 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<f64> for DVec2 {
+ #[inline]
+ fn mul_assign(&mut self, rhs: f64) {
+ self.x.mul_assign(rhs);
+ self.y.mul_assign(rhs);
+ }
+}
+
+impl Mul<DVec2> 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<DVec2> 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<DVec2> for DVec2 {
+ #[inline]
+ fn add_assign(&mut self, rhs: Self) {
+ self.x.add_assign(rhs.x);
+ self.y.add_assign(rhs.y);
+ }
+}
+
+impl Add<f64> 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<f64> for DVec2 {
+ #[inline]
+ fn add_assign(&mut self, rhs: f64) {
+ self.x.add_assign(rhs);
+ self.y.add_assign(rhs);
+ }
+}
+
+impl Add<DVec2> 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<DVec2> 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<DVec2> for DVec2 {
+ #[inline]
+ fn sub_assign(&mut self, rhs: DVec2) {
+ self.x.sub_assign(rhs.x);
+ self.y.sub_assign(rhs.y);
+ }
+}
+
+impl Sub<f64> 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<f64> for DVec2 {
+ #[inline]
+ fn sub_assign(&mut self, rhs: f64) {
+ self.x.sub_assign(rhs);
+ self.y.sub_assign(rhs);
+ }
+}
+
+impl Sub<DVec2> 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<DVec2> 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<DVec2> for DVec2 {
+ #[inline]
+ fn rem_assign(&mut self, rhs: Self) {
+ self.x.rem_assign(rhs.x);
+ self.y.rem_assign(rhs.y);
+ }
+}
+
+impl Rem<f64> 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<f64> for DVec2 {
+ #[inline]
+ fn rem_assign(&mut self, rhs: f64) {
+ self.x.rem_assign(rhs);
+ self.y.rem_assign(rhs);
+ }
+}
+
+impl Rem<DVec2> 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<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ZERO, Self::add)
+ }
+}
+
+impl<'a> Sum<&'a Self> for DVec2 {
+ #[inline]
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+ }
+}
+
+impl Product for DVec2 {
+ #[inline]
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ONE, Self::mul)
+ }
+}
+
+impl<'a> Product<&'a Self> for DVec2 {
+ #[inline]
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ 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<usize> 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<usize> 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<DVec2> 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<DVec2> 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<Self> {
+ 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<DVec3> 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<DVec3> 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<f64> 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<f64> 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<DVec3> 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<DVec3> 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<DVec3> 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<f64> 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<f64> 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<DVec3> 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<DVec3> 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<DVec3> 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<f64> 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<f64> 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<DVec3> 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<DVec3> 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<DVec3> 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<f64> 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<f64> 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<DVec3> 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<DVec3> 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<DVec3> 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<f64> 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<f64> 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<DVec3> 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<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ZERO, Self::add)
+ }
+}
+
+impl<'a> Sum<&'a Self> for DVec3 {
+ #[inline]
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+ }
+}
+
+impl Product for DVec3 {
+ #[inline]
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ONE, Self::mul)
+ }
+}
+
+impl<'a> Product<&'a Self> for DVec3 {
+ #[inline]
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ 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<usize> 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<usize> 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<DVec3> 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<DVec3> 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<Self> {
+ 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<DVec4> 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<DVec4> 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<f64> 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<f64> 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<DVec4> 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<DVec4> 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<DVec4> 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<f64> 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<f64> 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<DVec4> 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<DVec4> 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<DVec4> 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<f64> 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<f64> 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<DVec4> 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<DVec4> 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<DVec4> 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<f64> 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<f64> 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<DVec4> 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<DVec4> 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<DVec4> 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<f64> 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<f64> 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<DVec4> 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<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ZERO, Self::add)
+ }
+}
+
+impl<'a> Sum<&'a Self> for DVec4 {
+ #[inline]
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+ }
+}
+
+impl Product for DVec4 {
+ #[inline]
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ONE, Self::mul)
+ }
+}
+
+impl<'a> Product<&'a Self> for DVec4 {
+ #[inline]
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ 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<usize> 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<usize> 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<DVec4> 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<DVec4> 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/mod.rs b/src/features.rs
index 6d6436d..6d6436d 100644
--- a/src/features/mod.rs
+++ b/src/features.rs
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();
@@ -711,6 +711,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 = "[]";
pub const SX1: &str = "[1.0]";
@@ -730,8 +762,185 @@ 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<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ 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<D>(deserializer: D) -> Result<Self, D::Error>
+ 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<V>(self, mut seq: V) -> Result<BVec3A, V::Error>
+ 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::<BVec3A>(SX0);
+ assert!(deserialized.is_err());
+ let deserialized = serde_json::from_str::<BVec3A>(SX1);
+ assert!(deserialized.is_err());
+ let deserialized = serde_json::from_str::<BVec3A>(SX2);
+ assert!(deserialized.is_err());
+ let deserialized = serde_json::from_str::<BVec3A>(SX4);
+ assert!(deserialized.is_err());
+ }
+
+ #[cfg(not(feature = "scalar-math"))]
+ impl Serialize for BVec4A {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ 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<D>(deserializer: D) -> Result<Self, D::Error>
+ 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<V>(self, mut seq: V) -> Result<BVec4A, V::Error>
+ 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::<BVec4A>(SX0);
+ assert!(deserialized.is_err());
+ let deserialized = serde_json::from_str::<BVec4A>(SX1);
+ assert!(deserialized.is_err());
+ let deserialized = serde_json::from_str::<BVec4A>(SX2);
+ assert!(deserialized.is_err());
+ let deserialized = serde_json::from_str::<BVec4A>(SX3);
+ assert!(deserialized.is_err());
+ let deserialized = serde_json::from_str::<BVec4A>(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};
use core::fmt;
@@ -747,6 +956,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};
use core::fmt;
@@ -762,6 +973,8 @@ mod f64 {
mod i32 {
#[cfg(test)]
+ use super::test_i32::*;
+ #[cfg(test)]
use super::test_int::*;
use crate::{IVec2, IVec3, IVec4};
use core::fmt;
@@ -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/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::<i32>(),
+ core::mem::align_of::<super::IVec2>()
+ );
+ #[cfg(feature = "cuda")]
+ const_assert_eq!(8, core::mem::align_of::<super::IVec2>());
+ const_assert_eq!(8, core::mem::size_of::<super::IVec2>());
+ }
+
+ mod const_test_ivec3 {
+ const_assert_eq!(
+ core::mem::align_of::<i32>(),
+ core::mem::align_of::<super::IVec3>()
+ );
+ const_assert_eq!(12, core::mem::size_of::<super::IVec3>());
+ }
+
+ mod const_test_ivec4 {
+ #[cfg(not(feature = "cuda"))]
+ const_assert_eq!(
+ core::mem::align_of::<i32>(),
+ core::mem::align_of::<super::IVec4>()
+ );
+ #[cfg(feature = "cuda")]
+ const_assert_eq!(16, core::mem::align_of::<super::IVec4>());
+ const_assert_eq!(16, core::mem::size_of::<super::IVec4>());
+ }
+}
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<IVec2> 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<IVec2> for IVec2 {
+ #[inline]
+ fn div_assign(&mut self, rhs: Self) {
+ self.x.div_assign(rhs.x);
+ self.y.div_assign(rhs.y);
+ }
+}
+
+impl Div<i32> 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<i32> for IVec2 {
+ #[inline]
+ fn div_assign(&mut self, rhs: i32) {
+ self.x.div_assign(rhs);
+ self.y.div_assign(rhs);
+ }
+}
+
+impl Div<IVec2> 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<IVec2> 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<IVec2> for IVec2 {
+ #[inline]
+ fn mul_assign(&mut self, rhs: Self) {
+ self.x.mul_assign(rhs.x);
+ self.y.mul_assign(rhs.y);
+ }
+}
+
+impl Mul<i32> 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<i32> for IVec2 {
+ #[inline]
+ fn mul_assign(&mut self, rhs: i32) {
+ self.x.mul_assign(rhs);
+ self.y.mul_assign(rhs);
+ }
+}
+
+impl Mul<IVec2> 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<IVec2> 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<IVec2> for IVec2 {
+ #[inline]
+ fn add_assign(&mut self, rhs: Self) {
+ self.x.add_assign(rhs.x);
+ self.y.add_assign(rhs.y);
+ }
+}
+
+impl Add<i32> 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<i32> for IVec2 {
+ #[inline]
+ fn add_assign(&mut self, rhs: i32) {
+ self.x.add_assign(rhs);
+ self.y.add_assign(rhs);
+ }
+}
+
+impl Add<IVec2> 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<IVec2> 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<IVec2> for IVec2 {
+ #[inline]
+ fn sub_assign(&mut self, rhs: IVec2) {
+ self.x.sub_assign(rhs.x);
+ self.y.sub_assign(rhs.y);
+ }
+}
+
+impl Sub<i32> 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<i32> for IVec2 {
+ #[inline]
+ fn sub_assign(&mut self, rhs: i32) {
+ self.x.sub_assign(rhs);
+ self.y.sub_assign(rhs);
+ }
+}
+
+impl Sub<IVec2> 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<IVec2> 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<IVec2> for IVec2 {
+ #[inline]
+ fn rem_assign(&mut self, rhs: Self) {
+ self.x.rem_assign(rhs.x);
+ self.y.rem_assign(rhs.y);
+ }
+}
+
+impl Rem<i32> 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<i32> for IVec2 {
+ #[inline]
+ fn rem_assign(&mut self, rhs: i32) {
+ self.x.rem_assign(rhs);
+ self.y.rem_assign(rhs);
+ }
+}
+
+impl Rem<IVec2> 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<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ZERO, Self::add)
+ }
+}
+
+impl<'a> Sum<&'a Self> for IVec2 {
+ #[inline]
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+ }
+}
+
+impl Product for IVec2 {
+ #[inline]
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ONE, Self::mul)
+ }
+}
+
+impl<'a> Product<&'a Self> for IVec2 {
+ #[inline]
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ 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<i32> 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<i32> 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<i32> 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<i8> 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<i8> 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<i16> 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<i16> 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<i32> 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<i32> 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<u8> 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<u8> 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<u16> 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<u16> 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<u32> 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<u32> 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<crate::IVec2> 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<crate::IVec2> 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<crate::UVec2> 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<crate::UVec2> 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<usize> 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<usize> 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<IVec2> 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<IVec2> 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<IVec3> 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<IVec3> 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<i32> 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<i32> 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<IVec3> 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<IVec3> 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<IVec3> 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<i32> 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<i32> 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<IVec3> 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<IVec3> 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<IVec3> 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<i32> 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<i32> 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<IVec3> 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<IVec3> 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<IVec3> 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<i32> 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<i32> 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<IVec3> 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<IVec3> 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<IVec3> 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<i32> 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<i32> 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<IVec3> 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<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ZERO, Self::add)
+ }
+}
+
+impl<'a> Sum<&'a Self> for IVec3 {
+ #[inline]
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+ }
+}
+
+impl Product for IVec3 {
+ #[inline]
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ONE, Self::mul)
+ }
+}
+
+impl<'a> Product<&'a Self> for IVec3 {
+ #[inline]
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ 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<i32> 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<i32> 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<i32> 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<i8> 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<i8> 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<i16> 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<i16> 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<i32> 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<i32> 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<u8> 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<u8> 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<u16> 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<u16> 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<u32> 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<u32> 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<crate::IVec3> 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<crate::IVec3> 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<crate::UVec3> 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<crate::UVec3> 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<usize> 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<usize> 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<IVec3> 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<IVec3> 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<IVec4> 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<IVec4> 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<i32> 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<i32> 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<IVec4> 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<IVec4> 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<IVec4> 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<i32> 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<i32> 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<IVec4> 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<IVec4> 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<IVec4> 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<i32> 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<i32> 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<IVec4> 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<IVec4> 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<IVec4> 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<i32> 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<i32> 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<IVec4> 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<IVec4> 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<IVec4> 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<i32> 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<i32> 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<IVec4> 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<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ZERO, Self::add)
+ }
+}
+
+impl<'a> Sum<&'a Self> for IVec4 {
+ #[inline]
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+ }
+}
+
+impl Product for IVec4 {
+ #[inline]
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ONE, Self::mul)
+ }
+}
+
+impl<'a> Product<&'a Self> for IVec4 {
+ #[inline]
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ 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<i32> 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<i32> 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<i32> 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<i8> 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<i8> 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<i16> 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<i16> 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<i32> 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<i32> 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<u8> 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<u8> 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<u16> 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<u16> 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<u32> 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<u32> 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<crate::IVec4> 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<crate::IVec4> 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<crate::UVec4> 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<crate::UVec4> 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<usize> 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<usize> 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<IVec4> 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<IVec4> 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<I>(iter: I) -> Self
- where
- I: Iterator<Item = &'a Self>,
- {
- iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
- }
- }
-
- impl<'a> Product<&'a Self> for $matn {
- fn product<I>(iter: I) -> Self
- where
- I: Iterator<Item = &'a Self>,
- {
- 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<XY<f32>>;
-
-/// 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<XY<f64>>;
-
-/// 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::<super::Vec2>(),
- core::mem::align_of::<super::Mat2>()
- );
- #[cfg(not(any(feature = "scalar-math", target_arch = "spirv")))]
- const_assert_eq!(16, core::mem::align_of::<super::Mat2>());
- const_assert_eq!(16, core::mem::size_of::<super::Mat2>());
-}
-
-mod const_test_dmat2 {
- const_assert_eq!(
- core::mem::align_of::<super::DVec2>(),
- core::mem::align_of::<super::DMat2>()
- );
- const_assert_eq!(32, core::mem::size_of::<super::DMat2>());
-}
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<XYZ<f32>>;
-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<Vec3A> 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<v128>;
-
-#[cfg(any(
- not(any(target_feature = "sse2", target_feature = "simd128")),
- feature = "scalar-math"
-))]
-type InnerF32A = Columns3<crate::core::storage::XYZF32A16>;
-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<Vec3> for Mat3A {
- type Output = Vec3;
- #[inline(always)]
- fn mul(self, other: Vec3) -> Vec3 {
- self.mul_vec3(other)
- }
-}
-
-impl From<Mat3> for Mat3A {
- #[inline(always)]
- fn from(m: Mat3) -> Self {
- Self(m.0.into())
- }
-}
-
-impl From<Mat3A> for Mat3 {
- #[inline(always)]
- fn from(m: Mat3A) -> Self {
- Self(m.0.into())
- }
-}
-
-type InnerF64 = Columns3<XYZ<f64>>;
-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::<f32>(),
- core::mem::align_of::<super::Mat3>()
- );
- const_assert_eq!(36, core::mem::size_of::<super::Mat3>());
-}
-
-mod const_test_mat3a {
- const_assert_eq!(16, core::mem::align_of::<super::Mat3A>());
- const_assert_eq!(48, core::mem::size_of::<super::Mat3A>());
-}
-
-mod const_test_dmat3 {
- const_assert_eq!(
- core::mem::align_of::<f64>(),
- core::mem::align_of::<super::DMat3>()
- );
- const_assert_eq!(72, core::mem::size_of::<super::DMat3>());
-}
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 <https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluPerspective.xml>
- #[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
- /// <https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glOrtho.xml>
- #[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<v128>;
-
-#[cfg(any(
- not(any(target_feature = "sse2", target_feature = "simd128")),
- feature = "scalar-math"
-))]
-type InnerF32 = Columns4<XYZW<f32>>;
-
-/// 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<XYZW<f64>>;
-
-/// 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::<super::Vec4>(),
- core::mem::align_of::<super::Mat4>()
- );
- const_assert_eq!(64, core::mem::size_of::<super::Mat4>());
-}
-
-mod const_test_dmat4 {
- const_assert_eq!(
- core::mem::align_of::<super::DVec4>(),
- core::mem::align_of::<super::DMat4>()
- );
- const_assert_eq!(128, core::mem::size_of::<super::DMat4>());
-}
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<I>(iter: I) -> Self
- where
- I: Iterator<Item = &'a Self>,
- {
- 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<I>(iter: I) -> Self
- where
- I: Iterator<Item = &'a Self>,
- {
- 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<f32>;
-
-/// 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<Vec3A> for Quat {
- type Output = Vec3A;
- #[inline(always)]
- fn mul(self, other: Vec3A) -> Self::Output {
- self.mul_vec3a(other)
- }
-}
-
-type InnerF64 = crate::XYZW<f64>;
-
-/// 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::<f32>(),
- core::mem::align_of::<super::Quat>()
- );
- const_assert_eq!(16, core::mem::size_of::<super::Quat>());
-}
-
-#[cfg(not(any(feature = "scalar-math", target_arch = "spirv")))]
-mod const_test_quat {
- const_assert_eq!(16, core::mem::align_of::<super::Quat>());
- const_assert_eq!(16, core::mem::size_of::<super::Quat>());
-}
-
-mod const_test_dquat {
- const_assert_eq!(
- core::mem::align_of::<f64>(),
- core::mem::align_of::<super::DQuat>()
- );
- const_assert_eq!(32, core::mem::size_of::<super::DQuat>());
-}
diff --git a/src/core/sse2/float.rs b/src/sse2.rs
index 9c3ac8e..e1e6b74 100644
--- a/src/core/sse2/float.rs
+++ b/src/sse2.rs
@@ -3,47 +3,78 @@ 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 }
- };
+union UnionCast {
+ u32x4: [u32; 4],
+ f32x4: [f32; 4],
+ m128: __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]);
+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 =
- const_f32x4!([-0.16666667, 0.008_333_331, -0.00019840874, 2.752_556_2e-6]);
-const PS_SIN_COEFFICIENTS1: __m128 = const_f32x4!([
+ 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*/
+ -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]);
+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 m128_abs(v: __m128) -> __m128 {
- _mm_and_ps(v, _mm_castsi128_ps(_mm_set1_epi32(0x7f_ff_ff_ff)))
+pub(crate) unsafe fn dot3(lhs: __m128, rhs: __m128) -> f32 {
+ _mm_cvtss_f32(dot3_in_x(lhs, rhs))
}
#[inline]
-pub(crate) unsafe fn m128_round(v: __m128) -> __m128 {
- // Based on https://github.com/microsoft/DirectXMath `XMVectorRound`
- let sign = _mm_and_ps(v, PS_SIGN_MASK);
- let s_magic = _mm_or_ps(PS_NO_FRACTION, sign);
- let r1 = _mm_add_ps(v, s_magic);
- let r1 = _mm_sub_ps(r1, s_magic);
- let r2 = _mm_and_ps(v, PS_INV_SIGN_MASK);
- let mask = _mm_cmple_ps(r2, PS_NO_FRACTION);
- let r2 = _mm_andnot_ps(mask, v);
- let r1 = _mm_and_ps(r1, mask);
- _mm_xor_ps(r1, r2)
+pub(crate) unsafe fn dot3_into_m128(lhs: __m128, rhs: __m128) -> __m128 {
+ let dot_in_x = dot3_in_x(lhs, rhs);
+ _mm_shuffle_ps(dot_in_x, dot_in_x, 0b00_00_00_00)
+}
+
+#[inline]
+pub(crate) unsafe fn dot4(lhs: __m128, rhs: __m128) -> f32 {
+ _mm_cvtss_f32(dot4_in_x(lhs, rhs))
+}
+
+#[inline]
+pub(crate) unsafe fn dot4_into_m128(lhs: __m128, rhs: __m128) -> __m128 {
+ let dot_in_x = dot4_in_x(lhs, rhs);
+ _mm_shuffle_ps(dot_in_x, dot_in_x, 0b00_00_00_00)
}
#[inline]
@@ -86,6 +117,11 @@ pub(crate) unsafe fn m128_ceil(v: __m128) -> __m128 {
_mm_or_ps(result, _mm_castsi128_ps(test))
}
+#[inline]
+pub(crate) unsafe fn m128_abs(v: __m128) -> __m128 {
+ _mm_and_ps(v, _mm_castsi128_ps(_mm_set1_epi32(0x7f_ff_ff_ff)))
+}
+
#[inline(always)]
pub(crate) unsafe fn m128_mul_add(a: __m128, b: __m128, c: __m128) -> __m128 {
// Only enable fused multiply-adds here if "fast-math" is enabled and the
@@ -106,6 +142,20 @@ pub(crate) unsafe fn m128_neg_mul_sub(a: __m128, b: __m128, c: __m128) -> __m128
_mm_sub_ps(c, _mm_mul_ps(a, b))
}
+#[inline]
+pub(crate) unsafe fn m128_round(v: __m128) -> __m128 {
+ // Based on https://github.com/microsoft/DirectXMath `XMVectorRound`
+ let sign = _mm_and_ps(v, PS_SIGN_MASK);
+ let s_magic = _mm_or_ps(PS_NO_FRACTION, sign);
+ let r1 = _mm_add_ps(v, s_magic);
+ let r1 = _mm_sub_ps(r1, s_magic);
+ let r2 = _mm_and_ps(v, PS_INV_SIGN_MASK);
+ let mask = _mm_cmple_ps(r2, PS_NO_FRACTION);
+ let r2 = _mm_andnot_ps(mask, v);
+ let r1 = _mm_and_ps(r1, mask);
+ _mm_xor_ps(r1, r2)
+}
+
/// Returns a vector whose components are the corresponding components of Angles modulo 2PI.
#[inline]
pub(crate) unsafe fn m128_mod_angles(angles: __m128) -> __m128 {
@@ -164,109 +214,17 @@ pub(crate) unsafe fn m128_sin(v: __m128) -> __m128 {
result
}
-// Based on http://gruntthepeon.free.fr/ssemath/sse_mathfun.h
-// #[cfg(target_feature = "sse2")]
-// unsafe fn sin_cos_sse2(x: __m128) -> (__m128, __m128) {
-// let mut sign_bit_sin = x;
-// // take the absolute value
-// let mut x = _mm_and_ps(x, PS_INV_SIGN_MASK.m128);
-// // extract the sign bit (upper one)
-// sign_bit_sin = _mm_and_ps(sign_bit_sin, PS_SIGN_MASK.m128);
-
-// // scale by 4/Pi
-// let mut y = _mm_mul_ps(x, PS_CEPHES_FOPI.m128);
-
-// // store the integer part of y in emm2
-// let mut emm2 = _mm_cvttps_epi32(y);
-
-// // j=(j+1) & (~1) (see the cephes sources)
-// emm2 = _mm_add_epi32(emm2, PI32_1.m128i);
-// emm2 = _mm_and_si128(emm2, PI32_INV_1.m128i);
-// y = _mm_cvtepi32_ps(emm2);
-
-// let mut emm4 = emm2;
-
-// /* get the swap sign flag for the sine */
-// let mut emm0 = _mm_and_si128(emm2, PI32_4.m128i);
-// emm0 = _mm_slli_epi32(emm0, 29);
-// let swap_sign_bit_sin = _mm_castsi128_ps(emm0);
-
-// /* get the polynom selection mask for the sine*/
-// emm2 = _mm_and_si128(emm2, PI32_2.m128i);
-// emm2 = _mm_cmpeq_epi32(emm2, _mm_setzero_si128());
-// let poly_mask = _mm_castsi128_ps(emm2);
-
-// /* The magic pass: "Extended precision modular arithmetic"
-// x = ((x - y * DP1) - y * DP2) - y * DP3; */
-// let mut xmm1 = PS_MINUS_CEPHES_DP1.m128;
-// let mut xmm2 = PS_MINUS_CEPHES_DP2.m128;
-// let mut xmm3 = PS_MINUS_CEPHES_DP3.m128;
-// xmm1 = _mm_mul_ps(y, xmm1);
-// xmm2 = _mm_mul_ps(y, xmm2);
-// xmm3 = _mm_mul_ps(y, xmm3);
-// x = _mm_add_ps(x, xmm1);
-// x = _mm_add_ps(x, xmm2);
-// x = _mm_add_ps(x, xmm3);
-
-// emm4 = _mm_sub_epi32(emm4, PI32_2.m128i);
-// emm4 = _mm_andnot_si128(emm4, PI32_4.m128i);
-// emm4 = _mm_slli_epi32(emm4, 29);
-// let sign_bit_cos = _mm_castsi128_ps(emm4);
-
-// sign_bit_sin = _mm_xor_ps(sign_bit_sin, swap_sign_bit_sin);
-
-// // Evaluate the first polynom (0 <= x <= Pi/4)
-// let z = _mm_mul_ps(x, x);
-// y = PS_COSCOF_P0.m128;
-
-// y = _mm_mul_ps(y, z);
-// y = _mm_add_ps(y, PS_COSCOF_P1.m128);
-// y = _mm_mul_ps(y, z);
-// y = _mm_add_ps(y, PS_COSCOF_P2.m128);
-// y = _mm_mul_ps(y, z);
-// y = _mm_mul_ps(y, z);
-// let tmp = _mm_mul_ps(z, PS_0_5.m128);
-// y = _mm_sub_ps(y, tmp);
-// y = _mm_add_ps(y, PS_1_0.m128);
-
-// // Evaluate the second polynom (Pi/4 <= x <= 0)
-// let mut y2 = PS_SINCOF_P0.m128;
-// y2 = _mm_mul_ps(y2, z);
-// y2 = _mm_add_ps(y2, PS_SINCOF_P1.m128);
-// y2 = _mm_mul_ps(y2, z);
-// y2 = _mm_add_ps(y2, PS_SINCOF_P2.m128);
-// y2 = _mm_mul_ps(y2, z);
-// y2 = _mm_mul_ps(y2, x);
-// y2 = _mm_add_ps(y2, x);
-
-// // select the correct result from the two polynoms
-// xmm3 = poly_mask;
-// let ysin2 = _mm_and_ps(xmm3, y2);
-// let ysin1 = _mm_andnot_ps(xmm3, y);
-// y2 = _mm_sub_ps(y2, ysin2);
-// y = _mm_sub_ps(y, ysin1);
-
-// xmm1 = _mm_add_ps(ysin1, ysin2);
-// xmm2 = _mm_add_ps(y, y2);
-
-// // update the sign
-// (
-// _mm_xor_ps(xmm1, sign_bit_sin),
-// _mm_xor_ps(xmm2, sign_bit_cos),
-// )
-// }
-
#[test]
fn test_sse2_m128_sin() {
- use crate::core::traits::vector::*;
+ use crate::Vec4;
use core::f32::consts::PI;
fn test_sse2_m128_sin_angle(a: f32) {
let v = unsafe { m128_sin(_mm_set_ps1(a)) };
- let v = v.as_ref_xyzw();
+ let v = Vec4(v);
let a_sin = a.sin();
// dbg!((a, a_sin, v));
- assert!(v.abs_diff_eq(Vector::splat(a_sin), 1e-6));
+ assert!(v.abs_diff_eq(Vec4::splat(a_sin), 1e-6));
}
let mut a = -PI;
diff --git a/src/swizzles.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_scalar.rs b/src/swizzles/dvec2_impl.rs
index 1cb65e9..dbf6dc3 100644
--- a/src/swizzles/dvec2_impl_scalar.rs
+++ b/src/swizzles/dvec2_impl.rs
@@ -1,118 +1,193 @@
-// Generated by swizzlegen. Do not edit.
+// Generated from swizzle_impl.rs.tera template. Edit the template, not the generated file.
-use super::Vec2Swizzles;
-use crate::{DVec2, DVec3, DVec4};
+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)
}
- #[inline]
- fn xxx(self) -> DVec3 {
- DVec3::new(self.x, self.x, self.x)
- }
- #[inline]
- fn xxy(self) -> DVec3 {
- DVec3::new(self.x, self.x, self.y)
- }
- #[inline]
- fn xyx(self) -> DVec3 {
- DVec3::new(self.x, self.y, self.x)
- }
- #[inline]
- fn xyy(self) -> DVec3 {
- DVec3::new(self.x, self.y, self.y)
- }
- #[inline]
- fn yxx(self) -> DVec3 {
- DVec3::new(self.y, self.x, self.x)
- }
- #[inline]
- fn yxy(self) -> DVec3 {
- DVec3::new(self.y, self.x, self.y)
- }
- #[inline]
- fn yyx(self) -> DVec3 {
- DVec3::new(self.y, self.y, self.x)
- }
- #[inline]
- fn yyy(self) -> DVec3 {
- DVec3::new(self.y, self.y, self.y)
- }
- #[inline]
- fn xx(self) -> Self {
- Self::new(self.x, self.x)
- }
- #[inline]
- fn yx(self) -> Self {
- Self::new(self.y, self.x)
- }
- #[inline]
- fn yy(self) -> Self {
- Self::new(self.y, self.y)
- }
}
diff --git a/src/swizzles/dvec3_impl_scalar.rs b/src/swizzles/dvec3_impl.rs
index 53fab09..0ea0cd4 100644
--- a/src/swizzles/dvec3_impl_scalar.rs
+++ b/src/swizzles/dvec3_impl.rs
@@ -1,474 +1,729 @@
-// Generated by swizzlegen. Do not edit.
+// Generated from swizzle_impl.rs.tera template. Edit the template, not the generated file.
-use super::Vec3Swizzles;
-use crate::{DVec2, DVec3, DVec4};
+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)
}
- #[inline]
- fn xxx(self) -> Self {
- Self::new(self.x, self.x, self.x)
- }
- #[inline]
- fn xxy(self) -> Self {
- Self::new(self.x, self.x, self.y)
- }
- #[inline]
- fn xxz(self) -> Self {
- Self::new(self.x, self.x, self.z)
- }
- #[inline]
- fn xyx(self) -> Self {
- Self::new(self.x, self.y, self.x)
- }
- #[inline]
- fn xyy(self) -> Self {
- Self::new(self.x, self.y, self.y)
- }
- #[inline]
- fn xzx(self) -> Self {
- Self::new(self.x, self.z, self.x)
- }
- #[inline]
- fn xzy(self) -> Self {
- Self::new(self.x, self.z, self.y)
- }
- #[inline]
- fn xzz(self) -> Self {
- Self::new(self.x, self.z, self.z)
- }
- #[inline]
- fn yxx(self) -> Self {
- Self::new(self.y, self.x, self.x)
- }
- #[inline]
- fn yxy(self) -> Self {
- Self::new(self.y, self.x, self.y)
- }
- #[inline]
- fn yxz(self) -> Self {
- Self::new(self.y, self.x, self.z)
- }
- #[inline]
- fn yyx(self) -> Self {
- Self::new(self.y, self.y, self.x)
- }
- #[inline]
- fn yyy(self) -> Self {
- Self::new(self.y, self.y, self.y)
- }
- #[inline]
- fn yyz(self) -> Self {
- Self::new(self.y, self.y, self.z)
- }
- #[inline]
- fn yzx(self) -> Self {
- Self::new(self.y, self.z, self.x)
- }
- #[inline]
- fn yzy(self) -> Self {
- Self::new(self.y, self.z, self.y)
- }
- #[inline]
- fn yzz(self) -> Self {
- Self::new(self.y, self.z, self.z)
- }
- #[inline]
- fn zxx(self) -> Self {
- Self::new(self.z, self.x, self.x)
- }
- #[inline]
- fn zxy(self) -> Self {
- Self::new(self.z, self.x, self.y)
- }
- #[inline]
- fn zxz(self) -> Self {
- Self::new(self.z, self.x, self.z)
- }
- #[inline]
- fn zyx(self) -> Self {
- Self::new(self.z, self.y, self.x)
- }
- #[inline]
- fn zyy(self) -> Self {
- Self::new(self.z, self.y, self.y)
- }
- #[inline]
- fn zyz(self) -> Self {
- Self::new(self.z, self.y, self.z)
- }
- #[inline]
- fn zzx(self) -> Self {
- Self::new(self.z, self.z, self.x)
- }
- #[inline]
- fn zzy(self) -> Self {
- Self::new(self.z, self.z, self.y)
- }
- #[inline]
- fn zzz(self) -> Self {
- Self::new(self.z, self.z, self.z)
- }
- #[inline]
- fn xx(self) -> DVec2 {
- DVec2::new(self.x, self.x)
- }
- #[inline]
- fn xy(self) -> DVec2 {
- DVec2::new(self.x, self.y)
- }
- #[inline]
- fn xz(self) -> DVec2 {
- DVec2::new(self.x, self.z)
- }
- #[inline]
- fn yx(self) -> DVec2 {
- DVec2::new(self.y, self.x)
- }
- #[inline]
- fn yy(self) -> DVec2 {
- DVec2::new(self.y, self.y)
- }
- #[inline]
- fn yz(self) -> DVec2 {
- DVec2::new(self.y, self.z)
- }
- #[inline]
- fn zx(self) -> DVec2 {
- DVec2::new(self.z, self.x)
- }
- #[inline]
- fn zy(self) -> DVec2 {
- DVec2::new(self.z, self.y)
- }
- #[inline]
- fn zz(self) -> DVec2 {
- DVec2::new(self.z, self.z)
- }
}
diff --git a/src/swizzles/dvec4_impl_scalar.rs b/src/swizzles/dvec4_impl.rs
index 4b6740b..b791ad5 100644
--- a/src/swizzles/dvec4_impl_scalar.rs
+++ b/src/swizzles/dvec4_impl.rs
@@ -1,1350 +1,1993 @@
-// Generated by swizzlegen. Do not edit.
+// Generated from swizzle_impl.rs.tera template. Edit the template, not the generated file.
-use super::Vec4Swizzles;
-use crate::{DVec2, DVec3, DVec4};
+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)
}
- #[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_scalar.rs b/src/swizzles/ivec2_impl.rs
index 26702c8..701b72c 100644
--- a/src/swizzles/ivec2_impl_scalar.rs
+++ b/src/swizzles/ivec2_impl.rs
@@ -1,118 +1,193 @@
-// Generated by swizzlegen. Do not edit.
+// Generated from swizzle_impl.rs.tera template. Edit the template, not the generated file.
-use super::Vec2Swizzles;
-use crate::{IVec2, IVec3, IVec4};
+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)
}
- #[inline]
- fn xxx(self) -> IVec3 {
- IVec3::new(self.x, self.x, self.x)
- }
- #[inline]
- fn xxy(self) -> IVec3 {
- IVec3::new(self.x, self.x, self.y)
- }
- #[inline]
- fn xyx(self) -> IVec3 {
- IVec3::new(self.x, self.y, self.x)
- }
- #[inline]
- fn xyy(self) -> IVec3 {
- IVec3::new(self.x, self.y, self.y)
- }
- #[inline]
- fn yxx(self) -> IVec3 {
- IVec3::new(self.y, self.x, self.x)
- }
- #[inline]
- fn yxy(self) -> IVec3 {
- IVec3::new(self.y, self.x, self.y)
- }
- #[inline]
- fn yyx(self) -> IVec3 {
- IVec3::new(self.y, self.y, self.x)
- }
- #[inline]
- fn yyy(self) -> IVec3 {
- IVec3::new(self.y, self.y, self.y)
- }
- #[inline]
- fn xx(self) -> Self {
- Self::new(self.x, self.x)
- }
- #[inline]
- fn yx(self) -> Self {
- Self::new(self.y, self.x)
- }
- #[inline]
- fn yy(self) -> Self {
- Self::new(self.y, self.y)
- }
}
diff --git a/src/swizzles/ivec3_impl_scalar.rs b/src/swizzles/ivec3_impl.rs
index 799e5d8..03d5f43 100644
--- a/src/swizzles/ivec3_impl_scalar.rs
+++ b/src/swizzles/ivec3_impl.rs
@@ -1,474 +1,729 @@
-// Generated by swizzlegen. Do not edit.
+// Generated from swizzle_impl.rs.tera template. Edit the template, not the generated file.
-use super::Vec3Swizzles;
-use crate::{IVec2, IVec3, IVec4};
+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)
}
- #[inline]
- fn xxx(self) -> Self {
- Self::new(self.x, self.x, self.x)
- }
- #[inline]
- fn xxy(self) -> Self {
- Self::new(self.x, self.x, self.y)
- }
- #[inline]
- fn xxz(self) -> Self {
- Self::new(self.x, self.x, self.z)
- }
- #[inline]
- fn xyx(self) -> Self {
- Self::new(self.x, self.y, self.x)
- }
- #[inline]
- fn xyy(self) -> Self {
- Self::new(self.x, self.y, self.y)
- }
- #[inline]
- fn xzx(self) -> Self {
- Self::new(self.x, self.z, self.x)
- }
- #[inline]
- fn xzy(self) -> Self {
- Self::new(self.x, self.z, self.y)
- }
- #[inline]
- fn xzz(self) -> Self {
- Self::new(self.x, self.z, self.z)
- }
- #[inline]
- fn yxx(self) -> Self {
- Self::new(self.y, self.x, self.x)
- }
- #[inline]
- fn yxy(self) -> Self {
- Self::new(self.y, self.x, self.y)
- }
- #[inline]
- fn yxz(self) -> Self {
- Self::new(self.y, self.x, self.z)
- }
- #[inline]
- fn yyx(self) -> Self {
- Self::new(self.y, self.y, self.x)
- }
- #[inline]
- fn yyy(self) -> Self {
- Self::new(self.y, self.y, self.y)
- }
- #[inline]
- fn yyz(self) -> Self {
- Self::new(self.y, self.y, self.z)
- }
- #[inline]
- fn yzx(self) -> Self {
- Self::new(self.y, self.z, self.x)
- }
- #[inline]
- fn yzy(self) -> Self {
- Self::new(self.y, self.z, self.y)
- }
- #[inline]
- fn yzz(self) -> Self {
- Self::new(self.y, self.z, self.z)
- }
- #[inline]
- fn zxx(self) -> Self {
- Self::new(self.z, self.x, self.x)
- }
- #[inline]
- fn zxy(self) -> Self {
- Self::new(self.z, self.x, self.y)
- }
- #[inline]
- fn zxz(self) -> Self {
- Self::new(self.z, self.x, self.z)
- }
- #[inline]
- fn zyx(self) -> Self {
- Self::new(self.z, self.y, self.x)
- }
- #[inline]
- fn zyy(self) -> Self {
- Self::new(self.z, self.y, self.y)
- }
- #[inline]
- fn zyz(self) -> Self {
- Self::new(self.z, self.y, self.z)
- }
- #[inline]
- fn zzx(self) -> Self {
- Self::new(self.z, self.z, self.x)
- }
- #[inline]
- fn zzy(self) -> Self {
- Self::new(self.z, self.z, self.y)
- }
- #[inline]
- fn zzz(self) -> Self {
- Self::new(self.z, self.z, self.z)
- }
- #[inline]
- fn xx(self) -> IVec2 {
- IVec2::new(self.x, self.x)
- }
- #[inline]
- fn xy(self) -> IVec2 {
- IVec2::new(self.x, self.y)
- }
- #[inline]
- fn xz(self) -> IVec2 {
- IVec2::new(self.x, self.z)
- }
- #[inline]
- fn yx(self) -> IVec2 {
- IVec2::new(self.y, self.x)
- }
- #[inline]
- fn yy(self) -> IVec2 {
- IVec2::new(self.y, self.y)
- }
- #[inline]
- fn yz(self) -> IVec2 {
- IVec2::new(self.y, self.z)
- }
- #[inline]
- fn zx(self) -> IVec2 {
- IVec2::new(self.z, self.x)
- }
- #[inline]
- fn zy(self) -> IVec2 {
- IVec2::new(self.z, self.y)
- }
- #[inline]
- fn zz(self) -> IVec2 {
- IVec2::new(self.z, self.z)
- }
}
diff --git a/src/swizzles/ivec4_impl_scalar.rs b/src/swizzles/ivec4_impl.rs
index a4985af..c2845e8 100644
--- a/src/swizzles/ivec4_impl_scalar.rs
+++ b/src/swizzles/ivec4_impl.rs
@@ -1,1350 +1,1993 @@
-// Generated by swizzlegen. Do not edit.
+// Generated from swizzle_impl.rs.tera template. Edit the template, not the generated file.
-use super::Vec4Swizzles;
-use crate::{IVec2, IVec3, IVec4};
+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)
}
- #[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/vec3a_impl_scalar.rs b/src/swizzles/scalar/vec3a_impl.rs
index a1aaac3..8ac0a41 100644
--- a/src/swizzles/vec3a_impl_scalar.rs
+++ b/src/swizzles/scalar/vec3a_impl.rs
@@ -1,474 +1,729 @@
-// Generated by swizzlegen. Do not edit.
+// Generated from swizzle_impl.rs.tera template. Edit the template, not the generated file.
-use super::Vec3Swizzles;
-use crate::{Vec2, Vec3A, Vec4};
+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)
}
- #[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/vec4_impl_scalar.rs b/src/swizzles/scalar/vec4_impl.rs
index 19f97a7..03a8e6c 100644
--- a/src/swizzles/vec4_impl_scalar.rs
+++ b/src/swizzles/scalar/vec4_impl.rs
@@ -1,1350 +1,1993 @@
-// Generated by swizzlegen. Do not edit.
+// Generated from swizzle_impl.rs.tera template. Edit the template, not the generated file.
-use super::Vec4Swizzles;
-use crate::{Vec2, Vec3, Vec4};
+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)
}
- #[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/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_scalar.rs b/src/swizzles/uvec2_impl.rs
index 60ba857..16ddf21 100644
--- a/src/swizzles/uvec2_impl_scalar.rs
+++ b/src/swizzles/uvec2_impl.rs
@@ -1,118 +1,193 @@
-// Generated by swizzlegen. Do not edit.
+// Generated from swizzle_impl.rs.tera template. Edit the template, not the generated file.
-use super::Vec2Swizzles;
-use crate::{UVec2, UVec3, UVec4};
+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)
}
- #[inline]
- fn xxx(self) -> UVec3 {
- UVec3::new(self.x, self.x, self.x)
- }
- #[inline]
- fn xxy(self) -> UVec3 {
- UVec3::new(self.x, self.x, self.y)
- }
- #[inline]
- fn xyx(self) -> UVec3 {
- UVec3::new(self.x, self.y, self.x)
- }
- #[inline]
- fn xyy(self) -> UVec3 {
- UVec3::new(self.x, self.y, self.y)
- }
- #[inline]
- fn yxx(self) -> UVec3 {
- UVec3::new(self.y, self.x, self.x)
- }
- #[inline]
- fn yxy(self) -> UVec3 {
- UVec3::new(self.y, self.x, self.y)
- }
- #[inline]
- fn yyx(self) -> UVec3 {
- UVec3::new(self.y, self.y, self.x)
- }
- #[inline]
- fn yyy(self) -> UVec3 {
- UVec3::new(self.y, self.y, self.y)
- }
- #[inline]
- fn xx(self) -> Self {
- Self::new(self.x, self.x)
- }
- #[inline]
- fn yx(self) -> Self {
- Self::new(self.y, self.x)
- }
- #[inline]
- fn yy(self) -> Self {
- Self::new(self.y, self.y)
- }
}
diff --git a/src/swizzles/uvec3_impl_scalar.rs b/src/swizzles/uvec3_impl.rs
index 5158e07..75afb5c 100644
--- a/src/swizzles/uvec3_impl_scalar.rs
+++ b/src/swizzles/uvec3_impl.rs
@@ -1,474 +1,729 @@
-// Generated by swizzlegen. Do not edit.
+// Generated from swizzle_impl.rs.tera template. Edit the template, not the generated file.
-use super::Vec3Swizzles;
-use crate::{UVec2, UVec3, UVec4};
+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)
}
- #[inline]
- fn xxx(self) -> Self {
- Self::new(self.x, self.x, self.x)
- }
- #[inline]
- fn xxy(self) -> Self {
- Self::new(self.x, self.x, self.y)
- }
- #[inline]
- fn xxz(self) -> Self {
- Self::new(self.x, self.x, self.z)
- }
- #[inline]
- fn xyx(self) -> Self {
- Self::new(self.x, self.y, self.x)
- }
- #[inline]
- fn xyy(self) -> Self {
- Self::new(self.x, self.y, self.y)
- }
- #[inline]
- fn xzx(self) -> Self {
- Self::new(self.x, self.z, self.x)
- }
- #[inline]
- fn xzy(self) -> Self {
- Self::new(self.x, self.z, self.y)
- }
- #[inline]
- fn xzz(self) -> Self {
- Self::new(self.x, self.z, self.z)
- }
- #[inline]
- fn yxx(self) -> Self {
- Self::new(self.y, self.x, self.x)
- }
- #[inline]
- fn yxy(self) -> Self {
- Self::new(self.y, self.x, self.y)
- }
- #[inline]
- fn yxz(self) -> Self {
- Self::new(self.y, self.x, self.z)
- }
- #[inline]
- fn yyx(self) -> Self {
- Self::new(self.y, self.y, self.x)
- }
- #[inline]
- fn yyy(self) -> Self {
- Self::new(self.y, self.y, self.y)
- }
- #[inline]
- fn yyz(self) -> Self {
- Self::new(self.y, self.y, self.z)
- }
- #[inline]
- fn yzx(self) -> Self {
- Self::new(self.y, self.z, self.x)
- }
- #[inline]
- fn yzy(self) -> Self {
- Self::new(self.y, self.z, self.y)
- }
- #[inline]
- fn yzz(self) -> Self {
- Self::new(self.y, self.z, self.z)
- }
- #[inline]
- fn zxx(self) -> Self {
- Self::new(self.z, self.x, self.x)
- }
- #[inline]
- fn zxy(self) -> Self {
- Self::new(self.z, self.x, self.y)
- }
- #[inline]
- fn zxz(self) -> Self {
- Self::new(self.z, self.x, self.z)
- }
- #[inline]
- fn zyx(self) -> Self {
- Self::new(self.z, self.y, self.x)
- }
- #[inline]
- fn zyy(self) -> Self {
- Self::new(self.z, self.y, self.y)
- }
- #[inline]
- fn zyz(self) -> Self {
- Self::new(self.z, self.y, self.z)
- }
- #[inline]
- fn zzx(self) -> Self {
- Self::new(self.z, self.z, self.x)
- }
- #[inline]
- fn zzy(self) -> Self {
- Self::new(self.z, self.z, self.y)
- }
- #[inline]
- fn zzz(self) -> Self {
- Self::new(self.z, self.z, self.z)
- }
- #[inline]
- fn xx(self) -> UVec2 {
- UVec2::new(self.x, self.x)
- }
- #[inline]
- fn xy(self) -> UVec2 {
- UVec2::new(self.x, self.y)
- }
- #[inline]
- fn xz(self) -> UVec2 {
- UVec2::new(self.x, self.z)
- }
- #[inline]
- fn yx(self) -> UVec2 {
- UVec2::new(self.y, self.x)
- }
- #[inline]
- fn yy(self) -> UVec2 {
- UVec2::new(self.y, self.y)
- }
- #[inline]
- fn yz(self) -> UVec2 {
- UVec2::new(self.y, self.z)
- }
- #[inline]
- fn zx(self) -> UVec2 {
- UVec2::new(self.z, self.x)
- }
- #[inline]
- fn zy(self) -> UVec2 {
- UVec2::new(self.z, self.y)
- }
- #[inline]
- fn zz(self) -> UVec2 {
- UVec2::new(self.z, self.z)
- }
}
diff --git a/src/swizzles/uvec4_impl_scalar.rs b/src/swizzles/uvec4_impl.rs
index be4824c..6d43573 100644
--- a/src/swizzles/uvec4_impl_scalar.rs
+++ b/src/swizzles/uvec4_impl.rs
@@ -1,1350 +1,1993 @@
-// Generated by swizzlegen. Do not edit.
+// Generated from swizzle_impl.rs.tera template. Edit the template, not the generated file.
-use super::Vec4Swizzles;
-use crate::{UVec2, UVec3, UVec4};
+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)
}
- #[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_scalar.rs b/src/swizzles/vec2_impl.rs
index 9968553..4842194 100644
--- a/src/swizzles/vec2_impl_scalar.rs
+++ b/src/swizzles/vec2_impl.rs
@@ -1,118 +1,193 @@
-// Generated by swizzlegen. Do not edit.
+// Generated from swizzle_impl.rs.tera template. Edit the template, not the generated file.
-use super::Vec2Swizzles;
-use crate::{Vec2, Vec3, Vec4};
+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)
}
- #[inline]
- fn xxx(self) -> Vec3 {
- Vec3::new(self.x, self.x, self.x)
- }
- #[inline]
- fn xxy(self) -> Vec3 {
- Vec3::new(self.x, self.x, self.y)
- }
- #[inline]
- fn xyx(self) -> Vec3 {
- Vec3::new(self.x, self.y, self.x)
- }
- #[inline]
- fn xyy(self) -> Vec3 {
- Vec3::new(self.x, self.y, self.y)
- }
- #[inline]
- fn yxx(self) -> Vec3 {
- Vec3::new(self.y, self.x, self.x)
- }
- #[inline]
- fn yxy(self) -> Vec3 {
- Vec3::new(self.y, self.x, self.y)
- }
- #[inline]
- fn yyx(self) -> Vec3 {
- Vec3::new(self.y, self.y, self.x)
- }
- #[inline]
- fn yyy(self) -> Vec3 {
- Vec3::new(self.y, self.y, self.y)
- }
- #[inline]
- fn xx(self) -> Self {
- Self::new(self.x, self.x)
- }
- #[inline]
- fn yx(self) -> Self {
- Self::new(self.y, self.x)
- }
- #[inline]
- fn yy(self) -> Self {
- Self::new(self.y, self.y)
- }
}
diff --git a/src/swizzles/vec3_impl_scalar.rs b/src/swizzles/vec3_impl.rs
index 83d7418..e60e8e1 100644
--- a/src/swizzles/vec3_impl_scalar.rs
+++ b/src/swizzles/vec3_impl.rs
@@ -1,474 +1,729 @@
-// Generated by swizzlegen. Do not edit.
+// Generated from swizzle_impl.rs.tera template. Edit the template, not the generated file.
-use super::Vec3Swizzles;
-use crate::{Vec2, Vec3, Vec4};
+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)
}
- #[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/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/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/vec3a_impl_wasm32.rs b/src/swizzles/wasm32/vec3a_impl.rs
index fa5e01a..978f494 100644
--- a/src/swizzles/vec3a_impl_wasm32.rs
+++ b/src/swizzles/wasm32/vec3a_impl.rs
@@ -1,476 +1,625 @@
-// Generated by swizzlegen. Do not edit.
+// Generated from swizzle_impl.rs.tera template. Edit the template, not the generated file.
-use super::Vec3Swizzles;
-use crate::{Vec2, Vec3A, Vec4, XY};
+#![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))
}
- #[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_wasm32.rs b/src/swizzles/wasm32/vec4_impl.rs
index 46c7a22..73ff28f 100644
--- a/src/swizzles/vec4_impl_wasm32.rs
+++ b/src/swizzles/wasm32/vec4_impl.rs
@@ -1,1352 +1,1997 @@
-// Generated by swizzlegen. Do not edit.
+// Generated from swizzle_impl.rs.tera template. Edit the template, not the generated file.
-use super::Vec4Swizzles;
-use crate::{Vec2, Vec3, Vec4, XY, XYZ};
+#![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))
}
- #[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/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<TransformRT> for TransformRT {
- type Output = TransformRT;
- #[inline]
- fn mul(self, other: TransformRT) -> TransformRT {
- mul_rt_rt(&self, &other)
- }
-}
-
-impl Mul<TransformSRT> for TransformSRT {
- type Output = Self;
- #[inline]
- fn mul(self, other: Self) -> Self::Output {
- mul_srt_srt(&self, &other)
- }
-}
-
-impl Mul<TransformRT> for TransformSRT {
- type Output = TransformSRT;
- #[inline]
- fn mul(self, other: TransformRT) -> Self::Output {
- mul_srt_srt(&self, &other.into())
- }
-}
-
-impl Mul<TransformSRT> for TransformRT {
- type Output = TransformSRT;
- #[inline]
- fn mul(self, other: TransformSRT) -> Self::Output {
- mul_srt_srt(&self.into(), &other)
- }
-}
-
-impl From<TransformRT> for TransformSRT {
- #[inline]
- fn from(tr: TransformRT) -> Self {
- Self {
- translation: tr.translation,
- rotation: tr.rotation,
- scale: Vec3::ONE,
- }
- }
-}
-
-#[cfg(feature = "rand")]
-impl Distribution<TransformRT> for Standard {
- #[inline]
- fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> TransformRT {
- TransformRT::from_rotation_translation(
- rng.gen::<Quat>(),
- 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<TransformSRT> for Standard {
- #[inline]
- fn sample<R: Rng + ?Sized>(&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::<Quat>(),
- 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<TransformSRT> for Mat4 {
- #[inline]
- fn from(srt: TransformSRT) -> Self {
- Self::from_scale_rotation_translation(srt.scale, srt.rotation, srt.translation)
- }
-}
-
-impl From<TransformRT> for Mat4 {
- #[inline]
- fn from(rt: TransformRT) -> Self {
- Self::from_rotation_translation(rt.rotation, rt.translation)
- }
-}
-
-impl From<TransformSRT> for Affine3A {
- #[inline]
- fn from(srt: TransformSRT) -> Self {
- Self::from_scale_rotation_translation(srt.scale, srt.rotation, srt.translation)
- }
-}
-
-impl From<TransformRT> 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::<u32>(),
+ core::mem::align_of::<super::UVec2>()
+ );
+ #[cfg(feature = "cuda")]
+ const_assert_eq!(8, core::mem::align_of::<super::UVec2>());
+ const_assert_eq!(8, core::mem::size_of::<super::UVec2>());
+ }
+
+ mod const_test_uvec3 {
+ const_assert_eq!(
+ core::mem::align_of::<u32>(),
+ core::mem::align_of::<super::UVec3>()
+ );
+ const_assert_eq!(12, core::mem::size_of::<super::UVec3>());
+ }
+
+ mod const_test_uvec4 {
+ #[cfg(not(feature = "cuda"))]
+ const_assert_eq!(
+ core::mem::align_of::<u32>(),
+ core::mem::align_of::<super::UVec4>()
+ );
+ #[cfg(feature = "cuda")]
+ const_assert_eq!(16, core::mem::align_of::<super::UVec4>());
+ const_assert_eq!(16, core::mem::size_of::<super::UVec4>());
+ }
+}
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<UVec2> 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<UVec2> for UVec2 {
+ #[inline]
+ fn div_assign(&mut self, rhs: Self) {
+ self.x.div_assign(rhs.x);
+ self.y.div_assign(rhs.y);
+ }
+}
+
+impl Div<u32> 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<u32> for UVec2 {
+ #[inline]
+ fn div_assign(&mut self, rhs: u32) {
+ self.x.div_assign(rhs);
+ self.y.div_assign(rhs);
+ }
+}
+
+impl Div<UVec2> 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<UVec2> 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<UVec2> for UVec2 {
+ #[inline]
+ fn mul_assign(&mut self, rhs: Self) {
+ self.x.mul_assign(rhs.x);
+ self.y.mul_assign(rhs.y);
+ }
+}
+
+impl Mul<u32> 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<u32> for UVec2 {
+ #[inline]
+ fn mul_assign(&mut self, rhs: u32) {
+ self.x.mul_assign(rhs);
+ self.y.mul_assign(rhs);
+ }
+}
+
+impl Mul<UVec2> 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<UVec2> 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<UVec2> for UVec2 {
+ #[inline]
+ fn add_assign(&mut self, rhs: Self) {
+ self.x.add_assign(rhs.x);
+ self.y.add_assign(rhs.y);
+ }
+}
+
+impl Add<u32> 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<u32> for UVec2 {
+ #[inline]
+ fn add_assign(&mut self, rhs: u32) {
+ self.x.add_assign(rhs);
+ self.y.add_assign(rhs);
+ }
+}
+
+impl Add<UVec2> 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<UVec2> 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<UVec2> for UVec2 {
+ #[inline]
+ fn sub_assign(&mut self, rhs: UVec2) {
+ self.x.sub_assign(rhs.x);
+ self.y.sub_assign(rhs.y);
+ }
+}
+
+impl Sub<u32> 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<u32> for UVec2 {
+ #[inline]
+ fn sub_assign(&mut self, rhs: u32) {
+ self.x.sub_assign(rhs);
+ self.y.sub_assign(rhs);
+ }
+}
+
+impl Sub<UVec2> 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<UVec2> 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<UVec2> for UVec2 {
+ #[inline]
+ fn rem_assign(&mut self, rhs: Self) {
+ self.x.rem_assign(rhs.x);
+ self.y.rem_assign(rhs.y);
+ }
+}
+
+impl Rem<u32> 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<u32> for UVec2 {
+ #[inline]
+ fn rem_assign(&mut self, rhs: u32) {
+ self.x.rem_assign(rhs);
+ self.y.rem_assign(rhs);
+ }
+}
+
+impl Rem<UVec2> 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<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ZERO, Self::add)
+ }
+}
+
+impl<'a> Sum<&'a Self> for UVec2 {
+ #[inline]
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+ }
+}
+
+impl Product for UVec2 {
+ #[inline]
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ONE, Self::mul)
+ }
+}
+
+impl<'a> Product<&'a Self> for UVec2 {
+ #[inline]
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ 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<u32> 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<u32> 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<u32> 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<i8> 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<i8> 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<i16> 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<i16> 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<i32> 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<i32> 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<u8> 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<u8> 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<u16> 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<u16> 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<u32> 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<u32> 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<crate::IVec2> 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<crate::IVec2> 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<crate::UVec2> 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<crate::UVec2> 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<usize> 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<usize> 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<UVec2> 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<UVec2> 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<UVec3> 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<UVec3> 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<u32> 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<u32> 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<UVec3> 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<UVec3> 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<UVec3> 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<u32> 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<u32> 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<UVec3> 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<UVec3> 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<UVec3> 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<u32> 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<u32> 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<UVec3> 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<UVec3> 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<UVec3> 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<u32> 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<u32> 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<UVec3> 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<UVec3> 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<UVec3> 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<u32> 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<u32> 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<UVec3> 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<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ZERO, Self::add)
+ }
+}
+
+impl<'a> Sum<&'a Self> for UVec3 {
+ #[inline]
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+ }
+}
+
+impl Product for UVec3 {
+ #[inline]
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ONE, Self::mul)
+ }
+}
+
+impl<'a> Product<&'a Self> for UVec3 {
+ #[inline]
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ 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<u32> 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<u32> 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<u32> 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<i8> 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<i8> 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<i16> 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<i16> 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<i32> 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<i32> 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<u8> 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<u8> 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<u16> 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<u16> 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<u32> 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<u32> 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<crate::IVec3> 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<crate::IVec3> 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<crate::UVec3> 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<crate::UVec3> 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<usize> 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<usize> 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<UVec3> 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<UVec3> 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<UVec4> 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<UVec4> 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<u32> 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<u32> 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<UVec4> 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<UVec4> 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<UVec4> 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<u32> 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<u32> 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<UVec4> 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<UVec4> 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<UVec4> 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<u32> 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<u32> 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<UVec4> 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<UVec4> 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<UVec4> 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<u32> 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<u32> 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<UVec4> 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<UVec4> 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<UVec4> 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<u32> 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<u32> 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<UVec4> 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<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ZERO, Self::add)
+ }
+}
+
+impl<'a> Sum<&'a Self> for UVec4 {
+ #[inline]
+ fn sum<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+ }
+}
+
+impl Product for UVec4 {
+ #[inline]
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = Self>,
+ {
+ iter.fold(Self::ONE, Self::mul)
+ }
+}
+
+impl<'a> Product<&'a Self> for UVec4 {
+ #[inline]
+ fn product<I>(iter: I) -> Self
+ where
+ I: Iterator<Item = &'a Self>,
+ {
+ 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<u32> 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<u32> 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<u32> 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<i8> 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<i8> 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<i16> 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<i16> 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<i32> 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<i32> 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<u8> 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<u8> 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<u16> 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<u16> 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<u32> 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<u32> 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<crate::IVec4> 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<crate::IVec4> 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<crate::UVec4> 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<crate::UVec4> 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<usize> 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<usize> 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<UVec4> 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<UVec4> 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<Self> {
- 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<I>(iter: I) -> Self
- where
- I: Iterator<Item = &'a Self>,
- {
- iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
- }
- }
-
- impl<'a> Product<&'a Self> for $vecn {
- #[inline]
- fn product<I>(iter: I) -> Self
- where
- I: Iterator<Item = &'a Self>,
- {
- 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<H: core::hash::Hasher>(&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<usize> 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<usize> 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<f32>;
-
-/// 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<f64>;
-
-/// 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<i32>;
-
-/// 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<u32>;
-
-/// 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::<f32>(),
- core::mem::align_of::<super::Vec2>()
- );
- #[cfg(feature = "cuda")]
- const_assert_eq!(8, core::mem::align_of::<super::Vec2>());
- const_assert_eq!(8, core::mem::size_of::<super::Vec2>());
-}
-
-mod const_test_dvec2 {
- #[cfg(not(feature = "cuda"))]
- const_assert_eq!(
- core::mem::align_of::<f64>(),
- core::mem::align_of::<super::DVec2>()
- );
- #[cfg(feature = "cuda")]
- const_assert_eq!(16, core::mem::align_of::<super::DVec2>());
- const_assert_eq!(16, core::mem::size_of::<super::DVec2>());
-}
-
-mod const_test_ivec2 {
- #[cfg(not(feature = "cuda"))]
- const_assert_eq!(
- core::mem::align_of::<i32>(),
- core::mem::align_of::<super::IVec2>()
- );
- #[cfg(feature = "cuda")]
- const_assert_eq!(8, core::mem::align_of::<super::IVec2>());
- const_assert_eq!(8, core::mem::size_of::<super::IVec2>());
-}
-
-mod const_test_uvec2 {
- #[cfg(not(feature = "cuda"))]
- const_assert_eq!(
- core::mem::align_of::<u32>(),
- core::mem::align_of::<super::UVec2>()
- );
- #[cfg(feature = "cuda")]
- const_assert_eq!(8, core::mem::align_of::<super::UVec2>());
- const_assert_eq!(8, core::mem::size_of::<super::UVec2>());
-}
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<usize> 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<usize> 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<f32>;
-
-/// 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<Vec3> for Vec3A {
- #[inline(always)]
- fn from(v: Vec3) -> Self {
- Self(v.0.into())
- }
-}
-
-impl From<Vec3A> for Vec3 {
- #[inline(always)]
- fn from(v: Vec3A) -> Self {
- Self(v.0.into())
- }
-}
-
-type XYZF64 = XYZ<f64>;
-
-/// 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<i32>;
-
-/// 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<u32>;
-
-/// 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::<f32>(),
- core::mem::align_of::<super::Vec3>()
- );
- const_assert_eq!(12, core::mem::size_of::<super::Vec3>());
-}
-
-mod const_test_vec3a {
- const_assert_eq!(16, core::mem::align_of::<super::Vec3A>());
- const_assert_eq!(16, core::mem::size_of::<super::Vec3A>());
-}
-
-mod const_test_dvec3 {
- const_assert_eq!(
- core::mem::align_of::<f64>(),
- core::mem::align_of::<super::DVec3>()
- );
- const_assert_eq!(24, core::mem::size_of::<super::DVec3>());
-}
-
-mod const_test_ivec3 {
- const_assert_eq!(
- core::mem::align_of::<i32>(),
- core::mem::align_of::<super::IVec3>()
- );
- const_assert_eq!(12, core::mem::size_of::<super::IVec3>());
-}
-
-mod const_test_uvec3 {
- const_assert_eq!(
- core::mem::align_of::<u32>(),
- core::mem::align_of::<super::UVec3>()
- );
- const_assert_eq!(12, core::mem::size_of::<super::UVec3>());
-}
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<usize> 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<usize> 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<f32>;
-
-#[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<Vec4> 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<f64>;
-
-/// 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<i32>;
-
-/// 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<u32>;
-
-/// 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::<f32>(),
- core::mem::align_of::<super::Vec4>()
- );
- #[cfg(not(any(feature = "scalar-math", target_arch = "spirv")))]
- const_assert_eq!(16, core::mem::align_of::<super::Vec4>());
- const_assert_eq!(16, core::mem::size_of::<super::Vec4>());
-}
-
-mod const_test_dvec4 {
- #[cfg(not(feature = "cuda"))]
- const_assert_eq!(
- core::mem::align_of::<f64>(),
- core::mem::align_of::<super::DVec4>()
- );
- #[cfg(feature = "cuda")]
- const_assert_eq!(16, core::mem::align_of::<super::DVec4>());
- const_assert_eq!(32, core::mem::size_of::<super::DVec4>());
-}
-
-mod const_test_ivec4 {
- #[cfg(not(feature = "cuda"))]
- const_assert_eq!(
- core::mem::align_of::<i32>(),
- core::mem::align_of::<super::IVec4>()
- );
- #[cfg(feature = "cuda")]
- const_assert_eq!(16, core::mem::align_of::<super::IVec4>());
- const_assert_eq!(16, core::mem::size_of::<super::IVec4>());
-}
-
-mod const_test_uvec4 {
- #[cfg(not(feature = "cuda"))]
- const_assert_eq!(
- core::mem::align_of::<u32>(),
- core::mem::align_of::<super::UVec4>()
- );
- #[cfg(feature = "cuda")]
- const_assert_eq!(16, core::mem::align_of::<super::UVec4>());
- const_assert_eq!(16, core::mem::size_of::<super::UVec4>());
-}
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<H: hash::Hasher>(&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<BVec3> 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<BVec3A> 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<BVec4> 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<BVec4A> 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<bool>;
-
-/// 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<bool>;
-
-/// 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<bool>;
-
-/// 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::<bool>(),
- core::mem::align_of::<super::BVec2>()
- );
- const_assert_eq!(2, core::mem::size_of::<super::BVec2>());
-}
-
-mod const_test_bvec3 {
- const_assert_eq!(
- core::mem::align_of::<bool>(),
- core::mem::align_of::<super::BVec3>()
- );
- const_assert_eq!(3, core::mem::size_of::<super::BVec3>());
-}
-
-#[cfg(all(target_feature = "sse2", not(feature = "scalar-math")))]
-mod const_test_bvec3a {
- const_assert_eq!(16, core::mem::align_of::<super::BVec3A>());
- const_assert_eq!(16, core::mem::size_of::<super::BVec3A>());
-}
-
-mod const_test_bvec4 {
- const_assert_eq!(
- core::mem::align_of::<bool>(),
- core::mem::align_of::<super::BVec4>()
- );
- const_assert_eq!(4, core::mem::size_of::<super::BVec4>());
-}
-
-#[cfg(all(target_feature = "sse2", not(feature = "scalar-math")))]
-mod const_test_bvec4a {
- const_assert_eq!(16, core::mem::align_of::<super::BVec4A>());
- const_assert_eq!(16, core::mem::size_of::<super::BVec4A>());
-}
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::<DAffine2>());
});
- 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::<f64>(), mem::align_of::<DAffine3>());
});
- 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::<DVec2>(), mem::align_of::<DMat2>());
});
- 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::<DVec3>(), mem::align_of::<DMat3>());
});
- 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::<Mat4>());
});
+ 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::<DMat4>());
});
- 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::<f64>(), mem::align_of::<DQuat>());
});
- 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/mod.rs b/tests/support.rs
index 865aa5e..08000e9 100644
--- a/tests/support/mod.rs
+++ b/tests/support.rs
@@ -1,3 +1,4 @@
+#[path = "support/macros.rs"]
#[macro_use]
mod macros;
@@ -74,7 +75,7 @@ impl FloatCompare for f64 {
impl FloatCompare for Mat2 {
#[inline]
fn approx_eq(&self, other: &Self, max_abs_diff: f32) -> bool {
- self.abs_diff_eq(other, max_abs_diff)
+ self.abs_diff_eq(*other, max_abs_diff)
}
#[inline]
fn abs_diff(&self, other: &Self) -> Self {
@@ -88,7 +89,7 @@ impl FloatCompare for Mat2 {
impl FloatCompare for DMat2 {
#[inline]
fn approx_eq(&self, other: &Self, max_abs_diff: f32) -> bool {
- self.abs_diff_eq(other, max_abs_diff as f64)
+ self.abs_diff_eq(*other, max_abs_diff as f64)
}
#[inline]
fn abs_diff(&self, other: &Self) -> Self {
diff --git a/tests/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/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::<BVec2>());
});
- 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::<BVec2>());
});
- 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::<BVec2>());
});
- 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);
@@ -514,6 +609,10 @@ macro_rules! impl_vec3_float_tests {
$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::<Vec3A>());
assert_eq!(16, mem::align_of::<Vec3A>());
- 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::<BVec3A>());
assert_eq!(16, mem::align_of::<BVec3A>());
- } else {
- // BVec3A aliases BVec3
- assert_eq!(3, mem::size_of::<BVec3A>());
- assert_eq!(1, mem::align_of::<BVec3A>());
+ }
+ #[cfg(feature = "scalar-math")]
+ {
+ assert_eq!(3, mem::size_of::<BVec3>());
+ assert_eq!(1, mem::align_of::<BVec3>());
}
});
@@ -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::<BVec3>());
});
- 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::<BVec3>());
});
- 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::<BVec3>());
});
- 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;
@@ -583,6 +687,10 @@ macro_rules! impl_vec4_float_tests {
$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::<Vec4>());
}
- if cfg!(all(
- any(target_feature = "sse2", target_feature = "simd128"),
- not(feature = "scalar-math")
- )) {
- assert_eq!(16, mem::size_of::<Vec4Mask>());
- assert_eq!(16, mem::align_of::<Vec4Mask>());
- } else {
- assert_eq!(4, mem::size_of::<Vec4Mask>());
- assert_eq!(1, mem::align_of::<Vec4Mask>());
+ #[cfg(not(feature = "scalar-math"))]
+ {
+ assert_eq!(16, mem::size_of::<BVec4A>());
+ assert_eq!(16, mem::align_of::<BVec4A>());
+ }
+ #[cfg(feature = "scalar-math")]
+ {
+ assert_eq!(4, mem::size_of::<BVec4>());
+ assert_eq!(1, mem::align_of::<BVec4>());
}
});
- #[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::<BVec4>());
});
- 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::<BVec4>());
});
- 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::<BVec4>());
});
- 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);