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}