gltf_kun 0.0.2

Extensible library for building glTF toolchains.
Documentation
pub use gltf::json::accessor::ComponentType;
use std::{cell::RefCell, rc::Rc};

use crate::graph::{AccessorArray, AccessorData, ElementType, GltfGraph, GraphData, GraphNode};
use petgraph::graph::NodeIndex;

pub struct Accessor {
    pub(crate) node: GraphNode,
}

impl Accessor {
    pub fn new(graph: Rc<RefCell<GltfGraph>>, index: NodeIndex) -> Self {
        Self {
            node: GraphNode::new(graph, index),
        }
    }

    fn data(&self) -> AccessorData {
        match self.node.data() {
            GraphData::Accessor(data) => data,
            _ => panic!("data is not an accessor"),
        }
    }

    fn set_data(&mut self, data: AccessorData) {
        self.node.set_data(GraphData::Accessor(data));
    }

    pub fn name(&self) -> Option<String> {
        self.data().name
    }

    pub fn set_name(&mut self, name: Option<String>) {
        let mut data = self.data();
        data.name = name;
        self.set_data(data);
    }

    pub fn array(&self) -> AccessorArray {
        self.data().array
    }

    pub fn set_array(&mut self, array: AccessorArray) {
        let mut data = self.data();
        data.array = array;
        self.set_data(data);
    }

    pub fn element_type(&self) -> ElementType {
        self.data().element_type
    }

    pub fn set_element_type(&mut self, element_type: ElementType) {
        let mut data = self.data();
        data.element_type = element_type;
        self.set_data(data);
    }

    pub fn normalized(&self) -> bool {
        self.data().normalized
    }

    pub fn set_normalized(&mut self, normalized: bool) {
        let mut data = self.data();
        data.normalized = normalized;
        self.set_data(data);
    }

    /// The number of bytes required to store this accessor's data.
    pub fn byte_length(&self) -> usize {
        self.data().array.len() * self.component_size()
    }

    /// The datatype of components in this accessor.
    pub fn component_type(&self) -> ComponentType {
        match self.data().array {
            AccessorArray::I8(_) => ComponentType::I8,
            AccessorArray::U8(_) => ComponentType::U8,
            AccessorArray::I16(_) => ComponentType::I16,
            AccessorArray::U16(_) => ComponentType::U16,
            AccessorArray::U32(_) => ComponentType::U32,
            AccessorArray::F32(_) => ComponentType::F32,
        }
    }

    /// The number of bytes per component in this accessor.
    pub fn component_size(&self) -> usize {
        match self.component_type() {
            ComponentType::I8 => 1,
            ComponentType::U8 => 1,
            ComponentType::I16 => 2,
            ComponentType::U16 => 2,
            ComponentType::U32 => 4,
            ComponentType::F32 => 4,
        }
    }

    /// Number of elements in this accessor.
    pub fn count(&self) -> usize {
        let len = self.data().array.len();
        let element_size = self.element_size();
        len / element_size
    }

    /// Size of each element in this accessor.
    pub fn element_size(&self) -> usize {
        self.data().element_type.size()
    }

    /// Maxiumum value of each component in this accessor.
    pub fn max(&self) -> AccessorArray {
        let element_size = self.element_size();

        match self.data().array {
            AccessorArray::I8(array) => get_max(&array, element_size).into(),
            AccessorArray::U8(array) => get_max(&array, element_size).into(),
            AccessorArray::I16(array) => get_max(&array, element_size).into(),
            AccessorArray::U16(array) => get_max(&array, element_size).into(),
            AccessorArray::U32(array) => get_max(&array, element_size).into(),
            AccessorArray::F32(array) => get_max(&array, element_size).into(),
        }
    }

    /// Minimum value of each component in this accessor.
    pub fn min(&self) -> AccessorArray {
        let element_size = self.element_size();

        match self.data().array {
            AccessorArray::I8(array) => get_min(&array, element_size).into(),
            AccessorArray::U8(array) => get_min(&array, element_size).into(),
            AccessorArray::I16(array) => get_min(&array, element_size).into(),
            AccessorArray::U16(array) => get_min(&array, element_size).into(),
            AccessorArray::U32(array) => get_min(&array, element_size).into(),
            AccessorArray::F32(array) => get_min(&array, element_size).into(),
        }
    }
}

fn get_max<T>(array: &[T], element_size: usize) -> Vec<T>
where
    T: Copy + PartialOrd,
{
    array
        .chunks(element_size)
        .fold(Vec::with_capacity(element_size), |max: Vec<T>, chunk| {
            max.iter()
                .zip(chunk.iter())
                .map(|(a, b)| if a > b { *a } else { *b })
                .collect()
        })
}

fn get_min<T>(array: &[T], element_size: usize) -> Vec<T>
where
    T: Copy + PartialOrd,
{
    array
        .chunks(element_size)
        .fold(Vec::with_capacity(element_size), |min: Vec<T>, chunk| {
            min.iter()
                .zip(chunk.iter())
                .map(|(a, b)| if a < b { *a } else { *b })
                .collect()
        })
}