From 5bcd594cb4681bbac5d8d3ca5339188a340ef36c Mon Sep 17 00:00:00 2001 From: Carter Anderson Date: Mon, 1 Jun 2020 19:23:11 -0700 Subject: [PATCH] bytes: AsBytes trait, remove zerocopy, remove glam fork --- Cargo.toml | 6 +- crates/bevy_core/Cargo.toml | 3 +- crates/bevy_core/src/bytes.rs | 126 +- crates/bevy_glam/.cargo_vcs_info.json | 5 - crates/bevy_glam/.github/workflows/CI.yml | 8 - crates/bevy_glam/.gitignore | 6 - crates/bevy_glam/.travis.yml | 40 - crates/bevy_glam/CHANGELOG.md | 188 --- crates/bevy_glam/CONTRIBUTING.md | 50 - crates/bevy_glam/Cargo.toml | 83 - crates/bevy_glam/LICENSE-APACHE | 201 --- crates/bevy_glam/LICENSE-MIT | 23 - crates/bevy_glam/README.md | 163 -- crates/bevy_glam/benches/mat2.rs | 34 - crates/bevy_glam/benches/mat3.rs | 36 - crates/bevy_glam/benches/mat4.rs | 36 - crates/bevy_glam/benches/quat.rs | 62 - crates/bevy_glam/benches/support/macros.rs | 180 --- crates/bevy_glam/benches/support/mod.rs | 96 -- crates/bevy_glam/benches/transform.rs | 85 -- crates/bevy_glam/benches/vec2.rs | 31 - crates/bevy_glam/benches/vec3.rs | 98 -- crates/bevy_glam/benches/vec4.rs | 20 - crates/bevy_glam/build.rs | 29 - crates/bevy_glam/deny.toml | 18 - crates/bevy_glam/src/f32/funcs.rs | 550 ------- crates/bevy_glam/src/f32/glam_mint.rs | 309 ---- crates/bevy_glam/src/f32/glam_rand.rs | 59 - crates/bevy_glam/src/f32/glam_serde.rs | 385 ----- crates/bevy_glam/src/f32/glam_zerocopy.rs | 114 -- crates/bevy_glam/src/f32/mat2.rs | 335 ---- crates/bevy_glam/src/f32/mat3.rs | 482 ------ crates/bevy_glam/src/f32/mat4.rs | 886 ----------- crates/bevy_glam/src/f32/mod.rs | 47 - crates/bevy_glam/src/f32/quat.rs | 670 -------- crates/bevy_glam/src/f32/transform.rs | 361 ----- crates/bevy_glam/src/f32/vec2.rs | 509 ------- crates/bevy_glam/src/f32/vec2_mask.rs | 126 -- crates/bevy_glam/src/f32/vec3.rs | 1221 --------------- crates/bevy_glam/src/f32/vec3_mask.rs | 298 ---- crates/bevy_glam/src/f32/vec4.rs | 1347 ----------------- crates/bevy_glam/src/f32/vec4_mask.rs | 329 ---- crates/bevy_glam/src/f32/x86_utils.rs | 15 - crates/bevy_glam/src/lib.rs | 167 -- crates/bevy_glam/src/macros.rs | 32 - crates/bevy_glam/tests/mat2.rs | 186 --- crates/bevy_glam/tests/mat3.rs | 253 ---- crates/bevy_glam/tests/mat4.rs | 483 ------ crates/bevy_glam/tests/quat.rs | 284 ---- crates/bevy_glam/tests/support/macros.rs | 32 - crates/bevy_glam/tests/support/mod.rs | 166 -- crates/bevy_glam/tests/transform.rs | 88 -- crates/bevy_glam/tests/vec2.rs | 490 ------ crates/bevy_glam/tests/vec3.rs | 599 -------- crates/bevy_glam/tests/vec4.rs | 621 -------- crates/bevy_pbr/Cargo.toml | 3 +- crates/bevy_pbr/src/light.rs | 6 +- crates/bevy_pbr/src/nodes/lights_node.rs | 6 +- crates/bevy_property/Cargo.toml | 2 +- crates/bevy_render/Cargo.toml | 3 +- crates/bevy_render/src/color.rs | 16 +- crates/bevy_render/src/mesh.rs | 20 +- .../src/render_graph/nodes/camera_node.rs | 6 +- .../bevy_render/src/shader/shader_reflect.rs | 2 +- crates/bevy_render/src/vertex.rs | 8 +- crates/bevy_sprite/Cargo.toml | 2 +- crates/bevy_sprite/src/entity.rs | 33 +- crates/bevy_sprite/src/lib.rs | 7 + crates/bevy_sprite/src/quad.rs | 17 +- crates/bevy_sprite/src/rect.rs | 11 +- crates/bevy_sprite/src/render/mod.rs | 53 + .../bevy_sprite/src/render/sprite_sheet.frag | 14 + .../bevy_sprite/src/render/sprite_sheet.vert | 42 + crates/bevy_sprite/src/sprite_sheet.rs | 112 +- crates/bevy_transform/Cargo.toml | 2 +- crates/bevy_ui/Cargo.toml | 4 +- examples/2d/sprite_sheet.rs | 36 + src/prelude.rs | 2 +- 78 files changed, 407 insertions(+), 13071 deletions(-) delete mode 100644 crates/bevy_glam/.cargo_vcs_info.json delete mode 100644 crates/bevy_glam/.github/workflows/CI.yml delete mode 100644 crates/bevy_glam/.gitignore delete mode 100644 crates/bevy_glam/.travis.yml delete mode 100644 crates/bevy_glam/CHANGELOG.md delete mode 100644 crates/bevy_glam/CONTRIBUTING.md delete mode 100644 crates/bevy_glam/Cargo.toml delete mode 100644 crates/bevy_glam/LICENSE-APACHE delete mode 100644 crates/bevy_glam/LICENSE-MIT delete mode 100644 crates/bevy_glam/README.md delete mode 100644 crates/bevy_glam/benches/mat2.rs delete mode 100644 crates/bevy_glam/benches/mat3.rs delete mode 100644 crates/bevy_glam/benches/mat4.rs delete mode 100644 crates/bevy_glam/benches/quat.rs delete mode 100644 crates/bevy_glam/benches/support/macros.rs delete mode 100644 crates/bevy_glam/benches/support/mod.rs delete mode 100644 crates/bevy_glam/benches/transform.rs delete mode 100644 crates/bevy_glam/benches/vec2.rs delete mode 100644 crates/bevy_glam/benches/vec3.rs delete mode 100644 crates/bevy_glam/benches/vec4.rs delete mode 100644 crates/bevy_glam/build.rs delete mode 100644 crates/bevy_glam/deny.toml delete mode 100644 crates/bevy_glam/src/f32/funcs.rs delete mode 100644 crates/bevy_glam/src/f32/glam_mint.rs delete mode 100644 crates/bevy_glam/src/f32/glam_rand.rs delete mode 100644 crates/bevy_glam/src/f32/glam_serde.rs delete mode 100644 crates/bevy_glam/src/f32/glam_zerocopy.rs delete mode 100644 crates/bevy_glam/src/f32/mat2.rs delete mode 100644 crates/bevy_glam/src/f32/mat3.rs delete mode 100644 crates/bevy_glam/src/f32/mat4.rs delete mode 100644 crates/bevy_glam/src/f32/mod.rs delete mode 100644 crates/bevy_glam/src/f32/quat.rs delete mode 100644 crates/bevy_glam/src/f32/transform.rs delete mode 100644 crates/bevy_glam/src/f32/vec2.rs delete mode 100644 crates/bevy_glam/src/f32/vec2_mask.rs delete mode 100644 crates/bevy_glam/src/f32/vec3.rs delete mode 100644 crates/bevy_glam/src/f32/vec3_mask.rs delete mode 100644 crates/bevy_glam/src/f32/vec4.rs delete mode 100644 crates/bevy_glam/src/f32/vec4_mask.rs delete mode 100644 crates/bevy_glam/src/f32/x86_utils.rs delete mode 100644 crates/bevy_glam/src/lib.rs delete mode 100644 crates/bevy_glam/src/macros.rs delete mode 100644 crates/bevy_glam/tests/mat2.rs delete mode 100644 crates/bevy_glam/tests/mat3.rs delete mode 100644 crates/bevy_glam/tests/mat4.rs delete mode 100644 crates/bevy_glam/tests/quat.rs delete mode 100644 crates/bevy_glam/tests/support/macros.rs delete mode 100644 crates/bevy_glam/tests/support/mod.rs delete mode 100644 crates/bevy_glam/tests/transform.rs delete mode 100644 crates/bevy_glam/tests/vec2.rs delete mode 100644 crates/bevy_glam/tests/vec3.rs delete mode 100644 crates/bevy_glam/tests/vec4.rs create mode 100644 crates/bevy_sprite/src/render/sprite_sheet.frag create mode 100644 crates/bevy_sprite/src/render/sprite_sheet.vert create mode 100644 examples/2d/sprite_sheet.rs diff --git a/Cargo.toml b/Cargo.toml index 6f75f0fc48..8eeaaa45b3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,7 +59,7 @@ bevy_window = { path = "crates/bevy_window", optional = true } bevy_wgpu = { path = "crates/bevy_wgpu", optional = true } bevy_winit = { path = "crates/bevy_winit", optional = true } legion = { path = "crates/bevy_legion" } -glam = { path = "crates/bevy_glam" } +glam = "0.8.7" # other log = { version = "0.4", features = ["release_max_level_info"] } @@ -79,6 +79,10 @@ path = "examples/hello_world.rs" name = "sprite" path = "examples/2d/sprite.rs" +[[example]] +name = "sprite_sheet" +path = "examples/2d/sprite_sheet.rs" + [[example]] name = "load_model" path = "examples/3d/load_model.rs" diff --git a/crates/bevy_core/Cargo.toml b/crates/bevy_core/Cargo.toml index c2e534397d..7e638b4d7d 100644 --- a/crates/bevy_core/Cargo.toml +++ b/crates/bevy_core/Cargo.toml @@ -9,5 +9,4 @@ bevy_app = { path = "../bevy_app" } bevy_type_registry = { path = "../bevy_type_registry" } bevy_transform = { path = "../bevy_transform" } legion = { path = "../bevy_legion" } -glam = { path = "../bevy_glam" } -zerocopy = "0.3" \ No newline at end of file +glam = "0.8.7" \ No newline at end of file diff --git a/crates/bevy_core/src/bytes.rs b/crates/bevy_core/src/bytes.rs index bc691a6756..6b67049e95 100644 --- a/crates/bevy_core/src/bytes.rs +++ b/crates/bevy_core/src/bytes.rs @@ -1,82 +1,71 @@ use glam::{Mat4, Vec2, Vec3, Vec4}; -use zerocopy::AsBytes; - -macro_rules! impl_bytes_zerocopy { - ($ty:tt) => { - impl Bytes for $ty { - fn write_bytes(&self, buffer: &mut [u8]) { - buffer[0..self.byte_len()].copy_from_slice(self.as_bytes()) - } - fn byte_len(&self) -> usize { - std::mem::size_of::() - } - } - - }; -} - pub trait Bytes { fn write_bytes(&self, buffer: &mut [u8]); fn byte_len(&self) -> usize; } -impl_bytes_zerocopy!(u8); -impl_bytes_zerocopy!(u16); -impl_bytes_zerocopy!(u32); -impl_bytes_zerocopy!(u64); -impl_bytes_zerocopy!(usize); -impl_bytes_zerocopy!(i8); -impl_bytes_zerocopy!(i16); -impl_bytes_zerocopy!(i32); -impl_bytes_zerocopy!(i64); -impl_bytes_zerocopy!(isize); -impl_bytes_zerocopy!(f32); -impl_bytes_zerocopy!(f64); +pub unsafe trait Byteable where Self: Sized {} -impl_bytes_zerocopy!([u8; 2]); -impl_bytes_zerocopy!([u16; 2]); -impl_bytes_zerocopy!([u32; 2]); -impl_bytes_zerocopy!([u64; 2]); -impl_bytes_zerocopy!([usize; 2]); -impl_bytes_zerocopy!([i8; 2]); -impl_bytes_zerocopy!([i16; 2]); -impl_bytes_zerocopy!([i32; 2]); -impl_bytes_zerocopy!([i64; 2]); -impl_bytes_zerocopy!([isize; 2]); -impl_bytes_zerocopy!([f32; 2]); -impl_bytes_zerocopy!([f64; 2]); +impl Bytes for T +where + T: Byteable, +{ + fn write_bytes(&self, buffer: &mut [u8]) { + let bytes = self.as_bytes(); + buffer[0..self.byte_len()].copy_from_slice(bytes) + } + fn byte_len(&self) -> usize { + std::mem::size_of::() + } +} -impl_bytes_zerocopy!([u8; 3]); -impl_bytes_zerocopy!([u16; 3]); -impl_bytes_zerocopy!([u32; 3]); -impl_bytes_zerocopy!([u64; 3]); -impl_bytes_zerocopy!([usize; 3]); -impl_bytes_zerocopy!([i8; 3]); -impl_bytes_zerocopy!([i16; 3]); -impl_bytes_zerocopy!([i32; 3]); -impl_bytes_zerocopy!([i64; 3]); -impl_bytes_zerocopy!([isize; 3]); -impl_bytes_zerocopy!([f32; 3]); -impl_bytes_zerocopy!([f64; 3]); +pub trait AsBytes { + fn as_bytes(&self) -> &[u8]; +} -impl_bytes_zerocopy!([u8; 4]); -impl_bytes_zerocopy!([u16; 4]); -impl_bytes_zerocopy!([u32; 4]); -impl_bytes_zerocopy!([u64; 4]); -impl_bytes_zerocopy!([usize; 4]); -impl_bytes_zerocopy!([i8; 4]); -impl_bytes_zerocopy!([i16; 4]); -impl_bytes_zerocopy!([i32; 4]); -impl_bytes_zerocopy!([i64; 4]); -impl_bytes_zerocopy!([isize; 4]); -impl_bytes_zerocopy!([f32; 4]); -impl_bytes_zerocopy!([f64; 4]); +impl AsBytes for T +where + T: Byteable, +{ + fn as_bytes(&self) -> &[u8] { + let len = std::mem::size_of_val(self); + unsafe { core::slice::from_raw_parts(self as *const Self as *const u8, len) } + } +} +impl<'a, T> AsBytes for [T] +where + T: Byteable, +{ + fn as_bytes(&self) -> &[u8] { + let len = std::mem::size_of_val(self); + unsafe { core::slice::from_raw_parts(self as *const Self as *const u8, len) } + } +} + +unsafe impl Byteable for [T] where Self: Sized {} +unsafe impl Byteable for [T; 2] where T: Byteable {} +unsafe impl Byteable for [T; 3] where T: Byteable {} +unsafe impl Byteable for [T; 4] where T: Byteable {} +unsafe impl Byteable for [T; 16] where T: Byteable {} + +unsafe impl Byteable for u8 {} +unsafe impl Byteable for u16 {} +unsafe impl Byteable for u32 {} +unsafe impl Byteable for u64 {} +unsafe impl Byteable for usize {} +unsafe impl Byteable for i8 {} +unsafe impl Byteable for i16 {} +unsafe impl Byteable for i32 {} +unsafe impl Byteable for i64 {} +unsafe impl Byteable for isize {} +unsafe impl Byteable for f32 {} +unsafe impl Byteable for f64 {} impl Bytes for Vec2 { fn write_bytes(&self, buffer: &mut [u8]) { let array: [f32; 2] = (*self).into(); - buffer[0..self.byte_len()].copy_from_slice(array.as_bytes()) + array.write_bytes(buffer); } fn byte_len(&self) -> usize { std::mem::size_of::() @@ -86,7 +75,7 @@ impl Bytes for Vec2 { impl Bytes for Vec3 { fn write_bytes(&self, buffer: &mut [u8]) { let array: [f32; 3] = (*self).into(); - buffer[0..self.byte_len()].copy_from_slice(array.as_bytes()) + array.write_bytes(buffer); } fn byte_len(&self) -> usize { std::mem::size_of::() @@ -96,7 +85,7 @@ impl Bytes for Vec3 { impl Bytes for Vec4 { fn write_bytes(&self, buffer: &mut [u8]) { let array: [f32; 4] = (*self).into(); - buffer[0..self.byte_len()].copy_from_slice(array.as_bytes()) + array.write_bytes(buffer); } fn byte_len(&self) -> usize { std::mem::size_of::() @@ -105,7 +94,8 @@ impl Bytes for Vec4 { impl Bytes for Mat4 { fn write_bytes(&self, buffer: &mut [u8]) { - buffer[0..self.byte_len()].copy_from_slice(self.to_cols_array().as_bytes()) + let array = self.to_cols_array(); + array.write_bytes(buffer); } fn byte_len(&self) -> usize { std::mem::size_of::() diff --git a/crates/bevy_glam/.cargo_vcs_info.json b/crates/bevy_glam/.cargo_vcs_info.json deleted file mode 100644 index 272dadedee..0000000000 --- a/crates/bevy_glam/.cargo_vcs_info.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "git": { - "sha1": "9690d383cfa7d720706d66b25ec862fa6100adf5" - } -} diff --git a/crates/bevy_glam/.github/workflows/CI.yml b/crates/bevy_glam/.github/workflows/CI.yml deleted file mode 100644 index 547551da24..0000000000 --- a/crates/bevy_glam/.github/workflows/CI.yml +++ /dev/null @@ -1,8 +0,0 @@ -name: CI -on: [push, pull_request] -jobs: - cargo-deny: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v1 - - uses: EmbarkStudios/cargo-deny-action@v0 diff --git a/crates/bevy_glam/.gitignore b/crates/bevy_glam/.gitignore deleted file mode 100644 index 6a4d74b017..0000000000 --- a/crates/bevy_glam/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -/target -*.swp -**/*.rs.bk -Cargo.lock -Session.vim -.cargo-ok diff --git a/crates/bevy_glam/.travis.yml b/crates/bevy_glam/.travis.yml deleted file mode 100644 index ac627f1ffd..0000000000 --- a/crates/bevy_glam/.travis.yml +++ /dev/null @@ -1,40 +0,0 @@ -language: rust -sudo: required -dist: trusty -addons: - apt: - packages: - - libssl-dev - -cache: cargo - -rust: - - stable - - beta - - nightly - -env: - - CARGO_FEATURES="mint rand serde debug-glam-assert transform-types" - - CARGO_FEATURES="mint rand serde packed-vec3 debug-glam-assert transform-types" - - CARGO_FEATURES="mint rand serde scalar-math debug-glam-assert transform-types" - -matrix: - allow_failures: - - rust: nightly - fast_finish: true - -before_script: | - if [[ "$TRAVIS_RUST_VERSION" == stable ]]; then - cargo install cargo-tarpaulin - fi - -script: - - cargo clean - - cargo build --features "$CARGO_FEATURES" - - cargo test --features "$CARGO_FEATURES" - - cargo bench --features "$CARGO_FEATURES" --no-run - -after_success: | - if [[ "$TRAVIS_RUST_VERSION" == stable ]]; then - cargo tarpaulin --features "$CARGO_FEATURES" --exclude-files src/f32/transform.rs --exclude-files benches/* --exclude-files tests/support/mod.rs --ciserver travis-ci --coveralls $TRAVIS_JOB_ID - fi diff --git a/crates/bevy_glam/CHANGELOG.md b/crates/bevy_glam/CHANGELOG.md deleted file mode 100644 index d22f77f44b..0000000000 --- a/crates/bevy_glam/CHANGELOG.md +++ /dev/null @@ -1,188 +0,0 @@ -# Changelog -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog], and this project adheres to -[Semantic Versioning]. - -## [Unreleased] - -## [0.8.7] - 2020-04-28 - -### Added -* Added `Quat::slerp` - note that this uses a `sin` approximation. -* Added `angle_between` method for `Vec2` and `Vec3`. -* Implemented `Debug`, `Display`, `PartialEq`, `Eq`, `PartialOrd`, `Ord`, - `Hash`, and `AsRef` traits for `Vec2Mask`, `Vec3Mask` and `Vec4Mask`. -* Added conversion functions from `Vec2Mask`, `Vec3Mask` and `Vec4Mask` to an - array of `[u32]`. -* Added `build.rs` to simplify conditional feature compilation. - -### Changed -* Removed `cfg-if` dependency. -* Increased test coverage. - -## [0.8.6] - 2020-02-18 - -### Added -* Added the `packed-vec3` feature flag to disable using SIMD types for `Vec3` - and `Mat3` types. This avoids wasting some space due to 16 byte alignment at - the cost of some performance. -* Added `x_mut`, `y_mut`, `z_mut`, `w_mut` where appropriate to `Vec2`, `Vec3` - and `Vec4`. -* Added implementation of `core::ops::Index` and `core::ops::IndexMut` for - `Vec2`, `Vec3` and `Vec4`. - -### Changed -* Merged SSE2 and scalar `Vec3` and `Vec4` implementations into single files - using the `cfg-if` crate. - -## [0.8.5] - 2020-01-02 - -### Added -* Added projection functions `Mat4::perspective_lh`, - `Mat4::perspective_infinite_lh`, `Mat4::perspective_infinite_reverse_lh`, - `Mat4::orthgraphic_lh` and `Mat4::orthographic_rh`. -* Added `round`, `ceil` and `floor` methods to `Vec2`, `Vec3` and `Vec4`. - -## [0.8.4] - 2019-12-17 - -### Added -* Added `Mat4::to_scale_rotation_translation` for extracting scale, rotation and - translation from a 4x4 homogeneous transformation matrix. -* Added `cargo-deny` GitHub Action. - -### Changed -* Renamed `Quat::new` to `Quat::from_xyzw`. - -## [0.8.3] - 2019-11-27 - -### Added -* Added `Mat4::orthographic_rh_gl`. - -### Changed -* Renamed `Mat4::perspective_glu_rh` to `Mat4::perspective_rh_gl`. -* SSE2 optimizations for `Mat2::determinant`, `Mat2::inverse`, - `Mat2::transpose`, `Mat3::transpose`, `Quat::conjugate`, `Quat::lerp`, - `Quat::mul_vec3`, `Quat::mul_quat` and `Quat::from_rotation_ypr`. -* Disabled optimizations to `Mat4::transform_point3` and - `Mat4::transform_vector3` as they are probably incorrect and need - investigating. -* Added missing `#[repr(C)]` to `Mat2`, `Mat3` and `Mat4`. -* Benchmarks now store output of functions to better estimate the cost of a - function call. - -### Removed -* Removed deprecated functions `Mat2::new`, `Mat3::new` and `Mat4::new`. - -## [0.8.2] - 2019-11-06 -### Changed -* `glam_assert!` is no longer enabled by default in debug builds, it can be - enabled in any configuration using the `glam-assert` feature or in debug - builds only using the `debug-glam-assert` feature. -### Removed -* `glam_assert!`'s checking `lerp` is bounded between 0.0 and 1.0 and that - matrix scales are non-zero have been removed. - -## [0.8.1] - 2019-11-03 -### Added -* Added `Display` trait implementations for `Mat2`, `Mat3` and `Mat4`. - -### Changed -* Disabled `glam`'s SSE2 `sin_cos` implementation - it became less precise for - large angle values. -* Reduced the default epsilon used by the `is_normalized!` macro from - `std::f32::EPSILON` to `1e-6`. - -## [0.8.0] - 2019-10-14 -### Removed -* Removed the `approx` crate dependency. Each `glam` type has an `abs_diff_eq` - method added which is used by unit tests for approximate floating point - comparisons. -* Removed the `Angle` type. All angles are now `f32` and are expected to - be in radians. -* Removed the deprecated `Vec2b`, `Vec3b` and `Vec4b` types and the `mask` - methods on `Vec2Mask`, `Vec3Mask` and `Vec4Mask`. - -### Changed -* The `rand` crate dependency has been removed from default features. This was - required for benchmarking but a simple random number generator has been added - to the benches `support` module instead. -* The `From` trait implementation converting between 1D and 2D `f32` arrays and - matrix types have been removed. It was ambiguous how array data would map to - matrix columns so these have been replaced with explicit methods - `from_cols_array` and `from_cols_array_2d`. -* Matrix `new` methods have been renamed to `from_cols` to be consistent with - the other methods that create matrices from data. -* Renamed `Mat4::perspective_glu` to `Mat4::perspective_glu_rh`. - -## [0.7.2] - 2019-09-22 -### Fixed -* Fixed incorrect projection matrix methods `Mat4::look_at_lh` - and `Mat4::look_at_rh`. -### Added -* Added support for building infinite projection matrices, including both - standard and reverse depth `Mat4::perspective_infinite_rh` and - `Mat4::perspective_infinite_rh`. -* Added `Vec2Mask::new`, `Vec3Mask::new` and `Vec4Mask::new` methods. -* Implemented `std::ops` `BitAnd`, `BitAndAssign`, `BitOr`, `BitOrAssign` - and `Not` traits for `Vec2Mask`, `Vec3Mask` and `Vec4Mask`. -* Added method documentation for `Vec4` and `Vec4Mask` types. -* Added missing `serde` implementations for `Mat2`, `Mat3` and `Mat4`. -* Updated `rand` and `criterion` versions. - -## [0.7.1] - 2019-07-08 -### Fixed -* The SSE2 implementation of `Vec4` `dot` was missing a shuffle, meaning the - `dot`, `length`, `length_squared`, `length_reciprocal` and `normalize` - methods were sometimes incorrect. -### Added -* Added the `glam_assert` macro which behaves like Rust's `debug_assert` but - can be enabled separately to `debug_assert`. This is used to perform - asserts on correctness. -* Added `is_normalized` method to `Vec2`, `Vec3` and `Vec4`. -### Changed -* Replaced usage of `std::mem::uninitialized` with `std::mem::MaybeUninit`. This - change requires stable Rust 1.36. -* Renamed `Vec2b` to `Vec2Mask`, `Vec3b` to `Vec3Mask` and `Vec4b` to - `Vec4Mask`. Old names are aliased to the new name and deprecated. -* Deprecate `VecNMask` `mask` method, use new `bitmask` method instead -* Made fallback version of `VecNMask` types the same size and alignment as the - SIMD versions. -* Added `Default` support to `VecNMask` types, will add more common traits in - the future. -* Added `#[inline]` to `mat2`, `mat3` and `mat4` functions. - -## [0.7.0] - 2019-06-28 -### Added -* Added `Mat2` into `[f32; 4]`, `Mat3` into `[f32; 9]` and `Mat4` into - `[f32; 16]`. -### Changed -* Removed `impl Mul<&Vec2> for Mat2` and `impl Mul<&Vec3> for Vec3` as these - don't exist for any other types. - -## [0.6.1] - 2019-06-22 -### Changed -* `Mat2` now uses a `Vec4` internally which gives it some performance - improvements when SSE2 is available. - -## 0.6.0 - 2019-06-13 -### Changed -* Switched from row vectors to column vectors - * Vectors are now on the right of multiplications with matrices and quaternions. - - -[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.8.7...HEAD -[0.8.7]: https://github.com/bitshifter/glam-rs/compare/0.8.6...0.8.7 -[0.8.6]: https://github.com/bitshifter/glam-rs/compare/0.8.5...0.8.6 -[0.8.5]: https://github.com/bitshifter/glam-rs/compare/0.8.4...0.8.5 -[0.8.4]: https://github.com/bitshifter/glam-rs/compare/0.8.3...0.8.4 -[0.8.3]: https://github.com/bitshifter/glam-rs/compare/0.8.2...0.8.3 -[0.8.2]: https://github.com/bitshifter/glam-rs/compare/0.8.1...0.8.2 -[0.8.1]: https://github.com/bitshifter/glam-rs/compare/0.8.0...0.8.1 -[0.8.0]: https://github.com/bitshifter/glam-rs/compare/0.7.2...0.8.0 -[0.7.2]: https://github.com/bitshifter/glam-rs/compare/0.7.1...0.7.2 -[0.7.1]: https://github.com/bitshifter/glam-rs/compare/0.7.0...0.7.1 -[0.7.0]: https://github.com/bitshifter/glam-rs/compare/0.6.1...0.7.0 -[0.6.1]: https://github.com/bitshifter/glam-rs/compare/0.6.0...0.6.1 diff --git a/crates/bevy_glam/CONTRIBUTING.md b/crates/bevy_glam/CONTRIBUTING.md deleted file mode 100644 index 08782d9f5e..0000000000 --- a/crates/bevy_glam/CONTRIBUTING.md +++ /dev/null @@ -1,50 +0,0 @@ -Thanks for contributing to `glam`! These guidelines will try make the process -painless and efficient. - -The short guide to contributing is [open a github issue]. Pull requests are -welcome for bug fixes, documentation improvements and optimizations. For -anything else it would be best to discuss it first. - -# Questions - -If you have a question about the usage of this library please -[open a github issue]. That's the easiest way to get support right now. - -# Bugs - -If you find a bug please [open a github issue] or submit a pull request. A unit -test for any bug that slipped through existing coverage would also be greatly -appreciated. - -# New functions and methods - -If `glam` is missing functionality on existing types, [open a github issue] -describing what feature you would like added and ideally what your use case is -for it just so I have a better understanding of the feature. I'd like to keep -`glam` reasonably light functionality wise initially but commonly used -functionality that is missing is very welcome. If you do submit a pull request -please ensure any new functionality also has a test. - -# New types - -If you would like to add a new type to `glam` please [open a github issue]. Only -`f32` has been supported for now but long term I'd like to support people with -other needs. I am interested in what types you feel you need and what you would -use them for. Examples might be `i32` or `f64` vectors or generic types. I don't -want to rush to support new types until the API has stabilised a bit more but it -would be good to collect information on functionality people would like to see -in `glam`. - -# Optimizations - -If you feel some functionality could be optimized please [open a github issue] -or submit a pull request. Any optimization pull request should include a -benchmark if there isn't one already so I can confirm the performance -improvement. - -# Documentation - -If you feel any documentation could be added or improved please -[open a github issue] or submit a pull request. - -[open a github issue]: https://github.com/bitshifter/glam-rs/issues diff --git a/crates/bevy_glam/Cargo.toml b/crates/bevy_glam/Cargo.toml deleted file mode 100644 index 6f697afb20..0000000000 --- a/crates/bevy_glam/Cargo.toml +++ /dev/null @@ -1,83 +0,0 @@ -[package] -name = "glam" -version = "0.8.7" # remember to update html_root_url -edition = "2018" -authors = ["Cameron Hart "] -description = "A simple and fast 3D math library for games and graphics" -repository = "https://github.com/bitshifter/glam-rs" -readme = "README.md" -license = "MIT OR Apache-2.0" -keywords = ["gamedev", "math", "matrix", "vector", "quaternion"] -categories = ["game-engines"] -build = "build.rs" - -[badges] -travis-ci = { repository = "bitshifter/glam-rs" } -coveralls = { repository = "bitshifter/glam-rs" } -maintenance = { status = "experimental" } - -[features] -default = ["std"] - -# enable support for the standard library -std = [] - -# enable additional glam checks if debug assertions are enabled -debug-glam-assert = [] -# always enable additional glam checks -glam-assert = [] - -# opt out of Vec3 and Mat3 using SIMD (and thus being 16 byte aligned) -packed-vec3 = [] - -# this is primarily for testing the fallback implementation -scalar-math = [] - -# trying out transform types instead of matrices but they are generally slower -# at everything except for inverse. They are 16 bytes smaller than a Mat4. -transform-types = [] - -[dependencies] -mint = { version = "0.5", optional = true, default-features = false } -rand = { version = "0.7", optional = true, default-features = false } -serde = { version = "1.0", optional = true, features = ["derive"] } -zerocopy = { version = "0.3.0" } - -[dev-dependencies] -criterion = "0.3" -# rand_xoshiro is required for tests if rand is enabled -rand_xoshiro = "0.4" -serde_json = "1.0" - -[[bench]] -name = "mat2" -harness = false - -[[bench]] -name = "mat3" -harness = false - -[[bench]] -name = "mat4" -harness = false - -[[bench]] -name = "quat" -harness = false - -[[bench]] -name = "transform" -harness = false -required-features = ["transform-types"] - -[[bench]] -name = "vec2" -harness = false - -[[bench]] -name = "vec3" -harness = false - -[[bench]] -name = "vec4" -harness = false diff --git a/crates/bevy_glam/LICENSE-APACHE b/crates/bevy_glam/LICENSE-APACHE deleted file mode 100644 index 301f1f0eee..0000000000 --- a/crates/bevy_glam/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright 2020 Cameron Hart - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/crates/bevy_glam/LICENSE-MIT b/crates/bevy_glam/LICENSE-MIT deleted file mode 100644 index 31aa79387f..0000000000 --- a/crates/bevy_glam/LICENSE-MIT +++ /dev/null @@ -1,23 +0,0 @@ -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/crates/bevy_glam/README.md b/crates/bevy_glam/README.md deleted file mode 100644 index 1b2c6bcf43..0000000000 --- a/crates/bevy_glam/README.md +++ /dev/null @@ -1,163 +0,0 @@ -# glam - -[![Build Status]][travis-ci] [![Coverage Status]][coveralls.io] -[![Latest Version]][crates.io] [![docs]][docs.rs] - -A simple and fast 3D math library for games and graphics. - -## Development status - -`glam` is in alpha stage. Minimal base functionality has been implemented -and the look and feel of the API has solidified. - -## Features - -* Only single precision floating point (`f32`) arithmetic is supported -* vectors: `Vec2`, `Vec3`, `Vec4` -* square matrices: `Mat2`, `Mat3`, `Mat4` -* a quaternion type: `Quat` - -### SIMD - -The `Vec3`, `Vec4` and `Quat` types use SSE2 on x86/x86_64 architectures. -`Mat2`, `Mat3` and `Mat4` also use SSE2 for some functionality. Not everything -has a SIMD implementation yet. - -Note that this does result in some wasted space in the case of `Vec3` and `Mat3` -as the SIMD vector type is 16 bytes large and 16 byte aligned. - -It is possible to opt out of using SIMD types for Vec3 and Mat3 storage with the -`packed-vec3` feature. - -`glam` outperforms similar Rust libraries such as [`cgmath`][cgmath], -[`nalgebra-glm`][nalgebra-glm] and others for common operations as tested by the -[`mathbench`][mathbench] project. - -If you are more concerned with size than speed you can build glam with the -feature `scalar-math` enabled to disable SIMD usage. - -Due to the use of SIMD, vector elements may only be get and set via accessor -methods, e.g. `Vec3::x()` and `Vec3::x_mut()` or `Vec3::set_x()`. If getting or -setting more than one element it is more efficient to convert from tuples or -arrays: - -``` -let (x, y, z) = v.into(); -let [x, y, z]: [f32; 3] = v.into(); -``` - -### Optional features - -* `mint` - for interoperating with other 3D math libraries -* `rand` - implementations of `Distribution` trait for all `glam` types. This - is primarily used for unit testing -* `serde` - implementations of `Serialize` and `Deserialize` for all `glam` - types. Note that serialization should work between builds of `glam` with and - without SIMD enabled - -### Feature gates - -* `packed-vec3` - disable using SIMD types for `Vec3` and `Mat3` storage. This - avoids wasting space due to 16 byte alignment at the cost of some performance. -* `scalar-math` - compiles with SIMD support disabled -* `glam-assert` - adds assertions which check the validity of parameters passed to - `glam` to help catch runtime errors - -## Conventions - -### Column vectors - -`glam` interprets vectors as column matrices (also known as "column vectors") -meaning when transforming a vector with a matrix the matrix goes on the left, -e.g. `v' = Mv`. DirectX uses row vectors, OpenGL uses column vectors. There -are pros and cons to both. - -### Column-major order - -Matrices are stored in column major format. Each column vector is stored in -contiguous memory. - -### Co-ordinate system - -`glam` is co-ordinate system agnostic and intends to support both right handed -and left handed conventions. - -Rotations follow the left-hand rule. - -## Design Philosophy - -The design of this library is guided by a desire for simplicity and good -performance. - -* No traits or generics for simplicity of implementation and usage -* Only single precision floating point (`f32`) arithmetic is supported -* All dependencies are optional (e.g. `mint`, `rand` and `serde`) -* Follows the [Rust API Guidelines] where possible -* Aiming for 100% test [coverage][coveralls.io] -* Common functionality is benchmarked using [Criterion.rs] - -## Future work - -* Experiment with a using a 4x3 matrix as a 3D transform type that can be more - efficient than `Mat4` for certain operations like inverse and multiplies -* `no-std` support -* `wasm` support - -## Inspirations - -There were many inspirations for the interface and internals of glam from the -Rust and C++ worlds. In particular: - -* [How to write a maths library in 2016] inspired the initial `Vec3` - implementation -* [Realtime Math] - header only C++11 with SSE and NEON SIMD intrinsic support -* [DirectXMath] - header only SIMD C++ linear algebra library for use in games - and graphics apps -* `glam` is a play on the name of the popular C++ library `glm` - -## License - -Licensed under either of - -* Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) - or http://www.apache.org/licenses/LICENSE-2.0) -* MIT license ([LICENSE-MIT](LICENSE-MIT) - or http://opensource.org/licenses/MIT) - -at your option. - -## Contribution - -Contributions in any form (issues, pull requests, etc.) to this project must -adhere to Rust's [Code of Conduct]. - -Unless you explicitly state otherwise, any contribution intentionally submitted -for inclusion in the work by you, as defined in the Apache-2.0 license, shall be -dual licensed as above, without any additional terms or conditions. - -Thank you to all of the `glam` [contributors]! - -## Support -If you are interested in contributing or have a request or suggestion -[create an issue] on github. - - -[Build Status]: https://travis-ci.org/bitshifter/glam-rs.svg?branch=master -[travis-ci]: https://travis-ci.org/bitshifter/glam-rs -[Coverage Status]: https://coveralls.io/repos/github/bitshifter/glam-rs/badge.svg?branch=master -[coveralls.io]: https://coveralls.io/github/bitshifter/glam-rs?branch=master -[Code of Conduct]: https://www.rust-lang.org/en-US/conduct.html -[Latest Version]: https://img.shields.io/crates/v/glam.svg -[crates.io]: https://crates.io/crates/glam/ -[docs]: https://docs.rs/glam/badge.svg -[docs.rs]: https://docs.rs/glam/ -[Rust API Guidelines]: https://rust-lang-nursery.github.io/api-guidelines/ -[Criterion.rs]: https://bheisler.github.io/criterion.rs/book/index.html -[cgmath]: https://github.com/rustgd/cgmath -[nalgebra-glm]: https://github.com/rustsim/nalgebra -[mathbench]: https://github.com/bitshifter/mathbench-rs -[create an issue]: https://github.com/bitshifter/glam-rs/issues -[contributors]: https://github.com/bitshifter/glam-rs/graphs/contributors -[How to write a maths library in 2016]: http://www.codersnotes.com/notes/maths-lib-2016/ -[Realtime Math]: https://github.com/nfrechette/rtm -[DirectXMath]: https://docs.microsoft.com/en-us/windows/desktop/dxmath/directxmath-portal diff --git a/crates/bevy_glam/benches/mat2.rs b/crates/bevy_glam/benches/mat2.rs deleted file mode 100644 index 4ad4dd31a8..0000000000 --- a/crates/bevy_glam/benches/mat2.rs +++ /dev/null @@ -1,34 +0,0 @@ -#[path = "support/macros.rs"] -#[macro_use] -mod macros; -mod support; - -use criterion::{criterion_group, criterion_main, Criterion}; -use std::ops::Mul; -use support::*; - -bench_unop!( - mat2_transpose, - "mat2 transpose", - op => transpose, - from => random_mat2 -); -bench_unop!( - mat2_determinant, - "mat2 determinant", - op => determinant, - from => random_mat2 -); -bench_unop!(mat2_inverse, "mat2 inverse", op => inverse, from => random_mat2); -bench_binop!(mat2_mul_mat2, "mat2 * mat2", op => mul, from => random_mat2); - -criterion_group!( - benches, - mat2_transpose, - mat2_determinant, - mat2_inverse, - // mat2_mul_op_mat2, - mat2_mul_mat2, -); - -criterion_main!(benches); diff --git a/crates/bevy_glam/benches/mat3.rs b/crates/bevy_glam/benches/mat3.rs deleted file mode 100644 index 96a8c2b3f8..0000000000 --- a/crates/bevy_glam/benches/mat3.rs +++ /dev/null @@ -1,36 +0,0 @@ -#[path = "support/macros.rs"] -#[macro_use] -mod macros; -mod support; - -use criterion::{criterion_group, criterion_main, Criterion}; -use glam::Mat3; -use std::ops::Mul; -use support::*; - -bench_unop!( - mat3_transpose, - "mat3 transpose", - op => transpose, - from => random_mat3 -); -bench_unop!( - mat3_determinant, - "mat3 determinant", - op => determinant, - from => random_mat3 -); -bench_unop!(mat3_inverse, "mat3 inverse", op => inverse, from => random_mat3); -bench_binop!(mat3_mul_mat3, "mat3 * mat3", op => mul, from => random_mat3); -bench_from_ypr!(mat3_from_ypr, "mat3 from ypr", ty => Mat3); - -criterion_group!( - benches, - mat3_transpose, - mat3_determinant, - mat3_inverse, - mat3_mul_mat3, - mat3_from_ypr, -); - -criterion_main!(benches); diff --git a/crates/bevy_glam/benches/mat4.rs b/crates/bevy_glam/benches/mat4.rs deleted file mode 100644 index e5d580a03e..0000000000 --- a/crates/bevy_glam/benches/mat4.rs +++ /dev/null @@ -1,36 +0,0 @@ -#[path = "support/macros.rs"] -#[macro_use] -mod macros; -mod support; - -use criterion::{criterion_group, criterion_main, Criterion}; -use glam::Mat4; -use std::ops::Mul; -use support::*; - -bench_unop!( - mat4_transpose, - "mat4 transpose", - op => transpose, - from => random_srt_mat4 -); -bench_unop!( - mat4_determinant, - "mat4 determinant", - op => determinant, - from => random_srt_mat4 -); -bench_unop!(mat4_inverse, "mat4 inverse", op => inverse, from => random_srt_mat4); -bench_binop!(mat4_mul_mat4, "mat4 * mat4", op => mul, from => random_srt_mat4); -bench_from_ypr!(mat4_from_ypr, "mat4 from ypr", ty => Mat4); - -criterion_group!( - benches, - mat4_transpose, - mat4_determinant, - mat4_inverse, - mat4_mul_mat4, - mat4_from_ypr, -); - -criterion_main!(benches); diff --git a/crates/bevy_glam/benches/quat.rs b/crates/bevy_glam/benches/quat.rs deleted file mode 100644 index 3c6d40860e..0000000000 --- a/crates/bevy_glam/benches/quat.rs +++ /dev/null @@ -1,62 +0,0 @@ -#[path = "support/macros.rs"] -#[macro_use] -mod macros; -mod support; - -use criterion::{criterion_group, criterion_main, Criterion}; -use glam::Quat; -use std::ops::Mul; -use support::{random_f32, random_quat, random_radians}; - -bench_unop!( - quat_conjugate, - "quat conjugate", - op => conjugate, - from => random_quat -); - -bench_binop!( - quat_mul_quat, - "quat * quat", - op => mul, - from => random_quat -); - -bench_binop!( - quat_dot, - "quat dot", - op => dot, - from => random_quat -); - -bench_trinop!( - quat_lerp, - "quat lerp", - op => lerp, - from1 => random_quat, - from2 => random_quat, - from3 => random_f32 -); - -bench_trinop!( - quat_slerp, - "quat slerp", - op => slerp, - from1 => random_quat, - from2 => random_quat, - from3 => random_f32 -); - -bench_from_ypr!(quat_from_ypr, "quat from ypr", ty => Quat); - -criterion_group!( - benches, - quat_conjugate, - quat_dot, - quat_lerp, - quat_slerp, - quat_mul_quat, - quat_from_ypr -); - -criterion_main!(benches); diff --git a/crates/bevy_glam/benches/support/macros.rs b/crates/bevy_glam/benches/support/macros.rs deleted file mode 100644 index a63f5fa315..0000000000 --- a/crates/bevy_glam/benches/support/macros.rs +++ /dev/null @@ -1,180 +0,0 @@ -#[macro_export] -macro_rules! bench_func { - ($name: ident, $desc: expr, op => $func: ident, from => $from: expr) => { - pub(crate) fn $name(c: &mut Criterion) { - const SIZE: usize = 1 << 13; - let mut rng = support::PCG32::default(); - let inputs = - criterion::black_box((0..SIZE).map(|_| $from(&mut rng)).collect::>()); - // pre-fill output vector with some random value - let mut outputs = vec![$func($from(&mut rng)); SIZE]; - let mut i = 0; - c.bench_function($desc, |b| { - b.iter(|| { - i = (i + 1) & (SIZE - 1); - unsafe { - *outputs.get_unchecked_mut(i) = $func(*inputs.get_unchecked(i)); - } - }) - }); - criterion::black_box(outputs); - } - }; -} - -#[macro_export] -macro_rules! bench_unop { - ($name: ident, $desc: expr, op => $unop: ident, from => $from: expr) => { - pub(crate) fn $name(c: &mut Criterion) { - const SIZE: usize = 1 << 13; - let mut rng = support::PCG32::default(); - let inputs = - criterion::black_box((0..SIZE).map(|_| $from(&mut rng)).collect::>()); - // pre-fill output vector with some random value - let mut outputs = vec![$from(&mut rng).$unop(); SIZE]; - let mut i = 0; - c.bench_function($desc, |b| { - b.iter(|| { - i = (i + 1) & (SIZE - 1); - unsafe { - *outputs.get_unchecked_mut(i) = inputs.get_unchecked(i).$unop(); - } - }) - }); - criterion::black_box(outputs); - } - }; -} - -#[macro_export] -macro_rules! bench_binop { - ($name: ident, $desc: expr, op => $binop: ident, from1 => $from1:expr, from2 => $from2:expr) => { - pub(crate) fn $name(c: &mut Criterion) { - const SIZE: usize = 1 << 13; - let mut rng = support::PCG32::default(); - let inputs1 = - criterion::black_box((0..SIZE).map(|_| $from1(&mut rng)).collect::>()); - let inputs2 = - criterion::black_box((0..SIZE).map(|_| $from2(&mut rng)).collect::>()); - // pre-fill output vector with some random value - let mut outputs = vec![$from1(&mut rng).$binop($from2(&mut rng)); SIZE]; - let mut i = 0; - c.bench_function($desc, |b| { - b.iter(|| { - i = (i + 1) & (SIZE - 1); - unsafe { - *outputs.get_unchecked_mut(i) = inputs1.get_unchecked(i).$binop(*inputs2.get_unchecked(i)); - } - }) - }); - criterion::black_box(outputs); - } - }; - ($name: ident, $desc: expr, op => $binop: ident, from => $from: expr) => { - bench_binop!($name, $desc, op => $binop, from1 => $from, from2 => $from); - }; -} - -#[macro_export] -macro_rules! bench_trinop { - ($name: ident, $desc: expr, op => $trinop: ident, from1 => $from1:expr, from2 => $from2:expr, from3 => $from3:expr) => { - pub(crate) fn $name(c: &mut Criterion) { - const SIZE: usize = 1 << 13; - let mut rng = support::PCG32::default(); - let inputs1 = - criterion::black_box((0..SIZE).map(|_| $from1(&mut rng)).collect::>()); - let inputs2 = - criterion::black_box((0..SIZE).map(|_| $from2(&mut rng)).collect::>()); - let inputs3 = - criterion::black_box((0..SIZE).map(|_| $from3(&mut rng)).collect::>()); - // pre-fill output vector with some random value - let mut outputs = - vec![$from1(&mut rng).$trinop($from2(&mut rng), $from3(&mut rng)); SIZE]; - let mut i = 0; - c.bench_function($desc, |b| { - b.iter(|| { - i = (i + 1) & (SIZE - 1); - unsafe { - *outputs.get_unchecked_mut(i) = inputs1 - .get_unchecked(i) - .$trinop(*inputs2.get_unchecked(i), *inputs3.get_unchecked(i)); - } - }) - }); - criterion::black_box(outputs); - } - }; -} - -#[macro_export] -macro_rules! bench_from_ypr { - ($name: ident, $desc: expr, ty => $ty:ty) => { - pub(crate) fn $name(c: &mut Criterion) { - const SIZE: usize = 1 << 13; - let mut rng = support::PCG32::default(); - let inputs = criterion::black_box( - (0..SIZE) - .map(|_| { - ( - random_radians(&mut rng), - random_radians(&mut rng), - random_radians(&mut rng), - ) - }) - .collect::>(), - ); - let mut outputs = vec![<$ty>::default(); SIZE]; - let mut i = 0; - c.bench_function($desc, |b| { - b.iter(|| { - i = (i + 1) & (SIZE - 1); - unsafe { - let data = inputs.get_unchecked(i); - *outputs.get_unchecked_mut(i) = - <$ty>::from_rotation_ypr(data.0, data.1, data.2) - } - }) - }); - } - }; -} - -#[macro_export] -macro_rules! euler { - ($name: ident, $desc: expr, ty => $t: ty, storage => $storage: ty, zero => $zero: expr, rand => $rand: ident) => { - pub(crate) fn $name(c: &mut Criterion) { - const UPDATE_RATE: f32 = 1.0 / 60.0; - const NUM_OBJECTS: usize = 10000; - - struct TestData { - acc: Vec<$storage>, - vel: Vec<$storage>, - pos: Vec<$storage>, - } - - let mut rng = support::PCG32::default(); - let mut data = TestData { - acc: vec![$rand(&mut rng); NUM_OBJECTS], - vel: vec![$zero; NUM_OBJECTS], - pos: vec![$zero; NUM_OBJECTS], - }; - let dt = <$t>::splat(UPDATE_RATE); - - c.bench_function($desc, |b| { - b.iter(|| { - for ((position, acceleration), velocity) in - data.pos.iter_mut().zip(&data.acc).zip(&mut data.vel) - { - let local_acc: $t = (*acceleration).into(); - let mut local_pos: $t = (*position).into(); - let mut local_vel: $t = (*velocity).into(); - local_vel += local_acc * dt; - local_pos += local_vel * dt; - *velocity = local_vel.into(); - *position = local_pos.into(); - } - }) - }); - } - }; -} diff --git a/crates/bevy_glam/benches/support/mod.rs b/crates/bevy_glam/benches/support/mod.rs deleted file mode 100644 index a536fb7cf1..0000000000 --- a/crates/bevy_glam/benches/support/mod.rs +++ /dev/null @@ -1,96 +0,0 @@ -#![allow(dead_code)] -use core::f32; -use glam::f32::{Mat2, Mat3, Mat4, Quat, Vec2, Vec3, Vec4}; - -pub struct PCG32 { - state: u64, - inc: u64, -} - -impl PCG32 { - pub fn seed(initstate: u64, initseq: u64) -> Self { - let mut rng = PCG32 { - state: 0, - inc: (initseq << 1) | 1, - }; - rng.next_u32(); - rng.state = rng.state.wrapping_add(initstate); - rng.next_u32(); - rng - } - - pub fn default() -> Self { - PCG32::seed(0x853c49e6748fea9b, 0xda3e39cb94b95bdb) - } - - pub fn next_u32(&mut self) -> u32 { - let oldstate = self.state; - self.state = oldstate - .wrapping_mul(6364136223846793005) - .wrapping_add(self.inc | 1); - let xorshifted = ((oldstate >> 18) ^ oldstate) >> 27; - let rot = oldstate >> 59; - ((xorshifted >> rot) | (xorshifted << (rot.wrapping_neg() & 31))) as u32 - } - - pub fn next_f32(&mut self) -> f32 { - (self.next_u32() & 0xffffff) as f32 / 16777216.0 - } -} - -pub fn random_vec2(rng: &mut PCG32) -> Vec2 { - Vec2::new(rng.next_f32(), rng.next_f32()) -} - -pub fn random_vec3(rng: &mut PCG32) -> Vec3 { - Vec3::new(rng.next_f32(), rng.next_f32(), rng.next_f32()) -} - -pub fn random_vec4(rng: &mut PCG32) -> Vec4 { - Vec4::new( - rng.next_f32(), - rng.next_f32(), - rng.next_f32(), - rng.next_f32(), - ) -} - -pub fn random_nonzero_vec3(rng: &mut PCG32) -> Vec3 { - loop { - let v = random_vec3(rng); - if v.length_squared() > 0.01 { - return v; - } - } -} - -pub fn random_f32(rng: &mut PCG32) -> f32 { - rng.next_f32() -} - -pub fn random_radians(rng: &mut PCG32) -> f32 { - -f32::consts::PI + rng.next_f32() * 2.0 * f32::consts::PI -} - -pub fn random_quat(rng: &mut PCG32) -> Quat { - let yaw = random_radians(rng); - let pitch = random_radians(rng); - let roll = random_radians(rng); - Quat::from_rotation_ypr(yaw, pitch, roll) -} - -pub fn random_mat2(rng: &mut PCG32) -> Mat2 { - Mat2::from_cols(random_vec2(rng), random_vec2(rng)) -} - -pub fn random_mat3(rng: &mut PCG32) -> Mat3 { - Mat3::from_cols(random_vec3(rng), random_vec3(rng), random_vec3(rng)) -} - -pub fn random_srt_mat4(rng: &mut PCG32) -> Mat4 { - Mat4::from_scale_rotation_translation( - random_nonzero_vec3(rng), - random_quat(rng), - random_vec3(rng), - ) -} diff --git a/crates/bevy_glam/benches/transform.rs b/crates/bevy_glam/benches/transform.rs deleted file mode 100644 index 945a929154..0000000000 --- a/crates/bevy_glam/benches/transform.rs +++ /dev/null @@ -1,85 +0,0 @@ -#[path = "support/macros.rs"] -#[macro_use] -mod macros; -mod support; - -use criterion::{criterion_group, criterion_main, Criterion}; -use glam::f32::{TransformRT, TransformSRT}; -use std::ops::Mul; -use support::*; - -fn random_transform_srt(rng: &mut PCG32) -> TransformSRT { - TransformSRT::from_scale_rotation_translation( - random_nonzero_vec3(rng), - random_quat(rng), - random_vec3(rng), - ) -} - -fn random_transform_rt(rng: &mut PCG32) -> TransformRT { - TransformRT::from_rotation_translation(random_quat(rng), random_vec3(rng)) -} - -bench_unop!( - transform_srt_inverse, - "transform_srt inverse", - op => inverse, - from => random_transform_srt -); - -bench_binop!( - vec3_mul_transform_srt, - "transform_srt * vec3", - op => mul, - from1 => random_transform_srt, - from2 => random_vec3 -); - -bench_binop!( - vec3_mul_transform_rt, - "transform_rt * vec3", - op => mul, - from1 => random_transform_rt, - from2 => random_vec3 -); - -// bench_unop!( -// transform_srt_inverse_ptv_scale, -// "transform_srt inverse (+ve scale)", -// op => inverse, -// ty => TransformSRT, -// from => TransformRT -// ); -// bench_unop!( -// transform_rt_inverse, -// "transform_rt inverse", -// op => inverse, -// ty => TransformRT -// ); - -bench_binop!( - transform_srt_mul_srt, - "transform_srt * transform_srt", - op => mul, - from => random_transform_srt -); - -bench_binop!( - transform_rt_mul_rt, - "transform_rt * transform_rt", - op => mul, - from => random_transform_rt -); - -criterion_group!( - benches, - // transform_rt_inverse, - transform_srt_inverse, - // transform_srt_inverse_ptv_scale, - transform_rt_mul_rt, - transform_srt_mul_srt, - vec3_mul_transform_rt, - vec3_mul_transform_srt, -); - -criterion_main!(benches); diff --git a/crates/bevy_glam/benches/vec2.rs b/crates/bevy_glam/benches/vec2.rs deleted file mode 100644 index 6c93059cf9..0000000000 --- a/crates/bevy_glam/benches/vec2.rs +++ /dev/null @@ -1,31 +0,0 @@ -#[path = "support/macros.rs"] -#[macro_use] -mod macros; -mod support; - -use criterion::{criterion_group, criterion_main, Criterion}; -use glam::f32::Vec2; -use std::ops::Mul; -use support::{random_mat2, random_vec2}; - -euler!(vec2_euler, "vec2 euler", ty => Vec2, storage => Vec2, zero => Vec2::zero(), rand => random_vec2); - -bench_binop!( - mat2_mul_vec2, - "mat2 * vec2", - op => mul, - from1 => random_mat2, - from2 => random_vec2 -); - -bench_binop!( - vec2_angle_between, - "vec2 angle_between", - op => angle_between, - from1 => random_vec2, - from2 => random_vec2 -); - -criterion_group!(benches, vec2_euler, mat2_mul_vec2, vec2_angle_between); - -criterion_main!(benches); diff --git a/crates/bevy_glam/benches/vec3.rs b/crates/bevy_glam/benches/vec3.rs deleted file mode 100644 index 9a7b19ab32..0000000000 --- a/crates/bevy_glam/benches/vec3.rs +++ /dev/null @@ -1,98 +0,0 @@ -#[path = "support/macros.rs"] -#[macro_use] -mod macros; -mod support; - -use criterion::{criterion_group, criterion_main, Criterion}; -use glam::f32::Vec3; -use std::ops::Mul; -use support::{random_mat3, random_quat, random_vec3}; - -bench_binop!( - quat_mul_vec3, - "quat * vec3", - op => mul, - from1 => random_quat, - from2 => random_vec3 -); - -bench_binop!( - mat3_mul_vec3, - "mat3 * vec3", - op => mul, - from1 => random_mat3, - from2 => random_vec3 -); - -#[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() -} - -#[inline] -fn vec3_accessors(v: Vec3) -> [f32; 3] { - [v.x(), v.y(), v.z()] -} - -#[inline] -fn vec3_into_array(v: Vec3) -> [f32; 3] { - v.into() -} - -#[inline] -fn vec3_into_tuple(v: Vec3) -> (f32, f32, f32) { - v.into() -} - -bench_func!( -vec3_to_rgb, -"vec3 to rgb", -op => vec3_to_rgb_op, -from => random_vec3 -); - -bench_func!( -vec3_to_array_accessors, -"vec3 into array slow", -op => vec3_accessors, -from => random_vec3 -); - -bench_func!( -vec3_to_array_into, -"vec3 into array fast", -op => vec3_into_array, -from => random_vec3 -); - -bench_func!( -vec3_to_tuple_into, -"vec3 into tuple fast", -op => vec3_into_tuple, -from => random_vec3 -); - -euler!(vec3_euler, "vec3 euler", ty => Vec3, storage => Vec3, zero => Vec3::zero(), rand => random_vec3); - -bench_binop!( - vec3_angle_between, - "vec3 angle_between", - op => angle_between, - from1 => random_vec3, - from2 => random_vec3 -); - -criterion_group!( - benches, - quat_mul_vec3, - mat3_mul_vec3, - vec3_angle_between, - vec3_euler, - vec3_to_rgb, - vec3_to_array_accessors, - vec3_to_array_into, - vec3_to_tuple_into, -); - -criterion_main!(benches); diff --git a/crates/bevy_glam/benches/vec4.rs b/crates/bevy_glam/benches/vec4.rs deleted file mode 100644 index 2d905c0ace..0000000000 --- a/crates/bevy_glam/benches/vec4.rs +++ /dev/null @@ -1,20 +0,0 @@ -#[path = "support/macros.rs"] -#[macro_use] -mod macros; -mod support; - -use criterion::{criterion_group, criterion_main, Criterion}; -use std::ops::Mul; -use support::{random_srt_mat4, random_vec4}; - -bench_binop!( - vec4_mul_mat4, - "vec4 * mat4", - op => mul, - from1 => random_srt_mat4, - from2 => random_vec4 -); - -criterion_group!(benches, vec4_mul_mat4,); - -criterion_main!(benches); diff --git a/crates/bevy_glam/build.rs b/crates/bevy_glam/build.rs deleted file mode 100644 index 0982fbc33a..0000000000 --- a/crates/bevy_glam/build.rs +++ /dev/null @@ -1,29 +0,0 @@ -use std::env; - -fn main() { - let force_scalar_math = env::var("CARGO_FEATURE_SCALAR_MATH").is_ok(); - let force_packed_vec3 = env::var("CARGO_FEATURE_PACKED_VEC3").is_ok(); - - let target_feature_sse2 = env::var("CARGO_CFG_TARGET_FEATURE") - .map_or(false, |cfg| cfg.split(',').find(|&f| f == "sse2").is_some()); - - if target_feature_sse2 && !force_scalar_math && !force_packed_vec3 { - println!("cargo:rustc-cfg=vec3sse2"); - } else { - if !force_scalar_math && !force_packed_vec3 { - // simd not available but not explicitly disabled so maintain 16 byte alignment - println!("cargo:rustc-cfg=vec3f32_align16"); - } - println!("cargo:rustc-cfg=vec3f32"); - } - - if target_feature_sse2 && !force_scalar_math { - println!("cargo:rustc-cfg=vec4sse2"); - } else { - if !force_scalar_math { - // simd not available but not explicitly disabled so maintain 16 byte alignment - println!("cargo:rustc-cfg=vec4f32_align16"); - } - println!("cargo:rustc-cfg=vec4f32"); - } -} diff --git a/crates/bevy_glam/deny.toml b/crates/bevy_glam/deny.toml deleted file mode 100644 index a9cd9cb43b..0000000000 --- a/crates/bevy_glam/deny.toml +++ /dev/null @@ -1,18 +0,0 @@ -[bans] -multiple-versions = "deny" -deny = [] -skip-tree = [ - # ignore criterion dev-dependency that often have duplicate dependencies internally - { name = "criterion" }, -] - -[licenses] -unlicensed = "deny" -allow = [ - "Apache-2.0", - "BSD-2-Clause", - "BSD-3-Clause", - "ISC", - "MIT", - "MPL-2.0", -] diff --git a/crates/bevy_glam/src/f32/funcs.rs b/crates/bevy_glam/src/f32/funcs.rs deleted file mode 100644 index 90251bb02e..0000000000 --- a/crates/bevy_glam/src/f32/funcs.rs +++ /dev/null @@ -1,550 +0,0 @@ -#[inline] -pub(crate) fn scalar_sin_cos(x: f32) -> (f32, f32) { - // // expect sse2 to be available on all x86 builds - // #[cfg(target_feature = "sse2")] - // unsafe { - // let (sinx, cosx) = sin_cos_sse2(_mm_set1_ps(x)); - // (_mm_cvtss_f32(sinx), _mm_cvtss_f32(cosx)) - // } - // #[cfg(not(target_feature = "sse2"))] - x.sin_cos() -} - -#[inline] -pub fn scalar_acos(value: f32) -> f32 { - // from DirectXMath XMScalarAcos - // Clamp input to [-1,1]. - let nonnegative = value >= 0.0; - let x = value.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 - } -} - -#[cfg(vec4sse2)] -pub(crate) mod sse2 { - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - use crate::f32::x86_utils::UnionCast; - #[cfg(target_arch = "x86")] - use core::arch::x86::*; - #[cfg(target_arch = "x86_64")] - use core::arch::x86_64::*; - - macro_rules! _ps_const_ty { - ($name:ident, $field:ident, $x:expr) => { - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - const $name: UnionCast = UnionCast { - $field: [$x, $x, $x, $x], - }; - }; - - ($name:ident, $field:ident, $x:expr, $y:expr, $z:expr, $w:expr) => { - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - const $name: UnionCast = UnionCast { - $field: [$x, $y, $z, $w], - }; - }; - } - - _ps_const_ty!(PS_INV_SIGN_MASK, u32x4, !0x8000_0000); - _ps_const_ty!(PS_SIGN_MASK, u32x4, 0x8000_0000); - _ps_const_ty!(PS_NO_FRACTION, f32x4, 8388608.0); - - // _ps_const_ty!(PS_1_0, f32x4, 1.0); - // _ps_const_ty!(PS_0_5, f32x4, 0.5); - - // _ps_const_ty!(PI32_1, i32x4, 1); - // _ps_const_ty!(PI32_INV_1, i32x4, !1); - // _ps_const_ty!(PI32_2, i32x4, 2); - // _ps_const_ty!(PI32_4, i32x4, 4); - - // _ps_const_ty!(PS_MINUS_CEPHES_DP1, f32x4, -0.785_156_25); - // _ps_const_ty!(PS_MINUS_CEPHES_DP2, f32x4, -2.418_756_5e-4); - // _ps_const_ty!(PS_MINUS_CEPHES_DP3, f32x4, -3.774_895e-8); - // _ps_const_ty!(PS_SINCOF_P0, f32x4, -1.951_529_6e-4); - // _ps_const_ty!(PS_SINCOF_P1, f32x4, 8.332_161e-3); - // _ps_const_ty!(PS_SINCOF_P2, f32x4, -1.666_665_5e-1); - // _ps_const_ty!(PS_COSCOF_P0, f32x4, 2.443_315_7e-5); - // _ps_const_ty!(PS_COSCOF_P1, f32x4, -1.388_731_6E-3); - // _ps_const_ty!(PS_COSCOF_P2, f32x4, 4.166_664_6e-2); - // _ps_const_ty!(PS_CEPHES_FOPI, f32x4, 1.273_239_5); // 4 / M_PI - - _ps_const_ty!(PS_NEGATIVE_ZERO, u32x4, 0x80000000); - _ps_const_ty!(PS_PI, f32x4, core::f32::consts::PI); - _ps_const_ty!(PS_HALF_PI, f32x4, core::f32::consts::FRAC_PI_2); - _ps_const_ty!( - PS_SIN_COEFFICIENTS0, - f32x4, - -0.16666667, - 0.0083333310, - -0.00019840874, - 2.7525562e-06 - ); - _ps_const_ty!( - PS_SIN_COEFFICIENTS1, - f32x4, - -2.3889859e-08, - -0.16665852, /*Est1*/ - 0.0083139502, /*Est2*/ - -0.00018524670 /*Est3*/ - ); - _ps_const_ty!(PS_ONE, f32x4, 1.0); - _ps_const_ty!(PS_TWO_PI, f32x4, core::f32::consts::PI * 2.0); - _ps_const_ty!(PS_RECIPROCAL_TWO_PI, f32x4, 0.159154943); - - #[cfg(target_feature = "fma")] - macro_rules! m128_mul_add { - ($a:expr, $b:expr, $c:expr) => { - _mm_fmadd_ps($a, $b, $c) - }; - } - - #[cfg(not(target_feature = "fma"))] - macro_rules! m128_mul_add { - ($a:expr, $b:expr, $c:expr) => { - _mm_add_ps(_mm_mul_ps($a, $b), $c) - }; - } - - #[cfg(target_feature = "fma")] - macro_rules! m128_neg_mul_sub { - ($a:expr, $b:expr, $c:expr) => { - _mm_fnmadd_ps($a, $b, $c) - }; - } - - #[cfg(not(target_feature = "fma"))] - macro_rules! m128_neg_mul_sub { - ($a:expr, $b:expr, $c:expr) => { - _mm_sub_ps($c, _mm_mul_ps($a, $b)) - }; - } - - #[inline] - pub(crate) unsafe fn m128_round(v: __m128) -> __m128 { - // From DirectXMath XMVectorRound. - let sign = _mm_and_ps(v, PS_SIGN_MASK.m128); - let s_magic = _mm_or_ps(PS_NO_FRACTION.m128, 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.m128); - let mask = _mm_cmple_ps(r2, PS_NO_FRACTION.m128); - let r2 = _mm_andnot_ps(mask, v); - let r1 = _mm_and_ps(r1, mask); - _mm_xor_ps(r1, r2) - } - - #[inline] - pub(crate) unsafe fn m128_floor(v: __m128) -> __m128 { - // From DirectXMath XMVectorFloor - // To handle NAN, INF and numbers greater than 8388608, use masking - let test = _mm_and_si128(_mm_castps_si128(v), PS_INV_SIGN_MASK.m128i); - let test = _mm_cmplt_epi32(test, PS_NO_FRACTION.m128i); - // Truncate - let vint = _mm_cvttps_epi32(v); - let result = _mm_cvtepi32_ps(vint); - let larger = _mm_cmpgt_ps(result, v); - // 0 -> 0, 0xffffffff -> -1.0f - let larger = _mm_cvtepi32_ps(_mm_castps_si128(larger)); - let result = _mm_add_ps(result, larger); - // All numbers less than 8388608 will use the round to int - let result = _mm_and_ps(result, _mm_castsi128_ps(test)); - // All others, use the ORIGINAL value - let test = _mm_andnot_si128(test, _mm_castps_si128(v)); - _mm_or_ps(result, _mm_castsi128_ps(test)) - } - - #[inline] - pub(crate) unsafe fn m128_ceil(v: __m128) -> __m128 { - // From DirectXMath XMVectorCeil - // To handle NAN, INF and numbers greater than 8388608, use masking - let test = _mm_and_si128(_mm_castps_si128(v), PS_INV_SIGN_MASK.m128i); - let test = _mm_cmplt_epi32(test, PS_NO_FRACTION.m128i); - // Truncate - let vint = _mm_cvttps_epi32(v); - let result = _mm_cvtepi32_ps(vint); - let smaller = _mm_cmplt_ps(result, v); - // 0 -> 0, 0xffffffff -> -1.0f - let smaller = _mm_cvtepi32_ps(_mm_castps_si128(smaller)); - let result = _mm_sub_ps(result, smaller); - // All numbers less than 8388608 will use the round to int - let result = _mm_and_ps(result, _mm_castsi128_ps(test)); - // All others, use the ORIGINAL value - let test = _mm_andnot_si128(test, _mm_castps_si128(v)); - _mm_or_ps(result, _mm_castsi128_ps(test)) - } - - /// Returns a vector whose components are the corresponding components of Angles modulo 2PI. - #[inline] - pub(crate) unsafe fn m128_mod_angles(angles: __m128) -> __m128 { - // From DirectXMath: XMVectorModAngles - let v = _mm_mul_ps(angles, PS_RECIPROCAL_TWO_PI.m128); - let v = m128_round(v); - m128_neg_mul_sub!(PS_TWO_PI.m128, v, angles) - } - - /// Computes the sine of the angle in each lane of `v`. Values outside - /// the bounds of PI may produce an increasing error as the input angle - /// drifts from `[-PI, PI]`. - #[inline] - pub(crate) unsafe fn m128_sin(v: __m128) -> __m128 { - // From DirectXMath: XMVectorSin - // - // 11-degree minimax approximation - // - // Force the value within the bounds of pi - let mut x = m128_mod_angles(v); - - // Map in [-pi/2,pi/2] with sin(y) = sin(x). - let sign = _mm_and_ps(x, PS_NEGATIVE_ZERO.m128); - // pi when x >= 0, -pi when x < 0 - let c = _mm_or_ps(PS_PI.m128, sign); - // |x| - let absx = _mm_andnot_ps(sign, x); - let rflx = _mm_sub_ps(c, x); - let comp = _mm_cmple_ps(absx, PS_HALF_PI.m128); - let select0 = _mm_and_ps(comp, x); - let select1 = _mm_andnot_ps(comp, rflx); - x = _mm_or_ps(select0, select1); - - let x2 = _mm_mul_ps(x, x); - - // Compute polynomial approximation - const SC1: __m128 = unsafe { PS_SIN_COEFFICIENTS1.m128 }; - let v_constants_b = _mm_shuffle_ps(SC1, SC1, 0b00_00_00_00); - - const SC0: __m128 = unsafe { PS_SIN_COEFFICIENTS0.m128 }; - let mut v_constants = _mm_shuffle_ps(SC0, SC0, 0b11_11_11_11); - let mut result = m128_mul_add!(v_constants_b, x2, v_constants); - - v_constants = _mm_shuffle_ps(SC0, SC0, 0b10_10_10_10); - result = m128_mul_add!(result, x2, v_constants); - - v_constants = _mm_shuffle_ps(SC0, SC0, 0b01_01_01_01); - result = m128_mul_add!(result, x2, v_constants); - - v_constants = _mm_shuffle_ps(SC0, SC0, 0b00_00_00_00); - result = m128_mul_add!(result, x2, v_constants); - - result = m128_mul_add!(result, x2, PS_ONE.m128); - result = _mm_mul_ps(result, x); - - result - } - - // Based on http://gruntthepeon.free.fr/ssemath/sse_mathfun.h - // #[cfg(target_feature = "sse2")] - // unsafe fn sin_cos_sse2(x: __m128) -> (__m128, __m128) { - // let mut sign_bit_sin = x; - // // take the absolute value - // let mut x = _mm_and_ps(x, PS_INV_SIGN_MASK.m128); - // // extract the sign bit (upper one) - // sign_bit_sin = _mm_and_ps(sign_bit_sin, PS_SIGN_MASK.m128); - - // // scale by 4/Pi - // let mut y = _mm_mul_ps(x, PS_CEPHES_FOPI.m128); - - // // store the integer part of y in emm2 - // let mut emm2 = _mm_cvttps_epi32(y); - - // // j=(j+1) & (~1) (see the cephes sources) - // emm2 = _mm_add_epi32(emm2, PI32_1.m128i); - // emm2 = _mm_and_si128(emm2, PI32_INV_1.m128i); - // y = _mm_cvtepi32_ps(emm2); - - // let mut emm4 = emm2; - - // /* get the swap sign flag for the sine */ - // let mut emm0 = _mm_and_si128(emm2, PI32_4.m128i); - // emm0 = _mm_slli_epi32(emm0, 29); - // let swap_sign_bit_sin = _mm_castsi128_ps(emm0); - - // /* get the polynom selection mask for the sine*/ - // emm2 = _mm_and_si128(emm2, PI32_2.m128i); - // emm2 = _mm_cmpeq_epi32(emm2, _mm_setzero_si128()); - // let poly_mask = _mm_castsi128_ps(emm2); - - // /* The magic pass: "Extended precision modular arithmetic" - // x = ((x - y * DP1) - y * DP2) - y * DP3; */ - // let mut xmm1 = PS_MINUS_CEPHES_DP1.m128; - // let mut xmm2 = PS_MINUS_CEPHES_DP2.m128; - // let mut xmm3 = PS_MINUS_CEPHES_DP3.m128; - // xmm1 = _mm_mul_ps(y, xmm1); - // xmm2 = _mm_mul_ps(y, xmm2); - // xmm3 = _mm_mul_ps(y, xmm3); - // x = _mm_add_ps(x, xmm1); - // x = _mm_add_ps(x, xmm2); - // x = _mm_add_ps(x, xmm3); - - // emm4 = _mm_sub_epi32(emm4, PI32_2.m128i); - // emm4 = _mm_andnot_si128(emm4, PI32_4.m128i); - // emm4 = _mm_slli_epi32(emm4, 29); - // let sign_bit_cos = _mm_castsi128_ps(emm4); - - // sign_bit_sin = _mm_xor_ps(sign_bit_sin, swap_sign_bit_sin); - - // // Evaluate the first polynom (0 <= x <= Pi/4) - // let z = _mm_mul_ps(x, x); - // y = PS_COSCOF_P0.m128; - - // y = _mm_mul_ps(y, z); - // y = _mm_add_ps(y, PS_COSCOF_P1.m128); - // y = _mm_mul_ps(y, z); - // y = _mm_add_ps(y, PS_COSCOF_P2.m128); - // y = _mm_mul_ps(y, z); - // y = _mm_mul_ps(y, z); - // let tmp = _mm_mul_ps(z, PS_0_5.m128); - // y = _mm_sub_ps(y, tmp); - // y = _mm_add_ps(y, PS_1_0.m128); - - // // Evaluate the second polynom (Pi/4 <= x <= 0) - // let mut y2 = PS_SINCOF_P0.m128; - // y2 = _mm_mul_ps(y2, z); - // y2 = _mm_add_ps(y2, PS_SINCOF_P1.m128); - // y2 = _mm_mul_ps(y2, z); - // y2 = _mm_add_ps(y2, PS_SINCOF_P2.m128); - // y2 = _mm_mul_ps(y2, z); - // y2 = _mm_mul_ps(y2, x); - // y2 = _mm_add_ps(y2, x); - - // // select the correct result from the two polynoms - // xmm3 = poly_mask; - // let ysin2 = _mm_and_ps(xmm3, y2); - // let ysin1 = _mm_andnot_ps(xmm3, y); - // y2 = _mm_sub_ps(y2, ysin2); - // y = _mm_sub_ps(y, ysin1); - - // xmm1 = _mm_add_ps(ysin1, ysin2); - // xmm2 = _mm_add_ps(y, y2); - - // // update the sign - // ( - // _mm_xor_ps(xmm1, sign_bit_sin), - // _mm_xor_ps(xmm2, sign_bit_cos), - // ) - // } -} - -#[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!(scalar_acos(a), 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(|i| f32::from_bits(i)) - { - test_scalar_acos_angle(f); - } - for f in (0..=PTVE_ONE).step_by(STEP_SIZE).map(|i| f32::from_bits(i)) { - test_scalar_acos_angle(f); - } - - // input is clamped to -1.0..1.0 - assert_approx_eq!(scalar_acos(2.0), 0.0); - assert_approx_eq!(scalar_acos(-2.0), core::f32::consts::PI); -} - -#[test] -fn test_scalar_sin_cos() { - fn test_scalar_sin_cos_angle(a: f32) { - let (s1, c1) = scalar_sin_cos(a); - let (s2, c2) = a.sin_cos(); - dbg!(a); - assert_approx_eq!(s1, s2); - assert_approx_eq!(c1, c2); - } - - // test 1024 floats between -PI and PI inclusive - const MAX_TESTS: u32 = 1024 / 2; - const SIGN: u32 = 0x80_00_00_00; - let ptve_pi = core::f32::consts::PI.to_bits(); - let ngve_pi = SIGN | ptve_pi; - let step_pi = (ptve_pi / MAX_TESTS) as usize; - for f in (SIGN..=ngve_pi).step_by(step_pi).map(|i| f32::from_bits(i)) { - test_scalar_sin_cos_angle(f); - } - for f in (0..=ptve_pi).step_by(step_pi).map(|i| f32::from_bits(i)) { - test_scalar_sin_cos_angle(f); - } - - // test 1024 floats between -INF and +INF exclusive - let ptve_inf = core::f32::INFINITY.to_bits(); - let ngve_inf = core::f32::NEG_INFINITY.to_bits(); - let step_inf = (ptve_inf / MAX_TESTS) as usize; - for f in (SIGN..ngve_inf) - .step_by(step_inf) - .map(|i| f32::from_bits(i)) - { - test_scalar_sin_cos_angle(f); - } - for f in (0..ptve_inf).step_by(step_inf).map(|i| f32::from_bits(i)) { - test_scalar_sin_cos_angle(f); - } - - // +inf and -inf should return NaN - let (s, c) = scalar_sin_cos(core::f32::INFINITY); - assert!(s.is_nan()); - assert!(c.is_nan()); - - let (s, c) = scalar_sin_cos(core::f32::NEG_INFINITY); - assert!(s.is_nan()); - assert!(c.is_nan()); -} - -#[test] -#[cfg(vec4sse2)] -fn test_sse2_m128_sin() { - use crate::Vec4; - use core::f32::consts::PI; - - fn test_sse2_m128_sin_angle(a: f32) { - let v = Vec4::splat(a); - let v = unsafe { Vec4(sse2::m128_sin(v.0)) }; - let a_sin = a.sin(); - dbg!((a, a_sin, v)); - assert_approx_eq!(v.x(), a_sin, 1e-6); - assert_approx_eq!(v.z(), a_sin, 1e-6); - assert_approx_eq!(v.y(), a_sin, 1e-6); - assert_approx_eq!(v.w(), a_sin, 1e-6); - } - - let mut a = -PI; - let end = PI; - let step = PI / 8192.0; - - while a <= end { - test_sse2_m128_sin_angle(a); - a += step; - } -} - -// sse2::m128_sin is derived from the XMVectorSin in DirectXMath. It's been -// observed both here and in the C++ version that the error rate increases -// as the input angle drifts further from the bounds of PI. -// -// #[test] -// #[cfg(vec4sse2)] -// fn test_sse2_m128_sin2() { -// use crate::Vec4; - -// fn test_sse2_m128_sin_angle(a: f32) -> f32 { -// let v = Vec4::splat(a); -// let v = unsafe { Vec4(sse2::m128_sin(v.0)) }; -// let a_sin = a.sin(); -// let v_sin = v.x(); -// // println!("{:?}", (a, a_sin, v_sin)); -// assert_approx_eq!(a_sin, v.x(), 1e-4); -// assert_approx_eq!(a_sin, v.z(), 1e-4); -// assert_approx_eq!(a_sin, v.y(), 1e-4); -// assert_approx_eq!(a_sin, v.w(), 1e-4); -// v.x() -// } - -// // test 1024 floats between -PI and PI inclusive -// const MAX_TESTS: u32 = 1024 / 2; -// const SIGN: u32 = 0x80_00_00_00; -// let ptve_pi = std::f32::consts::PI.to_bits(); -// let ngve_pi = SIGN | ptve_pi; -// let step_pi = (ptve_pi / MAX_TESTS) as usize; -// for f in (SIGN..=ngve_pi).step_by(step_pi).map(|i| f32::from_bits(i)) { -// test_sse2_m128_sin_angle(f); -// } -// for f in (0..=ptve_pi).step_by(step_pi).map(|i| f32::from_bits(i)) { -// test_sse2_m128_sin_angle(f); -// } - -// // test 1024 floats between -INF and +INF exclusive -// let ptve_inf = std::f32::INFINITY.to_bits(); -// let ngve_inf = std::f32::NEG_INFINITY.to_bits(); -// let step_inf = (ptve_inf / MAX_TESTS) as usize; -// for f in (SIGN..ngve_inf) -// .step_by(step_inf) -// .map(|i| f32::from_bits(i)) -// { -// test_sse2_m128_sin_angle(f); -// } -// for f in (0..ptve_inf).step_by(step_inf).map(|i| f32::from_bits(i)) { -// test_sse2_m128_sin_angle(f); -// } - -// // +inf and -inf should return NaN -// let s = test_sse2_m128_sin_angle(std::f32::INFINITY); -// assert!(s.is_nan()); - -// let s = test_sse2_m128_sin_angle(std::f32::NEG_INFINITY); -// assert!(s.is_nan()); -// } diff --git a/crates/bevy_glam/src/f32/glam_mint.rs b/crates/bevy_glam/src/f32/glam_mint.rs deleted file mode 100644 index 350c595da1..0000000000 --- a/crates/bevy_glam/src/f32/glam_mint.rs +++ /dev/null @@ -1,309 +0,0 @@ -use super::{Mat2, Mat3, Mat4, Quat, Vec2, Vec3, Vec4}; -use mint; - -impl From> for Vec2 { - fn from(v: mint::Point2) -> Self { - Self::new(v.x, v.y) - } -} - -impl From for mint::Point2 { - fn from(v: Vec2) -> Self { - let (x, y) = v.into(); - Self { x, y } - } -} - -impl From> for Vec3 { - fn from(v: mint::Point3) -> Self { - Self::new(v.x, v.y, v.z) - } -} - -impl From for mint::Point3 { - fn from(v: Vec3) -> Self { - let (x, y, z) = v.into(); - Self { x, y, z } - } -} - -impl From> for Vec2 { - fn from(v: mint::Vector2) -> Self { - Self::new(v.x, v.y) - } -} - -impl From for mint::Vector2 { - fn from(v: Vec2) -> Self { - let (x, y) = v.into(); - Self { x, y } - } -} - -impl From> for Vec3 { - fn from(v: mint::Vector3) -> Self { - Self::new(v.x, v.y, v.z) - } -} - -impl From for mint::Vector3 { - fn from(v: Vec3) -> Self { - let (x, y, z) = v.into(); - Self { x, y, z } - } -} - -impl From> for Vec4 { - fn from(v: mint::Vector4) -> Self { - Self::new(v.x, v.y, v.z, v.w) - } -} - -impl From for mint::Vector4 { - fn from(v: Vec4) -> Self { - let (x, y, z, w) = v.into(); - Self { x, y, z, w } - } -} - -impl From> for Quat { - fn from(q: mint::Quaternion) -> Self { - Self::from_xyzw(q.v.x, q.v.y, q.v.z, q.s) - } -} - -impl From for mint::Quaternion { - fn from(q: Quat) -> Self { - let (x, y, z, s) = q.into(); - Self { - s, - v: mint::Vector3 { x, y, z }, - } - } -} - -impl From> for Mat2 { - fn from(m: mint::RowMatrix2) -> Self { - Self::from_cols(m.x.into(), m.y.into()).transpose() - } -} - -impl From for mint::RowMatrix2 { - fn from(m: Mat2) -> Self { - let mt = m.transpose(); - Self { - x: mt.x_axis().into(), - y: mt.y_axis().into(), - } - } -} - -impl From> for Mat2 { - fn from(m: mint::ColumnMatrix2) -> Self { - Self::from_cols(m.x.into(), m.y.into()) - } -} - -impl From for mint::ColumnMatrix2 { - fn from(m: Mat2) -> Self { - Self { - x: m.x_axis().into(), - y: m.y_axis().into(), - } - } -} - -impl From> for Mat3 { - fn from(m: mint::RowMatrix3) -> Self { - Self::from_cols(m.x.into(), m.y.into(), m.z.into()).transpose() - } -} - -impl From for mint::RowMatrix3 { - fn from(m: Mat3) -> Self { - let mt = m.transpose(); - Self { - x: mt.x_axis().into(), - y: mt.y_axis().into(), - z: mt.z_axis().into(), - } - } -} - -impl From> for Mat3 { - fn from(m: mint::ColumnMatrix3) -> Self { - Self::from_cols(m.x.into(), m.y.into(), m.z.into()) - } -} - -impl From for mint::ColumnMatrix3 { - fn from(m: Mat3) -> Self { - Self { - x: m.x_axis().into(), - y: m.y_axis().into(), - z: m.z_axis().into(), - } - } -} - -impl From> for Mat4 { - fn from(m: mint::RowMatrix4) -> Self { - Self::from_cols(m.x.into(), m.y.into(), m.z.into(), m.w.into()).transpose() - } -} - -impl From for mint::RowMatrix4 { - fn from(m: Mat4) -> Self { - let mt = m.transpose(); - Self { - x: mt.x_axis().into(), - y: mt.y_axis().into(), - z: mt.z_axis().into(), - w: mt.w_axis().into(), - } - } -} - -impl From> for Mat4 { - fn from(m: mint::ColumnMatrix4) -> Self { - Self::from_cols(m.x.into(), m.y.into(), m.z.into(), m.w.into()) - } -} - -impl From for mint::ColumnMatrix4 { - fn from(m: Mat4) -> Self { - Self { - x: m.x_axis().into(), - y: m.y_axis().into(), - z: m.z_axis().into(), - w: m.w_axis().into(), - } - } -} -#[cfg(test)] -mod test { - use mint; - - #[test] - fn test_point2() { - use crate::Vec2; - let m = mint::Point2 { x: 1.0, y: 2.0 }; - let g = Vec2::from(m); - assert_eq!(g, Vec2::new(1.0, 2.0)); - assert_eq!(m, g.into()); - } - - #[test] - fn test_point3() { - use crate::Vec3; - let m = mint::Point3 { - x: 1.0, - y: 2.0, - z: 3.0, - }; - let g = Vec3::from(m); - assert_eq!(g, Vec3::new(1.0, 2.0, 3.0)); - assert_eq!(m, g.into()); - } - - #[test] - fn test_vector2() { - use crate::Vec2; - let m = mint::Vector2 { x: 1.0, y: 2.0 }; - let g = Vec2::from(m); - assert_eq!(g, Vec2::new(1.0, 2.0)); - assert_eq!(m, g.into()); - } - - #[test] - fn test_vector3() { - use crate::Vec3; - let m = mint::Vector3 { - x: 1.0, - y: 2.0, - z: 3.0, - }; - let g = Vec3::from(m); - assert_eq!(g, Vec3::new(1.0, 2.0, 3.0)); - assert_eq!(m, g.into()); - } - - #[test] - fn test_vector4() { - use crate::Vec4; - let m = mint::Vector4 { - x: 1.0, - y: 2.0, - z: 3.0, - w: 4.0, - }; - let g = Vec4::from(m); - assert_eq!(g, Vec4::new(1.0, 2.0, 3.0, 4.0)); - assert_eq!(m, g.into()); - } - - #[test] - fn test_quaternion() { - use crate::Quat; - let m = mint::Quaternion { - v: mint::Vector3 { - x: 1.0, - y: 2.0, - z: 3.0, - }, - s: 4.0, - }; - let g = Quat::from(m); - assert_eq!(g, Quat::from((1.0, 2.0, 3.0, 4.0))); - assert_eq!(m, g.into()); - } - - #[test] - fn test_matrix2() { - use crate::Mat2; - let g = Mat2::from_cols_array_2d(&[[1.0, 2.0], [3.0, 4.0]]); - let m = mint::ColumnMatrix2::from(g); - assert_eq!(g, Mat2::from(m)); - let mt = mint::RowMatrix2::from(g); - assert_eq!(mt, mint::RowMatrix2::from([[1.0, 3.0], [2.0, 4.0]])); - assert_eq!(g, Mat2::from(mt)); - } - - #[test] - fn test_matrix3() { - use crate::Mat3; - let g = Mat3::from_cols_array_2d(&[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]]); - let m = mint::ColumnMatrix3::from(g); - assert_eq!(g, Mat3::from(m)); - let mt = mint::RowMatrix3::from(g); - assert_eq!( - mt, - mint::RowMatrix3::from([[1.0, 4.0, 7.0], [2.0, 5.0, 8.0], [3.0, 6.0, 9.0]]) - ); - assert_eq!(g, Mat3::from(mt)); - } - - #[test] - fn test_matrix4() { - use crate::Mat4; - let g = 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], - ]); - let m = mint::ColumnMatrix4::from(g); - assert_eq!(g, Mat4::from(m)); - let mt = mint::RowMatrix4::from(g); - assert_eq!( - mt, - mint::RowMatrix4::from([ - [1.0, 5.0, 9.0, 13.0], - [2.0, 6.0, 10.0, 14.0], - [3.0, 7.0, 11.0, 15.0], - [4.0, 8.0, 12.0, 16.0] - ]) - ); - assert_eq!(g, Mat4::from(mt)); - } -} diff --git a/crates/bevy_glam/src/f32/glam_rand.rs b/crates/bevy_glam/src/f32/glam_rand.rs deleted file mode 100644 index f923850431..0000000000 --- a/crates/bevy_glam/src/f32/glam_rand.rs +++ /dev/null @@ -1,59 +0,0 @@ -use super::{Mat2, Mat3, Mat4, Quat, Vec2, Vec3, Vec4}; - -use rand::{ - distributions::{Distribution, Standard}, - Rng, -}; - -impl Distribution for Standard { - #[inline] - fn sample(&self, rng: &mut R) -> Mat2 { - Mat2::from_cols_array(&rng.gen()) - } -} - -impl Distribution for Standard { - #[inline] - fn sample(&self, rng: &mut R) -> Mat3 { - Mat3::from_cols_array(&rng.gen()) - } -} - -impl Distribution for Standard { - #[inline] - fn sample(&self, rng: &mut R) -> Mat4 { - Mat4::from_cols_array(&rng.gen()) - } -} - -impl Distribution for Standard { - #[inline] - fn sample(&self, rng: &mut R) -> Quat { - use core::f32::consts::PI; - let yaw = -PI + rng.gen::() * 2.0 * PI; - let pitch = -PI + rng.gen::() * 2.0 * PI; - let roll = -PI + rng.gen::() * 2.0 * PI; - Quat::from_rotation_ypr(yaw, pitch, roll) - } -} - -impl Distribution for Standard { - #[inline] - fn sample(&self, rng: &mut R) -> Vec2 { - rng.gen::<(f32, f32)>().into() - } -} - -impl Distribution for Standard { - #[inline] - fn sample(&self, rng: &mut R) -> Vec3 { - rng.gen::<(f32, f32, f32)>().into() - } -} - -impl Distribution for Standard { - #[inline] - fn sample(&self, rng: &mut R) -> Vec4 { - rng.gen::<[f32; 4]>().into() - } -} diff --git a/crates/bevy_glam/src/f32/glam_serde.rs b/crates/bevy_glam/src/f32/glam_serde.rs deleted file mode 100644 index 8c0842199f..0000000000 --- a/crates/bevy_glam/src/f32/glam_serde.rs +++ /dev/null @@ -1,385 +0,0 @@ -use crate::{Mat2, Mat3, Mat4, Quat, Vec2, Vec3, Vec4}; -use core::fmt; -use serde::{ - de::{self, Deserialize, Deserializer, SeqAccess, Visitor}, - ser::{Serialize, SerializeTupleStruct, Serializer}, -}; - -impl Serialize for Vec2 { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let (x, y) = (*self).into(); - let mut state = serializer.serialize_tuple_struct("Vec2", 2)?; - state.serialize_field(&x)?; - state.serialize_field(&y)?; - state.end() - } -} - -#[cfg(feature = "serde")] -impl Serialize for Vec3 { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let (x, y, z) = (*self).into(); - // 3 is the number of fields in the struct. - let mut state = serializer.serialize_tuple_struct("Vec3", 3)?; - state.serialize_field(&x)?; - state.serialize_field(&y)?; - state.serialize_field(&z)?; - state.end() - } -} - -#[cfg(feature = "serde")] -impl Serialize for Vec4 { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let (x, y, z, w) = (*self).into(); - // 4 is the number of fields in the struct. - let mut state = serializer.serialize_tuple_struct("Vec4", 4)?; - state.serialize_field(&x)?; - state.serialize_field(&y)?; - state.serialize_field(&z)?; - state.serialize_field(&w)?; - state.end() - } -} - -#[cfg(feature = "serde")] -impl Serialize for Quat { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let (x, y, z, w) = (*self).into(); - // 4 is the number of fields in the struct. - let mut state = serializer.serialize_tuple_struct("Quat", 4)?; - state.serialize_field(&x)?; - state.serialize_field(&y)?; - state.serialize_field(&z)?; - state.serialize_field(&w)?; - state.end() - } -} - -#[cfg(feature = "serde")] -impl Serialize for Mat2 { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let f: &[f32; 4] = self.as_ref(); - let mut state = serializer.serialize_tuple_struct("Mat2", 4)?; - state.serialize_field(&f[0])?; - state.serialize_field(&f[1])?; - state.serialize_field(&f[2])?; - state.serialize_field(&f[3])?; - state.end() - } -} - -#[cfg(feature = "serde")] -impl Serialize for Mat3 { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let (m00, m01, m02) = self.x_axis.into(); - let (m10, m11, m12) = self.y_axis.into(); - let (m20, m21, m22) = self.z_axis.into(); - - let mut state = serializer.serialize_tuple_struct("Mat3", 9)?; - state.serialize_field(&m00)?; - state.serialize_field(&m01)?; - state.serialize_field(&m02)?; - state.serialize_field(&m10)?; - state.serialize_field(&m11)?; - state.serialize_field(&m12)?; - state.serialize_field(&m20)?; - state.serialize_field(&m21)?; - state.serialize_field(&m22)?; - state.end() - } -} - -#[cfg(feature = "serde")] -impl Serialize for Mat4 { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let mut state = serializer.serialize_tuple_struct("Mat4", 16)?; - for f in self.as_ref() { - state.serialize_field(f)?; - } - state.end() - } -} - -impl<'de> Deserialize<'de> for Vec2 { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - struct Vec2Visitor; - - // TODO: Not sure why this line is reported as uncovered - #[cfg_attr(tarpaulin, skip)] - impl<'de> Visitor<'de> for Vec2Visitor { - type Value = Vec2; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("struct Vec2") - } - - fn visit_seq(self, mut seq: V) -> Result - where - V: SeqAccess<'de>, - { - let x = seq - .next_element()? - .ok_or_else(|| de::Error::invalid_length(0, &self))?; - let y = seq - .next_element()? - .ok_or_else(|| de::Error::invalid_length(1, &self))?; - Ok(Vec2::new(x, y)) - } - } - - deserializer.deserialize_tuple_struct("Vec2", 2, Vec2Visitor) - } -} - -impl<'de> Deserialize<'de> for Vec3 { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - struct Vec3Visitor; - - // TODO: Not sure why this line is reported as uncovered - #[cfg_attr(tarpaulin, skip)] - impl<'de> Visitor<'de> for Vec3Visitor { - type Value = Vec3; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("struct Vec2") - } - - fn visit_seq(self, mut seq: V) -> Result - where - V: SeqAccess<'de>, - { - let x = seq - .next_element()? - .ok_or_else(|| de::Error::invalid_length(0, &self))?; - let y = seq - .next_element()? - .ok_or_else(|| de::Error::invalid_length(1, &self))?; - let z = seq - .next_element()? - .ok_or_else(|| de::Error::invalid_length(2, &self))?; - Ok(Vec3::new(x, y, z)) - } - } - - deserializer.deserialize_tuple_struct("Vec3", 3, Vec3Visitor) - } -} - -impl<'de> Deserialize<'de> for Vec4 { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - struct Vec4Visitor; - - // TODO: Not sure why this line is reported as uncovered - #[cfg_attr(tarpaulin, skip)] - impl<'de> Visitor<'de> for Vec4Visitor { - type Value = Vec4; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("struct Vec2") - } - - fn visit_seq(self, mut seq: V) -> Result - where - V: SeqAccess<'de>, - { - let x = seq - .next_element()? - .ok_or_else(|| de::Error::invalid_length(0, &self))?; - let y = seq - .next_element()? - .ok_or_else(|| de::Error::invalid_length(1, &self))?; - let z = seq - .next_element()? - .ok_or_else(|| de::Error::invalid_length(2, &self))?; - let w = seq - .next_element()? - .ok_or_else(|| de::Error::invalid_length(3, &self))?; - Ok(Vec4::new(x, y, z, w)) - } - } - - deserializer.deserialize_tuple_struct("Vec4", 4, Vec4Visitor) - } -} - -impl<'de> Deserialize<'de> for Quat { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - struct QuatVisitor; - - // TODO: Not sure why this line is reported as uncovered - #[cfg_attr(tarpaulin, skip)] - impl<'de> Visitor<'de> for QuatVisitor { - type Value = Quat; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("struct Vec2") - } - - fn visit_seq(self, mut seq: V) -> Result - where - V: SeqAccess<'de>, - { - let x = seq - .next_element()? - .ok_or_else(|| de::Error::invalid_length(0, &self))?; - let y = seq - .next_element()? - .ok_or_else(|| de::Error::invalid_length(1, &self))?; - let z = seq - .next_element()? - .ok_or_else(|| de::Error::invalid_length(2, &self))?; - let w = seq - .next_element()? - .ok_or_else(|| de::Error::invalid_length(3, &self))?; - Ok(Quat::from_xyzw(x, y, z, w)) - } - } - - deserializer.deserialize_tuple_struct("Quat", 4, QuatVisitor) - } -} - -impl<'de> Deserialize<'de> for Mat2 { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - struct Mat2Visitor; - - // TODO: Not sure why this line is reported as uncovered - #[cfg_attr(tarpaulin, skip)] - impl<'de> Visitor<'de> for Mat2Visitor { - type Value = Mat2; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("struct Mat2") - } - - fn visit_seq(self, mut seq: V) -> Result - where - V: SeqAccess<'de>, - { - let mut f = { [0.0; 4] }; - for i in 0..4 { - f[i] = seq - .next_element()? - .ok_or_else(|| de::Error::invalid_length(i, &self))?; - } - let x = Vec2::new(f[0], f[1]); - let y = Vec2::new(f[2], f[3]); - Ok(Mat2::from_cols(x, y)) - } - } - - deserializer.deserialize_tuple_struct("Mat2", 4, Mat2Visitor) - } -} - -impl<'de> Deserialize<'de> for Mat3 { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - struct Mat3Visitor; - - // TODO: Not sure why this line is reported as uncovered - #[cfg_attr(tarpaulin, skip)] - impl<'de> Visitor<'de> for Mat3Visitor { - type Value = Mat3; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("struct Mat3") - } - - fn visit_seq(self, mut seq: V) -> Result - where - V: SeqAccess<'de>, - { - let mut f = { [0.0; 9] }; - for i in 0..9 { - f[i] = seq - .next_element()? - .ok_or_else(|| de::Error::invalid_length(i, &self))?; - } - let x = Vec3::new(f[0], f[1], f[2]); - let y = Vec3::new(f[3], f[4], f[5]); - let z = Vec3::new(f[6], f[7], f[8]); - Ok(Mat3::from_cols(x, y, z)) - } - } - - deserializer.deserialize_tuple_struct("Mat3", 9, Mat3Visitor) - } -} - -impl<'de> Deserialize<'de> for Mat4 { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - struct Mat4Visitor; - - // TODO: Not sure why this line is reported as uncovered - #[cfg_attr(tarpaulin, skip)] - impl<'de> Visitor<'de> for Mat4Visitor { - type Value = Mat4; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("struct Mat4") - } - - fn visit_seq(self, mut seq: V) -> Result - where - V: SeqAccess<'de>, - { - let mut f = { [0.0; 16] }; - for i in 0..16 { - f[i] = seq - .next_element()? - .ok_or_else(|| de::Error::invalid_length(i, &self))?; - } - let x = Vec4::new(f[0], f[1], f[2], f[3]); - let y = Vec4::new(f[4], f[5], f[6], f[7]); - let z = Vec4::new(f[8], f[9], f[10], f[11]); - let w = Vec4::new(f[12], f[13], f[14], f[15]); - Ok(Mat4::from_cols(x, y, z, w)) - } - } - - deserializer.deserialize_tuple_struct("Mat4", 16, Mat4Visitor) - } -} diff --git a/crates/bevy_glam/src/f32/glam_zerocopy.rs b/crates/bevy_glam/src/f32/glam_zerocopy.rs deleted file mode 100644 index c6504fc632..0000000000 --- a/crates/bevy_glam/src/f32/glam_zerocopy.rs +++ /dev/null @@ -1,114 +0,0 @@ -use crate::{Mat2, Mat3, Mat4, Quat, Vec2, Vec3, Vec4}; -use zerocopy::{AsBytes, FromBytes}; - -unsafe impl AsBytes for Vec2 { - fn only_derive_is_allowed_to_implement_this_trait() - where - Self: Sized, - { - } -} - -unsafe impl FromBytes for Vec2 { - fn only_derive_is_allowed_to_implement_this_trait() - where - Self: Sized, - { - } -} - -unsafe impl AsBytes for Vec3 { - fn only_derive_is_allowed_to_implement_this_trait() - where - Self: Sized, - { - } -} - -unsafe impl FromBytes for Vec3 { - fn only_derive_is_allowed_to_implement_this_trait() - where - Self: Sized, - { - } -} - -unsafe impl AsBytes for Vec4 { - fn only_derive_is_allowed_to_implement_this_trait() - where - Self: Sized, - { - } -} - -unsafe impl FromBytes for Vec4 { - fn only_derive_is_allowed_to_implement_this_trait() - where - Self: Sized, - { - } -} - -unsafe impl AsBytes for Mat2 { - fn only_derive_is_allowed_to_implement_this_trait() - where - Self: Sized, - { - } -} - -unsafe impl FromBytes for Mat2 { - fn only_derive_is_allowed_to_implement_this_trait() - where - Self: Sized, - { - } -} - -unsafe impl AsBytes for Mat3 { - fn only_derive_is_allowed_to_implement_this_trait() - where - Self: Sized, - { - } -} - -unsafe impl FromBytes for Mat3 { - fn only_derive_is_allowed_to_implement_this_trait() - where - Self: Sized, - { - } -} - -unsafe impl AsBytes for Mat4 { - fn only_derive_is_allowed_to_implement_this_trait() - where - Self: Sized, - { - } -} - -unsafe impl FromBytes for Mat4 { - fn only_derive_is_allowed_to_implement_this_trait() - where - Self: Sized, - { - } -} - -unsafe impl AsBytes for Quat { - fn only_derive_is_allowed_to_implement_this_trait() - where - Self: Sized, - { - } -} - -unsafe impl FromBytes for Quat { - fn only_derive_is_allowed_to_implement_this_trait() - where - Self: Sized, - { - } -} diff --git a/crates/bevy_glam/src/f32/mat2.rs b/crates/bevy_glam/src/f32/mat2.rs deleted file mode 100644 index 4f3fa046c1..0000000000 --- a/crates/bevy_glam/src/f32/mat2.rs +++ /dev/null @@ -1,335 +0,0 @@ -use super::{scalar_sin_cos, Vec2, Vec4}; -#[cfg(all(vec4sse2, target_arch = "x86",))] -use core::arch::x86::*; -#[cfg(all(vec4sse2, target_arch = "x86_64",))] -use core::arch::x86_64::*; -use core::{ - fmt, - ops::{Add, Mul, Sub}, -}; - -#[inline] -pub fn mat2(x_axis: Vec2, y_axis: Vec2) -> Mat2 { - Mat2::from_cols(x_axis, y_axis) -} - -/// A 2x2 column major matrix. -#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)] -#[repr(C)] -pub struct Mat2(pub(crate) Vec4); - -impl Default for Mat2 { - #[inline] - fn default() -> Self { - Self::identity() - } -} - -impl fmt::Display for Mat2 { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "[{}, {}]", self.x_axis(), self.y_axis()) - } -} - -impl Mat2 { - /// Creates a 2x2 matrix with all elements set to `0.0`. - #[inline] - pub fn zero() -> Self { - Mat2(Vec4::zero()) - } - - /// Creates a 2x2 identity matrix. - #[inline] - pub fn identity() -> Self { - Self(Vec4::new(1.0, 0.0, 0.0, 1.0)) - } - - /// Creates a 2x2 matrix from four column vectors. - #[inline] - pub fn from_cols(x_axis: Vec2, y_axis: Vec2) -> Self { - Self(Vec4::new(x_axis.x(), x_axis.y(), y_axis.x(), y_axis.y())) - } - - /// Creates a 2x2 matrix from a `[f32; 4]` stored in column major order. If - /// your data is stored in row major you will need to `transpose` the - /// returned matrix. - #[inline] - pub fn from_cols_array(m: &[f32; 4]) -> Self { - Mat2(Vec4::new(m[0], m[1], m[2], m[3])) - } - - /// Creates a `[f32; 4]` storing data in column major order. - /// If you require data in row major order `transpose` the matrix first. - #[inline] - pub fn to_cols_array(&self) -> [f32; 4] { - self.0.into() - } - - /// Creates a 2x2 matrix from a `[[f32; 2]; 2]` 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]; 2]) -> Self { - Mat2(Vec4::new(m[0][0], m[0][1], m[1][0], m[1][1])) - } - - /// Creates a `[[f32; 2]; 2]` storing data in column major order. - /// If you require data in row major order `transpose` the matrix first. - #[inline] - pub fn to_cols_array_2d(&self) -> [[f32; 2]; 2] { - let (x0, y0, x1, y1) = self.0.into(); - [[x0, y0], [x1, y1]] - } - - /// Creates a 2x2 matrix containing the given `scale` and rotation of - /// `angle` (in radians). - #[inline] - pub fn from_scale_angle(scale: Vec2, angle: f32) -> Self { - let (sin, cos) = scalar_sin_cos(angle); - let (scale_x, scale_y) = scale.into(); - Self(Vec4::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) = scalar_sin_cos(angle); - Self(Vec4::new(cos, sin, -sin, cos)) - } - - /// Creates a 2x2 matrix containing the given non-uniform `scale`. - #[inline] - pub fn from_scale(scale: Vec2) -> Self { - let (x, y) = scale.into(); - Self(Vec4::new(x, 0.0, 0.0, y)) - } - - #[inline] - pub fn set_x_axis(&mut self, x: Vec2) { - let m = self.0.as_mut(); - m[0] = x.x(); - m[1] = x.y(); - } - - #[inline] - pub fn set_y_axis(&mut self, y: Vec2) { - let m = self.0.as_mut(); - m[2] = y.x(); - m[3] = y.y(); - } - - #[inline] - pub fn x_axis(&self) -> Vec2 { - let (x, y, _, _) = self.0.into(); - Vec2::new(x, y) - } - - #[inline] - pub fn y_axis(&self) -> Vec2 { - let (_, _, x, y) = self.0.into(); - Vec2::new(x, y) - } - - // #[inline] - // pub(crate) fn col(&self, index: usize) -> Vec2 { - // match index { - // 0 => self.x_axis(), - // 1 => self.y_axis(), - // _ => panic!( - // "index out of bounds: the len is 2 but the index is {}", - // index - // ), - // } - // } - - // #[inline] - // pub(crate) fn col_mut(&mut self, index: usize) -> &mut Vec2 { - // match index { - // 0 => unsafe { &mut *(self.0.as_mut().as_mut_ptr() as *mut Vec2) }, - // 1 => unsafe { &mut *(self.0.as_mut()[2..].as_mut_ptr() as *mut Vec2) }, - // _ => panic!( - // "index out of bounds: the len is 2 but the index is {}", - // index - // ), - // } - // } - - /// Returns the transpose of `self`. - #[inline] - pub fn transpose(&self) -> Self { - #[cfg(vec4sse2)] - unsafe { - let abcd = self.0.into(); - let acbd = _mm_shuffle_ps(abcd, abcd, 0b11_01_10_00); - Self(acbd.into()) - } - - #[cfg(vec4f32)] - { - let (m00, m01, m10, m11) = self.0.into(); - Self(Vec4::new(m00, m10, m01, m11)) - } - } - - /// Returns the determinant of `self`. - #[inline] - pub fn determinant(&self) -> f32 { - #[cfg(vec4sse2)] - unsafe { - let abcd = self.0.into(); - 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) - } - - #[cfg(vec4f32)] - { - let (a, b, c, d) = self.0.into(); - a * d - b * c - } - } - - /// Returns the inverse of `self`. - /// - /// If the matrix is not invertible the returned matrix will be invalid. - #[inline] - pub fn inverse(&self) -> Self { - #[cfg(vec4sse2)] - unsafe { - let abcd = self.0.into(); - 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(_mm_set_ps(1.0, -1.0, -1.0, 1.0), det); - let dbca = _mm_shuffle_ps(abcd, abcd, 0b00_10_01_11); - Self(_mm_mul_ps(dbca, tmp).into()) - } - - #[cfg(vec4f32)] - { - let (a, b, c, d) = self.0.into(); - let det = a * d - b * c; - glam_assert!(det != 0.0); - let tmp = Vec4::new(1.0, -1.0, -1.0, 1.0) / det; - Self(Vec4::new(d, b, c, a) * tmp) - } - } - - #[inline] - pub fn mul_vec2(&self, other: Vec2) -> Vec2 { - // TODO: SSE2 - let other = Vec4::new(other.x(), other.x(), other.y(), other.y()); - let tmp = self.0 * other; - let (x0, y0, x1, y1) = tmp.into(); - Vec2::new(x0 + x1, y0 + y1) - } - - #[inline] - pub fn mul_mat2(&self, other: &Self) -> Self { - // TODO: SSE2 - let (x0, y0, x1, y1) = other.0.into(); - Mat2::from_cols( - self.mul_vec2(Vec2::new(x0, y0)), - self.mul_vec2(Vec2::new(x1, y1)), - ) - } - - #[inline] - pub fn add_mat2(&self, other: &Self) -> Self { - Mat2(self.0 + other.0) - } - - #[inline] - pub fn sub_mat2(&self, other: &Self) -> Self { - Mat2(self.0 - other.0) - } - - #[inline] - pub fn mul_scalar(&self, other: f32) -> Self { - let s = Vec4::splat(other); - Mat2(self.0 * 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 `Mat2`'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.0.abs_diff_eq(other.0, max_abs_diff) - } -} - -impl AsRef<[f32; 4]> for Mat2 { - #[inline] - fn as_ref(&self) -> &[f32; 4] { - unsafe { &*(self as *const Self as *const [f32; 4]) } - } -} - -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 Add for Mat2 { - type Output = Self; - #[inline] - fn add(self, other: Self) -> Self { - self.add_mat2(&other) - } -} - -impl Sub for Mat2 { - type Output = Self; - #[inline] - fn sub(self, other: Self) -> Self { - self.sub_mat2(&other) - } -} - -impl Mul for Mat2 { - type Output = Self; - #[inline] - fn mul(self, other: Self) -> Self { - self.mul_mat2(&other) - } -} - -impl Mul for Mat2 { - type Output = Vec2; - #[inline] - fn mul(self, other: Vec2) -> Vec2 { - self.mul_vec2(other) - } -} - -impl Mul for f32 { - type Output = Mat2; - #[inline] - fn mul(self, other: Mat2) -> Mat2 { - other.mul_scalar(self) - } -} - -impl Mul for Mat2 { - type Output = Self; - #[inline] - fn mul(self, other: f32) -> Self { - self.mul_scalar(other) - } -} diff --git a/crates/bevy_glam/src/f32/mat3.rs b/crates/bevy_glam/src/f32/mat3.rs deleted file mode 100644 index f28b3aa35b..0000000000 --- a/crates/bevy_glam/src/f32/mat3.rs +++ /dev/null @@ -1,482 +0,0 @@ -use super::{scalar_sin_cos, Quat, Vec2, Vec3}; -use core::{ - fmt, - ops::{Add, Mul, Sub}, -}; - -#[inline] -pub fn mat3(x_axis: Vec3, y_axis: Vec3, z_axis: Vec3) -> Mat3 { - Mat3 { - x_axis, - y_axis, - z_axis, - } -} - -#[inline] -fn quat_to_axes(rotation: Quat) -> (Vec3, Vec3, Vec3) { - 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 = Vec3::new(1.0 - (yy + zz), xy + wz, xz - wy); - let y_axis = Vec3::new(xy - wz, 1.0 - (xx + zz), yz + wx); - let z_axis = Vec3::new(xz + wy, yz - wx, 1.0 - (xx + yy)); - (x_axis, y_axis, z_axis) -} - -/// A 3x3 column major matrix. -/// -/// This type is 16 byte aligned. -#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)] -#[repr(C)] -pub struct Mat3 { - pub(crate) x_axis: Vec3, - pub(crate) y_axis: Vec3, - pub(crate) z_axis: Vec3, -} - -impl Default for Mat3 { - #[inline] - fn default() -> Self { - Self::identity() - } -} - -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) - } -} - -impl Mat3 { - /// Creates a 3x3 matrix with all elements set to `0.0`. - #[inline] - pub fn zero() -> Self { - Self { - x_axis: Vec3::zero(), - y_axis: Vec3::zero(), - z_axis: Vec3::zero(), - } - } - - /// Creates a 3x3 identity matrix. - #[inline] - pub fn identity() -> Self { - Self { - x_axis: Vec3::unit_x(), - y_axis: Vec3::unit_y(), - z_axis: Vec3::unit_z(), - } - } - - /// Creates a 3x3 matrix from three column vectors. - #[inline] - pub 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]` stored in column major order. - /// If your data is stored in row major you will need to `transpose` the - /// returned matrix. - #[inline] - pub fn from_cols_array(m: &[f32; 9]) -> Self { - Mat3 { - x_axis: Vec3::new(m[0], m[1], m[2]), - y_axis: Vec3::new(m[3], m[4], m[5]), - z_axis: Vec3::new(m[6], m[7], m[8]), - } - } - - /// Creates a `[f32; 9]` storing data in column major order. - /// If you require data in row major order `transpose` the matrix first. - #[inline] - pub fn to_cols_array(&self) -> [f32; 9] { - let (m00, m01, m02) = self.x_axis.into(); - let (m10, m11, m12) = self.y_axis.into(); - let (m20, m21, m22) = self.z_axis.into(); - [m00, m01, m02, m10, m11, m12, m20, m21, m22] - } - - /// Creates a 3x3 matrix from a `[[f32; 3]; 3]` 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]; 3]) -> Self { - Mat3 { - x_axis: m[0].into(), - y_axis: m[1].into(), - z_axis: m[2].into(), - } - } - - /// Creates a `[[f32; 3]; 3]` storing data in column major order. - /// If you require data in row major order `transpose` the matrix first. - #[inline] - pub fn to_cols_array_2d(&self) -> [[f32; 3]; 3] { - [self.x_axis.into(), self.y_axis.into(), self.z_axis.into()] - } - - /// Creates a 3x3 homogeneous transformation matrix from the given `scale`, - /// rotation `angle` (in radians) and `translation`. - /// - /// The resulting matrix can be used to transform 2D points and vectors. - #[inline] - pub fn from_scale_angle_translation(scale: Vec2, angle: f32, translation: Vec2) -> Self { - let (sin, cos) = scalar_sin_cos(angle); - let (scale_x, scale_y) = scale.into(); - Self { - x_axis: Vec3::new(cos * scale_x, sin * scale_x, 0.0), - y_axis: Vec3::new(-sin * scale_y, cos * scale_y, 0.0), - z_axis: translation.extend(1.0), - } - } - - #[inline] - /// Creates a 3x3 rotation matrix from the given quaternion. - pub fn from_quat(rotation: Quat) -> Self { - let (x_axis, y_axis, z_axis) = quat_to_axes(rotation); - Self { - x_axis, - y_axis, - z_axis, - } - } - - /// Creates a 3x3 rotation matrix from a normalized rotation `axis` and - /// `angle` (in radians). - #[inline] - pub fn from_axis_angle(axis: Vec3, angle: f32) -> Self { - glam_assert!(axis.is_normalized()); - let (sin, cos) = scalar_sin_cos(angle); - let (x, y, z) = axis.into(); - let (xsin, ysin, zsin) = (axis * sin).into(); - let (x2, y2, z2) = (axis * axis).into(); - let omc = 1.0 - cos; - let xyomc = x * y * omc; - let xzomc = x * z * omc; - let yzomc = y * z * omc; - Self { - x_axis: Vec3::new(x2 * omc + cos, xyomc + zsin, xzomc - ysin), - y_axis: Vec3::new(xyomc - zsin, y2 * omc + cos, yzomc + xsin), - z_axis: Vec3::new(xzomc + ysin, yzomc - xsin, z2 * omc + cos), - } - } - - /// Creates a 3x3 rotation matrix from the given Euler angles (in radians). - #[inline] - pub fn from_rotation_ypr(yaw: f32, pitch: f32, roll: f32) -> Self { - let quat = Quat::from_rotation_ypr(yaw, pitch, roll); - Self::from_quat(quat) - } - - /// Creates a 3x3 rotation matrix from `angle` (in radians) around the x axis. - #[inline] - pub fn from_rotation_x(angle: f32) -> Self { - let (sina, cosa) = scalar_sin_cos(angle); - Self { - x_axis: Vec3::unit_x(), - y_axis: Vec3::new(0.0, cosa, sina), - z_axis: Vec3::new(0.0, -sina, cosa), - } - } - - /// Creates a 3x3 rotation matrix from `angle` (in radians) around the y axis. - #[inline] - pub fn from_rotation_y(angle: f32) -> Self { - let (sina, cosa) = scalar_sin_cos(angle); - Self { - x_axis: Vec3::new(cosa, 0.0, -sina), - y_axis: Vec3::unit_y(), - z_axis: Vec3::new(sina, 0.0, cosa), - } - } - - /// Creates a 3x3 rotation matrix from `angle` (in radians) around the z axis. - #[inline] - pub fn from_rotation_z(angle: f32) -> Self { - let (sina, cosa) = scalar_sin_cos(angle); - Self { - x_axis: Vec3::new(cosa, sina, 0.0), - y_axis: Vec3::new(-sina, cosa, 0.0), - z_axis: Vec3::unit_z(), - } - } - - /// Creates a 3x3 non-uniform scale matrix. - #[inline] - pub fn from_scale(scale: Vec3) -> Self { - // TODO: should have a affine 2D scale and a 3d scale? - // Do not panic as long as any component is non-zero - glam_assert!(scale.cmpne(Vec3::zero()).any()); - let (x, y, z) = scale.into(); - Self { - x_axis: Vec3::new(x, 0.0, 0.0), - y_axis: Vec3::new(0.0, y, 0.0), - z_axis: Vec3::new(0.0, 0.0, z), - } - } - - #[inline] - pub fn set_x_axis(&mut self, x: Vec3) { - self.x_axis = x; - } - - #[inline] - pub fn set_y_axis(&mut self, y: Vec3) { - self.y_axis = y; - } - - #[inline] - pub fn set_z_axis(&mut self, z: Vec3) { - self.z_axis = z; - } - - #[inline] - pub fn x_axis(&self) -> Vec3 { - self.x_axis - } - - #[inline] - pub fn y_axis(&self) -> Vec3 { - self.y_axis - } - - #[inline] - pub fn z_axis(&self) -> Vec3 { - self.z_axis - } - - // #[inline] - // pub(crate) 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: the len is 3 but the index is {}", - // index - // ), - // } - // } - - // #[inline] - // pub(crate) 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: the len is 3 but the index is {}", - // index - // ), - // } - // } - - /// Returns the transpose of `self`. - #[inline] - pub fn transpose(&self) -> Self { - #[cfg(vec3sse2)] - { - #[cfg(target_arch = "x86")] - use core::arch::x86::*; - #[cfg(target_arch = "x86_64")] - use core::arch::x86_64::*; - 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: _mm_shuffle_ps(tmp0, self.z_axis.0, 0b00_00_10_00).into(), - y_axis: _mm_shuffle_ps(tmp0, self.z_axis.0, 0b01_01_11_01).into(), - z_axis: _mm_shuffle_ps(tmp1, self.z_axis.0, 0b10_10_10_00).into(), - } - } - } - #[cfg(vec3f32)] - { - let (m00, m01, m02) = self.x_axis.into(); - let (m10, m11, m12) = self.y_axis.into(); - let (m20, m21, m22) = self.z_axis.into(); - - Self { - x_axis: Vec3::new(m00, m10, m20), - y_axis: Vec3::new(m01, m11, m21), - z_axis: Vec3::new(m02, m12, m22), - } - } - } - - /// 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. - 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_as_vec3(tmp2); - glam_assert!(det.cmpne(Vec3::zero()).all()); - let inv_det = det.reciprocal(); - // TODO: Work out if it's possible to get rid of the transpose - Mat3::from_cols(tmp0 * inv_det, tmp1 * inv_det, tmp2 * inv_det).transpose() - } - - /// Transforms a 3D vector. - #[inline] - pub fn mul_vec3(&self, other: Vec3) -> Vec3 { - let mut res = self.x_axis * other.dup_x(); - res = self.y_axis.mul_add(other.dup_y(), res); - res = self.z_axis.mul_add(other.dup_z(), res); - res - } - - /// Multiplies two 3x3 matrices. - #[inline] - pub fn mul_mat3(&self, other: &Self) -> Self { - Self { - x_axis: self.mul_vec3(other.x_axis), - y_axis: self.mul_vec3(other.y_axis), - z_axis: self.mul_vec3(other.z_axis), - } - } - - /// Adds two 3x3 matrices. - #[inline] - pub fn add_mat3(&self, other: &Self) -> Self { - Self { - x_axis: self.x_axis + other.x_axis, - y_axis: self.y_axis + other.y_axis, - z_axis: self.z_axis + other.z_axis, - } - } - - /// Subtracts two 3x3 matrices. - #[inline] - pub fn sub_mat3(&self, other: &Self) -> Self { - Self { - x_axis: self.x_axis - other.x_axis, - y_axis: self.y_axis - other.y_axis, - z_axis: self.z_axis - other.z_axis, - } - } - - #[inline] - /// Multiplies a 3x3 matrix by a scalar. - pub fn mul_scalar(&self, other: f32) -> Self { - let s = Vec3::splat(other); - Self { - x_axis: self.x_axis * s, - y_axis: self.y_axis * s, - z_axis: self.z_axis * s, - } - } - - /// Transforms the given `Vec2` as 2D point. - /// This is the equivalent of multiplying the `Vec2` as a `Vec3` where `w` - /// is `1.0`. - #[inline] - pub fn transform_point2(&self, other: Vec2) -> Vec2 { - // let mut res = self.x_axis * Vec3::splat(other.x()); - // res = self.y_axis.mul_add(Vec3::splat(other.y()), res); - // res = self.z_axis + res; - // res.truncate() - self.mul_vec3(other.extend(1.0)).truncate() - } - - /// Transforms the given `Vec2` as 2D vector. - /// This is the equivalent of multiplying the `Vec2` as a `Vec3` where `w` - /// is `0.0`. - #[inline] - pub fn transform_vector2(&self, other: Vec2) -> Vec2 { - // TODO: can optimize for w=0. - // let mut res = self.x_axis * Vec3::splat(other.x()); - // res = self.y_axis.mul_add(Vec3::splat(other.y()), res); - // res.truncate() - self.mul_vec3(other.extend(0.0)).truncate() - } - - /// 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 `Mat3`'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.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) - } -} - -impl Add for Mat3 { - type Output = Self; - #[inline] - fn add(self, other: Self) -> Self { - self.add_mat3(&other) - } -} - -impl Sub for Mat3 { - type Output = Self; - #[inline] - fn sub(self, other: Self) -> Self { - self.sub_mat3(&other) - } -} - -impl Mul for Mat3 { - type Output = Self; - #[inline] - fn mul(self, other: Self) -> Self { - self.mul_mat3(&other) - } -} - -impl Mul for Mat3 { - type Output = Vec3; - #[inline] - fn mul(self, other: Vec3) -> Vec3 { - self.mul_vec3(other) - } -} - -impl Mul for f32 { - type Output = Mat3; - #[inline] - fn mul(self, other: Mat3) -> Mat3 { - other.mul_scalar(self) - } -} - -impl Mul for Mat3 { - type Output = Self; - #[inline] - fn mul(self, other: f32) -> Self { - self.mul_scalar(other) - } -} diff --git a/crates/bevy_glam/src/f32/mat4.rs b/crates/bevy_glam/src/f32/mat4.rs deleted file mode 100644 index fca6d0766f..0000000000 --- a/crates/bevy_glam/src/f32/mat4.rs +++ /dev/null @@ -1,886 +0,0 @@ -use super::{scalar_sin_cos, Mat3, Quat, Vec3, Vec4}; -#[cfg(all(vec4sse2, target_arch = "x86"))] -use core::arch::x86::*; -#[cfg(all(vec4sse2, target_arch = "x86_64"))] -use core::arch::x86_64::*; -use core::{ - fmt, - ops::{Add, Mul, Sub}, -}; - -#[inline] -pub fn mat4(x_axis: Vec4, y_axis: Vec4, z_axis: Vec4, w_axis: Vec4) -> Mat4 { - Mat4 { - x_axis, - y_axis, - z_axis, - w_axis, - } -} - -#[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) -} - -/// A 4x4 column major matrix. -/// -/// This type is 16 byte aligned. -#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)] -#[repr(C)] -pub struct Mat4 { - pub(crate) x_axis: Vec4, - pub(crate) y_axis: Vec4, - pub(crate) z_axis: Vec4, - pub(crate) w_axis: Vec4, -} - -impl Default for Mat4 { - #[inline] - fn default() -> Self { - Self::identity() - } -} - -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 - ) - } -} - -impl Mat4 { - /// Creates a 4x4 matrix with all elements set to `0.0`. - #[inline] - pub fn zero() -> Self { - Self { - x_axis: Vec4::zero(), - y_axis: Vec4::zero(), - z_axis: Vec4::zero(), - w_axis: Vec4::zero(), - } - } - - /// Creates a 4x4 identity matrix. - #[inline] - pub fn identity() -> Self { - Self { - x_axis: Vec4::unit_x(), - y_axis: Vec4::unit_y(), - z_axis: Vec4::unit_z(), - w_axis: Vec4::unit_w(), - } - } - - /// Creates a 4x4 matrix from four column vectors. - #[inline] - pub 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]` stored in column major order. - /// If your data is stored in row major you will need to `transpose` the - /// returned matrix. - #[inline] - pub fn from_cols_array(m: &[f32; 16]) -> Self { - Mat4 { - x_axis: Vec4::new(m[0], m[1], m[2], m[3]), - y_axis: Vec4::new(m[4], m[5], m[6], m[7]), - z_axis: Vec4::new(m[8], m[9], m[10], m[11]), - w_axis: Vec4::new(m[12], m[13], m[14], m[15]), - } - } - - /// Creates a `[f32; 16]` storing data in column major order. - /// If you require data in row major order `transpose` the matrix first. - #[inline] - pub fn to_cols_array(&self) -> [f32; 16] { - *self.as_ref() - } - - /// Creates a 4x4 matrix from a `[[f32; 4]; 4]` 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; 4]; 4]) -> Self { - Mat4 { - x_axis: m[0].into(), - y_axis: m[1].into(), - z_axis: m[2].into(), - w_axis: m[3].into(), - } - } - - /// Creates a `[[f32; 4]; 4]` storing data in column major order. - /// If you require data in row major order `transpose` the matrix first. - #[inline] - pub fn to_cols_array_2d(&self) -> [[f32; 4]; 4] { - [ - self.x_axis.into(), - self.y_axis.into(), - self.z_axis.into(), - self.w_axis.into(), - ] - } - - /// Creates a 4x4 homogeneous transformation matrix from the given `scale`, - /// `rotation` and `translation`. - #[inline] - pub fn from_scale_rotation_translation(scale: Vec3, rotation: Quat, translation: Vec3) -> Self { - glam_assert!(rotation.is_normalized()); - let (x_axis, y_axis, z_axis) = quat_to_axes(rotation); - let (scale_x, scale_y, scale_z) = scale.into(); - Self { - x_axis: x_axis * scale_x, - y_axis: y_axis * scale_y, - z_axis: z_axis * scale_z, - w_axis: translation.extend(1.0), - } - } - - /// Creates a 4x4 homogeneous transformation matrix from the given `translation`. - #[inline] - pub fn from_rotation_translation(rotation: Quat, translation: Vec3) -> Self { - glam_assert!(rotation.is_normalized()); - let (x_axis, y_axis, z_axis) = quat_to_axes(rotation); - Self { - x_axis, - y_axis, - z_axis, - w_axis: translation.extend(1.0), - } - } - - /// Extracts `scale`, `rotation` and `translation` from `self`. The input matrix is expected to - /// be a 4x4 homogeneous transformation matrix otherwise the output will be invalid. - 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.reciprocal(); - - let rotation = Quat::from_rotation_mat3(&Mat3::from_cols( - self.x_axis().truncate() * inv_scale.dup_x(), - self.y_axis().truncate() * inv_scale.dup_y(), - self.z_axis().truncate() * inv_scale.dup_z(), - )); - - let translation = self.w_axis.truncate(); - - (scale, rotation, translation) - } - - /// Creates a 4x4 homogeneous transformation matrix from the given `rotation`. - #[inline] - pub fn from_quat(rotation: Quat) -> Self { - glam_assert!(rotation.is_normalized()); - let (x_axis, y_axis, z_axis) = quat_to_axes(rotation); - Self { - x_axis, - y_axis, - z_axis, - w_axis: Vec4::unit_w(), - } - } - - /// Creates a 4x4 homogeneous transformation matrix from the given `translation`. - #[inline] - pub fn from_translation(translation: Vec3) -> Self { - Self { - x_axis: Vec4::unit_x(), - y_axis: Vec4::unit_y(), - z_axis: Vec4::unit_z(), - w_axis: translation.extend(1.0), - } - } - - /// Creates a 4x4 homogeneous transformation matrix containing a rotation - /// around a normalized rotation `axis` of `angle` (in radians). - #[inline] - pub fn from_axis_angle(axis: Vec3, angle: f32) -> Self { - glam_assert!(axis.is_normalized()); - let (sin, cos) = scalar_sin_cos(angle); - let (x, y, z) = axis.into(); - let (xsin, ysin, zsin) = (axis * sin).into(); - let (x2, y2, z2) = (axis * axis).into(); - let omc = 1.0 - cos; - let xyomc = x * y * omc; - let xzomc = x * z * omc; - let yzomc = y * z * omc; - Self { - x_axis: Vec4::new(x2 * omc + cos, xyomc + zsin, xzomc - ysin, 0.0), - y_axis: Vec4::new(xyomc - zsin, y2 * omc + cos, yzomc + xsin, 0.0), - z_axis: Vec4::new(xzomc + ysin, yzomc - xsin, z2 * omc + cos, 0.0), - w_axis: Vec4::unit_w(), - } - } - - /// Creates a 4x4 homogeneous transformation matrix containing a rotation - /// around the given Euler angles (in radians). - #[inline] - pub fn from_rotation_ypr(yaw: f32, pitch: f32, roll: f32) -> Self { - let quat = Quat::from_rotation_ypr(yaw, pitch, roll); - Self::from_quat(quat) - } - - /// Creates a 4x4 homogeneous transformation matrix containing a rotation - /// around the x axis of `angle` (in radians). - #[inline] - pub fn from_rotation_x(angle: f32) -> Self { - let (sina, cosa) = scalar_sin_cos(angle); - Self { - x_axis: Vec4::unit_x(), - y_axis: Vec4::new(0.0, cosa, sina, 0.0), - z_axis: Vec4::new(0.0, -sina, cosa, 0.0), - w_axis: Vec4::unit_w(), - } - } - - /// Creates a 4x4 homogeneous transformation matrix containing a rotation - /// around the y axis of `angle` (in radians). - #[inline] - pub fn from_rotation_y(angle: f32) -> Self { - let (sina, cosa) = scalar_sin_cos(angle); - Self { - x_axis: Vec4::new(cosa, 0.0, -sina, 0.0), - y_axis: Vec4::unit_y(), - z_axis: Vec4::new(sina, 0.0, cosa, 0.0), - w_axis: Vec4::unit_w(), - } - } - - /// Creates a 4x4 homogeneous transformation matrix containing a rotation - /// around the z axis of `angle` (in radians). - #[inline] - pub fn from_rotation_z(angle: f32) -> Self { - let (sina, cosa) = scalar_sin_cos(angle); - Self { - x_axis: Vec4::new(cosa, sina, 0.0, 0.0), - y_axis: Vec4::new(-sina, cosa, 0.0, 0.0), - z_axis: Vec4::unit_z(), - w_axis: Vec4::unit_w(), - } - } - - /// Creates a 4x4 homogeneous transformation matrix containing the given - /// non-uniform `scale`. - #[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()); - let (x, y, z) = scale.into(); - Self { - x_axis: Vec4::new(x, 0.0, 0.0, 0.0), - y_axis: Vec4::new(0.0, y, 0.0, 0.0), - z_axis: Vec4::new(0.0, 0.0, z, 0.0), - w_axis: Vec4::unit_w(), - } - } - - #[inline] - pub fn set_x_axis(&mut self, x: Vec4) { - self.x_axis = x; - } - - #[inline] - pub fn set_y_axis(&mut self, y: Vec4) { - self.y_axis = y; - } - - #[inline] - pub fn set_z_axis(&mut self, z: Vec4) { - self.z_axis = z; - } - - #[inline] - pub fn set_w_axis(&mut self, w: Vec4) { - self.w_axis = w; - } - - #[inline] - pub fn x_axis(&self) -> Vec4 { - self.x_axis - } - - #[inline] - pub fn y_axis(&self) -> Vec4 { - self.y_axis - } - - #[inline] - pub fn z_axis(&self) -> Vec4 { - self.z_axis - } - - #[inline] - pub fn w_axis(&self) -> Vec4 { - self.w_axis - } - - // #[inline] - // pub(crate) 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: the len is 4 but the index is {}", - // index - // ), - // } - // } - - // #[inline] - // pub(crate) 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: the len is 4 but the index is {}", - // index - // ), - // } - // } - - /// Returns the transpose of `self`. - #[inline] - pub fn transpose(&self) -> Self { - #[cfg(vec4sse2)] - unsafe { - // sse2 implementation based off DirectXMath XMMatrixInverse (MIT License) - 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: _mm_shuffle_ps(tmp0, tmp2, 0b10_00_10_00).into(), - y_axis: _mm_shuffle_ps(tmp0, tmp2, 0b11_01_11_01).into(), - z_axis: _mm_shuffle_ps(tmp1, tmp3, 0b10_00_10_00).into(), - w_axis: _mm_shuffle_ps(tmp1, tmp3, 0b11_01_11_01).into(), - } - } - - #[cfg(vec4f32)] - { - 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(); - - Self { - x_axis: Vec4::new(m00, m10, m20, m30), - y_axis: Vec4::new(m01, m11, m21, m31), - z_axis: Vec4::new(m02, m12, m22, m32), - w_axis: Vec4::new(m03, m13, m23, m33), - } - } - } - - /// Returns the determinant of `self`. - #[inline] - 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. - 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 * fac0 - vec2 * fac1 + vec3 * fac2; - let inv1 = vec0 * fac0 - vec2 * fac3 + vec3 * fac4; - let inv2 = vec0 * fac1 - vec1 * fac3 + vec3 * fac5; - let inv3 = vec0 * fac2 - vec1 * fac4 + vec2 * 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 { - x_axis: inv0 * sign_a, - y_axis: inv1 * sign_b, - z_axis: inv2 * sign_a, - w_axis: inv3 * 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 * col0; - let dot1 = dot0.x() + dot0.y() + dot0.z() + dot0.w(); - - glam_assert!(dot1 != 0.0); - - let rcp_det = 1.0 / dot1; - inverse * rcp_det - } - - #[inline] - // TODO: make public at some point - 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); - let (fx, fy, fz) = f.into(); - let (sx, sy, sz) = s.into(); - let (ux, uy, uz) = u.into(); - Mat4::from_cols( - Vec4::new(sx, ux, fx, 0.0), - Vec4::new(sy, uy, fy, 0.0), - Vec4::new(sz, uz, fz, 0.0), - Vec4::new(-s.dot(eye), -u.dot(eye), -f.dot(eye), 1.0), - ) - } - - #[inline] - pub fn look_at_lh(eye: Vec3, center: Vec3, up: Vec3) -> Self { - glam_assert!(up.is_normalized()); - Mat4::look_to_lh(eye, center - eye, up) - } - - #[inline] - pub fn look_at_rh(eye: Vec3, center: Vec3, up: Vec3) -> Self { - glam_assert!(up.is_normalized()); - Mat4::look_to_lh(eye, eye - center, 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 - 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; - Mat4::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. - 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) = scalar_sin_cos(0.5 * fov_y_radians); - let h = cos_fov / sin_fov; - let w = h / aspect_ratio; - let r = z_far / (z_far - z_near); - Mat4::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. - 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) = scalar_sin_cos(0.5 * fov_y_radians); - let h = cos_fov / sin_fov; - let w = h / aspect_ratio; - Mat4::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. - 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) = scalar_sin_cos(0.5 * fov_y_radians); - let h = cos_fov / sin_fov; - let w = h / aspect_ratio; - Mat4::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), - ) - } - - #[inline] - #[deprecated(since = "0.8.2", note = "please use `Mat4::perspective_rh_gl` instead")] - pub fn perspective_glu_rh( - fov_y_radians: f32, - aspect_ratio: f32, - z_near: f32, - z_far: f32, - ) -> Self { - Mat4::perspective_rh_gl(fov_y_radians, aspect_ratio, z_near, z_far) - } - - /// Creates an infinite right-handed perspective projection matrix with - /// [0,1] depth range. - pub fn perspective_infinite_rh(fov_y_radians: f32, aspect_ratio: f32, z_near: f32) -> Self { - let f = 1.0 / (0.5 * fov_y_radians).tan(); - Mat4::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. - pub fn perspective_infinite_reverse_rh( - fov_y_radians: f32, - aspect_ratio: f32, - z_near: f32, - ) -> Self { - let f = 1.0 / (0.5 * fov_y_radians).tan(); - Mat4::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 - 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); - - Mat4::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. - 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); - Mat4::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. - 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); - Mat4::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, - ), - ) - } - - #[inline] - pub fn mul_vec4(&self, other: Vec4) -> Vec4 { - let mut res = self.x_axis * other.dup_x(); - res = self.y_axis.mul_add(other.dup_y(), res); - res = self.z_axis.mul_add(other.dup_z(), res); - res = self.w_axis.mul_add(other.dup_w(), res); - res - } - - /// Multiplies two 4x4 matrices. - #[inline] - pub fn mul_mat4(&self, other: &Self) -> Self { - Self { - x_axis: self.mul_vec4(other.x_axis), - y_axis: self.mul_vec4(other.y_axis), - z_axis: self.mul_vec4(other.z_axis), - w_axis: self.mul_vec4(other.w_axis), - } - } - - #[inline] - pub fn add_mat4(&self, other: &Self) -> Self { - Self { - x_axis: self.x_axis + other.x_axis, - y_axis: self.y_axis + other.y_axis, - z_axis: self.z_axis + other.z_axis, - w_axis: self.w_axis + other.w_axis, - } - } - - #[inline] - pub fn sub_mat4(&self, other: &Self) -> Self { - Self { - x_axis: self.x_axis - other.x_axis, - y_axis: self.y_axis - other.y_axis, - z_axis: self.z_axis - other.z_axis, - w_axis: self.w_axis - other.w_axis, - } - } - - #[inline] - pub fn mul_scalar(&self, other: f32) -> Self { - let s = Vec4::splat(other); - Self { - x_axis: self.x_axis * s, - y_axis: self.y_axis * s, - z_axis: self.z_axis * s, - w_axis: self.w_axis * s, - } - } - - /// Transforms the given `Vec3` as 3D point. - /// This is the equivalent of multiplying the `Vec3` as a `Vec4` where `w` - /// is `1.0`. - #[inline] - pub fn transform_point3(&self, other: Vec3) -> Vec3 { - // TODO: optimized version below probably won't work for perspective projections - // let mut res = self.x_axis.truncate() * other.dup_x(); - // res = self.y_axis.truncate().mul_add(other.dup_y(), res); - // res = self.z_axis.truncate().mul_add(other.dup_z(), res); - // // other w = 1 - // res = self.w_axis.truncate() + res; - // res - self.mul_vec4(other.extend(1.0)).truncate() - } - - /// Transforms the give `Vec3` as 3D vector. - /// This is the equivalent of multiplying the `Vec3` as a `Vec4` where `w` - /// is `0.0`. - #[inline] - pub fn transform_vector3(&self, other: Vec3) -> Vec3 { - // TODO: can optimize for w=0. - // TODO: optimized version below probably won't work for perspective projections - // let mut res = self.x_axis.truncate() * other.dup_x(); - // res = self.y_axis.truncate().mul_add(other.dup_y(), res); - // res = self.z_axis.truncate().mul_add(other.dup_z(), res); - // // other w = 0 - // res - self.mul_vec4(other.extend(0.0)).truncate() - } - - /// 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.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) - } -} - -impl AsRef<[f32; 16]> for Mat4 { - #[inline] - fn as_ref(&self) -> &[f32; 16] { - unsafe { &*(self as *const Self as *const [f32; 16]) } - } -} - -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]) } - } -} - -impl Add for Mat4 { - type Output = Self; - #[inline] - fn add(self, other: Self) -> Self { - self.add_mat4(&other) - } -} - -impl Sub for Mat4 { - type Output = Self; - #[inline] - fn sub(self, other: Self) -> Self { - self.sub_mat4(&other) - } -} - -impl Mul for Mat4 { - type Output = Self; - #[inline] - fn mul(self, other: Self) -> Self { - self.mul_mat4(&other) - } -} - -impl Mul for Mat4 { - type Output = Vec4; - #[inline] - fn mul(self, other: Vec4) -> Vec4 { - self.mul_vec4(other) - } -} - -impl Mul for f32 { - type Output = Mat4; - #[inline] - fn mul(self, other: Mat4) -> Mat4 { - other.mul_scalar(self) - } -} - -impl Mul for Mat4 { - type Output = Self; - #[inline] - fn mul(self, other: f32) -> Self { - self.mul_scalar(other) - } -} diff --git a/crates/bevy_glam/src/f32/mod.rs b/crates/bevy_glam/src/f32/mod.rs deleted file mode 100644 index fcad663afe..0000000000 --- a/crates/bevy_glam/src/f32/mod.rs +++ /dev/null @@ -1,47 +0,0 @@ -mod funcs; -mod mat2; -mod mat3; -mod mat4; -mod quat; -#[cfg(feature = "transform-types")] -mod transform; -mod vec2; -mod vec2_mask; -mod vec3; -mod vec3_mask; -mod vec4; -mod vec4_mask; -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -mod x86_utils; - -pub(crate) use funcs::{scalar_acos, scalar_sin_cos}; -pub use mat2::*; -pub use mat3::*; -pub use mat4::*; -pub use quat::*; -#[cfg(feature = "transform-types")] -pub use transform::*; -pub use vec2::*; -pub use vec2_mask::*; -pub use vec3::*; -pub use vec3_mask::*; -pub use vec4::*; -pub use vec4_mask::*; - -#[cfg(feature = "mint")] -mod glam_mint; -#[cfg(feature = "mint")] -pub use glam_mint::*; - -#[cfg(feature = "rand")] -mod glam_rand; -#[cfg(feature = "rand")] -pub use glam_rand::*; - -#[cfg(feature = "serde")] -mod glam_serde; -#[cfg(feature = "serde")] -pub use glam_serde::*; - -mod glam_zerocopy; -pub use glam_zerocopy::*; diff --git a/crates/bevy_glam/src/f32/quat.rs b/crates/bevy_glam/src/f32/quat.rs deleted file mode 100644 index 15fa7b8215..0000000000 --- a/crates/bevy_glam/src/f32/quat.rs +++ /dev/null @@ -1,670 +0,0 @@ -use super::{scalar_acos, scalar_sin_cos, Mat3, Mat4, Vec3, Vec4}; -#[cfg(all(vec4sse2, target_arch = "x86",))] -use core::arch::x86::*; -#[cfg(all(vec4sse2, target_arch = "x86_64",))] -use core::arch::x86_64::*; -use core::{ - cmp::Ordering, - fmt, - ops::{Mul, MulAssign, Neg}, -}; - -/// 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(C)] -pub struct Quat(pub(crate) Vec4); - -#[inline] -pub fn quat(x: f32, y: f32, z: f32, w: f32) -> Quat { - Quat::from_xyzw(x, y, z, w) -} - -impl Quat { - /// 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. - #[inline] - pub fn from_xyzw(x: f32, y: f32, z: f32, w: f32) -> Self { - Self(Vec4::new(x, y, z, w)) - } - - #[inline] - pub fn identity() -> Self { - Self(Vec4::new(0.0, 0.0, 0.0, 1.0)) - } - - /// Creates a new rotation quaternion from an unaligned `&[f32]`. - /// - /// # Preconditions - /// - /// The resulting quaternion is expected to be of unit length. - /// - /// # Panics - /// - /// Panics if `slice` length is less than 4. - #[inline] - pub fn from_slice_unaligned(slice: &[f32]) -> Self { - let q = Self(Vec4::from_slice_unaligned(slice)); - glam_assert!(q.is_normalized()); - q - } - - /// Writes the quaternion to an unaligned `&mut [f32]`. - /// - /// # Panics - /// - /// Panics if `slice` length is less than 4. - #[inline] - pub fn write_to_slice_unaligned(self, slice: &mut [f32]) { - self.0.write_to_slice_unaligned(slice) - } - - /// Create a new quaterion for a normalized rotation axis and angle - /// (in radians). - #[inline] - pub fn from_axis_angle(axis: Vec3, angle: f32) -> Self { - glam_assert!(axis.is_normalized()); - let (s, c) = scalar_sin_cos(angle * 0.5); - Self((axis * s).extend(c)) - } - - /// Creates a new quaternion from the angle (in radians) around the x axis. - #[inline] - pub fn from_rotation_x(angle: f32) -> Self { - let (s, c) = scalar_sin_cos(angle * 0.5); - Self::from_xyzw(s, 0.0, 0.0, c) - } - - /// Creates a new quaternion from the angle (in radians) around the y axis. - #[inline] - pub fn from_rotation_y(angle: f32) -> Self { - let (s, c) = scalar_sin_cos(angle * 0.5); - Self::from_xyzw(0.0, s, 0.0, c) - } - - /// Creates a new quaternion from the angle (in radians) around the z axis. - #[inline] - pub fn from_rotation_z(angle: f32) -> Self { - let (s, c) = scalar_sin_cos(angle * 0.5); - Self::from_xyzw(0.0, 0.0, s, c) - } - - #[inline] - /// Create a quaternion from the given yaw (around y), pitch (around x) and roll (around z) - /// in radians. - pub fn from_rotation_ypr(yaw: f32, pitch: f32, roll: f32) -> Self { - // Self::from_rotation_y(yaw) * Self::from_rotation_x(pitch) * Self::from_rotation_z(roll) - let (y0, w0) = scalar_sin_cos(yaw * 0.5); - let (x1, w1) = scalar_sin_cos(pitch * 0.5); - let (z2, w2) = scalar_sin_cos(roll * 0.5); - - let x3 = w0 * x1; - let y3 = y0 * w1; - let z3 = -y0 * x1; - let w3 = w0 * w1; - - let x4 = x3 * w2 + y3 * z2; - let y4 = -x3 * z2 + y3 * w2; - let z4 = w3 * z2 + z3 * w2; - let w4 = w3 * w2 - z3 * z2; - - Self(Vec4::new(x4, y4, z4, w4)) - } - - #[inline] - fn from_rotation_axes(x_axis: Vec3, y_axis: Vec3, z_axis: Vec3) -> Self { - // from DirectXMath XMQuaternionRotationMatrix - // TODO: sse2 version - let (m00, m01, m02) = x_axis.into(); - let (m10, m11, m12) = y_axis.into(); - let (m20, m21, m22) = z_axis.into(); - if m22 <= 0.0 { - // x^2 + y^2 >= z^2 + w^2 - let dif10 = m11 - m00; - let omm22 = 1.0 - m22; - if dif10 <= 0.0 { - // x^2 >= y^2 - let four_xsq = omm22 - dif10; - let inv4x = 0.5 / four_xsq.sqrt(); - Self::from_xyzw( - four_xsq * inv4x, - (m01 + m10) * inv4x, - (m02 + m20) * inv4x, - (m12 - m21) * inv4x, - ) - } else { - // y^2 >= x^2 - let four_ysq = omm22 + dif10; - let inv4y = 0.5 / four_ysq.sqrt(); - Self::from_xyzw( - (m01 + m10) * inv4y, - four_ysq * inv4y, - (m12 + m21) * inv4y, - (m20 - m02) * inv4y, - ) - } - } else { - // z^2 + w^2 >= x^2 + y^2 - let sum10 = m11 + m00; - let opm22 = 1.0 + m22; - if sum10 <= 0.0 { - // z^2 >= w^2 - let four_zsq = opm22 - sum10; - let inv4z = 0.5 / four_zsq.sqrt(); - Self::from_xyzw( - (m02 + m20) * inv4z, - (m12 + m21) * inv4z, - four_zsq * inv4z, - (m01 - m10) * inv4z, - ) - } else { - // w^2 >= z^2 - let four_wsq = opm22 + sum10; - let inv4w = 0.5 / four_wsq.sqrt(); - Self::from_xyzw( - (m12 - m21) * inv4w, - (m20 - m02) * inv4w, - (m01 - m10) * inv4w, - four_wsq * inv4w, - ) - } - } - } - - /// Creates a new quaternion from a 3x3 rotation matrix. - #[inline] - pub fn from_rotation_mat3(mat: &Mat3) -> Self { - Self::from_rotation_axes(mat.x_axis(), mat.y_axis(), mat.z_axis()) - } - - /// Creates a new quaternion from a 3x3 rotation matrix inside a homogeneous - /// 4x4 matrix. - #[inline] - pub fn from_rotation_mat4(mat: &Mat4) -> Self { - Self::from_rotation_axes( - mat.x_axis().truncate(), - mat.y_axis().truncate(), - mat.z_axis().truncate(), - ) - } - - /// Returns the rotation axis and angle of `self`. - #[inline] - pub fn to_axis_angle(self) -> (Vec3, f32) { - const EPSILON: f32 = 1.0e-8; - const EPSILON_SQUARED: f32 = EPSILON * EPSILON; - let (x, y, z, w) = self.0.into(); - let angle = scalar_acos(w) * 2.0; - let scale_sq = (1.0 - w * w).max(0.0); - if scale_sq >= EPSILON_SQUARED { - (Vec3::new(x, y, z) / scale_sq.sqrt(), angle) - } else { - (Vec3::unit_x(), angle) - } - } - - /// Returns the quaternion conjugate of `self`. For a unit quaternion the - /// conjugate is also the inverse. - #[inline] - pub fn conjugate(self) -> Self { - #[cfg(vec4sse2)] - unsafe { - Self(Vec4(_mm_xor_ps( - (self.0).0, - _mm_set_ps(0.0, -0.0, -0.0, -0.0), - ))) - } - - #[cfg(vec4f32)] - { - Self::from_xyzw(-(self.0).0, -(self.0).1, -(self.0).2, (self.0).3) - } - } - - /// Computes the dot product of `self` and `other`. The dot product is - /// equal to the the cosine of the angle between two quaterion rotations. - #[inline] - pub fn dot(self, other: Self) -> f32 { - self.0.dot(other.0) - } - - /// Computes the length of `self`. - #[inline] - pub fn length(self) -> f32 { - self.0.length() - } - - /// Computes the squared length of `self`. - /// - /// This is generally faster than `Quat::length()` as it avoids a square - /// root operation. - #[inline] - pub fn length_squared(self) -> f32 { - self.0.length_squared() - } - - /// Computes `1.0 / Quat::length()`. - /// - /// For valid results, `self` must _not_ be of length zero. - #[inline] - pub fn length_reciprocal(self) -> f32 { - 1.0 / self.0.length() - } - - /// Returns `self` normalized to length 1.0. - /// - /// For valid results, `self` must _not_ be of length zero. - #[inline] - pub fn normalize(self) -> Self { - let inv_len = self.0.length_reciprocal(); - Self(self.0.mul(inv_len)) - } - - /// Returns whether `self` of length `1.0` or not. - /// - /// Uses a precision threshold of `1e-6`. - #[inline] - pub fn is_normalized(self) -> bool { - is_normalized!(self) - } - - #[inline] - pub fn is_near_identity(self) -> bool { - // from rtm quat_near_identity - const THRESHOLD_ANGLE: f32 = 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 = scalar_acos(self.0.w().abs()) * 2.0; - positive_w_angle < THRESHOLD_ANGLE - } - - /// 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 `Quat`'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.0.abs_diff_eq(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`. - #[inline] - pub fn lerp(self, end: Self, s: f32) -> Self { - glam_assert!(self.is_normalized()); - glam_assert!(end.is_normalized()); - - #[cfg(vec4sse2)] - unsafe { - let start = self.0; - let end = end.0; - let dot = start.dot_as_vec4(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.into(), _mm_set_ps1(-0.0)); - let interpolated = Vec4(_mm_add_ps( - _mm_mul_ps( - _mm_sub_ps(_mm_xor_ps(end.into(), bias), start.0), - _mm_set_ps1(s), - ), - start.0, - )); - Self(interpolated.normalize()) - } - - #[cfg(vec4f32)] - { - let start = self.0; - let end = end.0; - let dot = start.dot(end); - let bias = if dot >= 0.0 { 1.0 } else { -1.0 }; - let interpolated = start + (s * ((end * bias) - start)); - Self(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`. - /// - /// 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`. - #[inline] - pub fn slerp(self, 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; - - let dot = self.dot(end); - - if dot > DOT_THRESHOLD { - // assumes lerp returns a normalized quaternion - self.lerp(end, s) - } else { - #[cfg(vec4f32)] - { - // assumes scalar_acos clamps the input to [-1.0, 1.0] - let theta = crate::f32::funcs::scalar_acos(dot); - let scale1 = f32::sin(theta * (1.0 - s)); - let scale2 = f32::sin(theta * s); - let theta_sin = f32::sin(theta); - - Quat((self.0 * scale1 + end.0 * scale2) * theta_sin.recip()) - } - - #[cfg(vec4sse2)] - { - // assumes scalar_acos clamps the input to [-1.0, 1.0] - let theta = crate::f32::funcs::scalar_acos(dot); - - let x = 1.0 - s; - let y = s; - let z = 1.0; - - unsafe { - let tmp = Vec4::splat(theta) * Vec4::new(x, y, z, 0.0); - let tmp = crate::f32::funcs::sse2::m128_sin(tmp.0); - - 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); - - let theta_sin_recip = Vec4(_mm_rcp_ps(theta_sin)); - - Quat((self.0 * Vec4(scale1) + end.0 * Vec4(scale2)) * theta_sin_recip) - } - } - } - } - - #[inline] - /// Multiplies a quaternion and a 3D vector, rotating it. - pub fn mul_vec3(self, other: Vec3) -> Vec3 { - glam_assert!(self.is_normalized()); - - #[cfg(vec4sse2)] - { - let w = self.0.dup_w().truncate(); - let two = Vec3::splat(2.0); - let b = self.0.truncate(); - let b2 = b.dot_as_vec3(b); - other * (w * w - b2) + b * (other.dot_as_vec3(b) * two) + b.cross(other) * (w * two) - } - - #[cfg(vec4f32)] - { - let w = self.0.w(); - let b = self.0.truncate(); - let b2 = b.dot(b); - other * (w * w - b2) + b * (other.dot(b) * 2.0) + b.cross(other) * (w * 2.0) - } - } - - #[inline] - /// Multiplies two quaternions. - /// Note that due to floating point rounding the result may not be perfectly normalized. - pub fn mul_quat(self, other: Self) -> Self { - glam_assert!(self.is_normalized()); - glam_assert!(other.is_normalized()); - - #[cfg(vec4sse2)] - unsafe { - // from rtm quat_mul - let lhs = self.0.into(); - let rhs = other.0.into(); - - let control_wzyx = _mm_set_ps(-1.0, 1.0, -1.0, 1.0); - let control_zwxy = _mm_set_ps(-1.0, -1.0, 1.0, 1.0); - let control_yxwz = _mm_set_ps(-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); - Self(Vec4(_mm_add_ps(result0, result1))) - } - - #[cfg(vec4f32)] - { - let (x0, y0, z0, w0) = self.0.into(); - let (x1, y1, z1, w1) = other.0.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, - ) - } - } - /// Returns element `x`. - #[inline] - pub fn x(self) -> f32 { - self.0.x() - } - - /// Returns element `y`. - #[inline] - pub fn y(self) -> f32 { - self.0.y() - } - - /// Returns element `z`. - #[inline] - pub fn z(self) -> f32 { - self.0.z() - } - - /// Returns element `w`. - #[inline] - pub fn w(self) -> f32 { - self.0.w() - } -} - -impl fmt::Debug for Quat { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - #[cfg(vec4sse2)] - { - fmt.debug_tuple("Quat").field(&(self.0).0).finish() - } - - #[cfg(vec4f32)] - { - fmt.debug_tuple("Quat") - .field(&self.0.x()) - .field(&self.0.y()) - .field(&self.0.z()) - .field(&self.0.w()) - .finish() - } - } -} - -impl fmt::Display for Quat { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - let (x, y, z, w) = self.0.into(); - write!(fmt, "[{}, {}, {}, {}]", x, y, z, w) - } -} - -impl Mul for Quat { - type Output = Self; - #[inline] - fn mul(self, other: Self) -> Self { - self.mul_quat(other) - } -} - -impl MulAssign for Quat { - #[inline] - fn mul_assign(&mut self, other: Self) { - *self = self.mul_quat(other); - } -} - -impl Mul for Quat { - type Output = Vec3; - #[inline] - fn mul(self, other: Vec3) -> Vec3 { - self.mul_vec3(other) - } -} - -impl Neg for Quat { - type Output = Self; - #[inline] - fn neg(self) -> Self { - Self(-1.0 * self.0) - } -} - -impl Default for Quat { - #[inline] - fn default() -> Self { - Self::identity() - } -} - -impl PartialEq for Quat { - #[inline] - fn eq(&self, other: &Self) -> bool { - self.0.cmpeq(other.0).all() - } -} - -impl PartialOrd for Quat { - #[inline] - fn partial_cmp(&self, other: &Self) -> Option { - self.as_ref().partial_cmp(other.as_ref()) - } -} - -impl AsRef<[f32; 4]> for Quat { - #[inline] - fn as_ref(&self) -> &[f32; 4] { - self.0.as_ref() - } -} - -impl AsMut<[f32; 4]> for Quat { - #[inline] - fn as_mut(&mut self) -> &mut [f32; 4] { - self.0.as_mut() - } -} - -impl From for Quat { - #[inline] - fn from(v: Vec4) -> Self { - Self(v) - } -} - -impl From for Vec4 { - #[inline] - fn from(q: Quat) -> Self { - q.0 - } -} - -impl From<(f32, f32, f32, f32)> for Quat { - #[inline] - fn from(t: (f32, f32, f32, f32)) -> Self { - Quat::from_xyzw(t.0, t.1, t.2, t.3) - } -} - -impl From for (f32, f32, f32, f32) { - #[inline] - fn from(q: Quat) -> Self { - q.0.into() - } -} - -impl From<[f32; 4]> for Quat { - #[inline] - fn from(a: [f32; 4]) -> Self { - Self(a.into()) - } -} - -impl From for [f32; 4] { - #[inline] - fn from(q: Quat) -> Self { - q.0.into() - } -} - -#[cfg(vec4sse2)] -impl From for __m128 { - // TODO: write test - #[cfg_attr(tarpaulin, skip)] - #[inline] - fn from(q: Quat) -> Self { - (q.0).0 - } -} - -#[cfg(vec4sse2)] -impl From<__m128> for Quat { - #[inline] - fn from(t: __m128) -> Self { - Self(Vec4(t)) - } -} diff --git a/crates/bevy_glam/src/f32/transform.rs b/crates/bevy_glam/src/f32/transform.rs deleted file mode 100644 index 3bd17e0a46..0000000000 --- a/crates/bevy_glam/src/f32/transform.rs +++ /dev/null @@ -1,361 +0,0 @@ -use super::{Mat4, Quat, Vec3}; -use core::ops::Mul; - -#[cfg(feature = "rand")] -use rand::{ - distributions::{Distribution, Standard}, - Rng, -}; - -#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)] -#[repr(C)] -pub struct TransformSRT { - pub scale: Vec3, - pub rotation: Quat, - pub translation: Vec3, -} - -impl Default for TransformSRT { - #[inline] - fn default() -> Self { - Self { - scale: Vec3::one(), - rotation: Quat::identity(), - translation: Vec3::zero(), - } - } -} - -#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)] -#[repr(C)] -pub struct TransformRT { - pub rotation: Quat, - pub translation: Vec3, -} - -impl Default for TransformRT { - #[inline] - fn default() -> Self { - Self { - rotation: Quat::identity(), - translation: Vec3::zero(), - } - } -} - -impl TransformSRT { - #[inline] - pub fn from_scale_rotation_translation(scale: Vec3, rotation: Quat, translation: Vec3) -> Self { - Self { - scale, - rotation, - translation, - } - } - - #[inline] - pub fn from_transform_rt(scale: Vec3, rt: &TransformRT) -> Self { - Self { - scale, - rotation: rt.rotation, - translation: rt.translation, - } - } - - #[inline] - pub fn identity() -> Self { - Self { - scale: Vec3::one(), - rotation: Quat::identity(), - translation: Vec3::zero(), - } - } - - #[inline] - pub fn inverse(&self) -> Self { - let scale = self.scale.reciprocal(); - let rotation = self.rotation.conjugate(); - let translation = -(rotation * (self.translation * scale)); - Self { - scale, - rotation, - translation, - } - } - - #[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) - } - - #[inline] - pub fn transform_vec3(self, other: Vec3) -> Vec3 { - (self.rotation * (other * self.scale)) + self.translation - } - - /// 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 { - // from rtm qvv_mul - let min_scale = lhs.scale.min(rhs.scale); - let scale = lhs.scale * rhs.scale; - - if min_scale.cmplt(Vec3::zero()).any() { - // If negative scale, we go through a matrix - let lhs_mtx = - Mat4::from_scale_rotation_translation(lhs.scale, lhs.rotation, lhs.translation); - let rhs_mtx = - Mat4::from_scale_rotation_translation(rhs.scale, rhs.rotation, rhs.translation); - let mut result_mtx = lhs_mtx * rhs_mtx; - - let sign = scale.sign(); - result_mtx - .set_x_axis((result_mtx.x_axis().truncate().normalize() * sign.dup_x()).extend(0.0)); - result_mtx - .set_y_axis((result_mtx.y_axis().truncate().normalize() * sign.dup_y()).extend(0.0)); - result_mtx - .set_z_axis((result_mtx.z_axis().truncate().normalize() * sign.dup_z()).extend(0.0)); - - let rotation = Quat::from_rotation_mat4(&result_mtx); - let translation = result_mtx.w_axis().truncate(); - TransformSRT { - scale, - rotation, - translation, - } - } else { - let rotation = lhs.rotation * rhs.rotation; - let translation = (rhs.rotation * (lhs.translation * rhs.scale)) + rhs.translation; - TransformSRT { - scale, - rotation, - translation, - } - } -} - -#[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 { - #[inline] - pub fn from_rotation_translation(rotation: Quat, translation: Vec3) -> Self { - Self { - rotation, - translation, - } - } - - #[inline] - pub fn identity() -> Self { - Self { - rotation: Quat::identity(), - translation: Vec3::zero(), - } - } - - #[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) - } - - #[inline] - pub fn transform_vec3(self, other: Vec3) -> Vec3 { - (self.rotation * other) + self.translation - } - - /// 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 AsRef for TransformSRT { - #[inline] - fn as_ref(&self) -> &TransformRT { - unsafe { &*(self as *const Self as *const TransformRT) } - } -} - -impl AsMut for TransformSRT { - #[inline] - fn as_mut(&mut self) -> &mut TransformRT { - unsafe { &mut *(self as *mut Self as *mut TransformRT) } - } -} - -impl Mul for TransformRT { - type Output = Vec3; - #[inline] - fn mul(self, other: Vec3) -> Vec3 { - self.transform_vec3(other) - } -} - -impl Mul for TransformSRT { - type Output = Vec3; - #[inline] - fn mul(self, other: Vec3) -> Vec3 { - self.transform_vec3(other) - } -} - -impl Mul for TransformRT { - type Output = TransformRT; - #[inline] - fn mul(self, other: TransformRT) -> TransformRT { - mul_rt_rt(&self, &other) - } -} - -impl Mul for TransformSRT { - type Output = Self; - #[inline] - fn mul(self, other: Self) -> Self::Output { - mul_srt_srt(&self, &other) - } -} - -impl Mul for TransformSRT { - type Output = TransformSRT; - #[inline] - fn mul(self, other: TransformRT) -> Self::Output { - mul_srt_srt(&self, &other.into()) - } -} - -impl Mul for TransformRT { - type Output = TransformSRT; - #[inline] - fn mul(self, other: TransformSRT) -> Self::Output { - mul_srt_srt(&self.into(), &other) - } -} - -impl From for TransformSRT { - #[inline] - fn from(tr: TransformRT) -> Self { - Self { - translation: tr.translation, - rotation: tr.rotation, - scale: Vec3::one(), - } - } -} - -#[cfg(feature = "rand")] -impl Distribution for Standard { - #[inline] - fn sample(&self, rng: &mut R) -> TransformRT { - TransformRT::from_rotation_translation( - rng.gen::(), - Vec3::new( - rng.gen_range(core::f32::MIN, core::f32::MAX), - rng.gen_range(core::f32::MIN, core::f32::MAX), - rng.gen_range(core::f32::MIN, core::f32::MAX), - ), - ) - } -} - -#[cfg(feature = "rand")] -impl Distribution for Standard { - #[inline] - fn sample(&self, rng: &mut R) -> TransformSRT { - let mut gen_non_zero = || loop { - let f: f32 = rng.gen_range(core::f32::MIN, core::f32::MAX); - if f.abs() > core::f32::MIN_POSITIVE { - return f; - } - }; - TransformSRT::from_scale_rotation_translation( - Vec3::new(gen_non_zero(), gen_non_zero(), gen_non_zero()), - rng.gen::(), - Vec3::new( - rng.gen_range(core::f32::MIN, core::f32::MAX), - rng.gen_range(core::f32::MIN, core::f32::MAX), - rng.gen_range(core::f32::MIN, core::f32::MAX), - ), - ) - } -} - -impl From for Mat4 { - #[inline] - fn from(srt: TransformSRT) -> Self { - Mat4::from_scale_rotation_translation(srt.scale, srt.rotation, srt.translation) - } -} - -impl From for Mat4 { - #[inline] - fn from(rt: TransformRT) -> Self { - Mat4::from_rotation_translation(rt.rotation, rt.translation) - } -} diff --git a/crates/bevy_glam/src/f32/vec2.rs b/crates/bevy_glam/src/f32/vec2.rs deleted file mode 100644 index 809a03f68a..0000000000 --- a/crates/bevy_glam/src/f32/vec2.rs +++ /dev/null @@ -1,509 +0,0 @@ -use crate::f32::{Vec2Mask, Vec3}; -use core::{f32, fmt, ops::*}; - -/// A 2-dimensional vector. -#[derive(Clone, Copy, PartialEq, PartialOrd, Debug, Default)] -#[repr(C)] -pub struct Vec2(pub(crate) f32, pub(crate) f32); - -#[inline] -pub fn vec2(x: f32, y: f32) -> Vec2 { - Vec2(x, y) -} - -impl Vec2 { - /// Returns a new `Vec4` 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` - #[inline] - pub fn sign(self) -> Self { - let mask = self.cmpge(Self::zero()); - mask.select(Self::splat(1.0), Self::splat(-1.0)) - } - - /// Computes the reciprocal `1.0/n` of each element, returning the - /// results in a new `Vec2`. - #[inline] - pub fn reciprocal(self) -> Self { - Self::one() / self - } - - /// 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`. - #[inline] - pub fn lerp(self, other: Self, s: f32) -> Self { - self + ((other - self) * s) - } - - /// Returns whether `self` is length `1.0` or not. - /// - /// Uses a precision threshold of `1e-6`. - #[inline] - pub fn is_normalized(self) -> bool { - is_normalized!(self) - } - - /// 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 `Vec2`'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 { - abs_diff_eq!(self, other, max_abs_diff) - } - - /// Creates a new `Vec2`. - #[inline] - pub fn new(x: f32, y: f32) -> Vec2 { - Vec2(x, y) - } - - /// Creates a new `Vec2` with all elements set to `0.0`. - #[inline] - pub fn zero() -> Vec2 { - Vec2(0.0, 0.0) - } - - /// Creates a new `Vec2` with all elements set to `1.0`. - #[inline] - pub fn one() -> Vec2 { - Vec2(1.0, 1.0) - } - - /// Creates a new `Vec2` with values `[x: 1.0, y: 0.0]`. - #[inline] - pub fn unit_x() -> Vec2 { - Vec2(1.0, 0.0) - } - - /// Creates a new `Vec2` with values `[x: 0.0, y: 1.0]`. - #[inline] - pub fn unit_y() -> Vec2 { - Vec2(0.0, 1.0) - } - - /// Creates a new `Vec2` with all elements set to `v`. - #[inline] - pub fn splat(v: f32) -> Vec2 { - Vec2(v, v) - } - - /// Creates a new `Vec3` from `self` and the given `z` value. - #[inline] - pub fn extend(self, z: f32) -> Vec3 { - Vec3::new(self.0, self.1, z) - } - - /// Returns element `x`. - #[inline] - pub fn x(self) -> f32 { - self.0 - } - - /// Returns element `y`. - #[inline] - pub fn y(self) -> f32 { - self.1 - } - - /// Returns a mutable reference to element `x`. - #[inline] - pub fn x_mut(&mut self) -> &mut f32 { - &mut self.0 - } - - /// Returns a mutable reference to element `y`. - #[inline] - pub fn y_mut(&mut self) -> &mut f32 { - &mut self.1 - } - - /// Sets element `x`. - #[inline] - pub fn set_x(&mut self, x: f32) { - self.0 = x; - } - - /// Sets element `y`. - #[inline] - pub fn set_y(&mut self, y: f32) { - self.1 = y; - } - - /// Computes the dot product of `self` and `other`. - #[inline] - pub fn dot(self, other: Vec2) -> f32 { - (self.0 * other.0) + (self.1 * other.1) - } - - /// Computes the length of `self`. - #[inline] - pub fn length(self) -> f32 { - self.dot(self).sqrt() - } - - /// Computes the squared length of `self`. - /// - /// This is generally faster than `Vec2::length()` as it avoids a square - /// root operation. - #[inline] - pub fn length_squared(self) -> f32 { - self.dot(self) - } - - /// Computes `1.0 / Vec2::length()`. - /// - /// For valid results, `self` must _not_ be of length zero. - #[inline] - pub fn length_reciprocal(self) -> f32 { - 1.0 / self.length() - } - - /// Returns `self` normalized to length 1.0. - /// - /// For valid results, `self` must _not_ be of length zero. - #[inline] - pub fn normalize(self) -> Vec2 { - self * self.length_reciprocal() - } - - /// Returns the vertical minimum of `self` and `other`. - /// - /// In other words, this computes - /// `[x: min(x1, x2), y: min(y1, y2)]`, - /// taking the minimum of each element individually. - #[inline] - pub fn min(self, other: Vec2) -> Vec2 { - Vec2(self.0.min(other.0), self.1.min(other.1)) - } - - /// Returns the vertical maximum of `self` and `other`. - /// - /// In other words, this computes - /// `[x: max(x1, x2), y: max(y1, y2)]`, - /// taking the maximum of each element individually. - #[inline] - pub fn max(self, other: Vec2) -> Vec2 { - Vec2(self.0.max(other.0), self.1.max(other.1)) - } - - /// Returns the horizontal minimum of `self`'s elements. - /// - /// In other words, this computes `min(x, y)`. - #[inline] - pub fn min_element(self) -> f32 { - self.0.min(self.1) - } - - /// Returns the horizontal maximum of `self`'s elements. - /// - /// In other words, this computes `max(x, y)`. - #[inline] - pub fn max_element(self) -> f32 { - self.0.max(self.1) - } - - /// Performs a vertical `==` comparison between `self` and `other`, - /// returning a `Vec2Mask` of the results. - /// - /// In other words, this computes `[x1 == x2, y1 == y2, z1 == z2, w1 == w2]`. - #[inline] - pub fn cmpeq(self, other: Vec2) -> Vec2Mask { - Vec2Mask::new(self.0.eq(&other.0), self.1.eq(&other.1)) - } - - /// Performs a vertical `!=` comparison between `self` and `other`, - /// returning a `Vec2Mask` of the results. - /// - /// In other words, this computes `[x1 != x2, y1 != y2, z1 != z2, w1 != w2]`. - #[inline] - pub fn cmpne(self, other: Vec2) -> Vec2Mask { - Vec2Mask::new(self.0.ne(&other.0), self.1.ne(&other.1)) - } - - /// Performs a vertical `>=` comparison between `self` and `other`, - /// returning a `Vec2Mask` of the results. - /// - /// In other words, this computes `[x1 >= x2, y1 >= y2, z1 >= z2, w1 >= w2]`. - #[inline] - pub fn cmpge(self, other: Vec2) -> Vec2Mask { - Vec2Mask::new(self.0.ge(&other.0), self.1.ge(&other.1)) - } - - /// Performs a vertical `>` comparison between `self` and `other`, - /// returning a `Vec2Mask` of the results. - /// - /// In other words, this computes `[x1 > x2, y1 > y2, z1 > z2, w1 > w2]`. - #[inline] - pub fn cmpgt(self, other: Vec2) -> Vec2Mask { - Vec2Mask::new(self.0.gt(&other.0), self.1.gt(&other.1)) - } - - /// Performs a vertical `<=` comparison between `self` and `other`, - /// returning a `Vec2Mask` of the results. - /// - /// In other words, this computes `[x1 <= x2, y1 <= y2, z1 <= z2, w1 <= w2]`. - #[inline] - pub fn cmple(self, other: Vec2) -> Vec2Mask { - Vec2Mask::new(self.0.le(&other.0), self.1.le(&other.1)) - } - - /// Performs a vertical `<` comparison between `self` and `other`, - /// returning a `Vec2Mask` of the results. - /// - /// In other words, this computes `[x1 < x2, y1 < y2, z1 < z2, w1 < w2]`. - #[inline] - pub fn cmplt(self, other: Vec2) -> Vec2Mask { - Vec2Mask::new(self.0.lt(&other.0), self.1.lt(&other.1)) - } - - /// Creates a new `Vec2` from the first two values in `slice`. - /// - /// # Panics - /// - /// Panics if `slice` is less than two elements long. - #[inline] - pub fn from_slice_unaligned(slice: &[f32]) -> Self { - Self(slice[0], slice[1]) - } - - /// Writes the elements of `self` to the first two elements in `slice`. - /// - /// # Panics - /// - /// Panics if `slice` is less than two elements long. - #[inline] - pub fn write_to_slice_unaligned(self, slice: &mut [f32]) { - slice[0] = self.0; - slice[1] = self.1; - } - - /// Returns a new `Vec2` containing the absolute value of each element of the original - /// `Vec2`. - #[inline] - pub fn abs(self) -> Self { - Self(self.0.abs(), self.1.abs()) - } - - #[inline] - pub fn round(self) -> Self { - Self(self.0.round(), self.1.round()) - } - - #[inline] - pub fn floor(self) -> Self { - Self(self.0.floor(), self.1.floor()) - } - - #[inline] - pub fn ceil(self) -> Self { - Self(self.0.ceil(), self.1.ceil()) - } - - /// The perpendicular dot product of the vector and `other`. - #[inline] - pub fn perp_dot(self, other: Vec2) -> f32 { - (self.0 * other.1) - (self.1 * other.0) - } - - /// Returns the angle between two vectors, in radians. - /// - /// The vectors do not need to be unit length, but this function does - /// perform a `sqrt`. - #[inline] - pub fn angle_between(self, other: Self) -> f32 { - let angle = crate::f32::funcs::scalar_acos( - self.dot(other) / (self.dot(self) * other.dot(other)).sqrt(), - ); - - if self.perp_dot(other) < 0.0 { - -angle - } else { - angle - } - } -} - -impl fmt::Display for Vec2 { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "[{}, {}]", self.0, self.1) - } -} - -impl Div for Vec2 { - type Output = Self; - #[inline] - fn div(self, other: Vec2) -> Self { - Self(self.0 / other.0, self.1 / other.1) - } -} - -impl DivAssign for Vec2 { - #[inline] - fn div_assign(&mut self, other: Vec2) { - self.0 /= other.0; - self.1 /= other.1; - } -} - -impl Div for Vec2 { - type Output = Self; - #[inline] - fn div(self, other: f32) -> Self { - Self(self.0 / other, self.1 / other) - } -} - -impl DivAssign for Vec2 { - #[inline] - fn div_assign(&mut self, other: f32) { - self.0 /= other; - self.1 /= other; - } -} - -impl Mul for Vec2 { - type Output = Self; - #[inline] - fn mul(self, other: Vec2) -> Self { - Self(self.0 * other.0, self.1 * other.1) - } -} - -impl MulAssign for Vec2 { - #[inline] - fn mul_assign(&mut self, other: Vec2) { - self.0 *= other.0; - self.1 *= other.1; - } -} - -impl Mul for Vec2 { - type Output = Self; - #[inline] - fn mul(self, other: f32) -> Self { - Self(self.0 * other, self.1 * other) - } -} - -impl MulAssign for Vec2 { - #[inline] - fn mul_assign(&mut self, other: f32) { - self.0 *= other; - self.1 *= other; - } -} - -impl Mul for f32 { - type Output = Vec2; - #[inline] - fn mul(self, other: Vec2) -> Vec2 { - Vec2(self * other.0, self * other.1) - } -} - -impl Add for Vec2 { - type Output = Self; - #[inline] - fn add(self, other: Self) -> Self { - Self(self.0 + other.0, self.1 + other.1) - } -} - -impl AddAssign for Vec2 { - #[inline] - fn add_assign(&mut self, other: Self) { - self.0 += other.0; - self.1 += other.1; - } -} - -impl Sub for Vec2 { - type Output = Self; - #[inline] - fn sub(self, other: Vec2) -> Self { - Self(self.0 - other.0, self.1 - other.1) - } -} - -impl SubAssign for Vec2 { - #[inline] - fn sub_assign(&mut self, other: Vec2) { - self.0 -= other.0; - self.1 -= other.1; - } -} - -impl Neg for Vec2 { - type Output = Self; - #[inline] - fn neg(self) -> Self { - Self(-self.0, -self.1) - } -} - -impl AsRef<[f32; 2]> for Vec2 { - #[inline] - fn as_ref(&self) -> &[f32; 2] { - unsafe { &*(self as *const Vec2 as *const [f32; 2]) } - } -} - -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 Index for Vec2 { - type Output = f32; - #[inline] - fn index(&self, index: usize) -> &Self::Output { - &self.as_ref()[index] - } -} - -impl IndexMut for Vec2 { - #[inline] - fn index_mut(&mut self, index: usize) -> &mut Self::Output { - &mut self.as_mut()[index] - } -} - -impl From<(f32, f32)> for Vec2 { - #[inline] - fn from(t: (f32, f32)) -> Self { - Self(t.0, t.1) - } -} - -impl From for (f32, f32) { - #[inline] - fn from(v: Vec2) -> Self { - (v.0, v.1) - } -} - -impl From<[f32; 2]> for Vec2 { - #[inline] - fn from(a: [f32; 2]) -> Self { - Self(a[0], a[1]) - } -} - -impl From for [f32; 2] { - #[inline] - fn from(v: Vec2) -> Self { - [v.0, v.1] - } -} diff --git a/crates/bevy_glam/src/f32/vec2_mask.rs b/crates/bevy_glam/src/f32/vec2_mask.rs deleted file mode 100644 index 99d75bfdee..0000000000 --- a/crates/bevy_glam/src/f32/vec2_mask.rs +++ /dev/null @@ -1,126 +0,0 @@ -use super::Vec2; -use core::{fmt, ops::*}; - -/// A 2-dimensional vector mask. -/// -/// This type is typically created by comparison methods on `Vec2`. -#[derive(Clone, Copy, Default, PartialEq, Eq, Ord, PartialOrd, Hash)] -#[repr(C)] -pub struct Vec2Mask(u32, u32); - -impl Vec2Mask { - /// Creates a new `Vec2Mask`. - #[inline] - pub fn new(x: bool, y: bool) -> Self { - const MASK: [u32; 2] = [0, 0xff_ff_ff_ff]; - Self(MASK[x as usize], MASK[y as usize]) - } - - /// Returns a bitmask with the lowest two bits set from the elements of - /// the `Vec2Mask`. - /// - /// 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 & 0x1) | (self.1 & 0x1) << 1 - } - - /// Returns true if any of the elements are true, false otherwise. - /// - /// In other words: `x || y`. - #[inline] - pub fn any(self) -> bool { - // implementaton matches SSE2 `Vec4Mask` version - ((self.0 | self.1) & 0x1) != 0 - } - - /// Returns true if all the elements are true, false otherwise. - /// - /// In other words: `x && y`. - #[inline] - pub fn all(self) -> bool { - // implementaton matches SSE2 `Vec4Mask` version - ((self.0 & self.1) & 0x1) != 0 - } - - /// Creates a new `Vec2` from the elements in `if_true` and `if_false`, - /// selecting which to use for each element based on the `Vec2Mask`. - /// - /// 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(self, if_true: Vec2, if_false: Vec2) -> Vec2 { - Vec2( - if self.0 != 0 { if_true.0 } else { if_false.0 }, - if self.1 != 0 { if_true.1 } else { if_false.1 }, - ) - } -} - -impl BitAnd for Vec2Mask { - type Output = Self; - #[inline] - fn bitand(self, other: Self) -> Self { - Self(self.0 & other.0, self.1 & other.1) - } -} - -impl BitAndAssign for Vec2Mask { - #[inline] - fn bitand_assign(&mut self, other: Self) { - self.0 &= other.0; - self.1 &= other.1; - } -} - -impl BitOr for Vec2Mask { - type Output = Self; - #[inline] - fn bitor(self, other: Self) -> Self { - Self(self.0 | other.0, self.1 | other.1) - } -} - -impl BitOrAssign for Vec2Mask { - #[inline] - fn bitor_assign(&mut self, other: Self) { - self.0 |= other.0; - self.1 |= other.1; - } -} - -impl Not for Vec2Mask { - type Output = Self; - #[inline] - fn not(self) -> Self { - Self(!self.0, !self.1) - } -} - -impl fmt::Debug for Vec2Mask { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "Vec2Mask({:#x}, {:#x})", self.0, self.1) - } -} - -impl fmt::Display for Vec2Mask { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "[{}, {}]", self.0 != 0, self.1 != 0) - } -} - -impl From for [u32; 2] { - #[inline] - fn from(mask: Vec2Mask) -> Self { - [mask.0, mask.1] - } -} - -impl AsRef<[u32; 2]> for Vec2Mask { - #[inline] - fn as_ref(&self) -> &[u32; 2] { - unsafe { &*(self as *const Self as *const [u32; 2]) } - } -} diff --git a/crates/bevy_glam/src/f32/vec3.rs b/crates/bevy_glam/src/f32/vec3.rs deleted file mode 100644 index 53ca3e59af..0000000000 --- a/crates/bevy_glam/src/f32/vec3.rs +++ /dev/null @@ -1,1221 +0,0 @@ -use super::{Vec2, Vec3Mask, Vec4}; -use core::{fmt, ops::*}; - -#[cfg(all(vec3sse2, target_arch = "x86"))] -use core::arch::x86::*; -#[cfg(all(vec3sse2, target_arch = "x86_64"))] -use core::arch::x86_64::*; - -#[cfg(vec3sse2)] -use core::{cmp::Ordering, f32, mem::MaybeUninit}; - -#[cfg(vec3sse2)] -use crate::{ - f32::{X_AXIS, Y_AXIS, Z_AXIS}, - Align16, -}; - -/// A 3-dimensional vector. -/// -/// This type is 16 byte aligned and thus contains 4 bytes padding. -#[cfg(vec3sse2)] -#[derive(Clone, Copy, Debug)] -#[repr(C)] -pub struct Vec3(pub(crate) __m128); - -/// A 3-dimensional vector. -#[cfg(vec3f32)] -#[derive(Clone, Copy, PartialEq, PartialOrd, Debug, Default)] -// if compiling with simd enabled assume alignment needs to match the simd type -#[cfg_attr(vec3f32_align16, repr(align(16)))] -#[repr(C)] -pub struct Vec3(pub(crate) f32, pub(crate) f32, pub(crate) f32); - -#[cfg(vec3sse2)] -impl Vec3 { - /// Calculates the Vec3 dot product and returns answer in x lane of __m128. - #[inline] - unsafe fn dot_as_m128(self, other: Self) -> __m128 { - let x2_y2_z2_w2 = _mm_mul_ps(self.0, other.0); - 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) - } -} - -#[cfg(vec3sse2)] -impl Default for Vec3 { - #[inline] - fn default() -> Self { - Vec3::zero() - } -} - -#[cfg(vec3sse2)] -impl PartialEq for Vec3 { - #[inline] - fn eq(&self, other: &Self) -> bool { - self.cmpeq(*other).all() - } -} - -#[cfg(vec3sse2)] -impl PartialOrd for Vec3 { - #[inline] - fn partial_cmp(&self, other: &Self) -> Option { - self.as_ref().partial_cmp(other.as_ref()) - } -} - -#[cfg(vec3sse2)] -impl From for __m128 { - // TODO: write test - #[cfg_attr(tarpaulin, skip)] - #[inline] - fn from(t: Vec3) -> Self { - t.0 - } -} - -#[cfg(vec3sse2)] -impl From<__m128> for Vec3 { - #[inline] - fn from(t: __m128) -> Self { - Self(t) - } -} - -#[inline] -pub fn vec3(x: f32, y: f32, z: f32) -> Vec3 { - Vec3::new(x, y, z) -} - -impl Vec3 { - /// Creates a new `Vec3`. - #[inline] - pub fn new(x: f32, y: f32, z: f32) -> Self { - #[cfg(vec3sse2)] - unsafe { - Self(_mm_set_ps(z, z, y, x)) - } - - #[cfg(vec3f32)] - { - Self(x, y, z) - } - } - - /// Creates a new `Vec3` with all elements set to `0.0`. - #[inline] - pub fn zero() -> Self { - #[cfg(vec3sse2)] - unsafe { - Self(_mm_setzero_ps()) - } - - #[cfg(vec3f32)] - { - Self(0.0, 0.0, 0.0) - } - } - - /// Creates a new `Vec3` with all elements set to `1.0`. - #[inline] - pub fn one() -> Self { - #[cfg(vec3sse2)] - unsafe { - Self(_mm_set1_ps(1.0)) - } - - #[cfg(vec3f32)] - { - Self(1.0, 1.0, 1.0) - } - } - - /// Creates a new `Vec3` with values `[x: 1.0, y: 0.0, z: 0.0]`. - #[inline] - pub fn unit_x() -> Self { - #[cfg(vec3sse2)] - unsafe { - Self(_mm_load_ps(X_AXIS.0.as_ptr())) - } - - #[cfg(vec3f32)] - { - Self(1.0, 0.0, 0.0) - } - } - - /// Creates a new `Vec3` with values `[x: 0.0, y: 1.0, z: 0.0]`. - #[inline] - pub fn unit_y() -> Self { - #[cfg(vec3sse2)] - unsafe { - Self(_mm_load_ps(Y_AXIS.0.as_ptr())) - } - - #[cfg(vec3f32)] - { - Self(0.0, 1.0, 0.0) - } - } - - /// Creates a new `Vec3` with values `[x: 0.0, y: 0.0, z: 1.0]`. - #[inline] - pub fn unit_z() -> Self { - #[cfg(vec3sse2)] - unsafe { - Self(_mm_load_ps(Z_AXIS.0.as_ptr())) - } - - #[cfg(vec3f32)] - { - Self(0.0, 0.0, 1.0) - } - } - - /// Creates a new `Vec3` with all elements set to `v`. - #[inline] - pub fn splat(v: f32) -> Self { - #[cfg(vec3sse2)] - unsafe { - Self(_mm_set_ps1(v)) - } - - #[cfg(vec3f32)] - { - Self(v, v, v) - } - } - - /// Creates a new `Vec4` from `self` and the given `w` value. - #[inline] - pub fn extend(self, w: f32) -> Vec4 { - #[cfg(vec3sse2)] - { - let mut temp: Vec4 = self.0.into(); - temp.set_w(w); - temp - } - - #[cfg(vec3f32)] - { - Vec4::new(self.0, self.1, self.2, w) - } - } - - /// Creates a `Vec2` from the first three elements of `self`, - /// removing `z`. - #[inline] - pub fn truncate(self) -> Vec2 { - #[cfg(vec3sse2)] - { - let (x, y, _) = self.into(); - Vec2::new(x, y) - } - - #[cfg(vec3f32)] - { - Vec2::new(self.0, self.1) - } - } - - /// Returns element `x`. - #[inline] - pub fn x(self) -> f32 { - #[cfg(vec3sse2)] - unsafe { - _mm_cvtss_f32(self.0) - } - - #[cfg(vec3f32)] - { - self.0 - } - } - - /// Returns element `y`. - #[inline] - pub fn y(self) -> f32 { - #[cfg(vec3sse2)] - unsafe { - _mm_cvtss_f32(_mm_shuffle_ps(self.0, self.0, 0b01_01_01_01)) - } - - #[cfg(vec3f32)] - { - self.1 - } - } - - /// Returns element `z`. - #[inline] - pub fn z(self) -> f32 { - #[cfg(vec3sse2)] - unsafe { - _mm_cvtss_f32(_mm_shuffle_ps(self.0, self.0, 0b10_10_10_10)) - } - - #[cfg(vec3f32)] - { - self.2 - } - } - - /// Returns a mutable reference to element `x`. - #[inline] - pub fn x_mut(&mut self) -> &mut f32 { - #[cfg(vec3sse2)] - unsafe { - &mut *(self as *mut Self as *mut f32) - } - - #[cfg(vec3f32)] - { - &mut self.0 - } - } - - /// Returns a mutable reference to element `y`. - #[inline] - pub fn y_mut(&mut self) -> &mut f32 { - #[cfg(vec3sse2)] - unsafe { - &mut *(self as *mut Self as *mut f32).offset(1) - } - - #[cfg(vec3f32)] - { - &mut self.1 - } - } - - /// Returns a mutable reference to element `z`. - #[inline] - pub fn z_mut(&mut self) -> &mut f32 { - #[cfg(vec3sse2)] - unsafe { - &mut *(self as *mut Self as *mut f32).offset(2) - } - - #[cfg(vec3f32)] - { - &mut self.2 - } - } - - /// Sets element `x`. - #[inline] - pub fn set_x(&mut self, x: f32) { - #[cfg(vec3sse2)] - unsafe { - self.0 = _mm_move_ss(self.0, _mm_set_ss(x)); - } - - #[cfg(vec3f32)] - { - self.0 = x; - } - } - - /// Sets element `y`. - #[inline] - pub fn set_y(&mut self, y: f32) { - #[cfg(vec3sse2)] - unsafe { - let mut t = _mm_move_ss(self.0, _mm_set_ss(y)); - t = _mm_shuffle_ps(t, t, 0b11_10_00_00); - self.0 = _mm_move_ss(t, self.0); - } - - #[cfg(vec3f32)] - { - self.1 = y; - } - } - - /// Sets element `z`. - #[inline] - pub fn set_z(&mut self, z: f32) { - #[cfg(vec3sse2)] - unsafe { - let mut t = _mm_move_ss(self.0, _mm_set_ss(z)); - t = _mm_shuffle_ps(t, t, 0b11_00_01_00); - self.0 = _mm_move_ss(t, self.0); - } - - #[cfg(vec3f32)] - { - self.2 = z; - } - } - - /// Returns a `Vec3` with all elements set to the value of element `x`. - #[inline] - pub(crate) fn dup_x(self) -> Self { - #[cfg(vec3sse2)] - unsafe { - Self(_mm_shuffle_ps(self.0, self.0, 0b00_00_00_00)) - } - - #[cfg(vec3f32)] - { - Self(self.0, self.0, self.0) - } - } - - /// Returns a `Vec3` with all elements set to the value of element `y`. - #[inline] - pub(crate) fn dup_y(self) -> Self { - #[cfg(vec3sse2)] - unsafe { - Self(_mm_shuffle_ps(self.0, self.0, 0b01_01_01_01)) - } - - #[cfg(vec3f32)] - { - Self(self.1, self.1, self.1) - } - } - - /// Returns a `Vec3` with all elements set to the value of element `z`. - #[inline] - pub(crate) fn dup_z(self) -> Self { - #[cfg(vec3sse2)] - unsafe { - Self(_mm_shuffle_ps(self.0, self.0, 0b10_10_10_10)) - } - - #[cfg(vec3f32)] - { - Self(self.2, self.2, self.2) - } - } - - /// Computes the dot product of `self` and `other`. - #[inline] - pub fn dot(self, other: Self) -> f32 { - #[cfg(vec3sse2)] - unsafe { - _mm_cvtss_f32(self.dot_as_m128(other)) - } - - #[cfg(vec3f32)] - { - (self.0 * other.0) + (self.1 * other.1) + (self.2 * other.2) - } - } - - /// Returns Vec3 dot in all lanes of Vec3 - #[inline] - pub(crate) fn dot_as_vec3(self, other: Self) -> Self { - #[cfg(vec3sse2)] - unsafe { - let dot_in_x = self.dot_as_m128(other); - Vec3(_mm_shuffle_ps(dot_in_x, dot_in_x, 0b00_00_00_00)) - } - - #[cfg(vec3f32)] - { - let dot = self.dot(other); - Vec3::new(dot, dot, dot) - } - } - - /// Computes the cross product of `self` and `other`. - #[inline] - pub fn cross(self, other: Self) -> Self { - #[cfg(vec3sse2)] - 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.0, self.0, 0b01_01_00_10); - let rhszxy = _mm_shuffle_ps(other.0, other.0, 0b01_01_00_10); - let lhszxy_rhs = _mm_mul_ps(lhszxy, other.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)) - } - - #[cfg(vec3f32)] - { - Self( - self.1 * other.2 - other.1 * self.2, - self.2 * other.0 - other.2 * self.0, - self.0 * other.1 - other.0 * self.1, - ) - } - } - - /// Computes the length of `self`. - #[inline] - pub fn length(self) -> f32 { - #[cfg(vec3sse2)] - unsafe { - _mm_cvtss_f32(_mm_sqrt_ss(self.dot_as_m128(self))) - } - - #[cfg(vec3f32)] - { - self.dot(self).sqrt() - } - } - - /// Computes the squared length of `self`. - /// - /// This is generally faster than `Vec3::length()` as it avoids a square - /// root operation. - #[inline] - pub fn length_squared(self) -> f32 { - self.dot(self) - } - - /// Computes `1.0 / Vec3::length()`. - /// - /// For valid results, `self` must _not_ be of length zero. - #[inline] - pub fn length_reciprocal(self) -> f32 { - #[cfg(vec3sse2)] - { - let dot = self.dot_as_vec3(self); - unsafe { - // _mm_rsqrt_ps is lower precision - _mm_cvtss_f32(_mm_div_ps(_mm_set_ps1(1.0), _mm_sqrt_ps(dot.0))) - } - } - - #[cfg(vec3f32)] - { - 1.0 / self.length() - } - } - - /// Returns `self` normalized to length 1.0. - /// - /// For valid results, `self` must _not_ be of length zero. - #[inline] - pub fn normalize(self) -> Self { - #[cfg(vec3sse2)] - { - let dot = self.dot_as_vec3(self); - unsafe { Self(_mm_div_ps(self.0, _mm_sqrt_ps(dot.0))) } - } - - #[cfg(vec3f32)] - { - self * self.length_reciprocal() - } - } - - /// Returns the vertical minimum of `self` and `other`. - /// - /// In other words, this computes - /// `[x: min(x1, x2), y: min(y1, y2), z: min(z1, z2)]`, - /// taking the minimum of each element individually. - #[inline] - pub fn min(self, other: Self) -> Self { - #[cfg(vec3sse2)] - unsafe { - Self(_mm_min_ps(self.0, other.0)) - } - - #[cfg(vec3f32)] - { - Self( - self.0.min(other.0), - self.1.min(other.1), - self.2.min(other.2), - ) - } - } - - /// Returns the vertical maximum of `self` and `other`. - /// - /// In other words, this computes - /// `[x: max(x1, x2), y: max(y1, y2), z: max(z1, z2)]`, - /// taking the maximum of each element individually. - #[inline] - pub fn max(self, other: Self) -> Self { - #[cfg(vec3sse2)] - unsafe { - Self(_mm_max_ps(self.0, other.0)) - } - - #[cfg(vec3f32)] - { - Self( - self.0.max(other.0), - self.1.max(other.1), - self.2.max(other.2), - ) - } - } - - /// Returns the horizontal minimum of `self`'s elements. - /// - /// In other words, this computes `min(x, y, z)`. - #[inline] - pub fn min_element(self) -> f32 { - #[cfg(vec3sse2)] - 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) - } - - #[cfg(vec3f32)] - { - self.0.min(self.1.min(self.2)) - } - } - - /// Returns the horizontal maximum of `self`'s elements. - /// - /// In other words, this computes `max(x, y, z)`. - #[inline] - pub fn max_element(self) -> f32 { - #[cfg(vec3sse2)] - 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) - } - - #[cfg(vec3f32)] - { - self.0.max(self.1.max(self.2)) - } - } - - /// Performs a vertical `==` comparison between `self` and `other`, - /// returning a `Vec3Mask` of the results. - /// - /// In other words, this computes `[x1 == x2, y1 == y2, z1 == z2, w1 == w2]`. - #[inline] - pub fn cmpeq(self, other: Self) -> Vec3Mask { - #[cfg(vec3sse2)] - unsafe { - Vec3Mask(_mm_cmpeq_ps(self.0, other.0)) - } - - #[cfg(vec3f32)] - { - Vec3Mask::new( - self.0.eq(&other.0), - self.1.eq(&other.1), - self.2.eq(&other.2), - ) - } - } - - /// Performs a vertical `!=` comparison between `self` and `other`, - /// returning a `Vec3Mask` of the results. - /// - /// In other words, this computes `[x1 != x2, y1 != y2, z1 != z2, w1 != w2]`. - #[inline] - pub fn cmpne(self, other: Self) -> Vec3Mask { - #[cfg(vec3sse2)] - unsafe { - Vec3Mask(_mm_cmpneq_ps(self.0, other.0)) - } - - #[cfg(vec3f32)] - { - Vec3Mask::new( - self.0.ne(&other.0), - self.1.ne(&other.1), - self.2.ne(&other.2), - ) - } - } - - /// Performs a vertical `>=` comparison between `self` and `other`, - /// returning a `Vec3Mask` of the results. - /// - /// In other words, this computes `[x1 >= x2, y1 >= y2, z1 >= z2, w1 >= w2]`. - #[inline] - pub fn cmpge(self, other: Self) -> Vec3Mask { - #[cfg(vec3sse2)] - unsafe { - Vec3Mask(_mm_cmpge_ps(self.0, other.0)) - } - - #[cfg(vec3f32)] - { - Vec3Mask::new( - self.0.ge(&other.0), - self.1.ge(&other.1), - self.2.ge(&other.2), - ) - } - } - - /// Performs a vertical `>` comparison between `self` and `other`, - /// returning a `Vec3Mask` of the results. - /// - /// In other words, this computes `[x1 > x2, y1 > y2, z1 > z2, w1 > w2]`. - #[inline] - pub fn cmpgt(self, other: Self) -> Vec3Mask { - #[cfg(vec3sse2)] - unsafe { - Vec3Mask(_mm_cmpgt_ps(self.0, other.0)) - } - - #[cfg(vec3f32)] - { - Vec3Mask::new( - self.0.gt(&other.0), - self.1.gt(&other.1), - self.2.gt(&other.2), - ) - } - } - - /// Performs a vertical `<=` comparison between `self` and `other`, - /// returning a `Vec3Mask` of the results. - /// - /// In other words, this computes `[x1 <= x2, y1 <= y2, z1 <= z2, w1 <= w2]`. - #[inline] - pub fn cmple(self, other: Self) -> Vec3Mask { - #[cfg(vec3sse2)] - unsafe { - Vec3Mask(_mm_cmple_ps(self.0, other.0)) - } - - #[cfg(vec3f32)] - { - Vec3Mask::new( - self.0.le(&other.0), - self.1.le(&other.1), - self.2.le(&other.2), - ) - } - } - - /// Performs a vertical `<` comparison between `self` and `other`, - /// returning a `Vec3Mask` of the results. - /// - /// In other words, this computes `[x1 < x2, y1 < y2, z1 < z2, w1 < w2]`. - #[inline] - pub fn cmplt(self, other: Self) -> Vec3Mask { - #[cfg(vec3sse2)] - unsafe { - Vec3Mask(_mm_cmplt_ps(self.0, other.0)) - } - - #[cfg(vec3f32)] - { - Vec3Mask::new( - self.0.lt(&other.0), - self.1.lt(&other.1), - self.2.lt(&other.2), - ) - } - } - - /// Creates a new `Vec3` from the first four values in `slice`. - /// - /// # Panics - /// - /// Panics if `slice` is less than three elements long. - #[inline] - pub fn from_slice_unaligned(slice: &[f32]) -> Self { - Self::new(slice[0], slice[1], slice[2]) - } - - /// Writes the elements of `self` to the first three elements in `slice`. - /// - /// # Panics - /// - /// Panics if `slice` is less than three elements long. - #[inline] - pub fn write_to_slice_unaligned(self, slice: &mut [f32]) { - let a = self.as_ref(); - slice[0] = a[0]; - slice[1] = a[1]; - slice[2] = a[2]; - } - - /// Per element multiplication/addition of the three inputs: b + (self * a) - #[inline] - pub(crate) fn mul_add(self, a: Self, b: Self) -> Self { - #[cfg(vec3sse2)] - unsafe { - Self(_mm_add_ps(_mm_mul_ps(self.0, a.0), b.0)) - } - - #[cfg(vec3f32)] - { - Self( - (self.0 * a.0) + b.0, - (self.1 * a.1) + b.1, - (self.2 * a.2) + b.2, - ) - } - } - - /// Returns a new `Vec3` containing the absolute value of each element of the original - /// `Vec3`. - #[inline] - pub fn abs(self) -> Self { - #[cfg(vec3sse2)] - unsafe { - Self(_mm_and_ps( - self.0, - _mm_castsi128_ps(_mm_set1_epi32(0x7f_ff_ff_ff)), - )) - } - - #[cfg(vec3f32)] - { - Self(self.0.abs(), self.1.abs(), self.2.abs()) - } - } - - #[inline] - pub fn round(self) -> Self { - #[cfg(vec3sse2)] - unsafe { - use crate::f32::funcs::sse2::m128_round; - Self(m128_round(self.0)) - } - - #[cfg(vec3f32)] - { - Self(self.0.round(), self.1.round(), self.2.round()) - } - } - - #[inline] - pub fn floor(self) -> Self { - #[cfg(vec3sse2)] - unsafe { - use crate::f32::funcs::sse2::m128_floor; - Self(m128_floor(self.0)) - } - - #[cfg(vec3f32)] - { - Self(self.0.floor(), self.1.floor(), self.2.floor()) - } - } - - #[inline] - pub fn ceil(self) -> Self { - #[cfg(vec3sse2)] - unsafe { - use crate::f32::funcs::sse2::m128_ceil; - Self(m128_ceil(self.0)) - } - - #[cfg(vec3f32)] - { - Self(self.0.ceil(), self.1.ceil(), self.2.ceil()) - } - } - - /// Returns a new `Vec4` 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` - #[inline] - pub fn sign(self) -> Self { - let mask = self.cmpge(Self::zero()); - mask.select(Self::splat(1.0), Self::splat(-1.0)) - } - - /// Computes the reciprocal `1.0/n` of each element, returning the - /// results in a new `Vec3`. - #[inline] - pub fn reciprocal(self) -> Self { - // TODO: Optimize - Self::one() / self - } - - /// 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`. - #[inline] - pub fn lerp(self, other: Self, s: f32) -> Self { - self + ((other - self) * s) - } - - /// Returns whether `self` of length `1.0` or not. - /// - /// Uses a precision threshold of `1e-6`. - #[inline] - pub fn is_normalized(self) -> bool { - is_normalized!(self) - } - - /// 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 `Vec3`'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 { - abs_diff_eq!(self, other, max_abs_diff) - } - - /// Returns the angle between two vectors, in radians. - /// - /// The vectors do not need to be unit length, but this function does - /// perform a `sqrt`. - #[inline] - pub fn angle_between(self, other: Self) -> f32 { - crate::f32::funcs::scalar_acos(self.dot(other) / (self.dot(self) * other.dot(other)).sqrt()) - } -} - -impl AsRef<[f32; 3]> for Vec3 { - #[inline] - fn as_ref(&self) -> &[f32; 3] { - unsafe { &*(self as *const Vec3 as *const [f32; 3]) } - } -} - -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 fmt::Display for Vec3 { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - #[cfg(vec3sse2)] - { - let (x, y, z) = (*self).into(); - write!(f, "[{}, {}, {}]", x, y, z) - } - - #[cfg(vec3f32)] - { - write!(f, "[{}, {}, {}]", self.0, self.1, self.2) - } - } -} - -impl Div for Vec3 { - type Output = Self; - #[inline] - fn div(self, other: Self) -> Self { - #[cfg(vec3sse2)] - unsafe { - Self(_mm_div_ps(self.0, other.0)) - } - - #[cfg(vec3f32)] - { - Self(self.0 / other.0, self.1 / other.1, self.2 / other.2) - } - } -} - -impl DivAssign for Vec3 { - #[inline] - fn div_assign(&mut self, other: Self) { - #[cfg(vec3sse2)] - { - self.0 = unsafe { _mm_div_ps(self.0, other.0) }; - } - - #[cfg(vec3f32)] - { - self.0 /= other.0; - self.1 /= other.1; - self.2 /= other.2; - } - } -} - -impl Div for Vec3 { - type Output = Self; - #[inline] - fn div(self, other: f32) -> Self { - #[cfg(vec3sse2)] - unsafe { - Self(_mm_div_ps(self.0, _mm_set1_ps(other))) - } - - #[cfg(vec3f32)] - { - Self(self.0 / other, self.1 / other, self.2 / other) - } - } -} - -impl DivAssign for Vec3 { - #[inline] - fn div_assign(&mut self, other: f32) { - #[cfg(vec3sse2)] - { - self.0 = unsafe { _mm_div_ps(self.0, _mm_set1_ps(other)) }; - } - - #[cfg(vec3f32)] - { - self.0 /= other; - self.1 /= other; - self.2 /= other; - } - } -} - -impl Mul for Vec3 { - type Output = Self; - #[inline] - fn mul(self, other: Self) -> Self { - #[cfg(vec3sse2)] - unsafe { - Self(_mm_mul_ps(self.0, other.0)) - } - - #[cfg(vec3f32)] - { - Self(self.0 * other.0, self.1 * other.1, self.2 * other.2) - } - } -} - -impl MulAssign for Vec3 { - #[inline] - fn mul_assign(&mut self, other: Self) { - #[cfg(vec3sse2)] - { - self.0 = unsafe { _mm_mul_ps(self.0, other.0) }; - } - - #[cfg(vec3f32)] - { - self.0 *= other.0; - self.1 *= other.1; - self.2 *= other.2; - } - } -} - -impl Mul for Vec3 { - type Output = Self; - #[inline] - fn mul(self, other: f32) -> Self { - #[cfg(vec3sse2)] - unsafe { - Self(_mm_mul_ps(self.0, _mm_set1_ps(other))) - } - - #[cfg(vec3f32)] - { - Self(self.0 * other, self.1 * other, self.2 * other) - } - } -} - -impl MulAssign for Vec3 { - #[inline] - fn mul_assign(&mut self, other: f32) { - #[cfg(vec3sse2)] - { - self.0 = unsafe { _mm_mul_ps(self.0, _mm_set1_ps(other)) }; - } - - #[cfg(vec3f32)] - { - self.0 *= other; - self.1 *= other; - self.2 *= other; - } - } -} - -impl Mul for f32 { - type Output = Vec3; - #[inline] - fn mul(self, other: Vec3) -> Vec3 { - #[cfg(vec3sse2)] - unsafe { - Vec3(_mm_mul_ps(_mm_set1_ps(self), other.0)) - } - - #[cfg(vec3f32)] - { - Vec3(self * other.0, self * other.1, self * other.2) - } - } -} - -impl Add for Vec3 { - type Output = Self; - #[inline] - fn add(self, other: Self) -> Self { - #[cfg(vec3sse2)] - unsafe { - Self(_mm_add_ps(self.0, other.0)) - } - - #[cfg(vec3f32)] - { - Self(self.0 + other.0, self.1 + other.1, self.2 + other.2) - } - } -} - -impl AddAssign for Vec3 { - #[inline] - fn add_assign(&mut self, other: Self) { - #[cfg(vec3sse2)] - { - self.0 = unsafe { _mm_add_ps(self.0, other.0) }; - } - - #[cfg(vec3f32)] - { - self.0 += other.0; - self.1 += other.1; - self.2 += other.2; - } - } -} - -impl Sub for Vec3 { - type Output = Self; - #[inline] - fn sub(self, other: Self) -> Self { - #[cfg(vec3sse2)] - unsafe { - Self(_mm_sub_ps(self.0, other.0)) - } - - #[cfg(vec3f32)] - { - Self(self.0 - other.0, self.1 - other.1, self.2 - other.2) - } - } -} - -impl SubAssign for Vec3 { - #[inline] - fn sub_assign(&mut self, other: Self) { - #[cfg(vec3sse2)] - { - self.0 = unsafe { _mm_sub_ps(self.0, other.0) }; - } - - #[cfg(vec3f32)] - { - self.0 -= other.0; - self.1 -= other.1; - self.2 -= other.2; - } - } -} - -impl Neg for Vec3 { - type Output = Self; - #[inline] - fn neg(self) -> Self { - #[cfg(vec3sse2)] - unsafe { - Self(_mm_sub_ps(_mm_set1_ps(0.0), self.0)) - } - - #[cfg(vec3f32)] - { - Self(-self.0, -self.1, -self.2) - } - } -} - -impl Index for Vec3 { - type Output = f32; - #[inline] - fn index(&self, index: usize) -> &Self::Output { - &self.as_ref()[index] - } -} - -impl IndexMut for Vec3 { - #[inline] - fn index_mut(&mut self, index: usize) -> &mut Self::Output { - &mut self.as_mut()[index] - } -} - -impl From<(f32, f32, f32)> for Vec3 { - #[inline] - fn from(t: (f32, f32, f32)) -> Self { - Self::new(t.0, t.1, t.2) - } -} - -impl From for (f32, f32, f32) { - #[inline] - fn from(v: Vec3) -> Self { - #[cfg(vec3sse2)] - { - let mut out: MaybeUninit> = MaybeUninit::uninit(); - unsafe { - // out is 16 bytes in size due to alignment - _mm_store_ps(out.as_mut_ptr() as *mut f32, v.0); - out.assume_init().0 - } - } - - #[cfg(vec3f32)] - { - (v.0, v.1, v.2) - } - } -} - -impl From<[f32; 3]> for Vec3 { - #[inline] - fn from(a: [f32; 3]) -> Self { - Self::new(a[0], a[1], a[2]) - } -} - -impl From for [f32; 3] { - #[inline] - fn from(v: Vec3) -> Self { - #[cfg(vec3sse2)] - { - let mut out: MaybeUninit> = MaybeUninit::uninit(); - unsafe { - // out is 16 bytes in size due to alignment - _mm_store_ps(out.as_mut_ptr() as *mut f32, v.0); - out.assume_init().0 - } - } - - #[cfg(vec3f32)] - { - [v.0, v.1, v.2] - } - } -} - -#[test] -fn test_vec3_private() { - assert_eq!( - vec3(1.0, 1.0, 1.0).mul_add(vec3(0.5, 2.0, -4.0), vec3(-1.0, -1.0, -1.0)), - vec3(-0.5, 1.0, -5.0) - ); - assert_eq!(vec3(1.0, 2.0, 3.0).dup_x(), vec3(1.0, 1.0, 1.0)); - assert_eq!(vec3(1.0, 2.0, 3.0).dup_y(), vec3(2.0, 2.0, 2.0)); - assert_eq!(vec3(1.0, 2.0, 3.0).dup_z(), vec3(3.0, 3.0, 3.0)); -} diff --git a/crates/bevy_glam/src/f32/vec3_mask.rs b/crates/bevy_glam/src/f32/vec3_mask.rs deleted file mode 100644 index ec5db445ba..0000000000 --- a/crates/bevy_glam/src/f32/vec3_mask.rs +++ /dev/null @@ -1,298 +0,0 @@ -use super::Vec3; -use core::{fmt, ops::*}; - -#[cfg(all(vec3sse2, target_arch = "x86"))] -use core::arch::x86::*; -#[cfg(all(vec3sse2, target_arch = "x86_64"))] -use core::arch::x86_64::*; -#[cfg(vec3sse2)] -use core::{cmp::Ordering, hash}; - -/// A 3-dimensional vector mask. -/// -/// This type is typically created by comparison methods on `Vec3`. It is -/// essentially a vector of three boolean values. -#[cfg(vec3sse2)] -#[derive(Clone, Copy)] -#[repr(C)] -pub struct Vec3Mask(pub(crate) __m128); - -/// A 3-dimensional vector mask. -#[cfg(vec3f32)] -#[derive(Clone, Copy, Default, PartialEq, Eq, Ord, PartialOrd, Hash)] -// if compiling with simd enabled assume alignment needs to match the simd type -#[cfg_attr(vec3f32_align16, repr(align(16)))] -#[repr(C)] -pub struct Vec3Mask(pub(crate) u32, pub(crate) u32, pub(crate) u32); - -#[cfg(vec3sse2)] -impl Default for Vec3Mask { - #[inline] - fn default() -> Self { - unsafe { Self(_mm_setzero_ps()) } - } -} - -#[cfg(vec3sse2)] -impl PartialEq for Vec3Mask { - #[inline] - fn eq(&self, other: &Self) -> bool { - self.as_ref().eq(other.as_ref()) - } -} - -#[cfg(vec3sse2)] -impl Eq for Vec3Mask {} - -#[cfg(vec3sse2)] -impl Ord for Vec3Mask { - #[inline] - fn cmp(&self, other: &Self) -> Ordering { - self.as_ref().cmp(other.as_ref()) - } -} - -#[cfg(vec3sse2)] -impl PartialOrd for Vec3Mask { - #[inline] - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -#[cfg(vec3sse2)] -impl hash::Hash for Vec3Mask { - #[inline] - fn hash(&self, state: &mut H) { - self.as_ref().hash(state); - } -} - -impl Vec3Mask { - /// Creates a new `Vec3Mask`. - #[inline] - pub 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. - - const MASK: [u32; 2] = [0, 0xff_ff_ff_ff]; - #[cfg(vec3sse2)] - unsafe { - Self(_mm_set_ps( - f32::from_bits(MASK[z as usize]), - f32::from_bits(MASK[z as usize]), - f32::from_bits(MASK[y as usize]), - f32::from_bits(MASK[x as usize]), - )) - } - - #[cfg(vec3f32)] - { - Self(MASK[x as usize], MASK[y as usize], MASK[z as usize]) - } - } - - /// Returns a bitmask with the lowest three bits set from the elements of - /// the `Vec3Mask`. - /// - /// 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 { - // _mm_movemask_ps only checks the most significant bit of the u32 is - // true, so we replicate that here with the non-SSE2 version. - - #[cfg(vec3sse2)] - unsafe { - (_mm_movemask_ps(self.0) as u32) & 0x7 - } - - #[cfg(vec3f32)] - { - (self.0 & 0x1) | (self.1 & 0x1) << 1 | (self.2 & 0x1) << 2 - } - } - - /// Returns true if any of the elements are true, false otherwise. - /// - /// In other words: `x || y || z`. - #[inline] - pub fn any(&self) -> bool { - #[cfg(vec3sse2)] - unsafe { - (_mm_movemask_ps(self.0) & 0x7) != 0 - } - - #[cfg(vec3f32)] - { - ((self.0 | self.1 | self.2) & 0x1) != 0 - } - } - - /// Returns true if all the elements are true, false otherwise. - /// - /// In other words: `x && y && z`. - #[inline] - pub fn all(&self) -> bool { - #[cfg(vec3sse2)] - unsafe { - (_mm_movemask_ps(self.0) & 0x7) == 0x7 - } - - #[cfg(vec3f32)] - { - ((self.0 & self.1 & self.2) & 0x1) != 0 - } - } - - /// Creates a new `Vec3` from the elements in `if_true` and `if_false`, - /// selecting which to use for each element based on the `Vec3Mask`. - /// - /// 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(self, if_true: Vec3, if_false: Vec3) -> Vec3 { - // We are assuming that the mask values are either 0 or 0xff_ff_ff_ff for the SSE2 and f32 - // to behave the same here. - - #[cfg(vec3sse2)] - unsafe { - Vec3(_mm_or_ps( - _mm_andnot_ps(self.0, if_false.0), - _mm_and_ps(if_true.0, self.0), - )) - } - - #[cfg(vec3f32)] - { - Vec3( - if self.0 != 0 { if_true.0 } else { if_false.0 }, - if self.1 != 0 { if_true.1 } else { if_false.1 }, - if self.2 != 0 { if_true.2 } else { if_false.2 }, - ) - } - } -} - -impl BitAnd for Vec3Mask { - type Output = Self; - #[inline] - fn bitand(self, other: Self) -> Self { - #[cfg(vec3sse2)] - unsafe { - Self(_mm_and_ps(self.0, other.0)) - } - - #[cfg(vec3f32)] - { - Self(self.0 & other.0, self.1 & other.1, self.2 & other.2) - } - } -} - -impl BitAndAssign for Vec3Mask { - #[inline] - fn bitand_assign(&mut self, other: Self) { - #[cfg(vec3sse2)] - { - self.0 = unsafe { _mm_and_ps(self.0, other.0) }; - } - - #[cfg(vec3f32)] - { - self.0 &= other.0; - self.1 &= other.1; - self.2 &= other.2; - } - } -} - -impl BitOr for Vec3Mask { - type Output = Self; - #[inline] - fn bitor(self, other: Self) -> Self { - #[cfg(vec3sse2)] - unsafe { - Self(_mm_or_ps(self.0, other.0)) - } - - #[cfg(vec3f32)] - { - Self(self.0 | other.0, self.1 | other.1, self.2 | other.2) - } - } -} - -impl BitOrAssign for Vec3Mask { - #[inline] - fn bitor_assign(&mut self, other: Self) { - #[cfg(vec3sse2)] - { - self.0 = unsafe { _mm_or_ps(self.0, other.0) }; - } - - #[cfg(vec3f32)] - { - self.0 |= other.0; - self.1 |= other.1; - self.2 |= other.2; - } - } -} - -impl Not for Vec3Mask { - type Output = Self; - #[inline] - fn not(self) -> Self { - #[cfg(vec3sse2)] - unsafe { - Self(_mm_andnot_ps( - self.0, - _mm_set_ps1(f32::from_bits(0xff_ff_ff_ff)), - )) - } - - #[cfg(vec3f32)] - { - Self(!self.0, !self.1, !self.2) - } - } -} - -impl fmt::Debug for Vec3Mask { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - #[cfg(vec3sse2)] - { - let arr = self.as_ref(); - write!(f, "Vec3Mask({:#x}, {:#x}, {:#x})", arr[0], arr[1], arr[2]) - } - - #[cfg(vec3f32)] - { - write!(f, "Vec3Mask({:#x}, {:#x}, {:#x})", self.0, self.1, self.2) - } - } -} - -impl fmt::Display for Vec3Mask { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let arr = self.as_ref(); - write!(f, "[{}, {}, {}]", arr[0] != 0, arr[1] != 0, arr[2] != 0,) - } -} - -impl From for [u32; 3] { - #[inline] - fn from(mask: Vec3Mask) -> Self { - *mask.as_ref() - } -} - -impl AsRef<[u32; 3]> for Vec3Mask { - #[inline] - fn as_ref(&self) -> &[u32; 3] { - unsafe { &*(self as *const Self as *const [u32; 3]) } - } -} diff --git a/crates/bevy_glam/src/f32/vec4.rs b/crates/bevy_glam/src/f32/vec4.rs deleted file mode 100644 index 7c5847ffd4..0000000000 --- a/crates/bevy_glam/src/f32/vec4.rs +++ /dev/null @@ -1,1347 +0,0 @@ -use super::{Vec3, Vec4Mask}; -use core::{fmt, ops::*}; - -#[cfg(all(vec4sse2, target_arch = "x86"))] -use core::arch::x86::*; -#[cfg(all(vec4sse2, target_arch = "x86_64"))] -use core::arch::x86_64::*; - -#[cfg(vec4sse2)] -use crate::Align16; -#[cfg(vec4sse2)] -use core::{cmp::Ordering, f32, mem::MaybeUninit}; - -#[cfg(vec4sse2)] -pub(crate) const X_AXIS: Align16<[f32; 4]> = Align16([1.0, 0.0, 0.0, 0.0]); -#[cfg(vec4sse2)] -pub(crate) const Y_AXIS: Align16<[f32; 4]> = Align16([0.0, 1.0, 0.0, 0.0]); -#[cfg(vec4sse2)] -pub(crate) const Z_AXIS: Align16<[f32; 4]> = Align16([0.0, 0.0, 1.0, 0.0]); -#[cfg(vec4sse2)] -pub(crate) const W_AXIS: Align16<[f32; 4]> = Align16([0.0, 0.0, 0.0, 1.0]); - -/// A 4-dimensional vector. -/// -/// This type is 16 byte aligned. -#[cfg(vec4sse2)] -#[derive(Clone, Copy, Debug)] -#[repr(C)] -pub struct Vec4(pub(crate) __m128); - -/// A 4-dimensional vector. -/// -/// This type is 16 byte aligned unless the `scalar-math` feature is enabed. -#[cfg(vec4f32)] -#[derive(Clone, Copy, PartialEq, PartialOrd, Debug, Default)] -// if compiling with simd enabled assume alignment needs to match the simd type -#[cfg_attr(vec4f32_align16, repr(align(16)))] -#[repr(C)] -pub struct Vec4( - pub(crate) f32, - pub(crate) f32, - pub(crate) f32, - pub(crate) f32, -); - -#[cfg(vec4sse2)] -impl Default for Vec4 { - #[inline] - fn default() -> Self { - Self::zero() - } -} - -#[cfg(vec4sse2)] -impl PartialEq for Vec4 { - #[inline] - fn eq(&self, other: &Self) -> bool { - self.cmpeq(*other).all() - } -} - -#[cfg(vec4sse2)] -impl PartialOrd for Vec4 { - #[inline] - fn partial_cmp(&self, other: &Self) -> Option { - self.as_ref().partial_cmp(other.as_ref()) - } -} - -#[cfg(vec4sse2)] -impl From for __m128 { - // TODO: write test - #[cfg_attr(tarpaulin, skip)] - #[inline] - fn from(t: Vec4) -> Self { - t.0 - } -} - -#[cfg(vec4sse2)] -impl From<__m128> for Vec4 { - #[inline] - fn from(t: __m128) -> Self { - Self(t) - } -} - -#[inline] -pub fn vec4(x: f32, y: f32, z: f32, w: f32) -> Vec4 { - Vec4::new(x, y, z, w) -} - -impl Vec4 { - /// Creates a new `Vec4`. - #[inline] - pub fn new(x: f32, y: f32, z: f32, w: f32) -> Self { - #[cfg(vec4sse2)] - unsafe { - Self(_mm_set_ps(w, z, y, x)) - } - #[cfg(vec4f32)] - { - Self(x, y, z, w) - } - } - - /// Creates a new `Vec4` with all elements set to `0.0`. - #[inline] - pub fn zero() -> Self { - #[cfg(vec4sse2)] - unsafe { - Self(_mm_setzero_ps()) - } - - #[cfg(vec4f32)] - { - Self(0.0, 0.0, 0.0, 0.0) - } - } - - /// Creates a new `Vec4` with all elements set to `1.0`. - #[inline] - pub fn one() -> Self { - #[cfg(vec4sse2)] - unsafe { - Self(_mm_set1_ps(1.0)) - } - - #[cfg(vec4f32)] - { - Self(1.0, 1.0, 1.0, 1.0) - } - } - - /// Creates a new `Vec4` with values `[x: 1.0, y: 0.0, z: 0.0, w: 0.0]`. - #[inline] - pub fn unit_x() -> Self { - #[cfg(vec4sse2)] - unsafe { - Self(_mm_load_ps(X_AXIS.0.as_ptr())) - } - - #[cfg(vec4f32)] - { - Self(1.0, 0.0, 0.0, 0.0) - } - } - - /// Creates a new `Vec4` with values `[x: 0.0, y: 1.0, z: 0.0, w: 0.0]`. - #[inline] - pub fn unit_y() -> Self { - #[cfg(vec4sse2)] - unsafe { - Self(_mm_load_ps(Y_AXIS.0.as_ptr())) - } - - #[cfg(vec4f32)] - { - Self(0.0, 1.0, 0.0, 0.0) - } - } - - /// Creates a new `Vec4` with values `[x: 0.0, y: 0.0, z: 1.0, w: 0.0]`. - #[inline] - pub fn unit_z() -> Self { - #[cfg(vec4sse2)] - unsafe { - Self(_mm_load_ps(Z_AXIS.0.as_ptr())) - } - - #[cfg(vec4f32)] - { - Self(0.0, 0.0, 1.0, 0.0) - } - } - - /// Creates a new `Vec4` with values `[x: 0.0, y: 0.0, z: 0.0, w: 1.0]`. - #[inline] - pub fn unit_w() -> Self { - #[cfg(vec4sse2)] - unsafe { - Self(_mm_load_ps(W_AXIS.0.as_ptr())) - } - - #[cfg(vec4f32)] - { - Self(0.0, 0.0, 0.0, 1.0) - } - } - - /// Creates a new `Vec4` with all elements set to `v`. - #[inline] - pub fn splat(v: f32) -> Self { - #[cfg(vec4sse2)] - unsafe { - Self(_mm_set_ps1(v)) - } - - #[cfg(vec4f32)] - { - Self(v, v, v, v) - } - } - - /// Creates a `Vec3` from the first three elements of `self`, - /// removing `w`. - #[inline] - pub fn truncate(self) -> Vec3 { - #[cfg(all(vec4sse2, vec3sse2))] - { - self.0.into() - } - - #[cfg(all(vec4sse2, not(vec3sse2)))] - { - let (x, y, z, _) = self.into(); - Vec3::new(x, y, z) - } - - #[cfg(vec4f32)] - { - Vec3::new(self.0, self.1, self.2) - } - } - - /// Returns element `x`. - #[inline] - pub fn x(self) -> f32 { - #[cfg(vec4sse2)] - unsafe { - _mm_cvtss_f32(self.0) - } - - #[cfg(vec4f32)] - { - self.0 - } - } - - /// Returns element `y`. - #[inline] - pub fn y(self) -> f32 { - #[cfg(vec4sse2)] - unsafe { - _mm_cvtss_f32(_mm_shuffle_ps(self.0, self.0, 0b01_01_01_01)) - } - - #[cfg(vec4f32)] - { - self.1 - } - } - - /// Returns element `z`. - #[inline] - pub fn z(self) -> f32 { - #[cfg(vec4sse2)] - unsafe { - _mm_cvtss_f32(_mm_shuffle_ps(self.0, self.0, 0b10_10_10_10)) - } - - #[cfg(vec4f32)] - { - self.2 - } - } - - /// Returns element `w`. - #[inline] - pub fn w(self) -> f32 { - #[cfg(vec4sse2)] - unsafe { - _mm_cvtss_f32(_mm_shuffle_ps(self.0, self.0, 0b11_11_11_11)) - } - - #[cfg(vec4f32)] - { - self.3 - } - } - - /// Returns a mutable reference to element `x`. - #[inline] - pub fn x_mut(&mut self) -> &mut f32 { - #[cfg(vec4sse2)] - unsafe { - &mut *(self as *mut Self as *mut f32) - } - - #[cfg(vec4f32)] - { - &mut self.0 - } - } - - /// Returns a mutable reference to element `y`. - #[inline] - pub fn y_mut(&mut self) -> &mut f32 { - #[cfg(vec4sse2)] - unsafe { - &mut *(self as *mut Self as *mut f32).offset(1) - } - - #[cfg(vec4f32)] - { - &mut self.1 - } - } - - /// Returns a mutable reference to element `z`. - #[inline] - pub fn z_mut(&mut self) -> &mut f32 { - #[cfg(vec4sse2)] - unsafe { - &mut *(self as *mut Self as *mut f32).offset(2) - } - - #[cfg(vec4f32)] - { - &mut self.2 - } - } - - /// Returns a mutable reference to element `w`. - #[inline] - pub fn w_mut(&mut self) -> &mut f32 { - #[cfg(vec4sse2)] - unsafe { - &mut *(self as *mut Self as *mut f32).offset(3) - } - - #[cfg(vec4f32)] - { - &mut self.3 - } - } - - /// Sets element `x`. - #[inline] - pub fn set_x(&mut self, x: f32) { - #[cfg(vec4sse2)] - unsafe { - self.0 = _mm_move_ss(self.0, _mm_set_ss(x)); - } - - #[cfg(vec4f32)] - { - self.0 = x; - } - } - - /// Sets element `y`. - #[inline] - pub fn set_y(&mut self, y: f32) { - #[cfg(vec4sse2)] - unsafe { - let mut t = _mm_move_ss(self.0, _mm_set_ss(y)); - t = _mm_shuffle_ps(t, t, 0b11_10_00_00); - self.0 = _mm_move_ss(t, self.0); - } - - #[cfg(vec4f32)] - { - self.1 = y; - } - } - - /// Sets element `z`. - #[inline] - pub fn set_z(&mut self, z: f32) { - #[cfg(vec4sse2)] - unsafe { - let mut t = _mm_move_ss(self.0, _mm_set_ss(z)); - t = _mm_shuffle_ps(t, t, 0b11_00_01_00); - self.0 = _mm_move_ss(t, self.0); - } - - #[cfg(vec4f32)] - { - self.2 = z; - } - } - - /// Sets element `w`. - #[inline] - pub fn set_w(&mut self, w: f32) { - #[cfg(vec4sse2)] - unsafe { - let mut t = _mm_move_ss(self.0, _mm_set_ss(w)); - t = _mm_shuffle_ps(t, t, 0b00_10_01_00); - self.0 = _mm_move_ss(t, self.0); - } - - #[cfg(vec4f32)] - { - self.3 = w; - } - } - - /// Returns a `Vec4` with all elements set to the value of element `x`. - #[inline] - pub(crate) fn dup_x(self) -> Self { - #[cfg(vec4sse2)] - unsafe { - Self(_mm_shuffle_ps(self.0, self.0, 0b00_00_00_00)) - } - - #[cfg(vec4f32)] - { - Self(self.0, self.0, self.0, self.0) - } - } - - /// Returns a `Vec4` with all elements set to the value of element `y`. - #[inline] - pub(crate) fn dup_y(self) -> Self { - #[cfg(vec4sse2)] - unsafe { - Self(_mm_shuffle_ps(self.0, self.0, 0b01_01_01_01)) - } - - #[cfg(vec4f32)] - { - Self(self.1, self.1, self.1, self.1) - } - } - - /// Returns a `Vec4` with all elements set to the value of element `z`. - #[inline] - pub(crate) fn dup_z(self) -> Self { - #[cfg(vec4sse2)] - unsafe { - Self(_mm_shuffle_ps(self.0, self.0, 0b10_10_10_10)) - } - - #[cfg(vec4f32)] - { - Self(self.2, self.2, self.2, self.2) - } - } - - /// Returns a `Vec4` with all elements set to the value of element `w`. - #[inline] - pub(crate) fn dup_w(self) -> Self { - #[cfg(vec4sse2)] - unsafe { - Self(_mm_shuffle_ps(self.0, self.0, 0b11_11_11_11)) - } - - #[cfg(vec4f32)] - { - Self(self.3, self.3, self.3, self.3) - } - } - - /// Calculates the Vec4 dot product and returns answer in x lane of __m128. - #[cfg(vec4sse2)] - #[inline] - unsafe fn dot_as_m128(self, other: Self) -> __m128 { - let x2_y2_z2_w2 = _mm_mul_ps(self.0, other.0); - 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) - } - - /// Returns Vec4 dot in all lanes of Vec4 - #[cfg(vec4sse2)] - #[inline] - pub(crate) fn dot_as_vec4(self, other: Self) -> Self { - unsafe { - let dot_in_x = self.dot_as_m128(other); - Self(_mm_shuffle_ps(dot_in_x, dot_in_x, 0b00_00_00_00)) - } - } - - /// Computes the 4D dot product of `self` and `other`. - #[inline] - pub fn dot(self, other: Self) -> f32 { - #[cfg(vec4sse2)] - unsafe { - _mm_cvtss_f32(self.dot_as_m128(other)) - } - - #[cfg(vec4f32)] - { - (self.0 * other.0) + (self.1 * other.1) + (self.2 * other.2) + (self.3 * other.3) - } - } - - /// Computes the 4D length of `self`. - #[inline] - pub fn length(self) -> f32 { - #[cfg(vec4sse2)] - { - let dot = self.dot_as_vec4(self); - unsafe { _mm_cvtss_f32(_mm_sqrt_ps(dot.0)) } - } - - #[cfg(vec4f32)] - { - self.dot(self).sqrt() - } - } - - /// Computes the squared 4D length of `self`. - /// - /// This is generally faster than `Vec4::length()` as it avoids a square - /// root operation. - #[inline] - pub fn length_squared(self) -> f32 { - self.dot(self) - } - - /// Computes `1.0 / Vec4::length()`. - /// - /// For valid results, `self` must _not_ be of length zero. - #[inline] - pub fn length_reciprocal(self) -> f32 { - #[cfg(vec4sse2)] - { - let dot = self.dot_as_vec4(self); - unsafe { - // _mm_rsqrt_ps is lower precision - _mm_cvtss_f32(_mm_div_ps(_mm_set_ps1(1.0), _mm_sqrt_ps(dot.0))) - } - } - - #[cfg(vec4f32)] - { - 1.0 / self.length() - } - } - - /// Returns `self` normalized to length 1.0. - /// - /// For valid results, `self` must _not_ be of length zero. - #[inline] - pub fn normalize(self) -> Self { - #[cfg(vec4sse2)] - { - let dot = self.dot_as_vec4(self); - unsafe { Self(_mm_div_ps(self.0, _mm_sqrt_ps(dot.0))) } - } - - #[cfg(vec4f32)] - { - self * self.length_reciprocal() - } - } - - /// Returns the vertical minimum of `self` and `other`. - /// - /// In other words, this computes - /// `[x: min(x1, x2), y: min(y1, y2), z: min(z1, z2), w: min(w1, w2)]`, - /// taking the minimum of each element individually. - #[inline] - pub fn min(self, other: Self) -> Self { - #[cfg(vec4sse2)] - unsafe { - Self(_mm_min_ps(self.0, other.0)) - } - - #[cfg(vec4f32)] - { - Self( - self.0.min(other.0), - self.1.min(other.1), - self.2.min(other.2), - self.3.min(other.3), - ) - } - } - - /// Returns the vertical maximum of `self` and `other`. - /// - /// In other words, this computes - /// `[x: max(x1, x2), y: max(y1, y2), z: max(z1, z2), w: max(w1, w2)]`, - /// taking the maximum of each element individually. - #[inline] - pub fn max(self, other: Self) -> Self { - #[cfg(vec4sse2)] - unsafe { - Self(_mm_max_ps(self.0, other.0)) - } - - #[cfg(vec4f32)] - { - Self( - self.0.max(other.0), - self.1.max(other.1), - self.2.max(other.2), - self.3.max(other.3), - ) - } - } - - /// Returns the horizontal minimum of `self`'s elements. - /// - /// In other words, this computes `min(x, y, z, w)`. - #[inline] - pub fn min_element(self) -> f32 { - #[cfg(vec4sse2)] - 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) - } - - #[cfg(vec4f32)] - { - self.0.min(self.1.min(self.2.min(self.3))) - } - } - - /// Returns the horizontal maximum of `self`'s elements. - /// - /// In other words, this computes `max(x, y, z, w)`. - #[inline] - pub fn max_element(self) -> f32 { - #[cfg(vec4sse2)] - 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) - } - - #[cfg(vec4f32)] - { - self.0.max(self.1.max(self.2.min(self.3))) - } - } - - /// Performs a vertical `==` comparison between `self` and `other`, - /// returning a `Vec4Mask` of the results. - /// - /// In other words, this computes `[x1 == x2, y1 == y2, z1 == z2, w1 == w2]`. - #[inline] - pub fn cmpeq(self, other: Self) -> Vec4Mask { - #[cfg(vec4sse2)] - unsafe { - Vec4Mask(_mm_cmpeq_ps(self.0, other.0)) - } - - #[cfg(vec4f32)] - { - Vec4Mask::new( - self.0.eq(&other.0), - self.1.eq(&other.1), - self.2.eq(&other.2), - self.3.eq(&other.3), - ) - } - } - - /// Performs a vertical `!=` comparison between `self` and `other`, - /// returning a `Vec4Mask` of the results. - /// - /// In other words, this computes `[x1 != x2, y1 != y2, z1 != z2, w1 != w2]`. - #[inline] - pub fn cmpne(self, other: Self) -> Vec4Mask { - #[cfg(vec4sse2)] - unsafe { - Vec4Mask(_mm_cmpneq_ps(self.0, other.0)) - } - - #[cfg(vec4f32)] - { - Vec4Mask::new( - self.0.ne(&other.0), - self.1.ne(&other.1), - self.2.ne(&other.2), - self.3.ne(&other.3), - ) - } - } - - /// Performs a vertical `>=` comparison between `self` and `other`, - /// returning a `Vec4Mask` of the results. - /// - /// In other words, this computes `[x1 >= x2, y1 >= y2, z1 >= z2, w1 >= w2]`. - #[inline] - pub fn cmpge(self, other: Self) -> Vec4Mask { - #[cfg(vec4sse2)] - unsafe { - Vec4Mask(_mm_cmpge_ps(self.0, other.0)) - } - - #[cfg(vec4f32)] - { - Vec4Mask::new( - self.0.ge(&other.0), - self.1.ge(&other.1), - self.2.ge(&other.2), - self.3.ge(&other.3), - ) - } - } - - /// Performs a vertical `>` comparison between `self` and `other`, - /// returning a `Vec4Mask` of the results. - /// - /// In other words, this computes `[x1 > x2, y1 > y2, z1 > z2, w1 > w2]`. - #[inline] - pub fn cmpgt(self, other: Self) -> Vec4Mask { - #[cfg(vec4sse2)] - unsafe { - Vec4Mask(_mm_cmpgt_ps(self.0, other.0)) - } - - #[cfg(vec4f32)] - { - Vec4Mask::new( - self.0.gt(&other.0), - self.1.gt(&other.1), - self.2.gt(&other.2), - self.3.gt(&other.3), - ) - } - } - - /// Performs a vertical `<=` comparison between `self` and `other`, - /// returning a `Vec4Mask` of the results. - /// - /// In other words, this computes `[x1 <= x2, y1 <= y2, z1 <= z2, w1 <= w2]`. - #[inline] - pub fn cmple(self, other: Self) -> Vec4Mask { - #[cfg(vec4sse2)] - unsafe { - Vec4Mask(_mm_cmple_ps(self.0, other.0)) - } - - #[cfg(vec4f32)] - { - Vec4Mask::new( - self.0.le(&other.0), - self.1.le(&other.1), - self.2.le(&other.2), - self.3.le(&other.3), - ) - } - } - - /// Performs a vertical `<` comparison between `self` and `other`, - /// returning a `Vec4Mask` of the results. - /// - /// In other words, this computes `[x1 < x2, y1 < y2, z1 < z2, w1 < w2]`. - #[inline] - pub fn cmplt(self, other: Self) -> Vec4Mask { - #[cfg(vec4sse2)] - unsafe { - Vec4Mask(_mm_cmplt_ps(self.0, other.0)) - } - - #[cfg(vec4f32)] - { - Vec4Mask::new( - self.0.lt(&other.0), - self.1.lt(&other.1), - self.2.lt(&other.2), - self.3.lt(&other.3), - ) - } - } - - /// Creates a new `Vec4` from the first four values in `slice`. - /// - /// # Panics - /// - /// Panics if `slice` is less than four elements long. - #[inline] - pub fn from_slice_unaligned(slice: &[f32]) -> Self { - #[cfg(vec4sse2)] - { - assert!(slice.len() >= 4); - unsafe { Self(_mm_loadu_ps(slice.as_ptr())) } - } - - #[cfg(vec4f32)] - { - Self(slice[0], slice[1], slice[2], slice[3]) - } - } - - /// Writes the elements of `self` to the first four elements in `slice`. - /// - /// # Panics - /// - /// Panics if `slice` is less than four elements long. - #[inline] - pub fn write_to_slice_unaligned(self, slice: &mut [f32]) { - #[cfg(vec4sse2)] - unsafe { - assert!(slice.len() >= 4); - _mm_storeu_ps(slice.as_mut_ptr(), self.0); - } - - #[cfg(vec4f32)] - { - slice[0] = self.0; - slice[1] = self.1; - slice[2] = self.2; - slice[3] = self.3; - } - } - - /// Per element multiplication/addition of the three inputs: b + (self * a) - #[inline] - pub(crate) fn mul_add(self, a: Self, b: Self) -> Self { - #[cfg(vec4sse2)] - unsafe { - Self(_mm_add_ps(_mm_mul_ps(self.0, a.0), b.0)) - } - - #[cfg(vec4f32)] - { - Self( - (self.0 * a.0) + b.0, - (self.1 * a.1) + b.1, - (self.2 * a.2) + b.2, - (self.3 * a.3) + b.3, - ) - } - } - - /// Returns a new `Vec4` containing the absolute value of each element of the original - /// `Vec4`. - #[inline] - pub fn abs(self) -> Self { - #[cfg(vec4sse2)] - unsafe { - Self(_mm_and_ps( - self.0, - _mm_castsi128_ps(_mm_set1_epi32(0x7f_ff_ff_ff)), - )) - } - - #[cfg(vec4f32)] - { - Self(self.0.abs(), self.1.abs(), self.2.abs(), self.3.abs()) - } - } - - #[inline] - pub fn round(self) -> Self { - #[cfg(vec4sse2)] - unsafe { - use crate::f32::funcs::sse2::m128_round; - Self(m128_round(self.0)) - } - - #[cfg(vec4f32)] - { - Self( - self.0.round(), - self.1.round(), - self.2.round(), - self.3.round(), - ) - } - } - - #[inline] - pub fn floor(self) -> Self { - #[cfg(vec4sse2)] - unsafe { - use crate::f32::funcs::sse2::m128_floor; - Self(m128_floor(self.0)) - } - - #[cfg(vec4f32)] - { - Self( - self.0.floor(), - self.1.floor(), - self.2.floor(), - self.3.floor(), - ) - } - } - - #[inline] - pub fn ceil(self) -> Self { - #[cfg(vec4sse2)] - unsafe { - use crate::f32::funcs::sse2::m128_ceil; - Self(m128_ceil(self.0)) - } - - #[cfg(vec4f32)] - { - Self(self.0.ceil(), self.1.ceil(), self.2.ceil(), self.3.ceil()) - } - } - - /// Returns a new `Vec4` 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` - #[inline] - pub fn sign(self) -> Self { - #[cfg(vec4sse2)] - { - let mask = self.cmpge(Self::zero()); - mask.select(Self::splat(1.0), Self::splat(-1.0)) - } - - #[cfg(vec4f32)] - { - Self( - self.0.signum(), - self.1.signum(), - self.2.signum(), - self.3.signum(), - ) - } - } - - /// Computes the reciprocal `1.0/n` of each element, returning the - /// results in a new `Vec4`. - #[inline] - pub fn reciprocal(self) -> Self { - // TODO: Optimize - Self::one() / self - } - - /// 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`. - #[inline] - pub fn lerp(self, other: Self, s: f32) -> Self { - self + ((other - self) * s) - } - - /// Returns whether `self` is length `1.0` or not. - /// - /// Uses a precision threshold of `1e-6`. - #[inline] - pub fn is_normalized(self) -> bool { - is_normalized!(self) - } - - /// 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 `Vec4`'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 { - abs_diff_eq!(self, other, max_abs_diff) - } -} - -impl AsRef<[f32; 4]> for Vec4 { - #[inline] - fn as_ref(&self) -> &[f32; 4] { - unsafe { &*(self as *const Self as *const [f32; 4]) } - } -} - -impl AsMut<[f32; 4]> for Vec4 { - #[inline] - fn as_mut(&mut self) -> &mut [f32; 4] { - unsafe { &mut *(self as *mut Self as *mut [f32; 4]) } - } -} - -impl fmt::Display for Vec4 { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - #[cfg(vec4sse2)] - { - let (x, y, z, w) = (*self).into(); - write!(fmt, "[{}, {}, {}, {}]", x, y, z, w) - } - - #[cfg(vec4f32)] - { - write!(fmt, "[{}, {}, {}, {}]", self.0, self.1, self.2, self.3) - } - } -} - -impl Div for Vec4 { - type Output = Self; - #[inline] - fn div(self, other: Self) -> Self { - #[cfg(vec4sse2)] - unsafe { - Self(_mm_div_ps(self.0, other.0)) - } - - #[cfg(vec4f32)] - { - Self( - self.0 / other.0, - self.1 / other.1, - self.2 / other.2, - self.3 / other.3, - ) - } - } -} - -impl DivAssign for Vec4 { - #[inline] - fn div_assign(&mut self, other: Self) { - #[cfg(vec4sse2)] - { - self.0 = unsafe { _mm_div_ps(self.0, other.0) }; - } - - #[cfg(vec4f32)] - { - self.0 /= other.0; - self.1 /= other.1; - self.2 /= other.2; - self.3 /= other.3; - } - } -} - -impl Div for Vec4 { - type Output = Self; - #[inline] - fn div(self, other: f32) -> Self { - #[cfg(vec4sse2)] - unsafe { - Self(_mm_div_ps(self.0, _mm_set1_ps(other))) - } - - #[cfg(vec4f32)] - { - Self( - self.0 / other, - self.1 / other, - self.2 / other, - self.3 / other, - ) - } - } -} - -impl DivAssign for Vec4 { - #[inline] - fn div_assign(&mut self, other: f32) { - #[cfg(vec4sse2)] - { - self.0 = unsafe { _mm_div_ps(self.0, _mm_set1_ps(other)) }; - } - - #[cfg(vec4f32)] - { - self.0 /= other; - self.1 /= other; - self.2 /= other; - self.3 /= other; - } - } -} - -impl Mul for Vec4 { - type Output = Self; - #[inline] - fn mul(self, other: Self) -> Self { - #[cfg(vec4sse2)] - unsafe { - Self(_mm_mul_ps(self.0, other.0)) - } - - #[cfg(vec4f32)] - { - Self( - self.0 * other.0, - self.1 * other.1, - self.2 * other.2, - self.3 * other.3, - ) - } - } -} - -impl MulAssign for Vec4 { - #[inline] - fn mul_assign(&mut self, other: Self) { - #[cfg(vec4sse2)] - { - self.0 = unsafe { _mm_mul_ps(self.0, other.0) }; - } - - #[cfg(vec4f32)] - { - self.0 *= other.0; - self.1 *= other.1; - self.2 *= other.2; - self.3 *= other.3; - } - } -} - -impl Mul for Vec4 { - type Output = Self; - #[inline] - fn mul(self, other: f32) -> Self { - #[cfg(vec4sse2)] - unsafe { - Self(_mm_mul_ps(self.0, _mm_set1_ps(other))) - } - - #[cfg(vec4f32)] - { - Self( - self.0 * other, - self.1 * other, - self.2 * other, - self.3 * other, - ) - } - } -} - -impl MulAssign for Vec4 { - #[inline] - fn mul_assign(&mut self, other: f32) { - #[cfg(vec4sse2)] - { - self.0 = unsafe { _mm_mul_ps(self.0, _mm_set1_ps(other)) }; - } - - #[cfg(vec4f32)] - { - self.0 *= other; - self.1 *= other; - self.2 *= other; - self.3 *= other; - } - } -} - -impl Mul for f32 { - type Output = Vec4; - #[inline] - fn mul(self, other: Vec4) -> Vec4 { - #[cfg(vec4sse2)] - unsafe { - Vec4(_mm_mul_ps(_mm_set1_ps(self), other.0)) - } - - #[cfg(vec4f32)] - { - Vec4( - self * other.0, - self * other.1, - self * other.2, - self * other.3, - ) - } - } -} - -impl Add for Vec4 { - type Output = Self; - #[inline] - fn add(self, other: Self) -> Self { - #[cfg(vec4sse2)] - unsafe { - Self(_mm_add_ps(self.0, other.0)) - } - - #[cfg(vec4f32)] - { - Self( - self.0 + other.0, - self.1 + other.1, - self.2 + other.2, - self.3 + other.3, - ) - } - } -} - -impl AddAssign for Vec4 { - #[inline] - fn add_assign(&mut self, other: Self) { - #[cfg(vec4sse2)] - { - self.0 = unsafe { _mm_add_ps(self.0, other.0) }; - } - - #[cfg(vec4f32)] - { - self.0 += other.0; - self.1 += other.1; - self.2 += other.2; - self.3 += other.3; - } - } -} - -impl Sub for Vec4 { - type Output = Self; - #[inline] - fn sub(self, other: Self) -> Self { - #[cfg(vec4sse2)] - unsafe { - Self(_mm_sub_ps(self.0, other.0)) - } - - #[cfg(vec4f32)] - { - Self( - self.0 - other.0, - self.1 - other.1, - self.2 - other.2, - self.3 - other.3, - ) - } - } -} - -impl SubAssign for Vec4 { - #[inline] - fn sub_assign(&mut self, other: Self) { - #[cfg(vec4sse2)] - { - self.0 = unsafe { _mm_sub_ps(self.0, other.0) }; - } - - #[cfg(vec4f32)] - { - self.0 -= other.0; - self.1 -= other.1; - self.2 -= other.2; - self.3 -= other.3; - } - } -} - -impl Neg for Vec4 { - type Output = Self; - #[inline] - fn neg(self) -> Self { - #[cfg(vec4sse2)] - unsafe { - Self(_mm_sub_ps(_mm_set1_ps(0.0), self.0)) - } - - #[cfg(vec4f32)] - { - Self(-self.0, -self.1, -self.2, -self.3) - } - } -} - -impl Index for Vec4 { - type Output = f32; - #[inline] - fn index(&self, index: usize) -> &Self::Output { - &self.as_ref()[index] - } -} - -impl IndexMut for Vec4 { - #[inline] - fn index_mut(&mut self, index: usize) -> &mut Self::Output { - &mut self.as_mut()[index] - } -} - -impl From<(f32, f32, f32, f32)> for Vec4 { - #[inline] - fn from(t: (f32, f32, f32, f32)) -> Self { - Self::new(t.0, t.1, t.2, t.3) - } -} - -impl From for (f32, f32, f32, f32) { - #[inline] - fn from(v: Vec4) -> Self { - #[cfg(vec4sse2)] - { - let mut out: MaybeUninit> = MaybeUninit::uninit(); - unsafe { - _mm_store_ps(out.as_mut_ptr() as *mut f32, v.0); - out.assume_init().0 - } - } - - #[cfg(vec4f32)] - { - (v.0, v.1, v.2, v.3) - } - } -} - -impl From<[f32; 4]> for Vec4 { - #[inline] - fn from(a: [f32; 4]) -> Self { - #[cfg(vec4sse2)] - unsafe { - Self(_mm_loadu_ps(a.as_ptr())) - } - - #[cfg(vec4f32)] - { - Self(a[0], a[1], a[2], a[3]) - } - } -} - -impl From for [f32; 4] { - #[inline] - fn from(v: Vec4) -> Self { - #[cfg(vec4sse2)] - { - let mut out: MaybeUninit> = MaybeUninit::uninit(); - unsafe { - _mm_store_ps(out.as_mut_ptr() as *mut f32, v.0); - out.assume_init().0 - } - } - - #[cfg(vec4f32)] - { - [v.0, v.1, v.2, v.3] - } - } -} - -#[test] -fn test_vec4_private() { - assert_eq!( - vec4(1.0, 1.0, 1.0, 1.0).mul_add(vec4(0.5, 2.0, -4.0, 0.0), vec4(-1.0, -1.0, -1.0, -1.0)), - vec4(-0.5, 1.0, -5.0, -1.0) - ); - assert_eq!(vec4(1.0, 2.0, 3.0, 4.0).dup_x(), vec4(1.0, 1.0, 1.0, 1.0)); - assert_eq!(vec4(1.0, 2.0, 3.0, 4.0).dup_y(), vec4(2.0, 2.0, 2.0, 2.0)); - assert_eq!(vec4(1.0, 2.0, 3.0, 4.0).dup_z(), vec4(3.0, 3.0, 3.0, 3.0)); - assert_eq!(vec4(1.0, 2.0, 4.0, 4.0).dup_w(), vec4(4.0, 4.0, 4.0, 4.0)); -} diff --git a/crates/bevy_glam/src/f32/vec4_mask.rs b/crates/bevy_glam/src/f32/vec4_mask.rs deleted file mode 100644 index 1293f1f823..0000000000 --- a/crates/bevy_glam/src/f32/vec4_mask.rs +++ /dev/null @@ -1,329 +0,0 @@ -use crate::Vec4; -use core::{fmt, ops::*}; - -#[cfg(all(vec4sse2, target_arch = "x86"))] -use core::arch::x86::*; -#[cfg(all(vec4sse2, target_arch = "x86_64"))] -use core::arch::x86_64::*; -#[cfg(vec4sse2)] -use core::{cmp::Ordering, hash}; - -/// A 4-dimensional vector mask. -/// -/// This type is typically created by comparison methods on `Vec4`. It is -/// essentially a vector of four boolean values. -#[cfg(vec4sse2)] -#[derive(Clone, Copy)] -#[repr(C)] -pub struct Vec4Mask(pub(crate) __m128); - -#[cfg(vec4f32)] -#[derive(Clone, Copy, Default, PartialEq, Eq, Ord, PartialOrd, Hash)] -#[cfg_attr(vec4f32_align16, repr(align(16)))] -#[repr(C)] -pub struct Vec4Mask(u32, u32, u32, u32); - -#[cfg(vec4sse2)] -impl Default for Vec4Mask { - #[inline] - fn default() -> Self { - unsafe { Self(_mm_setzero_ps()) } - } -} - -#[cfg(vec4sse2)] -impl PartialEq for Vec4Mask { - #[inline] - fn eq(&self, other: &Self) -> bool { - self.as_ref().eq(other.as_ref()) - } -} - -#[cfg(vec4sse2)] -impl Eq for Vec4Mask {} - -#[cfg(vec4sse2)] -impl Ord for Vec4Mask { - #[inline] - fn cmp(&self, other: &Self) -> Ordering { - self.as_ref().cmp(other.as_ref()) - } -} - -#[cfg(vec4sse2)] -impl PartialOrd for Vec4Mask { - #[inline] - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -#[cfg(vec4sse2)] -impl hash::Hash for Vec4Mask { - #[inline] - fn hash(&self, state: &mut H) { - self.as_ref().hash(state); - } -} - -impl Vec4Mask { - /// Creates a new `Vec4Mask`. - #[inline] - pub 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]; - #[cfg(vec4sse2)] - unsafe { - Self(_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]), - )) - } - - #[cfg(vec4f32)] - { - Self( - MASK[x as usize], - MASK[y as usize], - MASK[z as usize], - MASK[w as usize], - ) - } - } - - /// Returns a bitmask with the lowest four bits set from the elements of - /// the `Vec4Mask`. - /// - /// 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 { - // _mm_movemask_ps only checks the most significant bit of the u32 is true, so we replicate - // that here with the non-SSE2 version. - - #[cfg(vec4sse2)] - unsafe { - _mm_movemask_ps(self.0) as u32 - } - - #[cfg(vec4f32)] - { - (self.0 & 0x1) | (self.1 & 0x1) << 1 | (self.2 & 0x1) << 2 | (self.3 & 0x1) << 3 - } - } - - /// Returns true if any of the elements are true, false otherwise. - /// - /// In other words: `x || y || z || w`. - #[inline] - pub fn any(self) -> bool { - #[cfg(vec4sse2)] - unsafe { - _mm_movemask_ps(self.0) != 0 - } - - #[cfg(vec4f32)] - { - ((self.0 | self.1 | self.2 | self.3) & 0x1) != 0 - } - } - - /// Returns true if all the elements are true, false otherwise. - /// - /// In other words: `x && y && z && w`. - #[inline] - pub fn all(self) -> bool { - #[cfg(vec4sse2)] - unsafe { - _mm_movemask_ps(self.0) == 0xf - } - - #[cfg(vec4f32)] - { - ((self.0 & self.1 & self.2 & self.3) & 0x1) != 0 - } - } - - /// Creates a new `Vec4` from the elements in `if_true` and `if_false`, - /// selecting which to use for each element based on the `Vec4Mask`. - /// - /// 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(self, if_true: Vec4, if_false: Vec4) -> Vec4 { - // We are assuming that the mask values are either 0 or 0xff_ff_ff_ff for the SSE2 and f32 - // to behave the same here. - - #[cfg(vec4sse2)] - unsafe { - Vec4(_mm_or_ps( - _mm_andnot_ps(self.0, if_false.0), - _mm_and_ps(if_true.0, self.0), - )) - } - - #[cfg(vec4f32)] - { - Vec4( - if self.0 != 0 { if_true.0 } else { if_false.0 }, - if self.1 != 0 { if_true.1 } else { if_false.1 }, - if self.2 != 0 { if_true.2 } else { if_false.2 }, - if self.3 != 0 { if_true.3 } else { if_false.3 }, - ) - } - } -} - -impl BitAnd for Vec4Mask { - type Output = Self; - #[inline] - fn bitand(self, other: Self) -> Self { - #[cfg(vec4sse2)] - unsafe { - Self(_mm_and_ps(self.0, other.0)) - } - - #[cfg(vec4f32)] - { - Self( - self.0 & other.0, - self.1 & other.1, - self.2 & other.2, - self.3 & other.3, - ) - } - } -} - -impl BitAndAssign for Vec4Mask { - #[inline] - fn bitand_assign(&mut self, other: Self) { - #[cfg(vec4sse2)] - { - self.0 = unsafe { _mm_and_ps(self.0, other.0) }; - } - - #[cfg(vec4f32)] - { - self.0 &= other.0; - self.1 &= other.1; - self.2 &= other.2; - self.3 &= other.3; - } - } -} - -impl BitOr for Vec4Mask { - type Output = Self; - #[inline] - fn bitor(self, other: Self) -> Self { - #[cfg(vec4sse2)] - unsafe { - Self(_mm_or_ps(self.0, other.0)) - } - - #[cfg(vec4f32)] - { - Self( - self.0 | other.0, - self.1 | other.1, - self.2 | other.2, - self.3 | other.3, - ) - } - } -} - -impl BitOrAssign for Vec4Mask { - #[inline] - fn bitor_assign(&mut self, other: Self) { - #[cfg(vec4sse2)] - { - self.0 = unsafe { _mm_or_ps(self.0, other.0) }; - } - - #[cfg(vec4f32)] - { - self.0 |= other.0; - self.1 |= other.1; - self.2 |= other.2; - self.3 |= other.3; - } - } -} - -impl Not for Vec4Mask { - type Output = Self; - #[inline] - fn not(self) -> Self { - #[cfg(vec4sse2)] - unsafe { - Self(_mm_andnot_ps( - self.0, - _mm_set_ps1(f32::from_bits(0xff_ff_ff_ff)), - )) - } - - #[cfg(vec4f32)] - { - Self(!self.0, !self.1, !self.2, !self.3) - } - } -} - -impl fmt::Debug for Vec4Mask { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - #[cfg(vec4sse2)] - { - let arr = self.as_ref(); - write!( - f, - "Vec4Mask({:#x}, {:#x}, {:#x}, {:#x})", - arr[0], arr[1], arr[2], arr[3] - ) - } - - #[cfg(vec4f32)] - { - write!( - f, - "Vec4Mask({:#x}, {:#x}, {:#x}, {:#x})", - self.0, self.1, self.2, self.3 - ) - } - } -} - -impl fmt::Display for Vec4Mask { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let arr = self.as_ref(); - write!( - f, - "[{}, {}, {}, {}]", - arr[0] != 0, - arr[1] != 0, - arr[2] != 0, - arr[3] != 0 - ) - } -} - -impl From for [u32; 4] { - #[inline] - fn from(mask: Vec4Mask) -> Self { - *mask.as_ref() - } -} - -impl AsRef<[u32; 4]> for Vec4Mask { - #[inline] - fn as_ref(&self) -> &[u32; 4] { - unsafe { &*(self as *const Self as *const [u32; 4]) } - } -} diff --git a/crates/bevy_glam/src/f32/x86_utils.rs b/crates/bevy_glam/src/f32/x86_utils.rs deleted file mode 100644 index 47119b47f5..0000000000 --- a/crates/bevy_glam/src/f32/x86_utils.rs +++ /dev/null @@ -1,15 +0,0 @@ -#[cfg(target_arch = "x86")] -use core::arch::x86::*; -#[cfg(target_arch = "x86_64")] -use core::arch::x86_64::*; - -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -#[allow(dead_code)] -#[repr(C)] -pub(crate) union UnionCast { - pub m128: __m128, - pub m128i: __m128i, - pub f32x4: [f32; 4], - pub i32x4: [i32; 4], - pub u32x4: [u32; 4], -} diff --git a/crates/bevy_glam/src/lib.rs b/crates/bevy_glam/src/lib.rs deleted file mode 100644 index bb260514bb..0000000000 --- a/crates/bevy_glam/src/lib.rs +++ /dev/null @@ -1,167 +0,0 @@ -/*! -# glam - -`glam` is a simple and fast linear algebra library for games and graphics. - -## Features - -`glam` is built with SIMD in mind. Currently only SSE2 on x86/x86_64 is -supported as this is what stable Rust supports. - -* Single precision float (`f32`) support only -* SSE2 implementation for most types, including `Mat2`, `Mat3`, `Mat4`, `Quat`, - `Vec3` and `Vec4` -* Scalar fallback implementations exist when SSE2 is not available -* Most functionality includes unit tests and benchmarks - -## Linear algebra conventions - -`glam` interprets vectors as column matrices (also known as "column vectors") -meaning when transforming a vector with a matrix the matrix goes on the left. - -``` -use glam::{Mat3, Vec3}; -let m = Mat3::identity(); -let x = Vec3::unit_x(); -let v = m * x; -assert_eq!(v, x); -``` - -Matrices are stored in memory in column-major order. - -Rotations follow left-hand rule. The direction of the axis gives the direction -of rotation: with the left thumb pointing in the positive direction of the axis -the left fingers curl around the axis in the direction of the rotation. - -``` -use glam::{Mat3, Vec3}; -// rotate +x 90 degrees clockwise around y giving -z -let m = Mat3::from_rotation_y(90.0_f32.to_radians()); -let v = m * Vec3::unit_x(); -assert!(v.abs_diff_eq(-Vec3::unit_z(), core::f32::EPSILON)); -``` - -## Size and alignment of types - -Most `glam` types use SIMD for storage meaning most types are 16 byte aligned. -The only exception is Vec2`. When SSE2 is not available on the target -architecture the types will still be 16 byte aligned, so object sizes and -layouts will not change between architectures. - -16 byte alignment means that some types will have a stride larger than their -size resulting in some wasted space. - -| Type | f32 bytes | SIMD bytes | Wasted bytes | -|:-----|----------:|-----------:|-------------:| -|`Vec3`| 12| 16| 4| -|`Mat3`| 36| 48| 12| - -Despite this wasted space the SIMD version tends to outperform the `f32` -implementation in [**mathbench**](https://github.com/bitshifter/mathbench-rs) -benchmarks. - -SIMD support can be disabled entirely using the `scalar-math` feature. This -feature will also disable SIMD alignment meaning most types will use native -`f32` alignment of 4 bytes. - -All the main `glam` types are tagged with #[repr(C)], so they are possible -to expose as struct members to C interfaces if desired. Be mindful of Vec3's -extra float though. - -## Accessing internal data - -The SIMD types that `glam` builds on are opaque and their contents are not -directly accessible. Because of this `glam` types uses getter and setter -methods instead of providing direct access. - -``` -use glam::Vec3; -let mut v = Vec3::new(1.0, 2.0, 3.0); -assert_eq!(v.y(), 2.0); -v.set_z(1.0); -assert_eq!(v.z(), 1.0); -``` - -If you need to access multiple elements it is easier to convert the type to a -tuple or array: - -``` -use glam::Vec3; -let v = Vec3::new(1.0, 2.0, 3.0); -let (x, y, z) = v.into(); -assert_eq!((x, y, z), (1.0, 2.0, 3.0)); -``` - -## SIMD and scalar consistency - -`glam` types implement `serde` `Serialize` and `Deserialize` traits to ensure -that they will serialize and deserialize exactly the same whether or not -SIMD support is being used. - -The SIMD versions implement `core::fmt::Display` traits so they print the same as -the scalar version. - -``` -use glam::Vec3; -let a = Vec3::new(1.0, 2.0, 3.0); -assert_eq!(format!("{}", a), "[1, 2, 3]"); -``` - -## Feature gates - -All `glam` dependencies are optional, however some are required for tests -and benchmarks. - -* `std` - the default feature, has no dependencies. -* `rand` - used to generate random values. Used in benchmarks. -* `serde` - used for serialization and deserialization of types. -* `mint` - used for interoperating with other linear algebra libraries. -* `scalar-math` - disables SIMD support and uses native alignment for all - types. -* `debug-glam-assert` - adds assertions in debug builds which check the validity - of parameters 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. - -*/ -#![doc(html_root_url = "https://docs.rs/glam/0.8.7")] - -#[macro_use] -mod macros; - -pub mod f32; - -pub use self::f32::{ - mat2, mat3, mat4, quat, vec2, vec3, vec4, Mat2, Mat3, Mat4, Quat, Vec2, Vec2Mask, Vec3, - Vec3Mask, Vec4, Vec4Mask, -}; - -#[cfg(feature = "transform-types")] -pub use self::f32::{TransformRT, TransformSRT}; - -#[repr(align(16))] -pub(crate) struct Align16(T); - -impl Align16 { - #[allow(dead_code)] - pub fn as_ptr(&self) -> *const T { - &self.0 - } - - #[allow(dead_code)] - pub fn as_mut_ptr(&mut self) -> *mut T { - &mut self.0 - } -} - -#[test] -fn test_align16() { - use core::{mem, ptr}; - let mut a = Align16::(1.0); - assert_eq!(mem::align_of_val(&a), 16); - unsafe { - assert_eq!(ptr::read(a.as_ptr()), 1.0); - ptr::write(a.as_mut_ptr(), -1.0); - } - assert_eq!(a.0, -1.0); -} diff --git a/crates/bevy_glam/src/macros.rs b/crates/bevy_glam/src/macros.rs deleted file mode 100644 index f1c22d4e27..0000000000 --- a/crates/bevy_glam/src/macros.rs +++ /dev/null @@ -1,32 +0,0 @@ -#[cfg(any( - all(debug_assertions, feature = "debug-glam-assert"), - feature = "glam-assert" -))] -macro_rules! glam_assert { - ($($arg:tt)*) => ( assert!($($arg)*); ) -} -#[cfg(not(any( - all(debug_assertions, feature = "debug-glam-assert"), - feature = "glam-assert" -)))] -macro_rules! glam_assert { - ($($arg:tt)*) => {}; -} - -macro_rules! is_normalized { - ($self:expr, $max_diff:expr) => { - ($self.length_squared() - 1.0).abs() <= $max_diff - }; - ($self:expr) => { - is_normalized!($self, 1e-6) - }; -} - -macro_rules! abs_diff_eq { - ($self:expr, $other:expr, $max_abs_diff:expr) => { - ($self - $other) - .abs() - .cmple(Self::splat($max_abs_diff)) - .all() - }; -} diff --git a/crates/bevy_glam/tests/mat2.rs b/crates/bevy_glam/tests/mat2.rs deleted file mode 100644 index 5a30aa0902..0000000000 --- a/crates/bevy_glam/tests/mat2.rs +++ /dev/null @@ -1,186 +0,0 @@ -mod support; - -use glam::f32::*; -use support::deg; - -const IDENTITY: [[f32; 2]; 2] = [[1.0, 0.0], [0.0, 1.0]]; - -const MATRIX: [[f32; 2]; 2] = [[1.0, 2.0], [3.0, 4.0]]; - -const ZERO: [[f32; 2]; 2] = [[0.0; 2]; 2]; - -#[test] -fn test_mat2_align() { - use std::mem; - assert_eq!(16, mem::size_of::()); - if cfg!(feature = "scalar-math") { - assert_eq!(4, mem::align_of::()); - } else { - assert_eq!(16, mem::align_of::()); - } -} - -#[test] -fn test_mat2_identity() { - let identity = Mat2::identity(); - assert_eq!(IDENTITY, identity.to_cols_array_2d()); - assert_eq!(Mat2::from_cols_array_2d(&IDENTITY), identity); - assert_eq!(identity, identity * identity); - assert_eq!(identity, Mat2::default()); -} - -#[test] -fn test_mat2_zero() { - assert_eq!(Mat2::from_cols_array_2d(&ZERO), Mat2::zero()); -} - -#[test] -fn test_mat2_accessors() { - let mut m = Mat2::zero(); - m.set_x_axis(Vec2::new(1.0, 2.0)); - m.set_y_axis(Vec2::new(3.0, 4.0)); - assert_eq!(Mat2::from_cols_array_2d(&MATRIX), m); - assert_eq!(Vec2::new(1.0, 2.0), m.x_axis()); - assert_eq!(Vec2::new(3.0, 4.0), m.y_axis()); -} - -#[test] -fn test_mat2_from_axes() { - let a = Mat2::from_cols_array_2d(&[[1.0, 2.0], [3.0, 4.0]]); - assert_eq!(MATRIX, a.to_cols_array_2d()); - let b = Mat2::from_cols(vec2(1.0, 2.0), vec2(3.0, 4.0)); - assert_eq!(a, b); - let c = mat2(vec2(1.0, 2.0), vec2(3.0, 4.0)); - assert_eq!(a, c); - let d = b.to_cols_array(); - let f = Mat2::from_cols_array(&d); - assert_eq!(b, f); -} - -#[test] -fn test_mat2_mul() { - let mat_a = Mat2::from_angle(deg(90.0)); - let res_a = mat_a * Vec2::unit_y(); - assert_approx_eq!(vec2(-1.0, 0.0), res_a); - let res_b = mat_a * Vec2::unit_x(); - assert_approx_eq!(vec2(0.0, 1.0), res_b); -} - -#[test] -fn test_from_scale() { - let m = Mat2::from_scale(Vec2::new(2.0, 4.0)); - assert_approx_eq!(m * Vec2::new(1.0, 1.0), Vec2::new(2.0, 4.0)); - assert_approx_eq!(Vec2::unit_x() * 2.0, m.x_axis()); - assert_approx_eq!(Vec2::unit_y() * 4.0, m.y_axis()); - - let rot = Mat2::from_scale_angle(Vec2::new(4.0, 2.0), deg(180.0)); - assert_approx_eq!(Vec2::unit_x() * -4.0, rot * Vec2::unit_x(), 1.0e-6); - assert_approx_eq!(Vec2::unit_y() * -2.0, rot * Vec2::unit_y(), 1.0e-6); -} - -#[test] -fn test_mat2_transpose() { - let m = mat2(vec2(1.0, 2.0), vec2(3.0, 4.0)); - let mt = m.transpose(); - assert_eq!(mt.x_axis(), vec2(1.0, 3.0)); - assert_eq!(mt.y_axis(), vec2(2.0, 4.0)); -} - -#[test] -fn test_mat2_det() { - assert_eq!(0.0, Mat2::zero().determinant()); - assert_eq!(1.0, Mat2::identity().determinant()); - assert_eq!(1.0, Mat2::from_angle(deg(90.0)).determinant()); - assert_eq!(1.0, Mat2::from_angle(deg(180.0)).determinant()); - assert_eq!(1.0, Mat2::from_angle(deg(270.0)).determinant()); - assert_eq!(2.0 * 2.0, Mat2::from_scale(vec2(2.0, 2.0)).determinant()); - assert_eq!( - 1.0 * 4.0 - 2.0 * 3.0, - Mat2::from_cols_array(&[1.0, 2.0, 3.0, 4.0]).determinant() - ); -} - -#[test] -fn test_mat2_inverse() { - let inv = Mat2::identity().inverse(); - assert_approx_eq!(Mat2::identity(), inv); - - let rot = Mat2::from_angle(deg(90.0)); - let rot_inv = rot.inverse(); - assert_approx_eq!(Mat2::identity(), rot * rot_inv); - assert_approx_eq!(Mat2::identity(), rot_inv * rot); - - let scale = Mat2::from_scale(vec2(4.0, 5.0)); - let scale_inv = scale.inverse(); - assert_approx_eq!(Mat2::identity(), scale * scale_inv); - assert_approx_eq!(Mat2::identity(), scale_inv * scale); - - let m = scale * rot; - let m_inv = m.inverse(); - assert_approx_eq!(Mat2::identity(), m * m_inv); - assert_approx_eq!(Mat2::identity(), m_inv * m); - assert_approx_eq!(m_inv, rot_inv * scale_inv); -} - -#[test] -fn test_mat2_ops() { - let m0 = Mat2::from_cols_array_2d(&MATRIX); - assert_eq!( - Mat2::from_cols_array_2d(&[[2.0, 4.0], [6.0, 8.0]]), - m0 * 2.0 - ); - assert_eq!( - Mat2::from_cols_array_2d(&[[2.0, 4.0], [6.0, 8.0]]), - 2.0 * m0 - ); - assert_eq!(Mat2::from_cols_array_2d(&[[2.0, 4.0], [6.0, 8.0]]), m0 + m0); - assert_eq!(Mat2::zero(), m0 - m0); - assert_approx_eq!( - Mat2::from_cols_array_2d(&[[1.0, 2.0], [3.0, 4.0]]), - m0 * Mat2::identity() - ); - assert_approx_eq!( - Mat2::from_cols_array_2d(&[[1.0, 2.0], [3.0, 4.0]]), - Mat2::identity() * m0 - ); -} - -#[test] -fn test_mat2_fmt() { - let a = Mat2::from_cols_array_2d(&MATRIX); - assert_eq!(format!("{}", a), "[[1, 2], [3, 4]]"); -} - -#[cfg(feature = "serde")] -#[test] -fn test_mat2_serde() { - let a = Mat2::from_cols(vec2(1.0, 2.0), vec2(3.0, 4.0)); - let serialized = serde_json::to_string(&a).unwrap(); - assert_eq!(serialized, "[1.0,2.0,3.0,4.0]"); - let deserialized = serde_json::from_str(&serialized).unwrap(); - assert_eq!(a, deserialized); - let deserialized = serde_json::from_str::("[]"); - assert!(deserialized.is_err()); - let deserialized = serde_json::from_str::("[1.0]"); - assert!(deserialized.is_err()); - let deserialized = serde_json::from_str::("[1.0,2.0]"); - assert!(deserialized.is_err()); - let deserialized = serde_json::from_str::("[1.0,2.0,3.0]"); - assert!(deserialized.is_err()); - let deserialized = serde_json::from_str::("[1.0,2.0,3.0,4.0,5.0]"); - assert!(deserialized.is_err()); - let deserialized = serde_json::from_str::("[[1.0,2.0],[3.0,4.0]]"); - assert!(deserialized.is_err()); -} - -#[cfg(feature = "rand")] -#[test] -fn test_mat2_rand() { - use rand::{Rng, SeedableRng}; - use rand_xoshiro::Xoshiro256Plus; - let mut rng1 = Xoshiro256Plus::seed_from_u64(0); - let a = Mat2::from_cols_array(&rng1.gen::<[f32; 4]>()); - let mut rng2 = Xoshiro256Plus::seed_from_u64(0); - let b = rng2.gen::(); - assert_eq!(a, b); -} diff --git a/crates/bevy_glam/tests/mat3.rs b/crates/bevy_glam/tests/mat3.rs deleted file mode 100644 index da36311c13..0000000000 --- a/crates/bevy_glam/tests/mat3.rs +++ /dev/null @@ -1,253 +0,0 @@ -mod support; - -use glam::f32::*; -use support::deg; - -const IDENTITY: [[f32; 3]; 3] = [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]]; - -const MATRIX: [[f32; 3]; 3] = [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]]; - -const ZERO: [[f32; 3]; 3] = [[0.0; 3]; 3]; - -#[test] -fn test_mat3_align() { - use std::mem; - if cfg!(any(feature = "packed-vec3", feature = "scalar-math")) { - assert_eq!(36, mem::size_of::()); - assert_eq!(4, mem::align_of::()); - } else { - assert_eq!(48, mem::size_of::()); - assert_eq!(16, mem::align_of::()); - } -} - -#[test] -fn test_mat3_identity() { - let identity = Mat3::identity(); - assert_eq!(IDENTITY, identity.to_cols_array_2d()); - assert_eq!(Mat3::from_cols_array_2d(&IDENTITY), identity); - assert_eq!(identity, identity * identity); - assert_eq!(identity, Mat3::default()); -} - -#[test] -fn test_mat3_zero() { - assert_eq!(Mat3::from_cols_array_2d(&ZERO), Mat3::zero()); -} - -#[test] -fn test_mat3_accessors() { - let mut m = Mat3::zero(); - m.set_x_axis(Vec3::new(1.0, 2.0, 3.0)); - m.set_y_axis(Vec3::new(4.0, 5.0, 6.0)); - m.set_z_axis(Vec3::new(7.0, 8.0, 9.0)); - assert_eq!(Mat3::from_cols_array_2d(&MATRIX), m); - assert_eq!(Vec3::new(1.0, 2.0, 3.0), m.x_axis()); - assert_eq!(Vec3::new(4.0, 5.0, 6.0), m.y_axis()); - assert_eq!(Vec3::new(7.0, 8.0, 9.0), m.z_axis()); -} - -#[test] -fn test_mat3_from_axes() { - let a = Mat3::from_cols_array_2d(&[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]]); - assert_eq!(MATRIX, a.to_cols_array_2d()); - let b = Mat3::from_cols( - vec3(1.0, 2.0, 3.0), - vec3(4.0, 5.0, 6.0), - vec3(7.0, 8.0, 9.0), - ); - assert_eq!(a, b); - let c = mat3( - vec3(1.0, 2.0, 3.0), - vec3(4.0, 5.0, 6.0), - vec3(7.0, 8.0, 9.0), - ); - assert_eq!(a, c); - let d = b.to_cols_array(); - let f = Mat3::from_cols_array(&d); - assert_eq!(b, f); -} - -#[test] -fn test_from_rotation() { - let rot_x1 = Mat3::from_rotation_x(deg(180.0)); - let rot_x2 = Mat3::from_axis_angle(Vec3::unit_x(), deg(180.0)); - assert_approx_eq!(rot_x1, rot_x2); - let rot_y1 = Mat3::from_rotation_y(deg(180.0)); - let rot_y2 = Mat3::from_axis_angle(Vec3::unit_y(), deg(180.0)); - assert_approx_eq!(rot_y1, rot_y2); - let rot_z1 = Mat3::from_rotation_z(deg(180.0)); - let rot_z2 = Mat3::from_axis_angle(Vec3::unit_z(), deg(180.0)); - assert_approx_eq!(rot_z1, rot_z2); -} - -#[test] -fn test_mat3_mul() { - let mat_a = Mat3::from_axis_angle(Vec3::unit_z(), deg(90.0)); - let result3 = mat_a * Vec3::unit_y(); - assert_approx_eq!(vec3(-1.0, 0.0, 0.0), result3); -} - -#[test] -fn test_mat3_transform2d() { - let mat_b = Mat3::from_scale_angle_translation( - Vec2::new(0.5, 1.5), - f32::to_radians(90.0), - Vec2::new(1.0, 2.0), - ); - let result2 = mat_b.transform_vector2(Vec2::unit_y()); - assert_approx_eq!(vec2(-1.5, 0.0), result2, 1.0e-6); - assert_approx_eq!(result2, (mat_b * Vec2::unit_y().extend(0.0)).truncate()); - - let result2 = mat_b.transform_point2(Vec2::unit_y()); - assert_approx_eq!(vec2(-0.5, 2.0), result2, 1.0e-6); - assert_approx_eq!(result2, (mat_b * Vec2::unit_y().extend(1.0)).truncate()); -} - -#[test] -fn test_from_ypr() { - let zero = deg(0.0); - let yaw = deg(30.0); - let pitch = deg(60.0); - let roll = deg(90.0); - let y0 = Mat3::from_rotation_y(yaw); - let y1 = Mat3::from_rotation_ypr(yaw, zero, zero); - assert_approx_eq!(y0, y1); - - let x0 = Mat3::from_rotation_x(pitch); - let x1 = Mat3::from_rotation_ypr(zero, pitch, zero); - assert_approx_eq!(x0, x1); - - let z0 = Mat3::from_rotation_z(roll); - let z1 = Mat3::from_rotation_ypr(zero, zero, roll); - assert_approx_eq!(z0, z1); - - let yx0 = y0 * x0; - let yx1 = Mat3::from_rotation_ypr(yaw, pitch, zero); - assert_approx_eq!(yx0, yx1); - - let yxz0 = y0 * x0 * z0; - let yxz1 = Mat3::from_rotation_ypr(yaw, pitch, roll); - assert_approx_eq!(yxz0, yxz1, 1e-6); -} - -#[test] -fn test_from_scale() { - let m = Mat3::from_scale(Vec3::new(2.0, 4.0, 8.0)); - assert_approx_eq!(m * Vec3::new(1.0, 1.0, 1.0), Vec3::new(2.0, 4.0, 8.0)); - assert_approx_eq!(Vec3::unit_x() * 2.0, m.x_axis()); - assert_approx_eq!(Vec3::unit_y() * 4.0, m.y_axis()); - assert_approx_eq!(Vec3::unit_z() * 8.0, m.z_axis()); -} - -#[test] -fn test_mat3_transpose() { - let m = mat3( - vec3(1.0, 2.0, 3.0), - vec3(4.0, 5.0, 6.0), - vec3(7.0, 8.0, 9.0), - ); - let mt = m.transpose(); - assert_eq!(mt.x_axis(), vec3(1.0, 4.0, 7.0)); - assert_eq!(mt.y_axis(), vec3(2.0, 5.0, 8.0)); - assert_eq!(mt.z_axis(), vec3(3.0, 6.0, 9.0)); -} - -#[test] -fn test_mat3_det() { - assert_eq!(0.0, Mat3::zero().determinant()); - assert_eq!(1.0, Mat3::identity().determinant()); - assert_eq!(1.0, Mat3::from_rotation_x(deg(90.0)).determinant()); - assert_eq!(1.0, Mat3::from_rotation_y(deg(180.0)).determinant()); - assert_eq!(1.0, Mat3::from_rotation_z(deg(270.0)).determinant()); - assert_eq!( - 2.0 * 2.0 * 2.0, - Mat3::from_scale(vec3(2.0, 2.0, 2.0)).determinant() - ); -} - -#[test] -fn test_mat3_inverse() { - // assert_eq!(None, Mat3::zero().inverse()); - let inv = Mat3::identity().inverse(); - // assert_ne!(None, inv); - assert_approx_eq!(Mat3::identity(), inv); - - let rotz = Mat3::from_rotation_z(deg(90.0)); - let rotz_inv = rotz.inverse(); - // assert_ne!(None, rotz_inv); - // let rotz_inv = rotz_inv.unwrap(); - assert_approx_eq!(Mat3::identity(), rotz * rotz_inv); - assert_approx_eq!(Mat3::identity(), rotz_inv * rotz); - - let scale = Mat3::from_scale(vec3(4.0, 5.0, 6.0)); - let scale_inv = scale.inverse(); - // assert_ne!(None, scale_inv); - // let scale_inv = scale_inv.unwrap(); - assert_approx_eq!(Mat3::identity(), scale * scale_inv); - assert_approx_eq!(Mat3::identity(), scale_inv * scale); - - let m = scale * rotz; - let m_inv = m.inverse(); - // assert_ne!(None, m_inv); - // let m_inv = m_inv.unwrap(); - assert_approx_eq!(Mat3::identity(), m * m_inv); - assert_approx_eq!(Mat3::identity(), m_inv * m); - assert_approx_eq!(m_inv, rotz_inv * scale_inv); -} - -#[test] -fn test_mat3_ops() { - let m0 = Mat3::from_cols_array_2d(&MATRIX); - let m0x2 = Mat3::from_cols_array_2d(&[[2.0, 4.0, 6.0], [8.0, 10.0, 12.0], [14.0, 16.0, 18.0]]); - assert_eq!(m0x2, m0 * 2.0); - assert_eq!(m0x2, 2.0 * m0); - assert_eq!(m0x2, m0 + m0); - assert_eq!(Mat3::zero(), m0 - m0); - assert_approx_eq!(m0, m0 * Mat3::identity()); - assert_approx_eq!(m0, Mat3::identity() * m0); -} - -#[test] -fn test_mat3_fmt() { - let a = Mat3::from_cols_array_2d(&MATRIX); - assert_eq!(format!("{}", a), "[[1, 2, 3], [4, 5, 6], [7, 8, 9]]"); -} - -#[cfg(feature = "serde")] -#[test] -fn test_mat3_serde() { - let a = Mat3::from_cols( - vec3(1.0, 2.0, 3.0), - vec3(4.0, 5.0, 6.0), - vec3(7.0, 8.0, 9.0), - ); - let serialized = serde_json::to_string(&a).unwrap(); - assert_eq!(serialized, "[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0]"); - let deserialized = serde_json::from_str(&serialized).unwrap(); - assert_eq!(a, deserialized); - let deserialized = serde_json::from_str::("[]"); - assert!(deserialized.is_err()); - let deserialized = serde_json::from_str::("[1.0]"); - assert!(deserialized.is_err()); - let deserialized = serde_json::from_str::("[1.0,2.0]"); - assert!(deserialized.is_err()); - let deserialized = serde_json::from_str::("[1.0,2.0,3.0]"); - assert!(deserialized.is_err()); - let deserialized = serde_json::from_str::("[1.0,2.0,3.0,4.0,5.0]"); - assert!(deserialized.is_err()); - let deserialized = serde_json::from_str::("[[1.0,2.0,3.0],[4.0,5.0,6.0],[7.0,8.0,9.0]]"); - assert!(deserialized.is_err()); -} - -#[cfg(feature = "rand")] -#[test] -fn test_mat3_rand() { - use rand::{Rng, SeedableRng}; - use rand_xoshiro::Xoshiro256Plus; - let mut rng1 = Xoshiro256Plus::seed_from_u64(0); - let a = Mat3::from_cols_array(&rng1.gen::<[f32; 9]>()); - let mut rng2 = Xoshiro256Plus::seed_from_u64(0); - let b = rng2.gen::(); - assert_eq!(a, b); -} diff --git a/crates/bevy_glam/tests/mat4.rs b/crates/bevy_glam/tests/mat4.rs deleted file mode 100644 index 1e478f2043..0000000000 --- a/crates/bevy_glam/tests/mat4.rs +++ /dev/null @@ -1,483 +0,0 @@ -mod support; - -use glam::f32::*; -use support::deg; - -const IDENTITY: [[f32; 4]; 4] = [ - [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], -]; - -const MATRIX: [[f32; 4]; 4] = [ - [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 ZERO: [[f32; 4]; 4] = [[0.0; 4]; 4]; - -#[test] -fn test_mat4_align() { - use std::mem; - assert_eq!(64, mem::size_of::()); - if cfg!(feature = "scalar-math") { - assert_eq!(4, mem::align_of::()); - } else { - assert_eq!(16, mem::align_of::()); - } -} - -#[test] -fn test_mat4_identity() { - let identity = Mat4::identity(); - assert_eq!(IDENTITY, identity.to_cols_array_2d()); - assert_eq!(Mat4::from_cols_array_2d(&IDENTITY), identity); - assert_eq!(identity, identity * identity); - assert_eq!(identity, Mat4::default()); -} - -#[test] -fn test_mat4_zero() { - assert_eq!(Mat4::from_cols_array_2d(&ZERO), Mat4::zero()); -} - -#[test] -fn test_mat4_accessors() { - let mut m = Mat4::zero(); - m.set_x_axis(Vec4::new(1.0, 2.0, 3.0, 4.0)); - m.set_y_axis(Vec4::new(5.0, 6.0, 7.0, 8.0)); - m.set_z_axis(Vec4::new(9.0, 10.0, 11.0, 12.0)); - m.set_w_axis(Vec4::new(13.0, 14.0, 15.0, 16.0)); - assert_eq!(Mat4::from_cols_array_2d(&MATRIX), m); - assert_eq!(Vec4::new(1.0, 2.0, 3.0, 4.0), m.x_axis()); - assert_eq!(Vec4::new(5.0, 6.0, 7.0, 8.0), m.y_axis()); - assert_eq!(Vec4::new(9.0, 10.0, 11.0, 12.0), m.z_axis()); - assert_eq!(Vec4::new(13.0, 14.0, 15.0, 16.0), m.w_axis()); -} - -#[test] -fn test_mat4_from_axes() { - let a = 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], - ]); - assert_eq!(MATRIX, a.to_cols_array_2d()); - let b = Mat4::from_cols( - vec4(1.0, 2.0, 3.0, 4.0), - vec4(5.0, 6.0, 7.0, 8.0), - vec4(9.0, 10.0, 11.0, 12.0), - vec4(13.0, 14.0, 15.0, 16.0), - ); - assert_eq!(a, b); - let c = mat4( - vec4(1.0, 2.0, 3.0, 4.0), - vec4(5.0, 6.0, 7.0, 8.0), - vec4(9.0, 10.0, 11.0, 12.0), - vec4(13.0, 14.0, 15.0, 16.0), - ); - assert_eq!(a, c); - let d = b.to_cols_array(); - let f = Mat4::from_cols_array(&d); - assert_eq!(b, f); -} - -#[test] -fn test_mat4_translation() { - let translate = Mat4::from_translation(vec3(1.0, 2.0, 3.0)); - assert_eq!( - Mat4::from_cols( - vec4(1.0, 0.0, 0.0, 0.0), - vec4(0.0, 1.0, 0.0, 0.0), - vec4(0.0, 0.0, 1.0, 0.0), - vec4(1.0, 2.0, 3.0, 1.0) - ), - translate - ); -} - -#[test] -fn test_from_rotation() { - let rot_x1 = Mat4::from_rotation_x(deg(180.0)); - let rot_x2 = Mat4::from_axis_angle(Vec3::unit_x(), deg(180.0)); - assert_approx_eq!(rot_x1, rot_x2); - let rot_y1 = Mat4::from_rotation_y(deg(180.0)); - let rot_y2 = Mat4::from_axis_angle(Vec3::unit_y(), deg(180.0)); - assert_approx_eq!(rot_y1, rot_y2); - let rot_z1 = Mat4::from_rotation_z(deg(180.0)); - let rot_z2 = Mat4::from_axis_angle(Vec3::unit_z(), deg(180.0)); - assert_approx_eq!(rot_z1, rot_z2); -} - -#[test] -fn test_mat4_mul() { - let mat_a = Mat4::from_axis_angle(Vec3::unit_z(), deg(90.0)); - let result3 = mat_a.transform_vector3(Vec3::unit_y()); - assert_approx_eq!(vec3(-1.0, 0.0, 0.0), result3); - assert_approx_eq!(result3, (mat_a * Vec3::unit_y().extend(0.0)).truncate()); - let result4 = mat_a * Vec4::unit_y(); - assert_approx_eq!(vec4(-1.0, 0.0, 0.0, 0.0), result4); - assert_approx_eq!(result4, mat_a * Vec4::unit_y()); - - let mat_b = Mat4::from_scale_rotation_translation( - Vec3::new(0.5, 1.5, 2.0), - Quat::from_rotation_x(deg(90.0)), - Vec3::new(1.0, 2.0, 3.0), - ); - let result3 = mat_b.transform_vector3(Vec3::unit_y()); - assert_approx_eq!(vec3(0.0, 0.0, 1.5), result3, 1.0e-6); - assert_approx_eq!(result3, (mat_b * Vec3::unit_y().extend(0.0)).truncate()); - - let result3 = mat_b.transform_point3(Vec3::unit_y()); - assert_approx_eq!(vec3(1.0, 2.0, 4.5), result3, 1.0e-6); - assert_approx_eq!(result3, (mat_b * Vec3::unit_y().extend(1.0)).truncate()); -} - -#[test] -fn test_from_ypr() { - let zero = deg(0.0); - let yaw = deg(30.0); - let pitch = deg(60.0); - let roll = deg(90.0); - let y0 = Mat4::from_rotation_y(yaw); - let y1 = Mat4::from_rotation_ypr(yaw, zero, zero); - assert_approx_eq!(y0, y1); - - let x0 = Mat4::from_rotation_x(pitch); - let x1 = Mat4::from_rotation_ypr(zero, pitch, zero); - assert_approx_eq!(x0, x1); - - let z0 = Mat4::from_rotation_z(roll); - let z1 = Mat4::from_rotation_ypr(zero, zero, roll); - assert_approx_eq!(z0, z1); - - let yx0 = y0 * x0; - let yx1 = Mat4::from_rotation_ypr(yaw, pitch, zero); - assert_approx_eq!(yx0, yx1); - - let yxz0 = y0 * x0 * z0; - let yxz1 = Mat4::from_rotation_ypr(yaw, pitch, roll); - assert_approx_eq!(yxz0, yxz1, 1e-6); -} - -#[test] -fn test_from_scale() { - let m = Mat4::from_scale(Vec3::new(2.0, 4.0, 8.0)); - assert_approx_eq!( - m.transform_point3(Vec3::new(1.0, 1.0, 1.0)), - Vec3::new(2.0, 4.0, 8.0) - ); - assert_approx_eq!(Vec4::unit_x() * 2.0, m.x_axis()); - assert_approx_eq!(Vec4::unit_y() * 4.0, m.y_axis()); - assert_approx_eq!(Vec4::unit_z() * 8.0, m.z_axis()); - assert_approx_eq!(Vec4::unit_w(), m.w_axis()); -} - -#[test] -fn test_mat4_transpose() { - let m = mat4( - vec4(1.0, 2.0, 3.0, 4.0), - vec4(5.0, 6.0, 7.0, 8.0), - vec4(9.0, 10.0, 11.0, 12.0), - vec4(13.0, 14.0, 15.0, 16.0), - ); - let mt = m.transpose(); - assert_eq!(mt.x_axis(), vec4(1.0, 5.0, 9.0, 13.0)); - assert_eq!(mt.y_axis(), vec4(2.0, 6.0, 10.0, 14.0)); - assert_eq!(mt.z_axis(), vec4(3.0, 7.0, 11.0, 15.0)); - assert_eq!(mt.w_axis(), vec4(4.0, 8.0, 12.0, 16.0)); -} - -#[test] -fn test_mat4_det() { - assert_eq!(0.0, Mat4::zero().determinant()); - assert_eq!(1.0, Mat4::identity().determinant()); - assert_eq!(1.0, Mat4::from_rotation_x(deg(90.0)).determinant()); - assert_eq!(1.0, Mat4::from_rotation_y(deg(180.0)).determinant()); - assert_eq!(1.0, Mat4::from_rotation_z(deg(270.0)).determinant()); - assert_eq!( - 2.0 * 2.0 * 2.0, - Mat4::from_scale(vec3(2.0, 2.0, 2.0)).determinant() - ); -} - -#[test] -fn test_mat4_inverse() { - // assert_eq!(None, Mat4::zero().inverse()); - let inv = Mat4::identity().inverse(); - // assert_ne!(None, inv); - assert_approx_eq!(Mat4::identity(), inv); - - let rotz = Mat4::from_rotation_z(deg(90.0)); - let rotz_inv = rotz.inverse(); - // assert_ne!(None, rotz_inv); - // let rotz_inv = rotz_inv.unwrap(); - assert_approx_eq!(Mat4::identity(), rotz * rotz_inv); - assert_approx_eq!(Mat4::identity(), rotz_inv * rotz); - - let trans = Mat4::from_translation(vec3(1.0, 2.0, 3.0)); - let trans_inv = trans.inverse(); - // assert_ne!(None, trans_inv); - // let trans_inv = trans_inv.unwrap(); - assert_approx_eq!(Mat4::identity(), trans * trans_inv); - assert_approx_eq!(Mat4::identity(), trans_inv * trans); - - let scale = Mat4::from_scale(vec3(4.0, 5.0, 6.0)); - let scale_inv = scale.inverse(); - // assert_ne!(None, scale_inv); - // let scale_inv = scale_inv.unwrap(); - assert_approx_eq!(Mat4::identity(), scale * scale_inv); - assert_approx_eq!(Mat4::identity(), scale_inv * scale); - - let m = scale * rotz * trans; - let m_inv = m.inverse(); - // assert_ne!(None, m_inv); - // let m_inv = m_inv.unwrap(); - assert_approx_eq!(Mat4::identity(), m * m_inv, 1.0e-5); - assert_approx_eq!(Mat4::identity(), m_inv * m, 1.0e-5); - assert_approx_eq!(m_inv, trans_inv * rotz_inv * scale_inv, 1.0e-6); -} - -#[test] -fn test_mat4_decompose() { - // identity - let (out_scale, out_rotation, out_translation) = - Mat4::identity().to_scale_rotation_translation(); - assert_approx_eq!(Vec3::one(), out_scale); - assert!(out_rotation.is_near_identity()); - assert_approx_eq!(Vec3::zero(), out_translation); - - // no scale - let in_scale = Vec3::one(); - let in_translation = Vec3::new(-2.0, 4.0, -0.125); - let in_rotation = Quat::from_rotation_ypr( - f32::to_radians(-45.0), - f32::to_radians(180.0), - f32::to_radians(270.0), - ); - let in_mat = Mat4::from_scale_rotation_translation(in_scale, in_rotation, in_translation); - let (out_scale, out_rotation, out_translation) = in_mat.to_scale_rotation_translation(); - assert_approx_eq!(in_scale, out_scale, 1e-6); - // out_rotation is different but produces the same matrix - // assert_approx_eq!(in_rotation, out_rotation); - assert_approx_eq!(in_translation, out_translation); - assert_approx_eq!( - in_mat, - Mat4::from_scale_rotation_translation(out_scale, out_rotation, out_translation), - 1e-6 - ); - - // positive scale - let in_scale = Vec3::new(1.0, 2.0, 4.0); - let in_mat = Mat4::from_scale_rotation_translation(in_scale, in_rotation, in_translation); - let (out_scale, out_rotation, out_translation) = in_mat.to_scale_rotation_translation(); - assert_approx_eq!(in_scale, out_scale, 1e-6); - // out_rotation is different but produces the same matrix - // assert_approx_eq!(in_rotation, out_rotation); - assert_approx_eq!(in_translation, out_translation); - assert_approx_eq!( - in_mat, - Mat4::from_scale_rotation_translation(out_scale, out_rotation, out_translation), - 1e-6 - ); - - // negative scale - let in_scale = Vec3::new(-4.0, 1.0, 2.0); - let in_mat = Mat4::from_scale_rotation_translation(in_scale, in_rotation, in_translation); - let (out_scale, out_rotation, out_translation) = in_mat.to_scale_rotation_translation(); - assert_approx_eq!(in_scale, out_scale, 1e-6); - // out_rotation is different but produces the same matrix - // assert_approx_eq!(in_rotation, out_rotation); - assert_approx_eq!(in_translation, out_translation); - assert_approx_eq!( - in_mat, - Mat4::from_scale_rotation_translation(out_scale, out_rotation, out_translation), - 1e-5 - ); - - // negative scale - let in_scale = Vec3::new(4.0, -1.0, -2.0); - let in_mat = Mat4::from_scale_rotation_translation(in_scale, in_rotation, in_translation); - let (out_scale, out_rotation, out_translation) = in_mat.to_scale_rotation_translation(); - // out_scale and out_rotation are different but they produce the same matrix - // assert_approx_eq!(in_scale, out_scale, 1e-6); - // assert_approx_eq!(in_rotation, out_rotation); - assert_approx_eq!(in_translation, out_translation); - assert_approx_eq!( - in_mat, - Mat4::from_scale_rotation_translation(out_scale, out_rotation, out_translation), - 1e-6 - ); -} - -#[test] -fn test_mat4_look_at() { - 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 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)); -} - -#[test] -fn test_mat4_perspective_gl_rh() { - let projection = Mat4::perspective_rh_gl(f32::to_radians(90.0), 2.0, 5.0, 15.0); - - 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); - - 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); -} - -#[test] -fn test_mat4_perspective_lh() { - let projection = Mat4::perspective_lh(f32::to_radians(90.0), 2.0, 5.0, 15.0); - - 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); - - 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); -} - -#[test] -fn test_mat4_perspective_infinite_lh() { - let projection = Mat4::perspective_infinite_lh(f32::to_radians(90.0), 2.0, 5.0); - - 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); - - 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); -} - -#[test] -fn test_mat4_perspective_infinite_reverse_lh() { - let projection = Mat4::perspective_infinite_reverse_lh(f32::to_radians(90.0), 2.0, 5.0); - - 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); - - 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); -} - -#[test] -fn test_mat4_orthographic_gl_rh() { - let projection = Mat4::orthographic_rh_gl(-10.0, 10.0, -5.0, 5.0, 0.0, -10.0); - let original = Vec4::new(5.0, 5.0, -5.0, 1.0); - let projected = projection.mul_vec4(original); - assert_approx_eq!(projected, Vec4::new(0.5, 1.0, -2.0, 1.0)); -} - -#[test] -fn test_mat4_orthographic_rh() { - let projection = Mat4::orthographic_rh(-10.0, 10.0, -5.0, 5.0, -10.0, 10.0); - let original = Vec4::new(5.0, 5.0, -5.0, 1.0); - let projected = projection.mul_vec4(original); - assert_approx_eq!(projected, Vec4::new(0.5, 1.0, 0.75, 1.0)); - - let original = Vec4::new(5.0, 5.0, 5.0, 1.0); - let projected = projection.mul_vec4(original); - assert_approx_eq!(projected, Vec4::new(0.5, 1.0, 0.25, 1.0)); -} - -#[test] -fn test_mat4_orthographic_lh() { - let projection = Mat4::orthographic_lh(-10.0, 10.0, -5.0, 5.0, -10.0, 10.0); - let original = Vec4::new(5.0, 5.0, -5.0, 1.0); - let projected = projection.mul_vec4(original); - assert_approx_eq!(projected, Vec4::new(0.5, 1.0, 0.25, 1.0)); - - let original = Vec4::new(5.0, 5.0, 5.0, 1.0); - let projected = projection.mul_vec4(original); - assert_approx_eq!(projected, Vec4::new(0.5, 1.0, 0.75, 1.0)); -} - -#[test] -fn test_mat4_ops() { - let m0 = Mat4::from_cols_array_2d(&MATRIX); - let m0x2 = Mat4::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], - [26.0, 28.0, 30.0, 32.0], - ]); - assert_eq!(m0x2, m0 * 2.0); - assert_eq!(m0x2, 2.0 * m0); - assert_eq!(m0x2, m0 + m0); - assert_eq!(Mat4::zero(), m0 - m0); - assert_approx_eq!(m0, m0 * Mat4::identity()); - assert_approx_eq!(m0, Mat4::identity() * m0); -} - -#[test] -fn test_mat4_fmt() { - let a = Mat4::from_cols_array_2d(&MATRIX); - assert_eq!( - format!("{}", a), - "[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]]" - ); -} - -#[cfg(feature = "serde")] -#[test] -fn test_mat4_serde() { - let a = Mat4::from_cols( - vec4(1.0, 2.0, 3.0, 4.0), - vec4(5.0, 6.0, 7.0, 8.0), - vec4(9.0, 10.0, 11.0, 12.0), - vec4(13.0, 14.0, 15.0, 16.0), - ); - let serialized = serde_json::to_string(&a).unwrap(); - assert_eq!( - serialized, - "[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 deserialized = serde_json::from_str(&serialized).unwrap(); - assert_eq!(a, deserialized); - let deserialized = serde_json::from_str::("[]"); - assert!(deserialized.is_err()); - let deserialized = serde_json::from_str::("[1.0]"); - assert!(deserialized.is_err()); - let deserialized = serde_json::from_str::("[1.0,2.0]"); - assert!(deserialized.is_err()); - let deserialized = serde_json::from_str::("[1.0,2.0,3.0]"); - assert!(deserialized.is_err()); - let deserialized = serde_json::from_str::("[1.0,2.0,3.0,4.0,5.0]"); - assert!(deserialized.is_err()); - let deserialized = serde_json::from_str::("[[1.0,2.0,3.0],[4.0,5.0,6.0],[7.0,8.0,9.0]]"); - assert!(deserialized.is_err()); - let deserialized = serde_json::from_str::( - "[[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!(deserialized.is_err()); -} - -#[cfg(feature = "rand")] -#[test] -fn test_mat4_rand() { - use rand::{Rng, SeedableRng}; - use rand_xoshiro::Xoshiro256Plus; - let mut rng1 = Xoshiro256Plus::seed_from_u64(0); - let a = Mat4::from_cols_array(&rng1.gen::<[f32; 16]>()); - let mut rng2 = Xoshiro256Plus::seed_from_u64(0); - let b = rng2.gen::(); - assert_eq!(a, b); -} diff --git a/crates/bevy_glam/tests/quat.rs b/crates/bevy_glam/tests/quat.rs deleted file mode 100644 index def0accf2b..0000000000 --- a/crates/bevy_glam/tests/quat.rs +++ /dev/null @@ -1,284 +0,0 @@ -mod support; - -use glam::f32::{quat, Mat3, Mat4, Quat, Vec3, Vec4}; -use support::{deg, rad}; - -#[test] -fn test_quat_align() { - use std::mem; - assert_eq!(16, mem::size_of::()); - if cfg!(feature = "scalar-math") { - assert_eq!(4, mem::align_of::()); - } else { - assert_eq!(16, mem::align_of::()); - } -} - -#[test] -fn test_quat_rotation() { - let zero = deg(0.0); - let yaw = deg(30.0); - let pitch = deg(60.0); - let roll = deg(90.0); - let y0 = Quat::from_rotation_y(yaw); - assert!(y0.is_normalized()); - let (axis, angle) = y0.to_axis_angle(); - assert_approx_eq!(axis, Vec3::unit_y(), 1.0e-6); - assert_approx_eq!(angle, yaw); - let y1 = Quat::from_rotation_ypr(yaw, zero, zero); - assert_approx_eq!(y0, y1); - let y2 = Quat::from_axis_angle(Vec3::unit_y(), yaw); - assert_approx_eq!(y0, y2); - let y3 = Quat::from_rotation_mat3(&Mat3::from_rotation_y(yaw)); - assert_approx_eq!(y0, y3); - let y4 = Quat::from_rotation_mat3(&Mat3::from_quat(y0)); - assert_approx_eq!(y0, y4); - - let x0 = Quat::from_rotation_x(pitch); - assert!(x0.is_normalized()); - let (axis, angle) = x0.to_axis_angle(); - assert_approx_eq!(axis, Vec3::unit_x()); - assert_approx_eq!(angle, pitch); - let x1 = Quat::from_rotation_ypr(zero, pitch, zero); - assert_approx_eq!(x0, x1); - let x2 = Quat::from_axis_angle(Vec3::unit_x(), pitch); - assert_approx_eq!(x0, x2); - let x3 = Quat::from_rotation_mat4(&Mat4::from_rotation_x(deg(180.0))); - assert!(x3.is_normalized()); - assert_approx_eq!(Quat::from_rotation_x(deg(180.0)), x3); - - let z0 = Quat::from_rotation_z(roll); - assert!(z0.is_normalized()); - let (axis, angle) = z0.to_axis_angle(); - assert_approx_eq!(axis, Vec3::unit_z()); - assert_approx_eq!(angle, roll); - let z1 = Quat::from_rotation_ypr(zero, zero, roll); - assert_approx_eq!(z0, z1); - let z2 = Quat::from_axis_angle(Vec3::unit_z(), roll); - assert_approx_eq!(z0, z2); - let z3 = Quat::from_rotation_mat4(&Mat4::from_rotation_z(roll)); - assert_approx_eq!(z0, z3); - - let yx0 = y0 * x0; - assert!(yx0.is_normalized()); - let yx1 = Quat::from_rotation_ypr(yaw, pitch, zero); - assert_approx_eq!(yx0, yx1); - - let yxz0 = y0 * x0 * z0; - assert!(yxz0.is_normalized()); - let yxz1 = Quat::from_rotation_ypr(yaw, pitch, roll); - assert_approx_eq!(yxz0, yxz1); - - // use the conjugate of z0 to remove the rotation from yxz0 - let yx2 = yxz0 * z0.conjugate(); - assert_approx_eq!(yx0, yx2); - - let yxz2 = Quat::from_rotation_mat4(&Mat4::from_quat(yxz0)); - assert_approx_eq!(yxz0, yxz2); - - // if near identity, just returns x axis and 0 rotation - let (axis, angle) = Quat::identity().to_axis_angle(); - assert_eq!(axis, Vec3::unit_x()); - assert_eq!(angle, rad(0.0)); -} - -#[test] -fn test_quat_new() { - let ytheta = deg(45.0); - let q0 = Quat::from_rotation_y(ytheta); - - let t1 = (0.0, (ytheta * 0.5).sin(), 0.0, (ytheta * 0.5).cos()); - assert_eq!(q0, t1.into()); - let q1 = Quat::from(t1); - assert_eq!(t1, q1.into()); - - assert_eq!(q0, quat(t1.0, t1.1, t1.2, t1.3)); - - let a1 = [0.0, (ytheta * 0.5).sin(), 0.0, (ytheta * 0.5).cos()]; - assert_eq!(q0, a1.into()); - let q1 = Quat::from(a1); - let a2: [f32; 4] = q1.into(); - assert_eq!(a1, a2); -} - -#[test] -fn test_quat_mul_vec() { - let qrz = Quat::from_rotation_z(deg(90.0)); - assert_approx_eq!(Vec3::unit_y(), qrz * Vec3::unit_x()); - assert_approx_eq!(Vec3::unit_y(), -qrz * Vec3::unit_x()); - assert_approx_eq!(-Vec3::unit_x(), qrz * Vec3::unit_y()); - assert_approx_eq!(-Vec3::unit_x(), -qrz * Vec3::unit_y()); - - // check vec3 * mat3 is the same - let mrz = Mat3::from_quat(qrz); - assert_approx_eq!(Vec3::unit_y(), mrz * Vec3::unit_x()); - // assert_approx_eq!(Vec3::unit_y(), -mrz * Vec3::unit_x()); - assert_approx_eq!(-Vec3::unit_x(), mrz * Vec3::unit_y()); - - let qrx = Quat::from_rotation_x(deg(90.0)); - assert_approx_eq!(Vec3::unit_x(), qrx * Vec3::unit_x()); - assert_approx_eq!(Vec3::unit_x(), -qrx * Vec3::unit_x()); - assert_approx_eq!(Vec3::unit_z(), qrx * Vec3::unit_y()); - assert_approx_eq!(Vec3::unit_z(), -qrx * Vec3::unit_y()); - - // check vec3 * mat3 is the same - let mrx = Mat3::from_quat(qrx); - assert_approx_eq!(Vec3::unit_x(), mrx * Vec3::unit_x()); - assert_approx_eq!(Vec3::unit_z(), mrx * Vec3::unit_y()); - - let qrxz = qrz * qrx; - assert_approx_eq!(Vec3::unit_y(), qrxz * Vec3::unit_x()); - assert_approx_eq!(Vec3::unit_z(), qrxz * Vec3::unit_y()); - - let mrxz = mrz * mrx; - assert_approx_eq!(Vec3::unit_y(), mrxz * Vec3::unit_x()); - assert_approx_eq!(Vec3::unit_z(), mrxz * Vec3::unit_y()); - - let qrzx = qrx * qrz; - assert_approx_eq!(Vec3::unit_z(), qrzx * Vec3::unit_x()); - assert_approx_eq!(-Vec3::unit_x(), qrzx * Vec3::unit_y()); - - let mrzx = qrx * qrz; - assert_approx_eq!(Vec3::unit_z(), mrzx * Vec3::unit_x()); - assert_approx_eq!(-Vec3::unit_x(), mrzx * Vec3::unit_y()); -} - -#[test] -fn test_quat_funcs() { - let q0 = Quat::from_rotation_ypr(deg(45.0), deg(180.0), deg(90.0)); - assert!(q0.is_normalized()); - assert_approx_eq!(q0.length_squared(), 1.0); - assert_approx_eq!(q0.length(), 1.0); - assert_approx_eq!(q0.length_reciprocal(), 1.0); - assert_approx_eq!(q0, q0.normalize()); - - assert_approx_eq!(q0.dot(q0), 1.0); - assert_approx_eq!(q0.dot(q0), 1.0); - - let q1 = Quat::from(Vec4::from(q0) * 2.0); - assert!(!q1.is_normalized()); - assert_approx_eq!(q1.length_squared(), 4.0, 1.0e-6); - assert_approx_eq!(q1.length(), 2.0); - assert_approx_eq!(q1.length_reciprocal(), 0.5); - assert_approx_eq!(q0, q1.normalize()); - assert_approx_eq!(q0.dot(q1), 2.0, 1.0e-6); -} - -#[test] -fn test_quat_lerp() { - let q0 = Quat::from_rotation_y(deg(0.0)); - let q1 = Quat::from_rotation_y(deg(90.0)); - assert_approx_eq!(q0, q0.lerp(q1, 0.0)); - assert_approx_eq!(q1, q0.lerp(q1, 1.0)); - assert_approx_eq!(Quat::from_rotation_y(deg(45.0)), q0.lerp(q1, 0.5)); -} - -#[test] -fn test_quat_slerp() { - let q0 = Quat::from_rotation_y(deg(0.0)); - let q1 = Quat::from_rotation_y(deg(90.0)); - assert_approx_eq!(q0, q0.slerp(q1, 0.0), 1.0e-3); - assert_approx_eq!(q1, q0.slerp(q1, 1.0), 1.0e-3); - assert_approx_eq!(Quat::from_rotation_y(deg(45.0)), q0.slerp(q1, 0.5), 1.0e-3); -} - -#[test] -fn test_quat_slerp_constant_speed() { - let step = 0.01; - let mut s = 0.0; - 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 - ); - s += step; - } -} - -#[test] -fn test_quat_fmt() { - let a = Quat::identity(); - #[cfg(all(target_feature = "sse2", not(feature = "scalar-math")))] - assert_eq!(format!("{:?}", a), "Quat(__m128(0.0, 0.0, 0.0, 1.0))"); - #[cfg(any(not(target_feature = "sse2"), feature = "scalar-math"))] - assert_eq!(format!("{:?}", a), "Quat(0.0, 0.0, 0.0, 1.0)"); - // assert_eq!( - // format!("{:#?}", a), - // "Quat(\n 1.0,\n 2.0,\n 3.0,\n 4.0\n)" - // ); - assert_eq!(format!("{}", a), "[0, 0, 0, 1]"); -} - -#[test] -fn test_quat_identity() { - let identity = Quat::identity(); - assert!(identity.is_near_identity()); - assert!(identity.is_normalized()); - assert_eq!(identity, Quat::from_xyzw(0.0, 0.0, 0.0, 1.0)); - assert_eq!(identity, identity * identity); - let q = Quat::from_rotation_ypr(deg(10.0), deg(-10.0), deg(45.0)); - assert_eq!(q, q * identity); - assert_eq!(q, identity * q); - assert_eq!(identity, Quat::default()); -} - -#[test] -fn test_quat_slice() { - let a: [f32; 4] = Quat::from_rotation_ypr(deg(30.0), deg(60.0), deg(90.0)).into(); - let b = Quat::from_slice_unaligned(&a); - let c: [f32; 4] = b.into(); - assert_eq!(a, c); - let mut d = [0.0, 0.0, 0.0, 0.0]; - b.write_to_slice_unaligned(&mut d[..]); - assert_eq!(a, d); -} - -#[test] -fn test_quat_elements() { - let x = 1.0; - let y = 2.0; - let z = 3.0; - let w = 4.0; - - let a = Quat::from_xyzw(x, y, z, w); - assert!(a.x() == x); - assert!(a.y() == y); - assert!(a.z() == z); - assert!(a.w() == w); -} - -#[cfg(feature = "serde")] -#[test] -fn test_quat_serde() { - let a = Quat::from_xyzw(1.0, 2.0, 3.0, 4.0); - let serialized = serde_json::to_string(&a).unwrap(); - assert_eq!(serialized, "[1.0,2.0,3.0,4.0]"); - let deserialized = serde_json::from_str(&serialized).unwrap(); - assert_eq!(a, deserialized); - let deserialized = serde_json::from_str::("[]"); - assert!(deserialized.is_err()); - let deserialized = serde_json::from_str::("[1.0]"); - assert!(deserialized.is_err()); - let deserialized = serde_json::from_str::("[1.0,2.0]"); - assert!(deserialized.is_err()); - let deserialized = serde_json::from_str::("[1.0,2.0,3.0]"); - assert!(deserialized.is_err()); - let deserialized = serde_json::from_str::("[1.0,2.0,3.0,4.0,5.0]"); - assert!(deserialized.is_err()); -} - -#[cfg(feature = "rand")] -#[test] -fn test_quat_rand() { - use rand::{Rng, SeedableRng}; - use rand_xoshiro::Xoshiro256Plus; - let mut rng1 = Xoshiro256Plus::seed_from_u64(0); - let a: Quat = rng1.gen(); - assert!(a.is_normalized()); - let mut rng2 = Xoshiro256Plus::seed_from_u64(0); - let b: Quat = rng2.gen(); - assert_eq!(a, b); -} diff --git a/crates/bevy_glam/tests/support/macros.rs b/crates/bevy_glam/tests/support/macros.rs deleted file mode 100644 index 224b3f040f..0000000000 --- a/crates/bevy_glam/tests/support/macros.rs +++ /dev/null @@ -1,32 +0,0 @@ -#[macro_export] -macro_rules! assert_approx_eq { - ($a:expr, $b:expr) => {{ - #[allow(unused_imports)] - use support::FloatCompare; - let eps = core::f32::EPSILON; - let (a, b) = (&$a, &$b); - assert!( - a.approx_eq(b, eps), - "assertion failed: `(left !== right)` \ - (left: `{:?}`, right: `{:?}`, expect diff: `{:?}`, real diff: `{:?}`)", - *a, - *b, - eps, - a.abs_diff(b) - ); - }}; - ($a:expr, $b:expr, $eps:expr) => {{ - use support::FloatCompare; - let (a, b) = (&$a, &$b); - let eps = $eps; - assert!( - a.approx_eq(b, $eps), - "assertion failed: `(left !== right)` \ - (left: `{:?}`, right: `{:?}`, expect diff: `{:?}`, real diff: `{:?}`)", - *a, - *b, - eps, - a.abs_diff(b) - ); - }}; -} diff --git a/crates/bevy_glam/tests/support/mod.rs b/crates/bevy_glam/tests/support/mod.rs deleted file mode 100644 index 98bd080026..0000000000 --- a/crates/bevy_glam/tests/support/mod.rs +++ /dev/null @@ -1,166 +0,0 @@ -#[macro_use] -mod macros; - -use glam::{Mat2, Mat3, Mat4, Quat, Vec2, Vec3, Vec4}; - -#[cfg(feature = "transform-types")] -use glam::{TransformRT, TransformSRT}; - -/// Helper function for migrating away from `glam::angle::deg`. -#[allow(dead_code)] -#[inline] -pub fn deg(angle: f32) -> f32 { - angle.to_radians() -} - -/// Helper function for migrating away from `glam::angle::rad`. -#[allow(dead_code)] -#[inline] -pub fn rad(angle: f32) -> f32 { - angle -} - -/// Trait used by the `assert_approx_eq` macro for floating point comparisons. -pub trait FloatCompare { - /// Return true if the absolute difference between `self` and `other` is - /// less then or equal to `max_abs_diff`. - fn approx_eq(&self, other: &Rhs, max_abs_diff: f32) -> bool; - /// Returns the absolute difference of `self` and `other` which is printed - /// if `assert_approx_eq` fails. - fn abs_diff(&self, other: &Rhs) -> Rhs; -} - -impl FloatCompare for f32 { - #[inline] - fn approx_eq(&self, other: &f32, max_abs_diff: f32) -> bool { - (self - other).abs() <= max_abs_diff - } - #[inline] - fn abs_diff(&self, other: &f32) -> f32 { - (self - other).abs() - } -} - -impl FloatCompare for Mat2 { - #[inline] - fn approx_eq(&self, other: &Mat2, max_abs_diff: f32) -> bool { - self.abs_diff_eq(*other, max_abs_diff) - } - #[inline] - fn abs_diff(&self, other: &Mat2) -> Mat2 { - Mat2::from_cols( - (self.x_axis() - other.x_axis()).abs(), - (self.y_axis() - other.y_axis()).abs(), - ) - } -} - -impl FloatCompare for Mat3 { - #[inline] - fn approx_eq(&self, other: &Mat3, max_abs_diff: f32) -> bool { - self.abs_diff_eq(*other, max_abs_diff) - } - #[inline] - fn abs_diff(&self, other: &Mat3) -> Mat3 { - Mat3::from_cols( - (self.x_axis() - other.x_axis()).abs(), - (self.y_axis() - other.y_axis()).abs(), - (self.z_axis() - other.z_axis()).abs(), - ) - } -} - -impl FloatCompare for Mat4 { - #[inline] - fn approx_eq(&self, other: &Mat4, max_abs_diff: f32) -> bool { - self.abs_diff_eq(*other, max_abs_diff) - } - #[inline] - fn abs_diff(&self, other: &Mat4) -> Mat4 { - Mat4::from_cols( - (self.x_axis() - other.x_axis()).abs(), - (self.y_axis() - other.y_axis()).abs(), - (self.z_axis() - other.z_axis()).abs(), - (self.w_axis() - other.w_axis()).abs(), - ) - } -} - -impl FloatCompare for Quat { - #[inline] - fn approx_eq(&self, other: &Quat, max_abs_diff: f32) -> bool { - self.abs_diff_eq(*other, max_abs_diff) - } - #[inline] - fn abs_diff(&self, other: &Quat) -> Quat { - let a: Vec4 = (*self).into(); - let b: Vec4 = (*other).into(); - (a - b).abs().into() - } -} - -impl FloatCompare for Vec2 { - #[inline] - fn approx_eq(&self, other: &Vec2, max_abs_diff: f32) -> bool { - self.abs_diff_eq(*other, max_abs_diff) - } - #[inline] - fn abs_diff(&self, other: &Vec2) -> Vec2 { - (*self - *other).abs() - } -} - -impl FloatCompare for Vec3 { - #[inline] - fn approx_eq(&self, other: &Vec3, max_abs_diff: f32) -> bool { - self.abs_diff_eq(*other, max_abs_diff) - } - #[inline] - fn abs_diff(&self, other: &Vec3) -> Vec3 { - (*self - *other).abs() - } -} - -impl FloatCompare for Vec4 { - #[inline] - fn approx_eq(&self, other: &Vec4, max_abs_diff: f32) -> bool { - self.abs_diff_eq(*other, max_abs_diff) - } - #[inline] - fn abs_diff(&self, other: &Vec4) -> Vec4 { - (*self - *other).abs() - } -} - -#[cfg(feature = "transform-types")] -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), - ) - } -} - -#[cfg(feature = "transform-types")] -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), - ) - } -} diff --git a/crates/bevy_glam/tests/transform.rs b/crates/bevy_glam/tests/transform.rs deleted file mode 100644 index db08427b71..0000000000 --- a/crates/bevy_glam/tests/transform.rs +++ /dev/null @@ -1,88 +0,0 @@ -#[cfg(feature = "transform-types")] -#[macro_use] -mod support; - -#[cfg(feature = "transform-types")] -mod transform { - use super::support; - use glam::f32::*; - - #[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_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); - assert_eq!(srt, TransformSRT::from_transform_rt(s, &tr)); - } - - #[test] - fn test_mul() { - let tr = TransformRT::from_rotation_translation( - Quat::from_rotation_z(-90.0_f32.to_radians()), - Vec3::unit_x(), - ); - let v0 = Vec3::unit_y(); - let v1 = tr * v0; - assert_approx_eq!(v1, Vec3::unit_x() * 2.0); - assert_approx_eq!(v1, tr * v0); - let inv_tr = tr.inverse(); - let v2 = inv_tr * 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::unit_y(); - let srt = TransformSRT::from_scale_rotation_translation(s, r, t); - let v0 = Vec3::unit_x(); - let v1 = srt * v0; - assert_approx_eq!(v1, (r * (v0 * s)) + t); - assert_approx_eq!(v1, srt * v0); - let inv_srt = srt.inverse(); - let v2 = inv_srt * 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/crates/bevy_glam/tests/vec2.rs b/crates/bevy_glam/tests/vec2.rs deleted file mode 100644 index 24f67b7380..0000000000 --- a/crates/bevy_glam/tests/vec2.rs +++ /dev/null @@ -1,490 +0,0 @@ -mod support; - -use glam::*; -use std::f32; - -#[test] -fn test_vec2_align() { - use core::mem; - assert_eq!(8, mem::size_of::()); - assert_eq!(4, mem::align_of::()); - assert_eq!(8, mem::size_of::()); - assert_eq!(4, mem::align_of::()); -} - -#[test] -fn test_vec2_new() { - let v = vec2(1.0, 2.0); - - assert_eq!(v.x(), 1.0); - assert_eq!(v.y(), 2.0); - - let t = (1.0, 2.0); - let v = Vec2::from(t); - assert_eq!(t, v.into()); - - let a = [1.0, 2.0]; - let v = Vec2::from(a); - let a1: [f32; 2] = v.into(); - assert_eq!(a, a1); - - let v = Vec2::new(t.0, t.1); - assert_eq!(t, v.into()); - - assert_eq!(Vec2::new(1.0, 0.0), Vec2::unit_x()); - assert_eq!(Vec2::new(0.0, 1.0), Vec2::unit_y()); -} - -#[test] -fn test_vec2_fmt() { - let a = Vec2::new(1.0, 2.0); - assert_eq!(format!("{:?}", a), "Vec2(1.0, 2.0)"); - // assert_eq!(format!("{:#?}", a), "Vec2(\n 1.0,\n 2.0\n)"); - assert_eq!(format!("{}", a), "[1, 2]"); -} - -#[test] -fn test_vec2_zero() { - let v = Vec2::zero(); - assert_eq!(vec2(0.0, 0.0), v); - assert_eq!(v, Vec2::default()); -} - -#[test] -fn test_vec2_splat() { - let v = Vec2::splat(1.0); - assert_eq!(vec2(1.0, 1.0), v); -} - -#[test] -fn test_vec2_accessors() { - let mut a = Vec2::zero(); - a.set_x(1.0); - a.set_y(2.0); - assert_eq!(1.0, a.x()); - assert_eq!(2.0, a.y()); - assert_eq!(Vec2::new(1.0, 2.0), a); - - let mut a = Vec2::zero(); - *a.x_mut() = 1.0; - *a.y_mut() = 2.0; - assert_eq!(1.0, a.x()); - assert_eq!(2.0, a.y()); - assert_eq!(Vec2::new(1.0, 2.0), a); - - let mut a = Vec2::zero(); - a[0] = 1.0; - a[1] = 2.0; - assert_eq!(1.0, a[0]); - assert_eq!(2.0, a[1]); - assert_eq!(Vec2::new(1.0, 2.0), a); -} - -#[test] -fn test_vec2_funcs() { - let x = vec2(1.0, 0.0); - let y = vec2(0.0, 1.0); - assert_eq!(1.0, x.dot(x)); - assert_eq!(0.0, x.dot(y)); - assert_eq!(-1.0, x.dot(-x)); - assert_eq!(4.0, (2.0 * x).length_squared()); - assert_eq!(9.0, (-3.0 * y).length_squared()); - assert_eq!(2.0, (-2.0 * x).length()); - assert_eq!(3.0, (3.0 * y).length()); - assert_eq!(x, (2.0 * x).normalize()); - assert_eq!(1.0 * 3.0 + 2.0 * 4.0, vec2(1.0, 2.0).dot(vec2(3.0, 4.0))); - assert_eq!(2.0 * 2.0 + 3.0 * 3.0, vec2(2.0, 3.0).length_squared()); - assert_eq!((2.0_f32 * 2.0 + 3.0 * 3.0).sqrt(), vec2(2.0, 3.0).length()); - assert_eq!( - 1.0 / (2.0_f32 * 2.0 + 3.0 * 3.0).sqrt(), - vec2(2.0, 3.0).length_reciprocal() - ); - assert!(vec2(2.0, 3.0).normalize().is_normalized()); - assert_eq!( - vec2(2.0, 3.0) / (2.0_f32 * 2.0 + 3.0 * 3.0).sqrt(), - vec2(2.0, 3.0).normalize() - ); - assert_eq!(vec2(0.5, 0.25), vec2(2.0, 4.0).reciprocal()); -} - -#[test] -fn test_vec2_ops() { - let a = vec2(1.0, 2.0); - assert_eq!(vec2(2.0, 4.0), (a + a)); - assert_eq!(vec2(0.0, 0.0), (a - a)); - assert_eq!(vec2(1.0, 4.0), (a * a)); - assert_eq!(vec2(2.0, 4.0), (a * 2.0)); - assert_eq!(vec2(1.0, 1.0), (a / a)); - assert_eq!(vec2(0.5, 1.0), (a / 2.0)); - assert_eq!(vec2(-1.0, -2.0), (-a)); -} - -#[test] -fn test_vec2_assign_ops() { - let a = vec2(1.0, 2.0); - let mut b = a; - b += a; - assert_eq!(vec2(2.0, 4.0), b); - b -= a; - assert_eq!(vec2(1.0, 2.0), b); - b *= a; - assert_eq!(vec2(1.0, 4.0), b); - b /= a; - assert_eq!(vec2(1.0, 2.0), b); - b *= 2.0; - assert_eq!(vec2(2.0, 4.0), b); - b /= 2.0; - assert_eq!(vec2(1.0, 2.0), b); -} - -#[test] -fn test_vec2_min_max() { - let a = vec2(-1.0, 2.0); - let b = vec2(1.0, -2.0); - assert_eq!(vec2(-1.0, -2.0), a.min(b)); - assert_eq!(vec2(-1.0, -2.0), b.min(a)); - assert_eq!(vec2(1.0, 2.0), a.max(b)); - assert_eq!(vec2(1.0, 2.0), b.max(a)); -} - -#[test] -fn test_vec2_hmin_hmax() { - let a = vec2(-1.0, 2.0); - assert_eq!(-1.0, a.min_element()); - assert_eq!(2.0, a.max_element()); -} - -#[test] -fn test_vec2_eq() { - let a = vec2(1.0, 1.0); - let b = vec2(1.0, 2.0); - assert!(a.cmpeq(a).all()); - assert!(b.cmpeq(b).all()); - assert!(a.cmpne(b).any()); - assert!(b.cmpne(a).any()); - assert!(b.cmpeq(a).any()); -} - -#[test] -fn test_vec2_cmp() { - assert!(!Vec2Mask::default().any()); - assert!(!Vec2Mask::default().all()); - assert_eq!(Vec2Mask::default().bitmask(), 0x0); - let a = vec2(-1.0, -1.0); - let b = vec2(1.0, 1.0); - let c = vec2(-1.0, -1.0); - let d = vec2(1.0, -1.0); - assert_eq!(a.cmplt(a).bitmask(), 0x0); - assert_eq!(a.cmplt(b).bitmask(), 0x3); - assert_eq!(a.cmplt(d).bitmask(), 0x1); - assert_eq!(c.cmple(a).bitmask(), 0x3); - assert!(a.cmplt(b).all()); - assert!(a.cmplt(d).any()); - assert!(a.cmple(b).all()); - assert!(a.cmple(a).all()); - assert!(b.cmpgt(a).all()); - assert!(b.cmpge(a).all()); - assert!(b.cmpge(b).all()); - assert!(!(a.cmpge(d).all())); - assert!(c.cmple(c).all()); - assert!(c.cmpge(c).all()); - assert!(a == a); - assert!(a < b); - assert!(b > a); -} - -#[test] -fn test_extend_truncate() { - let a = vec2(1.0, 2.0); - let b = a.extend(3.0); - assert_eq!(vec3(1.0, 2.0, 3.0), b); -} - -#[test] -fn test_vec2b() { - // make sure the unused 'w' value doesn't break Vec2b behaviour - let a = Vec3::zero(); - let mut b = a.truncate(); - b.set_x(1.0); - b.set_y(1.0); - assert!(!b.cmpeq(Vec2::zero()).any()); - assert!(b.cmpeq(Vec2::splat(1.0)).all()); -} - -#[test] -fn test_vec2mask_as_ref() { - assert_eq!(Vec2Mask::new(false, false).as_ref(), &[0, 0]); - assert_eq!(Vec2Mask::new(true, false).as_ref(), &[!0, 0]); - assert_eq!(Vec2Mask::new(false, true).as_ref(), &[0, !0]); - assert_eq!(Vec2Mask::new(true, true).as_ref(), &[!0, !0]); -} - -#[test] -fn test_vec2mask_from() { - assert_eq!(Into::<[u32; 2]>::into(Vec2Mask::new(false, false)), [0, 0]); - assert_eq!(Into::<[u32; 2]>::into(Vec2Mask::new(true, false)), [!0, 0]); - assert_eq!(Into::<[u32; 2]>::into(Vec2Mask::new(false, true)), [0, !0]); - assert_eq!(Into::<[u32; 2]>::into(Vec2Mask::new(true, true)), [!0, !0]); -} - -#[test] -fn test_vec2mask_bitmask() { - assert_eq!(Vec2Mask::new(false, false).bitmask(), 0b00); - assert_eq!(Vec2Mask::new(true, false).bitmask(), 0b01); - assert_eq!(Vec2Mask::new(false, true).bitmask(), 0b10); - assert_eq!(Vec2Mask::new(true, true).bitmask(), 0b11); -} - -#[test] -fn test_vec2mask_any() { - assert_eq!(Vec2Mask::new(false, false).any(), false); - assert_eq!(Vec2Mask::new(true, false).any(), true); - assert_eq!(Vec2Mask::new(false, true).any(), true); - assert_eq!(Vec2Mask::new(true, true).any(), true); -} - -#[test] -fn test_vec2mask_all() { - assert_eq!(Vec2Mask::new(false, false).all(), false); - assert_eq!(Vec2Mask::new(true, false).all(), false); - assert_eq!(Vec2Mask::new(false, true).all(), false); - assert_eq!(Vec2Mask::new(true, true).all(), true); -} - -#[test] -fn test_vec2mask_select() { - let a = Vec2::new(1.0, 2.0); - let b = Vec2::new(3.0, 4.0); - assert_eq!(Vec2Mask::new(true, true).select(a, b), Vec2::new(1.0, 2.0),); - assert_eq!(Vec2Mask::new(true, false).select(a, b), Vec2::new(1.0, 4.0),); - assert_eq!(Vec2Mask::new(false, true).select(a, b), Vec2::new(3.0, 2.0),); - assert_eq!( - Vec2Mask::new(false, false).select(a, b), - Vec2::new(3.0, 4.0), - ); -} - -#[test] -fn test_vec2mask_and() { - assert_eq!( - (Vec2Mask::new(false, false) & Vec2Mask::new(false, false)).bitmask(), - 0b00, - ); - assert_eq!( - (Vec2Mask::new(true, true) & Vec2Mask::new(true, false)).bitmask(), - 0b01, - ); - assert_eq!( - (Vec2Mask::new(true, false) & Vec2Mask::new(false, true)).bitmask(), - 0b00, - ); - assert_eq!( - (Vec2Mask::new(true, true) & Vec2Mask::new(true, true)).bitmask(), - 0b11, - ); - - let mut mask = Vec2Mask::new(true, true); - mask &= Vec2Mask::new(true, false); - assert_eq!(mask.bitmask(), 0b01); -} - -#[test] -fn test_vec2mask_or() { - assert_eq!( - (Vec2Mask::new(false, false) | Vec2Mask::new(false, false)).bitmask(), - 0b00, - ); - assert_eq!( - (Vec2Mask::new(false, false) | Vec2Mask::new(false, true)).bitmask(), - 0b10, - ); - assert_eq!( - (Vec2Mask::new(true, false) | Vec2Mask::new(false, true)).bitmask(), - 0b11, - ); - assert_eq!( - (Vec2Mask::new(true, true) | Vec2Mask::new(true, true)).bitmask(), - 0b11, - ); - - let mut mask = Vec2Mask::new(true, true); - mask |= Vec2Mask::new(true, false); - assert_eq!(mask.bitmask(), 0b11); -} - -#[test] -fn test_vec2mask_not() { - assert_eq!((!Vec2Mask::new(false, false)).bitmask(), 0b11); - assert_eq!((!Vec2Mask::new(true, false)).bitmask(), 0b10); - assert_eq!((!Vec2Mask::new(false, true)).bitmask(), 0b01); - assert_eq!((!Vec2Mask::new(true, true)).bitmask(), 0b00); -} - -#[test] -fn test_vec2mask_fmt() { - let a = Vec2Mask::new(true, false); - - assert_eq!(format!("{:?}", a), "Vec2Mask(0xffffffff, 0x0)"); - assert_eq!(format!("{}", a), "[true, false]"); -} - -#[test] -fn test_vec2mask_eq() { - let a = Vec2Mask::new(true, false); - let b = Vec2Mask::new(true, false); - let c = Vec2Mask::new(false, true); - - assert_eq!(a, b); - assert_eq!(b, a); - assert_ne!(a, c); - assert_ne!(b, c); - - assert!(a > c); - assert!(c < a); -} - -#[test] -fn test_vec2mask_hash() { - use std::{ - collections::hash_map::DefaultHasher, - hash::{Hash, Hasher}, - }; - - let a = Vec2Mask::new(true, false); - let b = Vec2Mask::new(true, false); - let c = Vec2Mask::new(false, true); - - let mut hasher = DefaultHasher::new(); - a.hash(&mut hasher); - let a_hashed = hasher.finish(); - - let mut hasher = DefaultHasher::new(); - b.hash(&mut hasher); - let b_hashed = hasher.finish(); - - let mut hasher = DefaultHasher::new(); - c.hash(&mut hasher); - let c_hashed = hasher.finish(); - - assert_eq!(a, b); - assert_eq!(a_hashed, b_hashed); - assert_ne!(a, c); - assert_ne!(a_hashed, c_hashed); -} - -#[test] -fn test_vec2_sign() { - assert_eq!(Vec2::zero().sign(), Vec2::one()); - assert_eq!(-Vec2::zero().sign(), -Vec2::one()); - assert_eq!(Vec2::one().sign(), Vec2::one()); - assert_eq!((-Vec2::one()).sign(), -Vec2::one()); - assert_eq!(Vec2::splat(core::f32::NEG_INFINITY).sign(), -Vec2::one()); -} - -#[test] -fn test_vec2_abs() { - assert_eq!(Vec2::zero().abs(), Vec2::zero()); - assert_eq!(Vec2::one().abs(), Vec2::one()); - assert_eq!((-Vec2::one()).abs(), Vec2::one()); -} - -#[test] -fn test_vec2_round() { - assert_eq!(Vec2::new(1.35, 0.0).round().x(), 1.0); - assert_eq!(Vec2::new(0.0, 1.5).round().y(), 2.0); - assert_eq!(Vec2::new(0.0, -15.5).round().y(), -16.0); - assert_eq!(Vec2::new(0.0, 0.0).round().y(), 0.0); - assert_eq!(Vec2::new(0.0, 21.1).round().y(), 21.0); - assert_eq!(Vec2::new(0.0, 11.123).round().y(), 11.0); - assert_eq!(Vec2::new(0.0, 11.499).round().y(), 11.0); - assert_eq!( - Vec2::new(f32::NEG_INFINITY, f32::INFINITY).round(), - Vec2::new(f32::NEG_INFINITY, f32::INFINITY) - ); - assert!(Vec2::new(f32::NAN, 0.0).round().x().is_nan()); -} - -#[test] -fn test_vec2_floor() { - assert_eq!(Vec2::new(1.35, -1.5).floor(), Vec2::new(1.0, -2.0)); - assert_eq!( - Vec2::new(f32::INFINITY, f32::NEG_INFINITY).floor(), - Vec2::new(f32::INFINITY, f32::NEG_INFINITY) - ); - assert!(Vec2::new(f32::NAN, 0.0).floor().x().is_nan()); - assert_eq!( - Vec2::new(-2000000.123, 10000000.123).floor(), - Vec2::new(-2000001.0, 10000000.0) - ); -} - -#[test] -fn test_vec2_ceil() { - assert_eq!(Vec2::new(1.35, -1.5).ceil(), Vec2::new(2.0, -1.0)); - assert_eq!( - Vec2::new(f32::INFINITY, f32::NEG_INFINITY).ceil(), - Vec2::new(f32::INFINITY, f32::NEG_INFINITY) - ); - assert!(Vec2::new(f32::NAN, 0.0).ceil().x().is_nan()); - assert_eq!( - Vec2::new(-2000000.123, 1000000.123).ceil(), - Vec2::new(-2000000.0, 1000001.0) - ); -} - -#[test] -fn test_vec2_lerp() { - let v0 = Vec2::new(-1.0, -1.0); - let v1 = Vec2::new(1.0, 1.0); - assert_approx_eq!(v0, v0.lerp(v1, 0.0)); - assert_approx_eq!(v1, v0.lerp(v1, 1.0)); - assert_approx_eq!(Vec2::zero(), v0.lerp(v1, 0.5)); -} - -#[test] -fn test_vec2_to_from_slice() { - let v = Vec2::new(1.0, 2.0); - let mut a = [0.0, 0.0]; - v.write_to_slice_unaligned(&mut a); - assert_eq!(v, Vec2::from_slice_unaligned(&a)); -} - -#[test] -fn test_vec2_angle_between() { - let angle = Vec2::new(1.0, 0.0).angle_between(Vec2::new(0.0, 1.0)); - assert_approx_eq!(f32::consts::FRAC_PI_2, angle, 1e-6); - - let angle = Vec2::new(10.0, 0.0).angle_between(Vec2::new(0.0, 5.0)); - assert_approx_eq!(f32::consts::FRAC_PI_2, angle, 1e-6); - - let angle = Vec2::new(-1.0, 0.0).angle_between(Vec2::new(0.0, 1.0)); - assert_approx_eq!(-f32::consts::FRAC_PI_2, angle, 1e-6); -} - -#[cfg(feature = "serde")] -#[test] -fn test_vec2_serde() { - let a = Vec2::new(1.0, 2.0); - let serialized = serde_json::to_string(&a).unwrap(); - assert_eq!(serialized, "[1.0,2.0]"); - let deserialized = serde_json::from_str(&serialized).unwrap(); - assert_eq!(a, deserialized); - let deserialized = serde_json::from_str::("[]"); - assert!(deserialized.is_err()); - let deserialized = serde_json::from_str::("[1.0]"); - assert!(deserialized.is_err()); - let deserialized = serde_json::from_str::("[1.0,2.0,3.0]"); - assert!(deserialized.is_err()); -} - -#[cfg(feature = "rand")] -#[test] -fn test_vec2_rand() { - use rand::{Rng, SeedableRng}; - use rand_xoshiro::Xoshiro256Plus; - let mut rng1 = Xoshiro256Plus::seed_from_u64(0); - let a: (f32, f32) = rng1.gen(); - let mut rng2 = Xoshiro256Plus::seed_from_u64(0); - let b: Vec2 = rng2.gen(); - assert_eq!(a, b.into()); -} diff --git a/crates/bevy_glam/tests/vec3.rs b/crates/bevy_glam/tests/vec3.rs deleted file mode 100644 index 42d0770681..0000000000 --- a/crates/bevy_glam/tests/vec3.rs +++ /dev/null @@ -1,599 +0,0 @@ -mod support; - -use glam::*; -use std::f32; - -#[test] -fn test_vec3_align() { - use std::mem; - if cfg!(any(feature = "packed-vec3", feature = "scalar-math")) { - assert_eq!(12, mem::size_of::()); - assert_eq!(4, mem::align_of::()); - assert_eq!(12, mem::size_of::()); - assert_eq!(4, mem::align_of::()); - } else { - assert_eq!(16, mem::size_of::()); - assert_eq!(16, mem::align_of::()); - assert_eq!(16, mem::size_of::()); - assert_eq!(16, mem::align_of::()); - } -} - -#[test] -fn test_vec3_new() { - let v = vec3(1.0, 2.0, 3.0); - - assert_eq!(v.x(), 1.0); - assert_eq!(v.y(), 2.0); - assert_eq!(v.z(), 3.0); - - let t = (1.0, 2.0, 3.0); - let v = Vec3::from(t); - assert_eq!(t, v.into()); - - let a = [1.0, 2.0, 3.0]; - let v = Vec3::from(a); - let a1: [f32; 3] = v.into(); - assert_eq!(a, a1); - - let v = Vec3::new(t.0, t.1, t.2); - assert_eq!(t, v.into()); - - assert_eq!(Vec3::new(1.0, 0.0, 0.0), Vec3::unit_x()); - assert_eq!(Vec3::new(0.0, 1.0, 0.0), Vec3::unit_y()); - assert_eq!(Vec3::new(0.0, 0.0, 1.0), Vec3::unit_z()); -} - -#[test] -fn test_vec3_fmt() { - let a = Vec3::new(1.0, 2.0, 3.0); - #[cfg(all( - target_feature = "sse2", - not(feature = "packed-vec3"), - not(feature = "scalar-math") - ))] - assert_eq!(format!("{:?}", a), "Vec3(__m128(1.0, 2.0, 3.0, 3.0))"); - #[cfg(any( - not(target_feature = "sse2"), - feature = "packed-vec3", - feature = "scalar-math" - ))] - assert_eq!(format!("{:?}", a), "Vec3(1.0, 2.0, 3.0)"); - // assert_eq!(format!("{:#?}", a), "Vec3(\n 1.0,\n 2.0,\n 3.0\n)"); - assert_eq!(format!("{}", a), "[1, 2, 3]"); -} - -#[test] -fn test_vec3_zero() { - let v = Vec3::zero(); - assert_eq!((0.0, 0.0, 0.0), v.into()); - assert_eq!(v, Vec3::default()); -} - -#[test] -fn test_vec3_splat() { - let v = Vec3::splat(1.0); - assert_eq!((1.0, 1.0, 1.0), v.into()); -} - -#[test] -fn test_vec3_accessors() { - let mut a = Vec3::zero(); - a.set_x(1.0); - a.set_y(2.0); - a.set_z(3.0); - assert_eq!(1.0, a.x()); - assert_eq!(2.0, a.y()); - assert_eq!(3.0, a.z()); - assert_eq!((1.0, 2.0, 3.0), a.into()); - - let mut a = Vec3::zero(); - *a.x_mut() = 1.0; - *a.y_mut() = 2.0; - *a.z_mut() = 3.0; - assert_eq!(1.0, a.x()); - assert_eq!(2.0, a.y()); - assert_eq!(3.0, a.z()); - assert_eq!((1.0, 2.0, 3.0), a.into()); - - let mut a = Vec3::zero(); - a[0] = 1.0; - a[1] = 2.0; - a[2] = 3.0; - assert_eq!(1.0, a[0]); - assert_eq!(2.0, a[1]); - assert_eq!(3.0, a[2]); - assert_eq!((1.0, 2.0, 3.0), a.into()); -} - -#[test] -fn test_vec3_funcs() { - let x = vec3(1.0, 0.0, 0.0); - let y = vec3(0.0, 1.0, 0.0); - let z = vec3(0.0, 0.0, 1.0); - assert_eq!(1.0, x.dot(x)); - assert_eq!(0.0, x.dot(y)); - assert_eq!(-1.0, z.dot(-z)); - assert_eq!(y, z.cross(x)); - assert_eq!(z, x.cross(y)); - assert_eq!(4.0, (2.0 * x).length_squared()); - assert_eq!(9.0, (-3.0 * y).length_squared()); - assert_eq!(16.0, (4.0 * z).length_squared()); - assert_eq!(2.0, (-2.0 * x).length()); - assert_eq!(3.0, (3.0 * y).length()); - assert_eq!(4.0, (-4.0 * z).length()); - assert_eq!(x, (2.0 * x).normalize()); - assert_eq!( - 1.0 * 4.0 + 2.0 * 5.0 + 3.0 * 6.0, - vec3(1.0, 2.0, 3.0).dot(vec3(4.0, 5.0, 6.0)) - ); - assert_eq!( - 2.0 * 2.0 + 3.0 * 3.0 + 4.0 * 4.0, - vec3(2.0, 3.0, 4.0).length_squared() - ); - assert_eq!( - (2.0_f32 * 2.0 + 3.0 * 3.0 + 4.0 * 4.0).sqrt(), - vec3(2.0, 3.0, 4.0).length() - ); - assert_eq!( - 1.0 / (2.0_f32 * 2.0 + 3.0 * 3.0 + 4.0 * 4.0).sqrt(), - vec3(2.0, 3.0, 4.0).length_reciprocal() - ); - assert!(vec3(2.0, 3.0, 4.0).normalize().is_normalized()); - assert_approx_eq!( - vec3(2.0, 3.0, 4.0) / (2.0_f32 * 2.0 + 3.0 * 3.0 + 4.0 * 4.0).sqrt(), - vec3(2.0, 3.0, 4.0).normalize() - ); - assert_eq!(vec3(0.5, 0.25, 0.125), vec3(2.0, 4.0, 8.0).reciprocal()); -} - -#[test] -fn test_vec3_ops() { - let a = vec3(1.0, 2.0, 3.0); - assert_eq!((2.0, 4.0, 6.0), (a + a).into()); - assert_eq!((0.0, 0.0, 0.0), (a - a).into()); - assert_eq!((1.0, 4.0, 9.0), (a * a).into()); - assert_eq!((2.0, 4.0, 6.0), (a * 2.0).into()); - assert_eq!((1.0, 1.0, 1.0), (a / a).into()); - assert_eq!((0.5, 1.0, 1.5), (a / 2.0).into()); - assert_eq!((-1.0, -2.0, -3.0), (-a).into()); -} - -#[test] -fn test_vec3_assign_ops() { - let a = vec3(1.0, 2.0, 3.0); - let mut b = a; - b += a; - assert_eq!((2.0, 4.0, 6.0), b.into()); - b -= a; - assert_eq!((1.0, 2.0, 3.0), b.into()); - b *= a; - assert_eq!((1.0, 4.0, 9.0), b.into()); - b /= a; - assert_eq!((1.0, 2.0, 3.0), b.into()); - b *= 2.0; - assert_eq!((2.0, 4.0, 6.0), b.into()); - b /= 2.0; - assert_eq!((1.0, 2.0, 3.0), b.into()); -} - -#[test] -fn test_vec3_min_max() { - let a = vec3(-1.0, 2.0, -3.0); - let b = vec3(1.0, -2.0, 3.0); - assert_eq!((-1.0, -2.0, -3.0), a.min(b).into()); - assert_eq!((-1.0, -2.0, -3.0), b.min(a).into()); - assert_eq!((1.0, 2.0, 3.0), a.max(b).into()); - assert_eq!((1.0, 2.0, 3.0), b.max(a).into()); -} - -#[test] -fn test_vec3_hmin_hmax() { - let a = vec3(-1.0, 2.0, -3.0); - assert_eq!(-3.0, a.min_element()); - assert_eq!(2.0, a.max_element()); -} - -#[test] -fn test_vec3_eq() { - let a = vec3(1.0, 1.0, 1.0); - let b = vec3(1.0, 2.0, 3.0); - assert!(a.cmpeq(a).all()); - assert!(b.cmpeq(b).all()); - assert!(a.cmpne(b).any()); - assert!(b.cmpne(a).any()); - assert!(b.cmpeq(a).any()); -} - -#[test] -fn test_vec3_cmp() { - assert!(!Vec3Mask::default().any()); - assert!(!Vec3Mask::default().all()); - assert_eq!(Vec3Mask::default().bitmask(), 0x0); - let a = vec3(-1.0, -1.0, -1.0); - let b = vec3(1.0, 1.0, 1.0); - let c = vec3(-1.0, -1.0, 1.0); - let d = vec3(1.0, -1.0, -1.0); - assert_eq!(a.cmplt(a).bitmask(), 0x0); - assert_eq!(a.cmplt(b).bitmask(), 0x7); - assert_eq!(a.cmplt(c).bitmask(), 0x4); - assert_eq!(c.cmple(a).bitmask(), 0x3); - assert_eq!(a.cmplt(d).bitmask(), 0x1); - assert!(a.cmplt(b).all()); - assert!(a.cmplt(c).any()); - assert!(a.cmple(b).all()); - assert!(a.cmple(a).all()); - assert!(b.cmpgt(a).all()); - assert!(b.cmpge(a).all()); - assert!(b.cmpge(b).all()); - assert!(!(a.cmpge(c).all())); - assert!(c.cmple(c).all()); - assert!(c.cmpge(c).all()); - assert!(a == a); - assert!(a < b); - assert!(b > a); -} - -#[test] -fn test_extend_truncate() { - let a = vec3(1.0, 2.0, 3.0); - let b = a.extend(4.0); - assert_eq!((1.0, 2.0, 3.0, 4.0), b.into()); - let c = b.truncate(); - assert_eq!(a, c); -} - -#[test] -fn test_vec3b() { - // make sure the unused 'w' value doesn't break Vec3b behaviour - let a = Vec4::zero(); - let mut b = a.truncate(); - b.set_x(1.0); - b.set_y(1.0); - b.set_z(1.0); - assert!(!b.cmpeq(Vec3::zero()).any()); - assert!(b.cmpeq(Vec3::splat(1.0)).all()); -} - -#[test] -fn test_vec3mask_as_ref() { - assert_eq!(Vec3Mask::new(false, false, false).as_ref(), &[0, 0, 0]); - assert_eq!(Vec3Mask::new(true, false, false).as_ref(), &[!0, 0, 0]); - assert_eq!(Vec3Mask::new(false, true, true).as_ref(), &[0, !0, !0]); - assert_eq!(Vec3Mask::new(false, true, false).as_ref(), &[0, !0, 0]); - assert_eq!(Vec3Mask::new(true, false, true).as_ref(), &[!0, 0, !0]); - assert_eq!(Vec3Mask::new(true, true, true).as_ref(), &[!0, !0, !0]); -} - -#[test] -fn test_vec3mask_from() { - assert_eq!( - Into::<[u32; 3]>::into(Vec3Mask::new(false, false, false)), - [0, 0, 0] - ); - assert_eq!( - Into::<[u32; 3]>::into(Vec3Mask::new(true, false, false)), - [!0, 0, 0] - ); - assert_eq!( - Into::<[u32; 3]>::into(Vec3Mask::new(false, true, true)), - [0, !0, !0] - ); - assert_eq!( - Into::<[u32; 3]>::into(Vec3Mask::new(false, true, false)), - [0, !0, 0] - ); - assert_eq!( - Into::<[u32; 3]>::into(Vec3Mask::new(true, false, true)), - [!0, 0, !0] - ); - assert_eq!( - Into::<[u32; 3]>::into(Vec3Mask::new(true, true, true)), - [!0, !0, !0] - ); -} - -#[test] -fn test_vec3mask_bitmask() { - assert_eq!(Vec3Mask::new(false, false, false).bitmask(), 0b000); - assert_eq!(Vec3Mask::new(true, false, false).bitmask(), 0b001); - assert_eq!(Vec3Mask::new(false, true, true).bitmask(), 0b110); - assert_eq!(Vec3Mask::new(false, true, false).bitmask(), 0b010); - assert_eq!(Vec3Mask::new(true, false, true).bitmask(), 0b101); - assert_eq!(Vec3Mask::new(true, true, true).bitmask(), 0b111); -} - -#[test] -fn test_vec3mask_any() { - assert_eq!(Vec3Mask::new(false, false, false).any(), false); - assert_eq!(Vec3Mask::new(true, false, false).any(), true); - assert_eq!(Vec3Mask::new(false, true, false).any(), true); - assert_eq!(Vec3Mask::new(false, false, true).any(), true); -} - -#[test] -fn test_vec3mask_all() { - assert_eq!(Vec3Mask::new(true, true, true).all(), true); - assert_eq!(Vec3Mask::new(false, true, true).all(), false); - assert_eq!(Vec3Mask::new(true, false, true).all(), false); - assert_eq!(Vec3Mask::new(true, true, false).all(), false); -} - -#[test] -fn test_vec3mask_select() { - let a = Vec3::new(1.0, 2.0, 3.0); - let b = Vec3::new(4.0, 5.0, 6.0); - assert_eq!( - Vec3Mask::new(true, true, true).select(a, b), - Vec3::new(1.0, 2.0, 3.0), - ); - assert_eq!( - Vec3Mask::new(true, false, true).select(a, b), - Vec3::new(1.0, 5.0, 3.0), - ); - assert_eq!( - Vec3Mask::new(false, true, false).select(a, b), - Vec3::new(4.0, 2.0, 6.0), - ); - assert_eq!( - Vec3Mask::new(false, false, false).select(a, b), - Vec3::new(4.0, 5.0, 6.0), - ); -} - -#[test] -fn test_vec3mask_and() { - assert_eq!( - (Vec3Mask::new(false, false, false) & Vec3Mask::new(false, false, false)).bitmask(), - 0b000, - ); - assert_eq!( - (Vec3Mask::new(true, true, true) & Vec3Mask::new(true, true, true)).bitmask(), - 0b111, - ); - assert_eq!( - (Vec3Mask::new(true, false, true) & Vec3Mask::new(false, true, false)).bitmask(), - 0b000, - ); - assert_eq!( - (Vec3Mask::new(true, false, true) & Vec3Mask::new(true, true, true)).bitmask(), - 0b101, - ); - - let mut mask = Vec3Mask::new(true, true, false); - mask &= Vec3Mask::new(true, false, false); - assert_eq!(mask.bitmask(), 0b001); -} - -#[test] -fn test_vec3mask_or() { - assert_eq!( - (Vec3Mask::new(false, false, false) | Vec3Mask::new(false, false, false)).bitmask(), - 0b000, - ); - assert_eq!( - (Vec3Mask::new(true, true, true) | Vec3Mask::new(true, true, true)).bitmask(), - 0b111, - ); - assert_eq!( - (Vec3Mask::new(true, false, true) | Vec3Mask::new(false, true, false)).bitmask(), - 0b111, - ); - assert_eq!( - (Vec3Mask::new(true, false, true) | Vec3Mask::new(true, false, true)).bitmask(), - 0b101, - ); - - let mut mask = Vec3Mask::new(true, true, false); - mask |= Vec3Mask::new(true, false, false); - assert_eq!(mask.bitmask(), 0b011); -} - -#[test] -fn test_vec3mask_not() { - assert_eq!((!Vec3Mask::new(false, false, false)).bitmask(), 0b111); - assert_eq!((!Vec3Mask::new(true, true, true)).bitmask(), 0b000); - assert_eq!((!Vec3Mask::new(true, false, true)).bitmask(), 0b010); - assert_eq!((!Vec3Mask::new(false, true, false)).bitmask(), 0b101); -} - -#[test] -fn test_vec3mask_fmt() { - let a = Vec3Mask::new(true, false, false); - - // debug fmt - #[cfg(all( - target_feature = "sse2", - not(feature = "packed-vec3"), - not(feature = "scalar-math") - ))] - assert_eq!(format!("{:?}", a), "Vec3Mask(0xffffffff, 0x0, 0x0)"); - - #[cfg(any( - not(target_feature = "sse2"), - feature = "packed-vec3", - feature = "scalar-math" - ))] - assert_eq!(format!("{:?}", a), "Vec3Mask(0xffffffff, 0x0, 0x0)"); - - // display fmt - #[cfg(all( - target_feature = "sse2", - not(feature = "packed-vec3"), - not(feature = "scalar-math") - ))] - assert_eq!(format!("{}", a), "[true, false, false]"); - - #[cfg(any( - not(target_feature = "sse2"), - feature = "packed-vec3", - feature = "scalar-math" - ))] - assert_eq!(format!("{}", a), "[true, false, false]"); -} - -#[test] -fn test_vec3mask_eq() { - let a = Vec3Mask::new(true, false, true); - let b = Vec3Mask::new(true, false, true); - let c = Vec3Mask::new(false, true, true); - - assert_eq!(a, b); - assert_eq!(b, a); - assert_ne!(a, c); - assert_ne!(b, c); - - assert!(a > c); - assert!(c < a); -} - -#[test] -fn test_vec3mask_hash() { - use std::{ - collections::hash_map::DefaultHasher, - hash::{Hash, Hasher}, - }; - - let a = Vec3Mask::new(true, false, true); - let b = Vec3Mask::new(true, false, true); - let c = Vec3Mask::new(false, true, true); - - let mut hasher = DefaultHasher::new(); - a.hash(&mut hasher); - let a_hashed = hasher.finish(); - - let mut hasher = DefaultHasher::new(); - b.hash(&mut hasher); - let b_hashed = hasher.finish(); - - let mut hasher = DefaultHasher::new(); - c.hash(&mut hasher); - let c_hashed = hasher.finish(); - - assert_eq!(a, b); - assert_eq!(a_hashed, b_hashed); - assert_ne!(a, c); - assert_ne!(a_hashed, c_hashed); -} - -#[test] -fn test_vec3_sign() { - assert_eq!(Vec3::zero().sign(), Vec3::one()); - assert_eq!(-Vec3::zero().sign(), -Vec3::one()); - assert_eq!(Vec3::one().sign(), Vec3::one()); - assert_eq!((-Vec3::one()).sign(), -Vec3::one()); - assert_eq!(Vec3::splat(core::f32::NEG_INFINITY).sign(), -Vec3::one()); -} - -#[test] -fn test_vec3_abs() { - assert_eq!(Vec3::zero().abs(), Vec3::zero()); - assert_eq!(Vec3::one().abs(), Vec3::one()); - assert_eq!((-Vec3::one()).abs(), Vec3::one()); -} - -#[test] -fn test_vec3_round() { - assert_eq!(Vec3::new(1.35, 0.0, 0.0).round().x(), 1.0); - assert_eq!(Vec3::new(0.0, 1.5, 0.0).round().y(), 2.0); - assert_eq!(Vec3::new(0.0, 0.0, -15.5).round().z(), -16.0); - assert_eq!(Vec3::new(0.0, 0.0, 0.0).round().z(), 0.0); - assert_eq!(Vec3::new(0.0, 21.1, 0.0).round().y(), 21.0); - assert_eq!(Vec3::new(0.0, 11.123, 0.0).round().y(), 11.0); - assert_eq!(Vec3::new(0.0, 11.499, 0.0).round().y(), 11.0); - assert_eq!( - Vec3::new(f32::NEG_INFINITY, f32::INFINITY, 0.0).round(), - Vec3::new(f32::NEG_INFINITY, f32::INFINITY, 0.0) - ); - assert!(Vec3::new(f32::NAN, 0.0, 0.0).round().x().is_nan()); -} - -#[test] -fn test_vec3_floor() { - assert_eq!( - Vec3::new(1.35, 1.5, -1.5).floor(), - Vec3::new(1.0, 1.0, -2.0) - ); - assert_eq!( - Vec3::new(f32::INFINITY, f32::NEG_INFINITY, 0.0).floor(), - Vec3::new(f32::INFINITY, f32::NEG_INFINITY, 0.0) - ); - assert!(Vec3::new(f32::NAN, 0.0, 0.0).floor().x().is_nan()); - assert_eq!( - Vec3::new(-2000000.123, 10000000.123, 1000.9).floor(), - Vec3::new(-2000001.0, 10000000.0, 1000.0) - ); -} - -#[test] -fn test_vec3_ceil() { - assert_eq!(Vec3::new(1.35, 1.5, -1.5).ceil(), Vec3::new(2.0, 2.0, -1.0)); - assert_eq!( - Vec3::new(f32::INFINITY, f32::NEG_INFINITY, 0.0).ceil(), - Vec3::new(f32::INFINITY, f32::NEG_INFINITY, 0.0) - ); - assert!(Vec3::new(f32::NAN, 0.0, 0.0).ceil().x().is_nan()); - assert_eq!( - Vec3::new(-2000000.123, 1000000.123, 1000.9).ceil(), - Vec3::new(-2000000.0, 1000001.0, 1001.0) - ); -} - -#[test] -fn test_vec3_lerp() { - let v0 = Vec3::new(-1.0, -1.0, -1.0); - let v1 = Vec3::new(1.0, 1.0, 1.0); - assert_approx_eq!(v0, v0.lerp(v1, 0.0)); - assert_approx_eq!(v1, v0.lerp(v1, 1.0)); - assert_approx_eq!(Vec3::zero(), v0.lerp(v1, 0.5)); -} - -#[test] -fn test_vec3_to_from_slice() { - let v = Vec3::new(1.0, 2.0, 3.0); - let mut a = [0.0, 0.0, 0.0]; - v.write_to_slice_unaligned(&mut a); - assert_eq!(v, Vec3::from_slice_unaligned(&a)); -} - -#[test] -fn test_vec3_angle_between() { - let angle = Vec3::new(1.0, 0.0, 1.0).angle_between(Vec3::new(1.0, 1.0, 0.0)); - assert_approx_eq!(f32::consts::FRAC_PI_3, angle, 1e-6); - - let angle = Vec3::new(10.0, 0.0, 10.0).angle_between(Vec3::new(5.0, 5.0, 0.0)); - assert_approx_eq!(f32::consts::FRAC_PI_3, angle, 1e-6); - - let angle = Vec3::new(-1.0, 0.0, -1.0).angle_between(Vec3::new(1.0, -1.0, 0.0)); - assert_approx_eq!(2.0 * f32::consts::FRAC_PI_3, angle, 1e-6); -} - -#[cfg(feature = "serde")] -#[test] -fn test_vec3_serde() { - let a = Vec3::new(1.0, 2.0, 3.0); - let serialized = serde_json::to_string(&a).unwrap(); - assert_eq!(serialized, "[1.0,2.0,3.0]"); - let deserialized = serde_json::from_str(&serialized).unwrap(); - assert_eq!(a, deserialized); - let deserialized = serde_json::from_str::("[]"); - assert!(deserialized.is_err()); - let deserialized = serde_json::from_str::("[1.0]"); - assert!(deserialized.is_err()); - let deserialized = serde_json::from_str::("[1.0,2.0]"); - assert!(deserialized.is_err()); - let deserialized = serde_json::from_str::("[1.0,2.0,3.0,4.0]"); - assert!(deserialized.is_err()); -} - -#[cfg(feature = "rand")] -#[test] -fn test_vec3_rand() { - use rand::{Rng, SeedableRng}; - use rand_xoshiro::Xoshiro256Plus; - let mut rng1 = Xoshiro256Plus::seed_from_u64(0); - let a: (f32, f32, f32) = rng1.gen(); - let mut rng2 = Xoshiro256Plus::seed_from_u64(0); - let b: Vec3 = rng2.gen(); - assert_eq!(a, b.into()); -} diff --git a/crates/bevy_glam/tests/vec4.rs b/crates/bevy_glam/tests/vec4.rs deleted file mode 100644 index 5b90a59787..0000000000 --- a/crates/bevy_glam/tests/vec4.rs +++ /dev/null @@ -1,621 +0,0 @@ -mod support; - -use glam::*; -use std::f32; - -#[test] -fn test_vec4_align() { - use std::mem; - assert_eq!(16, mem::size_of::()); - assert_eq!(16, mem::size_of::()); - if cfg!(feature = "scalar-math") { - assert_eq!(4, mem::align_of::()); - assert_eq!(4, mem::align_of::()); - } else { - assert_eq!(16, mem::align_of::()); - assert_eq!(16, mem::align_of::()); - } -} - -#[test] -fn test_vec4_new() { - let v = vec4(1.0, 2.0, 3.0, 4.0); - - assert_eq!(v.x(), 1.0); - assert_eq!(v.y(), 2.0); - assert_eq!(v.z(), 3.0); - assert_eq!(v.w(), 4.0); - - let t = (1.0, 2.0, 3.0, 4.0); - let v = Vec4::from(t); - assert_eq!(t, v.into()); - - let a = [1.0, 2.0, 3.0, 4.0]; - let v = Vec4::from(a); - let a1: [f32; 4] = v.into(); - assert_eq!(a, a1); - - let v = Vec4::new(t.0, t.1, t.2, t.3); - assert_eq!(t, v.into()); - - assert_eq!(Vec4::new(1.0, 0.0, 0.0, 0.0), Vec4::unit_x()); - assert_eq!(Vec4::new(0.0, 1.0, 0.0, 0.0), Vec4::unit_y()); - assert_eq!(Vec4::new(0.0, 0.0, 1.0, 0.0), Vec4::unit_z()); - assert_eq!(Vec4::new(0.0, 0.0, 0.0, 1.0), Vec4::unit_w()); -} - -#[test] -fn test_vec4_fmt() { - let a = Vec4::new(1.0, 2.0, 3.0, 4.0); - #[cfg(all(target_feature = "sse2", not(feature = "scalar-math")))] - assert_eq!(format!("{:?}", a), "Vec4(__m128(1.0, 2.0, 3.0, 4.0))"); - #[cfg(any(not(target_feature = "sse2"), feature = "scalar-math"))] - assert_eq!(format!("{:?}", a), "Vec4(1.0, 2.0, 3.0, 4.0)"); - // assert_eq!( - // format!("{:#?}", a), - // "Vec4(\n 1.0,\n 2.0,\n 3.0,\n 4.0\n)" - // ); - assert_eq!(format!("{}", a), "[1, 2, 3, 4]"); -} - -#[test] -fn test_vec4_zero() { - let v = Vec4::zero(); - assert_eq!((0.0, 0.0, 0.0, 0.0), v.into()); - assert_eq!(v, Vec4::default()); -} - -#[test] -fn test_vec4_splat() { - let v = Vec4::splat(1.0); - assert_eq!((1.0, 1.0, 1.0, 1.0), v.into()); -} - -#[test] -fn test_vec4_accessors() { - let mut a = Vec4::zero(); - a.set_x(1.0); - a.set_y(2.0); - a.set_z(3.0); - a.set_w(4.0); - assert_eq!(1.0, a.x()); - assert_eq!(2.0, a.y()); - assert_eq!(3.0, a.z()); - assert_eq!(4.0, a.w()); - assert_eq!((1.0, 2.0, 3.0, 4.0), a.into()); - - let mut a = Vec4::zero(); - *a.x_mut() = 1.0; - *a.y_mut() = 2.0; - *a.z_mut() = 3.0; - *a.w_mut() = 4.0; - assert_eq!(1.0, a.x()); - assert_eq!(2.0, a.y()); - assert_eq!(3.0, a.z()); - assert_eq!(4.0, a.w()); - assert_eq!((1.0, 2.0, 3.0, 4.0), a.into()); - - let mut a = Vec4::zero(); - a[0] = 1.0; - a[1] = 2.0; - a[2] = 3.0; - a[3] = 4.0; - assert_eq!(1.0, a[0]); - assert_eq!(2.0, a[1]); - assert_eq!(3.0, a[2]); - assert_eq!(4.0, a[3]); - assert_eq!((1.0, 2.0, 3.0, 4.0), a.into()); -} - -#[test] -fn test_vec4_funcs() { - let x = vec4(1.0, 0.0, 0.0, 0.0); - let y = vec4(0.0, 1.0, 0.0, 0.0); - let z = vec4(0.0, 0.0, 1.0, 0.0); - let w = vec4(0.0, 0.0, 0.0, 1.0); - assert_eq!(1.0, x.dot(x)); - assert_eq!(0.0, x.dot(y)); - assert_eq!(-1.0, z.dot(-z)); - assert_eq!(4.0, (2.0 * x).length_squared()); - assert_eq!(9.0, (-3.0 * y).length_squared()); - assert_eq!(16.0, (4.0 * z).length_squared()); - assert_eq!(64.0, (8.0 * w).length_squared()); - assert_eq!(2.0, (-2.0 * x).length()); - assert_eq!(3.0, (3.0 * y).length()); - assert_eq!(4.0, (-4.0 * z).length()); - assert_eq!(5.0, (-5.0 * w).length()); - assert_eq!(x, (2.0 * x).normalize()); - assert_eq!( - 1.0 * 5.0 + 2.0 * 6.0 + 3.0 * 7.0 + 4.0 * 8.0, - vec4(1.0, 2.0, 3.0, 4.0).dot(vec4(5.0, 6.0, 7.0, 8.0)) - ); - assert_eq!( - 2.0 * 2.0 + 3.0 * 3.0 + 4.0 * 4.0 + 5.0 * 5.0, - vec4(2.0, 3.0, 4.0, 5.0).length_squared() - ); - assert_eq!( - (2.0_f32 * 2.0 + 3.0 * 3.0 + 4.0 * 4.0 + 5.0 * 5.0).sqrt(), - vec4(2.0, 3.0, 4.0, 5.0).length() - ); - assert_eq!( - 1.0 / (2.0_f32 * 2.0 + 3.0 * 3.0 + 4.0 * 4.0 + 5.0 * 5.0).sqrt(), - vec4(2.0, 3.0, 4.0, 5.0).length_reciprocal() - ); - assert!(vec4(2.0, 3.0, 4.0, 5.0).normalize().is_normalized()); - assert_approx_eq!( - vec4(2.0, 3.0, 4.0, 5.0) / (2.0_f32 * 2.0 + 3.0 * 3.0 + 4.0 * 4.0 + 5.0 * 5.0).sqrt(), - vec4(2.0, 3.0, 4.0, 5.0).normalize() - ); - assert_eq!( - vec4(0.5, 0.25, 0.125, 0.0625), - vec4(2.0, 4.0, 8.0, 16.0).reciprocal() - ); -} - -#[test] -fn test_vec4_ops() { - let a = vec4(1.0, 2.0, 3.0, 4.0); - assert_eq!((2.0, 4.0, 6.0, 8.0), (a + a).into()); - assert_eq!((0.0, 0.0, 0.0, 0.0), (a - a).into()); - assert_eq!((1.0, 4.0, 9.0, 16.0), (a * a).into()); - assert_eq!((2.0, 4.0, 6.0, 8.0), (a * 2.0).into()); - assert_eq!((2.0, 4.0, 6.0, 8.0), (2.0 * a).into()); - assert_eq!((1.0, 1.0, 1.0, 1.0), (a / a).into()); - assert_eq!((0.5, 1.0, 1.5, 2.0), (a / 2.0).into()); - // is this a sensible operator? - // assert_eq!((1.0, 0.5, 1.0/3.0, 0.25), (1.0 / a).into()); - assert_eq!((-1.0, -2.0, -3.0, -4.0), (-a).into()); -} - -#[test] -fn test_vec4_assign_ops() { - let a = vec4(1.0, 2.0, 3.0, 4.0); - let mut b = a; - b += a; - assert_eq!((2.0, 4.0, 6.0, 8.0), b.into()); - b -= a; - assert_eq!((1.0, 2.0, 3.0, 4.0), b.into()); - b *= a; - assert_eq!((1.0, 4.0, 9.0, 16.0), b.into()); - b /= a; - assert_eq!((1.0, 2.0, 3.0, 4.0), b.into()); - b *= 2.0; - assert_eq!((2.0, 4.0, 6.0, 8.0), b.into()); - b /= 2.0; - assert_eq!((1.0, 2.0, 3.0, 4.0), b.into()); -} - -#[test] -fn test_vec4_min_max() { - let a = vec4(-1.0, 2.0, -3.0, 4.0); - let b = vec4(1.0, -2.0, 3.0, -4.0); - assert_eq!((-1.0, -2.0, -3.0, -4.0), a.min(b).into()); - assert_eq!((-1.0, -2.0, -3.0, -4.0), b.min(a).into()); - assert_eq!((1.0, 2.0, 3.0, 4.0), a.max(b).into()); - assert_eq!((1.0, 2.0, 3.0, 4.0), b.max(a).into()); -} - -#[test] -fn test_vec4_hmin_hmax() { - let a = vec4(-1.0, 4.0, -3.0, 2.0); - assert_eq!(-3.0, a.min_element()); - assert_eq!(4.0, a.max_element()); - assert_eq!(3.0, vec4(1.0, 2.0, 3.0, 4.0).truncate().max_element()); - assert_eq!(-3.0, vec4(-1.0, -2.0, -3.0, -4.0).truncate().min_element()); -} - -#[test] -fn test_vec4_eq() { - let a = vec4(1.0, 1.0, 1.0, 1.0); - let b = vec4(1.0, 2.0, 3.0, 4.0); - assert!(a.cmpeq(a).all()); - assert!(b.cmpeq(b).all()); - assert!(a.cmpne(b).any()); - assert!(b.cmpne(a).any()); - assert!(b.cmpeq(a).any()); -} - -#[test] -fn test_vec4_cmp() { - assert!(!Vec4Mask::default().any()); - assert!(!Vec4Mask::default().all()); - assert_eq!(Vec4Mask::default().bitmask(), 0x0); - let a = vec4(-1.0, -1.0, -1.0, -1.0); - let b = vec4(1.0, 1.0, 1.0, 1.0); - let c = vec4(-1.0, -1.0, 1.0, 1.0); - let d = vec4(1.0, -1.0, -1.0, 1.0); - assert_eq!(a.cmplt(a).bitmask(), 0x0); - assert_eq!(a.cmplt(b).bitmask(), 0xf); - assert_eq!(a.cmplt(c).bitmask(), 0xc); - assert_eq!(c.cmple(a).bitmask(), 0x3); - assert_eq!(a.cmplt(d).bitmask(), 0x9); - assert!(a.cmplt(b).all()); - assert!(a.cmplt(c).any()); - assert!(a.cmple(b).all()); - assert!(a.cmple(a).all()); - assert!(b.cmpgt(a).all()); - assert!(b.cmpge(a).all()); - assert!(b.cmpge(b).all()); - assert!(!(a.cmpge(c).all())); - assert!(c.cmple(c).all()); - assert!(c.cmpge(c).all()); - assert!(a.cmpeq(a).all()); - assert!(!a.cmpeq(b).all()); - assert!(a.cmpeq(c).any()); - assert!(!a.cmpne(a).all()); - assert!(a.cmpne(b).all()); - assert!(a.cmpne(c).any()); - assert!(a == a); - assert!(a < b); - assert!(b > a); -} - -#[test] -fn test_vec4_slice() { - let a = [1.0, 2.0, 3.0, 4.0]; - let b = Vec4::from_slice_unaligned(&a); - let c: [f32; 4] = b.into(); - assert_eq!(a, c); - let mut d = [0.0, 0.0, 0.0, 0.0]; - b.write_to_slice_unaligned(&mut d[..]); - assert_eq!(a, d); -} - -#[test] -fn test_vec4_sign() { - assert_eq!(Vec4::zero().sign(), Vec4::one()); - assert_eq!(-Vec4::zero().sign(), -Vec4::one()); - assert_eq!(Vec4::one().sign(), Vec4::one()); - assert_eq!((-Vec4::one()).sign(), -Vec4::one()); - assert_eq!(Vec4::splat(core::f32::NEG_INFINITY).sign(), -Vec4::one()); -} - -#[test] -fn test_vec4_abs() { - assert_eq!(Vec4::zero().abs(), Vec4::zero()); - assert_eq!(Vec4::one().abs(), Vec4::one()); - assert_eq!((-Vec4::one()).abs(), Vec4::one()); -} - -// #[test] -// fn dup_element() { -// let a = vec4(1.0, 2.0, 3.0, 4.0); -// assert_eq!(vec4(1.0, 1.0, 1.0, 1.0), a.dup_x()); -// assert_eq!(vec4(2.0, 2.0, 2.0, 2.0), a.dup_y()); -// assert_eq!(vec4(3.0, 3.0, 3.0, 3.0), a.dup_z()); -// assert_eq!(vec4(4.0, 4.0, 4.0, 4.0), a.dup_w()); -// } - -#[test] -fn test_vec4mask_as_ref() { - assert_eq!( - Vec4Mask::new(false, false, false, false).as_ref(), - &[0, 0, 0, 0] - ); - assert_eq!( - Vec4Mask::new(false, false, true, true).as_ref(), - &[0, 0, !0, !0] - ); - assert_eq!( - Vec4Mask::new(true, true, false, false).as_ref(), - &[!0, !0, 0, 0] - ); - assert_eq!( - Vec4Mask::new(false, true, false, true).as_ref(), - &[0, !0, 0, !0] - ); - assert_eq!( - Vec4Mask::new(true, false, true, false).as_ref(), - &[!0, 0, !0, 0] - ); - assert_eq!( - Vec4Mask::new(true, true, true, true).as_ref(), - &[!0, !0, !0, !0] - ); -} - -#[test] -fn test_vec4mask_from() { - assert_eq!( - Into::<[u32; 4]>::into(Vec4Mask::new(false, false, false, false)), - [0, 0, 0, 0] - ); - assert_eq!( - Into::<[u32; 4]>::into(Vec4Mask::new(false, false, true, true)), - [0, 0, !0, !0] - ); - assert_eq!( - Into::<[u32; 4]>::into(Vec4Mask::new(true, true, false, false)), - [!0, !0, 0, 0] - ); - assert_eq!( - Into::<[u32; 4]>::into(Vec4Mask::new(false, true, false, true)), - [0, !0, 0, !0] - ); - assert_eq!( - Into::<[u32; 4]>::into(Vec4Mask::new(true, false, true, false)), - [!0, 0, !0, 0] - ); - assert_eq!( - Into::<[u32; 4]>::into(Vec4Mask::new(true, true, true, true)), - [!0, !0, !0, !0] - ); -} - -#[test] -fn test_vec4mask_bitmask() { - assert_eq!(Vec4Mask::new(false, false, false, false).bitmask(), 0b0000); - assert_eq!(Vec4Mask::new(false, false, true, true).bitmask(), 0b1100); - assert_eq!(Vec4Mask::new(true, true, false, false).bitmask(), 0b0011); - assert_eq!(Vec4Mask::new(false, true, false, true).bitmask(), 0b1010); - assert_eq!(Vec4Mask::new(true, false, true, false).bitmask(), 0b0101); - assert_eq!(Vec4Mask::new(true, true, true, true).bitmask(), 0b1111); -} - -#[test] -fn test_vec4mask_any() { - assert_eq!(Vec4Mask::new(false, false, false, false).any(), false); - assert_eq!(Vec4Mask::new(true, false, false, false).any(), true); - assert_eq!(Vec4Mask::new(false, true, false, false).any(), true); - assert_eq!(Vec4Mask::new(false, false, true, false).any(), true); - assert_eq!(Vec4Mask::new(false, false, false, true).any(), true); -} - -#[test] -fn test_vec4mask_all() { - assert_eq!(Vec4Mask::new(true, true, true, true).all(), true); - assert_eq!(Vec4Mask::new(false, true, true, true).all(), false); - assert_eq!(Vec4Mask::new(true, false, true, true).all(), false); - assert_eq!(Vec4Mask::new(true, true, false, true).all(), false); - assert_eq!(Vec4Mask::new(true, true, true, false).all(), false); -} - -#[test] -fn test_vec4mask_select() { - let a = Vec4::new(1.0, 2.0, 3.0, 4.0); - let b = Vec4::new(5.0, 6.0, 7.0, 8.0); - assert_eq!( - Vec4Mask::new(true, true, true, true).select(a, b), - Vec4::new(1.0, 2.0, 3.0, 4.0), - ); - assert_eq!( - Vec4Mask::new(true, false, true, false).select(a, b), - Vec4::new(1.0, 6.0, 3.0, 8.0), - ); - assert_eq!( - Vec4Mask::new(false, true, false, true).select(a, b), - Vec4::new(5.0, 2.0, 7.0, 4.0), - ); - assert_eq!( - Vec4Mask::new(false, false, false, false).select(a, b), - Vec4::new(5.0, 6.0, 7.0, 8.0), - ); -} - -#[test] -fn test_vec4mask_and() { - assert_eq!( - (Vec4Mask::new(false, false, false, false) & Vec4Mask::new(false, false, false, false)) - .bitmask(), - 0b0000, - ); - assert_eq!( - (Vec4Mask::new(true, true, true, true) & Vec4Mask::new(true, true, true, true)).bitmask(), - 0b1111, - ); - assert_eq!( - (Vec4Mask::new(true, false, true, false) & Vec4Mask::new(false, true, false, true)) - .bitmask(), - 0b0000, - ); - assert_eq!( - (Vec4Mask::new(true, false, true, true) & Vec4Mask::new(true, true, true, false)).bitmask(), - 0b0101, - ); - - let mut mask = Vec4Mask::new(true, true, false, false); - mask &= Vec4Mask::new(true, false, true, false); - assert_eq!(mask.bitmask(), 0b0001); -} - -#[test] -fn test_vec4mask_or() { - assert_eq!( - (Vec4Mask::new(false, false, false, false) | Vec4Mask::new(false, false, false, false)) - .bitmask(), - 0b0000, - ); - assert_eq!( - (Vec4Mask::new(true, true, true, true) | Vec4Mask::new(true, true, true, true)).bitmask(), - 0b1111, - ); - assert_eq!( - (Vec4Mask::new(true, false, true, false) | Vec4Mask::new(false, true, false, true)) - .bitmask(), - 0b1111, - ); - assert_eq!( - (Vec4Mask::new(true, false, true, false) | Vec4Mask::new(true, false, true, false)) - .bitmask(), - 0b0101, - ); - - let mut mask = Vec4Mask::new(true, true, false, false); - mask |= Vec4Mask::new(true, false, true, false); - assert_eq!(mask.bitmask(), 0b0111); -} - -#[test] -fn test_vec4mask_not() { - assert_eq!( - (!Vec4Mask::new(false, false, false, false)).bitmask(), - 0b1111 - ); - assert_eq!((!Vec4Mask::new(true, true, true, true)).bitmask(), 0b0000); - assert_eq!((!Vec4Mask::new(true, false, true, false)).bitmask(), 0b1010); - assert_eq!((!Vec4Mask::new(false, true, false, true)).bitmask(), 0b0101); -} - -#[test] -fn test_vec4mask_fmt() { - let a = Vec4Mask::new(true, false, true, false); - - #[cfg(all(target_feature = "sse2", not(feature = "scalar-math")))] - assert_eq!(format!("{}", a), "[true, false, true, false]"); - #[cfg(all(target_feature = "sse2", not(feature = "scalar-math")))] - assert_eq!( - format!("{:?}", a), - "Vec4Mask(0xffffffff, 0x0, 0xffffffff, 0x0)" - ); - - #[cfg(any(not(target_feature = "sse2"), feature = "scalar-math"))] - assert_eq!(format!("{}", a), "[true, false, true, false]"); - #[cfg(any(not(target_feature = "sse2"), feature = "scalar-math"))] - assert_eq!( - format!("{:?}", a), - "Vec4Mask(0xffffffff, 0x0, 0xffffffff, 0x0)" - ); -} - -#[test] -fn test_vec4mask_eq() { - let a = Vec4Mask::new(true, false, true, false); - let b = Vec4Mask::new(true, false, true, false); - let c = Vec4Mask::new(false, true, true, false); - - assert_eq!(a, b); - assert_eq!(b, a); - assert_ne!(a, c); - assert_ne!(b, c); - - assert!(a > c); - assert!(c < a); -} - -#[test] -fn test_vec4mask_hash() { - use std::{ - collections::hash_map::DefaultHasher, - hash::{Hash, Hasher}, - }; - - let a = Vec4Mask::new(true, false, true, false); - let b = Vec4Mask::new(true, false, true, false); - let c = Vec4Mask::new(false, true, true, false); - - let mut hasher = DefaultHasher::new(); - a.hash(&mut hasher); - let a_hashed = hasher.finish(); - - let mut hasher = DefaultHasher::new(); - b.hash(&mut hasher); - let b_hashed = hasher.finish(); - - let mut hasher = DefaultHasher::new(); - c.hash(&mut hasher); - let c_hashed = hasher.finish(); - - assert_eq!(a, b); - assert_eq!(a_hashed, b_hashed); - assert_ne!(a, c); - assert_ne!(a_hashed, c_hashed); -} - -#[test] -fn test_vec4_round() { - assert_eq!(Vec4::new(1.35, 0.0, 0.0, 0.0).round().x(), 1.0); - assert_eq!(Vec4::new(0.0, 1.5, 0.0, 0.0).round().y(), 2.0); - assert_eq!(Vec4::new(0.0, 0.0, -15.5, 0.0).round().z(), -16.0); - assert_eq!(Vec4::new(0.0, 0.0, 0.0, 0.0).round().z(), 0.0); - assert_eq!(Vec4::new(0.0, 21.1, 0.0, 0.0).round().y(), 21.0); - assert_eq!(Vec4::new(0.0, 0.0, 0.0, 11.123).round().w(), 11.0); - assert_eq!(Vec4::new(0.0, 0.0, 11.501, 0.0).round().z(), 12.0); - assert_eq!( - Vec4::new(f32::NEG_INFINITY, f32::INFINITY, 1.0, -1.0).round(), - Vec4::new(f32::NEG_INFINITY, f32::INFINITY, 1.0, -1.0) - ); - assert!(Vec4::new(f32::NAN, 0.0, 0.0, 1.0).round().x().is_nan()); -} - -#[test] -fn test_vec4_floor() { - assert_eq!( - Vec4::new(1.35, 1.5, -1.5, 1.999).floor(), - Vec4::new(1.0, 1.0, -2.0, 1.0) - ); - assert_eq!( - Vec4::new(f32::INFINITY, f32::NEG_INFINITY, 0.0, 0.0).floor(), - Vec4::new(f32::INFINITY, f32::NEG_INFINITY, 0.0, 0.0) - ); - assert!(Vec4::new(0.0, f32::NAN, 0.0, 0.0).floor().y().is_nan()); - assert_eq!( - Vec4::new(-0.0, -2000000.123, 10000000.123, 1000.9).floor(), - Vec4::new(-0.0, -2000001.0, 10000000.0, 1000.0) - ); -} - -#[test] -fn test_vec4_ceil() { - assert_eq!( - Vec4::new(1.35, 1.5, -1.5, 1234.1234).ceil(), - Vec4::new(2.0, 2.0, -1.0, 1235.0) - ); - assert_eq!( - Vec4::new(f32::INFINITY, f32::NEG_INFINITY, 0.0, 0.0).ceil(), - Vec4::new(f32::INFINITY, f32::NEG_INFINITY, 0.0, 0.0) - ); - assert!(Vec4::new(0.0, 0.0, f32::NAN, 0.0).ceil().z().is_nan()); - assert_eq!( - Vec4::new(-1234.1234, -2000000.123, 1000000.123, 1000.9).ceil(), - Vec4::new(-1234.0, -2000000.0, 1000001.0, 1001.0) - ); -} - -#[test] -fn test_vec4_lerp() { - let v0 = Vec4::new(-1.0, -1.0, -1.0, -1.0); - let v1 = Vec4::new(1.0, 1.0, 1.0, 1.0); - assert_approx_eq!(v0, v0.lerp(v1, 0.0)); - assert_approx_eq!(v1, v0.lerp(v1, 1.0)); - assert_approx_eq!(Vec4::zero(), v0.lerp(v1, 0.5)); -} - -#[test] -fn test_vec4_to_from_slice() { - let v = Vec4::new(1.0, 2.0, 3.0, 4.0); - let mut a = [0.0, 0.0, 0.0, 0.0]; - v.write_to_slice_unaligned(&mut a); - assert_eq!(v, Vec4::from_slice_unaligned(&a)); -} - -#[cfg(feature = "serde")] -#[test] -fn test_vec4_serde() { - let a = Vec4::new(1.0, 2.0, 3.0, 4.0); - let serialized = serde_json::to_string(&a).unwrap(); - assert_eq!(serialized, "[1.0,2.0,3.0,4.0]"); - let deserialized = serde_json::from_str(&serialized).unwrap(); - assert_eq!(a, deserialized); - let deserialized = serde_json::from_str::("[]"); - assert!(deserialized.is_err()); - let deserialized = serde_json::from_str::("[1.0]"); - assert!(deserialized.is_err()); - let deserialized = serde_json::from_str::("[1.0,2.0]"); - assert!(deserialized.is_err()); - let deserialized = serde_json::from_str::("[1.0,2.0,3.0]"); - assert!(deserialized.is_err()); - let deserialized = serde_json::from_str::("[1.0,2.0,3.0,4.0,5.0]"); - assert!(deserialized.is_err()); -} - -#[cfg(feature = "rand")] -#[test] -fn test_vec4_rand() { - use rand::{Rng, SeedableRng}; - use rand_xoshiro::Xoshiro256Plus; - let mut rng1 = Xoshiro256Plus::seed_from_u64(0); - let a: (f32, f32, f32, f32) = rng1.gen(); - let mut rng2 = Xoshiro256Plus::seed_from_u64(0); - let b: Vec4 = rng2.gen(); - assert_eq!(a, b.into()); -} diff --git a/crates/bevy_pbr/Cargo.toml b/crates/bevy_pbr/Cargo.toml index 06612145ed..b2e52bc2b3 100644 --- a/crates/bevy_pbr/Cargo.toml +++ b/crates/bevy_pbr/Cargo.toml @@ -16,5 +16,4 @@ bevy_transform = { path = "../bevy_transform" } bevy_window = { path = "../bevy_window" } legion = { path = "../bevy_legion"} -zerocopy = "0.3" -glam = { path = "../bevy_glam" } \ No newline at end of file +glam = "0.8.7" \ No newline at end of file diff --git a/crates/bevy_pbr/src/light.rs b/crates/bevy_pbr/src/light.rs index da3006da68..43f690fcb6 100644 --- a/crates/bevy_pbr/src/light.rs +++ b/crates/bevy_pbr/src/light.rs @@ -3,7 +3,7 @@ use bevy_transform::components::Translation; use bevy_property::Properties; use glam::Mat4; use std::ops::Range; -use zerocopy::{AsBytes, FromBytes}; +use bevy_core::bytes::Byteable; #[derive(Properties)] pub struct Light { @@ -23,13 +23,15 @@ impl Default for Light { } #[repr(C)] -#[derive(Clone, Copy, AsBytes, FromBytes)] +#[derive(Clone, Copy)] pub struct LightRaw { pub proj: [[f32; 4]; 4], pub pos: [f32; 4], pub color: [f32; 4], } +unsafe impl Byteable for LightRaw {} + impl LightRaw { pub fn from(light: &Light, transform: &Mat4, translation: &Translation) -> LightRaw { let perspective = PerspectiveProjection { diff --git a/crates/bevy_pbr/src/nodes/lights_node.rs b/crates/bevy_pbr/src/nodes/lights_node.rs index 1e73e6819d..b408e574af 100644 --- a/crates/bevy_pbr/src/nodes/lights_node.rs +++ b/crates/bevy_pbr/src/nodes/lights_node.rs @@ -12,7 +12,7 @@ use crate::{ }; use bevy_transform::prelude::*; use legion::prelude::*; -use zerocopy::AsBytes; +use bevy_core::bytes::{Byteable, AsBytes}; #[derive(Default)] pub struct LightsNode { @@ -43,11 +43,13 @@ impl Node for LightsNode { } #[repr(C)] -#[derive(Clone, Copy, AsBytes)] +#[derive(Clone, Copy)] pub struct LightCount { pub num_lights: [u32; 4], } +unsafe impl Byteable for LightCount {} + impl SystemNode for LightsNode { fn get_system(&self) -> Box { let mut light_buffer = None; diff --git a/crates/bevy_property/Cargo.toml b/crates/bevy_property/Cargo.toml index e67f8faa55..937b23046d 100644 --- a/crates/bevy_property/Cargo.toml +++ b/crates/bevy_property/Cargo.toml @@ -9,6 +9,6 @@ serde = "1" erased-serde = "0.3" bevy_property_derive = { path = "bevy_property_derive" } ron = { git = "https://github.com/ron-rs/ron", rev = "35355ba7eb495f07282162826c29873154c2fa14" } -glam = { path = "../bevy_glam", features = ["serde"] } +glam = { version = "0.8.7", features = ["serde"] } legion = { path = "../bevy_legion" } smallvec = { version = "1.4", features = ["serde"] } \ No newline at end of file diff --git a/crates/bevy_render/Cargo.toml b/crates/bevy_render/Cargo.toml index f27de4f526..15d1ad540f 100644 --- a/crates/bevy_render/Cargo.toml +++ b/crates/bevy_render/Cargo.toml @@ -26,9 +26,8 @@ png = "0.16.0" # misc log = { version = "0.4", features = ["release_max_level_info"] } uuid = { version = "0.8", features = ["v4", "serde"] } -glam = { path = "../bevy_glam" } +glam = "0.8.7" serde = { version = "1", features = ["derive"] } -zerocopy = "0.3" bitflags = "1.0" smallvec = "1.4.0" # TODO: replace once_cell with std equivalent if/when this lands: https://github.com/rust-lang/rfcs/pull/2788 diff --git a/crates/bevy_render/src/color.rs b/crates/bevy_render/src/color.rs index da61c45c39..655d73b952 100644 --- a/crates/bevy_render/src/color.rs +++ b/crates/bevy_render/src/color.rs @@ -1,15 +1,14 @@ use super::texture::Texture; use crate::shader::ShaderDefSuffixProvider; use bevy_asset::Handle; -use bevy_core::bytes::Bytes; +use bevy_core::bytes::{Byteable, Bytes}; use bevy_property::Property; use glam::Vec4; use serde::{Deserialize, Serialize}; use std::ops::{Add, AddAssign}; -use zerocopy::AsBytes; #[repr(C)] -#[derive(Debug, Clone, Copy, PartialEq, AsBytes, Serialize, Deserialize, Property)] +#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, Property)] pub struct Color { pub r: f32, pub g: f32, @@ -17,6 +16,8 @@ pub struct Color { pub a: f32, } +unsafe impl Byteable for Color {} + impl Color { pub const WHITE: Color = Color::rgb(1.0, 1.0, 1.0); pub const BLACK: Color = Color::rgb(0.0, 1.0, 0.0); @@ -91,15 +92,6 @@ impl Into<[f32; 4]> for Color { } } -impl Bytes for Color { - fn write_bytes(&self, buffer: &mut [u8]) { - buffer[0..self.byte_len()].copy_from_slice(self.as_bytes()) - } - fn byte_len(&self) -> usize { - std::mem::size_of::() - } -} - impl Bytes for ColorSource { fn write_bytes(&self, buffer: &mut [u8]) { match *self { diff --git a/crates/bevy_render/src/mesh.rs b/crates/bevy_render/src/mesh.rs index 2798bd8c96..3828896ac3 100644 --- a/crates/bevy_render/src/mesh.rs +++ b/crates/bevy_render/src/mesh.rs @@ -12,9 +12,9 @@ use bevy_app::{GetEventReader, Events}; use bevy_asset::{AssetEvent, Assets, Handle}; use glam::*; use legion::prelude::*; +use bevy_core::bytes::{Byteable, AsBytes}; use std::{borrow::Cow, collections::HashSet}; use thiserror::Error; -use zerocopy::AsBytes; pub const VERTEX_BUFFER_ASSET_INDEX: usize = 0; pub const INDEX_BUFFER_ASSET_INDEX: usize = 1; @@ -37,12 +37,13 @@ impl VertexAttributeValues { } // TODO: add vertex format as parameter here and perform type conversions - pub fn get_bytes(&self) -> &[u8] { - match *self { - VertexAttributeValues::Float(ref values) => values.as_bytes(), - VertexAttributeValues::Float2(ref values) => values.as_bytes(), - VertexAttributeValues::Float3(ref values) => values.as_bytes(), - VertexAttributeValues::Float4(ref values) => values.as_bytes(), + // TODO: make this zero-copy if possible. how did zerocopy implement AsBytes for Vec? + pub fn get_bytes(&self) -> Vec { + match self { + VertexAttributeValues::Float(values) => values.as_slice().as_bytes().to_vec(), + VertexAttributeValues::Float2(values) => values.as_slice().as_bytes().to_vec(), + VertexAttributeValues::Float3(values) => values.as_slice().as_bytes().to_vec(), + VertexAttributeValues::Float4(values) => values.as_slice().as_bytes().to_vec(), } } } @@ -159,9 +160,10 @@ impl Mesh { .iter() .map(|i| *i as u16) .collect::>() + .as_slice() .as_bytes() .to_vec(), - IndexFormat::Uint32 => indices.as_bytes().to_vec(), + IndexFormat::Uint32 => indices.as_slice().as_bytes().to_vec(), }) } } @@ -431,7 +433,7 @@ pub fn mesh_resource_provider_system(resources: &mut Resources) -> Box Self { - SpriteEntity { + Self { sprite: Default::default(), quad: Default::default(), mesh: QUAD_HANDLE, @@ -28,3 +29,31 @@ impl Default for SpriteEntity { } } } + +#[derive(EntityArchetype)] +pub struct SpriteSheetEntity { + pub sprite: Sprite, + pub sprite_sheet: Handle, + pub renderable: Renderable, + pub local_to_world: LocalToWorld, + pub translation: Translation, + pub rotation: Rotation, + pub scale: Scale, +} + +impl Default for SpriteSheetEntity { + fn default() -> Self { + Self { + sprite: Default::default(), + sprite_sheet: Default::default(), + renderable: Renderable { + pipelines: vec![SPRITE_SHEET_PIPELINE_HANDLE], + ..Default::default() + }, + local_to_world: Default::default(), + translation: Default::default(), + rotation: Default::default(), + scale: Default::default(), + } + } +} diff --git a/crates/bevy_sprite/src/lib.rs b/crates/bevy_sprite/src/lib.rs index 5f615ee0bc..ebbc4fc191 100644 --- a/crates/bevy_sprite/src/lib.rs +++ b/crates/bevy_sprite/src/lib.rs @@ -1,12 +1,14 @@ mod color_material; pub mod entity; mod quad; +mod rect; mod render; mod sprite; mod sprite_sheet; pub use color_material::*; pub use quad::*; +pub use rect::*; pub use render::*; pub use sprite::*; pub use sprite_sheet::*; @@ -30,10 +32,15 @@ pub const QUAD_HANDLE: Handle = Handle::from_u128(142404619811301375266013 impl AppPlugin for SpritePlugin { fn build(&self, app: &mut AppBuilder) { app.add_asset::() + .add_asset::() .add_system_to_stage(stage::POST_UPDATE, sprite_system()) .add_system_to_stage( stage::POST_UPDATE, asset_shader_def_system::.system(), + ) + .init_system_to_stage( + bevy_render::stage::RENDER_RESOURCE, + sprite_sheet_resource_provider_system, ); let resources = app.resources(); diff --git a/crates/bevy_sprite/src/quad.rs b/crates/bevy_sprite/src/quad.rs index 3e094e6e92..b3f0eec88c 100644 --- a/crates/bevy_sprite/src/quad.rs +++ b/crates/bevy_sprite/src/quad.rs @@ -1,20 +1,9 @@ -use bevy_core::bytes::GetBytes; -use bevy_derive::Uniform; +use bevy_derive::{Uniform, Bytes}; use glam::Vec2; -use zerocopy::AsBytes; #[repr(C)] -#[derive(Default, Clone, Copy, Debug, Uniform, AsBytes)] +#[derive(Default, Clone, Copy, Debug, Uniform, Bytes)] pub struct Quad { pub position: Vec2, pub size: Vec2, pub z_index: f32, -} - -impl GetBytes for Quad { - fn get_bytes(&self) -> Vec { - self.as_bytes().to_vec() - } - fn get_bytes_ref(&self) -> Option<&[u8]> { - Some(self.as_bytes()) - } -} +} \ No newline at end of file diff --git a/crates/bevy_sprite/src/rect.rs b/crates/bevy_sprite/src/rect.rs index 71edc17d12..b32088d80b 100644 --- a/crates/bevy_sprite/src/rect.rs +++ b/crates/bevy_sprite/src/rect.rs @@ -1,14 +1,21 @@ +use glam::Vec2; + +/// A rectangle defined by two points. There is no defined origin, so 0,0 could be anywhere (top-left, bottom-left, etc) +#[repr(C)] +#[derive(Default, Clone, Copy, Debug)] pub struct Rect { + /// The beginning point of the rect pub min: Vec2, + /// The ending point of the rect pub max: Vec2, } impl Rect { pub fn width(&self) -> f32 { - self.max.x - self.min.x + self.max.x() - self.min.x() } pub fn height(&self) -> f32 { - self.max.y - self.min.y + self.max.y() - self.min.y() } } \ No newline at end of file diff --git a/crates/bevy_sprite/src/render/mod.rs b/crates/bevy_sprite/src/render/mod.rs index 7a906487fd..5ecac686ff 100644 --- a/crates/bevy_sprite/src/render/mod.rs +++ b/crates/bevy_sprite/src/render/mod.rs @@ -16,6 +16,54 @@ use legion::prelude::Resources; pub const SPRITE_PIPELINE_HANDLE: Handle = Handle::from_u128(278534784033876544639935131272264723170); +pub const SPRITE_SHEET_PIPELINE_HANDLE: Handle = + Handle::from_u128(90168858051802816124217444474933884151); + +pub fn build_sprite_sheet_pipeline(shaders: &mut Assets) -> PipelineDescriptor { + PipelineDescriptor { + rasterization_state: Some(RasterizationStateDescriptor { + front_face: FrontFace::Ccw, + cull_mode: CullMode::None, + depth_bias: 0, + depth_bias_slope_scale: 0.0, + depth_bias_clamp: 0.0, + }), + depth_stencil_state: Some(DepthStencilStateDescriptor { + format: TextureFormat::Depth32Float, + depth_write_enabled: true, + depth_compare: CompareFunction::Less, + stencil_front: StencilStateFaceDescriptor::IGNORE, + stencil_back: StencilStateFaceDescriptor::IGNORE, + stencil_read_mask: 0, + stencil_write_mask: 0, + }), + color_states: vec![ColorStateDescriptor { + format: TextureFormat::Bgra8UnormSrgb, + color_blend: BlendDescriptor { + src_factor: BlendFactor::SrcAlpha, + dst_factor: BlendFactor::OneMinusSrcAlpha, + operation: BlendOperation::Add, + }, + alpha_blend: BlendDescriptor { + src_factor: BlendFactor::One, + dst_factor: BlendFactor::One, + operation: BlendOperation::Add, + }, + write_mask: ColorWrite::ALL, + }], + ..PipelineDescriptor::new(ShaderStages { + vertex: shaders.add(Shader::from_glsl( + ShaderStage::Vertex, + include_str!("sprite_sheet.vert"), + )), + fragment: Some(shaders.add(Shader::from_glsl( + ShaderStage::Fragment, + include_str!("sprite_sheet.frag"), + ))), + }) + } +} + pub fn build_sprite_pipeline(shaders: &mut Assets) -> PipelineDescriptor { PipelineDescriptor { rasterization_state: Some(RasterizationStateDescriptor { @@ -86,6 +134,7 @@ impl SpriteRenderGraphBuilder for RenderGraph { let mut pipelines = resources.get_mut::>().unwrap(); let mut shaders = resources.get_mut::>().unwrap(); pipelines.set(SPRITE_PIPELINE_HANDLE, build_sprite_pipeline(&mut shaders)); + pipelines.set(SPRITE_SHEET_PIPELINE_HANDLE, build_sprite_sheet_pipeline(&mut shaders)); let main_pass: &mut PassNode = self .get_node_mut(base_render_graph::node::MAIN_PASS) .unwrap(); @@ -93,6 +142,10 @@ impl SpriteRenderGraphBuilder for RenderGraph { SPRITE_PIPELINE_HANDLE, vec![Box::new(AssignedMeshesDrawTarget)], ); + main_pass.add_pipeline( + SPRITE_SHEET_PIPELINE_HANDLE, + vec![Box::new(AssignedMeshesDrawTarget)], + ); self } } diff --git a/crates/bevy_sprite/src/render/sprite_sheet.frag b/crates/bevy_sprite/src/render/sprite_sheet.frag new file mode 100644 index 0000000000..9995374756 --- /dev/null +++ b/crates/bevy_sprite/src/render/sprite_sheet.frag @@ -0,0 +1,14 @@ +#version 450 + +layout(location = 0) in vec2 v_Uv; + +layout(location = 0) out vec4 o_Target; + +layout(set = 1, binding = 1) uniform texture2D SpriteSheet_texture; +layout(set = 1, binding = 2) uniform sampler SpriteSheet_texture_sampler; + +void main() { + o_Target = texture( + sampler2D(SpriteSheet_texture, SpriteSheet_texture_sampler), + v_Uv);; +} diff --git a/crates/bevy_sprite/src/render/sprite_sheet.vert b/crates/bevy_sprite/src/render/sprite_sheet.vert new file mode 100644 index 0000000000..41555db818 --- /dev/null +++ b/crates/bevy_sprite/src/render/sprite_sheet.vert @@ -0,0 +1,42 @@ +#version 450 + +// sprite +layout(location = 0) in vec3 Sprite_Position; +// this is a vec2 instead of an int due to WebGPU limitations +layout(location = 1) in ivec2 Sprite_Index; + +layout(location = 0) out vec2 v_Uv; + +layout(set = 0, binding = 0) uniform Camera2d { + mat4 ViewProj; +}; + +struct Rect { + vec2 begin; + vec2 end; +}; + +layout(set = 1, binding = 0) buffer SpriteSheet { + Rect[] SpriteSheet_sprites; +}; + +const vec2 positions[4] = vec2[]( + vec2(0.5, -0.5), + vec2(-0.5, -0.5), + vec2(0.5, 0.5), + vec2(-0.5, 0.5) +); + +void main() { + Rect sprite_rect = SpriteSheet_sprites[Sprite_Index.x]; + vec2 dimensions = sprite_rect.end - sprite_rect.begin; + vec2 vertex_position = positions[gl_VertexIndex] * dimensions; + vec2 uvs[4] = vec2[]( + vec2(sprite_rect.end.x, sprite_rect.begin.y), + sprite_rect.begin, + sprite_rect.end, + vec2(sprite_rect.begin.x, sprite_rect.end.y) + ); + v_Uv = uvs[gl_VertexIndex]; + gl_Position = ViewProj * vec4(vec3(vertex_position, 0.0) + Sprite_Position, 1.0); +} \ No newline at end of file diff --git a/crates/bevy_sprite/src/sprite_sheet.rs b/crates/bevy_sprite/src/sprite_sheet.rs index 7ff28c0117..db04da8264 100644 --- a/crates/bevy_sprite/src/sprite_sheet.rs +++ b/crates/bevy_sprite/src/sprite_sheet.rs @@ -1,8 +1,112 @@ -use crate::Quad; -use bevy_asset::Handle; -use bevy_render::texture::Texture; +use crate::Rect; +use bevy_app::{Events, GetEventReader}; +use bevy_asset::{AssetEvent, Assets, Handle}; +use bevy_derive::{Uniform, Bytes}; +use bevy_render::{ + render_resource::{BufferInfo, BufferUsage, RenderResourceAssignment, ResourceInfo}, + renderer::{RenderResourceContext, RenderResources}, + texture::Texture, + Renderable, +}; +use legion::prelude::*; +use std::collections::HashSet; +use glam::{Vec4, Vec3}; pub struct SpriteSheet { pub texture: Handle, - pub sprites: Vec, + pub sprites: Vec, +} + +#[repr(C)] +#[derive(Uniform, Bytes)] +pub struct SpriteSheetSprite { + #[uniform(vertex)] + pub postition: Vec4, + #[uniform(vertex)] + pub index: u16, +} + +pub const SPRITE_SHEET_BUFFER_ASSET_INDEX: usize = 0; + +fn remove_sprite_sheet_resource( + render_resources: &dyn RenderResourceContext, + handle: Handle, +) { + if let Some(resource) = + render_resources.get_asset_resource(handle, SPRITE_SHEET_BUFFER_ASSET_INDEX) + { + render_resources.remove_buffer(resource); + render_resources.remove_asset_resource(handle, SPRITE_SHEET_BUFFER_ASSET_INDEX); + } +} + +pub fn sprite_sheet_resource_provider_system(resources: &mut Resources) -> Box { + let mut sprite_sheet_event_reader = resources.get_event_reader::>(); + (move |world: &mut SubWorld, + render_resources: Res, + sprite_sheets: Res>, + sprite_sheet_events: Res>>, + query: &mut Query<(Read>, Write)>| { + let render_resources = &*render_resources.context; + let mut changed_sprite_sheets = HashSet::new(); + for event in sprite_sheet_event_reader.iter(&sprite_sheet_events) { + match event { + AssetEvent::Created { handle } => { + changed_sprite_sheets.insert(*handle); + } + AssetEvent::Modified { handle } => { + changed_sprite_sheets.insert(*handle); + remove_sprite_sheet_resource(render_resources, *handle); + } + AssetEvent::Removed { handle } => { + remove_sprite_sheet_resource(render_resources, *handle); + // if sprite sheet was modified and removed in the same update, ignore the modification + // events are ordered so future modification events are ok + changed_sprite_sheets.remove(handle); + } + } + } + + for changed_sprite_sheet_handle in changed_sprite_sheets.iter() { + if let Some(sprite_sheet) = sprite_sheets.get(changed_sprite_sheet_handle) { + // let sprite_sheet_bytes = sprite_sheet.sprites.as_bytes(); + // let sprite_sheet_buffer = render_resources.create_buffer_with_data( + // BufferInfo { + // buffer_usage: BufferUsage::STORAGE, + // ..Default::default() + // }, + // &sprite_sheet_bytes, + // ); + + // render_resources.set_asset_resource( + // *changed_sprite_sheet_handle, + // sprite_sheet_buffer, + // SPRITE_SHEET_BUFFER_ASSET_INDEX, + // ); + } + } + + // TODO: remove this when batching is implemented + for (handle, mut renderable) in query.iter_mut(world) { + if let Some(sprite_sheet_buffer) = + render_resources.get_asset_resource(*handle, SPRITE_SHEET_BUFFER_ASSET_INDEX) + { + let mut buffer_size = None; + render_resources.get_resource_info(sprite_sheet_buffer, &mut |info| { + if let Some(ResourceInfo::Buffer(BufferInfo { size, .. })) = info { + buffer_size = Some(*size as u64) + } + }); + renderable.render_resource_assignments.set( + "SpriteSheet", + RenderResourceAssignment::Buffer { + dynamic_index: None, + range: 0..buffer_size.unwrap(), + resource: sprite_sheet_buffer, + }, + ) + } + } + }) + .system() } diff --git a/crates/bevy_transform/Cargo.toml b/crates/bevy_transform/Cargo.toml index 0597a8300a..724148f2b3 100644 --- a/crates/bevy_transform/Cargo.toml +++ b/crates/bevy_transform/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT" [dependencies] legion = { path = "../bevy_legion", features = ["serialize"]} -glam = { path = "../bevy_glam" } +glam = "0.8.7" bevy_property = { path = "../bevy_property" } log = "0.4" rayon = "1.2" diff --git a/crates/bevy_ui/Cargo.toml b/crates/bevy_ui/Cargo.toml index 27783ff4f3..d05f8aa14e 100644 --- a/crates/bevy_ui/Cargo.toml +++ b/crates/bevy_ui/Cargo.toml @@ -17,6 +17,4 @@ bevy_render = { path = "../bevy_render" } bevy_window = { path = "../bevy_window" } legion = { path = "../bevy_legion", features = ["serialize"] } -glam = { path = "../bevy_glam" } - -zerocopy = "0.3.0" \ No newline at end of file +glam = "0.8.7" \ No newline at end of file diff --git a/examples/2d/sprite_sheet.rs b/examples/2d/sprite_sheet.rs new file mode 100644 index 0000000000..1ef9713842 --- /dev/null +++ b/examples/2d/sprite_sheet.rs @@ -0,0 +1,36 @@ +use bevy::prelude::*; +use bevy::input::system::exit_on_esc_system; +use bevy_sprite::{Rect, SpriteSheet}; + +fn main() { + App::build() + .add_default_plugins() + .add_startup_system(setup.system()) + .init_system(exit_on_esc_system) + .run(); +} + +fn setup( + command_buffer: &mut CommandBuffer, + asset_server: Res, + mut sprite_sheets: ResMut>, +) { + let texture_handle = asset_server.load("assets/branding/icon.png").unwrap(); + let sprite_sheet = SpriteSheet { + texture: texture_handle, + sprites: vec![ + Rect { + min: Vec2::new(0.0, 0.0), + max: Vec2::new(1.0, 1.0), + } + ] + }; + let sprite_sheet_handle = sprite_sheets.add(sprite_sheet); + command_buffer + .build() + .add_entity(OrthographicCameraEntity::default()) + .add_entity(SpriteSheetEntity { + sprite_sheet: sprite_sheet_handle, + ..Default::default() + }); +} diff --git a/src/prelude.rs b/src/prelude.rs index 90da818f0e..ff015b3291 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -33,7 +33,7 @@ pub use crate::render::{ #[cfg(feature = "scene")] pub use crate::scene::{Scene, SceneSpawner}; #[cfg(feature = "sprite")] -pub use crate::sprite::{ColorMaterial, Quad, Sprite, entity::SpriteEntity}; +pub use crate::sprite::{ColorMaterial, Quad, Sprite, entity::{SpriteEntity, SpriteSheetEntity}}; #[cfg(feature = "text")] pub use crate::text::Font; #[cfg(feature = "transform")]