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}