use serde::{Serialize, Deserialize};
use std::collections::HashMap;
#[derive(Debug)]
pub enum GltfError {
Serde(serde_json::Error),
Io(std::io::Error),
Unloaded(String),
Index(usize, usize)
}
impl From<std::io::Error> for GltfError {
fn from(err: std::io::Error) -> Self { Self::Io(err) }
}
impl From<serde_json::Error> for GltfError {
fn from(err: serde_json::Error) -> Self { Self::Serde(err) }
}
impl std::fmt::Display for GltfError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
Self::Serde(err) => { write!(f, "Serialisation Error: {}", err) },
Self::Io(err) => { write!(f, "I/O Error: {}", err) },
Self::Unloaded(err) => { write!(f, "No {} loaded in this glTF file.", err) },
Self::Index(index, len) => { write!(f, "Index out of bounds: tried to access element {}, only {} elements.", index, len) }
}
}
}
#[derive(Serialize, Deserialize)]
pub struct GltfObj {
pub asset: Asset,
pub buffers: Option<Vec<Buffer>>,
#[serde(rename="bufferViews")]
pub buffer_views: Option<Vec<BufferView>>,
pub accessors: Option<Vec<Accessor>>,
pub animations: Option<Vec<Animation>>,
pub materials: Option<Vec<Material>>,
pub meshes: Option<Vec<Mesh>>,
pub nodes: Option<Vec<Node>>,
pub scenes: Option<Vec<Scene>>,
pub images: Option<Vec<Image>>,
pub samplers: Option<Vec<Sampler>>,
pub skins: Option<Vec<Skin>>,
pub textures: Option<Vec<Texture>>,
pub cameras: Option<Vec<Camera>>,
}
impl GltfObj {
pub fn from_file(file: &str) -> Result<Self, GltfError> {
let data = std::fs::read_to_string(file)?;
Self::from_string(&data)
}
pub fn from_string(data: &str) -> Result<Self, GltfError> {
let g: GltfObj = serde_json::from_str(data)?;
Ok(g)
}
pub fn get_animation(&self, index: u32) -> Result<Animation, GltfError> {
if let Some(data) = &self.animations {
if let Some(value) = data.get(index as usize) {
Ok(value.clone())
} else { Err(GltfError::Index(index as usize, data.len())) }
} else { Err(GltfError::Unloaded("Animations".to_string())) }
}
pub fn get_accessor(&self, index: u32) -> Result<Accessor, GltfError> {
if let Some(data) = &self.accessors {
if let Some(value) = data.get(index as usize) {
Ok(value.clone())
} else { Err(GltfError::Index(index as usize, data.len())) }
} else { Err(GltfError::Unloaded("Accessors".to_string())) }
}
pub fn get_buffer(&self, index: u32) -> Result<Buffer, GltfError> {
if let Some(data) = &self.buffers {
if let Some(value) = data.get(index as usize) {
Ok(value.clone())
} else { Err(GltfError::Index(index as usize, data.len())) }
} else { Err(GltfError::Unloaded("Buffers".to_string())) }
}
pub fn get_buffer_view(&self, index: u32) -> Result<BufferView, GltfError> {
if let Some(data) = &self.buffer_views {
if let Some(value) = data.get(index as usize) {
Ok(value.clone())
} else { Err(GltfError::Index(index as usize, data.len())) }
} else { Err(GltfError::Unloaded("Buffer Views".to_string())) }
}
pub fn get_material(&self, index: u32) -> Result<Material, GltfError> {
if let Some(data) = &self.materials {
if let Some(value) = data.get(index as usize) {
Ok(value.clone())
} else { Err(GltfError::Index(index as usize, data.len())) }
} else { Err(GltfError::Unloaded("Materials".to_string())) }
}
pub fn get_mesh(&self, index: u32) -> Result<Mesh, GltfError> {
if let Some(data) = &self.meshes {
if let Some(value) = data.get(index as usize) {
Ok(value.clone())
} else { Err(GltfError::Index(index as usize, data.len())) }
} else { Err(GltfError::Unloaded("Meshes".to_string())) }
}
pub fn get_node(&self, index: u32) -> Result<Node, GltfError> {
if let Some(data) = &self.nodes {
if let Some(value) = data.get(index as usize) {
Ok(value.clone())
} else { Err(GltfError::Index(index as usize, data.len())) }
} else { Err(GltfError::Unloaded("Nodes".to_string())) }
}
pub fn get_scene(&self, index: u32) -> Result<Scene, GltfError> {
if let Some(data) = &self.scenes {
if let Some(value) = data.get(index as usize) {
Ok(value.clone())
} else { Err(GltfError::Index(index as usize, data.len())) }
} else { Err(GltfError::Unloaded("Scenes".to_string())) }
}
pub fn get_image(&self, index: u32) -> Result<Image, GltfError> {
if let Some(data) = &self.images {
if let Some(value) = data.get(index as usize) {
Ok(value.clone())
} else { Err(GltfError::Index(index as usize, data.len())) }
} else { Err(GltfError::Unloaded("Images".to_string())) }
}
pub fn get_sampler(&self, index: u32) -> Result<Sampler, GltfError> {
if let Some(data) = &self.samplers {
if let Some(value) = data.get(index as usize) {
Ok(value.clone())
} else { Err(GltfError::Index(index as usize, data.len())) }
} else { Err(GltfError::Unloaded("Samplers".to_string())) }
}
pub fn get_skin(&self, index: u32) -> Result<Skin, GltfError> {
if let Some(data) = &self.skins {
if let Some(value) = data.get(index as usize) {
Ok(value.clone())
} else { Err(GltfError::Index(index as usize, data.len())) }
} else { Err(GltfError::Unloaded("Skins".to_string())) }
}
pub fn get_texture(&self, index: u32) -> Result<Texture, GltfError> {
if let Some(data) = &self.textures {
if let Some(value) = data.get(index as usize) {
Ok(value.clone())
} else { Err(GltfError::Index(index as usize, data.len())) }
} else { Err(GltfError::Unloaded("Textures".to_string())) }
}
pub fn get_camera(&self, index: u32) -> Result<Camera, GltfError> {
if let Some(data) = &self.cameras {
if let Some(value) = data.get(index as usize) {
Ok(value.clone())
} else { Err(GltfError::Index(index as usize, data.len())) }
} else { Err(GltfError::Unloaded("Cameras".to_string())) }
}
}
#[derive(Serialize, Deserialize, Clone)]
pub struct Asset {
pub version: String,
pub generator: Option<String>,
pub copyright: Option<String>,
}
#[derive(Serialize, Deserialize, Clone)]
pub struct Accessor {
#[serde(rename="bufferView")]
pub buffer_view: u32,
#[serde(rename="byteOffset")]
#[serde(default="Accessor::default_byte_offset")]
pub byte_offset: u32,
#[serde(rename="componentType")]
pub component_type: u32,
pub count: u32,
#[serde(rename="type")]
pub data_type: String,
}
impl Accessor {
fn default_byte_offset() -> u32 { 0 }
}
#[derive(Serialize, Deserialize, Clone)]
pub struct AnimationSampler {
pub input: u32,
#[serde(default="AnimationSampler::default_interpolation")]
pub interpolation: String,
pub output: u32,
}
impl AnimationSampler {
fn default_interpolation() -> String { "LINEAR".to_string() }
}
#[derive(Serialize, Deserialize, Clone)]
pub struct AnimationChannelTarget {
node: Option<u32>,
path: String,
}
#[derive(Serialize, Deserialize, Clone)]
pub struct AnimationChannel {
sampler: u32,
target: u32,
}
impl AnimationChannel {}
#[derive(Serialize, Deserialize, Clone)]
pub struct Animation {
channels: Vec<AnimationChannel>,
samplers: Vec<AnimationSampler>,
}
impl Animation {}
#[derive(Serialize, Deserialize, Clone)]
pub struct Buffer {
pub uri: Option<String>,
#[serde(rename="byteLength")]
pub byte_length: u32,
pub name: Option<String>
}
#[derive(Serialize, Deserialize, Clone)]
pub struct BufferView {
pub buffer: u32,
#[serde(rename="byteOffset")]
#[serde(default="BufferView::default_byte_offset")]
pub byte_offset: u32,
#[serde(rename="byteLength")]
pub byte_length: u32,
#[serde(rename="byteStride")]
pub byte_stride: Option<u32>,
pub target: Option<u32>,
pub name: Option<String>
}
impl BufferView {
fn default_byte_offset() -> u32 { 0 }
}
#[derive(Serialize, Deserialize, Clone)]
pub struct CameraOrthographic {
pub xmag: f64,
pub ymag: f64,
pub zfar: f64,
pub znear: f64,
}
#[derive(Serialize, Deserialize, Clone)]
pub struct CameraPerspective {
#[serde(rename="aspectRatio")]
pub aspect_ratio: f64,
pub yfov: f64,
pub zfar: f64,
pub znear: f64,
}
#[derive(Serialize, Deserialize, Clone)]
pub struct Camera {
pub orthographic: Option<CameraOrthographic>,
pub perspective: Option<CameraPerspective>,
#[serde(rename="type")]
pub camera_type: String,
pub name: Option<String>,
}
#[derive(Serialize, Deserialize, Clone)]
pub struct Image {
pub uri: Option<String>,
#[serde(rename="mimeType")]
pub mime_type: Option<String>,
#[serde(rename="bufferView")]
pub buffer_view: Option<u32>,
pub name: Option<String>,
}
#[derive(Serialize, Deserialize, Clone)]
pub struct TextureInfo {
pub index: u32,
#[serde(rename="texCoord")]
#[serde(default="TextureInfo::default_tex_coord")]
pub tex_coord: u32,
}
impl TextureInfo {
fn default_tex_coord() -> u32 { 0 }
}
#[derive(Serialize, Deserialize, Clone)]
pub struct Pbr {
#[serde(rename="baseColorFactor")]
#[serde(default="Pbr::default_base_color_factor")]
pub base_color_factor: [f64; 4],
#[serde(rename="baseColorTexture")]
pub base_color_texture: Option<TextureInfo>,
#[serde(rename="metallicFactor")]
#[serde(default="Pbr::default_metallic_factor")]
pub metallic_factor: f64,
#[serde(rename="roughnessFactor")]
#[serde(default="Pbr::default_roughness_factor")]
pub roughness_factor: f64,
#[serde(rename="metallicRoughnessTexture")]
pub metallic_roughness_texture: Option<TextureInfo>,
}
impl Pbr {
fn default_base_color_factor() -> [f64; 4] { [1.0, 1.0, 1.0, 1.0] }
fn default_metallic_factor() -> f64 { 1.0 }
fn default_roughness_factor() -> f64 { 1.0 }
}
#[derive(Serialize, Deserialize, Clone)]
pub struct NormalTexture {
pub index: u32,
#[serde(rename="texCoord")]
#[serde(default="NormalTexture::default_tex_coord")]
pub tex_coord: u32,
#[serde(default="NormalTexture::default_scale")]
pub scale: f64
}
impl NormalTexture {
fn default_tex_coord() -> u32 { 0 }
fn default_scale() -> f64 { 1.0 }
}
#[derive(Serialize, Deserialize, Clone)]
pub struct OcclusionTexture {
pub index: u32,
#[serde(rename="texCoord")]
#[serde(default="OcclusionTexture::default_tex_coord")]
pub tex_coord: u32,
#[serde(default="OcclusionTexture::default_strength")]
pub strength: f64,
}
impl OcclusionTexture {
fn default_tex_coord() -> u32 { 0 }
fn default_strength() -> f64 { 1.0 }
}
#[derive(Serialize, Deserialize, Clone)]
pub struct Material {
pub name: Option<String>,
#[serde(rename="pbrMetallicRoughness")]
pub pbr: Option<Pbr>,
#[serde(rename="normalTexture")]
pub normal_texture: Option<NormalTexture>,
#[serde(rename="occlusionTexture")]
pub occlusion_texture: Option<OcclusionTexture>,
#[serde(rename="emissiveTexture")]
pub emissive_texture: Option<TextureInfo>,
#[serde(rename="emissiveFactor")]
#[serde(default="Material::default_emissive_factor")]
pub emissive_factor: [f32; 3],
#[serde(rename="alphaMode")]
#[serde(default="Material::default_alpha_mode")]
pub alpha_mode: String,
#[serde(rename="alphaCutoff")]
#[serde(default="Material::default_alpha_cutoff")]
pub alpha_cutoff: f64,
#[serde(rename="doubleSided")]
#[serde(default="Material::default_double_sided")]
pub double_sided: bool,
}
impl Material {
fn default_emissive_factor() -> [f32; 3] { [0.0, 0.0, 0.0] }
fn default_alpha_mode() -> String { "OPAQUE".to_string() }
fn default_alpha_cutoff() -> f64 { 0.5 }
fn default_double_sided() -> bool { false }
}
#[derive(Serialize, Deserialize, Clone)]
pub struct Primitive {
pub attributes: HashMap<String, u32>,
pub indices: Option<u32>,
pub material: Option<u32>,
#[serde(default = "Primitive::default_mode")]
pub mode: u32,
}
impl Primitive {
fn default_mode() -> u32 { 4 }
}
#[derive(Serialize, Deserialize, Clone)]
pub struct Mesh {
pub primitives: Vec<Primitive>,
pub name: Option<String>
}
#[derive(Serialize, Deserialize, Clone)]
pub struct Node {
pub camera: Option<u32>,
pub children: Option<Vec<u32>>,
#[serde(default = "Node::default_matrix")]
pub matrix: [f32; 16],
pub mesh: Option<u32>,
#[serde(default = "Node::default_rotation")]
pub rotation: [f32; 4],
#[serde(default = "Node::default_scale")]
pub scale: [f32; 3],
#[serde(default = "Node::default_translation")]
pub translation: [f32; 3],
pub name: Option<String>
}
impl Node {
fn default_matrix() -> [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]
}
fn default_rotation() -> [f32; 4] { [0.0, 0.0, 0.0, 1.0] }
fn default_scale() -> [f32; 3] { [1.0, 1.0, 1.0] }
fn default_translation() -> [f32; 3] { [0.0, 0.0, 0.0] }
}
#[derive(Serialize, Deserialize, Clone)]
pub struct Sampler {
#[serde(rename="magFilter")]
pub mag_filter: Option<u32>,
#[serde(rename="minFilter")]
pub min_filter: Option<u32>,
#[serde(rename="wrapS")]
#[serde(default="Sampler::default_wrap")]
pub wrap_s: u32,
#[serde(rename="wrapT")]
#[serde(default="Sampler::default_wrap")]
pub wrap_t: u32,
}
impl Sampler {
fn default_wrap() -> u32 { 10497 }
}
#[derive(Serialize, Deserialize, Clone)]
pub struct Scene {
pub nodes: Option<Vec<u32>>,
pub name: Option<String>,
}
#[derive(Serialize, Deserialize, Clone)]
pub struct Skin {
#[serde(rename="inverseBindMatrices")]
pub inverse_bind_matrices: Option<u32>,
pub skeleton: Option<u32>,
pub joints: Vec<u32>,
}
#[derive(Serialize, Deserialize, Clone)]
pub struct Texture {
pub sampler: Option<u32>,
pub source: Option<u32>,
pub name: Option<String>,
}