extern crate gl;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
use std::fs::File;
use std::io::Read;
use std::path::Path;
use serde_json::from_str;
pub use serde_json::value::{Map, Value};
pub type Id = String;
pub trait Find<T> {
fn find(&self, id: &str) -> Option<&T>;
}
#[derive(Debug)]
pub enum Error {
Io(std::io::Error),
Parse(serde_json::error::Error),
}
#[derive(Debug, Deserialize, Serialize)]
pub struct Gltf {
#[serde(default)]
pub accessors: Map<Id, Accessor>,
#[serde(default)]
pub asset: Asset,
#[serde(default)]
pub buffers: Map<Id, Buffer>,
#[serde(default)]
#[serde(rename = "bufferViews")]
pub buffer_views: Map<Id, BufferView>,
#[serde(default)]
pub materials: Map<Id, Material>,
#[serde(default)]
pub meshes: Map<Id, Mesh>,
#[serde(default)]
pub programs: Map<Id, Program>,
#[serde(default)]
pub shaders: Map<Id, Shader>,
#[serde(default)]
pub techniques: Map<Id, Technique>,
}
#[derive(Debug, Default, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct Accessor {
#[serde(rename = "bufferView")]
pub buffer_view: Id,
#[serde(rename = "byteOffset")]
pub byte_offset: u32,
#[serde(rename = "byteStride")]
#[serde(default)]
pub byte_stride: u32,
#[serde(rename = "componentType")]
pub component_type: u32,
pub count: u32,
#[serde(rename = "type")]
pub component_width: String,
pub extensions: Option<Map<String, Value>>,
pub extras: Option<Map<String, Value>>,
pub max: Option<Vec<f32>>,
pub min: Option<Vec<f32>>,
}
#[derive(Debug, Default, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct Asset {
pub copyright: Option<String>,
pub extensions: Option<Map<String, Value>>,
pub extras: Option<Map<String, Value>>,
pub generator: Option<String>,
#[serde(default)]
#[serde(rename = "premultipliedAlpha")]
pub pre_multiplied_alpha: bool,
pub profile: Option<AssetProfile>,
pub version: String,
}
#[derive(Debug, Default, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct AssetProfile {
#[serde(default = "asset_profile_api_default")]
pub api: String,
pub extensions: Option<Map<String, Value>>,
pub extras: Option<Map<String, Value>>,
#[serde(default = "asset_profile_version_default")]
pub version: String,
}
fn asset_profile_api_default() -> String {
"WebGL".to_string()
}
fn asset_profile_version_default() -> String {
"1.0.3".to_string()
}
#[derive(Debug, Default, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct Buffer {
#[serde(default)]
#[serde(rename = "byteLength")]
pub byte_length: u32,
pub extensions: Option<Map<String, Value>>,
pub extras: Option<Map<String, Value>>,
pub name: Option<String>,
#[serde(default = "buffer_response_type_default")]
#[serde(rename = "type")]
pub response_type: String,
pub uri: String,
}
fn buffer_response_type_default() -> String {
"arraybuffer".to_string()
}
#[derive(Debug, Default, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct BufferView {
pub buffer: Id,
#[serde(default)]
#[serde(rename = "byteLength")]
pub byte_length: u32,
#[serde(rename = "byteOffset")]
pub byte_offset: u32,
pub extensions: Option<Map<String, Value>>,
pub extras: Option<Map<String, Value>>,
pub name: Option<String>,
pub target: Option<u32>,
}
#[derive(Debug, Default, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct Material {
pub extensions: Option<Map<String, Value>>,
pub extras: Option<Map<String, Value>>,
pub name: Option<String>,
pub technique: Option<Id>,
#[serde(default)]
pub values: Map<String, Value>,
}
#[derive(Debug, Default, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct Mesh {
pub extensions: Option<Map<String, Value>>,
pub extras: Option<Map<String, Value>>,
pub name: Option<String>,
#[serde(default)]
pub primitives: Vec<MeshPrimitive>,
}
#[derive(Debug, Default, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct MeshPrimitive {
#[serde(default)]
pub attributes: Map<String, Id>,
pub extensions: Option<Map<String, Value>>,
pub extras: Option<Map<String, Value>>,
pub indices: Option<Id>,
pub material: Id,
#[serde(default = "mesh_primitive_mode_default")]
pub mode: u32,
}
fn mesh_primitive_mode_default() -> u32 {
gl::TRIANGLES
}
#[derive(Debug, Default, Deserialize, Serialize)]
pub struct Node {
pub extensions: Option<Map<String, Value>>,
pub extras: Option<Map<String, Value>>,
pub meshes: Option<Vec<Id>>,
pub name: Option<String>,
}
#[derive(Debug, Default, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct Program {
#[serde(default)]
pub attributes: Vec<String>,
pub extensions: Option<Map<String, Value>>,
pub extras: Option<Map<String, Value>>,
#[serde(rename = "fragmentShader")]
pub fragment_shader: String,
pub name: Option<String>,
#[serde(rename = "vertexShader")]
pub vertex_shader: String,
}
#[derive(Debug, Default, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct Shader {
pub extensions: Option<Map<String, Value>>,
pub extras: Option<Map<String, Value>>,
pub name: Option<String>,
#[serde(rename = "type")]
pub type_id: u32,
pub uri: String,
}
#[derive(Debug, Default, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct Technique {
#[serde(default)]
pub attributes: Map<String, String>,
pub extensions: Option<Map<String, Value>>,
pub extras: Option<Map<String, Value>>,
pub name: Option<String>,
#[serde(default)]
pub parameters: Map<String, TechniqueParameter>,
pub program: Id,
#[serde(default)]
pub states: TechniqueStates,
#[serde(default)]
pub uniforms: Map<String, String>,
}
#[derive(Debug, Default, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct TechniqueParameter {
pub count: Option<u32>,
pub extensions: Option<Map<String, Value>>,
pub extras: Option<Map<String, Value>>,
pub node: Option<Id>,
pub semantic: Option<String>,
#[serde(rename = "type")]
pub type_id: u32,
pub value: Option<Value>,
}
#[derive(Debug, Default, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct TechniqueStateFunctions {
#[serde(default)]
#[serde(rename = "blendColor")]
pub blend_color: [f64; 4],
#[serde(default = "technique_state_functions_blend_equation_default")]
#[serde(rename = "blendEquationSeparate")]
pub blend_equation: [u32; 2],
#[serde(default = "technique_state_functions_blend_function_default")]
#[serde(rename = "blendFuncSeparate")]
pub blend_function: [u32; 4],
#[serde(default = "technique_state_functions_color_mask_default")]
#[serde(rename = "colorMask")]
pub color_mask: [bool; 4],
#[serde(default = "technique_state_functions_cull_face_default")]
#[serde(rename = "cullFace")]
pub cull_face: [u32; 1],
#[serde(default = "technique_state_functions_depth_func_default")]
#[serde(rename = "depthFunc")]
pub depth_function: [u32; 1],
#[serde(default = "technique_state_functions_depth_mask_default")]
#[serde(rename = "depthMask")]
pub depth_mask: [bool; 1],
#[serde(default = "technique_state_functions_depth_range_default")]
#[serde(rename = "depthRange")]
pub depth_range: [f64; 2],
pub extensions: Option<Map<String, Value>>,
pub extras: Option<Map<String, Value>>,
#[serde(default = "technique_state_functions_front_face_default")]
#[serde(rename = "frontFace")]
pub front_face: [u32; 1],
#[serde(default = "technique_state_functions_line_width_default")]
#[serde(rename = "lineWidth")]
pub line_width: [f32; 1],
#[serde(default)]
#[serde(rename = "polygonOffset")]
pub polygon_offset: [f32; 2],
#[serde(default)]
pub scissor: [i32; 4],
}
fn technique_state_functions_blend_equation_default() -> [u32; 2] {
[gl::FUNC_ADD, gl::FUNC_ADD]
}
fn technique_state_functions_blend_function_default() -> [u32; 4] {
[gl::ONE, gl::ZERO, gl::ONE, gl::ZERO]
}
fn technique_state_functions_color_mask_default() -> [bool; 4] {
[true, true, true, true]
}
fn technique_state_functions_cull_face_default() -> [u32; 1] {
[gl::BACK]
}
fn technique_state_functions_depth_func_default() -> [u32; 1] {
[gl::LESS]
}
fn technique_state_functions_depth_mask_default() -> [bool; 1] {
[true]
}
fn technique_state_functions_depth_range_default() -> [f64; 2] {
[0.0, 1.0]
}
fn technique_state_functions_front_face_default() -> [u32; 1] {
[gl::CCW]
}
fn technique_state_functions_line_width_default() -> [f32; 1] {
[1.0]
}
#[derive(Debug, Default, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct TechniqueStates {
#[serde(default)]
pub enable: Vec<u32>,
pub extensions: Option<Map<String, Value>>,
pub extras: Option<Map<String, Value>>,
pub functions: Option<TechniqueStateFunctions>,
}
impl Gltf {
pub fn new<P: AsRef<Path>>(path: P) -> Result<Self, Error> {
let mut file = try!(File::open(path));
let mut json = String::new();
try!(file.read_to_string(&mut json));
from_str(&json)
.map_err(|cause| Error::Parse(cause))
}
pub fn find<T>(&self, id: &str) -> Option<&T>
where Self: Find<T>
{
(self as &Find<T>).find(id)
}
}
macro_rules! impl_find {
($ident:ident, $ty:ty) => (
impl Find<$ty> for Gltf {
fn find(&self, id: &str) -> Option<&$ty> {
self.$ident
.iter()
.find(|&(entry_id, _)| entry_id == id)
.map(|(_, entry)| entry)
}
}
)
}
impl_find!(accessors, Accessor);
impl_find!(buffers, Buffer);
impl_find!(buffer_views, BufferView);
impl_find!(materials, Material);
impl_find!(meshes, Mesh);
impl_find!(programs, Program);
impl_find!(shaders, Shader);
impl_find!(techniques, Technique);
impl From<std::io::Error> for Error {
fn from(err: std::io::Error) -> Error {
Error::Io(err)
}
}
impl From<serde_json::error::Error> for Error {
fn from(err: serde_json::error::Error) -> Error {
Error::Parse(err)
}
}