Skip to main content

dynamis_world/
shape.rs

1use super::World;
2use crate::shape_pool::{ShapePool, height_field_triangles};
3use dynamis_abi::{SHAPE_HEIGHTFIELD, SHAPE_HULL, SHAPE_MESH};
4use dynamis_hull::hull;
5use dynamis_model::{Shape, ShapeSourceHandle, SolidGeometry, SurfaceDesc, SurfaceTable};
6
7#[derive(Clone)]
8pub(crate) struct Shapes {
9    pub(crate) pool: ShapePool,
10    pub(crate) dirty: bool,
11    pub(crate) uploaded: bool,
12}
13
14impl Shapes {
15    pub(crate) fn new() -> Self {
16        Self {
17            pool: ShapePool::new(),
18            dirty: false,
19            uploaded: false,
20        }
21    }
22}
23
24impl World {
25    pub fn add_hull(&mut self, vertices: &[[f32; 3]], triangles: &[[u32; 3]]) -> ShapeSourceHandle {
26        self.allocate_shape(SHAPE_HULL, vertices, triangles.to_vec(), None)
27    }
28
29    pub fn add_mesh(
30        &mut self,
31        vertices: &[[f32; 3]],
32        triangles: &[[u32; 3]],
33        surfaces: Option<SurfaceTable<'_>>,
34    ) -> ShapeSourceHandle {
35        self.allocate_shape(SHAPE_MESH, vertices, triangles.to_vec(), surfaces)
36    }
37
38    pub fn add_decomposed_mesh(
39        &mut self,
40        vertices: &[[f32; 3]],
41        triangles: &[[u32; 3]],
42        settings: dynamis_hull::DecomposeSettings,
43    ) -> Vec<ShapeSourceHandle> {
44        let parts = dynamis_hull::decompose(vertices, triangles, &settings);
45        parts
46            .iter()
47            .map(|part| self.add_hull(&part.vertices, &part.triangles))
48            .collect()
49    }
50
51    pub fn add_hull_from_mesh(
52        &mut self,
53        vertices: &[[f32; 3]],
54        triangles: &[[u32; 3]],
55    ) -> ShapeSourceHandle {
56        let (hull_vertices, hull_triangles) = hull(vertices, triangles);
57        self.allocate_shape(SHAPE_HULL, &hull_vertices, hull_triangles, None)
58    }
59
60    pub fn add_height_field(
61        &mut self,
62        rows: u32,
63        cols: u32,
64        heights: &[f32],
65        cell_size: [f32; 2],
66        surfaces: Option<SurfaceTable<'_>>,
67    ) -> ShapeSourceHandle {
68        let (vertices, triangles) = height_field_triangles(rows, cols, heights, cell_size);
69        let expanded = height_field_surfaces(surfaces, rows, cols);
70        let table = expanded
71            .as_ref()
72            .map(|(palette, indices)| SurfaceTable::new(palette, indices));
73        self.allocate_shape(SHAPE_HEIGHTFIELD, &vertices, triangles, table)
74    }
75
76    pub fn remove_shape(&mut self, handle: ShapeSourceHandle) {
77        self.shapes.pool.remove(handle);
78        self.shapes.dirty = true;
79    }
80
81    pub fn update_mesh(
82        &mut self,
83        handle: ShapeSourceHandle,
84        vertices: &[[f32; 3]],
85        triangles: &[[u32; 3]],
86        surfaces: Option<SurfaceTable<'_>>,
87    ) {
88        self.shapes
89            .pool
90            .update_mesh(handle, vertices, triangles, surfaces);
91        self.shapes.dirty = true;
92    }
93
94    pub fn update_height_field(
95        &mut self,
96        handle: ShapeSourceHandle,
97        rows: u32,
98        cols: u32,
99        heights: &[f32],
100        cell_size: [f32; 2],
101        surfaces: Option<SurfaceTable<'_>>,
102    ) {
103        let (vertices, triangles) = height_field_triangles(rows, cols, heights, cell_size);
104        let expanded = height_field_surfaces(surfaces, rows, cols);
105        let table = expanded
106            .as_ref()
107            .map(|(palette, indices)| SurfaceTable::new(palette, indices));
108        self.update_mesh(handle, &vertices, &triangles, table);
109    }
110
111    fn allocate_shape(
112        &mut self,
113        kind: u32,
114        vertices: &[[f32; 3]],
115        triangles: Vec<[u32; 3]>,
116        surfaces: Option<SurfaceTable<'_>>,
117    ) -> ShapeSourceHandle {
118        let handle = self
119            .shapes
120            .pool
121            .allocate(kind, vertices, &triangles, surfaces);
122        self.shapes.dirty = true;
123        handle
124    }
125
126    pub(super) fn shape_solid(&self, shape: &Shape) -> Option<SolidGeometry> {
127        match shape {
128            Shape::Hull(handle) => Some(self.shapes.pool.solid(*handle)),
129            _ => None,
130        }
131    }
132}
133
134fn height_field_surfaces(
135    surfaces: Option<SurfaceTable<'_>>,
136    rows: u32,
137    cols: u32,
138) -> Option<(Vec<SurfaceDesc>, Vec<u32>)> {
139    let table = surfaces?;
140    let cells = rows.saturating_sub(1) * cols.saturating_sub(1);
141    assert_eq!(
142        table.count(),
143        cells as usize,
144        "a height field carries one surface per cell"
145    );
146    let palette = table.palette().to_vec();
147    let mut indices = Vec::with_capacity(table.count() * 2);
148    for index in table.indices() {
149        indices.push(*index);
150        indices.push(*index);
151    }
152    Some((palette, indices))
153}