1use super::types::{
9 CompoundCapsule, CompoundData, CompoundSphere, HullInstance, MeshInstance,
10 COMPOUND_CONVEX_SIZE, COMPOUND_DATA_SIZE, COMPOUND_VERSION, DYNAMIC_TREE_SIZE,
11 HULL_INSTANCE_SIZE, MAX_COMPOUND_MESH_MATERIALS, MESH_INSTANCE_SIZE, TREE_NODE_SIZE,
12};
13use crate::core::NULL_INDEX;
14use crate::dynamic_tree::{DynamicTree, TreeNode, ALLOCATED_NODE, DYNAMIC_TREE_VERSION, LEAF_NODE};
15use crate::geometry::{SurfaceMaterial, SURFACE_MATERIAL_SIZE};
16use crate::hull::{HullData, HullFace, HullHalfEdge, HullVertex, HULL_DATA_SIZE, HULL_VERSION};
17use crate::math_functions::{
18 Aabb, Matrix3, Plane, Quat, Transform, Vec3, MAT3_ZERO, QUAT_IDENTITY, TRANSFORM_IDENTITY,
19 VEC3_ONE, VEC3_ZERO,
20};
21use crate::mesh::{
22 MeshData, MeshNode, MeshTriangle, MESH_DATA_SIZE, MESH_NODE_SIZE, MESH_TRIANGLE_SIZE,
23 MESH_VERSION,
24};
25
26fn write_u64(buf: &mut Vec<u8>, v: u64) {
27 buf.extend_from_slice(&v.to_le_bytes());
28}
29fn write_u32(buf: &mut Vec<u8>, v: u32) {
30 buf.extend_from_slice(&v.to_le_bytes());
31}
32fn write_i32(buf: &mut Vec<u8>, v: i32) {
33 buf.extend_from_slice(&v.to_le_bytes());
34}
35fn write_f32(buf: &mut Vec<u8>, v: f32) {
36 buf.extend_from_slice(&v.to_le_bytes());
37}
38fn write_vec3(buf: &mut Vec<u8>, v: Vec3) {
39 write_f32(buf, v.x);
40 write_f32(buf, v.y);
41 write_f32(buf, v.z);
42}
43fn write_quat(buf: &mut Vec<u8>, q: Quat) {
44 write_vec3(buf, q.v);
45 write_f32(buf, q.s);
46}
47fn write_transform(buf: &mut Vec<u8>, t: Transform) {
48 write_vec3(buf, t.p);
49 write_quat(buf, t.q);
50}
51fn write_aabb(buf: &mut Vec<u8>, a: Aabb) {
52 write_vec3(buf, a.lower_bound);
53 write_vec3(buf, a.upper_bound);
54}
55fn pad_to(buf: &mut Vec<u8>, len: usize) {
56 if buf.len() < len {
57 buf.resize(len, 0);
58 }
59}
60
61fn write_tree_node(buf: &mut Vec<u8>, node: &TreeNode) {
62 write_aabb(buf, node.aabb);
63 write_u64(buf, node.category_bits);
64 if node.flags & LEAF_NODE != 0 {
65 write_u64(buf, node.user_data);
66 } else {
67 write_i32(buf, node.child1);
68 write_i32(buf, node.child2);
69 }
70 if node.flags & ALLOCATED_NODE != 0 {
72 write_i32(buf, node.parent);
73 } else {
74 write_i32(buf, node.next);
75 }
76 buf.extend_from_slice(&node.height.to_le_bytes());
77 buf.extend_from_slice(&node.flags.to_le_bytes());
78}
79
80fn write_dynamic_tree_header(buf: &mut Vec<u8>, tree: &DynamicTree, nodes_ptr_zeroed: bool) {
81 let start = buf.len();
82 write_u64(buf, tree.version());
83 if nodes_ptr_zeroed {
85 buf.extend_from_slice(&0u64.to_le_bytes());
86 } else {
87 buf.extend_from_slice(&0u64.to_le_bytes());
88 }
89 write_i32(buf, tree.root);
90 write_i32(buf, tree.node_count());
91 write_i32(buf, tree.node_capacity());
92 write_i32(buf, tree.proxy_count());
93 write_i32(buf, tree.free_list);
94 pad_to(buf, start + 40);
96 buf.extend_from_slice(&0u64.to_le_bytes());
98 buf.extend_from_slice(&0u64.to_le_bytes());
99 buf.extend_from_slice(&0u64.to_le_bytes());
100 buf.extend_from_slice(&0u64.to_le_bytes());
101 write_i32(buf, tree.rebuild_capacity);
102 pad_to(buf, start + DYNAMIC_TREE_SIZE);
103}
104
105fn write_compound_header(buf: &mut Vec<u8>, c: &CompoundData) {
106 write_u64(buf, c.version);
107 write_i32(buf, c.byte_count);
108 write_i32(buf, c.node_offset);
109 write_dynamic_tree_header(buf, &c.tree, true);
110 write_i32(buf, c.material_offset);
111 write_i32(buf, c.material_count);
112 write_i32(buf, c.capsule_offset);
113 write_i32(buf, c.capsule_count);
114 write_i32(buf, c.hull_offset);
115 write_i32(buf, c.hull_count);
116 write_i32(buf, c.shared_hull_count);
117 write_i32(buf, c.mesh_offset);
118 write_i32(buf, c.mesh_count);
119 write_i32(buf, c.shared_mesh_count);
120 write_i32(buf, c.sphere_offset);
121 write_i32(buf, c.sphere_count);
122 debug_assert_eq!(buf.len(), COMPOUND_DATA_SIZE);
123}
124
125fn write_capsule(buf: &mut Vec<u8>, c: &CompoundCapsule) {
126 write_vec3(buf, c.capsule.center1);
127 write_vec3(buf, c.capsule.center2);
128 write_f32(buf, c.capsule.radius);
129 write_i32(buf, c.material_index);
130}
131
132fn write_sphere(buf: &mut Vec<u8>, s: &CompoundSphere) {
133 write_vec3(buf, s.sphere.center);
134 write_f32(buf, s.sphere.radius);
135 write_i32(buf, s.material_index);
136}
137
138fn write_hull_instance(buf: &mut Vec<u8>, h: &HullInstance) {
139 write_transform(buf, h.transform);
140 write_u32(buf, h.hull_offset);
141 write_u32(buf, h.material_index);
142}
143
144fn write_mesh_instance(buf: &mut Vec<u8>, m: &MeshInstance) {
145 write_transform(buf, m.transform);
146 write_vec3(buf, m.scale);
147 write_u32(buf, m.mesh_offset);
148 for i in 0..MAX_COMPOUND_MESH_MATERIALS {
149 write_u32(buf, m.material_indices[i]);
150 }
151}
152
153impl CompoundData {
154 pub fn to_bytes(&self) -> Vec<u8> {
156 let mut buf = Vec::with_capacity(self.byte_count as usize);
157 write_compound_header(&mut buf, self);
158
159 pad_to(&mut buf, self.node_offset as usize);
160 for node in &self.tree.nodes {
161 write_tree_node(&mut buf, node);
162 }
163
164 pad_to(&mut buf, self.material_offset as usize);
165 for mat in &self.materials {
166 buf.extend_from_slice(&mat.to_bytes());
167 }
168
169 pad_to(&mut buf, self.capsule_offset as usize);
170 for cap in &self.capsules {
171 write_capsule(&mut buf, cap);
172 }
173
174 pad_to(&mut buf, self.hull_offset as usize);
175 for inst in &self.hull_instances {
176 write_hull_instance(&mut buf, inst);
177 }
178 for (i, hull) in self.shared_hulls.iter().enumerate() {
180 let offset = self
181 .hull_instances
182 .iter()
183 .find(|inst| inst.shared_index as usize == i)
184 .map(|inst| inst.hull_offset as usize)
185 .unwrap_or(0);
186 if offset > 0 {
187 pad_to(&mut buf, offset);
188 buf.extend_from_slice(&hull.to_bytes());
189 }
190 }
191
192 pad_to(&mut buf, self.mesh_offset as usize);
193 for inst in &self.mesh_instances {
194 write_mesh_instance(&mut buf, inst);
195 }
196 for (i, mesh) in self.shared_meshes.iter().enumerate() {
197 let offset = self
198 .mesh_instances
199 .iter()
200 .find(|inst| inst.shared_index as usize == i)
201 .map(|inst| inst.mesh_offset as usize)
202 .unwrap_or(0);
203 if offset > 0 {
204 pad_to(&mut buf, offset);
205 buf.extend_from_slice(&mesh.to_bytes());
206 }
207 }
208
209 pad_to(&mut buf, self.sphere_offset as usize);
210 for sph in &self.spheres {
211 write_sphere(&mut buf, sph);
212 }
213
214 pad_to(&mut buf, self.byte_count as usize);
215 debug_assert_eq!(buf.len(), self.byte_count as usize);
216 buf
217 }
218}
219
220pub fn convert_compound_to_bytes(compound: &CompoundData) -> Vec<u8> {
222 compound.to_bytes()
223}
224
225fn read_u64(buf: &[u8], o: usize) -> u64 {
226 u64::from_le_bytes(buf[o..o + 8].try_into().unwrap())
227}
228fn read_u32(buf: &[u8], o: usize) -> u32 {
229 u32::from_le_bytes(buf[o..o + 4].try_into().unwrap())
230}
231fn read_i32(buf: &[u8], o: usize) -> i32 {
232 i32::from_le_bytes(buf[o..o + 4].try_into().unwrap())
233}
234fn read_f32(buf: &[u8], o: usize) -> f32 {
235 f32::from_le_bytes(buf[o..o + 4].try_into().unwrap())
236}
237fn read_vec3(buf: &[u8], o: usize) -> Vec3 {
238 Vec3 {
239 x: read_f32(buf, o),
240 y: read_f32(buf, o + 4),
241 z: read_f32(buf, o + 8),
242 }
243}
244fn read_quat(buf: &[u8], o: usize) -> Quat {
245 Quat {
246 v: read_vec3(buf, o),
247 s: read_f32(buf, o + 12),
248 }
249}
250fn read_transform(buf: &[u8], o: usize) -> Transform {
251 Transform {
252 p: read_vec3(buf, o),
253 q: read_quat(buf, o + 12),
254 }
255}
256fn read_aabb(buf: &[u8], o: usize) -> Aabb {
257 Aabb {
258 lower_bound: read_vec3(buf, o),
259 upper_bound: read_vec3(buf, o + 12),
260 }
261}
262
263fn read_tree_node(buf: &[u8], o: usize) -> TreeNode {
264 let aabb = read_aabb(buf, o);
265 let category_bits = read_u64(buf, o + 24);
266 let union8 = read_u64(buf, o + 32);
267 let parent_or_next = read_i32(buf, o + 40);
268 let height = u16::from_le_bytes(buf[o + 44..o + 46].try_into().unwrap());
269 let flags = u16::from_le_bytes(buf[o + 46..o + 48].try_into().unwrap());
270
271 let (child1, child2, user_data) = if flags & LEAF_NODE != 0 {
272 (NULL_INDEX, NULL_INDEX, union8)
273 } else {
274 let c1 = read_i32(buf, o + 32);
275 let c2 = read_i32(buf, o + 36);
276 (c1, c2, 0)
277 };
278
279 let (parent, next) = if flags & ALLOCATED_NODE != 0 {
280 (parent_or_next, NULL_INDEX)
281 } else {
282 (NULL_INDEX, parent_or_next)
283 };
284
285 TreeNode {
286 aabb,
287 category_bits,
288 child1,
289 child2,
290 user_data,
291 parent,
292 next,
293 height,
294 flags,
295 }
296}
297
298fn read_plane(buf: &[u8], o: usize) -> Plane {
299 Plane {
300 normal: read_vec3(buf, o),
301 offset: read_f32(buf, o + 12),
302 }
303}
304
305fn read_matrix3(buf: &[u8], o: usize) -> Matrix3 {
306 Matrix3 {
307 cx: read_vec3(buf, o),
308 cy: read_vec3(buf, o + 12),
309 cz: read_vec3(buf, o + 24),
310 }
311}
312
313fn read_hull_data(buf: &[u8]) -> Option<HullData> {
314 if buf.len() < HULL_DATA_SIZE {
315 return None;
316 }
317 let version = read_u64(buf, 0);
318 if version != HULL_VERSION {
319 return None;
320 }
321 let byte_count = read_i32(buf, 8);
322 if byte_count as usize > buf.len() || byte_count < HULL_DATA_SIZE as i32 {
323 return None;
324 }
325 let hash = read_u32(buf, 12);
326 let aabb = read_aabb(buf, 16);
327 let surface_area = read_f32(buf, 40);
328 let volume = read_f32(buf, 44);
329 let inner_radius = read_f32(buf, 48);
330 let center = read_vec3(buf, 52);
331 let central_inertia = read_matrix3(buf, 64);
332 let vertex_count = read_i32(buf, 100);
333 let vertex_offset = read_i32(buf, 104);
334 let point_offset = read_i32(buf, 108);
335 let edge_count = read_i32(buf, 112);
336 let edge_offset = read_i32(buf, 116);
337 let face_count = read_i32(buf, 120);
338 let face_offset = read_i32(buf, 124);
339 let plane_offset = read_i32(buf, 128);
340 let padding = read_i32(buf, 132);
341
342 let mut vertices = Vec::with_capacity(vertex_count as usize);
343 for i in 0..vertex_count as usize {
344 let o = vertex_offset as usize + i;
345 if o >= buf.len() {
346 return None;
347 }
348 vertices.push(HullVertex { edge: buf[o] });
349 }
350
351 let mut points = Vec::with_capacity(vertex_count as usize);
352 for i in 0..vertex_count as usize {
353 let o = point_offset as usize + i * 12;
354 points.push(read_vec3(buf, o));
355 }
356
357 let mut edges = Vec::with_capacity(edge_count as usize);
358 for i in 0..edge_count as usize {
359 let o = edge_offset as usize + i * 4;
360 edges.push(HullHalfEdge {
361 next: buf[o],
362 twin: buf[o + 1],
363 origin: buf[o + 2],
364 face: buf[o + 3],
365 });
366 }
367
368 let mut faces = Vec::with_capacity(face_count as usize);
369 for i in 0..face_count as usize {
370 let o = face_offset as usize + i;
371 faces.push(HullFace { edge: buf[o] });
372 }
373
374 let mut planes = Vec::with_capacity(face_count as usize);
375 for i in 0..face_count as usize {
376 let o = plane_offset as usize + i * 16;
377 planes.push(read_plane(buf, o));
378 }
379
380 Some(HullData {
381 version,
382 byte_count,
383 hash,
384 aabb,
385 surface_area,
386 volume,
387 inner_radius,
388 center,
389 central_inertia,
390 vertex_count,
391 vertex_offset,
392 point_offset,
393 edge_count,
394 edge_offset,
395 face_count,
396 face_offset,
397 plane_offset,
398 padding,
399 vertices,
400 points,
401 edges,
402 faces,
403 planes,
404 })
405}
406
407fn read_mesh_data(buf: &[u8]) -> Option<MeshData> {
408 if buf.len() < MESH_DATA_SIZE {
409 return None;
410 }
411 let version = read_u64(buf, 0);
412 if version != MESH_VERSION {
413 return None;
414 }
415 let byte_count = read_i32(buf, 8);
416 if byte_count as usize > buf.len() || byte_count < MESH_DATA_SIZE as i32 {
417 return None;
418 }
419 let hash = read_u32(buf, 12);
420 let bounds = read_aabb(buf, 16);
421 let surface_area = read_f32(buf, 40);
422 let tree_height = read_i32(buf, 44);
423 let degenerate_count = read_i32(buf, 48);
424 let node_offset = read_i32(buf, 52);
425 let node_count = read_i32(buf, 56);
426 let vertex_offset = read_i32(buf, 60);
427 let vertex_count = read_i32(buf, 64);
428 let triangle_offset = read_i32(buf, 68);
429 let triangle_count = read_i32(buf, 72);
430 let material_offset = read_i32(buf, 76);
431 let material_count = read_i32(buf, 80);
432 let flags_offset = read_i32(buf, 84);
433
434 let mut nodes = Vec::with_capacity(node_count as usize);
435 for i in 0..node_count as usize {
436 let o = node_offset as usize + i * MESH_NODE_SIZE;
437 nodes.push(MeshNode {
438 lower_bound: read_vec3(buf, o),
439 data: read_u32(buf, o + 12),
440 upper_bound: read_vec3(buf, o + 16),
441 triangle_offset: read_u32(buf, o + 28),
442 });
443 }
444
445 let mut vertices = Vec::with_capacity(vertex_count as usize);
446 for i in 0..vertex_count as usize {
447 vertices.push(read_vec3(buf, vertex_offset as usize + i * 12));
448 }
449
450 let mut triangles = Vec::with_capacity(triangle_count as usize);
451 for i in 0..triangle_count as usize {
452 let o = triangle_offset as usize + i * MESH_TRIANGLE_SIZE;
453 triangles.push(MeshTriangle {
454 index1: read_i32(buf, o),
455 index2: read_i32(buf, o + 4),
456 index3: read_i32(buf, o + 8),
457 });
458 }
459
460 let mat_start = material_offset as usize;
461 let material_indices = buf[mat_start..mat_start + material_count as usize].to_vec();
462 let flags_start = flags_offset as usize;
463 let flags = if flags_offset > 0 {
464 buf[flags_start..flags_start + triangle_count as usize].to_vec()
465 } else {
466 Vec::new()
467 };
468
469 Some(MeshData {
470 version,
471 byte_count,
472 hash,
473 bounds,
474 surface_area,
475 tree_height,
476 degenerate_count,
477 node_offset,
478 node_count,
479 vertex_offset,
480 vertex_count,
481 triangle_offset,
482 triangle_count,
483 material_offset,
484 material_count,
485 flags_offset,
486 nodes,
487 vertices,
488 triangles,
489 material_indices,
490 flags,
491 })
492}
493
494pub fn convert_bytes_to_compound(bytes: &[u8]) -> Option<CompoundData> {
496 if bytes.len() < COMPOUND_DATA_SIZE {
497 return None;
498 }
499
500 let version = read_u64(bytes, 0);
501 if version != COMPOUND_VERSION {
502 return None;
503 }
504
505 let byte_count = read_i32(bytes, 8);
506 if byte_count < COMPOUND_DATA_SIZE as i32 {
507 return None;
508 }
509 if bytes.len() != byte_count as usize {
510 return None;
511 }
512
513 let node_offset = read_i32(bytes, 12);
514 if node_offset <= 0 {
515 return None;
516 }
517
518 let tree_version = read_u64(bytes, 16);
520 let root = read_i32(bytes, 16 + 16);
521 let node_count = read_i32(bytes, 16 + 20);
522 let node_capacity = read_i32(bytes, 16 + 24);
523 let proxy_count = read_i32(bytes, 16 + 28);
524 let free_list = read_i32(bytes, 16 + 32);
525 let rebuild_capacity = read_i32(bytes, 16 + 72);
526
527 let material_offset = read_i32(bytes, 16 + DYNAMIC_TREE_SIZE);
528 let material_count = read_i32(bytes, 16 + DYNAMIC_TREE_SIZE + 4);
529 let capsule_offset = read_i32(bytes, 16 + DYNAMIC_TREE_SIZE + 8);
530 let capsule_count = read_i32(bytes, 16 + DYNAMIC_TREE_SIZE + 12);
531 let hull_offset = read_i32(bytes, 16 + DYNAMIC_TREE_SIZE + 16);
532 let hull_count = read_i32(bytes, 16 + DYNAMIC_TREE_SIZE + 20);
533 let shared_hull_count = read_i32(bytes, 16 + DYNAMIC_TREE_SIZE + 24);
534 let mesh_offset = read_i32(bytes, 16 + DYNAMIC_TREE_SIZE + 28);
535 let mesh_count = read_i32(bytes, 16 + DYNAMIC_TREE_SIZE + 32);
536 let shared_mesh_count = read_i32(bytes, 16 + DYNAMIC_TREE_SIZE + 36);
537 let sphere_offset = read_i32(bytes, 16 + DYNAMIC_TREE_SIZE + 40);
538 let sphere_count = read_i32(bytes, 16 + DYNAMIC_TREE_SIZE + 44);
539
540 let mut nodes = Vec::with_capacity(node_capacity as usize);
541 for i in 0..node_capacity as usize {
542 let o = node_offset as usize + i * TREE_NODE_SIZE;
543 nodes.push(read_tree_node(bytes, o));
544 }
545
546 let mut tree = DynamicTree::new(0);
547 tree.version = if tree_version != 0 {
548 tree_version
549 } else {
550 DYNAMIC_TREE_VERSION
551 };
552 tree.nodes = nodes;
553 tree.root = root;
554 tree.node_count = node_count;
555 tree.free_list = free_list;
556 tree.proxy_count = proxy_count;
557 tree.rebuild_capacity = rebuild_capacity;
558
559 let mut materials = Vec::with_capacity(material_count as usize);
560 for i in 0..material_count as usize {
561 let o = material_offset as usize + i * SURFACE_MATERIAL_SIZE;
562 materials.push(SurfaceMaterial::from_bytes(
563 &bytes[o..o + SURFACE_MATERIAL_SIZE],
564 ));
565 }
566
567 let mut capsules = Vec::with_capacity(capsule_count as usize);
568 for i in 0..capsule_count as usize {
569 let o = capsule_offset as usize + i * COMPOUND_CONVEX_SIZE;
570 capsules.push(CompoundCapsule {
571 capsule: crate::geometry::Capsule {
572 center1: read_vec3(bytes, o),
573 center2: read_vec3(bytes, o + 12),
574 radius: read_f32(bytes, o + 24),
575 },
576 material_index: read_i32(bytes, o + 28),
577 });
578 }
579
580 let mut hull_instances = Vec::with_capacity(hull_count as usize);
581 for i in 0..hull_count as usize {
582 let o = hull_offset as usize + i * HULL_INSTANCE_SIZE;
583 hull_instances.push(HullInstance {
584 transform: read_transform(bytes, o),
585 shared_index: 0, material_index: read_u32(bytes, o + 32),
587 hull_offset: read_u32(bytes, o + 28),
588 });
589 }
590
591 let mut shared_hulls = Vec::new();
593 let mut offset_to_shared: Vec<(u32, usize)> = Vec::new();
594 for inst in &mut hull_instances {
595 let off = inst.hull_offset;
596 if let Some((_, idx)) = offset_to_shared.iter().find(|(o, _)| *o == off) {
597 inst.shared_index = *idx as u32;
598 } else {
599 let idx = shared_hulls.len();
600 let hull_bytes = &bytes[off as usize..];
601 let hull_byte_count = read_i32(hull_bytes, 8) as usize;
603 let hull = read_hull_data(&hull_bytes[..hull_byte_count])?;
604 shared_hulls.push(hull);
605 offset_to_shared.push((off, idx));
606 inst.shared_index = idx as u32;
607 }
608 }
609 debug_assert_eq!(shared_hulls.len() as i32, shared_hull_count);
610
611 let mut mesh_instances = Vec::with_capacity(mesh_count as usize);
612 for i in 0..mesh_count as usize {
613 let o = mesh_offset as usize + i * MESH_INSTANCE_SIZE;
614 let mut material_indices = [0u32; MAX_COMPOUND_MESH_MATERIALS];
615 for j in 0..MAX_COMPOUND_MESH_MATERIALS {
616 material_indices[j] = read_u32(bytes, o + 44 + j * 4);
617 }
618 mesh_instances.push(MeshInstance {
619 transform: read_transform(bytes, o),
620 scale: read_vec3(bytes, o + 28),
621 shared_index: 0,
622 material_indices,
623 mesh_offset: read_u32(bytes, o + 40),
624 });
625 }
626
627 let mut shared_meshes = Vec::new();
628 let mut mesh_offset_to_shared: Vec<(u32, usize)> = Vec::new();
629 for inst in &mut mesh_instances {
630 let off = inst.mesh_offset;
631 if let Some((_, idx)) = mesh_offset_to_shared.iter().find(|(o, _)| *o == off) {
632 inst.shared_index = *idx as u32;
633 } else {
634 let idx = shared_meshes.len();
635 let mesh_bytes = &bytes[off as usize..];
636 let mesh_byte_count = read_i32(mesh_bytes, 8) as usize;
637 let mesh = read_mesh_data(&mesh_bytes[..mesh_byte_count])?;
638 shared_meshes.push(mesh);
639 mesh_offset_to_shared.push((off, idx));
640 inst.shared_index = idx as u32;
641 }
642 }
643 debug_assert_eq!(shared_meshes.len() as i32, shared_mesh_count);
644
645 let mut spheres = Vec::with_capacity(sphere_count as usize);
646 for i in 0..sphere_count as usize {
647 let o = sphere_offset as usize + i * COMPOUND_CONVEX_SIZE;
648 spheres.push(CompoundSphere {
649 sphere: crate::geometry::Sphere {
650 center: read_vec3(bytes, o),
651 radius: read_f32(bytes, o + 12),
652 },
653 material_index: read_i32(bytes, o + 16),
654 });
655 }
656
657 Some(CompoundData {
658 version,
659 byte_count,
660 node_offset,
661 tree,
662 material_offset,
663 material_count,
664 capsule_offset,
665 capsule_count,
666 hull_offset,
667 hull_count,
668 shared_hull_count,
669 mesh_offset,
670 mesh_count,
671 shared_mesh_count,
672 sphere_offset,
673 sphere_count,
674 materials,
675 capsules,
676 hull_instances,
677 shared_hulls,
678 mesh_instances,
679 shared_meshes,
680 spheres,
681 })
682}
683
684#[allow(dead_code)]
686fn _keep() {
687 let _ = (
688 TRANSFORM_IDENTITY,
689 QUAT_IDENTITY,
690 VEC3_ZERO,
691 VEC3_ONE,
692 MAT3_ZERO,
693 );
694}