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 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}