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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
//! Color.

use anyhow::{format_err, Error};

use crate::v7400::data::mesh::{
    layer::{
        LayerContentIndex, LayerElementHandle, MappingMode, ReferenceInformation, ReferenceMode,
    },
    TriangleVertexIndex, TriangleVertices,
};

/// Layer element node handle.
#[derive(Debug, Clone, Copy)]
pub struct LayerElementColorHandle<'a> {
    /// `LayerElementColor` node.
    node: LayerElementHandle<'a>,
}

impl<'a> LayerElementColorHandle<'a> {
    /// Creates a new `LayerElementColorHandle`.
    pub fn new(node: LayerElementHandle<'a>) -> Self {
        Self { node }
    }

    /// Returns `Color` data.
    pub fn color(&self) -> Result<Colors<'a>, Error> {
        Colors::new(self)
    }

    /// Returns reference to the colors slice.
    fn colors_slice(&self) -> Result<&'a [f64], Error> {
        self.children_by_name("Colors")
            .next()
            .ok_or_else(|| format_err!("No `Colors` found for `LayerElementColor` node"))?
            .attributes()
            .get(0)
            .ok_or_else(|| format_err!("No attributes found for `Colors` node"))?
            .get_arr_f64_or_type()
            .map_err(|ty| format_err!("Expected `[f64]` as colors, but got {:?}", ty))
    }

    /// Returns reference to the colors index slice.
    // NOTE: I (the author) am not sure `ColorsIndex` node really exists, but
    // it would be better to implement this rather than rejecting `ColorsIndex`
    // (if it exists).
    fn colors_index_slice(&self) -> Result<&'a [i32], Error> {
        self.children_by_name("ColorsIndex")
            .next()
            .ok_or_else(|| format_err!("No `ColorsIndex` found for `LayerElementColor` node"))?
            .attributes()
            .get(0)
            .ok_or_else(|| format_err!("No attributes found for `ColorsIndex` node"))?
            .get_arr_i32_or_type()
            .map_err(|ty| format_err!("Expected `[i32]` as color indices, but got {:?}", ty))
    }
}

impl<'a> std::ops::Deref for LayerElementColorHandle<'a> {
    type Target = LayerElementHandle<'a>;

    fn deref(&self) -> &Self::Target {
        &self.node
    }
}

/// Colors.
#[derive(Debug, Clone, Copy)]
pub struct Colors<'a> {
    /// Colors.
    colors: &'a [f64],
    /// Reference information.
    reference_info: ReferenceInformation<'a>,
    /// Mapping mode.
    mapping_mode: MappingMode,
}

impl<'a> Colors<'a> {
    /// Creates a new `Colors`.
    fn new(handle: &LayerElementColorHandle<'a>) -> Result<Self, Error> {
        let colors = handle.colors_slice()?;
        let mapping_mode = handle.mapping_mode()?;
        let reference_info = match handle.reference_mode()? {
            ReferenceMode::Direct => ReferenceInformation::Direct,
            ReferenceMode::IndexToDirect => {
                let colors_index = handle.colors_index_slice()?;
                ReferenceInformation::IndexToDirect(colors_index)
            }
        };

        Ok(Self {
            colors,
            reference_info,
            mapping_mode,
        })
    }

    /// Returns `[f64; 4]` color corresponding to the given triangle vertex
    /// index.
    pub fn color(
        &self,
        tris: &TriangleVertices<'a>,
        tri_vi: TriangleVertexIndex,
    ) -> Result<[f64; 4], Error> {
        let i = LayerContentIndex::control_point_data_from_triangle_vertices(
            self.reference_info,
            self.mapping_mode,
            tris,
            self.colors.len() / 4,
            tri_vi,
        )?;
        let i4 = i.get() * 4;
        Ok([
            self.colors[i4],
            self.colors[i4 + 1],
            self.colors[i4 + 2],
            self.colors[i4 + 3],
        ])
    }
}