1#![cfg_attr(docsrs, feature(doc_cfg))]
2#![warn(missing_docs)]
4
5pub mod prelude;
15
16mod camera;
17pub use camera::*;
18
19pub mod texture;
20pub use texture::*;
21
22pub mod material;
23pub use material::*;
24
25pub mod geometry;
26pub use geometry::*;
27
28pub mod volume;
29pub use volume::*;
30
31mod animation;
32pub use animation::*;
33
34#[derive(Debug, Clone)]
44#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
45pub struct Scene {
46 pub name: String,
48 pub children: Vec<Node>,
50 pub materials: Vec<PbrMaterial>,
52}
53
54impl Default for Scene {
55 fn default() -> Self {
56 Self {
57 name: "scene".to_owned(),
58 children: Vec::new(),
59 materials: Vec::new(),
60 }
61 }
62}
63
64#[derive(Debug, Clone)]
70#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
71pub struct Node {
72 pub name: String,
74 pub children: Vec<Node>,
76 pub transformation: Mat4,
78 pub animations: Vec<(Option<String>, KeyFrames)>,
81 pub geometry: Option<Geometry>,
83 pub material_index: Option<usize>,
85}
86
87impl Default for Node {
88 fn default() -> Self {
89 Self {
90 name: "node".to_owned(),
91 children: Vec::new(),
92 transformation: Mat4::identity(),
93 animations: Vec::new(),
94 geometry: None,
95 material_index: None,
96 }
97 }
98}
99
100#[derive(Debug, Clone)]
105#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
106pub struct Model {
107 pub name: String,
109 pub geometries: Vec<Primitive>,
111 pub materials: Vec<PbrMaterial>,
113}
114
115#[derive(Debug, Clone)]
120#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
121pub struct Primitive {
122 pub name: String,
124 pub transformation: Mat4,
126 pub animations: Vec<KeyFrameAnimation>,
129 pub geometry: Geometry,
131 pub material_index: Option<usize>,
133}
134
135impl std::ops::Deref for Primitive {
136 type Target = Geometry;
137 fn deref(&self) -> &Self::Target {
138 &self.geometry
139 }
140}
141
142impl std::ops::DerefMut for Primitive {
143 fn deref_mut(&mut self) -> &mut Self::Target {
144 &mut self.geometry
145 }
146}
147
148impl std::convert::From<Scene> for Model {
149 fn from(scene: Scene) -> Self {
150 let mut geometries = Vec::new();
151 for child in scene.children {
152 visit(child, Vec::new(), Mat4::identity(), &mut geometries);
153 }
154 Self {
155 name: scene.name,
156 materials: scene.materials,
157 geometries,
158 }
159 }
160}
161
162fn visit(
163 node: Node,
164 mut animations: Vec<KeyFrameAnimation>,
165 transformation: Mat4,
166 geometries: &mut Vec<Primitive>,
167) {
168 let mut transformation = transformation * node.transformation;
169 if !node.animations.is_empty() {
170 for (animation_name, key_frames) in node.animations {
171 if let Some(i) = animations.iter().position(|a| a.name == animation_name) {
172 animations[i]
173 .key_frames
174 .push((transformation, std::sync::Arc::new(key_frames)));
175 } else {
176 animations.push(KeyFrameAnimation {
177 name: animation_name,
178 key_frames: vec![(transformation, std::sync::Arc::new(key_frames))],
179 });
180 }
181 }
182 transformation = Mat4::identity();
183 };
184 if let Some(geometry) = node.geometry {
185 geometries.push(Primitive {
186 name: node.name.clone(),
187 transformation,
188 animations: animations.clone(),
189 geometry,
190 material_index: node.material_index,
191 });
192 }
193 for child in node.children {
194 visit(child, animations.clone(), transformation, geometries);
195 }
196}
197
198pub mod io;
199
200pub type Result<T> = std::result::Result<T, Error>;
202
203use thiserror::Error;
204#[derive(Error, Debug)]
208#[allow(missing_docs)]
209pub enum Error {
210 #[error("{0} buffer length must be {1}, actual length is {2}")]
211 InvalidBufferLength(String, usize, usize),
212 #[error("the number of indices must be divisable by 3, actual count is {0}")]
213 InvalidNumberOfIndices(usize),
214 #[error("the max index {0} must be less than the number of vertices {1}")]
215 InvalidIndices(usize, usize),
216 #[error("the transformation matrix cannot be inverted and is therefore invalid")]
217 FailedInvertingTransformationMatrix,
218 #[cfg(feature = "image")]
219 #[error("error while parsing an image file")]
220 Image(#[from] image::ImageError),
221
222 #[cfg(feature = "svg")]
223 #[error("error while parsing svg file")]
224 Svg(#[from] resvg::usvg::Error),
225
226 #[cfg(feature = "obj")]
227 #[error("error while parsing an .obj file")]
228 Obj(#[from] wavefront_obj::ParseError),
229
230 #[cfg(feature = "pcd")]
231 #[error("error while parsing an .pcd file")]
232 Pcd(#[from] pcd_rs::Error),
233
234 #[cfg(any(not(target_arch = "wasm32"), feature = "stl"))]
235 #[error("io error")]
236 IO(#[from] std::io::Error),
237 #[cfg(feature = "gltf")]
238 #[error("error while parsing a .gltf file")]
239 Gltf(#[from] ::gltf::Error),
240 #[cfg(feature = "gltf")]
241 #[error("the .gltf file contain corrupt buffer data")]
242 GltfCorruptData,
243 #[cfg(feature = "gltf")]
244 #[error("the .gltf file contain missing buffer data")]
245 GltfMissingData,
246 #[error("the .vol file contain wrong data size")]
247 VolCorruptData,
248 #[cfg(not(target_arch = "wasm32"))]
249 #[error("error while loading the file {0}: {1}")]
250 FailedLoading(String, std::io::Error),
251 #[cfg(feature = "reqwest")]
252 #[error("error while loading the url {0}: {1}")]
253 FailedLoadingUrlWithReqwest(String, reqwest::Error),
254 #[cfg(feature = "reqwest")]
255 #[error("error while loading the url {0}: {1}")]
256 FailedLoadingUrl(String, String),
257 #[cfg(feature = "reqwest")]
258 #[error("error while parsing the url {0}")]
259 FailedParsingUrl(String),
260 #[cfg(feature = "data-url")]
261 #[error("error while parsing data-url {0}: {1}")]
262 FailedParsingDataUrl(String, String),
263 #[error("tried to use {0} which was not loaded or otherwise added to the raw assets")]
264 NotLoaded(String),
265 #[error("the feature {0} is needed")]
266 FeatureMissing(String),
267 #[error("failed to deserialize the file {0}")]
268 FailedDeserialize(String),
269 #[error("failed to serialize the file {0}")]
270 FailedSerialize(String),
271 #[error("failed to find {0} in the file {1}")]
272 FailedConvertion(String, String),
273}