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
//a Imports
use crate::hierarchy;
use hierarchy::Hierarchy;

use crate::{Component, Instance, Material, RenderRecipe, Renderable, Skeleton, Texture, Vertices};

//a Instantiable
//tp Instantiable
/// An [Instantiable] is a type that is related to a set of Mesh data,
/// which can be instanced for different drawable::Instance's
///
/// It requires a related set of Mesh data that it does not refer to:
/// in object construction this Mesh data is likely to be the
/// structures containing vertex information and so on resident on a
/// CPU; in rendering the Mesh data is likely to be graphical objects
/// (such as OpenGL VAOs) that may reside (at least in part) on the
/// GPU.
///
/// The Instantiable data must be kept available to its related Instance.
///
/// The content of the Instantiable includes an array of Skeletons and
/// mesh transformation matrices, with appropriate index values. These
/// index values are into the related set of Mesh data.
#[derive(Debug)]
pub struct Instantiable<R>
where
    R: Renderable,
{
    /// Skeleton
    pub skeleton: Option<Skeleton>,
    /// All the vertices used
    pub vertices: Vec<R::Vertices>,
    /// All the textures used
    pub textures: Vec<R::Texture>,
    /// All the materials used
    pub materials: Vec<R::Material>,
    /// Render recipe
    pub render_recipe: RenderRecipe,
    /// Number of bone matrices required for all the bone sets in this structure
    pub num_bone_matrices: usize,
}

//ip Instantiable
impl<R> Instantiable<R>
where
    R: Renderable,
{
    //fp new
    /// Create a new instantiable drawable - something to which meshes
    /// and bone sets will be added, and for which a set of mesh
    /// matrices and rest bone positions will be derived.
    ///
    /// Such a type can that be 'instance'd with a specific
    /// transformation and bone poses, and such instances can then be
    /// drawn using shaders.
    pub fn new<M: Material>(
        skeleton: Option<Skeleton>,
        vertices: Vec<&Vertices<R>>,
        textures: Vec<&Texture<R>>,
        materials: Vec<R::Material>,
        mut components: Hierarchy<Component>,
    ) -> Self {
        components.find_roots();
        let render_recipe = RenderRecipe::from_component_hierarchy(&components);
        let num_bone_matrices = 0;
        let vertices = vertices
            .into_iter()
            .map(|v| v.borrow_client().clone())
            .collect();
        let textures = textures
            .into_iter()
            .map(|t| t.borrow_client().clone())
            .collect();
        Self {
            skeleton,
            vertices,
            textures,
            materials,
            render_recipe,
            num_bone_matrices,
        }
    }

    //mp instantiate
    /// Create an `Instance` from this instantiable - must be used with accompanying mesh data in the appropriate form for the client
    /// Must still add bone_poses one per bone set
    pub fn instantiate(&self) -> Instance<R> {
        Instance::new(self, self.num_bone_matrices)
    }

    //zz All done
}

/*
    //mp borrow_mesh_data
    /// Borrow the mesh data
    pub fn borrow_mesh_data (&self, index:usize) -> &MeshIndexData {
        &self.mesh_data[index]
    }

    pub fn add_meshes_of_node_iter(&self, meshes:&mut Vec<usize>, drawable:&mut drawable::Instantiable, iter:NodeIter<ObjectNode>) {
        let mut parent = None;
        let mut transformation = None;
        let mut bone_matrices = (0,0);
        let mut mesh_stack = Vec::new();
        for op in iter {
            match op {
                NodeIterOp::Push((n,obj_node), _has_children) => {
                    mesh_stack.push((parent, transformation, bone_matrices));
                    if let Some(bone_set) = obj_node.bones {
                        bone_matrices = drawable.add_bone_set(bone_set);
                    }
                    if let Some(obj_transformation) = &obj_node.transformation {
                        if transformation.is_none() {
                            transformation = Some(obj_transformation.mat4());
                        } else {
                            transformation = Some(matrix::multiply4(&transformation.unwrap(), &obj_transformation.mat4()));
                        }
                    }
                    if obj_node.mesh.is_some() {
                        let index = drawable.add_mesh(&parent, &transformation, &bone_matrices);
                        assert_eq!(index, meshes.len());
                        meshes.push(n);
                        parent = Some(index);
                        transformation = None;
                    }
                },
                NodeIterOp::Pop(_,_) => {
                    let ptb = mesh_stack.pop().unwrap();
                    parent = ptb.0;
                    transformation = ptb.1;
                    bone_matrices = ptb.2;
                },
            }
        }
    }

    pub fn create_instantiable(&mut self) -> drawable::Instantiable {
        self.nodes.find_roots();
        let mut drawable = drawable::Instantiable::new();
        let mut meshes = Vec::new();
        for r in self.nodes.borrow_roots() {
            self.add_meshes_of_node_iter(&mut meshes, &mut drawable, self.nodes.iter_from_root(*r));
        }
        self.meshes = meshes;
        drawable
    }
    pub fn bind_shader<'b, S:ShaderClass>(&self, drawable:&'b drawable::Instantiable, shader:&S) -> shader::Instantiable<'b> {
        let mut s = shader::Instantiable::new(drawable);
        for i in 0..self.meshes.len() {
            let obj_node = self.nodes.borrow_node(self.meshes[i]);
            assert!(obj_node.mesh.is_some(), "Mesh at node must be Some() for it to have been added to the self.meshes array by add_meshes_of_node_iter");
            let mesh = obj_node.mesh.unwrap();
            mesh.add_shader_drawables(shader, &mut s);
        }
        s
    }
*/