gltf_viewer_lib/render/
node.rs

1use std::rc::Rc;
2use std::path::Path;
3
4use gltf;
5
6use collision::{Aabb, Union};
7
8use crate::controls::CameraParams;
9use crate::render::math::*;
10use crate::render::mesh::Mesh;
11use crate::render::Root;
12use crate::render::camera::Camera;
13use crate::importdata::ImportData;
14
15pub struct Node {
16    pub index: usize, // glTF index
17    pub children: Vec<usize>,
18    pub mesh: Option<Rc<Mesh>>,
19    pub rotation: Quaternion,
20    pub scale: Vector3,
21    pub translation: Vector3,
22    // TODO: weights
23    // weights_id: usize,
24    pub camera: Option<Camera>,
25    pub name: Option<String>,
26
27    pub final_transform: Matrix4, // including parent transforms
28    pub bounds: Aabb3,
29}
30
31
32impl Node {
33    pub fn from_gltf(
34        g_node: &gltf::Node<'_>,
35        root: &mut Root,
36        imp: &ImportData,
37        base_path: &Path
38    ) -> Node {
39        let (trans, rot, scale) = g_node.transform().decomposed();
40        let r = rot;
41        let rotation = Quaternion::new(r[3], r[0], r[1], r[2]); // NOTE: different element order!
42
43        let mut mesh = None;
44        if let Some(g_mesh) = g_node.mesh() {
45            if let Some(existing_mesh) = root.meshes.iter().find(|mesh| (***mesh).index == g_mesh.index()) {
46                mesh = Some(Rc::clone(existing_mesh));
47            }
48
49            if mesh.is_none() { // not using else due to borrow-checking madness
50                mesh = Some(Rc::new(Mesh::from_gltf(&g_mesh, root, imp, base_path)));
51                root.meshes.push(mesh.clone().unwrap());
52            }
53        }
54        let children: Vec<_> = g_node.children()
55                .map(|g_node| g_node.index())
56                .collect();
57
58        Node {
59            index: g_node.index(),
60            children,
61            mesh,
62            rotation,
63            scale: scale.into(),
64            translation: trans.into(),
65            camera: g_node.camera().as_ref().map(Camera::from_gltf),
66            name: g_node.name().map(|s| s.into()),
67
68            final_transform: Matrix4::identity(),
69
70            bounds: Aabb3::zero(),
71        }
72    }
73
74    pub fn update_transform(&mut self, root: &mut Root, parent_transform: &Matrix4) {
75        self.final_transform = *parent_transform;
76
77        // TODO: cache local tranform when adding animations?
78        self.final_transform = self.final_transform *
79            Matrix4::from_translation(self.translation) *
80            Matrix4::from_nonuniform_scale(self.scale.x, self.scale.y, self.scale.z) *
81            Matrix4::from(self.rotation);
82
83        for node_id in &self.children {
84            let node = root.unsafe_get_node_mut(*node_id);
85            node.update_transform(root, &self.final_transform);
86        }
87    }
88
89    /// Should be called after update_transforms
90    pub fn update_bounds(&mut self, root: &mut Root) {
91        self.bounds = Aabb3::zero();
92        if let Some(ref mesh) = self.mesh {
93            self.bounds = mesh.bounds
94                .transform(&self.final_transform);
95        }
96
97        for node_id in &self.children {
98            let node = root.unsafe_get_node_mut(*node_id);
99            node.update_bounds(root);
100            self.bounds = self.bounds.union(&node.bounds);
101        }
102    }
103
104    pub fn draw(&mut self, root: &mut Root, cam_params: &CameraParams) {
105        if let Some(ref mesh) = self.mesh {
106            let mvp_matrix = cam_params.projection_matrix * cam_params.view_matrix * self.final_transform;
107
108            (*mesh).draw(&self.final_transform, &mvp_matrix, &cam_params.position);
109        }
110        for node_id in &self.children {
111            let node = root.unsafe_get_node_mut(*node_id);
112            node.draw(root, cam_params);
113        }
114    }
115}