use cgmath;
use cgmath::prelude::*;
use json;
use std::{mem, slice};
use {Camera, Gltf, Mesh, Skin};
type Matrix3 = cgmath::Matrix3<f32>;
type Matrix4 = cgmath::Matrix4<f32>;
type Quaternion = cgmath::Quaternion<f32>;
type Vector3 = cgmath::Vector3<f32>;
const IDENTITY: [f32; 16] = {
[1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0]
};
#[derive(Clone, Debug)]
pub enum Transform {
Matrix {
matrix: [[f32; 4]; 4],
},
Decomposed {
translation: [f32; 3],
rotation: [f32; 4],
scale: [f32; 3],
},
}
impl Transform {
pub fn matrix(self) -> [[f32; 4]; 4] {
match self {
Transform::Matrix { matrix } => matrix,
Transform::Decomposed { translation, rotation, scale } => {
let t = Matrix4::from_translation(translation.into());
let r = Matrix4::from(Quaternion::new(rotation[3], rotation[0], rotation[1], rotation[2]));
let s = Matrix4::from_nonuniform_scale(scale[0], scale[1], scale[2]);
(t * r * s).into()
},
}
}
pub fn decomposed(self) -> ([f32; 3], [f32; 4], [f32; 3]) {
match self {
Transform::Matrix { matrix: mut m } => {
let translation = [
mem::replace(&mut m[3][0], 0.0),
mem::replace(&mut m[3][1], 0.0),
mem::replace(&mut m[3][2], 0.0),
];
let sx = Vector3::new(m[0][0], m[0][1], m[0][2]).magnitude();
m[0][0] /= sx;
m[0][1] /= sx;
m[0][2] /= sx;
let sy = Vector3::new(m[1][0], m[1][1], m[1][2]).magnitude();
m[1][0] /= sy;
m[1][1] /= sy;
m[1][2] /= sy;
let sz = Vector3::new(m[2][0], m[2][1], m[2][2]).magnitude();
m[2][0] /= sz;
m[2][1] /= sz;
m[2][2] /= sz;
let scale = [sx, sy, sz];
let r = Quaternion::from(
Matrix3::new(
m[0][0], m[0][1], m[0][2],
m[1][0], m[1][1], m[1][2],
m[2][0], m[2][1], m[2][2],
),
);
let rotation = [r.v.x, r.v.y, r.v.z, r.s];
(translation, rotation, scale)
},
Transform::Decomposed { translation, rotation, scale } => {
(translation, rotation, scale)
},
}
}
}
#[derive(Clone, Debug)]
pub struct Node<'a> {
gltf: &'a Gltf,
index: usize,
json: &'a json::scene::Node,
}
#[derive(Clone, Debug)]
pub struct Scene<'a> {
#[allow(dead_code)]
gltf: &'a Gltf,
index: usize,
json: &'a json::scene::Scene,
}
#[derive(Clone, Debug)]
pub struct Nodes<'a> {
gltf: &'a Gltf,
iter: slice::Iter<'a, json::Index<json::scene::Node>>,
}
#[derive(Clone, Debug)]
pub struct Children<'a> {
gltf: &'a Gltf,
iter: slice::Iter<'a, json::Index<json::scene::Node>>,
}
impl<'a> Node<'a> {
pub(crate) fn new(
gltf: &'a Gltf,
index: usize,
json: &'a json::scene::Node,
) -> Self {
Self {
gltf: gltf,
index: index,
json: json,
}
}
pub fn index(&self) -> usize {
self.index
}
#[doc(hidden)]
pub fn as_json(&self) -> &json::scene::Node {
self.json
}
pub fn camera(&self) -> Option<Camera> {
self.json.camera.as_ref().map(|index| {
self.gltf.cameras().nth(index.value()).unwrap()
})
}
pub fn children(&self) -> Children {
Children {
gltf: self.gltf,
iter: self.json.children.as_ref().map_or([].iter(), |x| x.iter()),
}
}
pub fn extras(&self) -> &json::Extras {
&self.json.extras
}
#[deprecated(since = "0.9.1", note = "Use `transform().matrix()` instead")]
pub fn matrix(&self) -> [f32; 16] {
self.json.matrix.unwrap_or(IDENTITY)
}
pub fn mesh(&self) -> Option<Mesh> {
self.json.mesh.as_ref().map(|index| {
self.gltf.meshes().nth(index.value()).unwrap()
})
}
#[cfg(feature = "names")]
pub fn name(&self) -> Option<&str> {
self.json.name.as_ref().map(String::as_str)
}
#[deprecated(since = "0.9.1", note = "Use `transform().decomposed()` instead.")]
pub fn rotation(&self) -> [f32; 4] {
self.json.rotation.0
}
#[deprecated(since = "0.9.1", note = "Use `transform().decomposed()` instead.")]
pub fn scale(&self) -> [f32; 3] {
self.json.scale
}
#[deprecated(since = "0.9.1", note = "Use `transform().decomposed()` instead.")]
pub fn translation(&self) -> [f32; 3] {
self.json.translation
}
pub fn transform(&self) -> Transform {
if let Some(matrix) = self.json.matrix.clone() {
unsafe {
Transform::Matrix {
matrix: mem::transmute(matrix),
}
}
} else {
Transform::Decomposed {
translation: self.json.translation,
rotation: self.json.rotation.0,
scale: self.json.scale,
}
}
}
pub fn skin(&self) -> Option<Skin> {
self.json.skin.as_ref().map(|index| {
self.gltf.skins().nth(index.value()).unwrap()
})
}
pub fn weights(&self) -> Option<&[f32]> {
self.json.weights.as_ref().map(Vec::as_slice)
}
}
impl<'a> Scene<'a> {
pub(crate) fn new(
gltf: &'a Gltf,
index: usize,
json: &'a json::scene::Scene,
) -> Self {
Self {
gltf: gltf,
index: index,
json: json,
}
}
pub fn index(&self) -> usize {
self.index
}
#[doc(hidden)]
pub fn as_json(&self) -> &json::scene::Scene {
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 nodes(&self) -> Nodes<'a> {
Nodes {
gltf: self.gltf,
iter: self.json.nodes.iter(),
}
}
}
impl<'a> ExactSizeIterator for Nodes<'a> {}
impl<'a> Iterator for Nodes<'a> {
type Item = Node<'a>;
fn next(&mut self) -> Option<Self::Item> {
self.iter
.next()
.map(|index| self.gltf.nodes().nth(index.value()).unwrap())
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl<'a> ExactSizeIterator for Children<'a> {}
impl<'a> Iterator for Children<'a> {
type Item = Node<'a>;
fn next(&mut self) -> Option<Self::Item> {
self.iter
.next()
.map(|index| self.gltf.nodes().nth(index.value()).unwrap())
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}