rnm_3d/
scene.rs

1use crate::{file::ArchivedFile, file::File, Image, Light, Material, Mesh};
2
3#[cfg(feature = "safe")]
4use crate::{material::ArchivedMaterial, mesh::ArchivedMesh};
5
6#[derive(Debug, rkyv::Archive, rkyv::Deserialize, rkyv::Serialize)]
7pub struct Scene {
8    meshes: Option<Vec<Mesh>>,
9    materials: Option<Vec<Material>>,
10    lights: Option<Vec<Light>>,
11    images: Option<Vec<Image>>,
12}
13
14impl Scene {
15    pub fn meshes(&self) -> Option<&[Mesh]> {
16        self.meshes.as_deref()
17    }
18    pub fn materials(&self) -> Option<&[Material]> {
19        self.materials.as_deref()
20    }
21    pub fn lights(&self) -> Option<&[Light]> {
22        self.lights.as_deref()
23    }
24    pub fn images(&self) -> Option<&[Image]> {
25        self.images.as_deref()
26    }
27    pub fn decode_images(&self) -> Option<Vec<Vec<u8>>> {
28        self.images
29            .as_ref()
30            .map(|images| {
31                images
32                    .into_iter()
33                    .map(Image::decode)
34                    .map(Result::ok)
35                    .collect()
36            })
37            .flatten()
38    }
39    fn add<T>(items: &mut Option<Vec<T>>, item: T) {
40        if let Some(items) = items {
41            items.push(item);
42        } else {
43            *items = Some(vec![item]);
44        }
45    }
46    pub fn add_mesh(&mut self, mesh: Mesh) {
47        Self::add(&mut self.meshes, mesh);
48    }
49    pub fn add_material(&mut self, material: Material) {
50        Self::add(&mut self.materials, material);
51    }
52    pub fn add_light(&mut self, light: Light) {
53        Self::add(&mut self.lights, light);
54    }
55    pub fn add_image(&mut self, image: Image) {
56        Self::add(&mut self.images, image);
57    }
58    pub fn new(
59        meshes: Option<Vec<Mesh>>,
60        materials: Option<Vec<Material>>,
61        lights: Option<Vec<Light>>,
62        images: Option<Vec<Image>>,
63    ) -> Option<Self> {
64        #[cfg(feature = "safe")]
65        {
66            let tex = images.as_ref().map(Vec::len).unwrap_or(0);
67            let mat = materials.as_ref().map(Vec::len).unwrap_or(0);
68            if !materials
69                .as_ref()
70                .map(|m| {
71                    m.iter()
72                        .filter_map(Material::max_texture_idx)
73                        .max()
74                        .map(|x| x as usize)
75                        .map(|max| max < tex)
76                })
77                .flatten()
78                .unwrap_or(true)
79            {
80                println!("[ERROR]: images len is less than image index in material!");
81                None
82            } else if !meshes.as_ref().is_some_and(|m| {
83                m.iter()
84                    .filter_map(Mesh::material)
85                    .map(|x| x as usize)
86                    .all(|m| m < mat)
87            }) {
88                println!("[ERROR]: materials len is less than material index in mesh!");
89                None
90            } else if meshes
91                .as_ref()
92                .is_some_and(|m| m.iter().any(Mesh::isnt_right))
93            {
94                println!("[ERROR]: mesh attributes DOESNT have the same len!");
95                None
96            } else {
97                Some(Self {
98                    meshes,
99                    materials,
100                    lights,
101                    images,
102                })
103            }
104        }
105        #[cfg(not(feature = "safe"))]
106        {
107            Some(Self {
108                meshes,
109                materials,
110                lights,
111                images,
112            })
113        }
114    }
115    pub fn load(data: &[u8]) -> Option<Self> {
116        let mut bytes = rkyv::util::AlignedVec::<16>::new();
117        bytes.extend_from_slice(data);
118        #[cfg(feature = "safe")]
119        {
120            let file = File::load(
121                rkyv::access::<ArchivedFile, rkyv::rancor::Error>(&bytes)
122                    .map_err(|e| println!("[ERROR]: {e:?}"))
123                    .ok()?,
124            )?;
125            let data = rkyv::access::<ArchivedScene, rkyv::rancor::Error>(&file)
126                .map_err(|e| println!("[ERROR]: {e:?}"))
127                .ok()?;
128            let tex = data
129                .images
130                .as_ref()
131                .map(rkyv::vec::ArchivedVec::len)
132                .unwrap_or(0);
133            let mat = data
134                .materials
135                .as_ref()
136                .map(rkyv::vec::ArchivedVec::len)
137                .unwrap_or(0);
138            if !data
139                .materials
140                .as_ref()
141                .map(|m| {
142                    m.iter()
143                        .filter_map(ArchivedMaterial::max_texture_idx)
144                        .max()
145                        .map(|x| x as usize)
146                        .map(|max| max < tex)
147                })
148                .flatten()
149                .unwrap_or(true)
150            {
151                println!("[ERROR]: images len is less than image index in material!");
152                None
153            } else if !data.meshes.as_ref().is_some_and(|m| {
154                m.iter()
155                    .filter_map(ArchivedMesh::material)
156                    .map(|x| x as usize)
157                    .all(|m| m < mat)
158            }) {
159                println!("[ERROR]: materials len is less than material index in mesh!");
160                None
161            } else if data
162                .meshes
163                .as_ref()
164                .is_some_and(|m| m.iter().any(ArchivedMesh::isnt_right))
165            {
166                println!("[ERROR]: mesh attributes DOESNT have the same len!");
167                None
168            } else {
169                Some(
170                    rkyv::deserialize::<Self, rkyv::rancor::Error>(data)
171                        .map_err(|e| println!("[ERROR]: {e:?}"))
172                        .ok()?,
173                )
174            }
175        }
176        #[cfg(not(feature = "safe"))]
177        {
178            let file = File::load(unsafe { rkyv::access_unchecked::<ArchivedFile>(&bytes) })?;
179            let data = unsafe { rkyv::access_unchecked::<ArchivedScene>(&file) };
180            Some(
181                rkyv::deserialize::<Self, rkyv::rancor::Error>(data)
182                    .map_err(|e| println!("[ERROR]: {e:?}"))
183                    .ok()?,
184            )
185        }
186    }
187    pub fn save(&self, path: &str) -> Result<(), ()> {
188        use std::io::Write;
189        let mut file = std::fs::File::create(path).map_err(|e| println!("[ERROR]: {e:?}"))?;
190        let bytes =
191            rkyv::to_bytes::<rkyv::rancor::Error>(self).map_err(|e| println!("[ERROR]: {e:?}"))?;
192        let bytes = rkyv::to_bytes::<rkyv::rancor::Error>(&File::save(&bytes))
193            .map_err(|e| println!("[ERROR]: {e:?}"))?;
194        file.write_all(&bytes)
195            .map_err(|e| println!("[ERROR]: {e:?}"))?;
196        Ok(())
197    }
198}