1#![deny(missing_docs)]
2
3mod scene;
23mod utils;
24
25use std::error::Error;
26use std::path::Path;
27use utils::GltfData;
28
29pub use scene::*;
30
31pub fn load<P>(path: P) -> Result<Vec<Scene>, Box<dyn Error + Send + Sync>>
46where
47 P: AsRef<Path>,
48{
49 let (doc, buffers, _images) = gltf::import(&path)?;
51
52 let mut data = GltfData::new(buffers, &path);
54
55 let mut res = vec![];
57 for scene in doc.scenes() {
58 res.push(Scene::load(scene, &mut data));
59 }
60 Ok(res)
61}
62
63#[cfg(test)]
64mod tests {
65 use crate::model::Mode;
66 use crate::*;
67 use cgmath::*;
68
69 macro_rules! assert_delta {
70 ($x:expr, $y:expr, $d:expr) => {
71 if !($x - $y < $d || $y - $x < $d) {
72 panic!();
73 }
74 };
75 }
76
77 #[test]
78 fn check_cube_glb() {
79 let scenes = load("tests/cube.glb").unwrap();
80 assert_eq!(scenes.len(), 1);
81 let scene = &scenes[0];
82 assert_eq!(scene.cameras.len(), 1);
83 assert_eq!(scene.lights.len(), 3);
84 assert_eq!(scene.models.len(), 1);
85 }
86
87 #[test]
88 fn check_cube_glb_with_color() {
89 let scenes = load("tests/cube_color.glb").unwrap();
90 assert_eq!(scenes.len(), 1);
91 let scene = &scenes[0];
92 assert_eq!(scene.models.len(), 1);
93 assert!(scene.models[0].has_colors());
94 assert_eq!(scene.models[0].indices().unwrap().len(), 36);
95 }
96
97 #[test]
98 fn check_different_meshes() {
99 let scenes = load("tests/complete.glb").unwrap();
100 assert_eq!(scenes.len(), 1);
101 let scene = &scenes[0];
102 for model in scene.models.iter() {
103 match model.mode() {
104 Mode::Triangles | Mode::TriangleFan | Mode::TriangleStrip => {
105 assert!(model.triangles().is_ok());
106 }
107 Mode::Lines | Mode::LineLoop | Mode::LineStrip => {
108 assert!(model.lines().is_ok());
109 }
110 Mode::Points => {
111 assert!(model.points().is_ok());
112 }
113 }
114 }
115 }
116
117 #[test]
118 fn check_cube_gltf() {
119 let _ = load("tests/cube_classic.gltf").unwrap();
120 }
121
122 #[test]
123 fn check_default_texture() {
124 let _ = load("tests/box_sparse.glb").unwrap();
125 }
126
127 #[test]
128 fn check_camera() {
129 let scenes = load("tests/cube.glb").unwrap();
130 let scene = &scenes[0];
131 let cam = &scene.cameras[0];
132 assert!((cam.position() - Vector3::new(7.3589, 4.9583, 6.9258)).magnitude() < 0.1);
133 }
134
135 #[test]
136 fn check_lights() {
137 let scenes = load("tests/cube.glb").unwrap();
138 let scene = &scenes[0];
139 for light in scene.lights.iter() {
140 match light {
141 Light::Directional {
142 direction,
143 color: _,
144 intensity,
145 ..
146 } => {
147 assert!((direction - Vector3::new(0.6068, -0.7568, -0.2427)).magnitude() < 0.1);
148 assert_delta!(intensity, 542., 0.01);
149 }
150 Light::Point {
151 position,
152 color: _,
153 intensity,
154 ..
155 } => {
156 assert!((position - Vector3::new(4.0762, 5.9039, -1.0055)).magnitude() < 0.1);
157 assert_delta!(intensity, 1000., 0.01);
158 }
159 Light::Spot {
160 position,
161 direction,
162 color: _,
163 intensity,
164 inner_cone_angle: _,
165 outer_cone_angle,
166 ..
167 } => {
168 assert!((position - Vector3::new(4.337, 15.541, -8.106)).magnitude() < 0.1);
169 assert!(
170 (direction - Vector3::new(-0.0959, -0.98623, 0.1346)).magnitude() < 0.1
171 );
172 assert_delta!(intensity, 42., 0.01);
173 assert_delta!(outer_cone_angle, 40., 0.01);
174 }
175 }
176 }
177 }
178
179 #[test]
180 fn check_model() {
181 let scenes = load("tests/cube.glb").unwrap();
182 let scene = &scenes[0];
183 let model = &scene.models[0];
184 assert!(model.has_normals());
185 assert!(model.has_tex_coords());
186 assert!(model.has_tangents());
187 for t in model.triangles().unwrap().iter().flatten() {
188 let pos = t.position;
189 assert!(pos.x > -0.01 && pos.x < 1.01);
190 assert!(pos.y > -0.01 && pos.y < 1.01);
191 assert!(pos.z > -0.01 && pos.z < 1.01);
192
193 assert_eq!(t.tangent.w.abs(), 1.);
195 }
196 }
197
198 #[test]
199 fn check_material() {
200 let scenes = load("tests/head.glb").unwrap();
201 let scene = &scenes[0];
202 let mat = &scene.models[0].material;
203 assert!(mat.pbr.base_color_texture.is_some());
204 assert_eq!(mat.pbr.metallic_factor, 0.);
205 }
206
207 #[test]
208 fn check_invalid_path() {
209 assert!(load("tests/invalid.glb").is_err());
210 }
211}