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
// Oliver Berzs
// https://github.com/oberzs/duku

use std::slice::Iter;

use super::Mesh;
use crate::math::Matrix4;
use crate::pipeline::Material;
use crate::resources::Handle;

/// Collection of meshes and materials.
///
/// Makes it easier to render complex scenes
///
/// # Example
///
/// ```ignore
/// let model = duku.create_model_gltf("house.gltf")?;
///
/// target.draw_model(&model);
/// ```
pub struct Model {
    /// render-nodes of the model
    pub nodes: Vec<ModelNode>,
}

/// One node of the model.
///
/// Represents an object in a scene or a
/// child object.
pub struct ModelNode {
    /// meshes for this node
    pub meshes: Vec<Handle<Mesh>>,
    /// materials for this node
    pub materials: Vec<Handle<Material>>,
    /// transform in matrix form for this node
    pub matrix: Matrix4,
    /// child nodes
    pub children: Vec<Self>,
}

struct ChildIter<'a> {
    stack: Vec<Iter<'a, ModelNode>>,
}

impl Model {
    /// iterates through all meshes in the model
    pub fn meshes(&self) -> impl Iterator<Item = &Handle<Mesh>> {
        self.nodes.iter().map(|node| node.meshes()).flatten()
    }

    /// iterates through all materials in the model
    pub fn materials(&self) -> impl Iterator<Item = &Handle<Material>> {
        self.nodes.iter().map(|node| node.materials()).flatten()
    }
}

impl ModelNode {
    pub(crate) fn orders(&self) -> impl Iterator<Item = (&Handle<Mesh>, &Handle<Material>)> {
        self.meshes.iter().zip(self.materials.iter())
    }

    fn meshes(&self) -> impl Iterator<Item = &Handle<Mesh>> {
        self.meshes
            .iter()
            .chain(self.child_iter().map(|node| node.meshes.iter()).flatten())
    }

    fn materials(&self) -> impl Iterator<Item = &Handle<Material>> {
        self.materials.iter().chain(
            self.child_iter()
                .map(|node| node.materials.iter())
                .flatten(),
        )
    }

    fn child_iter(&self) -> ChildIter<'_> {
        ChildIter {
            stack: vec![self.children.iter()],
        }
    }
}

impl<'a> Iterator for ChildIter<'a> {
    type Item = &'a ModelNode;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            if let Some(mut top_iter) = self.stack.pop() {
                if let Some(node) = top_iter.next() {
                    // put iter back on stack
                    self.stack.push(top_iter);

                    // put node's children on stack
                    self.stack.push(node.children.iter());
                    return Some(&node);
                }
            } else {
                // stack emtpy
                return None;
            }
        }
    }
}