From d84b56019a419e1b87a41b9ac7abd61a22d346d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Crozet?= Date: Sun, 28 Apr 2024 17:10:28 +0200 Subject: [PATCH] feat: remove cuda support --- CHANGELOG.md | 26 + crates/parry2d-f64/Cargo.toml | 4 - crates/parry2d/Cargo.toml | 4 - crates/parry3d-f64/Cargo.toml | 4 - crates/parry3d/Cargo.toml | 4 - src/bounding_volume/aabb.rs | 1 - src/bounding_volume/aabb_heightfield.rs | 4 +- .../bounding_sphere_heightfield.rs | 4 +- src/bounding_volume/simd_aabb.rs | 1 - src/partitioning/mod.rs | 7 +- src/partitioning/qbvh/mod.rs | 10 +- src/partitioning/qbvh/qbvh.rs | 108 +--- src/partitioning/qbvh/storage.rs | 38 -- src/partitioning/qbvh/traversal.rs | 33 +- src/partitioning/qbvh/traversal_no_std.rs | 187 ------- src/partitioning/qbvh/update/tests.rs | 7 +- .../closest_points_composite_shape_shape.rs | 10 +- .../distance_composite_shape_shape.rs | 8 +- ...intersection_test_composite_shape_shape.rs | 14 +- ...ar_time_of_impact_composite_shape_shape.rs | 9 +- src/query/point/point_composite_shape.rs | 14 +- src/query/point/point_heightfield.rs | 6 +- src/query/ray/ray.rs | 1 - src/query/ray/ray_composite_shape.rs | 5 +- src/query/ray/ray_heightfield.rs | 6 +- .../time_of_impact_composite_shape_shape.rs | 9 +- .../time_of_impact_heightfield_shape.rs | 17 +- src/shape/ball.rs | 1 - src/shape/capsule.rs | 1 - src/shape/composite_shape.rs | 11 +- src/shape/compound.rs | 2 - src/shape/cone.rs | 1 - src/shape/cuboid.rs | 1 - src/shape/cylinder.rs | 1 - src/shape/half_space.rs | 1 - src/shape/heightfield2.rs | 118 +---- src/shape/heightfield3.rs | 192 ++----- src/shape/mod.rs | 2 - src/shape/polyline.rs | 2 - src/shape/round_shape.rs | 1 - src/shape/segment.rs | 1 - src/shape/tetrahedron.rs | 1 - src/shape/triangle.rs | 1 - src/shape/trimesh.rs | 485 ++---------------- src/shape/trimesh_storage.rs | 75 --- .../to_outline/heightfield_to_outline.rs | 4 +- .../to_trimesh/heightfield_to_trimesh.rs | 4 +- src/utils/array.rs | 99 ---- src/utils/cuda_array.rs | 270 ---------- src/utils/cuda_device_pointer.rs | 33 -- src/utils/mod.rs | 15 - 51 files changed, 206 insertions(+), 1657 deletions(-) delete mode 100644 src/partitioning/qbvh/storage.rs delete mode 100644 src/partitioning/qbvh/traversal_no_std.rs delete mode 100644 src/shape/trimesh_storage.rs delete mode 100644 src/utils/array.rs delete mode 100644 src/utils/cuda_array.rs delete mode 100644 src/utils/cuda_device_pointer.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 74219da5..994ed3b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,31 @@ # Change Log +## Unreleased + +### Modified + +- Remove CUDA support to break free from the toolchain restriction required by cust. +- Rework internal edges resolution using normal cones. This implies the modification of the + `SimdCompositeShape::map_part_at`, `TypedSimdCompositeShape::map_typed_part`, and + `TypedSimdCompositeShape::map_untyped_part` trait functions so that the closure argument takes + an extra argument for the (optional) normal constraints. This argument can be safely ignored + by user code unless applying the normal collection is relevant to your use-case. +- Contact manifolds will now retain all contacts (including the ones further than the specified `prediction` + distance) whenever any contact is actually closer than this `prediction` distance. +- Typo fix: renamed `TopologyError::BadAdjascentTrianglesOrientation` to `BadAdjacentTrianglesOrientation`. + +### Fixed + +- Fix contacts between convex shapes being occasionally ignored due to some rounding errors. +- Remove crash when entering unreachable code in non-linear TOI calculation. +- Fix accuracy issue in triangle-mesh center-of-mass calculation when the mesh isn’t manifold. + +### Added + +- Add `SdpMatrix2::inverse_and_get_determinant_unchecked`. This is useful for computing the + inverse in a AoSoA SIMD setting. +- Add `Aabb::intersects_moving_aabb` to perform a swept test between two moving aabbs. + ## v0.13.7 ### Modified diff --git a/crates/parry2d-f64/Cargo.toml b/crates/parry2d-f64/Cargo.toml index 828e3614..c5b4ebfd 100644 --- a/crates/parry2d-f64/Cargo.toml +++ b/crates/parry2d-f64/Cargo.toml @@ -28,7 +28,6 @@ bytemuck-serialize = ["bytemuck", "nalgebra/convert-bytemuck"] simd-stable = ["simba/wide", "simd-is-enabled"] simd-nightly = ["simba/packed_simd", "simd-is-enabled"] enhanced-determinism = ["simba/libm_force", "indexmap"] -cuda = ["cust_core", "cust", "nalgebra/cuda"] parallel = ["rayon"] # Do not enable this feature directly. It is automatically @@ -62,9 +61,6 @@ rayon = { version = "1", optional = true } bytemuck = { version = "1", features = ["derive"], optional = true } log = "0.4" -[target.'cfg(not(target_os = "cuda"))'.dependencies] -cust = { version = "0.3", optional = true } - [dev-dependencies] simba = { version = "0.8", default-features = false, features = ["partial_fixed_point_support"] } oorandom = "11" diff --git a/crates/parry2d/Cargo.toml b/crates/parry2d/Cargo.toml index c01bfc96..88905f73 100644 --- a/crates/parry2d/Cargo.toml +++ b/crates/parry2d/Cargo.toml @@ -28,7 +28,6 @@ bytemuck-serialize = ["bytemuck", "nalgebra/convert-bytemuck"] simd-stable = ["simba/wide", "simd-is-enabled"] simd-nightly = ["simba/packed_simd", "simd-is-enabled"] enhanced-determinism = ["simba/libm_force", "indexmap"] -cuda = ["cust_core", "cust", "nalgebra/cuda"] parallel = ["rayon"] # Do not enable this feature directly. It is automatically @@ -62,9 +61,6 @@ rayon = { version = "1", optional = true } bytemuck = { version = "1", features = ["derive"], optional = true } log = "0.4" -[target.'cfg(not(target_os = "cuda"))'.dependencies] -cust = { version = "0.3", optional = true } - [dev-dependencies] simba = { version = "0.8", default-features = false, features = ["partial_fixed_point_support"] } oorandom = "11" diff --git a/crates/parry3d-f64/Cargo.toml b/crates/parry3d-f64/Cargo.toml index 0e0586d0..a245911f 100644 --- a/crates/parry3d-f64/Cargo.toml +++ b/crates/parry3d-f64/Cargo.toml @@ -28,7 +28,6 @@ bytemuck-serialize = ["bytemuck", "nalgebra/convert-bytemuck"] simd-stable = ["simba/wide", "simd-is-enabled"] simd-nightly = ["simba/packed_simd", "simd-is-enabled"] enhanced-determinism = ["simba/libm_force", "indexmap"] -cuda = ["cust_core", "cust", "nalgebra/cuda"] parallel = ["rayon"] # Do not enable this feature directly. It is automatically @@ -62,9 +61,6 @@ rayon = { version = "1", optional = true } bytemuck = { version = "1", features = ["derive"], optional = true } log = "0.4" -[target.'cfg(not(target_os = "cuda"))'.dependencies] -cust = { version = "0.3", optional = true } - [dev-dependencies] oorandom = "11" ptree = "0.4.0" diff --git a/crates/parry3d/Cargo.toml b/crates/parry3d/Cargo.toml index b9b9a65b..a6853ef9 100644 --- a/crates/parry3d/Cargo.toml +++ b/crates/parry3d/Cargo.toml @@ -29,7 +29,6 @@ bytemuck-serialize = ["bytemuck", "nalgebra/convert-bytemuck"] simd-stable = ["simba/wide", "simd-is-enabled"] simd-nightly = ["simba/packed_simd", "simd-is-enabled"] enhanced-determinism = ["simba/libm_force", "indexmap"] -cuda = ["cust_core", "cust", "nalgebra/cuda"] parallel = ["rayon"] # Do not enable this feature directly. It is automatically @@ -63,9 +62,6 @@ rayon = { version = "1", optional = true } bytemuck = { version = "1", features = ["derive"], optional = true } log = "0.4" -[target.'cfg(not(target_os = "cuda"))'.dependencies] -cust = { version = "0.3", optional = true } - [dev-dependencies] oorandom = "11" ptree = "0.4.0" diff --git a/src/bounding_volume/aabb.rs b/src/bounding_volume/aabb.rs index df0697c4..68c82d76 100644 --- a/src/bounding_volume/aabb.rs +++ b/src/bounding_volume/aabb.rs @@ -23,7 +23,6 @@ use rkyv::{bytecheck, CheckBytes}; derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize, CheckBytes), archive(as = "Self") )] -#[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] #[derive(Debug, PartialEq, Copy, Clone)] #[repr(C)] pub struct Aabb { diff --git a/src/bounding_volume/aabb_heightfield.rs b/src/bounding_volume/aabb_heightfield.rs index 6338a8f3..c97ae3ce 100644 --- a/src/bounding_volume/aabb_heightfield.rs +++ b/src/bounding_volume/aabb_heightfield.rs @@ -1,8 +1,8 @@ use crate::bounding_volume::Aabb; use crate::math::{Isometry, Real}; -use crate::shape::{GenericHeightField, HeightFieldStorage}; +use crate::shape::HeightField; -impl GenericHeightField { +impl HeightField { /// Computes the world-space [`Aabb`] of this heightfield, transformed by `pos`. #[inline] pub fn aabb(&self, pos: &Isometry) -> Aabb { diff --git a/src/bounding_volume/bounding_sphere_heightfield.rs b/src/bounding_volume/bounding_sphere_heightfield.rs index 21dd0a3b..714e369f 100644 --- a/src/bounding_volume/bounding_sphere_heightfield.rs +++ b/src/bounding_volume/bounding_sphere_heightfield.rs @@ -1,8 +1,8 @@ use crate::bounding_volume::BoundingSphere; use crate::math::{Isometry, Real}; -use crate::shape::{GenericHeightField, HeightFieldStorage}; +use crate::shape::HeightField; -impl GenericHeightField { +impl HeightField { /// Computes the world-space bounding sphere of this height-field, transformed by `pos`. #[inline] pub fn bounding_sphere(&self, pos: &Isometry) -> BoundingSphere { diff --git a/src/bounding_volume/simd_aabb.rs b/src/bounding_volume/simd_aabb.rs index 8ac51f2c..75bbfde7 100644 --- a/src/bounding_volume/simd_aabb.rs +++ b/src/bounding_volume/simd_aabb.rs @@ -12,7 +12,6 @@ use simba::simd::{SimdPartialOrd, SimdValue}; derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize), archive(check_bytes) )] -#[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] pub struct SimdAabb { /// The min coordinates of the Aabbs. pub mins: Point, diff --git a/src/partitioning/mod.rs b/src/partitioning/mod.rs index 48c03823..a02e4160 100644 --- a/src/partitioning/mod.rs +++ b/src/partitioning/mod.rs @@ -2,10 +2,8 @@ #[cfg(feature = "std")] pub use self::qbvh::{ - CenterDataSplitter, QbvhDataGenerator, QbvhNonOverlappingDataSplitter, QbvhUpdateWorkspace, -}; -pub use self::qbvh::{ - GenericQbvh, IndexedData, NodeIndex, Qbvh, QbvhNode, QbvhProxy, QbvhStorage, SimdNodeIndex, + CenterDataSplitter, IndexedData, NodeIndex, Qbvh, QbvhDataGenerator, QbvhNode, + QbvhNonOverlappingDataSplitter, QbvhProxy, QbvhUpdateWorkspace, SimdNodeIndex, }; #[cfg(feature = "parallel")] pub use self::visitor::{ParallelSimdSimultaneousVisitor, ParallelSimdVisitor}; @@ -18,5 +16,6 @@ pub use self::visitor::{ #[deprecated(note = "Renamed to Qbvh")] pub type SimdQbvh = Qbvh; +#[cfg(feature = "std")] mod qbvh; mod visitor; diff --git a/src/partitioning/qbvh/mod.rs b/src/partitioning/qbvh/mod.rs index 1995b25b..699f48f5 100644 --- a/src/partitioning/qbvh/mod.rs +++ b/src/partitioning/qbvh/mod.rs @@ -1,23 +1,15 @@ -#[cfg(feature = "std")] pub use self::{ build::{CenterDataSplitter, QbvhDataGenerator, QbvhNonOverlappingDataSplitter}, update::QbvhUpdateWorkspace, }; pub use self::qbvh::{ - GenericQbvh, IndexedData, NodeIndex, Qbvh, QbvhNode, QbvhNodeFlags, QbvhProxy, SimdNodeIndex, + IndexedData, NodeIndex, Qbvh, QbvhNode, QbvhNodeFlags, QbvhProxy, SimdNodeIndex, }; -pub use self::storage::QbvhStorage; mod qbvh; -mod storage; mod utils; -#[cfg(feature = "std")] mod build; -#[cfg(feature = "std")] mod traversal; -#[cfg(not(feature = "std"))] -mod traversal_no_std; -#[cfg(feature = "std")] mod update; diff --git a/src/partitioning/qbvh/qbvh.rs b/src/partitioning/qbvh/qbvh.rs index 3015c314..99913438 100644 --- a/src/partitioning/qbvh/qbvh.rs +++ b/src/partitioning/qbvh/qbvh.rs @@ -1,20 +1,11 @@ use crate::bounding_volume::{Aabb, SimdAabb}; use crate::math::{Real, Vector}; -use crate::partitioning::qbvh::storage::QbvhStorage; -use crate::utils::DefaultStorage; use bitflags::bitflags; use na::SimdValue; #[cfg(feature = "rkyv")] use rkyv::{bytecheck, CheckBytes}; -#[cfg(all(feature = "std", feature = "cuda"))] -use {crate::utils::CudaArray1, cust::error::CudaResult}; -#[cfg(feature = "cuda")] -use { - crate::utils::{CudaStorage, CudaStoragePtr}, - cust_core::DeviceCopy, -}; /// A data to which an index is associated. pub trait IndexedData: Copy { @@ -64,7 +55,6 @@ pub type SimdNodeIndex = u32; derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize, CheckBytes), archive(as = "Self") )] -#[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] /// The index of one specific node of a Qbvh. pub struct NodeIndex { /// The index of the SIMD node containing the addressed node. @@ -97,7 +87,6 @@ bitflags! { derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize), archive(as = "Self") )] - #[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] #[derive(Default)] /// The status of a QBVH node. pub struct QbvhNodeFlags: u8 { @@ -120,7 +109,6 @@ bitflags! { derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize), archive(check_bytes) )] -#[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] pub struct QbvhNode { /// The Aabbs of the qbvh nodes represented by this node. pub simd_aabb: SimdAabb, @@ -194,7 +182,6 @@ impl QbvhNode { derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize), archive(check_bytes) )] -#[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] /// Combination of a leaf data and its associated node’s index. pub struct QbvhProxy { /// Index of the leaf node the leaf data is associated to. @@ -235,86 +222,22 @@ impl QbvhProxy { derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize), archive(check_bytes) )] -#[repr(C)] // Needed for Cuda. -#[derive(Debug)] -pub struct GenericQbvh> { +#[repr(C)] +#[derive(Debug, Clone)] +pub struct Qbvh { pub(super) root_aabb: Aabb, - pub(super) nodes: Storage::Nodes, - pub(super) dirty_nodes: Storage::ArrayU32, - pub(super) free_list: Storage::ArrayU32, - pub(super) proxies: Storage::ArrayProxies, + pub(super) nodes: Vec, + pub(super) dirty_nodes: Vec, + pub(super) free_list: Vec, + pub(super) proxies: Vec>, } -/// A quaternary bounding-volume-hierarchy. -/// -/// This is a bounding-volume-hierarchy where each node has either four children or none. -pub type Qbvh = GenericQbvh; -#[cfg(feature = "cuda")] -/// A Qbvh stored in CUDA memory. -pub type CudaQbvh = GenericQbvh; -#[cfg(feature = "cuda")] -/// A Qbvh accessible from CUDA kernels. -pub type CudaQbvhPtr = GenericQbvh; - -impl Clone for GenericQbvh -where - Storage: QbvhStorage, - Storage::Nodes: Clone, - Storage::ArrayU32: Clone, - Storage::ArrayProxies: Clone, -{ - fn clone(&self) -> Self { - Self { - root_aabb: self.root_aabb, - nodes: self.nodes.clone(), - dirty_nodes: self.dirty_nodes.clone(), - free_list: self.free_list.clone(), - proxies: self.proxies.clone(), - } - } -} - -impl Copy for GenericQbvh -where - Storage: QbvhStorage, - Storage::Nodes: Copy, - Storage::ArrayU32: Copy, - Storage::ArrayProxies: Copy, -{ -} - -#[cfg(feature = "cuda")] -unsafe impl DeviceCopy for GenericQbvh -where - Storage: QbvhStorage, - Storage::Nodes: DeviceCopy, - Storage::ArrayU32: DeviceCopy, - Storage::ArrayProxies: DeviceCopy, -{ -} - -#[cfg(all(feature = "std", feature = "cuda"))] -impl CudaQbvh { - /// Returns the qbvh usable from within a CUDA kernel. - pub fn as_device_ptr(&self) -> CudaQbvhPtr { - GenericQbvh { - root_aabb: self.root_aabb, - nodes: self.nodes.as_device_ptr(), - dirty_nodes: self.dirty_nodes.as_device_ptr(), - free_list: self.free_list.as_device_ptr(), - proxies: self.proxies.as_device_ptr(), - } - } -} - -#[cfg(feature = "std")] impl Default for Qbvh { fn default() -> Self { Self::new() } } -#[cfg(feature = "std")] impl Qbvh { /// Initialize an empty Qbvh. pub fn new() -> Self { @@ -327,21 +250,6 @@ impl Qbvh { } } - /// Converts this RAM-based qbvh to an qbvh based on CUDA memory. - #[cfg(feature = "cuda")] - pub fn to_cuda(&self) -> CudaResult> - where - LeafData: DeviceCopy, - { - Ok(CudaQbvh { - root_aabb: self.root_aabb, - nodes: CudaArray1::new(&self.nodes)?, - dirty_nodes: CudaArray1::new(&self.dirty_nodes)?, - free_list: CudaArray1::new(&self.free_list)?, - proxies: CudaArray1::new(&self.proxies)?, - }) - } - /// Iterates mutably through all the leaf data in this Qbvh. pub fn iter_data_mut(&mut self) -> impl Iterator { self.proxies.iter_mut().map(|p| (p.node, &mut p.data)) @@ -405,7 +313,7 @@ impl Qbvh { } } -impl> GenericQbvh { +impl Qbvh { /// The Aabb of the root of this tree. pub fn root_aabb(&self) -> &Aabb { &self.root_aabb diff --git a/src/partitioning/qbvh/storage.rs b/src/partitioning/qbvh/storage.rs deleted file mode 100644 index d54176c0..00000000 --- a/src/partitioning/qbvh/storage.rs +++ /dev/null @@ -1,38 +0,0 @@ -use crate::partitioning::{QbvhNode, QbvhProxy}; -use crate::utils::{Array1, DefaultStorage}; - -#[cfg(all(feature = "std", feature = "cuda"))] -use crate::utils::CudaArray1; -#[cfg(feature = "cuda")] -use crate::utils::{CudaArrayPointer1, CudaStorage, CudaStoragePtr}; - -/// Trait describing all the types needed for storing a Qbvh’s data. -pub trait QbvhStorage { - /// Type of the array containing the Qbvh nodes. - type Nodes: Array1; - /// Type of an array containing u32. - type ArrayU32: Array1; - /// Type of the array containing the Qbvh leaves. - type ArrayProxies: Array1>; -} - -#[cfg(feature = "std")] -impl QbvhStorage for DefaultStorage { - type Nodes = Vec; - type ArrayU32 = Vec; - type ArrayProxies = Vec>; -} - -#[cfg(all(feature = "std", feature = "cuda"))] -impl QbvhStorage for CudaStorage { - type Nodes = CudaArray1; - type ArrayU32 = CudaArray1; - type ArrayProxies = CudaArray1>; -} - -#[cfg(feature = "cuda")] -impl QbvhStorage for CudaStoragePtr { - type Nodes = CudaArrayPointer1; - type ArrayU32 = CudaArrayPointer1; - type ArrayProxies = CudaArrayPointer1>; -} diff --git a/src/partitioning/qbvh/traversal.rs b/src/partitioning/qbvh/traversal.rs index dcdaf792..9e2407cb 100644 --- a/src/partitioning/qbvh/traversal.rs +++ b/src/partitioning/qbvh/traversal.rs @@ -4,11 +4,10 @@ use crate::bounding_volume::{Aabb, SimdAabb}; use crate::math::Real; use crate::partitioning::visitor::SimdSimultaneousVisitStatus; use crate::partitioning::{ - GenericQbvh, QbvhStorage, SimdBestFirstVisitStatus, SimdBestFirstVisitor, - SimdSimultaneousVisitor, SimdVisitStatus, SimdVisitor, + Qbvh, SimdBestFirstVisitStatus, SimdBestFirstVisitor, SimdSimultaneousVisitor, SimdVisitStatus, + SimdVisitor, }; use crate::simd::SIMD_WIDTH; -use crate::utils::Array1; use crate::utils::WeightedValue; use num::Bounded; use simba::simd::SimdBool; @@ -21,9 +20,9 @@ use { std::sync::atomic::{AtomicBool, Ordering as AtomicOrdering}, }; -use super::{IndexedData, NodeIndex, Qbvh}; +use super::{IndexedData, NodeIndex}; -impl> GenericQbvh { +impl Qbvh { /// Performs a depth-first traversal on the BVH. /// /// # Return @@ -79,7 +78,7 @@ impl> GenericQbvh> GenericQbvh> GenericQbvh> GenericQbvh> GenericQbvh> GenericQbvh> GenericQbvh> GenericQbvh Qbvh { let mut stack: ArrayVec = ArrayVec::new(); let node = &self.nodes[entry as usize]; let leaf_data = if node.is_leaf() { - Some( - array![|ii| Some(&self.proxies.get_at(node.children[ii] as usize)?.data); SIMD_WIDTH], - ) + Some(array![|ii| Some(&self.proxies.get(node.children[ii] as usize)?.data); SIMD_WIDTH]) } else { None }; @@ -542,7 +539,7 @@ impl Qbvh { let leaf_data1 = if node1.is_leaf() { Some( - array![|ii| Some(&qbvh1.proxies.get_at(node1.children[ii] as usize)?.data); SIMD_WIDTH], + array![|ii| Some(&qbvh1.proxies.get(node1.children[ii] as usize)?.data); SIMD_WIDTH], ) } else { None @@ -550,7 +547,7 @@ impl Qbvh { let leaf_data2 = if node2.is_leaf() { Some( - array![|ii| Some(&qbvh2.proxies.get_at(node2.children[ii] as usize)?.data); SIMD_WIDTH], + array![|ii| Some(&qbvh2.proxies.get(node2.children[ii] as usize)?.data); SIMD_WIDTH], ) } else { None diff --git a/src/partitioning/qbvh/traversal_no_std.rs b/src/partitioning/qbvh/traversal_no_std.rs deleted file mode 100644 index aea894ce..00000000 --- a/src/partitioning/qbvh/traversal_no_std.rs +++ /dev/null @@ -1,187 +0,0 @@ -use crate::bounding_volume::{Aabb, SimdAabb}; -use crate::math::Real; -use crate::partitioning::visitor::SimdSimultaneousVisitStatus; -use crate::partitioning::{ - GenericQbvh, QbvhStorage, SimdBestFirstVisitStatus, SimdBestFirstVisitor, - SimdSimultaneousVisitor, SimdVisitStatus, SimdVisitor, -}; -use crate::simd::SIMD_WIDTH; -use crate::utils::{Array1, WeightedValue}; -use arrayvec::ArrayVec; -use num::Bounded; -use simba::simd::SimdBool; - -use super::{IndexedData, NodeIndex, Qbvh}; - -impl> GenericQbvh { - /// Performs a depth-first traversal on the BVH. - /// - /// # Return - /// - /// Returns `false` if the traversal exited early, and `true` otherwise. - pub fn traverse_depth_first(&self, visitor: &mut impl SimdVisitor) -> bool { - self.traverse_depth_first_node(visitor, 0) - } - - /// Performs a depth-first traversal on the BVH starting at the given node. - /// - /// # Return - /// - /// Returns `false` if the traversal exited early, and `true` otherwise. - pub fn traverse_depth_first_node( - &self, - visitor: &mut impl SimdVisitor, - curr_node: u32, - ) -> bool { - let node = &self.nodes[curr_node as usize]; - let leaf_data = if node.is_leaf() { - Some( - array![|ii| Some(&self.proxies.get_at(node.children[ii] as usize)?.data); SIMD_WIDTH], - ) - } else { - None - }; - - match visitor.visit(&node.simd_aabb, leaf_data) { - SimdVisitStatus::ExitEarly => { - return false; - } - SimdVisitStatus::MaybeContinue(mask) => { - let bitmask = mask.bitmask(); - - for ii in 0..SIMD_WIDTH { - if (bitmask & (1 << ii)) != 0 { - if !node.is_leaf() { - // Internal node, visit the child. - // Unfortunately, we have this check because invalid Aabbs - // return a hit as well. - if node.children[ii] as usize <= self.nodes.len() { - if !self.traverse_depth_first_node(visitor, node.children[ii]) { - return false; - } - } - } - } - } - } - } - - true - } - - /// Performs a best-first-search on the BVH. - /// - /// Returns the content of the leaf with the smallest associated cost, and a result of - /// user-defined type. - pub fn traverse_best_first(&self, visitor: &mut BFS) -> Option<(NodeIndex, BFS::Result)> - where - BFS: SimdBestFirstVisitor, - BFS::Result: Clone, // Because we cannot move out of an array… - { - self.traverse_best_first_node(visitor, 0, Real::MAX) - } - - /// Performs a best-first-search on the BVH. - /// - /// Returns the content of the leaf with the smallest associated cost, and a result of - /// user-defined type. - pub fn traverse_best_first_node( - &self, - visitor: &mut BFS, - start_node: u32, - init_cost: Real, - ) -> Option<(NodeIndex, BFS::Result)> - where - BFS: SimdBestFirstVisitor, - BFS::Result: Clone, // Because we cannot move out of an array… - { - if self.nodes.is_empty() { - return None; - } - - let mut best_cost = init_cost; - let mut result = None; - - // NOTE: a stack with 64 elements is enough for a depth-first search - // on a tree with up to about 4.000.000.000 triangles. - // See https://math.stackexchange.com/a/2739663 for the max - // stack depth on a depth-first search. - let mut stack: ArrayVec<_, 64> = ArrayVec::new(); - stack.push(WeightedValue::new(start_node, -best_cost / 2.0)); - - self.traverse_best_first_node_recursive(visitor, &mut stack, &mut best_cost, &mut result); - result - } - - fn traverse_best_first_node_recursive( - &self, - visitor: &mut BFS, - stack: &mut ArrayVec, 64>, - best_cost: &mut Real, - best_result: &mut Option<(NodeIndex, BFS::Result)>, - ) where - BFS: SimdBestFirstVisitor, - BFS::Result: Clone, // Because we cannot move out of an array… - { - while let Some(entry) = stack.pop() { - // NOTE: since we are not actually allowed to allocate, we can’t use the binary heap. - // So we are really just running a recursive depth-first traversal, with early - // exit on the current best cost. - if -entry.cost >= *best_cost { - continue; - } - - let node = &self.nodes[entry.value as usize]; - let leaf_data = if node.is_leaf() { - Some( - array![|ii| Some(&self.proxies.get_at(node.children[ii] as usize)?.data); SIMD_WIDTH], - ) - } else { - None - }; - - match visitor.visit(*best_cost, &node.simd_aabb, leaf_data) { - SimdBestFirstVisitStatus::ExitEarly(result) => { - if result.is_some() { - *best_result = result.map(|r| (node.parent, r)); - return; - } - } - SimdBestFirstVisitStatus::MaybeContinue { - weights, - mask, - results, - } => { - let bitmask = mask.bitmask(); - let weights: [Real; SIMD_WIDTH] = weights.into(); - - for ii in 0..SIMD_WIDTH { - if (bitmask & (1 << ii)) != 0 { - if node.is_leaf() { - if weights[ii] < *best_cost && results[ii].is_some() { - // We found a leaf! - if let Some(proxy) = - self.proxies.get_at(node.children[ii] as usize) - { - *best_cost = weights[ii]; - *best_result = - Some((proxy.node, results[ii].clone().unwrap())) - } - } - } else { - // Internal node, visit the child. - // Unfortunately, we have this check because invalid Aabbs - // return a hit as well. - if (node.children[ii] as usize) < self.nodes.len() { - let child_node = - WeightedValue::new(node.children[ii], -weights[ii]); - stack.push(child_node); - } - } - } - } - } - } - } - } -} diff --git a/src/partitioning/qbvh/update/tests.rs b/src/partitioning/qbvh/update/tests.rs index 36ce24bd..2f122b5d 100644 --- a/src/partitioning/qbvh/update/tests.rs +++ b/src/partitioning/qbvh/update/tests.rs @@ -4,8 +4,7 @@ use std::borrow::Cow; use crate::{ bounding_volume::Aabb, math::{Point, Real}, - partitioning::{GenericQbvh, Qbvh}, - utils::DefaultStorage, + partitioning::Qbvh, }; use super::QbvhUpdateWorkspace; @@ -323,14 +322,14 @@ impl<'q> ptree::TreeItem for QbvhTreeIterator<'q> { #[derive(Clone)] struct QbvhTreeIterator<'q> { - qbvh: &'q GenericQbvh, + qbvh: &'q Qbvh, node: u32, aabb: Aabb, child_of_leaf: bool, } impl<'q> QbvhTreeIterator<'q> { - fn new(qbvh: &'q GenericQbvh) -> Self { + fn new(qbvh: &'q Qbvh) -> Self { let aabb = *qbvh.root_aabb(); let child_of_leaf = qbvh.raw_nodes().is_empty(); diff --git a/src/query/closest_points/closest_points_composite_shape_shape.rs b/src/query/closest_points/closest_points_composite_shape_shape.rs index eaa350b2..85220a94 100644 --- a/src/query/closest_points/closest_points_composite_shape_shape.rs +++ b/src/query/closest_points/closest_points_composite_shape_shape.rs @@ -3,7 +3,7 @@ use crate::math::{Isometry, Real, SimdBool, SimdReal, Vector, SIMD_WIDTH}; use crate::partitioning::{SimdBestFirstVisitStatus, SimdBestFirstVisitor}; use crate::query::{ClosestPoints, QueryDispatcher}; use crate::shape::{Shape, TypedSimdCompositeShape}; -use crate::utils::{DefaultStorage, IsometryOpt}; +use crate::utils::IsometryOpt; use na; use simba::simd::{SimdBool as _, SimdPartialOrd, SimdValue}; @@ -17,7 +17,7 @@ pub fn closest_points_composite_shape_shape( ) -> ClosestPoints where D: QueryDispatcher, - G1: TypedSimdCompositeShape, + G1: TypedSimdCompositeShape, { let mut visitor = CompositeShapeAgainstShapeClosestPointsVisitor::new(dispatcher, pos12, g1, g2, margin); @@ -39,7 +39,7 @@ pub fn closest_points_shape_composite_shape( ) -> ClosestPoints where D: QueryDispatcher, - G2: TypedSimdCompositeShape, + G2: TypedSimdCompositeShape, { closest_points_composite_shape_shape(dispatcher, &pos12.inverse(), g2, g1, margin).flipped() } @@ -59,7 +59,7 @@ pub struct CompositeShapeAgainstShapeClosestPointsVisitor<'a, D: ?Sized, G1: ?Si impl<'a, D: ?Sized, G1: ?Sized> CompositeShapeAgainstShapeClosestPointsVisitor<'a, D, G1> where D: QueryDispatcher, - G1: TypedSimdCompositeShape, + G1: TypedSimdCompositeShape, { /// Initializes a visitor for computing the closest points between a composite-shape and a shape. pub fn new( @@ -87,7 +87,7 @@ impl<'a, D: ?Sized, G1: ?Sized> SimdBestFirstVisitor for CompositeShapeAgainstShapeClosestPointsVisitor<'a, D, G1> where D: QueryDispatcher, - G1: TypedSimdCompositeShape, + G1: TypedSimdCompositeShape, { type Result = (G1::PartId, ClosestPoints); diff --git a/src/query/distance/distance_composite_shape_shape.rs b/src/query/distance/distance_composite_shape_shape.rs index ebc86fc8..7e65916b 100644 --- a/src/query/distance/distance_composite_shape_shape.rs +++ b/src/query/distance/distance_composite_shape_shape.rs @@ -3,7 +3,7 @@ use crate::math::{Isometry, Real, SimdBool, SimdReal, Vector, SIMD_WIDTH}; use crate::partitioning::{SimdBestFirstVisitStatus, SimdBestFirstVisitor}; use crate::query::QueryDispatcher; use crate::shape::{Shape, TypedSimdCompositeShape}; -use crate::utils::{DefaultStorage, IsometryOpt}; +use crate::utils::IsometryOpt; use simba::simd::{SimdBool as _, SimdPartialOrd, SimdValue}; /// Smallest distance between a composite shape and any other shape. @@ -15,7 +15,7 @@ pub fn distance_composite_shape_shape( ) -> Real where D: QueryDispatcher, - G1: TypedSimdCompositeShape, + G1: TypedSimdCompositeShape, { let mut visitor = CompositeShapeAgainstAnyDistanceVisitor::new(dispatcher, pos12, g1, g2); g1.typed_qbvh() @@ -34,7 +34,7 @@ pub fn distance_shape_composite_shape( ) -> Real where D: QueryDispatcher, - G2: TypedSimdCompositeShape, + G2: TypedSimdCompositeShape, { distance_composite_shape_shape(dispatcher, &pos12.inverse(), g2, g1) } @@ -75,7 +75,7 @@ impl<'a, D: ?Sized, G1: ?Sized> SimdBestFirstVisitor for CompositeShapeAgainstAnyDistanceVisitor<'a, D, G1> where D: QueryDispatcher, - G1: TypedSimdCompositeShape, + G1: TypedSimdCompositeShape, { type Result = (G1::PartId, Real); diff --git a/src/query/intersection_test/intersection_test_composite_shape_shape.rs b/src/query/intersection_test/intersection_test_composite_shape_shape.rs index 09382541..04779327 100644 --- a/src/query/intersection_test/intersection_test_composite_shape_shape.rs +++ b/src/query/intersection_test/intersection_test_composite_shape_shape.rs @@ -7,7 +7,7 @@ use crate::partitioning::{ }; use crate::query::QueryDispatcher; use crate::shape::{Shape, TypedSimdCompositeShape}; -use crate::utils::{DefaultStorage, IsometryOpt}; +use crate::utils::IsometryOpt; use simba::simd::{SimdBool as _, SimdPartialOrd, SimdValue}; /// Intersection test between a composite shape (`Mesh`, `Compound`) and any other shape. @@ -19,7 +19,7 @@ pub fn intersection_test_composite_shape_shape( ) -> bool where D: QueryDispatcher, - G1: TypedSimdCompositeShape, + G1: TypedSimdCompositeShape, { let mut visitor = IntersectionCompositeShapeShapeVisitor::new(dispatcher, pos12, g1, g2); @@ -36,7 +36,7 @@ pub fn intersection_test_shape_composite_shape( ) -> bool where D: QueryDispatcher, - G2: TypedSimdCompositeShape, + G2: TypedSimdCompositeShape, { intersection_test_composite_shape_shape(dispatcher, &pos12.inverse(), g2, g1) } @@ -56,7 +56,7 @@ pub struct IntersectionCompositeShapeShapeVisitor<'a, D: ?Sized, G1: ?Sized + 'a impl<'a, D: ?Sized, G1: ?Sized> IntersectionCompositeShapeShapeVisitor<'a, D, G1> where D: QueryDispatcher, - G1: TypedSimdCompositeShape, + G1: TypedSimdCompositeShape, { /// Initialize a visitor for checking if a composite-shape and a shape intersect. pub fn new( @@ -82,7 +82,7 @@ impl<'a, D: ?Sized, G1: ?Sized> SimdVisitor for IntersectionCompositeShapeShapeVisitor<'a, D, G1> where D: QueryDispatcher, - G1: TypedSimdCompositeShape, + G1: TypedSimdCompositeShape, { fn visit( &mut self, @@ -134,7 +134,7 @@ pub struct IntersectionCompositeShapeShapeBestFirstVisitor<'a, D: ?Sized, G1: ?S impl<'a, D: ?Sized, G1: ?Sized> IntersectionCompositeShapeShapeBestFirstVisitor<'a, D, G1> where D: QueryDispatcher, - G1: TypedSimdCompositeShape, + G1: TypedSimdCompositeShape, { /// Initialize a visitor for checking if a composite-shape and a shape intersect. pub fn new( @@ -160,7 +160,7 @@ impl<'a, D: ?Sized, G1: ?Sized> SimdBestFirstVisitor for IntersectionCompositeShapeShapeBestFirstVisitor<'a, D, G1> where D: QueryDispatcher, - G1: TypedSimdCompositeShape, + G1: TypedSimdCompositeShape, { type Result = (G1::PartId, bool); diff --git a/src/query/nonlinear_time_of_impact/nonlinear_time_of_impact_composite_shape_shape.rs b/src/query/nonlinear_time_of_impact/nonlinear_time_of_impact_composite_shape_shape.rs index 46d2e1fd..5a337d67 100644 --- a/src/query/nonlinear_time_of_impact/nonlinear_time_of_impact_composite_shape_shape.rs +++ b/src/query/nonlinear_time_of_impact/nonlinear_time_of_impact_composite_shape_shape.rs @@ -3,7 +3,6 @@ use crate::math::{Real, SimdBool, SimdReal, SIMD_WIDTH}; use crate::partitioning::{SimdBestFirstVisitStatus, SimdBestFirstVisitor}; use crate::query::{self, details::NonlinearTOIMode, NonlinearRigidMotion, QueryDispatcher, TOI}; use crate::shape::{Ball, Shape, TypedSimdCompositeShape}; -use crate::utils::DefaultStorage; use simba::simd::SimdValue; /// Time Of Impact of a composite shape with any other shape, under a rigid motion (translation + rotation). @@ -19,7 +18,7 @@ pub fn nonlinear_time_of_impact_composite_shape_shape( ) -> Option where D: QueryDispatcher, - G1: TypedSimdCompositeShape, + G1: TypedSimdCompositeShape, { let mut visitor = NonlinearTOICompositeShapeShapeBestFirstVisitor::new( dispatcher, @@ -50,7 +49,7 @@ pub fn nonlinear_time_of_impact_shape_composite_shape( ) -> Option where D: QueryDispatcher, - G2: TypedSimdCompositeShape, + G2: TypedSimdCompositeShape, { nonlinear_time_of_impact_composite_shape_shape( dispatcher, @@ -82,7 +81,7 @@ pub struct NonlinearTOICompositeShapeShapeBestFirstVisitor<'a, D: ?Sized, G1: ?S impl<'a, D: ?Sized, G1: ?Sized> NonlinearTOICompositeShapeShapeBestFirstVisitor<'a, D, G1> where D: QueryDispatcher, - G1: TypedSimdCompositeShape, + G1: TypedSimdCompositeShape, { /// Initializes visitor used to determine the non-linear time of impact between /// a composite shape and another shape. @@ -114,7 +113,7 @@ impl<'a, D: ?Sized, G1: ?Sized> SimdBestFirstVisitor for NonlinearTOICompositeShapeShapeBestFirstVisitor<'a, D, G1> where D: QueryDispatcher, - G1: TypedSimdCompositeShape, + G1: TypedSimdCompositeShape, { type Result = (G1::PartId, TOI); diff --git a/src/query/point/point_composite_shape.rs b/src/query/point/point_composite_shape.rs index 0dea0798..502d5d50 100644 --- a/src/query/point/point_composite_shape.rs +++ b/src/query/point/point_composite_shape.rs @@ -6,15 +6,11 @@ use crate::partitioning::{SimdBestFirstVisitStatus, SimdBestFirstVisitor}; use crate::query::visitors::CompositePointContainmentTest; use crate::query::{PointProjection, PointQuery, PointQueryWithLocation}; use crate::shape::{ - FeatureId, GenericTriMesh, SegmentPointLocation, TriMeshStorage, TrianglePointLocation, - TypedSimdCompositeShape, + FeatureId, SegmentPointLocation, TriMesh, TrianglePointLocation, TypedSimdCompositeShape, }; use na; use simba::simd::{SimdBool as _, SimdPartialOrd, SimdValue}; -#[cfg(feature = "dim3")] -use crate::utils::Array1; - #[cfg(feature = "std")] use crate::shape::{Compound, Polyline}; @@ -48,7 +44,7 @@ impl PointQuery for Polyline { } } -impl PointQuery for GenericTriMesh { +impl PointQuery for TriMesh { #[inline] fn project_local_point(&self, point: &Point, solid: bool) -> PointProjection { self.project_local_point_and_get_location(point, solid).0 @@ -144,7 +140,7 @@ impl PointQueryWithLocation for Polyline { } } -impl PointQueryWithLocation for GenericTriMesh { +impl PointQueryWithLocation for TriMesh { type Location = (u32, TrianglePointLocation); #[inline] @@ -181,13 +177,13 @@ impl PointQueryWithLocation for GenericTriMesh } TrianglePointLocation::OnEdge(i, _) => pseudo_normals .edges_pseudo_normal - .get_at(part_id as usize) + .get(part_id as usize) .map(|pn| pn[i as usize]), TrianglePointLocation::OnVertex(i) => { let idx = self.indices()[part_id as usize]; pseudo_normals .vertices_pseudo_normal - .get_at(idx[i as usize] as usize) + .get(idx[i as usize] as usize) .copied() } }; diff --git a/src/query/point/point_heightfield.rs b/src/query/point/point_heightfield.rs index 10c1da3e..25507d24 100644 --- a/src/query/point/point_heightfield.rs +++ b/src/query/point/point_heightfield.rs @@ -1,11 +1,11 @@ use crate::bounding_volume::Aabb; use crate::math::{Point, Real, Vector}; use crate::query::{PointProjection, PointQuery, PointQueryWithLocation}; -use crate::shape::{FeatureId, GenericHeightField, HeightFieldStorage, TrianglePointLocation}; +use crate::shape::{FeatureId, HeightField, TrianglePointLocation}; #[cfg(not(feature = "std"))] use na::ComplexField; // For sqrt. -impl PointQuery for GenericHeightField { +impl PointQuery for HeightField { fn project_local_point_with_max_dist( &self, pt: &Point, @@ -71,7 +71,7 @@ impl PointQuery for GenericHeightField { } } -impl PointQueryWithLocation for GenericHeightField { +impl PointQueryWithLocation for HeightField { type Location = (usize, TrianglePointLocation); #[inline] diff --git a/src/query/ray/ray.rs b/src/query/ray/ray.rs index 7efe94ac..e6a4adc2 100644 --- a/src/query/ray/ray.rs +++ b/src/query/ray/ray.rs @@ -14,7 +14,6 @@ use rkyv::{bytecheck, CheckBytes}; derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize, CheckBytes), archive(as = "Self") )] -#[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] #[repr(C)] pub struct Ray { /// Starting point of the ray. diff --git a/src/query/ray/ray_composite_shape.rs b/src/query/ray/ray_composite_shape.rs index 18a54aee..06188d0f 100644 --- a/src/query/ray/ray_composite_shape.rs +++ b/src/query/ray/ray_composite_shape.rs @@ -3,7 +3,6 @@ use crate::math::{Real, SimdBool, SimdReal, SIMD_WIDTH}; use crate::partitioning::{SimdBestFirstVisitStatus, SimdBestFirstVisitor}; use crate::query::{Ray, RayCast, RayIntersection, SimdRay}; use crate::shape::{Compound, FeatureId, Polyline, TriMesh, TypedSimdCompositeShape}; -use crate::utils::DefaultStorage; use simba::simd::{SimdBool as _, SimdPartialOrd, SimdValue}; impl RayCast for TriMesh { @@ -121,7 +120,7 @@ impl<'a, S> RayCompositeShapeToiBestFirstVisitor<'a, S> { impl<'a, S> SimdBestFirstVisitor for RayCompositeShapeToiBestFirstVisitor<'a, S> where - S: TypedSimdCompositeShape, + S: TypedSimdCompositeShape, { type Result = (S::PartId, Real); @@ -201,7 +200,7 @@ impl<'a, S> RayCompositeShapeToiAndNormalBestFirstVisitor<'a, S> { impl<'a, S> SimdBestFirstVisitor for RayCompositeShapeToiAndNormalBestFirstVisitor<'a, S> where - S: TypedSimdCompositeShape, + S: TypedSimdCompositeShape, { type Result = (S::PartId, RayIntersection); diff --git a/src/query/ray/ray_heightfield.rs b/src/query/ray/ray_heightfield.rs index cfd80eee..da313acb 100644 --- a/src/query/ray/ray_heightfield.rs +++ b/src/query/ray/ray_heightfield.rs @@ -4,10 +4,10 @@ use crate::query; use crate::query::{Ray, RayCast, RayIntersection}; #[cfg(feature = "dim2")] use crate::shape::FeatureId; -use crate::shape::{GenericHeightField, HeightFieldStorage}; +use crate::shape::HeightField; #[cfg(feature = "dim2")] -impl RayCast for GenericHeightField { +impl RayCast for HeightField { #[inline] fn cast_local_ray_and_get_normal( &self, @@ -119,7 +119,7 @@ impl RayCast for GenericHeightField { } #[cfg(feature = "dim3")] -impl RayCast for GenericHeightField { +impl RayCast for HeightField { #[inline] fn cast_local_ray_and_get_normal( &self, diff --git a/src/query/time_of_impact/time_of_impact_composite_shape_shape.rs b/src/query/time_of_impact/time_of_impact_composite_shape_shape.rs index 960a241b..420365a3 100644 --- a/src/query/time_of_impact/time_of_impact_composite_shape_shape.rs +++ b/src/query/time_of_impact/time_of_impact_composite_shape_shape.rs @@ -3,7 +3,6 @@ use crate::math::{Isometry, Point, Real, SimdBool, SimdReal, Vector, SIMD_WIDTH} use crate::partitioning::{SimdBestFirstVisitStatus, SimdBestFirstVisitor}; use crate::query::{QueryDispatcher, Ray, SimdRay, TOI}; use crate::shape::{Shape, TypedSimdCompositeShape}; -use crate::utils::DefaultStorage; use simba::simd::{SimdBool as _, SimdPartialOrd, SimdValue}; /// Time Of Impact of a composite shape with any other shape, under translational movement. @@ -18,7 +17,7 @@ pub fn time_of_impact_composite_shape_shape( ) -> Option where D: QueryDispatcher, - G1: TypedSimdCompositeShape, + G1: TypedSimdCompositeShape, { let mut visitor = TOICompositeShapeShapeBestFirstVisitor::new( dispatcher, @@ -46,7 +45,7 @@ pub fn time_of_impact_shape_composite_shape( ) -> Option where D: QueryDispatcher, - G2: TypedSimdCompositeShape, + G2: TypedSimdCompositeShape, { time_of_impact_composite_shape_shape( dispatcher, @@ -78,7 +77,7 @@ pub struct TOICompositeShapeShapeBestFirstVisitor<'a, D: ?Sized, G1: ?Sized + 'a impl<'a, D: ?Sized, G1: ?Sized> TOICompositeShapeShapeBestFirstVisitor<'a, D, G1> where D: QueryDispatcher, - G1: TypedSimdCompositeShape, + G1: TypedSimdCompositeShape, { /// Creates a new visitor used to find the time-of-impact between a composite shape and a shape. pub fn new( @@ -112,7 +111,7 @@ impl<'a, D: ?Sized, G1: ?Sized> SimdBestFirstVisitor for TOICompositeShapeShapeBestFirstVisitor<'a, D, G1> where D: QueryDispatcher, - G1: TypedSimdCompositeShape, + G1: TypedSimdCompositeShape, { type Result = (G1::PartId, TOI); diff --git a/src/query/time_of_impact/time_of_impact_heightfield_shape.rs b/src/query/time_of_impact/time_of_impact_heightfield_shape.rs index 92611b4b..c48eda35 100644 --- a/src/query/time_of_impact/time_of_impact_heightfield_shape.rs +++ b/src/query/time_of_impact/time_of_impact_heightfield_shape.rs @@ -1,22 +1,21 @@ use crate::math::{Isometry, Real, Vector}; use crate::query::{QueryDispatcher, Ray, Unsupported, TOI}; -use crate::shape::{GenericHeightField, HeightFieldStorage, Shape}; +use crate::shape::{HeightField, Shape}; #[cfg(feature = "dim3")] use crate::{bounding_volume::Aabb, query::RayCast}; /// Time Of Impact between a moving shape and a heightfield. #[cfg(feature = "dim2")] -pub fn time_of_impact_heightfield_shape( +pub fn time_of_impact_heightfield_shape( dispatcher: &D, pos12: &Isometry, vel12: &Vector, - heightfield1: &GenericHeightField, + heightfield1: &HeightField, g2: &dyn Shape, max_toi: Real, stop_at_penetration: bool, ) -> Result, Unsupported> where - Storage: HeightFieldStorage, D: QueryDispatcher, { let aabb2_1 = g2.compute_aabb(pos12); @@ -104,17 +103,16 @@ where /// Time Of Impact between a moving shape and a heightfield. #[cfg(feature = "dim3")] -pub fn time_of_impact_heightfield_shape( +pub fn time_of_impact_heightfield_shape( dispatcher: &D, pos12: &Isometry, vel12: &Vector, - heightfield1: &GenericHeightField, + heightfield1: &HeightField, g2: &dyn Shape, max_toi: Real, stop_at_penetration: bool, ) -> Result, Unsupported> where - Storage: HeightFieldStorage, D: QueryDispatcher, { let aabb1 = heightfield1.local_aabb(); @@ -279,17 +277,16 @@ where } /// Time Of Impact between a moving shape and a heightfield. -pub fn time_of_impact_shape_heightfield( +pub fn time_of_impact_shape_heightfield( dispatcher: &D, pos12: &Isometry, vel12: &Vector, g1: &dyn Shape, - heightfield2: &GenericHeightField, + heightfield2: &HeightField, max_toi: Real, stop_at_penetration: bool, ) -> Result, Unsupported> where - Storage: HeightFieldStorage, D: QueryDispatcher, { Ok(time_of_impact_heightfield_shape( diff --git a/src/shape/ball.rs b/src/shape/ball.rs index 7d2a9220..677246ab 100644 --- a/src/shape/ball.rs +++ b/src/shape/ball.rs @@ -13,7 +13,6 @@ use crate::shape::SupportMap; derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize), archive(check_bytes) )] -#[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] #[derive(PartialEq, Debug, Copy, Clone)] #[repr(C)] pub struct Ball { diff --git a/src/shape/capsule.rs b/src/shape/capsule.rs index 54b595e4..357e2571 100644 --- a/src/shape/capsule.rs +++ b/src/shape/capsule.rs @@ -16,7 +16,6 @@ use rkyv::{bytecheck, CheckBytes}; derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize, CheckBytes), archive(as = "Self") )] -#[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] #[repr(C)] /// A capsule shape defined as a round segment. pub struct Capsule { diff --git a/src/shape/composite_shape.rs b/src/shape/composite_shape.rs index 1598c8e9..6a5aa9bb 100644 --- a/src/shape/composite_shape.rs +++ b/src/shape/composite_shape.rs @@ -1,8 +1,7 @@ use crate::math::{Isometry, Real}; -use crate::partitioning::{GenericQbvh, IndexedData, Qbvh, QbvhStorage}; +use crate::partitioning::{IndexedData, Qbvh}; use crate::query::details::NormalConstraints; use crate::shape::Shape; -use crate::utils::DefaultStorage; /// Trait implemented by shapes composed of multiple simpler shapes. /// @@ -25,7 +24,6 @@ pub trait TypedSimdCompositeShape { type PartShape: ?Sized + Shape; type PartNormalConstraints: ?Sized + NormalConstraints; type PartId: IndexedData; - type QbvhStorage: QbvhStorage; fn map_typed_part_at( &self, @@ -35,14 +33,14 @@ pub trait TypedSimdCompositeShape { // TODO: we need this method because the compiler won't want // to cast `&Self::PartShape` to `&dyn Shape` because it complains - // that `PairtShape` is not `Sized`. + // that `PartShape` is not `Sized`. fn map_untyped_part_at( &self, shape_id: Self::PartId, f: impl FnMut(Option<&Isometry>, &dyn Shape, Option<&dyn NormalConstraints>), ); - fn typed_qbvh(&self) -> &GenericQbvh; + fn typed_qbvh(&self) -> &Qbvh; } #[cfg(feature = "std")] @@ -50,7 +48,6 @@ impl<'a> TypedSimdCompositeShape for dyn SimdCompositeShape + 'a { type PartShape = dyn Shape; type PartNormalConstraints = dyn NormalConstraints; type PartId = u32; - type QbvhStorage = DefaultStorage; fn map_typed_part_at( &self, @@ -72,7 +69,7 @@ impl<'a> TypedSimdCompositeShape for dyn SimdCompositeShape + 'a { self.map_part_at(shape_id, &mut f) } - fn typed_qbvh(&self) -> &GenericQbvh { + fn typed_qbvh(&self) -> &Qbvh { self.qbvh() } } diff --git a/src/shape/compound.rs b/src/shape/compound.rs index 718e09c6..7be11a95 100644 --- a/src/shape/compound.rs +++ b/src/shape/compound.rs @@ -11,7 +11,6 @@ use crate::shape::{ConvexPolygon, TriMesh, Triangle}; use crate::shape::{Shape, SharedShape, SimdCompositeShape, TypedSimdCompositeShape}; #[cfg(feature = "dim2")] use crate::transformation::hertel_mehlhorn; -use crate::utils::DefaultStorage; /// A compound shape with an aabb bounding volume. /// @@ -144,7 +143,6 @@ impl TypedSimdCompositeShape for Compound { type PartShape = dyn Shape; type PartNormalConstraints = (); type PartId = u32; - type QbvhStorage = DefaultStorage; #[inline(always)] fn map_typed_part_at( diff --git a/src/shape/cone.rs b/src/shape/cone.rs index 8cead502..beeabb6a 100644 --- a/src/shape/cone.rs +++ b/src/shape/cone.rs @@ -22,7 +22,6 @@ use rkyv::{bytecheck, CheckBytes}; derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize, CheckBytes), archive(as = "Self") )] -#[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] #[derive(PartialEq, Debug, Copy, Clone)] #[repr(C)] pub struct Cone { diff --git a/src/shape/cuboid.rs b/src/shape/cuboid.rs index 835020b6..ef922e3a 100644 --- a/src/shape/cuboid.rs +++ b/src/shape/cuboid.rs @@ -21,7 +21,6 @@ use rkyv::{bytecheck, CheckBytes}; derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize, CheckBytes), archive(as = "Self") )] -#[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] #[derive(PartialEq, Debug, Copy, Clone)] #[repr(C)] pub struct Cuboid { diff --git a/src/shape/cylinder.rs b/src/shape/cylinder.rs index c9905fd0..2c1e514e 100644 --- a/src/shape/cylinder.rs +++ b/src/shape/cylinder.rs @@ -22,7 +22,6 @@ use rkyv::{bytecheck, CheckBytes}; derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize, CheckBytes), archive(as = "Self") )] -#[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] #[derive(PartialEq, Debug, Copy, Clone)] #[repr(C)] pub struct Cylinder { diff --git a/src/shape/half_space.rs b/src/shape/half_space.rs index 0dda578e..cdcbf50a 100644 --- a/src/shape/half_space.rs +++ b/src/shape/half_space.rs @@ -13,7 +13,6 @@ use rkyv::{bytecheck, CheckBytes}; derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize, CheckBytes), archive(as = "Self") )] -#[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] #[repr(C)] pub struct HalfSpace { /// The halfspace planar boundary's outward normal. diff --git a/src/shape/heightfield2.rs b/src/shape/heightfield2.rs index b3943b5e..9a2e6c31 100644 --- a/src/shape/heightfield2.rs +++ b/src/shape/heightfield2.rs @@ -4,114 +4,34 @@ use na::ComplexField; use na::DVector; use std::ops::Range; -use crate::utils::DefaultStorage; - -#[cfg(feature = "cuda")] -use crate::utils::{CudaArrayPointer1, CudaStorage, CudaStoragePtr}; - -#[cfg(all(feature = "std", feature = "cuda"))] -use {crate::utils::CudaArray1, cust::error::CudaResult}; - use na::Point2; use crate::bounding_volume::Aabb; use crate::math::{Real, Vector}; use crate::shape::Segment; -use crate::utils::Array1; /// Indicates if a cell of an heightfield is removed or not. Set this to `false` for /// a removed cell. pub type HeightFieldCellStatus = bool; -/// Trait describing all the types needed for storing an heightfield’s data. -pub trait HeightFieldStorage { - /// Type of the array containing the heightfield’s heights. - type Heights: Array1; - /// Type of the array containing the heightfield’s cells status. - type Status: Array1; -} - -#[cfg(feature = "std")] -impl HeightFieldStorage for DefaultStorage { - type Heights = DVector; - type Status = DVector; -} - -#[cfg(all(feature = "std", feature = "cuda"))] -impl HeightFieldStorage for CudaStorage { - type Heights = CudaArray1; - type Status = CudaArray1; -} - -#[cfg(feature = "cuda")] -impl HeightFieldStorage for CudaStoragePtr { - type Heights = CudaArrayPointer1; - type Status = CudaArrayPointer1; -} - #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr( feature = "rkyv", derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize), archive(check_bytes) )] -#[derive(Debug)] -#[repr(C)] // Needed for Cuda. +#[derive(Debug, Clone)] +#[repr(C)] /// A 2D heightfield with a generic storage buffer for its heights. -pub struct GenericHeightField { - heights: Storage::Heights, - status: Storage::Status, +pub struct HeightField { + heights: DVector, + status: DVector, scale: Vector, aabb: Aabb, } -impl Clone for GenericHeightField -where - Storage: HeightFieldStorage, - Storage::Heights: Clone, - Storage::Status: Clone, -{ - fn clone(&self) -> Self { - Self { - heights: self.heights.clone(), - status: self.status.clone(), - scale: self.scale, - aabb: self.aabb, - } - } -} - -impl Copy for GenericHeightField -where - Storage: HeightFieldStorage, - Storage::Heights: Copy, - Storage::Status: Copy, -{ -} - -#[cfg(feature = "cuda")] -unsafe impl cust_core::DeviceCopy for GenericHeightField -where - Storage: HeightFieldStorage, - Storage::Heights: cust_core::DeviceCopy + Copy, - Storage::Status: cust_core::DeviceCopy + Copy, -{ -} - -/// A 2D heightfield. -#[cfg(feature = "std")] -pub type HeightField = GenericHeightField; - -/// A 2D heightfield stored in the CUDA memory, initializable from the host. -#[cfg(all(feature = "std", feature = "cuda"))] -pub type CudaHeightField = GenericHeightField; - -/// A 2D heightfield stored in the CUDA memory, accessible from within a Cuda kernel. -#[cfg(feature = "cuda")] -pub type CudaHeightFieldPtr = GenericHeightField; - #[cfg(feature = "std")] impl HeightField { /// Creates a new 2D heightfield with the given heights and scale factor. @@ -137,40 +57,16 @@ impl HeightField { aabb, } } - - /// Converts this RAM-based heightfield to an heightfield based on CUDA memory. - #[cfg(feature = "cuda")] - pub fn to_cuda(&self) -> CudaResult { - Ok(CudaHeightField { - heights: CudaArray1::from_vector(&self.heights)?, - status: CudaArray1::from_vector(&self.status)?, - scale: self.scale, - aabb: self.aabb, - }) - } } -#[cfg(all(feature = "std", feature = "cuda"))] -impl CudaHeightField { - /// Returns the heightfield usable from within a CUDA kernel. - pub fn as_device_ptr(&self) -> CudaHeightFieldPtr { - CudaHeightFieldPtr { - heights: self.heights.as_device_ptr(), - status: self.status.as_device_ptr(), - aabb: self.aabb, - scale: self.scale, - } - } -} - -impl GenericHeightField { +impl HeightField { /// The number of cells of this heightfield. pub fn num_cells(&self) -> usize { self.heights.len() - 1 } /// The height at each cell endpoint. - pub fn heights(&self) -> &Storage::Heights { + pub fn heights(&self) -> &DVector { &self.heights } diff --git a/src/shape/heightfield3.rs b/src/shape/heightfield3.rs index 9934db4a..1ce4a973 100644 --- a/src/shape/heightfield3.rs +++ b/src/shape/heightfield3.rs @@ -1,17 +1,10 @@ -use crate::utils::DefaultStorage; #[cfg(feature = "std")] use na::DMatrix; use std::ops::Range; -#[cfg(feature = "cuda")] -use crate::utils::{CudaArrayPointer2, CudaStorage, CudaStoragePtr}; -#[cfg(all(feature = "std", feature = "cuda"))] -use {crate::utils::CudaArray2, cust::error::CudaResult}; - use crate::bounding_volume::Aabb; use crate::math::{Real, Vector}; use crate::shape::{FeatureId, Triangle, TrianglePseudoNormals}; -use crate::utils::Array2; use na::{Point3, Unit}; #[cfg(not(feature = "std"))] @@ -24,7 +17,6 @@ bitflags! { derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize), archive(as = "Self"), )] - #[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] #[derive(Default)] /// The status of the cell of an heightfield. pub struct HeightFieldCellStatus: u8 { @@ -46,8 +38,7 @@ bitflags::bitflags! { derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize), archive(as = "Self"), )] - #[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] - #[repr(C)] // Needed for Cuda. + #[repr(C)] #[derive(Default)] /// The status of the cell of an heightfield. pub struct HeightFieldFlags: u8 { @@ -61,44 +52,18 @@ bitflags::bitflags! { } } -/// Trait describing all the types needed for storing an heightfield’s data. -pub trait HeightFieldStorage { - /// Type of the array containing the heightfield’s heights. - type Heights: Array2; - /// Type of the array containing the heightfield’s cells status. - type Status: Array2; -} - -#[cfg(feature = "std")] -impl HeightFieldStorage for DefaultStorage { - type Heights = DMatrix; - type Status = DMatrix; -} - -#[cfg(all(feature = "std", feature = "cuda"))] -impl HeightFieldStorage for CudaStorage { - type Heights = CudaArray2; - type Status = CudaArray2; -} - -#[cfg(feature = "cuda")] -impl HeightFieldStorage for CudaStoragePtr { - type Heights = CudaArrayPointer2; - type Status = CudaArrayPointer2; -} - #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr( feature = "rkyv", derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize), archive(check_bytes) )] -#[derive(Debug)] -#[repr(C)] // Needed for Cuda. -/// A 3D heightfield with a generic storage buffer for its height grid. -pub struct GenericHeightField { - heights: Storage::Heights, - status: Storage::Status, +#[derive(Debug, Clone)] +#[repr(C)] +/// A 3D heightfield. +pub struct HeightField { + heights: DMatrix, + status: DMatrix, scale: Vector, aabb: Aabb, @@ -106,53 +71,6 @@ pub struct GenericHeightField { flags: HeightFieldFlags, } -impl Clone for GenericHeightField -where - Storage: HeightFieldStorage, - Storage::Heights: Clone, - Storage::Status: Clone, -{ - fn clone(&self) -> Self { - Self { - heights: self.heights.clone(), - status: self.status.clone(), - scale: self.scale, - aabb: self.aabb, - num_triangles: self.num_triangles, - flags: self.flags, - } - } -} - -impl Copy for GenericHeightField -where - Storage: HeightFieldStorage, - Storage::Heights: Copy, - Storage::Status: Copy, -{ -} - -#[cfg(feature = "cuda")] -unsafe impl cust_core::DeviceCopy for GenericHeightField -where - Storage: HeightFieldStorage, - Storage::Heights: cust_core::DeviceCopy + Copy, - Storage::Status: cust_core::DeviceCopy + Copy, -{ -} - -/// A 3D heightfield. -#[cfg(feature = "std")] -pub type HeightField = GenericHeightField; - -/// A 3D heightfield stored in the CUDA memory, initializable from the host. -#[cfg(all(feature = "std", feature = "cuda"))] -pub type CudaHeightField = GenericHeightField; - -/// A 3D heightfield stored in the CUDA memory, accessible from within a Cuda kernel. -#[cfg(feature = "cuda")] -pub type CudaHeightFieldPtr = GenericHeightField; - #[cfg(feature = "std")] impl HeightField { /// Initializes a new heightfield with the given heights, scaling factor, and flags. @@ -193,36 +111,9 @@ impl HeightField { flags, } } - - /// Converts this RAM-based heightfield to an heightfield based on CUDA memory. - #[cfg(feature = "cuda")] - pub fn to_cuda(&self) -> CudaResult { - Ok(CudaHeightField { - heights: CudaArray2::from_matrix(&self.heights)?, - status: CudaArray2::from_matrix(&self.status)?, - aabb: self.aabb, - num_triangles: self.num_triangles, - scale: self.scale, - oriented: self.oriented, - }) - } } -#[cfg(all(feature = "std", feature = "cuda"))] -impl CudaHeightField { - /// Returns the heightfield usable from within a CUDA kernel. - pub fn as_device_ptr(&self) -> CudaHeightFieldPtr { - CudaHeightFieldPtr { - heights: self.heights.as_device_ptr(), - status: self.status.as_device_ptr(), - aabb: self.aabb, - num_triangles: self.num_triangles, - scale: self.scale, - } - } -} - -impl GenericHeightField { +impl HeightField { /// The number of rows of this heightfield. pub fn nrows(&self) -> usize { self.heights.nrows() - 1 @@ -355,10 +246,7 @@ impl GenericHeightField { } /// An iterator through all the triangles around the given point, after vertical projection on the heightfield. - pub fn triangles_around_point( - &self, - point: &Point3, - ) -> HeightFieldRadialTriangles { + pub fn triangles_around_point(&self, point: &Point3) -> HeightFieldRadialTriangles { let center = self.closest_cell_at_point(point); HeightFieldRadialTriangles { heightfield: self, @@ -395,7 +283,7 @@ impl GenericHeightField { return (None, None); } - let status = self.status.get(i, j); + let status = self.status[(i, j)]; if status.contains( HeightFieldCellStatus::LEFT_TRIANGLE_REMOVED @@ -449,7 +337,7 @@ impl GenericHeightField { return (None, None); } - let status = self.status.get(i, j); + let status = self.status[(i, j)]; if status.contains( HeightFieldCellStatus::LEFT_TRIANGLE_REMOVED @@ -467,10 +355,10 @@ impl GenericHeightField { let x0 = -0.5 + cell_width * (j as Real); let x1 = -0.5 + cell_width * ((j + 1) as Real); - let y00 = self.heights.get(i, j); - let y10 = self.heights.get(i + 1, j); - let y01 = self.heights.get(i, j + 1); - let y11 = self.heights.get(i + 1, j + 1); + let y00 = self.heights[(i, j)]; + let y10 = self.heights[(i + 1, j)]; + let y01 = self.heights[(i, j + 1)]; + let y11 = self.heights[(i + 1, j + 1)]; let mut p00 = Point3::new(x0, y00, z0); let mut p10 = Point3::new(x0, y10, z1); @@ -523,7 +411,7 @@ impl GenericHeightField { pub fn triangle_normal_constraints(&self, id: u32) -> Option { if self.flags.contains(HeightFieldFlags::FIX_INTERNAL_EDGES) { let (i, j, left) = self.split_triangle_id(id); - let status = self.status.get(i, j); + let status = self.status[(i, j)]; let (tri_left, tri_right) = self.triangles_at(i, j); let tri_normal = if left { @@ -567,7 +455,7 @@ impl GenericHeightField { { // The neighbor is below. let ((bot_left, bot_right), bot_status) = if j > 0 { - (self.triangles_at(i, j - 1), self.status.get(i, j - 1)) + (self.triangles_at(i, j - 1), self.status[(i, j - 1)]) } else { ((None, None), HeightFieldCellStatus::empty()) }; @@ -582,7 +470,7 @@ impl GenericHeightField { } else { // The neighbor is above. let ((top_left, top_right), top_status) = if j < self.heights.ncols() - 2 { - (self.triangles_at(i, j + 1), self.status.get(i, j + 1)) + (self.triangles_at(i, j + 1), self.status[(i, j + 1)]) } else { ((None, None), HeightFieldCellStatus::empty()) }; @@ -620,26 +508,26 @@ impl GenericHeightField { /// The status of the `(i, j)`-th cell. pub fn cell_status(&self, i: usize, j: usize) -> HeightFieldCellStatus { - self.status.get(i, j) + self.status[(i, j)] } /// Set the status of the `(i, j)`-th cell. pub fn set_cell_status(&mut self, i: usize, j: usize, status: HeightFieldCellStatus) { - self.status.set(i, j, status) + self.status[(i, j)] = status; } /// The statuses of all the cells of this heightfield. - pub fn cells_statuses(&self) -> &Storage::Status { + pub fn cells_statuses(&self) -> &DMatrix { &self.status } /// The mutable statuses of all the cells of this heightfield. - pub fn cells_statuses_mut(&mut self) -> &mut Storage::Status { + pub fn cells_statuses_mut(&mut self) -> &mut DMatrix { &mut self.status } /// The heights of this heightfield. - pub fn heights(&self) -> &Storage::Heights { + pub fn heights(&self) -> &DMatrix { &self.heights } @@ -701,11 +589,7 @@ impl GenericHeightField { let nrows = self.heights.nrows(); let ij = i + j * nrows; - if self - .status - .get(i, j) - .contains(HeightFieldCellStatus::ZIGZAG_SUBDIVISION) - { + if self.status[(i, j)].contains(HeightFieldCellStatus::ZIGZAG_SUBDIVISION) { if left { FeatureId::Vertex([ij, ij + 1, ij + 1 + nrows][ivertex as usize] as u32) } else { @@ -728,11 +612,7 @@ impl GenericHeightField { let ileft = vshift + i + j * (nrows - 1); let iright = ileft + nrows - 1; - if self - .status - .get(i, j) - .contains(HeightFieldCellStatus::ZIGZAG_SUBDIVISION) - { + if self.status[(i, j)].contains(HeightFieldCellStatus::ZIGZAG_SUBDIVISION) { if left { // Triangle: // @@ -818,7 +698,7 @@ impl GenericHeightField { // multiple times. for j in min_x..max_x { for i in min_z..max_z { - let status = self.status.get(i, j); + let status = self.status[(i, j)]; if status.contains(HeightFieldCellStatus::CELL_REMOVED) { continue; @@ -830,10 +710,10 @@ impl GenericHeightField { let x0 = -0.5 + cell_width * (j as Real); let x1 = x0 + cell_width; - let y00 = self.heights.get(i, j); - let y10 = self.heights.get(i + 1, j); - let y01 = self.heights.get(i, j + 1); - let y11 = self.heights.get(i + 1, j + 1); + let y00 = self.heights[(i, j)]; + let y10 = self.heights[(i + 1, j)]; + let y01 = self.heights[(i, j + 1)]; + let y11 = self.heights[(i + 1, j + 1)]; if (y00 > ref_maxs.y && y10 > ref_maxs.y && y01 > ref_maxs.y && y11 > ref_maxs.y) || (y00 < ref_mins.y @@ -881,13 +761,13 @@ impl GenericHeightField { } } -struct HeightFieldTriangles<'a, Storage: HeightFieldStorage> { - heightfield: &'a GenericHeightField, +struct HeightFieldTriangles<'a> { + heightfield: &'a HeightField, curr: (usize, usize), tris: (Option, Option), } -impl<'a, Storage: HeightFieldStorage> Iterator for HeightFieldTriangles<'a, Storage> { +impl<'a> Iterator for HeightFieldTriangles<'a> { type Item = Triangle; fn next(&mut self) -> Option { @@ -916,15 +796,15 @@ impl<'a, Storage: HeightFieldStorage> Iterator for HeightFieldTriangles<'a, Stor } /// An iterator through all the triangles around the given point, after vertical projection on the heightfield. -pub struct HeightFieldRadialTriangles<'a, Storage: HeightFieldStorage> { - heightfield: &'a GenericHeightField, +pub struct HeightFieldRadialTriangles<'a> { + heightfield: &'a HeightField, center: (usize, usize), curr_radius: usize, curr_element: usize, tris: (Option, Option), } -impl<'a, Storage: HeightFieldStorage> HeightFieldRadialTriangles<'a, Storage> { +impl<'a> HeightFieldRadialTriangles<'a> { /// Returns the next triangle in this iterator. /// /// Returns `None` no triangle closest than `max_dist` remain diff --git a/src/shape/mod.rs b/src/shape/mod.rs index a7268d8f..b9c08095 100644 --- a/src/shape/mod.rs +++ b/src/shape/mod.rs @@ -47,7 +47,6 @@ pub use self::polygonal_feature3d::PolygonalFeature; pub use self::tetrahedron::{Tetrahedron, TetrahedronPointLocation}; pub use self::triangle_pseudo_normals::TrianglePseudoNormals; pub use self::trimesh::*; -pub use self::trimesh_storage::TriMeshStorage; /// A cylinder dilated by a sphere (so it has round corners). #[cfg(feature = "dim3")] @@ -114,4 +113,3 @@ mod polygonal_feature2d; #[cfg(feature = "std")] mod shared_shape; mod triangle_pseudo_normals; -mod trimesh_storage; diff --git a/src/shape/polyline.rs b/src/shape/polyline.rs index 3e9c158c..f78b812f 100644 --- a/src/shape/polyline.rs +++ b/src/shape/polyline.rs @@ -6,7 +6,6 @@ use crate::shape::composite_shape::SimdCompositeShape; use crate::shape::{FeatureId, Segment, SegmentPointLocation, Shape, TypedSimdCompositeShape}; use crate::query::details::NormalConstraints; -use crate::utils::DefaultStorage; #[cfg(not(feature = "std"))] use na::ComplexField; // for .abs() @@ -297,7 +296,6 @@ impl TypedSimdCompositeShape for Polyline { type PartShape = Segment; type PartNormalConstraints = (); type PartId = u32; - type QbvhStorage = DefaultStorage; #[inline(always)] fn map_typed_part_at( diff --git a/src/shape/round_shape.rs b/src/shape/round_shape.rs index 96c05130..318f61cd 100644 --- a/src/shape/round_shape.rs +++ b/src/shape/round_shape.rs @@ -8,7 +8,6 @@ use na::Unit; derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize), archive(check_bytes) )] -#[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] #[derive(Copy, Clone, Debug)] #[repr(C)] /// A shape with rounded borders. diff --git a/src/shape/segment.rs b/src/shape/segment.rs index f883f33d..41b598cc 100644 --- a/src/shape/segment.rs +++ b/src/shape/segment.rs @@ -17,7 +17,6 @@ use rkyv::{bytecheck, CheckBytes}; derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize, CheckBytes), archive(as = "Self") )] -#[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] #[derive(PartialEq, Debug, Copy, Clone)] #[repr(C)] pub struct Segment { diff --git a/src/shape/tetrahedron.rs b/src/shape/tetrahedron.rs index 94149781..d232635e 100644 --- a/src/shape/tetrahedron.rs +++ b/src/shape/tetrahedron.rs @@ -20,7 +20,6 @@ use rkyv::{bytecheck, CheckBytes}; derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize, CheckBytes), archive(as = "Self") )] -#[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] #[derive(Copy, Clone, Debug)] #[repr(C)] pub struct Tetrahedron { diff --git a/src/shape/triangle.rs b/src/shape/triangle.rs index d3931460..7dc2e761 100644 --- a/src/shape/triangle.rs +++ b/src/shape/triangle.rs @@ -25,7 +25,6 @@ use rkyv::{bytecheck, CheckBytes}; derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize, CheckBytes), archive(as = "Self") )] -#[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] #[derive(PartialEq, Debug, Copy, Clone, Default)] #[repr(C)] pub struct Triangle { diff --git a/src/shape/trimesh.rs b/src/shape/trimesh.rs index e7b5017e..5d9643f8 100644 --- a/src/shape/trimesh.rs +++ b/src/shape/trimesh.rs @@ -1,14 +1,12 @@ use crate::bounding_volume::Aabb; use crate::math::{Isometry, Point, Real, Vector}; -use crate::partitioning::QbvhStorage; -use crate::partitioning::{GenericQbvh, Qbvh}; -use crate::shape::trimesh_storage::TriMeshStorage; +use crate::partitioning::Qbvh; use crate::shape::{FeatureId, Shape, Triangle, TrianglePseudoNormals, TypedSimdCompositeShape}; use std::fmt; -use crate::utils::{Array1, DefaultStorage, HashablePartialEq}; +use crate::utils::HashablePartialEq; #[cfg(feature = "dim3")] -use {crate::shape::Cuboid, crate::shape::HeightFieldStorage, crate::utils::SortedPair, na::Unit}; +use {crate::shape::Cuboid, crate::utils::SortedPair, na::Unit}; #[cfg(feature = "std")] use { @@ -20,11 +18,6 @@ use { #[cfg(all(feature = "dim2", feature = "std"))] use crate::transformation::ear_clipping::triangulate_ear_clipping; -#[cfg(feature = "cuda")] -use crate::utils::{CudaStorage, CudaStoragePtr}; -#[cfg(all(feature = "std", feature = "cuda"))] -use {crate::utils::CudaArray1, cust::error::CudaResult}; - use crate::query::details::NormalConstraints; #[cfg(feature = "rkyv")] use rkyv::{bytecheck, CheckBytes}; @@ -35,7 +28,7 @@ pub enum TopologyError { /// Found a triangle with two or three identical vertices. BadTriangle(u32), /// At least two adjacent triangles have opposite orientations. - BadAdjascentTrianglesOrientation { + BadAdjacentTrianglesOrientation { /// The first triangle, with an orientation opposite to the second triangle. triangle1: u32, /// The second triangle, with an orientation opposite to the first triangle. @@ -52,7 +45,7 @@ impl std::fmt::Display for TopologyError { Self::BadTriangle(fid) => { f.pad(&format!("the triangle {fid} has at least two identical vertices.")) } - Self::BadAdjascentTrianglesOrientation { + Self::BadAdjacentTrianglesOrientation { triangle1, triangle2, edge, @@ -70,93 +63,49 @@ impl std::error::Error for TopologyError {} /// point on the triangle, as described in the paper: /// "Signed distance computation using the angle weighted pseudonormal", Baerentzen, et al. /// DOI: 10.1109/TVCG.2005.49 -#[derive(Default)] +#[derive(Default, Clone)] #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[cfg_attr( feature = "rkyv", derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize), archive(check_bytes) )] -#[repr(C)] // Needed for Cuda. +#[repr(C)] #[cfg(feature = "dim3")] -pub struct TriMeshPseudoNormals { +pub struct TriMeshPseudoNormals { /// The pseudo-normals of the vertices. - pub vertices_pseudo_normal: Storage::ArrayVector, + pub vertices_pseudo_normal: Vec>, /// The pseudo-normals of the edges. - pub edges_pseudo_normal: Storage::ArrayVectorTriple, -} - -#[cfg(all(feature = "dim3", feature = "std", feature = "cuda"))] -impl TriMeshPseudoNormals { - /// Returns the heightfield usable from within a CUDA kernel. - fn as_device_ptr(&self) -> TriMeshPseudoNormals { - TriMeshPseudoNormals { - vertices_pseudo_normal: self.vertices_pseudo_normal.as_device_ptr(), - edges_pseudo_normal: self.edges_pseudo_normal.as_device_ptr(), - } - } -} - -#[cfg(all(feature = "dim3", feature = "std", feature = "cuda"))] -impl TriMeshPseudoNormals { - fn to_cuda(&self) -> CudaResult> { - Ok(TriMeshPseudoNormals { - vertices_pseudo_normal: CudaArray1::new(&self.vertices_pseudo_normal)?, - edges_pseudo_normal: CudaArray1::new(&self.edges_pseudo_normal)?, - }) - } + pub edges_pseudo_normal: Vec<[Vector; 3]>, } /// The connected-components of a triangle mesh. -#[derive(Debug)] +#[derive(Debug, Clone)] #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[cfg_attr( feature = "rkyv", derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize), archive(check_bytes) )] -#[repr(C)] // Needed for Cuda. -pub struct TriMeshConnectedComponents { +#[repr(C)] +pub struct TriMeshConnectedComponents { /// The `face_colors[i]` gives the connected-component index /// of the i-th face. - pub face_colors: Storage::ArrayU32, + pub face_colors: Vec, /// The set of faces grouped by connected components. - pub grouped_faces: Storage::ArrayU32, + pub grouped_faces: Vec, /// The range of connected components. `self.grouped_faces[self.ranges[i]..self.ranges[i + 1]]` /// contains the indices of all the faces part of the i-th connected component. - pub ranges: Storage::ArrayUsize, + pub ranges: Vec, } -impl TriMeshConnectedComponents { +impl TriMeshConnectedComponents { /// The total number of connected components. pub fn num_connected_components(&self) -> usize { self.ranges.len() - 1 } } -#[cfg(all(feature = "std", feature = "cuda"))] -impl TriMeshConnectedComponents { - /// Returns the heightfield usable from within a CUDA kernel. - fn as_device_ptr(&self) -> TriMeshConnectedComponents { - TriMeshConnectedComponents { - face_colors: self.face_colors.as_device_ptr(), - grouped_faces: self.grouped_faces.as_device_ptr(), - ranges: self.ranges.as_device_ptr(), - } - } -} - -#[cfg(all(feature = "std", feature = "cuda"))] -impl TriMeshConnectedComponents { - fn to_cuda(&self) -> CudaResult> { - Ok(TriMeshConnectedComponents { - face_colors: CudaArray1::new(&self.face_colors)?, - grouped_faces: CudaArray1::new(&self.grouped_faces)?, - ranges: CudaArray1::new(&self.ranges)?, - }) - } -} - /// A vertex of a triangle-mesh’s half-edge topology. #[derive(Clone, Copy, Debug)] #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] @@ -165,8 +114,7 @@ impl TriMeshConnectedComponents { derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize, CheckBytes), archive(as = "Self") )] -#[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] -#[repr(C)] // Needed for Cuda. +#[repr(C)] pub struct TopoVertex { /// One of the half-edge with this vertex as endpoint. pub half_edge: u32, @@ -180,8 +128,7 @@ pub struct TopoVertex { derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize, CheckBytes), archive(as = "Self") )] -#[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] -#[repr(C)] // Needed for Cuda. +#[repr(C)] pub struct TopoFace { /// The half-edge adjacent to this face, with a starting point equal /// to the first point of this face. @@ -196,8 +143,7 @@ pub struct TopoFace { derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize, CheckBytes), archive(as = "Self") )] -#[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] -#[repr(C)] // Needed for Cuda. +#[repr(C)] pub struct TopoHalfEdge { /// The next half-edge. pub next: u32, @@ -212,35 +158,24 @@ pub struct TopoHalfEdge { } /// The half-edge topology information of a triangle mesh. -#[derive(Default)] +#[derive(Default, Clone)] #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[cfg_attr( feature = "rkyv", derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize), archive(check_bytes) )] -#[repr(C)] // Needed for Cuda. -pub struct TriMeshTopology { +#[repr(C)] +pub struct TriMeshTopology { /// The vertices of this half-edge representation. - pub vertices: Storage::ArrayTopoVertex, + pub vertices: Vec, /// The faces of this half-edge representation. - pub faces: Storage::ArrayTopoFace, + pub faces: Vec, /// The half-edges of this half-edge representation. - pub half_edges: Storage::ArrayTopoHalfEdge, -} - -#[cfg(all(feature = "std", feature = "cuda"))] -impl TriMeshTopology { - fn as_device_ptr(&self) -> TriMeshTopology { - TriMeshTopology { - vertices: self.vertices.as_device_ptr(), - faces: self.faces.as_device_ptr(), - half_edges: self.half_edges.as_device_ptr(), - } - } + pub half_edges: Vec, } -impl TriMeshTopology { +impl TriMeshTopology { #[cfg(feature = "dim3")] pub(crate) fn face_half_edges_ids(&self, fid: u32) -> [u32; 3] { let first_half_edge = self.faces[fid as usize].half_edge; @@ -255,17 +190,6 @@ impl TriMeshTopology { } } -#[cfg(all(feature = "std", feature = "cuda"))] -impl TriMeshTopology { - fn to_cuda(&self) -> CudaResult> { - Ok(TriMeshTopology { - vertices: CudaArray1::new(&self.vertices)?, - faces: CudaArray1::new(&self.faces)?, - half_edges: CudaArray1::new(&self.half_edges)?, - }) - } -} - bitflags::bitflags! { #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr( @@ -273,8 +197,7 @@ bitflags::bitflags! { derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize), archive(as = "Self"), )] - #[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] - #[repr(C)] // Needed for Cuda. + #[repr(C)] #[derive(Default)] /// The status of the cell of an heightfield. pub struct TriMeshFlags: u16 { @@ -321,88 +244,31 @@ bitflags::bitflags! { } #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] -#[cfg_attr( - feature = "serde-serialize", - serde(bound( - serialize = ">::Nodes: serde::Serialize, \ - >::ArrayU32: serde::Serialize, \ - >::ArrayProxies: serde::Serialize,\ - Storage::ArrayTopoVertex: serde::Serialize,\ - Storage::ArrayTopoFace: serde::Serialize,\ - Storage::ArrayTopoHalfEdge: serde::Serialize,\ - Storage::ArrayU32: serde::Serialize,\ - Storage::ArrayUsize: serde::Serialize,\ - Storage::ArrayVector: serde::Serialize,\ - Storage::ArrayPoint: serde::Serialize,\ - Storage::ArrayIdx: serde::Serialize,\ - Storage::ArrayVectorTriple: serde::Serialize", - deserialize = ">::Nodes: serde::Deserialize<'de>, \ - >::ArrayU32: serde::Deserialize<'de>, \ - >::ArrayProxies: serde::Deserialize<'de>,\ - Storage::ArrayTopoVertex: serde::Deserialize<'de>,\ - Storage::ArrayTopoFace: serde::Deserialize<'de>,\ - Storage::ArrayTopoHalfEdge: serde::Deserialize<'de>,\ - Storage::ArrayU32: serde::Deserialize<'de>,\ - Storage::ArrayUsize: serde::Deserialize<'de>,\ - Storage::ArrayVector: serde::Deserialize<'de>,\ - Storage::ArrayPoint: serde::Deserialize<'de>,\ - Storage::ArrayIdx: serde::Deserialize<'de>,\ - Storage::ArrayVectorTriple: serde::Deserialize<'de>", - )) -)] #[cfg_attr( feature = "rkyv", derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize), archive(check_bytes) )] -#[repr(C)] // Needed for Cuda. +#[repr(C)] +#[derive(Clone)] /// A triangle mesh. -pub struct GenericTriMesh { - qbvh: GenericQbvh, - vertices: Storage::ArrayPoint, - indices: Storage::ArrayIdx, +pub struct TriMesh { + qbvh: Qbvh, + vertices: Vec>, + indices: Vec<[u32; 3]>, #[cfg(feature = "dim3")] - pub(crate) pseudo_normals: Option>, - topology: Option>, - connected_components: Option>, + pub(crate) pseudo_normals: Option, + topology: Option, + connected_components: Option, flags: TriMeshFlags, } -impl fmt::Debug for GenericTriMesh { +impl fmt::Debug for TriMesh { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "GenericTriMesh") } } -/// A triangle-mesh. -pub type TriMesh = GenericTriMesh; -#[cfg(feature = "cuda")] -/// A triangle-mesh stored on CUDA memory. -pub type CudaTriMesh = GenericTriMesh; -#[cfg(feature = "cuda")] -/// A triangle-mesh accessible from CUDA kernels. -pub type CudaTriMeshPtr = GenericTriMesh; - -#[cfg(all(feature = "std", feature = "cuda"))] -impl CudaTriMesh { - /// Returns the heightfield usable from within a CUDA kernel. - pub fn as_device_ptr(&self) -> CudaTriMeshPtr { - GenericTriMesh { - qbvh: self.qbvh.as_device_ptr(), - vertices: self.vertices.as_device_ptr(), - indices: self.indices.as_device_ptr(), - #[cfg(feature = "dim3")] - pseudo_normals: self.pseudo_normals.as_ref().map(|pn| pn.as_device_ptr()), - topology: self.topology.as_ref().map(|topo| topo.as_device_ptr()), - connected_components: self - .connected_components - .as_ref() - .map(|cc| cc.as_device_ptr()), - flags: self.flags, - } - } -} - #[cfg(feature = "std")] impl TriMesh { /// Creates a new triangle mesh from a vertex buffer and an index buffer. @@ -410,33 +276,6 @@ impl TriMesh { Self::with_flags(vertices, indices, TriMeshFlags::empty()) } - /// Converts this RAM-based heightfield to an heightfield based on CUDA memory. - #[cfg(feature = "cuda")] - pub fn to_cuda(&self) -> CudaResult { - Ok(CudaTriMesh { - qbvh: self.qbvh.to_cuda()?, - vertices: CudaArray1::new(&self.vertices)?, - indices: CudaArray1::new(&self.indices)?, - #[cfg(feature = "dim3")] - pseudo_normals: self - .pseudo_normals - .as_ref() - .map(|pn| pn.to_cuda()) - .transpose()?, - topology: self - .topology - .as_ref() - .map(|topo| topo.to_cuda()) - .transpose()?, - connected_components: self - .connected_components - .as_ref() - .map(|cc| cc.to_cuda()) - .transpose()?, - flags: self.flags, - }) - } - /// Creates a new triangle mesh from a vertex buffer and an index buffer, and flags controlling optional properties. pub fn with_flags( vertices: Vec>, @@ -870,7 +709,7 @@ impl TriMesh { self.delete_bad_topology_triangles(); } - let mut topology = TriMeshTopology::::default(); + let mut topology = TriMeshTopology::default(); let mut half_edge_map = HashMap::default(); topology.vertices.resize( @@ -906,7 +745,7 @@ impl TriMesh { if let Some(existing) = half_edge_map.insert(edge_key, half_edge_base_id + k) { // If the same edge already exists (with the same vertex order) then // we have two triangles sharing the same but with opposite incompatible orientations. - return Err(TopologyError::BadAdjascentTrianglesOrientation { + return Err(TopologyError::BadAdjacentTrianglesOrientation { edge: edge_key, triangle1: topology.half_edges[existing as usize].face, triangle2: fid as u32, @@ -1028,7 +867,7 @@ impl TriMesh { } } -impl GenericTriMesh { +impl TriMesh { /// The flags of this triangle mesh. pub fn flags(&self) -> TriMeshFlags { self.flags @@ -1045,7 +884,7 @@ impl GenericTriMesh { } /// The acceleration structure used by this triangle-mesh. - pub fn qbvh(&self) -> &GenericQbvh { + pub fn qbvh(&self) -> &Qbvh { &self.qbvh } @@ -1107,83 +946,36 @@ impl GenericTriMesh { } /// The vertex buffer of this mesh. - pub fn vertices(&self) -> &Storage::ArrayPoint { + pub fn vertices(&self) -> &[Point] { &self.vertices } /// The index buffer of this mesh. - pub fn indices(&self) -> &Storage::ArrayIdx { + pub fn indices(&self) -> &[[u32; 3]] { &self.indices } /// Returns the topology information of this trimesh, if it has been computed. - pub fn topology(&self) -> Option<&TriMeshTopology> { + pub fn topology(&self) -> Option<&TriMeshTopology> { self.topology.as_ref() } /// Returns the connected-component information of this trimesh, if it has been computed. - pub fn connected_components(&self) -> Option<&TriMeshConnectedComponents> { + pub fn connected_components(&self) -> Option<&TriMeshConnectedComponents> { self.connected_components.as_ref() } /// The pseudo-normals of this triangle mesh, if they have been computed. #[cfg(feature = "dim3")] - pub fn pseudo_normals(&self) -> Option<&TriMeshPseudoNormals> { + pub fn pseudo_normals(&self) -> Option<&TriMeshPseudoNormals> { self.pseudo_normals.as_ref() } } -/* -#[cfg(feature = "dim3")] -impl RayCast for TriMesh { - fn cast_local_ray_and_get_normal( - &self, - ray: &Ray, - max_toi: Real, - solid: bool, - ) -> Option { - // FIXME: do a best-first search. - let mut intersections = Vec::new(); - self.qbvh.cast_ray(&ray, max_toi, &mut intersections); - let mut best: Option = None; - - for inter in intersections { - let tri = self.triangle(inter); - if let Some(inter) = tri.cast_local_ray_and_get_normal(ray, max_toi, solid) { - if let Some(curr) = &mut best { - if curr.toi > inter.toi { - *curr = inter; - } - } else { - best = Some(inter); - } - } - } - - best - } - - fn intersects_local_ray(&self, ray: &Ray, max_toi: Real) -> bool { - // FIXME: do a best-first search. - let mut intersections = Vec::new(); - self.qbvh.cast_ray(&ray, max_toi, &mut intersections); - - for inter in intersections { - let tri = self.triangle(inter); - if tri.intersects_local_ray(ray, max_toi) { - return true; - } - } - - false - } -} -*/ - #[cfg(feature = "dim3")] #[cfg(feature = "std")] -impl From> for TriMesh { - fn from(heightfield: crate::shape::GenericHeightField) -> Self { +impl From for TriMesh { + fn from(heightfield: crate::shape::HeightField) -> Self { let (vtx, idx) = heightfield.to_trimesh(); TriMesh::new(vtx, idx) } @@ -1219,11 +1011,10 @@ impl SimdCompositeShape for TriMesh { } } -impl TypedSimdCompositeShape for GenericTriMesh { +impl TypedSimdCompositeShape for TriMesh { type PartShape = Triangle; type PartNormalConstraints = TrianglePseudoNormals; type PartId = u32; - type QbvhStorage = Storage::QbvhStorage; #[inline(always)] fn map_typed_part_at( @@ -1255,181 +1046,7 @@ impl TypedSimdCompositeShape for GenericTriMesh &GenericQbvh { + fn typed_qbvh(&self) -> &Qbvh { &self.qbvh } } - -/******************************************* - * - * BOILERPLACE Copy/Clone implementations - * - * - ******************************************/ -#[cfg(feature = "dim3")] -impl Clone for TriMeshPseudoNormals -where - Storage: TriMeshStorage, - Storage::ArrayVector: Clone, - Storage::ArrayVectorTriple: Clone, -{ - fn clone(&self) -> Self { - Self { - vertices_pseudo_normal: self.vertices_pseudo_normal.clone(), - edges_pseudo_normal: self.edges_pseudo_normal.clone(), - } - } -} - -#[cfg(feature = "dim3")] -impl Copy for TriMeshPseudoNormals -where - Storage: TriMeshStorage, - Storage::ArrayVector: Copy, - Storage::ArrayVectorTriple: Copy, -{ -} - -#[cfg(feature = "dim3")] -#[cfg(feature = "cuda")] -unsafe impl cust_core::DeviceCopy for TriMeshPseudoNormals -where - Storage: TriMeshStorage, - Storage::ArrayVector: cust_core::DeviceCopy + Copy, - Storage::ArrayVectorTriple: cust_core::DeviceCopy + Copy, -{ -} - -impl Clone for TriMeshConnectedComponents -where - Storage: TriMeshStorage, - Storage::ArrayU32: Clone, - Storage::ArrayUsize: Clone, -{ - fn clone(&self) -> Self { - Self { - face_colors: self.face_colors.clone(), - grouped_faces: self.grouped_faces.clone(), - ranges: self.ranges.clone(), - } - } -} - -impl Copy for TriMeshConnectedComponents -where - Storage: TriMeshStorage, - Storage::ArrayU32: Copy, - Storage::ArrayUsize: Copy, -{ -} - -#[cfg(feature = "cuda")] -unsafe impl cust_core::DeviceCopy for TriMeshConnectedComponents -where - Storage: TriMeshStorage, - Storage::ArrayU32: cust_core::DeviceCopy + Copy, - Storage::ArrayUsize: cust_core::DeviceCopy + Copy, -{ -} - -impl Clone for TriMeshTopology -where - Storage: TriMeshStorage, - Storage::ArrayTopoVertex: Clone, - Storage::ArrayTopoFace: Clone, - Storage::ArrayTopoHalfEdge: Clone, -{ - fn clone(&self) -> Self { - Self { - vertices: self.vertices.clone(), - faces: self.faces.clone(), - half_edges: self.half_edges.clone(), - } - } -} - -impl Copy for TriMeshTopology -where - Storage: TriMeshStorage, - Storage::ArrayTopoVertex: Copy, - Storage::ArrayTopoFace: Copy, - Storage::ArrayTopoHalfEdge: Copy, -{ -} - -#[cfg(feature = "cuda")] -unsafe impl cust_core::DeviceCopy for TriMeshTopology -where - Storage: TriMeshStorage, - Storage::ArrayTopoVertex: cust_core::DeviceCopy + Copy, - Storage::ArrayTopoFace: cust_core::DeviceCopy + Copy, - Storage::ArrayTopoHalfEdge: cust_core::DeviceCopy + Copy, -{ -} - -impl Clone for GenericTriMesh -where - Storage: TriMeshStorage, - >::Nodes: Clone, - >::ArrayU32: Clone, - >::ArrayProxies: Clone, - Storage::ArrayTopoVertex: Clone, - Storage::ArrayTopoFace: Clone, - Storage::ArrayTopoHalfEdge: Clone, - Storage::ArrayU32: Clone, - Storage::ArrayUsize: Clone, - Storage::ArrayVector: Clone, - Storage::ArrayPoint: Clone, - Storage::ArrayIdx: Clone, - Storage::ArrayVectorTriple: Clone, -{ - fn clone(&self) -> Self { - Self { - qbvh: self.qbvh.clone(), - vertices: self.vertices.clone(), - indices: self.indices.clone(), - #[cfg(feature = "dim3")] - pseudo_normals: self.pseudo_normals.clone(), - topology: self.topology.clone(), - connected_components: self.connected_components.clone(), - flags: self.flags, - } - } -} - -impl Copy for GenericTriMesh -where - Storage: TriMeshStorage, - >::Nodes: Copy, - >::ArrayU32: Copy, - >::ArrayProxies: Copy, - Storage::ArrayTopoVertex: Copy, - Storage::ArrayTopoFace: Copy, - Storage::ArrayTopoHalfEdge: Copy, - Storage::ArrayU32: Copy, - Storage::ArrayUsize: Copy, - Storage::ArrayVector: Copy, - Storage::ArrayPoint: Copy, - Storage::ArrayIdx: Copy, - Storage::ArrayVectorTriple: Copy, -{ -} - -#[cfg(feature = "cuda")] -unsafe impl cust_core::DeviceCopy for GenericTriMesh -where - Storage: TriMeshStorage, - >::Nodes: cust_core::DeviceCopy + Copy, - >::ArrayU32: cust_core::DeviceCopy + Copy, - >::ArrayProxies: cust_core::DeviceCopy + Copy, - Storage::ArrayTopoVertex: cust_core::DeviceCopy + Copy, - Storage::ArrayTopoFace: cust_core::DeviceCopy + Copy, - Storage::ArrayTopoHalfEdge: cust_core::DeviceCopy + Copy, - Storage::ArrayU32: cust_core::DeviceCopy + Copy, - Storage::ArrayUsize: cust_core::DeviceCopy + Copy, - Storage::ArrayVector: cust_core::DeviceCopy + Copy, - Storage::ArrayPoint: cust_core::DeviceCopy + Copy, - Storage::ArrayIdx: cust_core::DeviceCopy + Copy, - Storage::ArrayVectorTriple: cust_core::DeviceCopy + Copy, -{ -} diff --git a/src/shape/trimesh_storage.rs b/src/shape/trimesh_storage.rs deleted file mode 100644 index 914ad142..00000000 --- a/src/shape/trimesh_storage.rs +++ /dev/null @@ -1,75 +0,0 @@ -use crate::math::{Point, Real, Vector}; -use crate::partitioning::QbvhStorage; -use crate::shape::{TopoFace, TopoHalfEdge, TopoVertex}; -use crate::utils::{Array1, DefaultStorage}; - -#[cfg(all(feature = "std", feature = "cuda"))] -use crate::utils::CudaArray1; -#[cfg(feature = "cuda")] -use crate::utils::{CudaArrayPointer1, CudaStorage, CudaStoragePtr}; - -/// Trait describing all the types needed for storing a triangle mesh’s data. -pub trait TriMeshStorage { - /// Storage needed to store a Qbvh. - type QbvhStorage: QbvhStorage; - /// Storage needed to store topology vertices. - type ArrayTopoVertex: Array1; - /// Storage needed to store topology faces. - type ArrayTopoFace: Array1; - /// Storage needed to store topology half-edges. - type ArrayTopoHalfEdge: Array1; - /// Storage needed to store u32 - type ArrayU32: Array1; - /// Storage needed to store usize. - type ArrayUsize: Array1; - /// Storage needed to store vectors. - type ArrayVector: Array1>; - /// Storage needed to store points. - type ArrayPoint: Array1>; - /// Storage needed to store triangle indices. - type ArrayIdx: Array1<[u32; 3]>; - /// Storage needed to store triples of vectors. - type ArrayVectorTriple: Array1<[Vector; 3]>; -} - -#[cfg(feature = "std")] -impl TriMeshStorage for DefaultStorage { - type QbvhStorage = Self; - type ArrayTopoVertex = Vec; - type ArrayTopoFace = Vec; - type ArrayTopoHalfEdge = Vec; - type ArrayU32 = Vec; - type ArrayUsize = Vec; - type ArrayVector = Vec>; - type ArrayPoint = Vec>; - type ArrayIdx = Vec<[u32; 3]>; - type ArrayVectorTriple = Vec<[Vector; 3]>; -} - -#[cfg(all(feature = "std", feature = "cuda"))] -impl TriMeshStorage for CudaStorage { - type QbvhStorage = Self; - type ArrayTopoVertex = CudaArray1; - type ArrayTopoFace = CudaArray1; - type ArrayTopoHalfEdge = CudaArray1; - type ArrayU32 = CudaArray1; - type ArrayUsize = CudaArray1; - type ArrayVector = CudaArray1>; - type ArrayPoint = CudaArray1>; - type ArrayIdx = CudaArray1<[u32; 3]>; - type ArrayVectorTriple = CudaArray1<[Vector; 3]>; -} - -#[cfg(feature = "cuda")] -impl TriMeshStorage for CudaStoragePtr { - type QbvhStorage = Self; - type ArrayTopoVertex = CudaArrayPointer1; - type ArrayTopoFace = CudaArrayPointer1; - type ArrayTopoHalfEdge = CudaArrayPointer1; - type ArrayU32 = CudaArrayPointer1; - type ArrayUsize = CudaArrayPointer1; - type ArrayVector = CudaArrayPointer1>; - type ArrayPoint = CudaArrayPointer1>; - type ArrayIdx = CudaArrayPointer1<[u32; 3]>; - type ArrayVectorTriple = CudaArrayPointer1<[Vector; 3]>; -} diff --git a/src/transformation/to_outline/heightfield_to_outline.rs b/src/transformation/to_outline/heightfield_to_outline.rs index 13e7a597..9f79664c 100644 --- a/src/transformation/to_outline/heightfield_to_outline.rs +++ b/src/transformation/to_outline/heightfield_to_outline.rs @@ -1,8 +1,8 @@ use crate::math::Real; -use crate::shape::{GenericHeightField, HeightFieldCellStatus, HeightFieldStorage}; +use crate::shape::{HeightField, HeightFieldCellStatus}; use na::Point3; -impl GenericHeightField { +impl HeightField { /// Outlines this heightfield’s shape using polylines. pub fn to_outline(&self) -> (Vec>, Vec<[u32; 2]>) { todo!() diff --git a/src/transformation/to_trimesh/heightfield_to_trimesh.rs b/src/transformation/to_trimesh/heightfield_to_trimesh.rs index 6e615d38..28d27cc3 100644 --- a/src/transformation/to_trimesh/heightfield_to_trimesh.rs +++ b/src/transformation/to_trimesh/heightfield_to_trimesh.rs @@ -1,8 +1,8 @@ use crate::math::Real; -use crate::shape::{GenericHeightField, HeightFieldStorage}; +use crate::shape::HeightField; use na::Point3; -impl GenericHeightField { +impl HeightField { /// Discretize the boundary of this heightfield as a triangle-mesh. pub fn to_trimesh(&self) -> (Vec>, Vec<[u32; 3]>) { let mut vertices = Vec::new(); diff --git a/src/utils/array.rs b/src/utils/array.rs deleted file mode 100644 index 1eead7e2..00000000 --- a/src/utils/array.rs +++ /dev/null @@ -1,99 +0,0 @@ -use core::ops::IndexMut; -#[cfg(feature = "std")] -use na::{DMatrix, DVector, Scalar}; - -/// Abstraction over a 1D array. -pub trait Array1: IndexMut { - /// The number of heights on this storage. - fn len(&self) -> usize; - - /// Is this array empty? - #[inline] - fn is_empty(&self) -> bool { - self.len() == 0 - } - - // NOTE: we don’t name it just `get` to avoid clashes with pre-existing `get` methods. - /// Gets the i-th element of this array, if it exists. - #[inline] - fn get_at(&self, i: usize) -> Option<&T> { - if i < self.len() { - Some(&self[i]) - } else { - None - } - } -} - -#[cfg(feature = "std")] -impl Array1 for Vec { - #[inline] - fn len(&self) -> usize { - self.len() - } -} - -#[cfg(feature = "std")] -impl Array1 for DVector { - #[inline] - fn len(&self) -> usize { - self.len() - } -} - -/// Abstraction over a 2D array. -pub trait Array2 { - /// The type of heights. - type Item; - /// The number of rows of the heights grid. - fn nrows(&self) -> usize; - /// The number of columns of the heights grid. - fn ncols(&self) -> usize; - /// Gets the height on the `(i, j)`-th cell of the height grid. - fn get(&self, i: usize, j: usize) -> Self::Item; - /// Sets the height on the `(i, j)`-th cell of the height grid. - fn set(&mut self, i: usize, j: usize, val: Self::Item); -} - -#[cfg(feature = "std")] -impl Array2 for DMatrix { - type Item = T; - - #[inline] - fn nrows(&self) -> usize { - self.nrows() - } - - #[inline] - fn ncols(&self) -> usize { - self.ncols() - } - - #[inline] - fn get(&self, i: usize, j: usize) -> Self::Item { - self[(i, j)].clone() - } - - #[inline] - fn set(&mut self, i: usize, j: usize, val: Self::Item) { - self[(i, j)] = val - } -} - -#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] -#[cfg_attr( - feature = "rkyv", - derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize), - archive(check_bytes) -)] -#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)] -/// Default data storage based on `Vec`, `DVector`, and `DMatrix`. -pub struct DefaultStorage; -#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)] -#[cfg(feature = "cuda")] -/// Data storage residing in CUDA memory. -pub struct CudaStorage; -#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)] -#[cfg(feature = "cuda")] -/// Data storage for accessing data from CUDA kernels. -pub struct CudaStoragePtr; diff --git a/src/utils/cuda_array.rs b/src/utils/cuda_array.rs deleted file mode 100644 index 751199b1..00000000 --- a/src/utils/cuda_array.rs +++ /dev/null @@ -1,270 +0,0 @@ -#[cfg(target_os = "cuda")] -use crate::shape::HeightFieldStorage; -use crate::utils::{Array1, Array2, DevicePointer}; - -#[cfg(feature = "std")] -use cust::{error::CudaResult, memory::DeviceBuffer}; -use cust_core::DeviceCopy; -use std::ops::{Index, IndexMut}; - -/* - * - * 2D array. - * -*/ -#[cfg(feature = "std")] -/// A 2D array residing on GPU memory. -pub struct CudaArray2 { - data: DeviceBuffer, - nrows: usize, - ncols: usize, -} - -#[cfg(feature = "std")] -impl CudaArray2 { - /// Initialize a 2D cuda array on the GPU. - pub fn new(data: &[T], nrows: usize, ncols: usize) -> CudaResult { - assert_eq!( - data.len(), - nrows * ncols, - "The data length much match the array length." - ); - DeviceBuffer::from_slice(data).map(|data| Self { data, nrows, ncols }) - } - - /// Initialize, using a matrix, a 2D cuda array on the GPU. - pub fn from_matrix(mat: &na::DMatrix) -> CudaResult { - Self::new(mat.as_slice(), mat.nrows(), mat.ncols()) - } - - /// Gets the device pointer to the CUDA memory. - pub fn as_device_ptr(&self) -> CudaArrayPointer2 { - CudaArrayPointer2 { - data: self.data.as_device_ptr(), - nrows: self.nrows, - ncols: self.ncols, - } - } -} - -#[cfg(feature = "std")] -impl Array2 for CudaArray2 { - type Item = T; - - fn nrows(&self) -> usize { - panic!("Cuda arrays cannot be read directly."); - } - - fn ncols(&self) -> usize { - panic!("Cuda arrays cannot be read directly."); - } - - fn get(&self, i: usize, j: usize) -> Self::Item { - panic!("Cuda arrays cannot be read directly."); - } - - fn set(&mut self, i: usize, j: usize, val: Self::Item) { - panic!("Cuda arrays cannot be read directly."); - } -} - -#[repr(C)] -#[derive(Copy, Clone, cust_core::DeviceCopy)] -/// A pointer to a 2D CUDA array. -pub struct CudaArrayPointer2 { - data: DevicePointer, - nrows: usize, - ncols: usize, -} - -#[cfg(all(feature = "dim3", target_os = "cuda"))] -impl Array2 for CudaArrayPointer2 { - type Item = T; - - #[inline] - fn nrows(&self) -> usize { - self.nrows - } - - #[inline] - fn ncols(&self) -> usize { - self.ncols - } - - #[inline] - fn get(&self, i: usize, j: usize) -> Self::Item { - let linear_index = i + j * self.nrows; - assert!(linear_index < self.nrows * self.ncols); - unsafe { *self.data.as_ptr().add(linear_index) } - } - - #[inline] - fn set(&mut self, i: usize, j: usize, val: Self::Item) { - let linear_index = i + j * self.nrows; - assert!(linear_index < self.nrows * self.ncols); - unsafe { - *self.data.as_mut_ptr().add(linear_index) = val; - } - } -} - -#[cfg(all(feature = "dim3", not(target_os = "cuda")))] -impl Array2 for CudaArrayPointer2 { - type Item = T; - - fn nrows(&self) -> usize { - panic!("Cuda pointers can only be read from of a cuda kernel."); - } - - fn ncols(&self) -> usize { - panic!("Cuda pointers can only be read from of a cuda kernel."); - } - - fn get(&self, i: usize, j: usize) -> Self::Item { - panic!("Cuda pointers can only be read from of a cuda kernel."); - } - - fn set(&mut self, i: usize, j: usize, val: Self::Item) { - panic!("Cuda pointers can only be read from of a cuda kernel."); - } -} - -/* - * - * 1D array. - * - */ -#[cfg(feature = "std")] -/// A 1D array residing on GPU memory. -pub struct CudaArray1 { - data: DeviceBuffer, -} - -#[cfg(feature = "std")] -impl CudaArray1 { - /// Initialize a 1D cuda array on the GPU. - pub fn new(data: &[T]) -> CudaResult { - DeviceBuffer::from_slice(data).map(|data| Self { data }) - } - - /// Initialize a 1D cuda array on the GPU using a dynamically-sized vector. - pub fn from_vector(vect: &na::DVector) -> CudaResult { - Self::new(vect.as_slice()) - } - - /// Gets the device pointer to the CUDA memory. - pub fn as_device_ptr(&self) -> CudaArrayPointer1 { - CudaArrayPointer1 { - data: self.data.as_device_ptr(), - len: self.data.len(), - } - } -} - -#[cfg(feature = "std")] -impl Array1 for CudaArray1 { - fn len(&self) -> usize { - panic!("Cuda arrays cannot be read directly."); - } -} - -#[cfg(feature = "std")] -impl Index for CudaArray1 { - type Output = T; - - #[inline] - fn index(&self, _: usize) -> &T { - panic!("Cuda arrays cannot be read directly."); - } -} - -#[cfg(feature = "std")] -impl IndexMut for CudaArray1 { - #[inline] - fn index_mut(&mut self, _: usize) -> &mut T { - panic!("Cuda arrays cannot be read directly."); - } -} - -#[repr(C)] -#[derive(Copy, Clone, cust_core::DeviceCopy)] -/// A pointer to a 2D CUDA array. -pub struct CudaArrayPointer1 { - data: DevicePointer, - len: usize, -} - -#[cfg(target_os = "cuda")] -impl CudaArrayPointer1 { - #[inline] - pub fn len(&self) -> usize { - self.len - } - - #[inline] - pub fn get(&self, i: usize) -> T { - assert!(i < self.len); - unsafe { *self.data.as_ptr().add(i) } - } - - #[inline] - pub fn set(&mut self, i: usize, val: T) { - assert!(i < self.len); - unsafe { - *self.data.as_mut_ptr().add(i) = val; - } - } -} - -#[cfg(not(target_os = "cuda"))] -impl Array1 for CudaArrayPointer1 { - fn len(&self) -> usize { - panic!("Cuda pointers can only be read from of a cuda kernel."); - } -} - -#[cfg(target_os = "cuda")] -impl Array1 for CudaArrayPointer1 { - #[inline] - fn len(&self) -> usize { - self.len - } -} - -#[cfg(not(target_os = "cuda"))] -impl Index for CudaArrayPointer1 { - type Output = T; - - #[inline] - fn index(&self, i: usize) -> &T { - panic!("Cuda pointers can only be read from of a cuda kernel."); - } -} - -#[cfg(not(target_os = "cuda"))] -impl IndexMut for CudaArrayPointer1 { - #[inline] - fn index_mut(&mut self, i: usize) -> &mut T { - panic!("Cuda pointers can only be read from of a cuda kernel."); - } -} - -#[cfg(target_os = "cuda")] -impl Index for CudaArrayPointer1 { - type Output = T; - - #[inline] - fn index(&self, i: usize) -> &T { - assert!(i < self.len); - unsafe { &*self.data.as_ptr().add(i) } - } -} - -#[cfg(target_os = "cuda")] -impl IndexMut for CudaArrayPointer1 { - #[inline] - fn index_mut(&mut self, i: usize) -> &mut T { - assert!(i < self.len); - unsafe { &mut *self.data.as_mut_ptr().add(i) } - } -} diff --git a/src/utils/cuda_device_pointer.rs b/src/utils/cuda_device_pointer.rs deleted file mode 100644 index b5a73611..00000000 --- a/src/utils/cuda_device_pointer.rs +++ /dev/null @@ -1,33 +0,0 @@ -#[cfg(not(target_os = "cuda"))] -pub use cust::memory::DevicePointer; - -#[cfg(target_os = "cuda")] -pub use self::cuda_utils::*; - -#[cfg(target_os = "cuda")] -pub mod cuda_utils { - #[repr(transparent)] - #[derive(PartialEq)] - pub struct DevicePointer(*mut T); - - impl Clone for DevicePointer { - fn clone(&self) -> Self { - Self(self.0) - } - } - - impl Copy for DevicePointer {} - unsafe impl cust_core::DeviceCopy for DevicePointer {} - - impl DevicePointer { - pub fn null() -> Self { - Self(core::ptr::null_mut()) - } - pub fn as_ptr(self) -> *const T { - self.0 - } - pub fn as_mut_ptr(&self) -> *mut T { - self.0 - } - } -} diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 6dbfe227..ce43163a 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -17,7 +17,6 @@ pub use self::point_cloud_support_point::{ pub use self::point_in_poly2d::{point_in_convex_poly2d, point_in_poly2d}; pub use self::sdp_matrix::{SdpMatrix2, SdpMatrix3}; -pub use self::array::{Array1, Array2, DefaultStorage}; pub use self::as_bytes::AsBytes; pub(crate) use self::consts::*; pub use self::cov::{center_cov, cov}; @@ -33,16 +32,6 @@ pub use self::sorted_pair::SortedPair; pub(crate) use self::weighted_value::WeightedValue; pub(crate) use self::wops::{simd_swap, WBasis, WCross, WSign}; -#[cfg(all(feature = "cuda", feature = "std"))] -pub use self::cuda_array::{CudaArray1, CudaArray2}; -#[cfg(feature = "cuda")] -pub use { - self::array::{CudaStorage, CudaStoragePtr}, - self::cuda_array::{CudaArrayPointer1, CudaArrayPointer2}, - self::cuda_device_pointer::DevicePointer, -}; - -mod array; mod as_bytes; mod ccw_face_normal; mod center; @@ -51,10 +40,6 @@ mod center; mod cleanup; mod consts; mod cov; -#[cfg(feature = "cuda")] -mod cuda_array; -#[cfg(feature = "cuda")] -mod cuda_device_pointer; #[cfg(feature = "std")] mod deterministic_state; mod hashable_partial_eq;