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
1819#[macro_use]
20extern crate failure;
21#[macro_use]
22extern crate serde_derive;
2324pub 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;
3637mod 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;
4950mod create_mesh;
5152#[cfg(test)]
53mod test_utils;
5455/// 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 )]
64Stderr(String),
65}
6667/// 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")]
77multi_indexed_vertex_attributes: MultiIndexedVertexAttributes,
78#[serde(default, serialize_with = "serialize_hashmap_deterministic")]
79materials: HashMap<String, PrincipledBSDF>,
80#[serde(default, serialize_with = "serialize_hashmap_deterministic")]
81custom_properties: HashMap<String, CustomProperty>,
82}
8384impl BlenderMesh {
85/// The name of this mesh's parent armature
86pub fn armature_name(&self) -> Option<&String> {
87self.armature_name.as_ref()
88 }
8990/// Set the name of this mesh's parent armature
91pub fn set_armature_name(&mut self, armature_name: Option<String>) {
92self.armature_name = armature_name;
93 }
9495/// A map of material name to the material's data
96pub fn materials(&self) -> &HashMap<String, PrincipledBSDF> {
97&self.materials
98 }
99100/// A mutable map of material name to the material's data
101pub fn materials_mut(&mut self) -> &mut HashMap<String, PrincipledBSDF> {
102&mut self.materials
103 }
104105/// Custom properties for this mesh
106 ///
107 /// i.e. in Blender this might be found with `bpy.context.view_layer.objects.active.keys()`
108pub fn custom_properties(&self) -> &HashMap<String, CustomProperty> {
109&self.custom_properties
110 }
111112/// The smallest box that contains the entire mesh
113pub fn bounding_box(&self) -> BoundingBox {
114self.bounding_box
115 }
116117/// Set the mesh's bounding box.
118pub fn set_bounding_box(&mut self, bounding_box: BoundingBox) {
119self.bounding_box = bounding_box;
120 }
121122/// The name of the mesh
123pub fn name(&self) -> &String {
124&self.name
125 }
126127/// Set the name of the mesh
128pub fn set_name(&mut self, name: String) {
129self.name = name;
130 }
131}
132133/// 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 {
149let mut concatenated_vec = Vec::new();
150 $(
151 concatenated_vec.append(&mut $vec.clone());
152 )*
153 concatenated_vec
154 }
155 }
156}
157158#[cfg(test)]
159fn indexed(
160 attribute: crate::vertex_attributes::VertexAttribute<f32>,
161) -> crate::vertex_attributes::IndexedAttribute {
162crate::vertex_attributes::IndexedAttribute {
163 indices: vec![],
164 attribute,
165 }
166}