use std::{collections, iter, slice};
use json;
use {Accessor, Gltf, Material};
pub use json::mesh::{Mode, Semantic};
use json::validation::Checked;
#[derive(Clone, Debug)]
pub enum Attribute<'a> {
Colors(u32, Accessor<'a>),
#[cfg(feature = "extras")]
Extras(&'a str, Accessor<'a>),
Joints(u32, Accessor<'a>),
Positions(Accessor<'a>),
Normals(Accessor<'a>),
Tangents(Accessor<'a>),
TexCoords(u32, Accessor<'a>),
Weights(u32, Accessor<'a>),
}
#[derive(Clone, Debug)]
pub struct MorphTargets<'a> {
positions: Option<Accessor<'a>>,
normals: Option<Accessor<'a>>,
tangents: Option<Accessor<'a>>,
}
#[derive(Clone, Debug)]
pub struct Mesh<'a> {
gltf: &'a Gltf,
index: usize,
json: &'a json::mesh::Mesh,
}
#[derive(Clone, Debug)]
pub struct Primitive<'a> {
mesh: &'a Mesh<'a>,
index: usize,
json: &'a json::mesh::Primitive,
}
#[derive(Clone, Debug)]
pub struct Attributes<'a> {
gltf: &'a Gltf,
prim: &'a Primitive<'a>,
iter: collections::hash_map::Iter<
'a,
json::validation::Checked<json::mesh::Semantic>,
json::Index<json::accessor::Accessor>,
>,
}
#[derive(Clone, Debug)]
pub struct Primitives<'a> {
mesh: &'a Mesh<'a>,
iter: iter::Enumerate<slice::Iter<'a, json::mesh::Primitive>>,
}
#[derive(Clone, Debug, PartialEq)]
pub struct Bounds<T> {
pub min: T,
pub max: T
}
impl<'a> Mesh<'a> {
pub(crate) fn new(
gltf: &'a Gltf,
index: usize,
json: &'a json::mesh::Mesh,
) -> Self {
Self {
gltf: gltf,
index: index,
json: json,
}
}
pub fn index(&self) -> usize {
self.index
}
pub fn as_json(&self) -> &json::mesh::Mesh {
self.json
}
pub fn extras(&self) -> &json::Extras {
&self.json.extras
}
#[cfg(feature = "names")]
pub fn name(&self) -> Option<&str> {
self.json.name.as_ref().map(String::as_str)
}
pub fn primitives(&'a self) -> Primitives<'a> {
Primitives {
mesh: self,
iter: self.json.primitives.iter().enumerate(),
}
}
pub fn weights(&self) -> Option<&[f32]> {
self.json.weights.as_ref().map(Vec::as_slice)
}
}
impl<'a> Primitive<'a> {
pub(crate) fn new(
mesh: &'a Mesh<'a>,
index: usize,
json: &'a json::mesh::Primitive,
) -> Self {
Self {
mesh: mesh,
index: index,
json: json,
}
}
pub fn as_json(&self) -> &json::mesh::Primitive {
self.json
}
pub fn position_bounds(&self) -> Option<Bounds<[f32; 3]>> {
if let Some(pos_accessor_index) = self.json.attributes.get(&Checked::Valid(Semantic::Positions)) {
let pos_accessor = self.mesh.gltf.accessors().nth(pos_accessor_index.value()).unwrap();
let min: [f32; 3] = json::from_value(pos_accessor.min().unwrap()).unwrap();
let max: [f32; 3] = json::from_value(pos_accessor.max().unwrap()).unwrap();
Some(Bounds {
min: [min[0], min[1], min[2]],
max: [max[0], max[1], max[2]]
})
} else {
None
}
}
pub fn extras(&self) -> &json::Extras {
&self.json.extras
}
pub fn get(&self, semantic: &Semantic) -> Option<Accessor> {
self.json.attributes
.get(&json::validation::Checked::Valid(semantic.clone()))
.map(|index| self.mesh.gltf.accessors().nth(index.value()).unwrap())
}
pub fn indices(&self) -> Option<Accessor> {
self.json.indices
.as_ref()
.map(|index| self.mesh.gltf.accessors().nth(index.value()).unwrap())
}
pub fn attributes(&self) -> Attributes {
Attributes {
gltf: self.mesh.gltf,
prim: self,
iter: self.json.attributes.iter(),
}
}
pub fn material(&self) -> Material {
self.json.material
.as_ref()
.map(|index| self.mesh.gltf.materials().nth(index.value()).unwrap())
.unwrap_or_else(|| Material::default(self.mesh.gltf))
}
pub fn mode(&self) -> Mode {
self.json.mode.unwrap()
}
}
impl<'a> ExactSizeIterator for Attributes<'a> {}
impl<'a> Iterator for Attributes<'a> {
type Item = Attribute<'a>;
fn next(&mut self) -> Option<Self::Item> {
use self::Semantic::*;
self.iter
.next()
.map(|(ref key, ref index)| {
let semantic = key.as_ref().unwrap();
let accessor = self.gltf.accessors().nth(index.value()).unwrap();
match *semantic {
Positions => Attribute::Positions(accessor),
Normals => Attribute::Normals(accessor),
Tangents => Attribute::Tangents(accessor),
Colors(set) => Attribute::Colors(set, accessor),
TexCoords(set) => Attribute::TexCoords(set, accessor),
Joints(set) => Attribute::Joints(set, accessor),
Weights(set) => Attribute::Weights(set, accessor),
#[cfg(feature = "extras")]
Extras(ref id) => Attribute::Extras(id, accessor),
}
})
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl<'a> ExactSizeIterator for Primitives<'a> {}
impl<'a> Iterator for Primitives<'a> {
type Item = Primitive<'a>;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|(index, json)| Primitive::new(self.mesh, index, json))
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}