mod3d_base/
render_recipe.rs

1//a Imports
2use crate::hierarchy;
3use hierarchy::{Hierarchy, NodeEnumOp};
4
5use geo_nd::matrix;
6
7use crate::Mat4;
8use crate::{Component, Primitive};
9
10//a RenderRecipe
11//tp RenderRecipe
12/// A [RenderRecipe] for a hierarchy of components
13///
14/// Created from a hierarchy of components, this is an array of
15/// transformation matrices, an array of [Primitive]s, and an array of
16/// pairs (matrix index, primitive index) of what needs to be drawn
17#[derive(Debug)]
18pub struct RenderRecipe {
19    /// Matrices to use (the first is the identity matrix)
20    pub matrices: Vec<Mat4>,
21    /// The primitives within the component
22    pub primitives: Vec<Primitive>,
23    /// Draw requirements - matrix index for the associated primitive index
24    pub matrix_for_primitives: Vec<usize>,
25}
26
27//ip Default RenderRecipe
28impl Default for RenderRecipe {
29    fn default() -> Self {
30        Self::new()
31    }
32}
33
34//ip RenderRecipe
35impl RenderRecipe {
36    //fp new
37    /// Create a new [RenderRecipe]
38    pub fn new() -> Self {
39        let matrices = Vec::new();
40        let primitives = Vec::new();
41        let matrix_for_primitives = Vec::new();
42        Self {
43            matrices,
44            primitives,
45            matrix_for_primitives,
46        }
47    }
48
49    //fp from_component_hierarchy
50    /// Build a RenderRecipe from a [Hierarchy] of [Component]
51    ///
52    /// It requires the hierarchy to have had 'find_roots' executed prior
53    pub fn from_component_hierarchy(components: &Hierarchy<Component>) -> Self {
54        let mut recipe = Self::new();
55
56        // Create matrices for all meshes in the component,
57        // and enumerate them as (mesh index, matrix index) in `meshes`
58        recipe.matrices.push(matrix::identity4());
59        let mut meshes = Vec::new();
60        for root in components.borrow_roots() {
61            let mut trans_index = 0;
62            let mut mesh_stack = Vec::new();
63            for op in components.iter_from(*root) {
64                match op {
65                    NodeEnumOp::Push((n, comp), _has_children) => {
66                        mesh_stack.push(trans_index);
67                        if let Some(transformation) = comp.transformation {
68                            let transformation = matrix::multiply4(
69                                &recipe.matrices[trans_index],
70                                &transformation.mat4(),
71                            );
72                            trans_index = recipe.matrices.len();
73                            recipe.matrices.push(transformation);
74                        } // else keep same trans_index as its parent
75                        meshes.push((n, trans_index));
76                    }
77                    NodeEnumOp::Pop(_, _) => {
78                        trans_index = mesh_stack.pop().unwrap();
79                    }
80                }
81            }
82        }
83
84        // Copy out the mesh primitives paired with the matrix index
85        for (n, trans_index) in meshes {
86            for p in &components.borrow_node(n).mesh.primitives {
87                recipe.primitives.push(p.clone());
88                recipe.matrix_for_primitives.push(trans_index);
89            }
90        }
91
92        recipe
93    }
94}