1use super::types::{
9 CompoundCapsule, CompoundData, CompoundDef, CompoundSphere, HullInstance, MeshInstance,
10 COMPOUND_CONVEX_SIZE, COMPOUND_DATA_SIZE, COMPOUND_VERSION, HULL_INSTANCE_SIZE,
11 MAX_COMPOUND_MESH_MATERIALS, MESH_INSTANCE_SIZE, TREE_NODE_SIZE,
12};
13use crate::constants::MAX_CHILD_SHAPES;
14use crate::core::NULL_INDEX;
15use crate::dynamic_tree::DynamicTree;
16use crate::geometry::{
17 compute_capsule_aabb, compute_sphere_aabb, SurfaceMaterial, SURFACE_MATERIAL_SIZE,
18};
19use crate::hull::{compare_hull_data, compute_hull_aabb, HullData};
20use crate::math_functions::TRANSFORM_IDENTITY;
21use crate::mesh::{compute_mesh_aabb, MeshData};
22
23struct SharedHull {
24 hull: HullData,
25 hull_offset: i32,
26}
27
28struct SharedMesh {
29 mesh_data: MeshData,
30 mesh_offset: i32,
31}
32
33fn materials_equal(a: &SurfaceMaterial, b: &SurfaceMaterial) -> bool {
34 a.to_bytes() == b.to_bytes()
35}
36
37fn get_or_insert_material(materials: &mut Vec<SurfaceMaterial>, mat: &SurfaceMaterial) -> i32 {
38 if let Some(i) = materials.iter().position(|m| materials_equal(m, mat)) {
39 return i as i32;
40 }
41 let index = materials.len() as i32;
42 materials.push(*mat);
43 index
44}
45
46fn meshes_equal(a: &MeshData, b: &MeshData) -> bool {
47 if core::ptr::eq(a, b) {
48 return true;
49 }
50 if a.byte_count != b.byte_count {
51 return false;
52 }
53 a.to_bytes() == b.to_bytes()
54}
55
56pub fn create_compound(def: &CompoundDef<'_>) -> Option<CompoundData> {
58 let capsule_count = def.capsules.len() as i32;
59 let hull_count = def.hulls.len() as i32;
60 let mesh_count = def.meshes.len() as i32;
61 let sphere_count = def.spheres.len() as i32;
62
63 let convex_count = capsule_count + hull_count + sphere_count;
64 let shape_count = convex_count + mesh_count;
65
66 if shape_count >= MAX_CHILD_SHAPES {
67 debug_assert!(false);
68 return None;
69 }
70
71 let mut tree = DynamicTree::new(shape_count);
72 let mut child_index = 0i32;
73
74 let mut capsule_instances = vec![CompoundCapsule::default(); capsule_count as usize];
75 let mut hull_instances = vec![
76 HullInstance {
77 transform: TRANSFORM_IDENTITY,
78 shared_index: 0,
79 material_index: 0,
80 hull_offset: 0,
81 };
82 hull_count as usize
83 ];
84 let mut mesh_instances = vec![
85 MeshInstance {
86 transform: TRANSFORM_IDENTITY,
87 scale: crate::math_functions::VEC3_ONE,
88 shared_index: 0,
89 material_indices: [0; MAX_COMPOUND_MESH_MATERIALS],
90 mesh_offset: 0,
91 };
92 mesh_count as usize
93 ];
94 let mut sphere_instances = vec![CompoundSphere::default(); sphere_count as usize];
95
96 let mut material_capacity = convex_count;
97 for mesh in def.meshes {
98 debug_assert!(!mesh.materials.is_empty());
99 material_capacity += mesh.materials.len() as i32;
100 }
101
102 let mut materials: Vec<SurfaceMaterial> = Vec::with_capacity(material_capacity.max(0) as usize);
103
104 for (i, capsule_def) in def.capsules.iter().enumerate() {
105 capsule_instances[i].capsule = capsule_def.capsule;
106 let material_index = get_or_insert_material(&mut materials, &capsule_def.material);
107 capsule_instances[i].material_index = material_index;
108
109 let aabb = compute_capsule_aabb(&capsule_def.capsule, TRANSFORM_IDENTITY);
110 tree.create_proxy(aabb, !0u64, child_index as u64);
111 child_index += 1;
112 }
113
114 let mut shared_hulls: Vec<SharedHull> = Vec::with_capacity(hull_count as usize);
115
116 for (i, hull_def) in def.hulls.iter().enumerate() {
117 let hull = hull_def.hull;
118 let aabb = compute_hull_aabb(hull, hull_def.transform);
119 tree.create_proxy(aabb, !0u64, child_index as u64);
120 child_index += 1;
121
122 let material_index = get_or_insert_material(&mut materials, &hull_def.material);
123 hull_instances[i].material_index = material_index as u32;
124 hull_instances[i].transform = hull_def.transform;
125
126 let shared_index = if let Some(idx) = shared_hulls
127 .iter()
128 .position(|s| compare_hull_data(&s.hull, hull))
129 {
130 idx
131 } else {
132 let idx = shared_hulls.len();
133 shared_hulls.push(SharedHull {
134 hull: hull.clone(),
135 hull_offset: NULL_INDEX,
136 });
137 idx
138 };
139 hull_instances[i].shared_index = shared_index as u32;
140 hull_instances[i].hull_offset = shared_index as u32;
142 }
143
144 let mut shared_meshes: Vec<SharedMesh> = Vec::with_capacity(mesh_count as usize);
145
146 for (i, mesh_def) in def.meshes.iter().enumerate() {
147 let mesh_data = mesh_def.mesh_data;
148 let aabb = compute_mesh_aabb(mesh_data, mesh_def.transform, mesh_def.scale);
149 tree.create_proxy(aabb, !0u64, child_index as u64);
150 child_index += 1;
151
152 debug_assert_eq!(mesh_data.material_count as usize, mesh_def.materials.len());
153
154 for (j, mat) in mesh_def.materials.iter().enumerate() {
155 let material_index = get_or_insert_material(&mut materials, mat);
156 mesh_instances[i].material_indices[j] = material_index as u32;
157 }
158
159 let shared_index = if let Some(idx) = shared_meshes
160 .iter()
161 .position(|s| meshes_equal(&s.mesh_data, mesh_data))
162 {
163 idx
164 } else {
165 let idx = shared_meshes.len();
166 shared_meshes.push(SharedMesh {
167 mesh_data: mesh_data.clone(),
168 mesh_offset: NULL_INDEX,
169 });
170 idx
171 };
172
173 mesh_instances[i].transform = mesh_def.transform;
174 mesh_instances[i].scale = mesh_def.scale;
175 mesh_instances[i].shared_index = shared_index as u32;
176 mesh_instances[i].mesh_offset = shared_index as u32;
177 }
178
179 for (i, sphere_def) in def.spheres.iter().enumerate() {
180 sphere_instances[i].sphere = sphere_def.sphere;
181 let material_index = get_or_insert_material(&mut materials, &sphere_def.material);
182 sphere_instances[i].material_index = material_index;
183
184 let aabb = compute_sphere_aabb(&sphere_def.sphere, TRANSFORM_IDENTITY);
185 tree.create_proxy(aabb, !0u64, child_index as u64);
186 child_index += 1;
187 }
188
189 let material_count = materials.len() as i32;
190 debug_assert!(material_count <= material_capacity);
191 debug_assert!(tree.node_count() > 0);
192
193 tree.rebuild(true);
194
195 let shared_hull_count = shared_hulls.len() as i32;
196 let shared_mesh_count = shared_meshes.len() as i32;
197
198 let mut byte_count = COMPOUND_DATA_SIZE;
199
200 let node_offset = byte_count as i32;
201 byte_count += tree.node_capacity() as usize * TREE_NODE_SIZE;
202
203 let material_offset = byte_count as i32;
204 byte_count += material_count as usize * SURFACE_MATERIAL_SIZE;
205
206 let capsule_offset = byte_count as i32;
207 byte_count += capsule_count as usize * COMPOUND_CONVEX_SIZE;
208
209 let hull_array_offset = byte_count as i32;
210 byte_count += hull_count as usize * HULL_INSTANCE_SIZE;
211
212 for shared in &mut shared_hulls {
213 shared.hull_offset = byte_count as i32;
214 byte_count += shared.hull.byte_count as usize;
215 }
216
217 let mesh_array_offset = byte_count as i32;
218 byte_count += mesh_count as usize * MESH_INSTANCE_SIZE;
219
220 for shared in &mut shared_meshes {
221 shared.mesh_offset = byte_count as i32;
222 byte_count += shared.mesh_data.byte_count as usize;
223 }
224
225 let sphere_offset = byte_count as i32;
226 byte_count += sphere_count as usize * COMPOUND_CONVEX_SIZE;
227
228 for inst in &mut hull_instances {
231 let shared_index = inst.hull_offset as usize;
232 debug_assert!(shared_index < shared_hulls.len());
233 inst.hull_offset = shared_hulls[shared_index].hull_offset as u32;
234 }
235 for inst in &mut mesh_instances {
236 let shared_index = inst.mesh_offset as usize;
237 debug_assert!(shared_index < shared_meshes.len());
238 inst.mesh_offset = shared_meshes[shared_index].mesh_offset as u32;
239 }
240
241 tree.free_list = 0;
243 tree.leaf_indices.clear();
244 tree.leaf_centers.clear();
245 tree.rebuild_capacity = 0;
246
247 debug_assert!(material_count > 0);
248
249 Some(CompoundData {
250 version: COMPOUND_VERSION,
251 byte_count: byte_count as i32,
252 node_offset,
253 tree,
254 material_offset,
255 material_count,
256 capsule_offset,
257 capsule_count,
258 hull_offset: hull_array_offset,
259 hull_count,
260 shared_hull_count,
261 mesh_offset: mesh_array_offset,
262 mesh_count,
263 shared_mesh_count,
264 sphere_offset,
265 sphere_count,
266 materials,
267 capsules: capsule_instances,
268 hull_instances,
269 shared_hulls: shared_hulls.into_iter().map(|s| s.hull).collect(),
270 mesh_instances,
271 shared_meshes: shared_meshes.into_iter().map(|s| s.mesh_data).collect(),
272 spheres: sphere_instances,
273 })
274}
275
276pub fn destroy_compound(_compound: CompoundData) {}