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}