gltf_v1_json/
gltf.rs

1use gltf_v1_derive::Validate;
2use indexmap::IndexMap;
3
4use crate::extensions;
5
6use super::accessor::Accessor;
7use super::animation::Animation;
8use super::asset::Asset;
9use super::buffer::{Buffer, BufferView};
10use super::camera::Camera;
11use super::common::StringIndex;
12use super::image::Image;
13use super::material::{Material, Technique};
14use super::mesh::Mesh;
15use super::node::Node;
16use super::scene::Scene;
17use super::shader::{Program, Shader};
18use super::skin::Skin;
19use super::texture::{Sampler, Texture};
20
21pub trait Get<T> {
22    fn get(&self, id: StringIndex<T>) -> Option<&T>;
23}
24
25pub struct UniqueKeyGenerator {
26    prefix: String,
27    counter: usize,
28}
29
30impl UniqueKeyGenerator {
31    fn new(prefix: &str) -> Self {
32        Self {
33            prefix: prefix.to_string(),
34            counter: 0,
35        }
36    }
37
38    fn next_key<T>(&mut self, map: &IndexMap<String, T>) -> String {
39        loop {
40            let key = format!("{}{}", self.prefix, self.counter);
41            self.counter += 1;
42            if !map.contains_key(&key) {
43                return key;
44            }
45        }
46    }
47}
48
49#[derive(Clone, Debug, serde_derive::Deserialize, serde_derive::Serialize, Validate, Default)]
50pub struct Root {
51    #[serde(default)]
52    #[serde(skip_serializing_if = "IndexMap::is_empty")]
53    pub accessors: IndexMap<String, Accessor>,
54    #[serde(default)]
55    #[serde(skip_serializing_if = "IndexMap::is_empty")]
56    pub animations: IndexMap<String, Animation>,
57    #[serde(skip_serializing_if = "Option::is_none")]
58    pub asset: Option<Asset>,
59    #[serde(default)]
60    #[serde(skip_serializing_if = "IndexMap::is_empty")]
61    pub buffers: IndexMap<String, Buffer>,
62    #[serde(default)]
63    #[serde(rename = "bufferViews")]
64    #[serde(skip_serializing_if = "IndexMap::is_empty")]
65    pub buffer_views: IndexMap<String, BufferView>,
66    #[serde(default)]
67    #[serde(skip_serializing_if = "IndexMap::is_empty")]
68    pub cameras: IndexMap<String, Camera>,
69    #[serde(default)]
70    #[serde(skip_serializing_if = "IndexMap::is_empty")]
71    pub images: IndexMap<String, Image>,
72    #[serde(default)]
73    #[serde(skip_serializing_if = "IndexMap::is_empty")]
74    pub materials: IndexMap<String, Material>,
75    #[serde(default)]
76    #[serde(skip_serializing_if = "IndexMap::is_empty")]
77    pub meshes: IndexMap<String, Mesh>,
78    #[serde(default)]
79    #[serde(skip_serializing_if = "IndexMap::is_empty")]
80    pub nodes: IndexMap<String, Node>,
81    #[serde(default)]
82    #[serde(skip_serializing_if = "IndexMap::is_empty")]
83    pub programs: IndexMap<String, Program>,
84    #[serde(default)]
85    #[serde(skip_serializing_if = "IndexMap::is_empty")]
86    pub samplers: IndexMap<String, Sampler>,
87    #[serde(default)]
88    #[serde(skip_serializing_if = "Option::is_none")]
89    pub scene: Option<StringIndex<Scene>>,
90    #[serde(default)]
91    #[serde(skip_serializing_if = "IndexMap::is_empty")]
92    pub scenes: IndexMap<String, Scene>,
93    #[serde(default)]
94    #[serde(skip_serializing_if = "IndexMap::is_empty")]
95    pub shaders: IndexMap<String, Shader>,
96    #[serde(default)]
97    #[serde(skip_serializing_if = "IndexMap::is_empty")]
98    pub skins: IndexMap<String, Skin>,
99    #[serde(default)]
100    #[serde(skip_serializing_if = "IndexMap::is_empty")]
101    pub techniques: IndexMap<String, Technique>,
102    #[serde(default)]
103    #[serde(skip_serializing_if = "IndexMap::is_empty")]
104    pub textures: IndexMap<String, Texture>,
105    #[serde(default)]
106    #[serde(skip_serializing_if = "Vec::is_empty")]
107    pub extensions_used: Vec<String>,
108    #[serde(default)]
109    #[serde(skip_serializing_if = "Option::is_none")]
110    pub extensions: Option<extensions::gltf::Root>,
111}
112
113impl Root {
114    pub fn add_default_material(&mut self) {
115        // Give all Materials with no Technique a Default Technique as the Default Material
116        let materials_with_no_technique: Vec<(&String, &mut Material)> = self
117            .materials
118            .iter_mut()
119            .filter(|x| x.1.technique.is_none())
120            .collect();
121        if materials_with_no_technique.is_empty() {
122            return;
123        }
124
125        let mut generator = UniqueKeyGenerator::new("vertexShader");
126        let vertex_shader_key = generator.next_key(&self.shaders);
127        self.shaders
128            .insert(vertex_shader_key.clone(), Shader::default_vertex_shader());
129        let mut generator = UniqueKeyGenerator::new("fragmentShader");
130        let fragment_shader_key = generator.next_key(&self.shaders);
131        self.shaders.insert(
132            fragment_shader_key.clone(),
133            Shader::default_fragment_shader(),
134        );
135        let mut generator = UniqueKeyGenerator::new("program");
136        let program_key = generator.next_key(&self.programs);
137        self.programs.insert(
138            program_key.clone(),
139            Program::default_program(fragment_shader_key, vertex_shader_key),
140        );
141        let mut generator = UniqueKeyGenerator::new("technique");
142        let technique_key = generator.next_key(&self.techniques);
143        self.techniques.insert(
144            technique_key.clone(),
145            Technique::default_technique(program_key),
146        );
147
148        for (_, material) in materials_with_no_technique {
149            material.technique = Some(StringIndex::new(technique_key.clone()))
150        }
151    }
152}
153
154macro_rules! impl_get {
155    ($ty:ty, $field:ident) => {
156        impl<'a> Get<$ty> for Root {
157            fn get(&self, index: StringIndex<$ty>) -> Option<&$ty> {
158                self.$field.get(index.value())
159            }
160        }
161    };
162}
163
164impl_get!(Accessor, accessors);
165impl_get!(Animation, animations);
166impl_get!(Buffer, buffers);
167impl_get!(BufferView, buffer_views);
168impl_get!(Camera, cameras);
169impl_get!(Image, images);
170impl_get!(Material, materials);
171impl_get!(Mesh, meshes);
172impl_get!(Node, nodes);
173impl_get!(Program, programs);
174impl_get!(Sampler, samplers);
175impl_get!(Scene, scenes);
176impl_get!(Shader, shaders);
177impl_get!(Skin, skins);
178impl_get!(Texture, textures);
179impl_get!(Technique, techniques);
180
181#[test]
182fn test_gltf_deserialize() {
183    let data = r#"{
184    "asset" : {
185        "copyright" : "(C) Copyright Khronos Group",
186        "generator" : "collada2gltf@042d7d2a3782aaf6d86961d052fc53bea8b3e424",
187        "premultipliedAlpha" : true,
188        "profile" : {
189            "api" : "WebGL",
190            "version" : "1.0.3",
191            "extras" : {
192                "Application specific" : "The extra object can contain any properties."
193            }  
194        },
195        "version" : "1.0",
196        "extensions" : {
197           "extension_name" : {
198              "extension specific" : "value"
199           }
200        },
201        "extras" : {
202            "Application specific" : "The extra object can contain any properties."
203        }  
204    }
205}"#;
206    let gltf: Root = serde_json::from_str(data).unwrap();
207    println!("{}", serde_json::to_string(&gltf).unwrap());
208    assert_eq!(
209        &Some("(C) Copyright Khronos Group".to_string()),
210        &gltf.asset.unwrap().copyright
211    );
212}