#![deny(missing_docs)]
#![allow(unknown_lints)]
#![cfg_attr(docsrs, feature(doc_cfg))]
#[cfg(test)]
#[macro_use]
extern crate approx;
#[cfg(feature = "import")]
extern crate image as image_crate;
#[macro_use]
extern crate lazy_static;
pub extern crate gltf_json as json;
pub mod accessor;
pub mod animation;
pub mod binary;
pub mod buffer;
pub mod camera;
pub mod image;
#[cfg(feature = "import")]
#[cfg_attr(docsrs, doc(cfg(feature = "import")))]
mod import;
pub mod iter;
#[cfg(feature = "KHR_lights_punctual")]
#[cfg_attr(docsrs, doc(cfg(feature = "KHR_lights_punctual")))]
pub mod khr_lights_punctual;
#[cfg(feature = "KHR_materials_variants")]
#[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_variants")))]
pub mod khr_materials_variants;
pub mod material;
mod math;
pub mod mesh;
pub mod scene;
pub mod skin;
pub mod texture;
#[cfg(feature = "extensions")]
use json::Value;
#[cfg(feature = "extensions")]
use serde_json::Map;
#[doc(inline)]
pub use self::accessor::Accessor;
#[doc(inline)]
pub use self::animation::Animation;
#[doc(inline)]
pub use self::binary::Glb;
#[doc(inline)]
pub use self::buffer::Buffer;
#[doc(inline)]
pub use self::camera::Camera;
#[doc(inline)]
pub use self::image::Image;
#[cfg(feature = "import")]
#[doc(inline)]
pub use self::import::import;
#[cfg(feature = "import")]
#[doc(inline)]
pub use self::import::import_buffers;
#[cfg(feature = "import")]
#[doc(inline)]
pub use self::import::import_images;
#[cfg(feature = "import")]
#[doc(inline)]
pub use self::import::import_slice;
#[doc(inline)]
pub use self::material::Material;
#[doc(inline)]
pub use self::mesh::{Attribute, Mesh, Primitive, Semantic};
#[doc(inline)]
pub use self::scene::{Node, Scene};
#[doc(inline)]
pub use self::skin::Skin;
#[doc(inline)]
pub use self::texture::Texture;
use std::path::Path;
use std::{fs, io, ops, result};
pub(crate) trait Normalize<T> {
fn normalize(self) -> T;
}
pub type Result<T> = result::Result<T, Error>;
#[derive(Debug)]
pub enum Error {
#[cfg(feature = "import")]
#[cfg_attr(docsrs, doc(cfg(feature = "import")))]
Base64(base64::DecodeError),
Binary(binary::Error),
#[cfg(feature = "import")]
#[cfg_attr(docsrs, doc(cfg(feature = "import")))]
BufferLength {
buffer: usize,
expected: usize,
actual: usize,
},
Deserialize(json::Error),
Io(std::io::Error),
#[cfg(feature = "import")]
#[cfg_attr(docsrs, doc(cfg(feature = "import")))]
Image(image_crate::ImageError),
#[cfg(feature = "import")]
#[cfg_attr(docsrs, doc(cfg(feature = "import")))]
MissingBlob,
#[cfg(feature = "import")]
#[cfg_attr(docsrs, doc(cfg(feature = "import")))]
ExternalReferenceInSliceImport,
#[cfg(feature = "import")]
#[cfg_attr(docsrs, doc(cfg(feature = "import")))]
UnsupportedImageEncoding,
#[cfg(feature = "import")]
#[cfg_attr(docsrs, doc(cfg(feature = "import")))]
UnsupportedImageFormat(image_crate::DynamicImage),
#[cfg(feature = "import")]
#[cfg_attr(docsrs, doc(cfg(feature = "import")))]
UnsupportedScheme,
Validation(Vec<(json::Path, json::validation::Error)>),
}
#[derive(Clone, Debug)]
pub struct Gltf {
pub document: Document,
pub blob: Option<Vec<u8>>,
}
#[derive(Clone, Debug)]
pub struct Document(json::Root);
impl Gltf {
pub fn open<P>(path: P) -> Result<Self>
where
P: AsRef<Path>,
{
let file = fs::File::open(path)?;
let reader = io::BufReader::new(file);
let gltf = Self::from_reader(reader)?;
Ok(gltf)
}
pub fn from_reader_without_validation<R>(mut reader: R) -> Result<Self>
where
R: io::Read + io::Seek,
{
let mut magic = [0u8; 4];
reader.read_exact(&mut magic)?;
reader.seek(io::SeekFrom::Current(-4))?;
let (json, blob): (json::Root, Option<Vec<u8>>);
if magic.starts_with(b"glTF") {
let mut glb = binary::Glb::from_reader(reader)?;
json = json::deserialize::from_slice(&glb.json)?;
blob = glb.bin.take().map(|x| x.into_owned());
} else {
json = json::deserialize::from_reader(reader)?;
blob = None;
};
let document = Document::from_json_without_validation(json);
Ok(Gltf { document, blob })
}
pub fn from_reader<R>(reader: R) -> Result<Self>
where
R: io::Read + io::Seek,
{
let gltf = Self::from_reader_without_validation(reader)?;
gltf.document.validate()?;
Ok(gltf)
}
pub fn from_slice_without_validation(slice: &[u8]) -> Result<Self> {
let (json, blob): (json::Root, Option<Vec<u8>>);
if slice.starts_with(b"glTF") {
let mut glb = binary::Glb::from_slice(slice)?;
json = json::deserialize::from_slice(&glb.json)?;
blob = glb.bin.take().map(|x| x.into_owned());
} else {
json = json::deserialize::from_slice(slice)?;
blob = None;
};
let document = Document::from_json_without_validation(json);
Ok(Gltf { document, blob })
}
pub fn from_slice(slice: &[u8]) -> Result<Self> {
let gltf = Self::from_slice_without_validation(slice)?;
gltf.document.validate()?;
Ok(gltf)
}
}
impl ops::Deref for Gltf {
type Target = Document;
fn deref(&self) -> &Self::Target {
&self.document
}
}
impl ops::DerefMut for Gltf {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.document
}
}
impl Document {
pub fn from_json(json: json::Root) -> Result<Self> {
let document = Self::from_json_without_validation(json);
document.validate()?;
Ok(document)
}
pub fn from_json_without_validation(json: json::Root) -> Self {
Document(json)
}
pub fn into_json(self) -> json::Root {
self.0
}
pub(crate) fn validate(&self) -> Result<()> {
use json::validation::Validate;
let mut errors = Vec::new();
self.0
.validate(&self.0, json::Path::new, &mut |path, error| {
errors.push((path(), error))
});
if errors.is_empty() {
Ok(())
} else {
Err(Error::Validation(errors))
}
}
pub fn accessors(&self) -> iter::Accessors {
iter::Accessors {
iter: self.0.accessors.iter().enumerate(),
document: self,
}
}
pub fn animations(&self) -> iter::Animations {
iter::Animations {
iter: self.0.animations.iter().enumerate(),
document: self,
}
}
pub fn buffers(&self) -> iter::Buffers {
iter::Buffers {
iter: self.0.buffers.iter().enumerate(),
document: self,
}
}
pub fn cameras(&self) -> iter::Cameras {
iter::Cameras {
iter: self.0.cameras.iter().enumerate(),
document: self,
}
}
pub fn default_scene(&self) -> Option<Scene> {
self.0
.scene
.as_ref()
.map(|index| self.scenes().nth(index.value()).unwrap())
}
pub fn extensions_used(&self) -> iter::ExtensionsUsed {
iter::ExtensionsUsed(self.0.extensions_used.iter())
}
pub fn extensions_required(&self) -> iter::ExtensionsRequired {
iter::ExtensionsRequired(self.0.extensions_required.iter())
}
pub fn images(&self) -> iter::Images {
iter::Images {
iter: self.0.images.iter().enumerate(),
document: self,
}
}
#[cfg(feature = "extensions")]
#[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
pub fn extensions(&self) -> Option<&Map<String, Value>> {
let root = self.0.extensions.as_ref()?;
Some(&root.others)
}
#[cfg(feature = "extensions")]
#[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
pub fn extension_value(&self, ext_name: &str) -> Option<&Value> {
let root = self.0.extensions.as_ref()?;
root.others.get(ext_name)
}
#[cfg(feature = "KHR_lights_punctual")]
#[cfg_attr(docsrs, doc(cfg(feature = "KHR_lights_punctual")))]
pub fn lights(&self) -> Option<iter::Lights> {
let iter = self
.0
.extensions
.as_ref()?
.khr_lights_punctual
.as_ref()?
.lights
.iter()
.enumerate();
Some(iter::Lights {
iter,
document: self,
})
}
#[cfg(feature = "KHR_materials_variants")]
#[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_variants")))]
pub fn variants(&self) -> Option<iter::Variants> {
let iter = self
.0
.extensions
.as_ref()?
.khr_materials_variants
.as_ref()?
.variants
.iter()
.enumerate();
Some(iter::Variants {
iter,
document: self,
})
}
pub fn materials(&self) -> iter::Materials {
iter::Materials {
iter: self.0.materials.iter().enumerate(),
document: self,
}
}
pub fn meshes(&self) -> iter::Meshes {
iter::Meshes {
iter: self.0.meshes.iter().enumerate(),
document: self,
}
}
pub fn nodes(&self) -> iter::Nodes {
iter::Nodes {
iter: self.0.nodes.iter().enumerate(),
document: self,
}
}
pub fn samplers(&self) -> iter::Samplers {
iter::Samplers {
iter: self.0.samplers.iter().enumerate(),
document: self,
}
}
pub fn scenes(&self) -> iter::Scenes {
iter::Scenes {
iter: self.0.scenes.iter().enumerate(),
document: self,
}
}
pub fn skins(&self) -> iter::Skins {
iter::Skins {
iter: self.0.skins.iter().enumerate(),
document: self,
}
}
pub fn textures(&self) -> iter::Textures {
iter::Textures {
iter: self.0.textures.iter().enumerate(),
document: self,
}
}
pub fn views(&self) -> iter::Views {
iter::Views {
iter: self.0.buffer_views.iter().enumerate(),
document: self,
}
}
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
#[cfg(feature = "import")]
Error::Base64(ref e) => e.fmt(f),
Error::Binary(ref e) => e.fmt(f),
#[cfg(feature = "import")]
Error::BufferLength {
buffer,
expected,
actual,
} => {
write!(
f,
"buffer {}: expected {} bytes but received {} bytes",
buffer, expected, actual
)
}
Error::Deserialize(ref e) => e.fmt(f),
Error::Io(ref e) => e.fmt(f),
#[cfg(feature = "import")]
Error::Image(ref e) => e.fmt(f),
#[cfg(feature = "import")]
Error::MissingBlob => write!(f, "missing binary portion of binary glTF"),
#[cfg(feature = "import")]
Error::ExternalReferenceInSliceImport => {
write!(f, "external reference in slice only import")
}
#[cfg(feature = "import")]
Error::UnsupportedImageEncoding => write!(f, "unsupported image encoding"),
#[cfg(feature = "import")]
Error::UnsupportedImageFormat(image) => {
write!(f, "unsupported image format: {:?}", image.color())
}
#[cfg(feature = "import")]
Error::UnsupportedScheme => write!(f, "unsupported URI scheme"),
Error::Validation(ref xs) => {
write!(f, "invalid glTF:")?;
for (ref path, ref error) in xs {
write!(f, " {}: {};", path, error)?;
}
Ok(())
}
}
}
}
impl std::error::Error for Error {}
impl From<binary::Error> for Error {
fn from(err: binary::Error) -> Self {
Error::Binary(err)
}
}
impl From<std::io::Error> for Error {
fn from(err: std::io::Error) -> Self {
Error::Io(err)
}
}
#[cfg(feature = "import")]
impl From<image_crate::ImageError> for Error {
fn from(err: image_crate::ImageError) -> Self {
Error::Image(err)
}
}
impl From<json::Error> for Error {
fn from(err: json::Error) -> Self {
Error::Deserialize(err)
}
}
impl From<Vec<(json::Path, json::validation::Error)>> for Error {
fn from(errs: Vec<(json::Path, json::validation::Error)>) -> Self {
Error::Validation(errs)
}
}
impl Normalize<i8> for i8 {
fn normalize(self) -> i8 {
self
}
}
impl Normalize<u8> for i8 {
fn normalize(self) -> u8 {
self.max(0) as u8 * 2
}
}
impl Normalize<i16> for i8 {
fn normalize(self) -> i16 {
self as i16 * 0x100
}
}
impl Normalize<u16> for i8 {
fn normalize(self) -> u16 {
self.max(0) as u16 * 0x200
}
}
impl Normalize<f32> for i8 {
fn normalize(self) -> f32 {
(self as f32 * 127.0_f32.recip()).max(-1.0)
}
}
impl Normalize<i8> for u8 {
fn normalize(self) -> i8 {
(self / 2) as i8
}
}
impl Normalize<u8> for u8 {
fn normalize(self) -> u8 {
self
}
}
impl Normalize<i16> for u8 {
fn normalize(self) -> i16 {
self as i16 * 0x80
}
}
impl Normalize<u16> for u8 {
fn normalize(self) -> u16 {
self as u16 * 0x100
}
}
impl Normalize<f32> for u8 {
fn normalize(self) -> f32 {
self as f32 * 255.0_f32.recip()
}
}
impl Normalize<i8> for i16 {
fn normalize(self) -> i8 {
(self / 0x100) as i8
}
}
impl Normalize<u8> for i16 {
fn normalize(self) -> u8 {
(self.max(0) / 0x80) as u8
}
}
impl Normalize<i16> for i16 {
fn normalize(self) -> i16 {
self
}
}
impl Normalize<u16> for i16 {
fn normalize(self) -> u16 {
self.max(0) as u16 * 2
}
}
impl Normalize<f32> for i16 {
fn normalize(self) -> f32 {
(self as f32 * 32767.0_f32.recip()).max(-1.0)
}
}
impl Normalize<i8> for u16 {
fn normalize(self) -> i8 {
(self / 0x200) as i8
}
}
impl Normalize<u8> for u16 {
fn normalize(self) -> u8 {
(self / 0x100) as u8
}
}
impl Normalize<i16> for u16 {
fn normalize(self) -> i16 {
(self / 2) as i16
}
}
impl Normalize<u16> for u16 {
fn normalize(self) -> u16 {
self
}
}
impl Normalize<f32> for u16 {
fn normalize(self) -> f32 {
self as f32 * 65535.0_f32.recip()
}
}
impl Normalize<i8> for f32 {
fn normalize(self) -> i8 {
(self * 127.0) as i8
}
}
impl Normalize<u8> for f32 {
fn normalize(self) -> u8 {
(self.max(0.0) * 255.0) as u8
}
}
impl Normalize<i16> for f32 {
fn normalize(self) -> i16 {
(self * 32767.0) as i16
}
}
impl Normalize<u16> for f32 {
fn normalize(self) -> u16 {
(self.max(0.0) * 65535.0) as u16
}
}
impl Normalize<f32> for f32 {
fn normalize(self) -> f32 {
self
}
}
impl<U, T> Normalize<[T; 2]> for [U; 2]
where
U: Normalize<T> + Copy,
{
fn normalize(self) -> [T; 2] {
[self[0].normalize(), self[1].normalize()]
}
}
impl<U, T> Normalize<[T; 3]> for [U; 3]
where
U: Normalize<T> + Copy,
{
fn normalize(self) -> [T; 3] {
[
self[0].normalize(),
self[1].normalize(),
self[2].normalize(),
]
}
}
impl<U, T> Normalize<[T; 4]> for [U; 4]
where
U: Normalize<T> + Copy,
{
fn normalize(self) -> [T; 4] {
[
self[0].normalize(),
self[1].normalize(),
self[2].normalize(),
self[3].normalize(),
]
}
}