1use std::collections::HashMap;
4
5pub type Matrix = [f32; 16];
6pub const IDENTITY: Matrix = [
7 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0,
8];
9const MAX_NODES: usize = 100_000;
10const MAX_NAME: usize = 4096;
11const MAX_BYTES: usize = 16 * 1024 * 1024;
12#[derive(Clone, Copy, Debug, PartialEq)]
13pub struct Transform {
14 pub translation: [f32; 3],
15 pub rotation: [f32; 4],
16 pub scale: [f32; 3],
17}
18impl Default for Transform {
19 fn default() -> Self {
20 Self {
21 translation: [0.0; 3],
22 rotation: [0.0, 0.0, 0.0, 1.0],
23 scale: [1.0; 3],
24 }
25 }
26}
27impl Transform {
28 pub fn valid(self) -> bool {
29 self.translation
30 .into_iter()
31 .chain(self.rotation)
32 .chain(self.scale)
33 .all(f32::is_finite)
34 && self
35 .rotation
36 .into_iter()
37 .map(|n| f64::from(n).powi(2))
38 .sum::<f64>()
39 > 1e-20
40 }
41 pub fn matrix(self) -> Result<Matrix, SceneError> {
43 if !self.valid() {
44 return Err(SceneError::InvalidTransform);
45 }
46 let length = self
47 .rotation
48 .into_iter()
49 .map(|v| f64::from(v).powi(2))
50 .sum::<f64>()
51 .sqrt();
52 let [x, y, z, w] = self.rotation.map(|v| (f64::from(v) / length) as f32);
53 let [sx, sy, sz] = self.scale;
54 let [tx, ty, tz] = self.translation;
55 Ok([
56 (1.0 - 2.0 * (y * y + z * z)) * sx,
57 2.0 * (x * y + z * w) * sx,
58 2.0 * (x * z - y * w) * sx,
59 0.0,
60 2.0 * (x * y - z * w) * sy,
61 (1.0 - 2.0 * (x * x + z * z)) * sy,
62 2.0 * (y * z + x * w) * sy,
63 0.0,
64 2.0 * (x * z + y * w) * sz,
65 2.0 * (y * z - x * w) * sz,
66 (1.0 - 2.0 * (x * x + y * y)) * sz,
67 0.0,
68 tx,
69 ty,
70 tz,
71 1.0,
72 ])
73 }
74}
75pub fn multiply(a: Matrix, b: Matrix) -> Matrix {
78 std::array::from_fn(|index| {
79 let row = index % 4;
80 let col = index / 4;
81 (0..4)
82 .map(|k| f64::from(a[k * 4 + row]) * f64::from(b[col * 4 + k]))
83 .sum::<f64>() as f32
84 })
85}
86pub fn transform_point(m: Matrix, p: [f32; 3]) -> [f32; 3] {
87 std::array::from_fn(|row| m[row] * p[0] + m[4 + row] * p[1] + m[8 + row] * p[2] + m[12 + row])
88}
89#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
90pub struct NodeId {
91 index: u32,
92 generation: u32,
93}
94#[derive(Clone, Copy, Debug, PartialEq, Eq)]
95pub enum SceneError {
96 InvalidNode,
97 InvalidTransform,
98 Cycle,
99 Capacity,
100 NameTooLong,
101 InvalidFormat,
102 InvalidSkeleton,
103}
104#[derive(Clone, Debug)]
105pub struct Node {
106 name: String,
107 local: Transform,
108 parent: Option<NodeId>,
109 children: Vec<NodeId>,
110}
111impl Node {
112 pub fn name(&self) -> &str {
113 &self.name
114 }
115 pub fn local(&self) -> Transform {
116 self.local
117 }
118 pub fn parent(&self) -> Option<NodeId> {
119 self.parent
120 }
121 pub fn children(&self) -> &[NodeId] {
122 &self.children
123 }
124}
125struct Slot {
126 generation: u32,
127 node: Option<Node>,
128}
129#[derive(Default)]
130pub struct Scene {
131 slots: Vec<Slot>,
132 free: Vec<u32>,
133 len: usize,
134}
135#[derive(Clone, Debug)]
136pub struct Prefab {
137 nodes: Vec<PrefabNode>,
138}
139#[derive(Clone, Debug)]
140struct PrefabNode {
141 name: String,
142 local: Transform,
143 parent: Option<usize>,
144}
145impl Prefab {
146 pub fn len(&self) -> usize {
147 self.nodes.len()
148 }
149 pub fn is_empty(&self) -> bool {
150 self.nodes.is_empty()
151 }
152}
153impl Scene {
154 pub fn new() -> Self {
155 Self::default()
156 }
157 pub fn len(&self) -> usize {
158 self.len
159 }
160 pub fn is_empty(&self) -> bool {
161 self.len == 0
162 }
163 pub fn node(&self, id: NodeId) -> Result<&Node, SceneError> {
164 self.slots
165 .get(id.index as usize)
166 .filter(|s| s.generation == id.generation)
167 .and_then(|s| s.node.as_ref())
168 .ok_or(SceneError::InvalidNode)
169 }
170 fn node_mut(&mut self, id: NodeId) -> Result<&mut Node, SceneError> {
171 self.slots
172 .get_mut(id.index as usize)
173 .filter(|s| s.generation == id.generation)
174 .and_then(|s| s.node.as_mut())
175 .ok_or(SceneError::InvalidNode)
176 }
177 pub fn nodes(&self) -> impl Iterator<Item = (NodeId, &Node)> {
178 self.slots.iter().enumerate().filter_map(|(index, slot)| {
179 slot.node.as_ref().map(|node| {
180 (
181 NodeId {
182 index: index as u32,
183 generation: slot.generation,
184 },
185 node,
186 )
187 })
188 })
189 }
190 pub fn create(
191 &mut self,
192 name: impl Into<String>,
193 local: Transform,
194 parent: Option<NodeId>,
195 ) -> Result<NodeId, SceneError> {
196 let name = name.into();
197 if name.len() > MAX_NAME {
198 return Err(SceneError::NameTooLong);
199 }
200 if !local.valid() {
201 return Err(SceneError::InvalidTransform);
202 }
203 if self.len == MAX_NODES || (self.free.is_empty() && self.slots.len() == MAX_NODES) {
204 return Err(SceneError::Capacity);
205 }
206 if let Some(parent) = parent {
207 self.node(parent)?;
208 }
209 let index = if let Some(index) = self.free.pop() {
210 index
211 } else {
212 self.slots.push(Slot {
213 generation: 0,
214 node: None,
215 });
216 (self.slots.len() - 1) as u32
217 };
218 let slot = &mut self.slots[index as usize];
219 let id = NodeId {
220 index,
221 generation: slot.generation,
222 };
223 slot.node = Some(Node {
224 name,
225 local,
226 parent,
227 children: Vec::new(),
228 });
229 self.len += 1;
230 if let Some(parent) = parent {
231 self.node_mut(parent)?.children.push(id);
232 }
233 Ok(id)
234 }
235 pub fn set_local(&mut self, id: NodeId, local: Transform) -> Result<(), SceneError> {
236 if !local.valid() {
237 return Err(SceneError::InvalidTransform);
238 }
239 self.node_mut(id)?.local = local;
240 Ok(())
241 }
242 pub fn set_parent(&mut self, id: NodeId, parent: Option<NodeId>) -> Result<(), SceneError> {
245 let old = self.node(id)?.parent;
246 let mut ancestor = parent;
247 while let Some(candidate) = ancestor {
248 if candidate == id {
249 return Err(SceneError::Cycle);
250 }
251 ancestor = self.node(candidate)?.parent;
252 }
253 if old == parent {
254 return Ok(());
255 }
256 if let Some(old) = old {
257 self.node_mut(old)?.children.retain(|child| *child != id);
258 }
259 if let Some(parent) = parent {
260 self.node_mut(parent)?.children.push(id);
261 }
262 self.node_mut(id)?.parent = parent;
263 Ok(())
264 }
265 pub fn world_matrix(&self, id: NodeId) -> Result<Matrix, SceneError> {
266 let node = self.node(id)?;
267 let mut matrix = node.local.matrix()?;
268 let mut parent = node.parent;
269 while let Some(id) = parent {
270 let node = self.node(id)?;
271 matrix = multiply(node.local.matrix()?, matrix);
272 parent = node.parent;
273 }
274 if matrix.into_iter().all(f32::is_finite) {
275 Ok(matrix)
276 } else {
277 Err(SceneError::InvalidTransform)
278 }
279 }
280 pub fn remove_subtree(&mut self, root: NodeId) -> Result<usize, SceneError> {
281 let parent = self.node(root)?.parent;
282 let mut ids = vec![root];
283 let mut index = 0;
284 while index < ids.len() {
285 ids.extend_from_slice(self.node(ids[index])?.children());
286 index += 1;
287 }
288 if let Some(parent) = parent {
289 self.node_mut(parent)?
290 .children
291 .retain(|child| *child != root);
292 }
293 for id in ids.iter().rev() {
294 let slot = &mut self.slots[id.index as usize];
295 slot.node = None;
296 if let Some(next) = slot.generation.checked_add(1) {
297 slot.generation = next;
298 self.free.push(id.index);
299 }
300 }
301 self.len -= ids.len();
302 Ok(ids.len())
303 }
304 pub fn prefab(&self, root: NodeId) -> Result<Prefab, SceneError> {
306 self.node(root)?;
307 let mut pending = vec![(root, None)];
308 let mut nodes = Vec::new();
309 let mut cursor = 0;
310 while cursor < pending.len() {
311 let (id, parent) = pending[cursor];
312 let node = self.node(id)?;
313 nodes.push(PrefabNode {
314 name: node.name.clone(),
315 local: node.local,
316 parent,
317 });
318 pending.extend(node.children.iter().map(|child| (*child, Some(cursor))));
319 cursor += 1;
320 }
321 Ok(Prefab { nodes })
322 }
323 pub fn instantiate(
324 &mut self,
325 prefab: &Prefab,
326 parent: Option<NodeId>,
327 ) -> Result<NodeId, SceneError> {
328 if let Some(parent) = parent {
329 self.node(parent)?;
330 }
331 let available = MAX_NODES - self.slots.len() + self.free.len();
332 if prefab.nodes.is_empty() || prefab.nodes.len() > available {
333 return Err(SceneError::Capacity);
334 }
335 let mut ids = Vec::with_capacity(prefab.nodes.len());
336 for node in &prefab.nodes {
337 let node_parent = node.parent.map(|index| ids[index]).or(parent);
338 ids.push(self.create(node.name.clone(), node.local, node_parent)?);
339 }
340 Ok(ids[0])
341 }
342 pub fn clone_subtree(
343 &mut self,
344 root: NodeId,
345 parent: Option<NodeId>,
346 ) -> Result<NodeId, SceneError> {
347 self.instantiate(&self.prefab(root)?, parent)
348 }
349 pub fn encode(&self) -> Result<Vec<u8>, SceneError> {
353 let nodes: Vec<_> = self.nodes().collect();
354 let indices: HashMap<_, _> = nodes
355 .iter()
356 .enumerate()
357 .map(|(i, (id, _))| (*id, i as u32))
358 .collect();
359 let length = 10
360 + nodes
361 .iter()
362 .map(|(_, node)| 46 + node.name.len())
363 .sum::<usize>();
364 if length > MAX_BYTES {
365 return Err(SceneError::Capacity);
366 }
367 let mut bytes = Vec::with_capacity(length);
368 bytes.extend_from_slice(b"GSC1");
369 bytes.extend_from_slice(&1_u16.to_le_bytes());
370 bytes.extend_from_slice(&(nodes.len() as u32).to_le_bytes());
371 for (_, node) in nodes {
372 bytes.extend_from_slice(
373 &node
374 .parent
375 .map_or(u32::MAX, |parent| indices[&parent])
376 .to_le_bytes(),
377 );
378 bytes.extend_from_slice(&(node.name.len() as u16).to_le_bytes());
379 bytes.extend_from_slice(node.name.as_bytes());
380 for value in node
381 .local
382 .translation
383 .into_iter()
384 .chain(node.local.rotation)
385 .chain(node.local.scale)
386 {
387 bytes.extend_from_slice(&value.to_le_bytes());
388 }
389 }
390 Ok(bytes)
391 }
392 pub fn decode(bytes: &[u8]) -> Result<Self, SceneError> {
393 if bytes.len() > MAX_BYTES {
394 return Err(SceneError::InvalidFormat);
395 }
396 let mut reader = Reader { bytes, cursor: 0 };
397 if reader.take(4)? != b"GSC1" || reader.u16()? != 1 {
398 return Err(SceneError::InvalidFormat);
399 }
400 let count = reader.u32()? as usize;
401 if count > MAX_NODES || count > bytes.len().saturating_sub(10) / 46 {
402 return Err(SceneError::InvalidFormat);
403 }
404 let mut scene = Self::new();
405 let mut ids = Vec::with_capacity(count);
406 let mut parents = Vec::with_capacity(count);
407 for _ in 0..count {
408 let parent = reader.u32()?;
409 if parent != u32::MAX && parent as usize >= count {
410 return Err(SceneError::InvalidFormat);
411 }
412 let len = reader.u16()? as usize;
413 if len > MAX_NAME {
414 return Err(SceneError::InvalidFormat);
415 }
416 let name =
417 std::str::from_utf8(reader.take(len)?).map_err(|_| SceneError::InvalidFormat)?;
418 let mut values = [0.0; 10];
419 for value in &mut values {
420 *value = reader.f32()?;
421 }
422 let transform = Transform {
423 translation: [values[0], values[1], values[2]],
424 rotation: [values[3], values[4], values[5], values[6]],
425 scale: [values[7], values[8], values[9]],
426 };
427 ids.push(
428 scene
429 .create(name, transform, None)
430 .map_err(|_| SceneError::InvalidFormat)?,
431 );
432 parents.push(parent);
433 }
434 if reader.cursor != bytes.len() {
435 return Err(SceneError::InvalidFormat);
436 }
437 let mut marks = vec![0_u8; count];
440 let mut chain = Vec::new();
441 for start in 0..count {
442 if marks[start] != 0 {
443 continue;
444 }
445 let mut cursor = Some(start);
446 while let Some(index) = cursor {
447 if marks[index] != 0 {
448 break;
449 }
450 marks[index] = 1;
451 chain.push(index);
452 cursor = (parents[index] != u32::MAX).then_some(parents[index] as usize);
453 }
454 if cursor.is_some_and(|index| marks[index] == 1) {
455 return Err(SceneError::InvalidFormat);
456 }
457 for index in chain.drain(..) {
458 marks[index] = 2;
459 }
460 }
461 for (index, parent) in parents.into_iter().enumerate() {
462 if parent != u32::MAX {
463 let child_id = ids[index];
464 let parent_id = ids[parent as usize];
465 scene.node_mut(child_id)?.parent = Some(parent_id);
466 scene.node_mut(parent_id)?.children.push(child_id);
467 }
468 }
469 Ok(scene)
470 }
471}
472struct Reader<'a> {
473 bytes: &'a [u8],
474 cursor: usize,
475}
476impl<'a> Reader<'a> {
477 fn take(&mut self, count: usize) -> Result<&'a [u8], SceneError> {
478 let end = self
479 .cursor
480 .checked_add(count)
481 .ok_or(SceneError::InvalidFormat)?;
482 let bytes = self
483 .bytes
484 .get(self.cursor..end)
485 .ok_or(SceneError::InvalidFormat)?;
486 self.cursor = end;
487 Ok(bytes)
488 }
489 fn u16(&mut self) -> Result<u16, SceneError> {
490 Ok(u16::from_le_bytes(
491 self.take(2)?
492 .try_into()
493 .map_err(|_| SceneError::InvalidFormat)?,
494 ))
495 }
496 fn u32(&mut self) -> Result<u32, SceneError> {
497 Ok(u32::from_le_bytes(
498 self.take(4)?
499 .try_into()
500 .map_err(|_| SceneError::InvalidFormat)?,
501 ))
502 }
503 fn f32(&mut self) -> Result<f32, SceneError> {
504 Ok(f32::from_le_bytes(
505 self.take(4)?
506 .try_into()
507 .map_err(|_| SceneError::InvalidFormat)?,
508 ))
509 }
510}
511
512#[derive(Clone, Debug)]
513pub struct Joint {
514 pub parent: Option<usize>,
515 pub inverse_bind: Matrix,
516}
517#[derive(Clone, Debug)]
518pub struct Skeleton {
519 joints: Vec<Joint>,
520}
521impl Skeleton {
522 pub fn new(joints: Vec<Joint>) -> Result<Self, SceneError> {
524 if joints.is_empty()
525 || joints.len() > 4096
526 || joints.iter().enumerate().any(|(i, joint)| {
527 joint.parent.is_some_and(|parent| parent >= i)
528 || !joint.inverse_bind.into_iter().all(f32::is_finite)
529 })
530 {
531 return Err(SceneError::InvalidSkeleton);
532 }
533 Ok(Self { joints })
534 }
535 pub fn joint_count(&self) -> usize {
536 self.joints.len()
537 }
538 pub fn world_pose(&self, locals: &[Transform]) -> Result<Vec<Matrix>, SceneError> {
539 if locals.len() != self.joints.len() {
540 return Err(SceneError::InvalidSkeleton);
541 }
542 let mut world = Vec::with_capacity(locals.len());
543 for (joint, local) in self.joints.iter().zip(locals) {
544 let matrix = local.matrix()?;
545 let matrix = joint
546 .parent
547 .map_or(matrix, |parent| multiply(world[parent], matrix));
548 if !matrix.into_iter().all(f32::is_finite) {
549 return Err(SceneError::InvalidTransform);
550 }
551 world.push(matrix);
552 }
553 Ok(world)
554 }
555 pub fn skin_palette(&self, locals: &[Transform]) -> Result<Vec<Matrix>, SceneError> {
557 let world = self.world_pose(locals)?;
558 let palette: Vec<_> = world
559 .into_iter()
560 .zip(&self.joints)
561 .map(|(pose, joint)| multiply(pose, joint.inverse_bind))
562 .collect();
563 if palette.iter().flatten().all(|v| v.is_finite()) {
564 Ok(palette)
565 } else {
566 Err(SceneError::InvalidTransform)
567 }
568 }
569}
570
571#[cfg(test)]
572mod tests {
573 use super::*;
574 fn translated(x: f32, y: f32, z: f32) -> Transform {
575 Transform {
576 translation: [x, y, z],
577 ..Transform::default()
578 }
579 }
580 #[test]
581 fn hierarchy_composes_parent_rotation_and_child_translation() {
582 let mut scene = Scene::new();
583 let root = scene
584 .create(
585 "root",
586 Transform {
587 rotation: [
588 0.0,
589 0.0,
590 std::f32::consts::FRAC_1_SQRT_2,
591 std::f32::consts::FRAC_1_SQRT_2,
592 ],
593 ..translated(2.0, 0.0, 0.0)
594 },
595 None,
596 )
597 .unwrap();
598 let child = scene
599 .create("child", translated(3.0, 0.0, 0.0), Some(root))
600 .unwrap();
601 let p = transform_point(scene.world_matrix(child).unwrap(), [0.0; 3]);
602 assert!((p[0] - 2.0).abs() < 1e-5);
603 assert!((p[1] - 3.0).abs() < 1e-5);
604 assert_eq!(scene.set_parent(root, Some(child)), Err(SceneError::Cycle));
605 assert_eq!(scene.node(root).unwrap().parent(), None);
606 }
607 #[test]
608 fn prefab_copy_is_independent_and_stale_ids_stay_invalid() {
609 let mut scene = Scene::new();
610 let root = scene.create("root", Transform::default(), None).unwrap();
611 let child = scene
612 .create("child", translated(2.0, 0.0, 0.0), Some(root))
613 .unwrap();
614 let copy = scene.clone_subtree(root, None).unwrap();
615 assert_eq!(scene.len(), 4);
616 let copied_child = scene.node(copy).unwrap().children()[0];
617 scene.set_local(child, translated(5.0, 0.0, 0.0)).unwrap();
618 assert_eq!(
619 scene.node(copied_child).unwrap().local().translation[0],
620 2.0
621 );
622 assert_eq!(scene.remove_subtree(root).unwrap(), 2);
623 scene.create("reuse", Transform::default(), None).unwrap();
624 assert!(matches!(scene.node(root), Err(SceneError::InvalidNode)));
625 assert!(matches!(scene.node(child), Err(SceneError::InvalidNode)));
626 }
627 #[test]
628 fn scene_binary_roundtrip_and_strict_malformed_rejection() {
629 let mut scene = Scene::new();
630 let root = scene.create("父", translated(1.0, 2.0, 3.0), None).unwrap();
631 scene
632 .create("child", translated(4.0, 0.0, 0.0), Some(root))
633 .unwrap();
634 let bytes = scene.encode().unwrap();
635 let decoded = Scene::decode(&bytes).unwrap();
636 assert_eq!(decoded.encode().unwrap(), bytes);
637 for cut in 0..bytes.len() {
638 assert!(Scene::decode(&bytes[..cut]).is_err());
639 }
640 let mut trailing = bytes.clone();
641 trailing.push(0);
642 assert!(Scene::decode(&trailing).is_err());
643 let mut cycle = bytes.clone();
644 cycle[10..14].copy_from_slice(&1_u32.to_le_bytes());
645 assert!(Scene::decode(&cycle).is_err());
646 let mut oversized = bytes.clone();
647 oversized[6..10].copy_from_slice(&u32::MAX.to_le_bytes());
648 assert!(Scene::decode(&oversized).is_err());
649 }
650 #[test]
651 fn skeleton_bind_pose_palette_is_identity_and_animation_moves_child() {
652 let inverse = translated(-2.0, 0.0, 0.0).matrix().unwrap();
653 let skeleton = Skeleton::new(vec![
654 Joint {
655 parent: None,
656 inverse_bind: IDENTITY,
657 },
658 Joint {
659 parent: Some(0),
660 inverse_bind: inverse,
661 },
662 ])
663 .unwrap();
664 let palette = skeleton
665 .skin_palette(&[Transform::default(), translated(2.0, 0.0, 0.0)])
666 .unwrap();
667 assert_eq!(palette, vec![IDENTITY, IDENTITY]);
668 let pose = skeleton
669 .world_pose(&[translated(1.0, 0.0, 0.0), translated(3.0, 0.0, 0.0)])
670 .unwrap();
671 assert_eq!(transform_point(pose[1], [0.0; 3]), [4.0, 0.0, 0.0]);
672 assert!(
673 Skeleton::new(vec![Joint {
674 parent: Some(0),
675 inverse_bind: IDENTITY
676 }])
677 .is_err()
678 );
679 assert!(skeleton.skin_palette(&[]).is_err());
680 }
681}