use std::{iter, slice};
use {accessor, json, material};
use accessor::{Accessor, DataType, Dimensions, Iter};
use {Gltf, Loaded};
pub use json::mesh::{Mode, Semantic};
#[derive(Clone, Debug)]
pub struct Normals<'a>(Iter<'a, [f32; 3]>);
#[derive(Clone, Debug)]
pub struct NormalDisplacements<'a>(Iter<'a, [f32; 3]>);
#[derive(Clone, Debug)]
pub struct Positions<'a>(Iter<'a, [f32; 3]>);
#[derive(Clone, Debug)]
pub struct PositionDisplacements<'a>(Iter<'a, [f32; 3]>);
#[derive(Clone, Debug)]
pub struct Tangents<'a>(Iter<'a, [f32; 4]>);
#[derive(Clone, Debug)]
pub struct TangentDisplacements<'a>(Iter<'a, [f32; 3]>);
#[derive(Clone, Debug)]
pub enum Colors<'a> {
RgbU8(Iter<'a, [u8; 3]>),
RgbaU8(Iter<'a, [u8; 4]>),
RgbU16(Iter<'a, [u16; 3]>),
RgbaU16(Iter<'a, [u16; 4]>),
RgbF32(Iter<'a, [f32; 3]>),
RgbaF32(Iter<'a, [f32; 4]>),
}
#[derive(Clone, Debug)]
pub enum Indices<'a> {
U8(Iter<'a, u8>),
U16(Iter<'a, u16>),
U32(Iter<'a, u32>),
}
#[derive(Clone, Debug)]
pub struct IndicesU32<'a>(Indices<'a>);
#[derive(Clone, Debug)]
pub struct TexCoordsF32<'a>(TexCoords<'a>);
#[derive(Clone, Debug)]
pub enum Joints<'a> {
U8(Iter<'a, [u8; 4]>),
U16(Iter<'a, [u16; 4]>),
}
#[derive(Clone, Debug)]
pub enum TexCoords<'a> {
F32(Iter<'a, [f32; 2]>),
U8(Iter<'a, [u8; 2]>),
U16(Iter<'a, [u16; 2]>),
}
#[derive(Clone, Debug)]
pub enum Weights<'a> {
F32(Iter<'a, [f32; 4]>),
U8(Iter<'a, [u8; 4]>),
U16(Iter<'a, [u16; 4]>),
}
#[derive(Clone, Debug)]
pub struct MorphTargets<'a> {
positions: Option<PositionDisplacements<'a>>,
normals: Option<NormalDisplacements<'a>>,
tangents: Option<TangentDisplacements<'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 Primitives<'a> {
mesh: &'a Mesh<'a>,
iter: iter::Enumerate<slice::Iter<'a, json::mesh::Primitive>>,
}
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> Loaded<'a, Mesh<'a>> {
pub fn primitives(&'a self) -> Loaded<'a, Primitives<'a>> {
Loaded {
item: self.item.primitives(),
source: self.source,
}
}
}
impl<'a> Colors<'a> {
fn from_accessor(accessor: Loaded<'a, Accessor<'a>>) -> Colors<'a> {
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<'a> TexCoords<'a> {
fn from_accessor(accessor: Loaded<'a, Accessor<'a>>) -> TexCoords<'a> {
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<'a> Indices<'a> {
fn from_accessor(accessor: Loaded<'a, Accessor<'a>>) -> Indices<'a> {
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<'a> Joints<'a> {
fn from_accessor(accessor: Loaded<'a, Accessor<'a>>) -> Joints<'a> {
unsafe {
match accessor.data_type() {
DataType::U8 => Joints::U8(accessor.iter()),
DataType::U16 => Joints::U16(accessor.iter()),
_ => unreachable!(),
}
}
}
}
impl<'a> Weights<'a> {
fn from_accessor(accessor: Loaded<'a, Accessor<'a>>) -> Weights<'a> {
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(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 extras(&self) -> &json::Extras {
&self.json.extras
}
pub fn material(&self) -> material::Material<'a> {
self.json.material
.as_ref()
.map(|index| self.mesh.gltf.materials().nth(index.value()).unwrap())
.unwrap_or_else(|| material::Material::default(self.mesh.gltf))
}
pub fn mode(&self) -> Mode {
self.json.mode.unwrap()
}
}
impl<'a> Loaded<'a, Primitive<'a>> {
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 tex_coords_f32(&self, set: u32) -> Option<TexCoordsF32> {
self.tex_coords(set).map(TexCoordsF32)
}
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()
.loaded(self.source);
Indices::from_accessor(accessor)
})
}
pub fn indices_u32(&self) -> Option<IndicesU32> {
self.indices().map(IndicesU32)
}
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<Loaded<'a, 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()
.loaded(self.source)
})
}
pub fn material(&self) -> Loaded<'a, material::Material<'a>> {
Loaded {
item: self.item.material(),
source: self.source,
}
}
}
impl<'a> ExactSizeIterator for IndicesU32<'a> {}
impl<'a> Iterator for IndicesU32<'a> {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> {
match self.0 {
Indices::U8(ref mut i) => i.next().map(|x| x as u32),
Indices::U16(ref mut i) => i.next().map(|x| x as u32),
Indices::U32(ref mut i) => i.next(),
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
match self.0 {
Indices::U8(ref i) => i.size_hint(),
Indices::U16(ref i) => i.size_hint(),
Indices::U32(ref i) => i.size_hint(),
}
}
}
impl<'a> ExactSizeIterator for TexCoordsF32<'a> {}
impl<'a> Iterator for TexCoordsF32<'a> {
type Item = [f32; 2];
fn next(&mut self) -> Option<Self::Item> {
match self.0 {
TexCoords::U8(ref mut i) => {
i.next().map(|x| [x[0] as f32 / 255.0, x[1] as f32 / 255.0])
},
TexCoords::U16(ref mut i) => {
i.next().map(|x| [x[0] as f32 / 65535.0, x[1] as f32 / 65535.0])
},
TexCoords::F32(ref mut i) => i.next(),
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
match self.0 {
TexCoords::U8(ref i) => i.size_hint(),
TexCoords::U16(ref i) => i.size_hint(),
TexCoords::F32(ref i) => i.size_hint(),
}
}
}
impl<'a> ExactSizeIterator for Positions<'a> {}
impl<'a> Iterator for Positions<'a> {
type Item = [f32; 3];
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}
impl<'a> ExactSizeIterator for PositionDisplacements<'a> {}
impl<'a> Iterator for PositionDisplacements<'a> {
type Item = [f32; 3];
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}
impl<'a> ExactSizeIterator for Normals<'a> {}
impl<'a> Iterator for Normals<'a> {
type Item = [f32; 3];
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}
impl<'a> ExactSizeIterator for NormalDisplacements<'a> {}
impl<'a> Iterator for NormalDisplacements<'a> {
type Item = [f32; 3];
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}
impl<'a> ExactSizeIterator for Tangents<'a> {}
impl<'a> Iterator for Tangents<'a> {
type Item = [f32; 4];
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}
impl<'a> ExactSizeIterator for TangentDisplacements<'a> {}
impl<'a> Iterator for TangentDisplacements<'a> {
type Item = [f32; 3];
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}
impl<'a> ExactSizeIterator for Loaded<'a, Primitives<'a>> {}
impl<'a> Iterator for Loaded<'a, Primitives<'a>> {
type Item = Loaded<'a, Primitive<'a>>;
fn next(&mut self) -> Option<Self::Item> {
self.item
.next()
.map(|primitive| {
Loaded {
item: primitive,
source: self.source,
}
})
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.item.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()
}
}