1use crate::{metadata::MetaData, sys::aiNode, *};
2use derivative::Derivative;
3use std::{
4 cell::RefCell,
5 rc::{Rc, Weak},
6};
7
8#[derive(Default, Derivative)]
9#[derivative(Debug)]
10pub struct Node {
11 pub name: String,
12 pub children: RefCell<Vec<Rc<Node>>>,
13 pub meshes: Vec<u32>,
14 pub metadata: Option<MetaData>,
15 pub transformation: Matrix4x4,
16 #[derivative(Debug = "ignore")]
17 pub parent: Weak<Node>,
18}
19
20impl Node {
21 pub(crate) fn new(node: &aiNode) -> Rc<Node> {
22 Self::allocate(node, None)
23 }
24
25 fn allocate(node: &aiNode, parent: Option<&Rc<Node>>) -> Rc<Node> {
26 let res_node = Rc::new(Self::create_simple_node(node, parent));
28
29 *res_node.children.borrow_mut() =
30 utils::get_base_type_vec_from_raw(node.mChildren, node.mNumChildren)
31 .into_iter()
32 .map(|child| Self::allocate(child, Some(&res_node)))
33 .collect::<Vec<_>>();
34
35 res_node
36 }
37
38 fn create_simple_node(node: &aiNode, parent: Option<&Rc<Node>>) -> Node {
39 Node {
40 name: node.mName.into(),
41 children: RefCell::new(Vec::new()),
42 meshes: utils::get_raw_vec(node.mMeshes, node.mNumMeshes),
43 metadata: utils::get_raw(node.mMetaData),
44 transformation: (&node.mTransformation).into(),
45 parent: parent.map(Rc::downgrade).unwrap_or_default(),
46 }
47 }
48}
49
50#[cfg(test)]
51mod test {
52 use crate::utils;
53
54 #[test]
55 fn checking_nodes() {
56 use crate::scene::{PostProcess, Scene};
57
58 let current_directory_buf = utils::get_model("models/BLEND/box.blend");
59
60 let scene = Scene::from_file(
61 current_directory_buf.as_str(),
62 vec![
63 PostProcess::CalculateTangentSpace,
64 PostProcess::Triangulate,
65 PostProcess::JoinIdenticalVertices,
66 PostProcess::SortByPrimitiveType,
67 ],
68 )
69 .unwrap();
70
71 let root = scene.root.as_ref().unwrap();
72 let children = root.children.borrow();
73
74 assert_eq!("<BlenderRoot>".to_string(), root.name);
75 assert_eq!(3, children.len());
76
77 let first_son = &children[0];
78 assert_eq!("Cube".to_string(), first_son.name);
79
80 let second_son = &children[1];
81 assert_eq!("Lamp".to_string(), second_son.name);
82
83 assert_eq!(0, root.meshes.len());
84
85 assert!(root.metadata.is_none());
86
87 assert_eq!(1.0, root.transformation.a1);
88 assert_eq!(1.0, root.transformation.b2);
89 assert_eq!(1.0, root.transformation.c3);
90 assert_eq!(1.0, root.transformation.d4);
91 }
92
93 #[test]
94 fn childs_parent_name_matches() {
95 use crate::scene::{PostProcess, Scene};
96
97 let current_directory_buf = utils::get_model("models/BLEND/box.blend");
98
99 let scene = Scene::from_file(
100 current_directory_buf.as_str(),
101 vec![
102 PostProcess::CalculateTangentSpace,
103 PostProcess::Triangulate,
104 PostProcess::JoinIdenticalVertices,
105 PostProcess::SortByPrimitiveType,
106 ],
107 )
108 .unwrap();
109
110 let root = scene.root.as_ref().unwrap();
111 let children = root.children.borrow();
112
113 let first_son = &children[0];
114 let dad = first_son.parent.upgrade().unwrap();
115
116 assert_eq!(root.name, dad.name);
117 }
118
119 #[test]
120 fn debug_root() {
121 use crate::scene::{PostProcess, Scene};
122
123 let current_directory_buf = utils::get_model("models/BLEND/box.blend");
124
125 let scene = Scene::from_file(
126 current_directory_buf.as_str(),
127 vec![
128 PostProcess::CalculateTangentSpace,
129 PostProcess::Triangulate,
130 PostProcess::JoinIdenticalVertices,
131 PostProcess::SortByPrimitiveType,
132 ],
133 )
134 .unwrap();
135
136 dbg!(&scene.root);
137 }
138}