1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
use cgmath;
use froggy;
use mint;

use hub::SubNode;
use material::Material;

use std::marker::PhantomData;

/// Pointer to a Node
pub(crate) type NodePointer = froggy::Pointer<NodeInternal>;
pub(crate) type TransformInternal = cgmath::Decomposed<cgmath::Vector3<f32>, cgmath::Quaternion<f32>>;

// Fat node of the scene graph.
//
// `NodeInternal` is used by `three-rs` to represent an object in our scene graph,
// shaped as a node tree. Client code uses [`object::Base`](struct.Base.html) instead.
#[derive(Debug)]
pub(crate) struct NodeInternal {
    /// `true` if this node (and its children) are visible to cameras.
    pub(crate) visible: bool,

    /// A user-defined name for the node.
    ///
    /// Not used internally to implement functionality. This is used by users to identify nodes
    /// programatically, and to act as a utility when debugging.
    pub(crate) name: Option<String>,

    /// The transform relative to the node's parent.
    pub(crate) transform: TransformInternal,

    /// The transform relative to the scene root.
    pub(crate) world_transform: TransformInternal,

    /// Pointer to the next sibling.
    pub(crate) next_sibling: Option<NodePointer>,

    /// Context specific-data, for example, `UiText`, `Visual` or `Light`.
    pub(crate) sub_node: SubNode,
}

impl NodeInternal {
    pub(crate) fn to_node(&self) -> Node<Local> {
        Node {
            transform: self.transform.into(),
            visible: self.visible,
            name: self.name.clone(),
            material: match self.sub_node {
                SubNode::Visual(ref mat, _, _) => Some(mat.clone()),
                _ => None,
            },
            _space: PhantomData,
        }
    }
}

impl From<SubNode> for NodeInternal {
    fn from(sub: SubNode) -> Self {
        NodeInternal {
            visible: true,
            name: None,
            transform: cgmath::Transform::one(),
            world_transform: cgmath::Transform::one(),
            next_sibling: None,
            sub_node: sub,
        }
    }
}

/// Position, rotation, and scale of the scene node.
#[derive(Clone, Debug, PartialEq)]
pub struct Transform {
    /// Position.
    pub position: mint::Point3<f32>,
    /// Orientation.
    pub orientation: mint::Quaternion<f32>,
    /// Scale.
    pub scale: f32,
}

impl Transform {
    /// Creates a new `Transform` with default position, orientation, and scale.
    ///
    /// * The default position is `(0, 0, 0)`, meaning the global origin when in world space, or
    ///   meaning no translation relative to a parent in local space.
    /// * The default orientation has no rotation, meaning the coordinate axes will match the
    ///   global axes when the transform is in world space, or will match the axis of the parent
    ///   when in local space.
    /// * The default scale is 1, meaning no change from the object's natural dimensions, or
    ///   no change relative to the parent's dimensions.
    pub fn new() -> Transform {
        Default::default()
    }
}

impl Default for Transform {
    fn default() -> Self {
        Transform {
            position: [0.0, 0.0, 0.0].into(),
            orientation: [0.0, 0.0, 0.0, 1.0].into(),
            scale: 1.0,
        }
    }
}

impl From<TransformInternal> for Transform {
    fn from(tf: TransformInternal) -> Self {
        let pos: mint::Vector3<f32> = tf.disp.into();
        Transform {
            position: pos.into(),
            orientation: tf.rot.into(),
            scale: tf.scale,
        }
    }
}

/// Local space, defined relative to the parent node.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Local {}

/// World space, defined relative to the scene root.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum World {}

/// General information about an object in a scene.
#[derive(Clone, Debug, PartialEq)]
pub struct Node<Space> {
    /// Is `Node` visible by cameras or not?
    pub visible: bool,

    /// The name of the node, if any.
    pub name: Option<String>,

    /// Transformation in `Space`.
    // NOTE: this really begs for `euclid`-style parametrized math types.
    pub transform: Transform,

    /// Material in case this `Node` has it.
    pub material: Option<Material>,

    ///
    pub(crate) _space: PhantomData<Space>,
}