diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5d246083..4a732429 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,60 +1,81 @@ name: CI on: - push: - branches: - - main - pull_request: + push: + branches: + - main + pull_request: env: - CARGO_TERM_COLOR: always + CARGO_TERM_COLOR: always jobs: - check: - name: Check - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable - - uses: Swatinem/rust-cache@v2 - - name: Run cargo check - run: cargo check + check: + name: Check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + - uses: Swatinem/rust-cache@v2 + - name: Run cargo check + run: cargo check - docs: - name: Check Documentation - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable - - uses: Swatinem/rust-cache@v2 - - name: Run cargo doc - run: cargo doc --workspace --no-deps --document-private-items --keep-going - env: - RUSTDOCFLAGS: "-D warnings" + check-compiles-no-std: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + target: + - "x86_64-unknown-none" + - "wasm32v1-none" + - "thumbv6m-none-eabi" + dimensions: + - "2d" + - "3d" + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + with: + targets: ${{ matrix.target }} + - uses: Swatinem/rust-cache@v2 + - name: Run cargo check + run: cargo check -p avian${{ matrix.dimensions }} --no-default-features --features "${{ matrix.dimensions }} f32 parry-f32 libm" --target ${{ matrix.target }} - test: - name: Test Suite - strategy: - matrix: - # TODO: Add ubuntu-latest back. It had CI storage issues, so it's left out for now. - os: [windows-latest, macos-latest] - runs-on: ${{ matrix.os }} - timeout-minutes: 60 - steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable - - uses: Swatinem/rust-cache@v2 - - name: Run cargo test - run: cargo test --no-default-features --features enhanced-determinism,collider-from-mesh,serialize,debug-plugin,avian2d/2d,avian3d/3d,avian2d/f64,avian3d/f64,default-collider,parry-f64,bevy_scene,bevy_picking,diagnostic_ui + docs: + name: Check Documentation + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + - uses: Swatinem/rust-cache@v2 + - name: Run cargo doc + run: cargo doc --workspace --no-deps --document-private-items --keep-going + env: + RUSTDOCFLAGS: "-D warnings" - lints: - name: Lints - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable - - uses: Swatinem/rust-cache@v2 - - name: Run cargo fmt - run: cargo fmt --all -- --check - - name: Run cargo clippy - run: cargo clippy -- -D warnings + test: + name: Test Suite + strategy: + matrix: + # TODO: Add ubuntu-latest back. It had CI storage issues, so it's left out for now. + os: [windows-latest, macos-latest] + runs-on: ${{ matrix.os }} + timeout-minutes: 60 + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + - uses: Swatinem/rust-cache@v2 + - name: Run cargo test + run: cargo test --no-default-features --features std,enhanced-determinism,collider-from-mesh,serialize,debug-plugin,avian2d/2d,avian3d/3d,avian2d/f64,avian3d/f64,default-collider,parry-f64,bevy_scene,bevy_picking,diagnostic_ui + + lints: + name: Lints + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + - uses: Swatinem/rust-cache@v2 + - name: Run cargo fmt + run: cargo fmt --all -- --check + - name: Run cargo clippy + run: cargo clippy -- -D warnings diff --git a/Cargo.toml b/Cargo.toml index 375766db..008884bd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,3 +9,6 @@ std_instead_of_core = "warn" [profile.dev] opt-level = 1 # Use slightly better optimization, so examples work + +[patch.crates-io] +nalgebra = { git = "https://github.com/Jondolf/nalgebra", branch = "glam-no-default-features" } diff --git a/clippy.toml b/clippy.toml new file mode 100644 index 00000000..ddc8bf45 --- /dev/null +++ b/clippy.toml @@ -0,0 +1,78 @@ +disallowed-methods = [ + # f32 + { path = "f32::powi", reason = "use math_ops::FloatPow::squared, math_ops::FloatPow::cubed, or math_ops::powf instead for libm determinism" }, + { path = "f32::log", reason = "use math_ops::ln, math_ops::log2, or math_ops::log10 instead for libm determinism" }, + { path = "f32::abs_sub", reason = "deprecated and deeply confusing method" }, + { path = "f32::powf", reason = "use math_ops::powf instead for libm determinism" }, + { path = "f32::exp", reason = "use math_ops::exp instead for libm determinism" }, + { path = "f32::exp2", reason = "use math_ops::exp2 instead for libm determinism" }, + { path = "f32::ln", reason = "use math_ops::ln instead for libm determinism" }, + { path = "f32::log2", reason = "use math_ops::log2 instead for libm determinism" }, + { path = "f32::log10", reason = "use math_ops::log10 instead for libm determinism" }, + { path = "f32::cbrt", reason = "use math_ops::cbrt instead for libm determinism" }, + { path = "f32::hypot", reason = "use math_ops::hypot instead for libm determinism" }, + { path = "f32::sin", reason = "use math_ops::sin instead for libm determinism" }, + { path = "f32::cos", reason = "use math_ops::cos instead for libm determinism" }, + { path = "f32::tan", reason = "use math_ops::tan instead for libm determinism" }, + { path = "f32::asin", reason = "use math_ops::asin instead for libm determinism" }, + { path = "f32::acos", reason = "use math_ops::acos instead for libm determinism" }, + { path = "f32::atan", reason = "use math_ops::atan instead for libm determinism" }, + { path = "f32::atan2", reason = "use math_ops::atan2 instead for libm determinism" }, + { path = "f32::sin_cos", reason = "use math_ops::sin_cos instead for libm determinism" }, + { path = "f32::exp_m1", reason = "use math_ops::exp_m1 instead for libm determinism" }, + { path = "f32::ln_1p", reason = "use math_ops::ln_1p instead for libm determinism" }, + { path = "f32::sinh", reason = "use math_ops::sinh instead for libm determinism" }, + { path = "f32::cosh", reason = "use math_ops::cosh instead for libm determinism" }, + { path = "f32::tanh", reason = "use math_ops::tanh instead for libm determinism" }, + { path = "f32::asinh", reason = "use math_ops::asinh instead for libm determinism" }, + { path = "f32::acosh", reason = "use math_ops::acosh instead for libm determinism" }, + { path = "f32::atanh", reason = "use math_ops::atanh instead for libm determinism" }, + # f64 + { path = "f64::powi", reason = "use math_ops::FloatPow::squared, math_ops::FloatPow::cubed, or math_ops::powf instead for libm determinism" }, + { path = "f64::log", reason = "use math_ops::ln, math_ops::log2, or math_ops::log10 instead for libm determinism" }, + { path = "f64::abs_sub", reason = "deprecated and deeply confusing method" }, + { path = "f64::powf", reason = "use math_ops::powf instead for libm determinism" }, + { path = "f64::exp", reason = "use math_ops::exp instead for libm determinism" }, + { path = "f64::exp2", reason = "use math_ops::exp2 instead for libm determinism" }, + { path = "f64::ln", reason = "use math_ops::ln instead for libm determinism" }, + { path = "f64::log2", reason = "use math_ops::log2 instead for libm determinism" }, + { path = "f64::log10", reason = "use math_ops::log10 instead for libm determinism" }, + { path = "f64::cbrt", reason = "use math_ops::cbrt instead for libm determinism" }, + { path = "f64::hypot", reason = "use math_ops::hypot instead for libm determinism" }, + { path = "f64::sin", reason = "use math_ops::sin instead for libm determinism" }, + { path = "f64::cos", reason = "use math_ops::cos instead for libm determinism" }, + { path = "f64::tan", reason = "use math_ops::tan instead for libm determinism" }, + { path = "f64::asin", reason = "use math_ops::asin instead for libm determinism" }, + { path = "f64::acos", reason = "use math_ops::acos instead for libm determinism" }, + { path = "f64::atan", reason = "use math_ops::atan instead for libm determinism" }, + { path = "f64::atan2", reason = "use math_ops::atan2 instead for libm determinism" }, + { path = "f64::sin_cos", reason = "use math_ops::sin_cos instead for libm determinism" }, + { path = "f64::exp_m1", reason = "use math_ops::exp_m1 instead for libm determinism" }, + { path = "f64::ln_1p", reason = "use math_ops::ln_1p instead for libm determinism" }, + { path = "f64::sinh", reason = "use math_ops::sinh instead for libm determinism" }, + { path = "f64::cosh", reason = "use math_ops::cosh instead for libm determinism" }, + { path = "f64::tanh", reason = "use math_ops::tanh instead for libm determinism" }, + { path = "f64::asinh", reason = "use math_ops::asinh instead for libm determinism" }, + { path = "f64::acosh", reason = "use math_ops::acosh instead for libm determinism" }, + { path = "f64::atanh", reason = "use math_ops::atanh instead for libm determinism" }, + # These methods have defined precision, but are only available from the standard library, + # not in core. Using these substitutes allows for no_std compatibility. + # f32 + { path = "f32::rem_euclid", reason = "use math_ops::rem_euclid instead for no_std compatibility" }, + { path = "f32::abs", reason = "use math_ops::abs instead for no_std compatibility" }, + { path = "f32::sqrt", reason = "use math_ops::sqrt instead for no_std compatibility" }, + { path = "f32::copysign", reason = "use math_ops::copysign instead for no_std compatibility" }, + { path = "f32::round", reason = "use math_ops::round instead for no_std compatibility" }, + { path = "f32::floor", reason = "use math_ops::floor instead for no_std compatibility" }, + { path = "f32::ceil", reason = "use math_ops::ceil instead for no_std compatibility" }, + { path = "f32::fract", reason = "use math_ops::fract instead for no_std compatibility" }, + # f64 + { path = "f64::rem_euclid", reason = "use math_ops::rem_euclid instead for no_std compatibility" }, + { path = "f64::abs", reason = "use math_ops::abs instead for no_std compatibility" }, + { path = "f64::sqrt", reason = "use math_ops::sqrt instead for no_std compatibility" }, + { path = "f64::copysign", reason = "use math_ops::copysign instead for no_std compatibility" }, + { path = "f64::round", reason = "use math_ops::round instead for no_std compatibility" }, + { path = "f64::floor", reason = "use math_ops::floor instead for no_std compatibility" }, + { path = "f64::ceil", reason = "use math_ops::ceil instead for no_std compatibility" }, + { path = "f64::fract", reason = "use math_ops::fract instead for no_std compatibility" }, +] diff --git a/crates/avian2d/Cargo.toml b/crates/avian2d/Cargo.toml index 1c34b16f..e7e8bc41 100644 --- a/crates/avian2d/Cargo.toml +++ b/crates/avian2d/Cargo.toml @@ -13,6 +13,7 @@ categories = ["game-development", "science", "simulation"] [features] default = [ + "std", "2d", "f32", "parry-f32", @@ -28,15 +29,14 @@ f64 = [] debug-plugin = ["bevy/bevy_gizmos", "bevy/bevy_render"] simd = ["parry2d?/simd-stable", "parry2d-f64?/simd-stable"] parallel = [ + "std", "dep:thread_local", "bevy/multi_threaded", "parry2d?/parallel", "parry2d-f64?/parallel", ] enhanced-determinism = [ - "dep:libm", - "bevy_math/libm", - "bevy_heavy/libm", + "libm", "parry2d?/enhanced-determinism", "parry2d-f64?/enhanced-determinism", ] @@ -65,6 +65,23 @@ bevy_diagnostic = [] # Enables the `PhysicsDiagnosticsUiPlugin` for visualizing physics diagnostics data with a debug UI. diagnostic_ui = ["bevy_diagnostic", "bevy/bevy_ui"] +# Enable the Rust standard library. +std = [ + "bevy/std", + "bevy_heavy/std", + "bevy_transform_interpolation/std", + "parry2d?/std", + "parry2d-f64?/std", +] + +# Enable `libm` math operations for `no_std` environments and cross-platform determinism. +libm = [ + "dep:libm", + "bevy/libm", + "bevy_heavy/libm", + "bevy_transform_interpolation/libm", +] + [lib] name = "avian2d" path = "../../src/lib.rs" @@ -73,23 +90,36 @@ bench = false [dependencies] avian_derive = { path = "../avian_derive", version = "0.2" } -bevy = { version = "0.16.0-rc", default-features = false, features = [ - "std", - "bevy_log", +bevy = { version = "0.16.0-rc", default-features = false } +bevy_math = { version = "0.16.0-rc", default-features = false } +bevy_heavy = { git = "https://github.com/Jondolf/bevy_heavy", default-features = false, features = [ + "2d", + "3d", + "bevy_reflect", ] } -bevy_math = { version = "0.16.0-rc" } -bevy_heavy = { git = "https://github.com/Jondolf/bevy_heavy" } -bevy_transform_interpolation = { git = "https://github.com/Jondolf/bevy_transform_interpolation" } +bevy_transform_interpolation = { git = "https://github.com/Jondolf/bevy_transform_interpolation", default-features = false } libm = { version = "0.2", optional = true } -parry2d = { version = "0.17", optional = true } -parry2d-f64 = { version = "0.17", optional = true } -nalgebra = { version = "0.33", features = ["convert-glam029"], optional = true } -serde = { version = "1", features = ["derive"], optional = true } -derive_more = "1" -arrayvec = "0.7" -itertools = "0.13" -bitflags = "2.5.0" -thread_local = { version = "1.1", optional = true } +parry2d = { version = "0.19", optional = true, default-features = false, features = [ + "required-features", + "alloc", +] } +parry2d-f64 = { version = "0.19", optional = true, default-features = false, features = [ + "required-features", + "alloc", +] } +nalgebra = { version = "0.33", default-features = false, features = [ + "convert-glam029", +], optional = true } +serde = { version = "1", default-features = false, features = [ + "derive", +], optional = true } +derive_more = { version = "1", default-features = false } +log = { version = "0.4", default-features = false } +arrayvec = { version = "0.7", default-features = false } +hashbrown = { version = "0.15", default-features = false } +itertools = { version = "0.13", default-features = false } +bitflags = { version = "2.5.0", default-features = false } +thread_local = { version = "1.1", default-features = false, optional = true } [dev-dependencies] examples_common_2d = { path = "../examples_common_2d" } @@ -98,7 +128,6 @@ bevy_math = { version = "0.16.0-rc", features = ["approx"] } bevy_heavy = { git = "https://github.com/Jondolf/bevy_heavy", features = [ "approx", ] } -glam = { version = "0.29", features = ["bytemuck"] } approx = "0.5" bytemuck = "1.19" criterion = { version = "0.5", features = ["html_reports"] } diff --git a/crates/avian3d/Cargo.toml b/crates/avian3d/Cargo.toml index 6d7e2c61..b7403a3b 100644 --- a/crates/avian3d/Cargo.toml +++ b/crates/avian3d/Cargo.toml @@ -13,14 +13,15 @@ categories = ["game-development", "science", "simulation"] [features] default = [ + "std", "3d", "f32", "parry-f32", "collider-from-mesh", - "bevy_scene", - "bevy_picking", "debug-plugin", "parallel", + "bevy_scene", + "bevy_picking", ] 3d = [] f32 = [] @@ -29,15 +30,14 @@ f64 = [] debug-plugin = ["bevy/bevy_gizmos", "bevy/bevy_render"] simd = ["parry3d?/simd-stable", "parry3d-f64?/simd-stable"] parallel = [ + "std", "dep:thread_local", "bevy/multi_threaded", "parry3d?/parallel", "parry3d-f64?/parallel", ] enhanced-determinism = [ - "dep:libm", - "bevy_math/libm", - "bevy_heavy/libm", + "libm", "parry3d?/enhanced-determinism", "parry3d-f64?/enhanced-determinism", ] @@ -67,6 +67,24 @@ bevy_diagnostic = [] # Enables the `PhysicsDiagnosticsUiPlugin` for visualizing physics diagnostics data with a debug UI. diagnostic_ui = ["bevy_diagnostic", "bevy/bevy_ui"] +# Enable the Rust standard library. +std = [ + "bevy/std", + "bevy_heavy/std", + "bevy_transform_interpolation/std", + "parry3d?/std", + "parry3d-f64?/std", +] + +# Enable `libm` math operations for `no_std` environments and cross-platform determinism. +libm = [ + "dep:libm", + "bevy/libm", + "bevy_math/libm", + "bevy_heavy/libm", + "bevy_transform_interpolation/libm", +] + [lib] name = "avian3d" path = "../../src/lib.rs" @@ -75,22 +93,35 @@ bench = false [dependencies] avian_derive = { path = "../avian_derive", version = "0.2" } -bevy = { version = "0.16.0-rc", default-features = false, features = [ - "std", - "bevy_log", +bevy = { version = "0.16.0-rc", default-features = false } +bevy_math = { version = "0.16.0-rc", default-features = false } +bevy_heavy = { git = "https://github.com/Jondolf/bevy_heavy", default-features = false, features = [ + "2d", + "3d", + "bevy_reflect", ] } -bevy_math = { version = "0.16.0-rc" } -bevy_heavy = { git = "https://github.com/Jondolf/bevy_heavy" } -bevy_transform_interpolation = { git = "https://github.com/Jondolf/bevy_transform_interpolation" } +bevy_transform_interpolation = { git = "https://github.com/Jondolf/bevy_transform_interpolation", default-features = false } libm = { version = "0.2", optional = true } -parry3d = { version = "0.17", optional = true } -parry3d-f64 = { version = "0.17", optional = true } -nalgebra = { version = "0.33", features = ["convert-glam029"], optional = true } -serde = { version = "1", features = ["derive"], optional = true } -derive_more = "1" -itertools = "0.13" -bitflags = "2.5.0" -thread_local = { version = "1.1", optional = true } +parry3d = { version = "0.19", optional = true, default-features = false, features = [ + "required-features", + "alloc", +] } +parry3d-f64 = { version = "0.19", optional = true, default-features = false, features = [ + "required-features", + "alloc", +] } +nalgebra = { version = "0.33", default-features = false, features = [ + "convert-glam029", +], optional = true } +serde = { version = "1", default-features = false, features = [ + "derive", +], optional = true } +derive_more = { version = "1", default-features = false } +log = { version = "0.4", default-features = false } +hashbrown = { version = "0.15", default-features = false } +itertools = { version = "0.13", default-features = false } +bitflags = { version = "2.5.0", default-features = false } +thread_local = { version = "1.1", default-features = false, optional = true } [dev-dependencies] examples_common_3d = { path = "../examples_common_3d" } diff --git a/src/collision/collider/backend.rs b/src/collision/collider/backend.rs index 995aeb94..5918cec2 100644 --- a/src/collision/collider/backend.rs +++ b/src/collision/collider/backend.rs @@ -312,7 +312,7 @@ fn init_collider_constructors( for (entity, existing_collider, name, constructor) in constructors.iter() { let name = pretty_name(name, entity); if existing_collider.is_some() { - warn!( + log::warn!( "Tried to add a collider to entity {name} via {constructor:#?}, \ but that entity already holds a collider. Skipping.", ); @@ -342,7 +342,7 @@ fn init_collider_constructors( if let Some(collider) = collider { commands.entity(entity).insert(collider); } else { - error!( + log::error!( "Tried to add a collider to entity {name} via {constructor:#?}, \ but the collider could not be generated. Skipping.", ); @@ -405,7 +405,7 @@ fn init_collider_constructor_hierarchies( .cloned() .unwrap_or_else(default_collider) } else if existing_collider.is_some() { - warn!("Tried to add a collider to entity {pretty_name} via {collider_constructor_hierarchy:#?}, \ + log::warn!("Tried to add a collider to entity {pretty_name} via {collider_constructor_hierarchy:#?}, \ but that entity already holds a collider. Skipping. \ If this was intentional, add the name of the collider to overwrite to `ColliderConstructorHierarchy.config`."); continue; @@ -454,7 +454,7 @@ fn init_collider_constructor_hierarchies( .unwrap_or(collider_constructor_hierarchy.default_density), )); } else { - error!( + log::error!( "Tried to add a collider to entity {pretty_name} via {collider_constructor_hierarchy:#?}, \ but the collider could not be generated. Skipping.", ); diff --git a/src/collision/collider/collider_hierarchy/mod.rs b/src/collision/collider/collider_hierarchy/mod.rs index 34e32599..389c6ae3 100644 --- a/src/collision/collider/collider_hierarchy/mod.rs +++ b/src/collision/collider/collider_hierarchy/mod.rs @@ -121,7 +121,7 @@ impl Relationship for ColliderOf { .insert(RigidBodyColliders(vec![collider])); } } else { - warn!( + log::warn!( "{}Tried to attach collider on entity {collider} to rigid body on entity {rigid_body}, but the rigid body does not exist.", caller.map(|location| format!("{location}: ")).unwrap_or_default(), ); diff --git a/src/collision/collider/parry/mod.rs b/src/collision/collider/parry/mod.rs index 990102a4..9cd32347 100644 --- a/src/collision/collider/parry/mod.rs +++ b/src/collision/collider/parry/mod.rs @@ -11,9 +11,9 @@ mod primitives3d; pub use primitives2d::{EllipseColliderShape, RegularPolygonColliderShape}; use crate::{make_isometry, prelude::*}; +use bevy::prelude::*; #[cfg(feature = "collider-from-mesh")] use bevy::render::mesh::{Indices, VertexAttributeValues}; -use bevy::{log, prelude::*}; use contact_query::UnsupportedShape; use itertools::Either; use parry::shape::{RoundShape, SharedShape, TypedShape}; @@ -863,7 +863,7 @@ impl Collider { /// For thin shapes like triangle meshes, it can help improve collision stability and performance. pub fn trimesh(vertices: Vec, indices: Vec<[u32; 3]>) -> Self { let vertices = vertices.into_iter().map(|v| v.into()).collect(); - SharedShape::trimesh(vertices, indices).into() + SharedShape::trimesh(vertices, indices).unwrap().into() } /// Creates a collider with a triangle mesh shape defined by its vertex and index buffers @@ -879,7 +879,9 @@ impl Collider { flags: TrimeshFlags, ) -> Self { let vertices = vertices.into_iter().map(|v| v.into()).collect(); - SharedShape::trimesh_with_flags(vertices, indices, flags.into()).into() + SharedShape::trimesh_with_flags(vertices, indices, flags.into()) + .unwrap() + .into() } /// Creates a collider shape with a compound shape obtained from the decomposition of a given polyline @@ -1007,6 +1009,7 @@ impl Collider { indices, TrimeshFlags::MERGE_DUPLICATE_VERTICES.into(), ) + .unwrap() .into() }) } @@ -1036,7 +1039,9 @@ impl Collider { #[cfg(feature = "collider-from-mesh")] pub fn trimesh_from_mesh_with_config(mesh: &Mesh, flags: TrimeshFlags) -> Option { extract_mesh_vertices_indices(mesh).map(|(vertices, indices)| { - SharedShape::trimesh_with_flags(vertices, indices, flags.into()).into() + SharedShape::trimesh_with_flags(vertices, indices, flags.into()) + .unwrap() + .into() }) } @@ -1321,7 +1326,7 @@ fn scale_shape( #[cfg(feature = "2d")] { if scale.x == scale.y { - Ok(SharedShape::ball(b.radius * scale.x.abs())) + Ok(SharedShape::ball(b.radius * math_ops::abs(scale.x))) } else { // A 2D circle becomes an ellipse when scaled non-uniformly. Ok(SharedShape::new(EllipseColliderShape(Ellipse { @@ -1483,7 +1488,7 @@ fn scale_shape( if scale.x == scale.y { return Ok(SharedShape::new(RegularPolygonColliderShape( RegularPolygon::new( - polygon.circumradius() * scale.x.abs() as f32, + polygon.circumradius() * math_ops::abs(scale.x) as f32, polygon.sides, ), ))); diff --git a/src/collision/collider/parry/primitives2d.rs b/src/collision/collider/parry/primitives2d.rs index 5324dd9b..f3e9fa7e 100644 --- a/src/collision/collider/parry/primitives2d.rs +++ b/src/collision/collider/parry/primitives2d.rs @@ -1,6 +1,10 @@ -use crate::{math, AdjustPrecision, Scalar, Vector, FRAC_PI_2, PI, TAU}; +use crate::{ + math::{self, math_ops, FloatPow}, + AdjustPrecision, Scalar, Vector, FRAC_PI_2, PI, TAU, +}; use super::{AsF32, Collider, IntoCollider}; +use alloc::boxed::Box; use bevy::prelude::{Deref, DerefMut}; use bevy_math::{bounding::Bounded2d, prelude::*}; use nalgebra::{Point2, UnitVector2, Vector2}; @@ -40,7 +44,7 @@ impl SupportMap for EllipseColliderShape { #[inline] fn local_support_point(&self, direction: &Vector2) -> Point2 { let [a, b] = self.half_size.adjust_precision().to_array(); - let denom = (direction.x.powi(2) * a * a + direction.y.powi(2) * b * b).sqrt(); + let denom = math_ops::sqrt(direction.x.squared() * a * a + direction.y.squared() * b * b); Point2::new(a * a * direction.x / denom, b * b * direction.y / denom) } } @@ -99,6 +103,7 @@ impl Shape for EllipseColliderShape { ) } + #[cfg(feature = "std")] fn clone_box(&self) -> Box { Box::new(*self) } @@ -271,7 +276,7 @@ impl SupportMap for RegularPolygonColliderShape { }; // How many rotations of `external_angle` correspond to the vertex closest to the support direction. - let n = (angle_from_top / external_angle).round() % self.sides as Scalar; + let n = math_ops::round(angle_from_top / external_angle) % self.sides as Scalar; // Rotate by an additional 90 degrees so that the first vertex is always at the top. let target_angle = n * external_angle + FRAC_PI_2; @@ -300,8 +305,8 @@ impl PolygonalFeatureMap for RegularPolygonColliderShape { // How many rotations of `external_angle` correspond to the vertices. let n_unnormalized = angle_from_top / external_angle; - let n1 = n_unnormalized.floor() % self.sides as Scalar; - let n2 = n_unnormalized.ceil() % self.sides as Scalar; + let n1 = math_ops::floor(n_unnormalized) % self.sides as Scalar; + let n2 = math_ops::ceil(n_unnormalized) % self.sides as Scalar; // Rotate by an additional 90 degrees so that the first vertex is always at the top. let target_angle1 = n1 * external_angle + FRAC_PI_2; @@ -377,6 +382,7 @@ impl Shape for RegularPolygonColliderShape { ) } + #[cfg(feature = "std")] fn clone_box(&self) -> Box { Box::new(*self) } @@ -386,8 +392,8 @@ impl Shape for RegularPolygonColliderShape { let mass = volume * density; let half_external_angle = PI / self.sides as Scalar; - let angular_inertia = mass * self.circumradius().adjust_precision().powi(2) / 6.0 - * (1.0 + 2.0 * half_external_angle.cos().powi(2)); + let angular_inertia = mass * self.circumradius().adjust_precision().squared() / 6.0 + * (1.0 + 2.0 * math_ops::cos(half_external_angle).squared()); MassProperties::new(Point2::origin(), mass, angular_inertia) } diff --git a/src/collision/collider/parry/primitives3d.rs b/src/collision/collider/parry/primitives3d.rs index 9917b686..f948808b 100644 --- a/src/collision/collider/parry/primitives3d.rs +++ b/src/collision/collider/parry/primitives3d.rs @@ -1,3 +1,4 @@ +use alloc::vec; use bevy_math::primitives::{ BoxedPolyline3d, Capsule3d, Cone, Cuboid, Cylinder, Line3d, Plane3d, Polyline3d, Segment3d, Sphere, diff --git a/src/collision/contact_types/mod.rs b/src/collision/contact_types/mod.rs index ee02a815..501239b7 100644 --- a/src/collision/contact_types/mod.rs +++ b/src/collision/contact_types/mod.rs @@ -109,7 +109,7 @@ impl ContactPair { for manifold in &self.manifolds { let impulse = manifold.max_normal_impulse(); - if impulse.abs() > magnitude.abs() { + if math_ops::abs(impulse) > math_ops::abs(magnitude) { magnitude = impulse; normal = manifold.normal; } @@ -282,7 +282,7 @@ impl ContactManifold { distance_threshold: Scalar, ) { // The squared maximum distance for two contact points to be considered matching. - let distance_threshold_squared = distance_threshold.powi(2); + let distance_threshold_squared = distance_threshold.squared(); for contact in self.points.iter_mut() { for previous_contact in previous_contacts.iter() { diff --git a/src/collision/diagnostics.rs b/src/collision/diagnostics.rs index a369b018..d14c9754 100644 --- a/src/collision/diagnostics.rs +++ b/src/collision/diagnostics.rs @@ -1,3 +1,4 @@ +use alloc::{vec, vec::Vec}; use bevy::{ diagnostic::DiagnosticPath, prelude::{ReflectResource, Resource}, diff --git a/src/collision/mod.rs b/src/collision/mod.rs index 9dea5cfa..4a91ca62 100644 --- a/src/collision/mod.rs +++ b/src/collision/mod.rs @@ -93,11 +93,15 @@ pub mod prelude { pub use super::collider::{ collider_hierarchy::{ColliderHierarchyPlugin, ColliderOf, RigidBodyColliders}, collider_transform::{ColliderTransform, ColliderTransformPlugin}, - AabbContext, AnyCollider, Collider, ColliderAabb, ColliderBackendPlugin, - ColliderConstructor, ColliderConstructorHierarchy, ColliderDisabled, ColliderMarker, - CollidingEntities, CollisionLayers, CollisionMargin, ContactManifoldContext, FillMode, - IntoCollider, LayerMask, PhysicsLayer, ScalableCollider, Sensor, SimpleCollider, - TrimeshFlags, VhacdParameters, + AabbContext, AnyCollider, ColliderAabb, ColliderBackendPlugin, ColliderDisabled, + ColliderMarker, CollidingEntities, CollisionLayers, CollisionMargin, + ContactManifoldContext, IntoCollider, LayerMask, PhysicsLayer, ScalableCollider, Sensor, + SimpleCollider, + }; + #[cfg(feature = "default-collider")] + pub use super::collider::{ + Collider, ColliderConstructor, ColliderConstructorHierarchy, FillMode, TrimeshFlags, + VhacdParameters, }; pub use super::collision_events::{CollisionEnded, CollisionEventsEnabled, CollisionStarted}; pub use super::contact_types::{ diff --git a/src/collision/narrow_phase/mod.rs b/src/collision/narrow_phase/mod.rs index f6c03bc5..38fbb83c 100644 --- a/src/collision/narrow_phase/mod.rs +++ b/src/collision/narrow_phase/mod.rs @@ -123,7 +123,7 @@ where // Remove collision pairs when colliders are disabled or removed. app.add_observer(remove_collider_on::); app.add_observer(remove_collider_on::); - app.add_observer(remove_collider_on::); + app.add_observer(remove_collider_on::); // Perform narrow phase collision detection. app.add_systems( diff --git a/src/data_structures/bit_vec.rs b/src/data_structures/bit_vec.rs index 1bb9ca41..8a75f3bf 100644 --- a/src/data_structures/bit_vec.rs +++ b/src/data_structures/bit_vec.rs @@ -5,6 +5,8 @@ use core::ops::BitOrAssign; use core::slice; +use alloc::{vec, vec::Vec}; + /// A dynamically sized compact bit vector with a fixed block size of 64 bits. #[derive(Clone, Debug, Default)] #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] diff --git a/src/data_structures/graph.rs b/src/data_structures/graph.rs index bd1dc779..fd9f45bb 100644 --- a/src/data_structures/graph.rs +++ b/src/data_structures/graph.rs @@ -7,6 +7,7 @@ use core::cmp::max; use core::ops::{Index, IndexMut}; +use alloc::vec::Vec; use derive_more::derive::From; /// A node identifier for a graph structure. diff --git a/src/data_structures/sparse_secondary_map.rs b/src/data_structures/sparse_secondary_map.rs index 27597b9c..d2c10d6b 100644 --- a/src/data_structures/sparse_secondary_map.rs +++ b/src/data_structures/sparse_secondary_map.rs @@ -9,11 +9,12 @@ //! //! [`slotmap::SparseSecondaryMap`]: https://docs.rs/slotmap/1.0.7/slotmap/struct.SparseSecondaryMap.html -use alloc::collections::TryReserveError; -use bevy::platform::hash::RandomState; -use core::mem::MaybeUninit; -use std::collections::hash_map::{self, HashMap}; -use std::hash; +use bevy::platform::{ + collections::{hash_map::Entry, HashMap}, + hash::FixedHasher, +}; +use core::{hash::BuildHasher, mem::MaybeUninit}; +use hashbrown::TryReserveError; use bevy::ecs::entity::Entity; @@ -26,11 +27,11 @@ struct Slot { /// Sparse secondary map for associating data with previously stored entities /// in a generational arena. #[derive(Debug, Clone)] -pub struct SparseSecondaryEntityMap { +pub struct SparseSecondaryEntityMap { slots: HashMap, S>, } -impl SparseSecondaryEntityMap { +impl SparseSecondaryEntityMap { /// Constructs a new, empty [`SparseSecondaryEntityMap`]. #[inline] pub fn new() -> Self { @@ -56,7 +57,7 @@ fn is_older_generation(a: u32, b: u32) -> bool { diff >= (1 << 31) } -impl SparseSecondaryEntityMap { +impl SparseSecondaryEntityMap { /// Creates an empty [`SparseSecondaryEntityMap`] which will use the given hash /// builder to hash keys. /// @@ -164,7 +165,7 @@ impl SparseSecondaryEntityMap { /// the entity was not previously removed. #[inline] pub fn remove(&mut self, entity: Entity) -> Option { - if let hash_map::Entry::Occupied(entry) = self.slots.entry(entity.index()) { + if let Entry::Occupied(entry) = self.slots.entry(entity.index()) { if entry.get().generation == entity.generation() { return Some(entry.remove_entry().1.value); } @@ -317,7 +318,7 @@ impl SparseSecondaryEntityMap { impl Default for SparseSecondaryEntityMap where - S: hash::BuildHasher + Default, + S: BuildHasher + Default, { fn default() -> Self { Self::with_hasher(Default::default()) diff --git a/src/diagnostics/mod.rs b/src/diagnostics/mod.rs index dbdd2298..dd9fbd05 100644 --- a/src/diagnostics/mod.rs +++ b/src/diagnostics/mod.rs @@ -76,6 +76,7 @@ pub(crate) use path_macro::impl_diagnostic_paths; pub use total::{PhysicsTotalDiagnostics, PhysicsTotalDiagnosticsPlugin}; use crate::{schedule::PhysicsSchedule, PhysicsStepSet}; +use alloc::vec::Vec; use bevy::{ app::{App, Plugin}, diagnostic::{Diagnostic, DiagnosticPath, Diagnostics, RegisterDiagnostic}, diff --git a/src/diagnostics/ui.rs b/src/diagnostics/ui.rs index 06847ec5..5fd16a3e 100644 --- a/src/diagnostics/ui.rs +++ b/src/diagnostics/ui.rs @@ -427,9 +427,10 @@ fn update_timers( }; // Linearly interpolating between green and red, with `lower_bound` and `upper_bound`. - let t = (average as f32 - color_config.lower_bound) - / (color_config.upper_bound - color_config.lower_bound); - text_color.0 = Animatable::interpolate(&green, &red, t.min(1.0)).into(); + let t = ((average as f32 - color_config.lower_bound) + / (color_config.upper_bound - color_config.lower_bound)) + .min(1.0); + text_color.0 = (green * (1.0 - t) + red * t).into(); // Make sure the node is visible. node.display = Display::Flex; diff --git a/src/dynamics/ccd/mod.rs b/src/dynamics/ccd/mod.rs index 88c6dbeb..2d76edb7 100644 --- a/src/dynamics/ccd/mod.rs +++ b/src/dynamics/ccd/mod.rs @@ -580,15 +580,15 @@ fn solve_swept_ccd( #[cfg(feature = "2d")] let ang_vel_below_threshold = - (ang_vel1.0 - ang_vel2).abs() < ccd1.angular_threshold; + math_ops::abs(ang_vel1.0 - ang_vel2) < ccd1.angular_threshold; #[cfg(feature = "3d")] let ang_vel_below_threshold = - (ang_vel1.0 - ang_vel2).length_squared() < ccd1.angular_threshold.powi(2); + (ang_vel1.0 - ang_vel2).length_squared() < ccd1.angular_threshold.squared(); // If both the relative linear and relative angular velocity // are below the defined thresholds, skip this body. if ang_vel_below_threshold - && (lin_vel1.0 - lin_vel2).length_squared() < ccd1.linear_threshold.powi(2) + && (lin_vel1.0 - lin_vel2).length_squared() < ccd1.linear_threshold.squared() { continue; } diff --git a/src/dynamics/integrator/mod.rs b/src/dynamics/integrator/mod.rs index a0727c63..0cc6a74a 100644 --- a/src/dynamics/integrator/mod.rs +++ b/src/dynamics/integrator/mod.rs @@ -233,20 +233,20 @@ fn integrate_velocities( // Clamp velocities if let Some(max_linear_speed) = body.max_linear_speed { let linear_speed_squared = body.lin_vel.0.length_squared(); - if linear_speed_squared > max_linear_speed.0.powi(2) { - body.lin_vel.0 *= max_linear_speed.0 / linear_speed_squared.sqrt(); + if linear_speed_squared > max_linear_speed.0.squared() { + body.lin_vel.0 *= max_linear_speed.0 / math_ops::sqrt(linear_speed_squared); } } if let Some(max_angular_speed) = body.max_angular_speed { #[cfg(feature = "2d")] - if body.ang_vel.abs() > max_angular_speed.0 { - body.ang_vel.0 = max_angular_speed.copysign(body.ang_vel.0); + if math_ops::abs(body.ang_vel.0) > max_angular_speed.0 { + body.ang_vel.0 = math_ops::copysign(max_angular_speed.0, body.ang_vel.0); } #[cfg(feature = "3d")] { let angular_speed_squared = body.ang_vel.0.length_squared(); - if angular_speed_squared > max_angular_speed.0.powi(2) { - body.ang_vel.0 *= max_angular_speed.0 / angular_speed_squared.sqrt(); + if angular_speed_squared > max_angular_speed.0.squared() { + body.ang_vel.0 *= max_angular_speed.0 / math_ops::sqrt(angular_speed_squared); } } } diff --git a/src/dynamics/rigid_body/mass_properties/mod.rs b/src/dynamics/rigid_body/mass_properties/mod.rs index f2b14775..b0682265 100644 --- a/src/dynamics/rigid_body/mass_properties/mod.rs +++ b/src/dynamics/rigid_body/mass_properties/mod.rs @@ -450,7 +450,7 @@ fn warn_missing_mass( // Warn about dynamic bodies with no mass or inertia if rb.is_dynamic() && !(is_mass_valid && is_inertia_valid) { - warn!( + log::warn!( "Dynamic rigid body {:?} has no mass or inertia. This can cause NaN values. Consider adding a `MassPropertiesBundle` or a `Collider` with mass.", entity ); diff --git a/src/dynamics/rigid_body/physics_material.rs b/src/dynamics/rigid_body/physics_material.rs index 4b077820..64705c88 100644 --- a/src/dynamics/rigid_body/physics_material.rs +++ b/src/dynamics/rigid_body/physics_material.rs @@ -28,7 +28,7 @@ impl CoefficientCombine { pub fn mix(&self, a: Scalar, b: Scalar) -> Scalar { match self { CoefficientCombine::Average => (a + b) * 0.5, - CoefficientCombine::GeometricMean => (a * b).sqrt(), + CoefficientCombine::GeometricMean => math_ops::sqrt(a * b), CoefficientCombine::Min => a.min(b), CoefficientCombine::Multiply => a * b, CoefficientCombine::Max => a.max(b), diff --git a/src/dynamics/sleeping/mod.rs b/src/dynamics/sleeping/mod.rs index 5e33eac5..b87a5ee2 100644 --- a/src/dynamics/sleeping/mod.rs +++ b/src/dynamics/sleeping/mod.rs @@ -146,7 +146,7 @@ pub fn mark_sleeping_bodies( length_unit: Res, time: Res