Skip to main content

dynamis_world/world/
shape.rs

1use super::World;
2use crate::world::shape_pool::{ShapePool, height_field_triangles};
3use dynamis_layout::{SHAPE_HEIGHTFIELD, SHAPE_HULL, SHAPE_MESH};
4use dynamis_mesh::convex_hull_mesh;
5use dynamis_model::{MAX_COLLIDERS_PER_BODY, Shape, ShapeSourceHandle};
6
7pub(crate) struct Shapes {
8    pub(crate) pool: ShapePool,
9    pub(crate) dirty: bool,
10}
11
12impl Shapes {
13    pub(crate) fn new() -> Self {
14        Self {
15            pool: ShapePool::new(),
16            dirty: false,
17        }
18    }
19}
20
21impl World {
22    pub fn add_hull(&mut self, vertices: &[[f32; 3]], triangles: &[[u32; 3]]) -> ShapeSourceHandle {
23        self.allocate_shape(SHAPE_HULL, vertices, triangles.to_vec())
24    }
25
26    pub fn add_mesh(&mut self, vertices: &[[f32; 3]], triangles: &[[u32; 3]]) -> ShapeSourceHandle {
27        self.allocate_shape(SHAPE_MESH, vertices, triangles.to_vec())
28    }
29
30    pub fn add_decomposed_mesh(
31        &mut self,
32        vertices: &[[f32; 3]],
33        triangles: &[[u32; 3]],
34        settings: dynamis_mesh::HullDecomposeSettings,
35    ) -> Vec<ShapeSourceHandle> {
36        assert!(
37            settings.max_parts as usize <= MAX_COLLIDERS_PER_BODY,
38            "decomposition part limit must fit within one body"
39        );
40        let parts = dynamis_mesh::decompose_mesh(vertices, triangles, &settings);
41        parts
42            .iter()
43            .map(|part| self.add_hull(&part.vertices, &part.triangles))
44            .collect()
45    }
46
47    pub fn add_hull_from_mesh(
48        &mut self,
49        vertices: &[[f32; 3]],
50        triangles: &[[u32; 3]],
51    ) -> ShapeSourceHandle {
52        let (hull_vertices, hull_triangles) = convex_hull_mesh(vertices, triangles);
53        self.allocate_shape(SHAPE_HULL, &hull_vertices, hull_triangles)
54    }
55
56    pub fn add_height_field(
57        &mut self,
58        rows: u32,
59        cols: u32,
60        heights: &[f32],
61        cell_size: [f32; 2],
62    ) -> ShapeSourceHandle {
63        let (vertices, triangles) = height_field_triangles(rows, cols, heights, cell_size);
64        self.allocate_shape(SHAPE_HEIGHTFIELD, &vertices, triangles)
65    }
66
67    pub fn remove_shape(&mut self, handle: ShapeSourceHandle) {
68        self.shapes.pool.remove(handle);
69        self.shapes.dirty = true;
70    }
71
72    pub fn update_mesh(
73        &mut self,
74        handle: ShapeSourceHandle,
75        vertices: &[[f32; 3]],
76        triangles: &[[u32; 3]],
77    ) {
78        self.shapes.pool.update_mesh(handle, vertices, triangles);
79        self.shapes.pool.upload_update(
80            self.backend.gpu.queue(),
81            &self.backend.buffers.shapes.sources,
82            &self.backend.buffers.shapes.vertices,
83            &self.backend.buffers.shapes.triangles,
84            &self.backend.buffers.shapes.nodes,
85            handle,
86        );
87    }
88
89    pub fn update_height_field(
90        &mut self,
91        handle: ShapeSourceHandle,
92        rows: u32,
93        cols: u32,
94        heights: &[f32],
95        cell_size: [f32; 2],
96    ) {
97        let (vertices, triangles) = height_field_triangles(rows, cols, heights, cell_size);
98        self.update_mesh(handle, &vertices, &triangles);
99    }
100
101    fn allocate_shape(
102        &mut self,
103        kind: u32,
104        vertices: &[[f32; 3]],
105        triangles: Vec<[u32; 3]>,
106    ) -> ShapeSourceHandle {
107        let handle = self.shapes.pool.allocate(kind, vertices, &triangles);
108        self.shapes.dirty = true;
109        handle
110    }
111
112    pub(super) fn shape_bounds(&self, shape: &Shape) -> Option<([f32; 3], [f32; 3])> {
113        match shape {
114            Shape::Hull(handle) | Shape::Mesh(handle) | Shape::HeightField(handle) => {
115                Some(self.shapes.pool.record(*handle).bounds)
116            }
117            _ => None,
118        }
119    }
120}