fbxcel_dom/v7400/data/mesh/layer/
material.rs

1//! Material.
2
3use anyhow::{bail, format_err, Error};
4
5use crate::v7400::data::mesh::{
6    layer::{
7        LayerContentIndex, LayerElementHandle, MappingMode, ReferenceInformation, ReferenceMode,
8    },
9    TriangleVertexIndex, TriangleVertices,
10};
11
12/// Layer element node handle.
13#[derive(Debug, Clone, Copy)]
14pub struct LayerElementMaterialHandle<'a> {
15    /// `LayerElementMaterial` node.
16    node: LayerElementHandle<'a>,
17}
18
19impl<'a> LayerElementMaterialHandle<'a> {
20    /// Creates a new `LayerElementMaterialHandle`.
21    pub fn new(node: LayerElementHandle<'a>) -> Self {
22        Self { node }
23    }
24
25    /// Returns `Materials` data.
26    pub fn materials(&self) -> Result<Materials<'a>, Error> {
27        Materials::new(self)
28    }
29
30    /// Returns material indices slice.
31    fn material_indices_slice(&self) -> Result<&'a [i32], Error> {
32        self.children_by_name("Materials")
33            .next()
34            .ok_or_else(|| format_err!("No `Materials` found for `LayerElementMaterial` node"))?
35            .attributes()
36            .get(0)
37            .ok_or_else(|| format_err!("No attributes found for `Materials` node"))?
38            .get_arr_i32_or_type()
39            .map_err(|ty| format_err!("Expected `[i32]` as material indices, but got {:?}", ty))
40    }
41}
42
43impl<'a> std::ops::Deref for LayerElementMaterialHandle<'a> {
44    type Target = LayerElementHandle<'a>;
45
46    fn deref(&self) -> &Self::Target {
47        &self.node
48    }
49}
50
51/// Materials.
52#[derive(Debug, Clone, Copy)]
53pub struct Materials<'a> {
54    /// Mapping mode.
55    mapping_mode: MappingMode,
56    /// Reference information.
57    indices: &'a [i32],
58}
59
60impl<'a> Materials<'a> {
61    /// Creates a new `Materials`.
62    fn new(handle: &LayerElementMaterialHandle<'a>) -> Result<Self, Error> {
63        let mapping_mode = handle.mapping_mode()?;
64        let reference_mode = handle.reference_mode()?;
65        if reference_mode != ReferenceMode::IndexToDirect {
66            bail!(
67                "Unsupported reference mode for material: {:?}",
68                reference_mode
69            );
70        }
71        let indices = handle.material_indices_slice()?;
72
73        Ok(Self {
74            mapping_mode,
75            indices,
76        })
77    }
78
79    /// Returns material index corresponding to the given triangle vertex index.
80    pub fn material_index(
81        &self,
82        tris: &TriangleVertices<'a>,
83        tri_vi: TriangleVertexIndex,
84    ) -> Result<MaterialIndex, Error> {
85        let i = LayerContentIndex::control_point_data_from_triangle_vertices(
86            ReferenceInformation::Direct,
87            self.mapping_mode,
88            tris,
89            self.indices.len(),
90            tri_vi,
91        )?;
92        let material_index_index = self.indices[i.get()];
93        if material_index_index < 0 {
94            bail!(
95                "Negative index is not allowed: material_index_index={:?}",
96                material_index_index
97            );
98        }
99
100        Ok(MaterialIndex::new(material_index_index as u32))
101    }
102}
103
104/// Material index.
105#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
106pub struct MaterialIndex(u32);
107
108impl MaterialIndex {
109    /// Creates a new `MaterialIndex`.
110    fn new(i: u32) -> Self {
111        Self(i)
112    }
113
114    /// Returns the material index.
115    pub fn to_u32(self) -> u32 {
116        self.0
117    }
118
119    /// Returns the material index.
120    #[deprecated(since = "0.0.3", note = "Renamed to `to_u32`")]
121    pub fn get_u32(self) -> u32 {
122        self.to_u32()
123    }
124}