1mod loader;
38pub use loader::*;
39
40mod raw_assets;
41pub use raw_assets::*;
42
43#[cfg(not(target_arch = "wasm32"))]
44mod saver;
45#[cfg(not(target_arch = "wasm32"))]
46pub use saver::*;
47
48#[cfg(feature = "obj")]
49mod obj;
50
51#[cfg(feature = "stl")]
52mod stl;
53
54#[cfg(feature = "gltf")]
55mod gltf;
56
57#[cfg(feature = "image")]
58mod img;
59
60#[cfg(feature = "vol")]
61mod vol;
62
63#[cfg(feature = "pcd")]
64mod pcd;
65
66pub fn deserialize<T: Deserialize>(bytes: Vec<u8>) -> crate::Result<T> {
72 let mut assets = RawAssets::new();
73 assets.insert("", bytes);
74 assets.deserialize("")
75}
76
77#[cfg(not(target_arch = "wasm32"))]
81pub fn load_and_deserialize<T: Deserialize>(path: impl AsRef<std::path::Path>) -> crate::Result<T> {
82 load(&[&path])?.deserialize(path)
83}
84
85pub async fn load_and_deserialize_async<T: Deserialize>(
89 path: impl AsRef<std::path::Path>,
90) -> crate::Result<T> {
91 load_async(&[&path]).await?.deserialize(path)
92}
93
94#[cfg(not(target_arch = "wasm32"))]
98pub fn serialize_and_save<T: Serialize>(
99 path: impl AsRef<std::path::Path>,
100 data: T,
101) -> crate::Result<()> {
102 save(&data.serialize(path)?)
103}
104
105pub trait Deserialize: Sized {
109 fn deserialize(
113 path: impl AsRef<std::path::Path>,
114 raw_assets: &mut RawAssets,
115 ) -> crate::Result<Self>;
116}
117
118pub trait Serialize: Sized {
122 fn serialize(&self, path: impl AsRef<std::path::Path>) -> crate::Result<RawAssets>;
127}
128
129use crate::{Error, Geometry, Result};
130use std::collections::HashSet;
131use std::path::{Path, PathBuf};
132
133impl Deserialize for crate::Texture2D {
134 fn deserialize(path: impl AsRef<std::path::Path>, raw_assets: &mut RawAssets) -> Result<Self> {
135 let path = raw_assets.match_path(path.as_ref())?;
136 let extension = path
137 .extension()
138 .map(|e| e.to_str().unwrap())
139 .unwrap_or("image")
140 .to_string();
141 #[allow(unused_variables)]
142 let bytes = raw_assets.get(&path)?;
143
144 if "svg" == extension {
145 #[cfg(not(feature = "svg"))]
147 return Err(Error::FeatureMissing("svg".to_string()));
148
149 #[cfg(feature = "svg")]
150 img::deserialize_svg(path, bytes)
151 } else {
152 #[cfg(not(feature = "image"))]
153 return Err(Error::FeatureMissing(extension));
154
155 #[cfg(feature = "image")]
156 img::deserialize_img(path, bytes)
157 }
158 }
159}
160
161impl Serialize for crate::Texture2D {
162 fn serialize(&self, path: impl AsRef<Path>) -> Result<RawAssets> {
163 let path = path.as_ref();
164
165 #[cfg(not(feature = "image"))]
166 return Err(Error::FeatureMissing(
167 path.extension()
168 .map(|e| e.to_str().unwrap())
169 .unwrap_or("image")
170 .to_string(),
171 ));
172
173 #[cfg(feature = "image")]
174 img::serialize_img(self, path)
175 }
176}
177
178impl Deserialize for crate::Scene {
179 fn deserialize(path: impl AsRef<Path>, raw_assets: &mut RawAssets) -> Result<Self> {
180 let path = raw_assets.match_path(path.as_ref())?;
181 match path.extension().map(|e| e.to_str().unwrap()).unwrap_or("") {
182 "gltf" | "glb" => {
183 #[cfg(not(feature = "gltf"))]
184 return Err(Error::FeatureMissing("gltf".to_string()));
185
186 #[cfg(feature = "gltf")]
187 gltf::deserialize_gltf(raw_assets, &path)
188 }
189 "obj" => {
190 #[cfg(not(feature = "obj"))]
191 return Err(Error::FeatureMissing("obj".to_string()));
192
193 #[cfg(feature = "obj")]
194 obj::deserialize_obj(raw_assets, &path)
195 }
196 "stl" => {
197 #[cfg(not(feature = "stl"))]
198 return Err(Error::FeatureMissing("stl".to_string()));
199
200 #[cfg(feature = "stl")]
201 stl::deserialize_stl(raw_assets, &path)
202 }
203 "pcd" => {
204 #[cfg(not(feature = "pcd"))]
205 return Err(Error::FeatureMissing("pcd".to_string()));
206
207 #[cfg(feature = "pcd")]
208 pcd::deserialize_pcd(raw_assets, &path)
209 }
210 _ => Err(Error::FailedDeserialize(path.to_str().unwrap().to_string())),
211 }
212 }
213}
214
215impl Deserialize for crate::Model {
216 fn deserialize(path: impl AsRef<Path>, raw_assets: &mut RawAssets) -> Result<Self> {
217 let scene = crate::Scene::deserialize(path, raw_assets)?;
218 Ok(scene.into())
219 }
220}
221
222impl Deserialize for crate::VoxelGrid {
223 fn deserialize(path: impl AsRef<Path>, raw_assets: &mut RawAssets) -> Result<Self> {
224 let path = raw_assets.match_path(path.as_ref())?;
225 match path.extension().map(|e| e.to_str().unwrap()).unwrap_or("") {
226 "vol" => {
227 #[cfg(not(feature = "vol"))]
228 return Err(Error::FeatureMissing("vol".to_string()));
229
230 #[cfg(feature = "vol")]
231 vol::deserialize_vol(raw_assets, &path)
232 }
233 _ => Err(Error::FailedDeserialize(path.to_str().unwrap().to_string())),
234 }
235 }
236}
237
238impl Deserialize for crate::Texture3D {
239 fn deserialize(path: impl AsRef<Path>, raw_assets: &mut RawAssets) -> Result<Self> {
240 let path = raw_assets.match_path(path.as_ref())?;
241 let voxel_grid = crate::VoxelGrid::deserialize(path, raw_assets)?;
242 Ok(voxel_grid.voxels)
243 }
244}
245
246impl Deserialize for crate::TriMesh {
247 fn deserialize(path: impl AsRef<Path>, raw_assets: &mut RawAssets) -> Result<Self> {
248 let path = path.as_ref();
249 let model = crate::Model::deserialize(path, raw_assets)?;
250 model
251 .geometries
252 .into_iter()
253 .find_map(|p| {
254 if let Geometry::Triangles(mesh) = p.geometry {
255 Some(mesh)
256 } else {
257 None
258 }
259 })
260 .ok_or_else(|| {
261 Error::FailedConvertion(
262 "a triangle mesh".to_owned(),
263 path.to_str().unwrap().to_owned(),
264 )
265 })
266 }
267}
268
269impl Deserialize for crate::PointCloud {
270 fn deserialize(path: impl AsRef<Path>, raw_assets: &mut RawAssets) -> Result<Self> {
271 let path = path.as_ref();
272 let model = crate::Model::deserialize(path, raw_assets)?;
273 model
274 .geometries
275 .into_iter()
276 .find_map(|p| {
277 if let Geometry::Points(point_cloud) = p.geometry {
278 Some(point_cloud)
279 } else {
280 None
281 }
282 })
283 .ok_or_else(|| {
284 Error::FailedConvertion(
285 "a point cloud".to_owned(),
286 path.to_str().unwrap().to_owned(),
287 )
288 })
289 }
290}
291
292fn get_dependencies(raw_assets: &RawAssets) -> Vec<PathBuf> {
293 #[allow(unused_mut)]
294 let mut dependencies = HashSet::new();
295 for (path, _) in raw_assets.iter() {
296 match path.extension().map(|e| e.to_str().unwrap()).unwrap_or("") {
297 "gltf" | "glb" => {
298 #[cfg(feature = "gltf")]
299 dependencies.extend(gltf::dependencies(raw_assets, path));
300 }
301 "obj" => {
302 #[cfg(feature = "obj")]
303 dependencies.extend(obj::dependencies_obj(raw_assets, path));
304 }
305 "mtl" => {
306 #[cfg(feature = "obj")]
307 dependencies.extend(obj::dependencies_mtl(raw_assets, path));
308 }
309 _ => {}
310 }
311 }
312 dependencies
313 .into_iter()
314 .filter(|d| !raw_assets.contains_key(d))
315 .collect()
316}