1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
//!
//! Contains functionality to load any type of asset runtime as well as parsers for common 3D assets.
//! Also includes functionality to save data which is limited to native.
//!
//!
//! A typical use-case is to load and deserialize assets:
//! ```
//! use three_d_asset::io::*;
//! use three_d_asset::{Texture2D, Model};
//!
//! let mut assets = load(&["test_data/test.png", "test_data/cube.obj"]).unwrap();
//! let texture: Texture2D = assets.deserialize("test.png").unwrap();
//! let model: Model = assets.deserialize("cube.obj").unwrap();
//! ```
//!
//! Or serialize and save assets:
//! ```
//! use three_d_asset::io::*;
//! use three_d_asset::{Texture2D, TextureData};
//!
//! let texture = Texture2D {
//!     data: TextureData::RgbaU8(vec![
//!         [0, 0, 0, 255],
//!         [255, 0, 0, 255],
//!         [0, 255, 0, 255],
//!         [0, 0, 255, 255],
//!     ]),
//!     width: 2,
//!     height: 2,
//!     ..Default::default()
//! };
//! let assets = texture.serialize("test_data/test.png").unwrap();
//! save(&assets).unwrap();
//! ```
//!

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 = "gltf")]
mod gltf;

#[cfg(feature = "image")]
mod img;

#[cfg(feature = "vol")]
mod vol;

///
/// Implemented for assets that can be deserialized after being loaded (see also [load] and [RawAssets::deserialize]).
///
pub trait Deserialize: Sized {
    ///
    /// See [RawAssets::deserialize].
    ///
    fn deserialize(
        path: impl AsRef<std::path::Path>,
        raw_assets: &mut RawAssets,
    ) -> crate::Result<Self>;
}

///
/// Implemented for assets that can be serialized before being saved (see also [save]).
///
pub trait Serialize: Sized {
    ///
    /// Serialize the asset into a list of raw assets which consist of byte arrays and related path to where they should be saved (see also [save]).
    /// The path given as input is the path to the main raw asset.
    ///
    fn serialize(&self, path: impl AsRef<std::path::Path>) -> crate::Result<RawAssets>;
}

use crate::{Error, Result};
use std::path::Path;

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)?;
        #[allow(unused_variables)]
        let bytes = raw_assets.get(&path)?;

        #[cfg(not(feature = "image"))]
        return Err(Error::FeatureMissing(
            path.extension()
                .map(|e| e.to_str().unwrap())
                .unwrap_or("image")
                .to_string(),
            path.to_str().unwrap().to_string(),
        ));

        #[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(),
            path.to_str().unwrap().to_string(),
        ));

        #[cfg(feature = "image")]
        img::serialize_img(self, path)
    }
}

impl Deserialize for crate::Model {
    fn deserialize(path: impl AsRef<Path>, raw_assets: &mut RawAssets) -> Result<Self> {
        let path = raw_assets.match_path(path)?;
        match path.extension().map(|e| e.to_str().unwrap()).unwrap_or("") {
            "gltf" | "glb" => {
                #[cfg(not(feature = "gltf"))]
                return Err(Error::FeatureMissing(
                    "gltf".to_string(),
                    path.to_str().unwrap().to_string(),
                ));

                #[cfg(feature = "gltf")]
                gltf::deserialize_gltf(raw_assets, path)
            }
            "obj" => {
                #[cfg(not(feature = "obj"))]
                return Err(Error::FeatureMissing(
                    "obj".to_string(),
                    path.to_str().unwrap().to_string(),
                ));

                #[cfg(feature = "obj")]
                obj::deserialize_obj(raw_assets, path)
            }
            _ => Err(Error::FailedDeserialize(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)?;
        match path.extension().map(|e| e.to_str().unwrap()).unwrap_or("") {
            "vol" => {
                #[cfg(feature = "vol")]
                let result = vol::deserialize_vol(raw_assets, path);

                #[cfg(not(feature = "vol"))]
                let result = Err(Error::FeatureMissing(
                    "vol".to_string(),
                    path.to_str().unwrap().to_string(),
                ));
                result
            }
            _ => Err(Error::FailedDeserialize(path.to_str().unwrap().to_string())),
        }
    }
}