pub mod iter;
#[cfg(feature = "utils")]
#[cfg_attr(docsrs, doc(cfg(feature = "utils")))]
pub mod util;
use crate::{Accessor, Buffer, Document, Material};
#[cfg(feature = "utils")]
use crate::accessor;
pub use json::mesh::{Mode, Semantic};
use json::validation::Checked;
#[cfg(feature = "extensions")]
use serde_json::{Map, Value};
pub type Attribute<'a> = (Semantic, Accessor<'a>);
pub type BoundingBox = Bounds<[f32; 3]>;
#[derive(Clone, Debug, PartialEq)]
pub struct Bounds<T> {
pub min: T,
pub max: T,
}
#[derive(Clone, Debug)]
pub struct Mesh<'a> {
document: &'a Document,
index: usize,
json: &'a json::mesh::Mesh,
}
#[derive(Clone, Debug)]
pub struct MorphTarget<'a> {
positions: Option<Accessor<'a>>,
normals: Option<Accessor<'a>>,
tangents: Option<Accessor<'a>>,
}
#[derive(Clone, Debug)]
pub struct Primitive<'a> {
mesh: Mesh<'a>,
index: usize,
json: &'a json::mesh::Primitive,
}
#[derive(Clone, Debug)]
pub struct Reader<'a, 's, F>
where
F: Clone + Fn(Buffer<'a>) -> Option<&'s [u8]>,
{
#[allow(dead_code)]
pub(crate) primitive: &'a Primitive<'a>,
#[allow(dead_code)]
pub(crate) get_buffer_data: F,
}
impl<'a> Mesh<'a> {
pub(crate) fn new(document: &'a Document, index: usize, json: &'a json::mesh::Mesh) -> Self {
Self {
document,
index,
json,
}
}
pub fn index(&self) -> usize {
self.index
}
#[cfg(feature = "extensions")]
#[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
pub fn extensions(&self) -> Option<&Map<String, Value>> {
let ext = self.json.extensions.as_ref()?;
Some(&ext.others)
}
#[cfg(feature = "extensions")]
#[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
pub fn extension_value(&self, ext_name: &str) -> Option<&Value> {
let ext = self.json.extensions.as_ref()?;
ext.others.get(ext_name)
}
pub fn extras(&self) -> &'a json::Extras {
&self.json.extras
}
#[cfg(feature = "names")]
#[cfg_attr(docsrs, doc(cfg(feature = "names")))]
pub fn name(&self) -> Option<&'a str> {
self.json.name.as_deref()
}
pub fn primitives(&self) -> iter::Primitives<'a> {
iter::Primitives {
mesh: self.clone(),
iter: self.json.primitives.iter().enumerate(),
}
}
pub fn weights(&self) -> Option<&'a [f32]> {
self.json.weights.as_deref()
}
}
impl<'a> Primitive<'a> {
pub(crate) fn new(mesh: Mesh<'a>, index: usize, json: &'a json::mesh::Primitive) -> Self {
Self { mesh, index, json }
}
pub fn bounding_box(&self) -> BoundingBox {
let pos_accessor_index = self
.json
.attributes
.get(&Checked::Valid(Semantic::Positions))
.unwrap();
let pos_accessor = self
.mesh
.document
.accessors()
.nth(pos_accessor_index.value())
.unwrap();
let min: [f32; 3] = json::deserialize::from_value(pos_accessor.min().unwrap()).unwrap();
let max: [f32; 3] = json::deserialize::from_value(pos_accessor.max().unwrap()).unwrap();
Bounds { min, max }
}
#[cfg(feature = "extensions")]
#[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
pub fn extensions(&self) -> Option<&Map<String, Value>> {
let ext = self.json.extensions.as_ref()?;
Some(&ext.others)
}
#[cfg(feature = "extensions")]
#[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
pub fn extension_value(&self, ext_name: &str) -> Option<&Value> {
let ext = self.json.extensions.as_ref()?;
ext.others.get(ext_name)
}
pub fn extras(&self) -> &'a json::Extras {
&self.json.extras
}
pub fn get(&self, semantic: &Semantic) -> Option<Accessor<'a>> {
self.json
.attributes
.get(&json::validation::Checked::Valid(semantic.clone()))
.map(|index| self.mesh.document.accessors().nth(index.value()).unwrap())
}
pub fn index(&self) -> usize {
self.index
}
pub fn indices(&self) -> Option<Accessor<'a>> {
self.json
.indices
.as_ref()
.map(|index| self.mesh.document.accessors().nth(index.value()).unwrap())
}
pub fn attributes(&self) -> iter::Attributes<'a> {
iter::Attributes {
document: self.mesh.document,
prim: self.clone(),
iter: self.json.attributes.iter(),
}
}
pub fn material(&self) -> Material<'a> {
self.json
.material
.as_ref()
.map(|index| self.mesh.document.materials().nth(index.value()).unwrap())
.unwrap_or_else(|| Material::default(self.mesh.document))
}
pub fn mode(&self) -> Mode {
self.json.mode.unwrap()
}
pub fn morph_targets(&self) -> iter::MorphTargets<'a> {
if let Some(slice) = self.json.targets.as_ref() {
iter::MorphTargets {
document: self.mesh.document,
iter: slice.iter(),
}
} else {
iter::MorphTargets {
document: self.mesh.document,
iter: ([]).iter(),
}
}
}
#[cfg(feature = "KHR_materials_variants")]
#[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_variants")))]
pub fn mappings(&self) -> iter::Mappings<'a> {
let iter = self
.json
.extensions
.as_ref()
.and_then(|extensions| extensions.khr_materials_variants.as_ref())
.map(|variants| variants.mappings.iter())
.unwrap_or_else(|| ([]).iter());
iter::Mappings {
document: self.mesh.document,
iter,
}
}
#[cfg(feature = "utils")]
#[cfg_attr(docsrs, doc(cfg(feature = "utils")))]
pub fn reader<'s, F>(&'a self, get_buffer_data: F) -> Reader<'a, 's, F>
where
F: Clone + Fn(Buffer<'a>) -> Option<&'s [u8]>,
{
Reader {
primitive: self,
get_buffer_data,
}
}
}
#[cfg(feature = "utils")]
impl<'a, 's, F> Reader<'a, 's, F>
where
F: Clone + Fn(Buffer<'a>) -> Option<&'s [u8]>,
{
pub fn read_positions(&self) -> Option<util::ReadPositions<'s>> {
self.primitive
.get(&Semantic::Positions)
.and_then(|accessor| accessor::Iter::new(accessor, self.get_buffer_data.clone()))
}
pub fn read_normals(&self) -> Option<util::ReadNormals<'s>> {
self.primitive
.get(&Semantic::Normals)
.and_then(|accessor| accessor::Iter::new(accessor, self.get_buffer_data.clone()))
}
pub fn read_tangents(&self) -> Option<util::ReadTangents<'s>> {
self.primitive
.get(&Semantic::Tangents)
.and_then(|accessor| accessor::Iter::new(accessor, self.get_buffer_data.clone()))
}
pub fn read_colors(&self, set: u32) -> Option<util::ReadColors<'s>> {
use self::util::ReadColors;
use accessor::DataType::{F32, U16, U8};
use accessor::Dimensions::{Vec3, Vec4};
self.primitive
.get(&Semantic::Colors(set))
.and_then(
|accessor| match (accessor.data_type(), accessor.dimensions()) {
(U8, Vec3) => accessor::Iter::new(accessor, self.get_buffer_data.clone())
.map(ReadColors::RgbU8),
(U16, Vec3) => accessor::Iter::new(accessor, self.get_buffer_data.clone())
.map(ReadColors::RgbU16),
(F32, Vec3) => accessor::Iter::new(accessor, self.get_buffer_data.clone())
.map(ReadColors::RgbF32),
(U8, Vec4) => accessor::Iter::new(accessor, self.get_buffer_data.clone())
.map(ReadColors::RgbaU8),
(U16, Vec4) => accessor::Iter::new(accessor, self.get_buffer_data.clone())
.map(ReadColors::RgbaU16),
(F32, Vec4) => accessor::Iter::new(accessor, self.get_buffer_data.clone())
.map(ReadColors::RgbaF32),
_ => unreachable!(),
},
)
}
pub fn read_indices(&self) -> Option<util::ReadIndices<'s>> {
use self::util::ReadIndices;
use accessor::DataType;
self.primitive
.indices()
.and_then(|accessor| match accessor.data_type() {
DataType::U8 => {
accessor::Iter::new(accessor, self.get_buffer_data.clone()).map(ReadIndices::U8)
}
DataType::U16 => accessor::Iter::new(accessor, self.get_buffer_data.clone())
.map(ReadIndices::U16),
DataType::U32 => accessor::Iter::new(accessor, self.get_buffer_data.clone())
.map(ReadIndices::U32),
_ => unreachable!(),
})
}
pub fn read_joints(&self, set: u32) -> Option<util::ReadJoints<'s>> {
use self::util::ReadJoints;
use accessor::DataType;
self.primitive
.get(&Semantic::Joints(set))
.and_then(|accessor| match accessor.data_type() {
DataType::U8 => {
accessor::Iter::new(accessor, self.get_buffer_data.clone()).map(ReadJoints::U8)
}
DataType::U16 => {
accessor::Iter::new(accessor, self.get_buffer_data.clone()).map(ReadJoints::U16)
}
_ => unreachable!(),
})
}
pub fn read_tex_coords(&self, set: u32) -> Option<util::ReadTexCoords<'s>> {
use self::util::ReadTexCoords;
use accessor::DataType;
self.primitive
.get(&Semantic::TexCoords(set))
.and_then(|accessor| match accessor.data_type() {
DataType::U8 => accessor::Iter::new(accessor, self.get_buffer_data.clone())
.map(ReadTexCoords::U8),
DataType::U16 => accessor::Iter::new(accessor, self.get_buffer_data.clone())
.map(ReadTexCoords::U16),
DataType::F32 => accessor::Iter::new(accessor, self.get_buffer_data.clone())
.map(ReadTexCoords::F32),
_ => unreachable!(),
})
}
pub fn read_weights(&self, set: u32) -> Option<util::ReadWeights<'s>> {
use self::accessor::DataType;
use self::util::ReadWeights;
self.primitive
.get(&Semantic::Weights(set))
.and_then(|accessor| match accessor.data_type() {
DataType::U8 => {
accessor::Iter::new(accessor, self.get_buffer_data.clone()).map(ReadWeights::U8)
}
DataType::U16 => accessor::Iter::new(accessor, self.get_buffer_data.clone())
.map(ReadWeights::U16),
DataType::F32 => accessor::Iter::new(accessor, self.get_buffer_data.clone())
.map(ReadWeights::F32),
_ => unreachable!(),
})
}
pub fn read_morph_targets(&self) -> util::ReadMorphTargets<'a, 's, F> {
util::ReadMorphTargets {
index: 0,
reader: self.clone(),
}
}
}
impl<'a> MorphTarget<'a> {
pub fn positions(&self) -> Option<Accessor<'a>> {
self.positions.clone()
}
pub fn normals(&self) -> Option<Accessor<'a>> {
self.normals.clone()
}
pub fn tangents(&self) -> Option<Accessor<'a>> {
self.tangents.clone()
}
}