use std::collections::hash_map;
use std::{iter, slice};
use {accessor, extensions, json, material};
use accessor::{Accessor, DataType, Dimensions, Iter};
use Gltf;
pub use json::mesh::{Mode, Semantic};
#[derive(Debug)]
pub struct Normals(Iter<[f32; 3]>);
#[derive(Debug)]
pub struct NormalDisplacements(Iter<[f32; 3]>);
#[derive(Debug)]
pub struct Positions(Iter<[f32; 3]>);
#[derive(Debug)]
pub struct PositionDisplacements(Iter<[f32; 3]>);
#[derive(Debug)]
pub struct Tangents(Iter<[f32; 4]>);
#[derive(Debug)]
pub struct TangentDisplacements(Iter<[f32; 3]>);
#[derive(Debug)]
pub enum Colors {
RgbU8(Iter<[u8; 3]>),
RgbaU8(Iter<[u8; 4]>),
RgbU16(Iter<[u16; 3]>),
RgbaU16(Iter<[u16; 4]>),
RgbF32(Iter<[f32; 3]>),
RgbaF32(Iter<[f32; 4]>),
}
#[derive(Debug)]
pub enum Indices {
U8(Iter<u8>),
U16(Iter<u16>),
U32(Iter<u32>),
}
#[derive(Debug)]
pub enum Joints {
U8(Iter<[u8; 4]>),
U16(Iter<[u16; 4]>),
}
#[derive(Debug)]
pub enum TexCoords {
F32(Iter<[f32; 2]>),
U8(Iter<[u8; 2]>),
U16(Iter<[u16; 2]>),
}
#[derive(Debug)]
pub enum Weights {
F32(Iter<[f32; 4]>),
U8(Iter<[u8; 4]>),
U16(Iter<[u16; 4]>),
}
#[derive(Debug)]
pub enum Attribute {
Colors(u32, Colors),
Joints(u32, Joints),
Positions(Positions),
Normals(Normals),
Tangents(Tangents),
TexCoords(u32, TexCoords),
Weights(u32, Weights),
}
#[derive(Debug)]
pub struct MorphTarget {
positions: Option<PositionDisplacements>,
normals: Option<NormalDisplacements>,
tangents: Option<TangentDisplacements>,
}
#[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> {
prim: &'a Primitive<'a>,
iter: hash_map::Iter<'a, 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>>,
}
impl<'a> Mesh<'a> {
pub 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 extensions(&self) -> extensions::mesh::Mesh<'a> {
extensions::mesh::Mesh::new(
self.gltf,
&self.json.extensions,
)
}
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 Colors {
fn from_accessor<'a>(accessor: Accessor<'a>) -> Colors {
unsafe {
match (accessor.dimensions(), accessor.data_type()) {
(Dimensions::Vec3, DataType::U8) => {
Colors::RgbU8(accessor.iter())
},
(Dimensions::Vec4, DataType::U8) => {
Colors::RgbaU8(accessor.iter())
},
(Dimensions::Vec3, DataType::U16) => {
Colors::RgbU16(accessor.iter())
},
(Dimensions::Vec4, DataType::U16) => {
Colors::RgbaU16(accessor.iter())
},
(Dimensions::Vec3, DataType::F32) => {
Colors::RgbF32(accessor.iter())
},
(Dimensions::Vec4, DataType::F32) => {
Colors::RgbaF32(accessor.iter())
},
_ => unreachable!(),
}
}
}
}
impl TexCoords {
fn from_accessor<'a>(accessor: Accessor<'a>) -> TexCoords {
unsafe {
match accessor.data_type() {
DataType::U8 => TexCoords::U8(accessor.iter()),
DataType::U16 => TexCoords::U16(accessor.iter()),
DataType::F32 => TexCoords::F32(accessor.iter()),
_ => unreachable!(),
}
}
}
}
impl Indices {
fn from_accessor<'a>(accessor: Accessor) -> Indices {
unsafe {
match accessor.data_type() {
DataType::U8 => Indices::U8(accessor.iter()),
DataType::U16 => Indices::U16(accessor.iter()),
DataType::U32 => Indices::U32(accessor.iter()),
_ => unreachable!(),
}
}
}
}
impl Joints {
fn from_accessor<'a>(accessor: Accessor<'a>) -> Joints {
unsafe {
match accessor.data_type() {
DataType::U8 => Joints::U8(accessor.iter()),
DataType::U16 => Joints::U16(accessor.iter()),
_ => unreachable!(),
}
}
}
}
impl Weights {
fn from_accessor<'a>(accessor: Accessor<'a>) -> Weights {
unsafe {
match accessor.data_type() {
DataType::U8 => Weights::U8(accessor.iter()),
DataType::U16 => Weights::U16(accessor.iter()),
DataType::F32 => Weights::F32(accessor.iter()),
_ => unreachable!(),
}
}
}
}
impl<'a> Primitive<'a> {
pub 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 colors(&self, set: u32) -> Option<Colors> {
self.find_accessor_with_semantic(Semantic::Colors(set))
.map(|accessor| Colors::from_accessor(accessor))
}
pub fn tex_coords(&self, set: u32) -> Option<TexCoords> {
self.find_accessor_with_semantic(Semantic::TexCoords(set))
.map(|accessor| TexCoords::from_accessor(accessor))
}
pub fn joints(&self, set: u32) -> Option<Joints> {
self.find_accessor_with_semantic(Semantic::Joints(set))
.map(|accessor| Joints::from_accessor(accessor))
}
pub fn weights(&self, set: u32) -> Option<Weights> {
self.find_accessor_with_semantic(Semantic::Weights(set))
.map(|accessor| Weights::from_accessor(accessor))
}
pub fn indices(&self) -> Option<Indices> {
self.json.indices.as_ref().map(|index| {
let accessor = self.mesh.gltf.accessors().nth(index.value()).unwrap();
Indices::from_accessor(accessor)
})
}
pub fn positions(&self) -> Option<Positions> {
self.find_accessor_with_semantic(Semantic::Positions)
.map(|accessor| unsafe {
Positions(accessor.iter())
})
}
pub fn normals(&self) -> Option<Normals> {
self.find_accessor_with_semantic(Semantic::Normals)
.map(|accessor| unsafe {
Normals(accessor.iter())
})
}
pub fn tangents(&self) -> Option<Tangents> {
self.find_accessor_with_semantic(Semantic::Tangents)
.map(|accessor| unsafe {
Tangents(accessor.iter())
})
}
fn find_accessor_with_semantic(
&self,
semantic: Semantic,
) -> Option<accessor::Accessor<'a>> {
self.json.attributes
.iter()
.find(|&(ref key, _)| key.as_ref().unwrap() == &semantic)
.map(|(_, index)| self.mesh.gltf.accessors().nth(index.value()).unwrap())
}
pub fn extensions(&self) -> extensions::mesh::Primitive<'a> {
extensions::mesh::Primitive::new(
self.mesh,
&self.json.extensions,
)
}
pub fn extras(&self) -> &json::Extras {
&self.json.extras
}
pub fn material(&self) -> Option<material::Material<'a>> {
self.json.material.as_ref().map(|index| {
self.mesh.gltf.materials().nth(index.value()).unwrap()
})
}
pub fn mode(&self) -> Mode {
self.json.mode.unwrap()
}
}
impl Iterator for Positions {
type Item = [f32; 3];
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}
impl Iterator for PositionDisplacements {
type Item = [f32; 3];
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}
impl Iterator for Normals {
type Item = [f32; 3];
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}
impl Iterator for NormalDisplacements {
type Item = [f32; 3];
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}
impl Iterator for Tangents {
type Item = [f32; 4];
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}
impl Iterator for TangentDisplacements {
type Item = [f32; 3];
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}
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))
}
}