ray_tracing_utility/serialization/core/
scene.rs

1use crate::serialization::core::{Camera, Configuration};
2use crate::serialization::environment::SerializeEnvironment;
3use crate::serialization::geometry::SerializeGeometry;
4use crate::serialization::{IdConstructor, IdReference, RayTracingObject};
5use ray_tracing_core::core;
6use ray_tracing_core::environment;
7use ray_tracing_core::geometry;
8use ray_tracing_core::material;
9use ray_tracing_core::texture;
10use serde::{Deserialize, Serialize};
11use std::cell::RefCell;
12use std::collections::HashMap;
13use std::error::Error;
14use std::path::Path;
15use std::rc::Rc;
16use std::sync::Arc;
17
18#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
19pub struct Scene {
20    pub configuration_id: usize,
21
22    pub camera_id: usize,
23
24    pub sky_id: usize,
25
26    pub root_node_id: usize,
27
28    #[serde(default = "Scene::default_light_node")]
29    pub light_node_id: usize,
30
31    pub objects: Vec<RayTracingObject>,
32}
33
34pub struct DeserializeOptions {
35    pub root_path: Option<String>,
36}
37
38impl DeserializeOptions {
39    pub fn default() -> DeserializeOptions {
40        DeserializeOptions { root_path: None }
41    }
42
43    pub fn form_path(root_path: &Path) -> DeserializeOptions {
44        DeserializeOptions {
45            root_path: match root_path.to_str() {
46                Some(path) => Some(String::from(path)),
47                None => None,
48            },
49        }
50    }
51}
52
53impl Scene {
54    fn default_light_node() -> usize {
55        0
56    }
57
58    pub fn from_scene(s: &core::Scene) -> Result<Scene, Box<dyn Error>> {
59        let object_map = Rc::new(RefCell::new(HashMap::<usize, RayTracingObject>::default()));
60        object_map.borrow_mut().insert(
61            s.configuration.id,
62            RayTracingObject::Configuration(Configuration::from_configuration(&s.configuration)?),
63        );
64        object_map.borrow_mut().insert(
65            s.camera.id,
66            RayTracingObject::Camera(Camera::from_camera(&s.camera)?),
67        );
68        let mut se = SerializeEnvironment {
69            object_map: object_map.clone(),
70        };
71        s.sky.accept(&mut se)?;
72        let mut sh = SerializeGeometry {
73            object_map: object_map.clone(),
74            collection: None,
75        };
76        s.world.accept(&mut sh)?;
77        drop(sh);
78        //let objects = object_map.take().into_iter().map(|(_id, obj)| obj).collect();
79        let mut tuples: Vec<(usize, RayTracingObject)> = object_map.take().into_iter().collect();
80        tuples.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap());
81        let objects = tuples.iter().map(|(_id, obj)| obj.clone()).collect();
82        Ok(Scene {
83            camera_id: s.camera.id,
84            root_node_id: s.world.get_id(),
85            sky_id: s.sky.get_id(),
86            configuration_id: s.configuration.id,
87            light_node_id: 0,
88            objects: objects,
89        })
90    }
91
92    pub fn to_scene(&self) -> Result<core::Scene, Box<dyn Error>> {
93        self.to_scene_with_options(&DeserializeOptions::default())
94    }
95
96    pub fn insert_texture<T, F>(
97        container: &mut HashMap<usize, Arc<dyn texture::Texture>>,
98        id: &IdConstructor,
99        object: &T,
100        convert: F,
101    ) where
102        F: Fn(&T, usize, &HashMap<usize, Arc<dyn texture::Texture>>) -> Arc<dyn texture::Texture>,
103    {
104        for index in 0..id.len() {
105            container.insert(id.get_id(index), convert(object, index, container));
106        }
107    }
108
109    pub fn insert_material<T, F>(
110        container: &mut HashMap<usize, Arc<dyn material::Material>>,
111        id: &IdConstructor,
112        object: &T,
113        convert: F,
114    ) where
115        F: Fn(
116            &T,
117            usize,
118            &HashMap<usize, Arc<dyn material::Material>>,
119        ) -> Arc<dyn material::Material>,
120    {
121        for index in 0..id.len() {
122            container.insert(id.get_id(index), convert(object, index, container));
123        }
124    }
125
126    pub fn insert_geometry<T, F>(
127        container: &mut HashMap<usize, Arc<dyn geometry::Geometry>>,
128        id: &IdConstructor,
129        object: &T,
130        convert: F,
131    ) where
132        F: Fn(
133            &T,
134            usize,
135            &HashMap<usize, Arc<dyn geometry::Geometry>>,
136        ) -> Arc<dyn geometry::Geometry>,
137    {
138        for index in 0..id.len() {
139            container.insert(id.get_id(index), convert(object, index, container));
140        }
141    }
142
143    pub fn to_scene_with_options(
144        &self,
145        deserialize_options: &DeserializeOptions,
146    ) -> Result<core::Scene, Box<dyn Error>> {
147        let mut configuration_map = HashMap::<usize, core::Configuration>::default();
148        let mut camera_map = HashMap::<usize, Arc<core::Camera>>::default();
149        let mut texture_map = HashMap::<usize, Arc<dyn texture::Texture>>::default();
150        for obj in self.objects.iter() {
151            match obj {
152                RayTracingObject::Configuration(c) => {
153                    for index in 0..c.id.len() {
154                        configuration_map.insert(c.id.get_id(index), c.to_configuration(index)?);
155                    }
156                }
157                RayTracingObject::Camera(c) => {
158                    for index in 0..c.id.len() {
159                        camera_map.insert(c.id.get_id(index), Arc::new(c.to_camera(index)?));
160                    }
161                }
162                RayTracingObject::CameraVerticalField(c) => {
163                    for index in 0..c.id.len() {
164                        camera_map.insert(c.id.get_id(index), Arc::new(c.to_camera(index)?));
165                    }
166                }
167                RayTracingObject::CameraLookAt(c) => {
168                    for index in 0..c.id.len() {
169                        camera_map.insert(c.id.get_id(index), Arc::new(c.to_camera(index)?));
170                    }
171                }
172                RayTracingObject::ConstantTexture(t) => {
173                    Scene::insert_texture(&mut texture_map, &t.id, t, |t, i, _| {
174                        Arc::new(t.to_texture(i).unwrap())
175                    })
176                }
177                RayTracingObject::BitmapFile(t) => {
178                    Scene::insert_texture(&mut texture_map, &t.id, t, |t, i, _| {
179                        Arc::new(t.to_texture(i, &deserialize_options.root_path).unwrap())
180                    })
181                }
182
183                RayTracingObject::CheckerTexture(t) => {
184                    Scene::insert_texture(&mut texture_map, &t.id, t, |t, i, tm| {
185                        Arc::new(
186                            t.to_texture(
187                                i,
188                                Scene::get_texture(tm, &t.even_texture, i),
189                                Scene::get_texture(tm, &t.odd_texture, i),
190                            )
191                            .unwrap(),
192                        )
193                    })
194                }
195                RayTracingObject::BlendTexture(t) => {
196                    Scene::insert_texture(&mut texture_map, &t.id, t, |t, i, tm| {
197                        Arc::new(
198                            t.to_texture(
199                                i,
200                                Scene::get_texture(tm, &t.first_texture, i),
201                                Scene::get_texture(tm, &t.second_texture, i),
202                                Scene::get_texture(tm, &t.mask_texture, i),
203                            )
204                            .unwrap(),
205                        )
206                    })
207                }
208                RayTracingObject::NoiseTexture(t) => {
209                    Scene::insert_texture(&mut texture_map, &t.id, t, |t, i, tm| {
210                        Arc::new(
211                            t.to_texture(
212                                i,
213                                Scene::get_texture(tm, &t.min_texture, i),
214                                Scene::get_texture(tm, &t.max_texture, i),
215                            )
216                            .unwrap(),
217                        )
218                    })
219                }
220                RayTracingObject::ColorFilter(f) => {
221                    Scene::insert_texture(&mut texture_map, &f.id, f, |t, i, tm| {
222                        Arc::new(
223                            f.to_texture(i, Scene::get_texture(tm, &t.texture, i))
224                                .unwrap(),
225                        )
226                    })
227                }
228                _ => (),
229            };
230        }
231        let mut material_map = HashMap::<usize, Arc<dyn material::Material>>::default();
232        let mut environment_map = HashMap::<usize, Arc<dyn environment::Environment>>::default();
233        for obj in self.objects.iter() {
234            match obj {
235                RayTracingObject::NoMaterial(m) => {
236                    Scene::insert_material(&mut material_map, &m.id, m, |m, i, _| {
237                        Arc::new(m.to_material(i).unwrap())
238                    })
239                }
240                RayTracingObject::Lambertian(m) => {
241                    Scene::insert_material(&mut material_map, &m.id, m, |m, i, _| {
242                        Arc::new(
243                            m.to_material(i, Scene::get_texture(&texture_map, &m.albedo, i))
244                                .unwrap(),
245                        )
246                    })
247                }
248                RayTracingObject::Metal(m) => {
249                    Scene::insert_material(&mut material_map, &m.id, m, |m, i, _| {
250                        Arc::new(
251                            m.to_material(i, Scene::get_texture(&texture_map, &m.albedo, i))
252                                .unwrap(),
253                        )
254                    })
255                }
256                RayTracingObject::Dielectric(m) => {
257                    Scene::insert_material(&mut material_map, &m.id, m, |m, i, _| {
258                        Arc::new(
259                            m.to_material(i, Scene::get_texture(&texture_map, &m.albedo, i))
260                                .unwrap(),
261                        )
262                    })
263                }
264                RayTracingObject::Isotropic(m) => {
265                    Scene::insert_material(&mut material_map, &m.id, m, |m, i, _| {
266                        Arc::new(
267                            m.to_material(i, Scene::get_texture(&texture_map, &m.albedo, i))
268                                .unwrap(),
269                        )
270                    })
271                }
272                RayTracingObject::DiffuseLight(m) => {
273                    Scene::insert_material(&mut material_map, &m.id, m, |m, i, _| {
274                        Arc::new(
275                            m.to_material(i, Scene::get_texture(&texture_map, &m.emit, i))
276                                .unwrap(),
277                        )
278                    })
279                }
280                RayTracingObject::Sky(s) => {
281                    for index in 0..s.id.len() {
282                        environment_map
283                            .insert(s.id.get_id(index), Arc::new(s.to_environment(index)?));
284                    }
285                }
286                _ => (),
287            };
288        }
289        for obj in self.objects.iter() {
290            match obj {
291                RayTracingObject::MaterialBlend(m) => {
292                    for index in 0..m.id.len() {
293                        let v = m
294                            .materials
295                            .iter()
296                            .map(|id| Scene::get_material(&material_map, id, index))
297                            .collect();
298                        material_map
299                            .insert(m.id.get_id(index), Arc::new(m.to_material(index, &v)?));
300                    }
301                }
302                _ => (),
303            }
304        }
305        let mut object_map = HashMap::<usize, Arc<dyn geometry::Geometry>>::default();
306        for obj in self.objects.iter() {
307            match obj {
308                RayTracingObject::Sphere(h) => {
309                    Scene::insert_geometry(&mut object_map, &h.id, h, |h, i, _| {
310                        Arc::new(
311                            h.to_shape(i, Scene::get_material(&material_map, &h.material, i))
312                                .unwrap(),
313                        )
314                    })
315                }
316                RayTracingObject::MovableSphere(h) => {
317                    Scene::insert_geometry(&mut object_map, &h.id, h, |h, i, _| {
318                        Arc::new(
319                            h.to_shape(i, Scene::get_material(&material_map, &h.material, i))
320                                .unwrap(),
321                        )
322                    })
323                }
324                RayTracingObject::Collection(c) => {
325                    let mut obj_list = Vec::<Arc<dyn geometry::Geometry>>::default();
326                    for id in IdReference::get_list(&c.object_id_list) {
327                        obj_list.push(Scene::get_geometry(
328                            &object_map,
329                            &IdReference::Single(id),
330                            0,
331                        ));
332                    }
333                    Scene::insert_geometry(&mut object_map, &c.id, c, |c, _, _| {
334                        c.to_collection(&obj_list, 0.0..0.0).unwrap()
335                    })
336                }
337                RayTracingObject::XYRect(h) => {
338                    Scene::insert_geometry(&mut object_map, &h.id, h, |h, i, _| {
339                        Arc::new(
340                            h.to_shape(i, Scene::get_material(&material_map, &h.material, i))
341                                .unwrap(),
342                        )
343                    })
344                }
345                RayTracingObject::XZRect(h) => {
346                    Scene::insert_geometry(&mut object_map, &h.id, h, |h, i, _| {
347                        Arc::new(
348                            h.to_shape(i, Scene::get_material(&material_map, &h.material, i))
349                                .unwrap(),
350                        )
351                    })
352                }
353                RayTracingObject::YZRect(h) => {
354                    Scene::insert_geometry(&mut object_map, &h.id, h, |h, i, _| {
355                        Arc::new(
356                            h.to_shape(i, Scene::get_material(&material_map, &h.material, i))
357                                .unwrap(),
358                        )
359                    })
360                }
361                RayTracingObject::Cuboid(h) => {
362                    Scene::insert_geometry(&mut object_map, &h.id, h, |h, i, _| {
363                        Arc::new(
364                            h.to_shape(i, Scene::get_material(&material_map, &h.material, i))
365                                .unwrap(),
366                        )
367                    })
368                }
369                RayTracingObject::ConstantMedium(h) => {
370                    Scene::insert_geometry(&mut object_map, &h.id, h, |h, i, om| {
371                        Arc::new(
372                            h.to_volume(
373                                i,
374                                Scene::get_geometry(&om, &h.boundary, i),
375                                Scene::get_material(&material_map, &h.phase_function, i),
376                            )
377                            .unwrap(),
378                        )
379                    })
380                }
381                RayTracingObject::FlipNormals(h) => {
382                    Scene::insert_geometry(&mut object_map, &h.id, h, |h, i, om| {
383                        Arc::new(
384                            h.to_geometry(i, Scene::get_geometry(&om, &h.node, i))
385                                .unwrap(),
386                        )
387                    })
388                }
389                RayTracingObject::RotateX(h) => {
390                    Scene::insert_geometry(&mut object_map, &h.id, h, |h, i, om| {
391                        Arc::new(
392                            h.to_geometry(i, Scene::get_geometry(&om, &h.node, i))
393                                .unwrap(),
394                        )
395                    })
396                }
397                RayTracingObject::RotateY(h) => {
398                    Scene::insert_geometry(&mut object_map, &h.id, h, |h, i, om| {
399                        Arc::new(
400                            h.to_geometry(i, Scene::get_geometry(&om, &h.node, i))
401                                .unwrap(),
402                        )
403                    })
404                }
405                RayTracingObject::RotateZ(h) => {
406                    Scene::insert_geometry(&mut object_map, &h.id, h, |h, i, om| {
407                        Arc::new(
408                            h.to_geometry(i, Scene::get_geometry(&om, &h.node, i))
409                                .unwrap(),
410                        )
411                    })
412                }
413                RayTracingObject::Translate(h) => {
414                    Scene::insert_geometry(&mut object_map, &h.id, h, |h, i, om| {
415                        Arc::new(
416                            h.to_geometry(i, Scene::get_geometry(&om, &h.node, i))
417                                .unwrap(),
418                        )
419                    })
420                }
421                _ => (),
422            };
423        }
424        let light = if self.light_node_id > 0 {
425            Some(Scene::get_geometry(
426                &object_map,
427                &IdReference::Single(self.light_node_id),
428                0,
429            ))
430        } else {
431            None
432        };
433        Ok(core::Scene::new(
434            Scene::get_configuration(&configuration_map, &self.configuration_id),
435            Scene::get_camera(&camera_map, &self.camera_id),
436            Scene::get_environment(&environment_map, &self.sky_id),
437            Scene::get_geometry(&object_map, &IdReference::Single(self.root_node_id), 0),
438            light,
439        ))
440    }
441
442    fn get_configuration(
443        configuration_map: &HashMap<usize, core::Configuration>,
444        id: &usize,
445    ) -> core::Configuration {
446        if !configuration_map.contains_key(id) {
447            panic!("No configuration with id {} found", id);
448        }
449        configuration_map[id].clone()
450    }
451
452    fn get_camera(camera_map: &HashMap<usize, Arc<core::Camera>>, id: &usize) -> Arc<core::Camera> {
453        if !camera_map.contains_key(id) {
454            panic!("No camera with id {} found", id);
455        }
456        camera_map[id].clone()
457    }
458
459    fn get_environment(
460        environment_map: &HashMap<usize, Arc<dyn environment::Environment>>,
461        id: &usize,
462    ) -> Arc<dyn environment::Environment> {
463        if !environment_map.contains_key(id) {
464            panic!("No environment with id {} found", id);
465        }
466        environment_map[id].clone()
467    }
468
469    fn get_texture(
470        texture_map: &HashMap<usize, Arc<dyn texture::Texture>>,
471        id: &IdReference,
472        index: usize,
473    ) -> Arc<dyn texture::Texture> {
474        let id = id.get_id(index);
475        if !texture_map.contains_key(&id) {
476            panic!("No texture with id {} found", id);
477        }
478        texture_map[&id].clone()
479    }
480
481    fn get_material(
482        material_map: &HashMap<usize, Arc<dyn material::Material>>,
483        id: &IdReference,
484        index: usize,
485    ) -> Arc<dyn material::Material> {
486        let id = id.get_id(index);
487        if !material_map.contains_key(&id) {
488            panic!("No material with id {} found", id);
489        }
490        material_map[&id].clone()
491    }
492
493    fn get_geometry(
494        object_map: &HashMap<usize, Arc<dyn geometry::Geometry>>,
495        id: &IdReference,
496        index: usize,
497    ) -> Arc<dyn geometry::Geometry> {
498        let id = id.get_id(index);
499        if !object_map.contains_key(&id) {
500            panic!("No hit able object with id {} found", id);
501        }
502        object_map[&id].clone()
503    }
504}
505
506#[cfg(test)]
507mod serialize_scene_test {
508    use super::*;
509    use ray_tracing_core::test;
510
511    #[test]
512    fn serialize_scene_from_scene() {
513        let ts = test::TestSceneSimple::new();
514        let s = Scene::from_scene(&ts.scene).unwrap();
515        assert_eq!(s.objects.len(), 10);
516    }
517
518    #[test]
519    fn serialize_scene_to_scene() {
520        let ts = test::TestSceneSimple::new();
521        let s = Scene::from_scene(&ts.scene).unwrap();
522        let ds = s.to_scene().unwrap();
523        assert_eq!(ds.configuration.maximum_depth, 50);
524    }
525}