#![allow(clippy::question_mark)]
pub mod extensions;
use nanoserde::{DeJson, SerJson};
use std::fmt::Debug;
pub trait Extensions: DeJson + SerJson {
type RootExtensions: DeJson + SerJson + Default + Debug + Clone;
type TextureExtensions: DeJson + SerJson + Default + Debug + Clone;
type TextureInfoExtensions: DeJson + SerJson + Default + Debug + Clone;
type MaterialExtensions: DeJson + SerJson + Default + Debug + Clone;
type BufferExtensions: DeJson + SerJson + Default + Debug + Clone;
type NodeExtensions: DeJson + SerJson + Default + Debug + Clone;
type NodeExtras: DeJson + SerJson + Default + Debug + Clone;
type BufferViewExtensions: DeJson + SerJson + Default + Debug + Clone;
}
impl Extensions for () {
type RootExtensions = ();
type TextureExtensions = ();
type TextureInfoExtensions = ();
type MaterialExtensions = ();
type BufferExtensions = ();
type NodeExtensions = ();
type NodeExtras = ();
type BufferViewExtensions = ();
}
#[derive(Debug, DeJson, SerJson)]
pub struct Gltf<E: Extensions> {
pub asset: Asset,
#[cfg(feature = "names")]
#[nserde(default, rename = "extensionsUsed")]
pub extensions_used: Vec<String>,
#[cfg(feature = "names")]
#[nserde(default, rename = "extensionsRequired")]
pub extensions_required: Vec<String>,
#[nserde(default)]
pub extensions: E::RootExtensions,
#[nserde(default)]
pub scene: usize,
#[nserde(default)]
pub scenes: Vec<Scene>,
#[nserde(default)]
pub nodes: Vec<Node<E>>,
#[nserde(default)]
pub materials: Vec<Material<E>>,
#[nserde(default)]
pub meshes: Vec<Mesh>,
#[nserde(default)]
pub textures: Vec<Texture<E>>,
#[nserde(default)]
pub images: Vec<Image>,
#[nserde(default)]
pub accessors: Vec<Accessor>,
#[nserde(rename = "bufferViews")]
#[nserde(default)]
pub buffer_views: Vec<BufferView<E>>,
#[nserde(default)]
pub animations: Vec<Animation>,
#[nserde(default)]
pub skins: Vec<Skin>,
#[nserde(default)]
pub samplers: Vec<Sampler>,
#[nserde(default)]
pub buffers: Vec<Buffer<E>>,
#[nserde(default)]
pub cameras: Vec<Camera>,
}
impl<E: Extensions> Gltf<E> {
pub fn from_bytes(bytes: &[u8]) -> Result<(Self, Option<&[u8]>), nanoserde::DeJsonErr> {
if !bytes.starts_with(b"glTF") {
return Ok((Self::from_json_bytes(bytes)?, None));
}
let json_chunk_length = u32::from_le_bytes(bytes[12..16].try_into().unwrap());
let json_chunk_end = 20 + json_chunk_length as usize;
let json_chunk_bytes = &bytes[20..20 + json_chunk_length as usize];
let json = Self::from_json_bytes(json_chunk_bytes)?;
let binary_buffer = if bytes.len() != json_chunk_end {
Some(&bytes[json_chunk_end + 8..])
} else {
None
};
Ok((json, binary_buffer))
}
pub fn write_to_glb<W: std::io::Write>(
&self,
bytes: &[u8],
mut writer: W,
) -> std::io::Result<()> {
writer.write_all(b"glTF")?;
let version = 2_u32;
writer.write_all(&version.to_le_bytes())?;
let string = self.serialize_json();
let header_len = 4 + 4 + 4;
let json_chunk_len = 4 + 4 + string.len() as u32;
let binary_chunk_len = 4 + 4 + bytes.len() as u32;
let total_len = header_len + json_chunk_len + binary_chunk_len;
writer.write_all(&total_len.to_le_bytes())?;
writer.write_all(&(string.len() as u32).to_le_bytes())?;
writer.write_all(b"JSON")?;
writer.write_all(string.as_bytes())?;
writer.write_all(&(bytes.len() as u32).to_le_bytes())?;
writer.write_all(b"BIN\0")?;
writer.write_all(bytes)?;
Ok(())
}
pub fn from_json_bytes(bytes: &[u8]) -> Result<Self, nanoserde::DeJsonErr> {
match std::str::from_utf8(bytes) {
Ok(string) => Self::from_json_string(string),
Err(error) => Err(nanoserde::DeJsonState::default().err_parse(&error.to_string())),
}
}
pub fn from_json_string(string: &str) -> Result<Self, nanoserde::DeJsonErr> {
Self::deserialize_json(string)
}
}
#[derive(Debug, DeJson, SerJson)]
pub struct Skin {
#[nserde(rename = "inverseBindMatrices")]
pub inverse_bind_matrices: Option<usize>,
pub skeleton: Option<usize>,
pub joints: Vec<usize>,
#[cfg(feature = "names")]
pub name: Option<String>,
}
#[derive(Debug, DeJson, SerJson)]
pub struct Animation {
pub channels: Vec<Channel>,
pub samplers: Vec<AnimationSampler>,
#[cfg(feature = "names")]
pub name: Option<String>,
}
#[derive(Debug, DeJson, SerJson)]
pub struct Channel {
pub sampler: usize,
pub target: Target,
}
#[derive(Debug, DeJson, SerJson)]
pub struct Target {
pub node: Option<usize>,
pub path: TargetPath,
}
#[derive(Debug, DeJson, SerJson)]
pub struct AnimationSampler {
pub input: usize,
#[nserde(default)]
pub interpolation: Interpolation,
pub output: usize,
}
#[derive(Debug, DeJson, SerJson)]
pub struct Asset {
#[cfg(feature = "names")]
generator: Option<String>,
version: String,
}
#[derive(Default, Debug, DeJson, SerJson, Clone, Copy)]
pub enum Interpolation {
#[default]
#[nserde(rename = "LINEAR")]
Linear,
#[nserde(rename = "STEP")]
Step,
#[nserde(rename = "CUBICSPLINE")]
CubicSpline,
}
#[derive(Debug, DeJson, SerJson)]
pub enum TargetPath {
#[nserde(rename = "translation")]
Translation,
#[nserde(rename = "rotation")]
Rotation,
#[nserde(rename = "scale")]
Scale,
#[nserde(rename = "weights")]
Weights,
}
#[derive(Debug, DeJson, SerJson)]
pub struct Buffer<E: Extensions> {
pub uri: Option<String>,
#[nserde(rename = "byteLength")]
pub byte_length: usize,
#[cfg(feature = "names")]
pub name: Option<String>,
#[nserde(default)]
pub extensions: E::BufferExtensions,
}
#[derive(Debug, DeJson, SerJson)]
pub struct Node<E: Extensions> {
pub camera: Option<usize>,
#[nserde(default)]
pub children: Vec<usize>,
pub skin: Option<usize>,
pub matrix: Option<[f32; 16]>,
pub mesh: Option<usize>,
#[cfg(feature = "names")]
pub name: Option<String>,
pub rotation: Option<[f32; 4]>,
pub scale: Option<[f32; 3]>,
pub translation: Option<[f32; 3]>,
#[nserde(default)]
pub extensions: E::NodeExtensions,
#[nserde(default)]
pub extras: E::NodeExtras,
}
impl<E: Extensions> Node<E> {
pub fn transform(&self) -> NodeTransform {
match self.matrix {
Some(matrix) => match (self.translation, self.rotation, self.scale) {
(Some(translation), Some(rotation), Some(scale)) => NodeTransform::Set {
translation,
rotation,
scale,
},
_ => NodeTransform::Matrix(matrix),
},
None => {
let translation = self.translation.unwrap_or([0.0; 3]);
let rotation = self.rotation.unwrap_or([0.0, 0.0, 0.0, 1.0]);
let scale = self.scale.unwrap_or([1.0; 3]);
NodeTransform::Set {
translation,
rotation,
scale,
}
}
}
}
}
#[derive(Debug)]
pub enum NodeTransform {
Matrix([f32; 16]),
Set {
translation: [f32; 3],
rotation: [f32; 4],
scale: [f32; 3],
},
}
#[derive(Debug, DeJson, SerJson)]
pub struct Mesh {
#[cfg(feature = "names")]
pub name: Option<String>,
pub primitives: Vec<Primitive>,
pub weights: Option<Vec<f32>>,
}
#[derive(Debug, DeJson, SerJson)]
pub struct Primitive {
pub attributes: Attributes,
pub indices: Option<usize>,
pub material: Option<usize>,
#[nserde(default)]
pub mode: PrimitiveMode,
pub targets: Option<Vec<Attributes>>,
}
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
pub enum PrimitiveMode {
Points,
Lines,
LineLoop,
LineStrip,
#[default]
Triangles,
TriangleStrip,
TriangleFan,
}
impl DeJson for PrimitiveMode {
fn de_json(
state: &mut nanoserde::DeJsonState,
input: &mut core::str::Chars,
) -> Result<Self, nanoserde::DeJsonErr> {
let ty = match &state.tok {
nanoserde::DeJsonTok::U64(ty) => match ty {
0 => Self::Points,
1 => Self::Lines,
2 => Self::LineLoop,
3 => Self::LineStrip,
4 => Self::Triangles,
5 => Self::TriangleStrip,
6 => Self::TriangleFan,
_ => return Err(state.err_range(&ty.to_string())),
},
_ => return Err(state.err_token("U64")),
};
state.next_tok(input)?;
Ok(ty)
}
}
impl SerJson for PrimitiveMode {
fn ser_json(&self, d: usize, s: &mut nanoserde::SerJsonState) {
match self {
Self::Points => 0,
Self::Lines => 1,
Self::LineLoop => 2,
Self::LineStrip => 3,
Self::Triangles => 4,
Self::TriangleStrip => 5,
Self::TriangleFan => 6,
}
.ser_json(d, s)
}
}
#[derive(Debug, DeJson, SerJson)]
pub struct Attributes {
#[nserde(rename = "POSITION")]
pub position: Option<usize>,
#[nserde(rename = "TANGENT")]
pub tangent: Option<usize>,
#[nserde(rename = "NORMAL")]
pub normal: Option<usize>,
#[nserde(rename = "TEXCOORD_0")]
pub texcoord_0: Option<usize>,
#[nserde(rename = "TEXCOORD_1")]
pub texcoord_1: Option<usize>,
#[nserde(rename = "JOINTS_0")]
pub joints_0: Option<usize>,
#[nserde(rename = "WEIGHTS_0")]
pub weights_0: Option<usize>,
}
#[derive(Debug, DeJson, SerJson, Clone)]
pub struct Image {
#[nserde(rename = "bufferView")]
pub buffer_view: Option<usize>,
pub uri: Option<String>,
#[nserde(rename = "mimeType")]
pub mime_type: Option<String>,
#[cfg(feature = "names")]
pub name: Option<String>,
}
#[derive(Debug, DeJson, SerJson)]
pub struct Texture<E: Extensions> {
pub sampler: Option<usize>,
pub source: Option<usize>,
#[cfg(feature = "names")]
pub name: Option<String>,
#[nserde(default)]
pub extensions: E::TextureExtensions,
}
#[derive(Debug, DeJson, SerJson)]
pub struct BufferView<E: Extensions> {
pub buffer: usize,
#[nserde(rename = "byteLength")]
pub byte_length: usize,
#[nserde(rename = "byteOffset")]
#[nserde(default)]
pub byte_offset: usize,
#[nserde(rename = "byteStride")]
pub byte_stride: Option<usize>,
#[nserde(default)]
pub target: u32,
#[cfg(feature = "names")]
pub name: Option<String>,
#[nserde(default)]
pub extensions: E::BufferViewExtensions,
}
#[derive(Debug, DeJson, SerJson)]
pub struct Accessor {
#[nserde(rename = "bufferView")]
pub buffer_view: Option<usize>,
#[nserde(rename = "componentType")]
pub component_type: ComponentType,
pub count: usize,
pub sparse: Option<Sparse>,
pub max: Option<Vec<f32>>,
pub min: Option<Vec<f32>>,
#[nserde(rename = "type")]
pub accessor_type: AccessorType,
#[cfg(feature = "names")]
pub name: Option<String>,
#[nserde(rename = "byteOffset")]
#[nserde(default)]
pub byte_offset: usize,
#[nserde(default)]
pub normalized: bool,
}
impl Accessor {
pub fn byte_length<E: Extensions>(&self, buffer_view: &BufferView<E>) -> usize {
self.count
* buffer_view.byte_stride.unwrap_or_else(|| {
self.component_type.byte_size() * self.accessor_type.num_components()
})
}
}
#[derive(Debug, DeJson, SerJson)]
pub struct Sparse {
pub count: usize,
pub indices: SparseIndices,
pub values: SparseValues,
}
#[derive(Debug, DeJson, SerJson)]
pub struct SparseIndices {
#[nserde(rename = "bufferView")]
pub buffer_view: usize,
#[nserde(rename = "byteOffset")]
#[nserde(default)]
pub byte_offset: usize,
#[nserde(rename = "componentType")]
pub component_type: ComponentType,
}
#[derive(Debug, DeJson, SerJson)]
pub struct SparseValues {
#[nserde(rename = "bufferView")]
pub buffer_view: usize,
#[nserde(rename = "byteOffset")]
#[nserde(default)]
pub byte_offset: usize,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ComponentType {
UnsignedByte,
Byte,
UnsignedShort,
Short,
UnsignedInt,
Float,
}
impl ComponentType {
pub fn byte_size(&self) -> usize {
match self {
Self::UnsignedByte | Self::Byte => 1,
Self::UnsignedShort | Self::Short => 2,
Self::UnsignedInt | Self::Float => 4,
}
}
}
impl DeJson for ComponentType {
fn de_json(
state: &mut nanoserde::DeJsonState,
input: &mut core::str::Chars,
) -> Result<Self, nanoserde::DeJsonErr> {
let ty = match &state.tok {
nanoserde::DeJsonTok::U64(ty) => match ty {
5120 => Self::Byte,
5121 => Self::UnsignedByte,
5122 => Self::Short,
5123 => Self::UnsignedShort,
5125 => Self::UnsignedInt,
5126 => Self::Float,
_ => return Err(state.err_range(&ty.to_string())),
},
_ => return Err(state.err_token("U64")),
};
state.next_tok(input)?;
Ok(ty)
}
}
impl SerJson for ComponentType {
fn ser_json(&self, d: usize, s: &mut nanoserde::SerJsonState) {
match self {
Self::Byte => 5120,
Self::UnsignedByte => 5121,
Self::Short => 5122,
Self::UnsignedShort => 5123,
Self::UnsignedInt => 5125,
Self::Float => 5126,
}
.ser_json(d, s)
}
}
#[derive(Debug, DeJson, SerJson, PartialEq, Clone, Copy)]
pub enum AccessorType {
#[nserde(rename = "SCALAR")]
Scalar,
#[nserde(rename = "VEC2")]
Vec2,
#[nserde(rename = "VEC3")]
Vec3,
#[nserde(rename = "VEC4")]
Vec4,
#[nserde(rename = "MAT2")]
Mat2,
#[nserde(rename = "MAT3")]
Mat3,
#[nserde(rename = "MAT4")]
Mat4,
}
impl AccessorType {
pub fn num_components(&self) -> usize {
match self {
Self::Scalar => 1,
Self::Vec2 => 2,
Self::Vec3 => 3,
Self::Vec4 | Self::Mat2 => 4,
Self::Mat3 => 9,
Self::Mat4 => 16,
}
}
}
#[derive(Debug, DeJson, SerJson, Clone)]
pub struct Material<E: Extensions> {
#[nserde(rename = "alphaMode")]
#[nserde(default)]
pub alpha_mode: AlphaMode,
#[nserde(default)]
pub extensions: E::MaterialExtensions,
#[cfg(feature = "names")]
pub name: Option<String>,
#[nserde(rename = "pbrMetallicRoughness")]
#[nserde(default)]
pub pbr_metallic_roughness: PbrMetallicRoughness<E>,
#[nserde(rename = "normalTexture")]
pub normal_texture: Option<NormalTextureInfo<E>>,
#[nserde(rename = "occlusionTexture")]
pub occlusion_texture: Option<OcclusionTextureInfo<E>>,
#[nserde(rename = "emissiveTexture")]
pub emissive_texture: Option<TextureInfo<E>>,
#[nserde(rename = "emissiveFactor")]
#[nserde(default)]
pub emissive_factor: [f32; 3],
#[nserde(rename = "alphaCutoff")]
#[nserde(default = "0.5")]
pub alpha_cutoff: f32,
#[nserde(rename = "doubleSided")]
#[nserde(default)]
pub double_sided: bool,
}
#[derive(Default, Debug, DeJson, SerJson, Clone, Copy)]
pub enum AlphaMode {
#[default]
#[nserde(rename = "OPAQUE")]
Opaque,
#[nserde(rename = "MASK")]
Mask,
#[nserde(rename = "BLEND")]
Blend,
}
#[derive(Debug, DeJson, SerJson, Clone)]
pub struct PbrMetallicRoughness<E: Extensions> {
#[nserde(rename = "baseColorFactor")]
#[nserde(default = "[1.0, 1.0, 1.0, 1.0]")]
pub base_color_factor: [f32; 4],
#[nserde(rename = "baseColorTexture")]
pub base_color_texture: Option<TextureInfo<E>>,
#[nserde(rename = "metallicFactor")]
#[nserde(default = "1.0")]
pub metallic_factor: f32,
#[nserde(rename = "roughnessFactor")]
#[nserde(default = "1.0")]
pub roughness_factor: f32,
#[nserde(rename = "metallicRoughnessTexture")]
pub metallic_roughness_texture: Option<TextureInfo<E>>,
}
impl<E: Extensions> Default for PbrMetallicRoughness<E> {
fn default() -> Self {
Self {
base_color_factor: [1.0; 4],
base_color_texture: None,
metallic_factor: 1.0,
roughness_factor: 1.0,
metallic_roughness_texture: None,
}
}
}
#[derive(Debug, DeJson, SerJson, Clone)]
pub struct TextureInfo<E: Extensions> {
pub index: usize,
#[nserde(rename = "texCoord")]
#[nserde(default)]
pub tex_coord: usize,
#[nserde(default)]
pub extensions: E::TextureInfoExtensions,
}
#[derive(Debug, DeJson, SerJson, Clone)]
pub struct NormalTextureInfo<E: Extensions> {
pub index: usize,
#[nserde(rename = "texCoord")]
#[nserde(default)]
pub tex_coord: usize,
#[nserde(default = "1.0")]
pub scale: f32,
#[nserde(default)]
pub extensions: E::TextureInfoExtensions,
}
#[derive(Debug, DeJson, SerJson, Clone)]
pub struct OcclusionTextureInfo<E: Extensions> {
pub index: usize,
#[nserde(rename = "texCoord")]
#[nserde(default)]
pub tex_coord: usize,
#[nserde(default = "1.0")]
pub strength: f32,
#[nserde(default)]
pub extensions: E::TextureInfoExtensions,
}
#[derive(Debug, DeJson, SerJson)]
pub struct Sampler {
#[nserde(rename = "magFilter")]
pub mag_filter: Option<FilterMode>,
#[nserde(rename = "minFilter")]
pub min_filter: Option<MinFilter>,
#[nserde(rename = "wrapS")]
#[nserde(default)]
pub wrap_s: SamplerWrap,
#[nserde(rename = "wrapT")]
#[nserde(default)]
pub wrap_t: SamplerWrap,
#[cfg(feature = "names")]
pub name: Option<String>,
}
#[derive(Debug, PartialEq)]
pub enum FilterMode {
Nearest,
Linear,
}
impl DeJson for FilterMode {
fn de_json(
state: &mut nanoserde::DeJsonState,
input: &mut core::str::Chars,
) -> Result<Self, nanoserde::DeJsonErr> {
let ty = match &state.tok {
nanoserde::DeJsonTok::U64(ty) => match ty {
9728 => Self::Nearest,
9729 => Self::Linear,
_ => return Err(state.err_range(&ty.to_string())),
},
_ => return Err(state.err_token("U64")),
};
state.next_tok(input)?;
Ok(ty)
}
}
impl SerJson for FilterMode {
fn ser_json(&self, d: usize, s: &mut nanoserde::SerJsonState) {
match self {
Self::Nearest => 9728,
Self::Linear => 9729,
}
.ser_json(d, s)
}
}
#[derive(Debug, PartialEq)]
pub struct MinFilter {
pub mode: FilterMode,
pub mipmap: Option<FilterMode>,
}
impl DeJson for MinFilter {
fn de_json(
state: &mut nanoserde::DeJsonState,
input: &mut core::str::Chars,
) -> Result<Self, nanoserde::DeJsonErr> {
let ty = match &state.tok {
nanoserde::DeJsonTok::U64(ty) => match ty {
9728 => Self {
mode: FilterMode::Nearest,
mipmap: None,
},
9729 => Self {
mode: FilterMode::Linear,
mipmap: None,
},
9984 => Self {
mode: FilterMode::Nearest,
mipmap: Some(FilterMode::Nearest),
},
9985 => Self {
mode: FilterMode::Linear,
mipmap: Some(FilterMode::Nearest),
},
9986 => Self {
mode: FilterMode::Nearest,
mipmap: Some(FilterMode::Linear),
},
9987 => Self {
mode: FilterMode::Linear,
mipmap: Some(FilterMode::Linear),
},
_ => return Err(state.err_range(&ty.to_string())),
},
_ => return Err(state.err_token("U64")),
};
state.next_tok(input)?;
Ok(ty)
}
}
impl SerJson for MinFilter {
fn ser_json(&self, d: usize, s: &mut nanoserde::SerJsonState) {
match &self {
MinFilter {
mode: FilterMode::Nearest,
mipmap: None,
} => 9728,
MinFilter {
mode: FilterMode::Linear,
mipmap: None,
} => 9729,
MinFilter {
mode: FilterMode::Nearest,
mipmap: Some(FilterMode::Nearest),
} => 9984,
MinFilter {
mode: FilterMode::Linear,
mipmap: Some(FilterMode::Nearest),
} => 9985,
MinFilter {
mode: FilterMode::Nearest,
mipmap: Some(FilterMode::Linear),
} => 9986,
MinFilter {
mode: FilterMode::Linear,
mipmap: Some(FilterMode::Linear),
} => 9987,
}
.ser_json(d, s)
}
}
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
pub enum SamplerWrap {
ClampToEdge,
MirroredRepeat,
#[default]
Repeat,
}
impl DeJson for SamplerWrap {
fn de_json(
state: &mut nanoserde::DeJsonState,
input: &mut core::str::Chars,
) -> Result<Self, nanoserde::DeJsonErr> {
let ty = match &state.tok {
nanoserde::DeJsonTok::U64(ty) => match ty {
33071 => Self::ClampToEdge,
33648 => Self::MirroredRepeat,
10497 => Self::Repeat,
_ => return Err(state.err_range(&ty.to_string())),
},
_ => return Err(state.err_token("U64")),
};
state.next_tok(input)?;
Ok(ty)
}
}
impl SerJson for SamplerWrap {
fn ser_json(&self, d: usize, s: &mut nanoserde::SerJsonState) {
match self {
Self::ClampToEdge => 33071,
Self::MirroredRepeat => 33648,
Self::Repeat => 10497,
}
.ser_json(d, s)
}
}
#[derive(Debug, DeJson, SerJson, Clone)]
pub struct Camera {
pub perspective: Option<CameraPerspective>,
pub orthographic: Option<CameraOrthographic>,
#[nserde(rename = "type")]
pub ty: CameraType,
#[cfg(feature = "names")]
pub name: Option<String>,
}
#[derive(Debug, DeJson, SerJson, Clone, Copy)]
pub struct CameraPerspective {
pub yfov: f32,
pub znear: f32,
pub zfar: Option<f32>,
#[nserde(rename = "aspectRatio")]
pub aspect_ratio: Option<f32>,
}
#[derive(Debug, DeJson, SerJson, Clone, Copy)]
pub struct CameraOrthographic {
pub xmag: f32,
pub ymag: f32,
pub zfar: f32,
pub znear: f32,
}
#[derive(Debug, DeJson, SerJson, Clone, Copy, PartialEq, Eq)]
pub enum CameraType {
#[nserde(rename = "perspective")]
Perspective,
#[nserde(rename = "orthographic")]
Orthographic,
}
#[derive(Debug, DeJson, SerJson, Clone)]
pub struct Scene {
#[cfg(feature = "names")]
pub name: Option<String>,
pub nodes: Vec<usize>,
}
pub mod default_extensions {
use crate::extensions;
use nanoserde::{DeJson, SerJson};
#[derive(Debug, Default, Clone, Copy, DeJson, SerJson)]
pub struct Extensions;
impl super::Extensions for Extensions {
type RootExtensions = RootExtensions;
type TextureExtensions = TextureExtensions;
type TextureInfoExtensions = TextureInfoExtensions;
type MaterialExtensions = MaterialExtensions<Self>;
type BufferExtensions = BufferExtensions;
type NodeExtensions = NodeExtensions;
type NodeExtras = NodeExtras;
type BufferViewExtensions = BufferViewExtensions;
}
#[derive(Debug, DeJson, SerJson, Default, Clone)]
pub struct RootExtensions {
#[nserde(rename = "KHR_lights_punctual")]
pub khr_lights_punctual: Option<extensions::khr_lights_punctual::Root>,
}
#[derive(Debug, DeJson, SerJson, Default, Clone)]
pub struct BufferExtensions {
#[nserde(rename = "EXT_meshopt_compression")]
pub ext_meshopt_compression: Option<extensions::ExtMeshoptCompressionBuffer>,
}
#[derive(Debug, DeJson, SerJson, Default, Clone)]
pub struct NodeExtensions {
#[nserde(rename = "EXT_mesh_gpu_instancing")]
pub ext_mesh_gpu_instancing: Option<extensions::ExtMeshGpuInstancing>,
#[nserde(rename = "MSFT_lod")]
pub msft_lod: Option<extensions::MsftLod>,
#[nserde(rename = "KHR_lights_punctual")]
pub khr_lights_punctual: Option<extensions::khr_lights_punctual::Node>,
}
#[derive(Debug, DeJson, SerJson, Default, Clone)]
pub struct NodeExtras {
#[nserde(rename = "MSFT_screencoverage")]
pub msft_screencoverage: Option<Vec<f32>>,
}
#[derive(Debug, DeJson, SerJson, Default, Clone)]
pub struct TextureExtensions {
#[nserde(rename = "KHR_texture_basisu")]
pub khr_texture_basisu: Option<extensions::KhrTextureBasisu>,
}
#[derive(Debug, DeJson, SerJson, Default, Clone)]
pub struct BufferViewExtensions {
#[nserde(rename = "EXT_meshopt_compression")]
pub ext_meshopt_compression: Option<extensions::ExtMeshoptCompression>,
}
#[derive(Debug, DeJson, SerJson, Default, Clone)]
pub struct MaterialExtensions<E: super::Extensions> {
#[nserde(rename = "KHR_materials_sheen")]
pub khr_materials_sheen: Option<extensions::KhrMaterialsSheen<E>>,
#[nserde(rename = "KHR_materials_emissive_strength")]
pub khr_materials_emissive_strength: Option<extensions::KhrMaterialsEmissiveStrength>,
#[nserde(rename = "KHR_materials_unlit")]
pub khr_materials_unlit: Option<extensions::KhrMaterialsUnlit>,
#[nserde(rename = "KHR_materials_ior")]
pub khr_materials_ior: Option<extensions::KhrMaterialsIor>,
#[nserde(rename = "KHR_materials_specular")]
pub khr_materials_specular: Option<extensions::KhrMaterialsSpecular<E>>,
#[nserde(rename = "KHR_materials_transmission")]
pub khr_materials_transmission: Option<extensions::KhrMaterialsTransmission<E>>,
}
#[derive(Debug, DeJson, SerJson, Default, Clone, Copy)]
pub struct TextureInfoExtensions {
#[nserde(rename = "KHR_texture_transform")]
pub khr_texture_transform: Option<extensions::KhrTextureTransform>,
}
}
#[cfg(test)]
mod tests {
use super::*;
use nanoserde::{DeJson, SerJson};
fn test_roundtrip<T: DeJson + SerJson + PartialEq + Debug>(value: &T) {
assert_eq!(
*value,
T::deserialize_json(&value.serialize_json()).unwrap()
);
}
#[test]
fn test_primitive_mode_roundtrip() {
for variant in &[
PrimitiveMode::Points,
PrimitiveMode::Lines,
PrimitiveMode::LineLoop,
PrimitiveMode::LineStrip,
PrimitiveMode::Triangles,
PrimitiveMode::TriangleStrip,
PrimitiveMode::TriangleFan,
] {
test_roundtrip(variant);
}
}
#[test]
fn test_component_type_roundtrip() {
for variant in &[
ComponentType::UnsignedByte,
ComponentType::Byte,
ComponentType::UnsignedShort,
ComponentType::Short,
ComponentType::UnsignedInt,
ComponentType::Float,
] {
test_roundtrip(variant);
}
}
#[test]
fn test_filter_mode_roundtrip() {
for variant in &[FilterMode::Nearest, FilterMode::Linear] {
test_roundtrip(variant);
}
}
#[test]
fn test_min_filter_roundtrip() {
for variant in &[
MinFilter {
mode: FilterMode::Nearest,
mipmap: None,
},
MinFilter {
mode: FilterMode::Linear,
mipmap: None,
},
MinFilter {
mode: FilterMode::Nearest,
mipmap: Some(FilterMode::Nearest),
},
MinFilter {
mode: FilterMode::Linear,
mipmap: Some(FilterMode::Nearest),
},
MinFilter {
mode: FilterMode::Nearest,
mipmap: Some(FilterMode::Linear),
},
MinFilter {
mode: FilterMode::Linear,
mipmap: Some(FilterMode::Linear),
},
] {
test_roundtrip(variant);
}
}
#[test]
fn test_sampler_wrap_roundtrip() {
for variant in &[
SamplerWrap::ClampToEdge,
SamplerWrap::MirroredRepeat,
SamplerWrap::Repeat,
] {
test_roundtrip(variant);
}
}
}