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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
//a Imports
use crate::hierarchy;
use crate::Renderable;
use crate::{
    Component, Instantiable, Material, Mesh, ShortIndex, Skeleton, Texture, Transformation,
    Vertices,
};
use hierarchy::Hierarchy;

//a Object
//tp Object
/// A hierarchy of ObjectNode's
///
/// This can be flattened in to an Instantiable
pub struct Object<'object, M, R>
where
    R: Renderable,
    M: Material + 'object,
{
    /// Skeleton
    pub skeleton: Option<Skeleton>,
    /// All the vertices used
    pub vertices: Vec<&'object Vertices<'object, R>>,
    /// All the vertices used
    pub textures: Vec<&'object Texture<'object, R>>,
    /// All the materials used
    pub materials: Vec<&'object M>,
    /// The meshes etc that make up the object
    pub components: Hierarchy<Component>,
    // The roots of the bones and hierarchical recipes for traversal
    // pub roots   : Vec<(usize, Recipe)>,
    // Meshes - indices in to nodes.nodes array of the meshes in the order of instance
    // pub meshes : Vec<usize>
}

//ip Display for Object
impl<'object, M, R> std::fmt::Display for Object<'object, M, R>
where
    R: Renderable,
    M: Material + 'object,
{
    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
        writeln!(fmt, "Object: {{")?;
        for v in &self.vertices {
            writeln!(fmt, "  {v}")?;
        }
        writeln!(fmt, "}}")
    }
}

//ip Default for Object
impl<'object, M, R> Default for Object<'object, M, R>
where
    M: Material + 'object,
    R: Renderable,
{
    fn default() -> Self {
        Self::new()
    }
}

//ip Object
impl<'object, M, R> Object<'object, M, R>
where
    M: Material + 'object,
    R: Renderable,
{
    //fp new
    /// Create a new [Object] with no components
    pub fn new() -> Self {
        let skeleton = None;
        let vertices = Vec::new();
        let textures = Vec::new();
        let materials = Vec::new();
        let components = Hierarchy::new();
        Self {
            skeleton,
            vertices,
            textures,
            materials,
            components,
        }
    }

    //ap vertices
    /// Borrow one of the vertices
    pub fn vertices(&self, n: ShortIndex) -> &Vertices<'object, R> {
        self.vertices[n.as_usize()]
    }

    //ap texture
    /// Borrow one of the textures
    pub fn texture(&self, n: ShortIndex) -> &Texture<'object, R> {
        self.textures[n.as_usize()]
    }

    //mp material
    /// Borrow a materiaal from the object
    pub fn material(&self, n: ShortIndex) -> &M {
        self.materials[n.as_usize()]
    }

    //mp add_vertices
    /// Add vertices to the object
    pub fn add_vertices(&mut self, vertices: &'object Vertices<'object, R>) -> ShortIndex {
        let n = self.vertices.len();
        self.vertices.push(vertices);
        n.into()
    }

    //mp add_texture
    /// Add texture to the object
    pub fn add_texture(&mut self, texture: &'object Texture<'object, R>) -> ShortIndex {
        let n = self.textures.len();
        self.textures.push(texture);
        n.into()
    }

    //fp add_material
    /// Add a material to the object
    pub fn add_material(&mut self, material: &'object M) -> ShortIndex {
        let n = self.materials.len();
        self.materials.push(material);
        n.into()
    }

    //fp add_component
    /// Add a component to the hierarchy
    pub fn add_component(
        &mut self,
        parent: Option<usize>,
        transformation: Option<Transformation>,
        mesh: Mesh,
    ) -> usize {
        let node = Component::new(transformation, mesh);
        let child = self.components.add_node(node);
        if let Some(parent) = parent {
            self.components.relate(parent, child);
        }
        child
    }

    //fp relate
    /// Add a relation between two components
    pub fn relate(&mut self, parent: usize, child: usize) {
        self.components.relate(parent, child);
    }

    //mp analyze
    /// Analyze the object once it has been completely created
    ///
    /// This must be performed before clients are created, render
    /// recipes are generated, or the object is deconnstructed into an
    /// [Instantiable].
    pub fn analyze(&mut self) {
        self.components.find_roots();
    }

    //dp into_instantiable
    /// Deconstruct the object into an [Instantiable] for the
    /// renderable. This should be invoked after analysis and clients
    /// have been created.
    ///
    /// This permits (for exampl in OpenGL) the CPU-side buffers in
    /// the object to be dropped, but the GPU-side objects (created by
    /// create_client) can be maintained. The [Instantiable] contains
    /// only instances of the types for the [Renderable].
    pub fn into_instantiable(self, renderer: &mut R) -> Result<Instantiable<R>, (Self, String)> {
        for v in &self.vertices {
            v.create_client(renderer);
        }
        for t in &self.textures {
            t.create_client(renderer);
        }
        let materials: Vec<R::Material> = self
            .materials
            .iter()
            .map(|m| renderer.create_material_client(&self, m))
            .collect();
        Ok(Instantiable::<R>::new::<M>(
            self.skeleton,
            self.vertices,
            self.textures,
            materials,
            self.components,
        ))
    }

    //zz All done
}