blender_mesh/
lib.rs

1//! Blender files can have meshes such as circles, cubes, cylinders, a dragon or any other
2//! 3D shape.
3//!
4//! A mesh can be represented as a group of vertices and data about those vertices, such as their
5//! normals or UV coordinates.
6//!
7//! Meshes can also have metadata, such as the name of it's parent armature (useful for vertex
8//! skinning).
9//!
10//! blender-mesh-to-json seeks to be a well tested, well documented exporter for blender mesh
11//! metadata.
12//!
13//! You can write data to stdout or to a file. At the onset it will be geared towards @chinedufn's
14//! needs - but if you have needs that aren't met feel very free to open an issue.
15//!
16//! @see https://docs.blender.org/manual/en/dev/modeling/meshes/introduction.html - Mesh Introduction
17//! @see https://github.com/chinedufn/blender-actions-to-json - Exporting blender armatures / actions
18
19#[macro_use]
20extern crate failure;
21#[macro_use]
22extern crate serde_derive;
23
24pub use self::combine_indices::CreateSingleIndexConfig;
25pub use self::export::*;
26pub use crate::bounding_box::BoundingBox;
27use crate::custom_property::CustomProperty;
28pub use crate::material::PrincipledBSDF;
29use crate::serde::serialize_hashmap_deterministic;
30pub use crate::vertex_attributes::{
31    BoneInfluence, MultiIndexedVertexAttributes, SingleIndexedVertexAttributes, Vertex,
32    VertexAttribute,
33};
34pub use material::{Channel, MaterialInput};
35use std::collections::HashMap;
36
37mod bone;
38mod bounding_box;
39mod combine_indices;
40mod custom_property;
41mod export;
42mod face_tangents;
43mod interleave;
44mod material;
45mod serde;
46mod triangulate;
47mod vertex_attributes;
48mod y_up;
49
50mod create_mesh;
51
52#[cfg(test)]
53mod test_utils;
54
55/// Something went wrong in the Blender child process that was trying to parse your mesh data.
56#[derive(Debug, Fail)]
57pub enum BlenderError {
58    /// Errors in Blender are written to stderr. We capture the stderr from the `blender` child
59    /// process that we spawned when attempting to export meshes from a `.blend` file.
60    #[fail(
61        display = "There was an issue while exporting meshes: Blender stderr output: {}",
62        _0
63    )]
64    Stderr(String),
65}
66
67/// All of the data about a mesh
68///
69/// TODO: Rename crate to `MeshIr`
70#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
71#[serde(deny_unknown_fields)]
72pub struct BlenderMesh {
73    name: String,
74    armature_name: Option<String>,
75    bounding_box: BoundingBox,
76    #[serde(alias = "attribs")]
77    multi_indexed_vertex_attributes: MultiIndexedVertexAttributes,
78    #[serde(default, serialize_with = "serialize_hashmap_deterministic")]
79    materials: HashMap<String, PrincipledBSDF>,
80    #[serde(default, serialize_with = "serialize_hashmap_deterministic")]
81    custom_properties: HashMap<String, CustomProperty>,
82}
83
84impl BlenderMesh {
85    /// The name of this mesh's parent armature
86    pub fn armature_name(&self) -> Option<&String> {
87        self.armature_name.as_ref()
88    }
89
90    /// Set the name of this mesh's parent armature
91    pub fn set_armature_name(&mut self, armature_name: Option<String>) {
92        self.armature_name = armature_name;
93    }
94
95    /// A map of material name to the material's data
96    pub fn materials(&self) -> &HashMap<String, PrincipledBSDF> {
97        &self.materials
98    }
99
100    /// A mutable map of material name to the material's data
101    pub fn materials_mut(&mut self) -> &mut HashMap<String, PrincipledBSDF> {
102        &mut self.materials
103    }
104
105    /// Custom properties for this mesh
106    ///
107    /// i.e. in Blender this might be found with `bpy.context.view_layer.objects.active.keys()`
108    pub fn custom_properties(&self) -> &HashMap<String, CustomProperty> {
109        &self.custom_properties
110    }
111
112    /// The smallest box that contains the entire mesh
113    pub fn bounding_box(&self) -> BoundingBox {
114        self.bounding_box
115    }
116
117    /// Set the mesh's bounding box.
118    pub fn set_bounding_box(&mut self, bounding_box: BoundingBox) {
119        self.bounding_box = bounding_box;
120    }
121
122    /// The name of the mesh
123    pub fn name(&self) -> &String {
124        &self.name
125    }
126
127    /// Set the name of the mesh
128    pub fn set_name(&mut self, name: String) {
129        self.name = name;
130    }
131}
132
133/// Concatenate a series of vectors into one vector.
134///
135/// Useful for generating fake vertex data for unit tests.
136///
137/// ```ignore
138/// assert_eq!(
139///     concat_vecs!(vec![1, 2, 3], vec![4,5]),
140///     vec![1, 2, 3, 4, 5]
141/// );
142/// ```
143#[cfg(test)]
144#[macro_export]
145#[cfg(test)]
146macro_rules! concat_vecs {
147    ( $( $vec:expr),* ) => {
148        {
149            let mut concatenated_vec = Vec::new();
150            $(
151                concatenated_vec.append(&mut $vec.clone());
152            )*
153            concatenated_vec
154        }
155    }
156}
157
158#[cfg(test)]
159fn indexed(
160    attribute: crate::vertex_attributes::VertexAttribute<f32>,
161) -> crate::vertex_attributes::IndexedAttribute {
162    crate::vertex_attributes::IndexedAttribute {
163        indices: vec![],
164        attribute,
165    }
166}