mod loader;
pub use loader::*;
mod raw_assets;
pub use raw_assets::*;
#[cfg(not(target_arch = "wasm32"))]
mod saver;
#[cfg(not(target_arch = "wasm32"))]
pub use saver::*;
#[cfg(feature = "obj")]
mod obj;
#[cfg(feature = "stl")]
mod stl;
#[cfg(feature = "gltf")]
mod gltf;
#[cfg(feature = "image")]
mod img;
#[cfg(feature = "vol")]
mod vol;
#[cfg(feature = "pcd")]
mod pcd;
#[cfg(feature = "3mf")]
#[path = "io/3mf.rs"]
mod three_mf;
pub fn deserialize<T: Deserialize>(key: &str, bytes: Vec<u8>) -> crate::Result<T> {
let mut assets = RawAssets::new();
assets.insert(key, bytes);
assets.deserialize(key)
}
#[cfg(not(target_arch = "wasm32"))]
pub fn load_and_deserialize<T: Deserialize>(path: impl AsRef<std::path::Path>) -> crate::Result<T> {
load(&[&path])?.deserialize(path)
}
pub async fn load_and_deserialize_async<T: Deserialize>(
path: impl AsRef<std::path::Path>,
) -> crate::Result<T> {
load_async(&[&path]).await?.deserialize(path)
}
#[cfg(not(target_arch = "wasm32"))]
pub fn serialize_and_save<T: Serialize>(
path: impl AsRef<std::path::Path>,
data: T,
) -> crate::Result<()> {
save(&data.serialize(path)?)
}
pub trait Deserialize: Sized {
fn deserialize(
path: impl AsRef<std::path::Path>,
raw_assets: &mut RawAssets,
) -> crate::Result<Self>;
}
pub trait Serialize: Sized {
fn serialize(&self, path: impl AsRef<std::path::Path>) -> crate::Result<RawAssets>;
}
use crate::{Error, Geometry, Result};
use std::collections::HashSet;
use std::path::{Path, PathBuf};
impl Deserialize for crate::Texture2D {
fn deserialize(path: impl AsRef<std::path::Path>, raw_assets: &mut RawAssets) -> Result<Self> {
let path = raw_assets.match_path(path.as_ref())?;
let extension = path
.extension()
.map(|e| e.to_str().unwrap())
.unwrap_or("image")
.to_string();
let data_url_bytes = if is_data_url(&path) {
Some(parse_data_url(path.to_str().unwrap())?)
} else {
None
};
#[allow(unused_variables)]
let bytes = if let Some(bytes) = data_url_bytes.as_ref() {
bytes
} else {
raw_assets.get(&path)?
};
if "svg" == extension {
#[cfg(not(feature = "svg"))]
return Err(Error::FeatureMissing("svg".to_string()));
#[cfg(feature = "svg")]
img::deserialize_svg(path, bytes)
} else {
#[cfg(not(feature = "image"))]
return Err(Error::FeatureMissing(extension));
#[cfg(feature = "image")]
img::deserialize_img(path, bytes)
}
}
}
impl Serialize for crate::Texture2D {
fn serialize(&self, path: impl AsRef<Path>) -> Result<RawAssets> {
let path = path.as_ref();
#[cfg(not(feature = "image"))]
return Err(Error::FeatureMissing(
path.extension()
.map(|e| e.to_str().unwrap())
.unwrap_or("image")
.to_string(),
));
#[cfg(feature = "image")]
img::serialize_img(self, path)
}
}
impl Deserialize for crate::Scene {
fn deserialize(path: impl AsRef<Path>, raw_assets: &mut RawAssets) -> Result<Self> {
let path = raw_assets.match_path(path.as_ref())?;
match path.extension().map(|e| e.to_str().unwrap()).unwrap_or("") {
"gltf" | "glb" => {
#[cfg(not(feature = "gltf"))]
return Err(Error::FeatureMissing("gltf".to_string()));
#[cfg(feature = "gltf")]
gltf::deserialize_gltf(raw_assets, &path)
}
"obj" => {
#[cfg(not(feature = "obj"))]
return Err(Error::FeatureMissing("obj".to_string()));
#[cfg(feature = "obj")]
obj::deserialize_obj(raw_assets, &path)
}
"stl" => {
#[cfg(not(feature = "stl"))]
return Err(Error::FeatureMissing("stl".to_string()));
#[cfg(feature = "stl")]
stl::deserialize_stl(raw_assets, &path)
}
"pcd" => {
#[cfg(not(feature = "pcd"))]
return Err(Error::FeatureMissing("pcd".to_string()));
#[cfg(feature = "pcd")]
pcd::deserialize_pcd(raw_assets, &path)
}
"3mf" => {
#[cfg(not(feature = "3mf"))]
return Err(Error::FeatureMissing("3mf".to_string()));
#[cfg(feature = "3mf")]
three_mf::deserialize_3mf(raw_assets, &path)
}
_ => Err(Error::FailedDeserialize(path.to_str().unwrap().to_string())),
}
}
}
impl Deserialize for crate::Model {
fn deserialize(path: impl AsRef<Path>, raw_assets: &mut RawAssets) -> Result<Self> {
let scene = crate::Scene::deserialize(path, raw_assets)?;
Ok(scene.into())
}
}
impl Serialize for crate::Scene {
fn serialize(&self, path: impl AsRef<Path>) -> Result<RawAssets> {
let path = path.as_ref();
match path.extension().map(|e| e.to_str().unwrap()).unwrap_or("") {
"3mf" => {
#[cfg(not(feature = "3mf"))]
return Err(Error::FeatureMissing("3mf".to_string()));
#[cfg(feature = "3mf")]
{
let bytes = three_mf::serialize_3mf(self)?;
let mut raw_assets = RawAssets::new();
raw_assets.insert(path, bytes);
Ok(raw_assets)
}
}
_ => Err(Error::FailedSerialize(path.to_str().unwrap().to_string())),
}
}
}
impl Deserialize for crate::VoxelGrid {
fn deserialize(path: impl AsRef<Path>, raw_assets: &mut RawAssets) -> Result<Self> {
let path = raw_assets.match_path(path.as_ref())?;
match path.extension().map(|e| e.to_str().unwrap()).unwrap_or("") {
"vol" => {
#[cfg(not(feature = "vol"))]
return Err(Error::FeatureMissing("vol".to_string()));
#[cfg(feature = "vol")]
vol::deserialize_vol(raw_assets, &path)
}
_ => Err(Error::FailedDeserialize(path.to_str().unwrap().to_string())),
}
}
}
impl Deserialize for crate::Texture3D {
fn deserialize(path: impl AsRef<Path>, raw_assets: &mut RawAssets) -> Result<Self> {
let path = raw_assets.match_path(path.as_ref())?;
let voxel_grid = crate::VoxelGrid::deserialize(path, raw_assets)?;
Ok(voxel_grid.voxels)
}
}
impl Deserialize for crate::TriMesh {
fn deserialize(path: impl AsRef<Path>, raw_assets: &mut RawAssets) -> Result<Self> {
let path = path.as_ref();
let model = crate::Model::deserialize(path, raw_assets)?;
model
.geometries
.into_iter()
.find_map(|p| {
if let Geometry::Triangles(mesh) = p.geometry {
Some(mesh)
} else {
None
}
})
.ok_or_else(|| {
Error::FailedConvertion(
"a triangle mesh".to_owned(),
path.to_str().unwrap().to_owned(),
)
})
}
}
impl Deserialize for crate::PointCloud {
fn deserialize(path: impl AsRef<Path>, raw_assets: &mut RawAssets) -> Result<Self> {
let path = path.as_ref();
let model = crate::Model::deserialize(path, raw_assets)?;
model
.geometries
.into_iter()
.find_map(|p| {
if let Geometry::Points(point_cloud) = p.geometry {
Some(point_cloud)
} else {
None
}
})
.ok_or_else(|| {
Error::FailedConvertion(
"a point cloud".to_owned(),
path.to_str().unwrap().to_owned(),
)
})
}
}
fn get_dependencies(raw_assets: &RawAssets) -> Vec<PathBuf> {
#[allow(unused_mut)]
let mut dependencies = HashSet::new();
for (path, _) in raw_assets.iter() {
match path.extension().map(|e| e.to_str().unwrap()).unwrap_or("") {
"gltf" | "glb" => {
#[cfg(feature = "gltf")]
dependencies.extend(gltf::dependencies(raw_assets, path));
}
"obj" => {
#[cfg(feature = "obj")]
dependencies.extend(obj::dependencies_obj(raw_assets, path));
}
"mtl" => {
#[cfg(feature = "obj")]
dependencies.extend(obj::dependencies_mtl(raw_assets, path));
}
_ => {}
}
}
dependencies
.into_iter()
.filter(|d| !raw_assets.contains_key(d))
.collect()
}
fn is_data_url(path: &Path) -> bool {
path.to_str()
.map(|s| s.starts_with("data:"))
.unwrap_or(false)
}
#[allow(unused_variables)]
fn parse_data_url(path: &str) -> Result<Vec<u8>> {
#[cfg(feature = "data-url")]
{
let url = data_url::DataUrl::process(path)
.map_err(|e| Error::FailedParsingDataUrl(path.to_string(), format!("{:?}", e)))?;
let (body, _) = url
.decode_to_vec()
.map_err(|e| Error::FailedParsingDataUrl(path.to_string(), format!("{:?}", e)))?;
Ok(body)
}
#[cfg(not(feature = "data-url"))]
Err(Error::FeatureMissing("data-url".to_string()))
}