1#[cfg(feature = "extensions")]
2use serde_json::{Map, Value};
3
4use crate::math::*;
5use crate::{Camera, Document, Mesh, Skin};
6
7pub mod iter;
9
10#[derive(Clone, Debug)]
12pub enum Transform {
13 Matrix {
15 matrix: [[f32; 4]; 4],
17 },
18
19 Decomposed {
21 translation: [f32; 3],
23
24 rotation: [f32; 4],
26
27 scale: [f32; 3],
29 },
30}
31
32impl Transform {
33 pub fn matrix(self) -> [[f32; 4]; 4] {
38 match self {
39 Transform::Matrix { matrix } => matrix,
40 Transform::Decomposed {
41 translation: t,
42 rotation: r,
43 scale: s,
44 } => {
45 let t = Matrix4::from_translation(Vector3::new(t[0], t[1], t[2]));
46 let r = Matrix4::from_quaternion(Quaternion::new(r[3], r[0], r[1], r[2]));
47 let s = Matrix4::from_nonuniform_scale(s[0], s[1], s[2]);
48 (t * r * s).as_array()
49 }
50 }
51 }
52
53 pub fn decomposed(self) -> ([f32; 3], [f32; 4], [f32; 3]) {
58 match self {
59 Transform::Matrix { matrix: m } => {
60 let translation = [m[3][0], m[3][1], m[3][2]];
61 #[rustfmt::skip]
62 let mut i = Matrix3::new(
63 m[0][0], m[0][1], m[0][2],
64 m[1][0], m[1][1], m[1][2],
65 m[2][0], m[2][1], m[2][2],
66 );
67 let sx = i.x.magnitude();
68 let sy = i.y.magnitude();
69 let sz = i.determinant().signum() * i.z.magnitude();
70 let scale = [sx, sy, sz];
71 i.x.multiply(1.0 / sx);
72 i.y.multiply(1.0 / sy);
73 i.z.multiply(1.0 / sz);
74 let r = Quaternion::from_matrix(i);
75 let rotation = [r.v.x, r.v.y, r.v.z, r.s];
76 (translation, rotation, scale)
77 }
78 Transform::Decomposed {
79 translation,
80 rotation,
81 scale,
82 } => (translation, rotation, scale),
83 }
84 }
85}
86
87#[derive(Clone, Debug)]
92pub struct Node<'a> {
93 document: &'a Document,
95
96 index: usize,
98
99 json: &'a json::scene::Node,
101}
102
103#[derive(Clone, Debug)]
105pub struct Scene<'a> {
106 #[allow(dead_code)]
108 document: &'a Document,
109
110 index: usize,
112
113 json: &'a json::scene::Scene,
115}
116
117impl<'a> Node<'a> {
118 pub(crate) fn new(document: &'a Document, index: usize, json: &'a json::scene::Node) -> Self {
120 Self {
121 document,
122 index,
123 json,
124 }
125 }
126
127 pub fn index(&self) -> usize {
129 self.index
130 }
131
132 pub fn camera(&self) -> Option<Camera<'a>> {
134 self.json
135 .camera
136 .as_ref()
137 .map(|index| self.document.cameras().nth(index.value()).unwrap())
138 }
139
140 pub fn children(&self) -> iter::Children<'a> {
142 iter::Children {
143 document: self.document,
144 iter: self.json.children.as_ref().map_or([].iter(), |x| x.iter()),
145 }
146 }
147
148 #[cfg(feature = "extensions")]
150 #[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
151 pub fn extensions(&self) -> Option<&Map<String, Value>> {
152 let ext = self.json.extensions.as_ref()?;
153 Some(&ext.others)
154 }
155
156 #[cfg(feature = "extensions")]
158 #[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
159 pub fn extension_value(&self, ext_name: &str) -> Option<&Value> {
160 let ext = self.json.extensions.as_ref()?;
161 ext.others.get(ext_name)
162 }
163
164 pub fn extras(&self) -> &'a json::Extras {
166 &self.json.extras
167 }
168
169 #[cfg(feature = "KHR_lights_punctual")]
171 #[cfg_attr(docsrs, doc(cfg(feature = "KHR_lights_punctual")))]
172 pub fn light(&self) -> Option<crate::khr_lights_punctual::Light<'a>> {
173 if let Some(extensions) = self.json.extensions.as_ref() {
174 if let Some(khr_lights_punctual) = extensions.khr_lights_punctual.as_ref() {
175 let mut lights = self.document.lights().unwrap();
176 Some(lights.nth(khr_lights_punctual.light.value()).unwrap())
177 } else {
178 None
179 }
180 } else {
181 None
182 }
183 }
184
185 pub fn mesh(&self) -> Option<Mesh<'a>> {
187 self.json
188 .mesh
189 .as_ref()
190 .map(|index| self.document.meshes().nth(index.value()).unwrap())
191 }
192
193 #[cfg(feature = "names")]
195 pub fn name(&self) -> Option<&'a str> {
196 self.json.name.as_deref()
197 }
198
199 pub fn transform(&self) -> Transform {
201 if let Some(m) = self.json.matrix {
202 Transform::Matrix {
203 matrix: [
204 [m[0], m[1], m[2], m[3]],
205 [m[4], m[5], m[6], m[7]],
206 [m[8], m[9], m[10], m[11]],
207 [m[12], m[13], m[14], m[15]],
208 ],
209 }
210 } else {
211 Transform::Decomposed {
212 translation: self.json.translation.unwrap_or([0.0, 0.0, 0.0]),
213 rotation: self.json.rotation.unwrap_or_default().0,
214 scale: self.json.scale.unwrap_or([1.0, 1.0, 1.0]),
215 }
216 }
217 }
218
219 pub fn skin(&self) -> Option<Skin<'a>> {
221 self.json
222 .skin
223 .as_ref()
224 .map(|index| self.document.skins().nth(index.value()).unwrap())
225 }
226
227 pub fn weights(&self) -> Option<&'a [f32]> {
229 self.json.weights.as_deref()
230 }
231}
232
233impl<'a> Scene<'a> {
234 pub(crate) fn new(document: &'a Document, index: usize, json: &'a json::scene::Scene) -> Self {
236 Self {
237 document,
238 index,
239 json,
240 }
241 }
242
243 pub fn index(&self) -> usize {
245 self.index
246 }
247
248 #[cfg(feature = "extensions")]
250 #[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
251 pub fn extensions(&self) -> Option<&Map<String, Value>> {
252 let ext = self.json.extensions.as_ref()?;
253 Some(&ext.others)
254 }
255
256 #[cfg(feature = "extensions")]
258 #[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
259 pub fn extension_value(&self, ext_name: &str) -> Option<&Value> {
260 let ext = self.json.extensions.as_ref()?;
261 ext.others.get(ext_name)
262 }
263
264 pub fn extras(&self) -> &'a json::Extras {
266 &self.json.extras
267 }
268
269 #[cfg(feature = "names")]
271 pub fn name(&self) -> Option<&'a str> {
272 self.json.name.as_deref()
273 }
274
275 pub fn nodes(&self) -> iter::Nodes<'a> {
277 iter::Nodes {
278 document: self.document,
279 iter: self.json.nodes.iter(),
280 }
281 }
282}
283
284#[cfg(test)]
285mod tests {
286 use crate::math::*;
287 use crate::scene::Transform;
288 use std::f32::consts::PI;
289
290 fn rotate(x: f32, y: f32, z: f32, r: f32) -> [f32; 4] {
291 let r = Quaternion::from_axis_angle(Vector3::new(x, y, z).normalize(), r);
292 [r.v.x, r.v.y, r.v.z, r.s]
293 }
294
295 fn test_decompose(translation: [f32; 3], rotation: [f32; 4], scale: [f32; 3]) {
296 let matrix = Transform::Decomposed {
297 translation,
298 rotation,
299 scale,
300 }
301 .matrix();
302 let (translation, rotation, scale) = Transform::Matrix { matrix }.decomposed();
303 let check = Transform::Decomposed {
304 translation,
305 rotation,
306 scale,
307 }
308 .matrix();
309 assert_relative_eq!(
310 Matrix4::from_array(check),
311 Matrix4::from_array(matrix),
312 epsilon = 0.05
313 );
314 }
315
316 fn test_decompose_rotation(rotation: [f32; 4]) {
317 let translation = [1.0, -2.0, 3.0];
318 let scale = [1.0, 1.0, 1.0];
319 test_decompose(translation, rotation, scale);
320 }
321
322 fn test_decompose_scale(scale: [f32; 3]) {
323 let translation = [1.0, 2.0, 3.0];
324 let rotation = rotate(1.0, 0.0, 0.0, PI / 2.0);
325 test_decompose(translation, rotation, scale);
326 }
327
328 fn test_decompose_translation(translation: [f32; 3]) {
329 let rotation = [0.0, 0.0, 0.0, 1.0];
330 let scale = [1.0, 1.0, 1.0];
331 test_decompose(translation, rotation, scale);
332 }
333
334 #[test]
335 fn decompose_identity() {
336 let translation = [0.0, 0.0, 0.0];
337 let rotation = [0.0, 0.0, 0.0, 1.0];
338 let scale = [1.0, 1.0, 1.0];
339 test_decompose(translation, rotation, scale);
340 }
341
342 #[test]
343 fn decompose_translation_unit_x() {
344 let translation = [1.0, 0.0, 0.0];
345 test_decompose_translation(translation);
346 }
347
348 #[test]
349 fn decompose_translation_unit_y() {
350 let translation = [0.0, 1.0, 0.0];
351 test_decompose_translation(translation);
352 }
353
354 #[test]
355 fn decompose_translation_unit_z() {
356 let translation = [0.0, 0.0, 1.0];
357 test_decompose_translation(translation);
358 }
359
360 #[test]
361 fn decompose_translation_random0() {
362 let translation = [1.0, -1.0, 1.0];
363 test_decompose_translation(translation);
364 }
365
366 #[test]
367 fn decompose_translation_random1() {
368 let translation = [-1.0, -1.0, -1.0];
369 test_decompose_translation(translation);
370 }
371
372 #[test]
373 fn decompose_translation_random2() {
374 let translation = [-10.0, 100000.0, -0.0001];
375 test_decompose_translation(translation);
376 }
377
378 #[test]
379 fn decompose_rotation_xaxis() {
380 let rotation = rotate(1.0, 0.0, 0.0, PI / 2.0);
381 test_decompose_rotation(rotation);
382 }
383
384 #[test]
385 fn decompose_rotation_yaxis() {
386 let rotation = rotate(0.0, 1.0, 0.0, PI / 2.0);
387 test_decompose_rotation(rotation);
388 }
389
390 #[test]
391 fn decompose_rotation_zaxis() {
392 let rotation = rotate(0.0, 0.0, 1.0, PI / 2.0);
393 test_decompose_rotation(rotation);
394 }
395
396 #[test]
397 fn decompose_rotation_negative_xaxis() {
398 let rotation = rotate(-1.0, 0.0, 0.0, PI / 2.0);
399 test_decompose_rotation(rotation);
400 }
401
402 #[test]
403 fn decompose_rotation_negative_yaxis() {
404 let rotation = rotate(0.0, -1.0, 0.0, PI / 2.0);
405 test_decompose_rotation(rotation);
406 }
407
408 #[test]
409 fn decompose_rotation_negative_zaxis() {
410 let rotation = rotate(0.0, 0.0, -1.0, PI / 2.0);
411 test_decompose_rotation(rotation);
412 }
413
414 #[test]
415 fn decompose_rotation_eighth_turn() {
416 let rotation = rotate(1.0, 0.0, 0.0, PI / 4.0);
417 test_decompose_rotation(rotation);
418 }
419
420 #[test]
421 fn decompose_rotation_negative_quarter_turn() {
422 let rotation = rotate(0.0, 1.0, 0.0, -PI / 2.0);
423 test_decompose_rotation(rotation);
424 }
425
426 #[test]
427 fn decompose_rotation_half_turn() {
428 let rotation = rotate(0.0, 0.0, 1.0, PI);
429 test_decompose_rotation(rotation);
430 }
431
432 #[test]
433 fn decompose_rotation_zero_turn_xaxis() {
434 let rotation = rotate(1.0, 0.0, 0.0, 0.0);
435 test_decompose_rotation(rotation);
436 }
437
438 #[test]
439 fn decompose_rotation_zero_turn_yaxis() {
440 let rotation = rotate(0.0, 1.0, 0.0, 0.0);
441 test_decompose_rotation(rotation);
442 }
443
444 #[test]
445 fn decompose_rotation_zero_turn_zaxis() {
446 let rotation = rotate(0.0, 0.0, 1.0, 0.0);
447 test_decompose_rotation(rotation);
448 }
449
450 #[test]
451 fn decompose_rotation_full_turn() {
452 let rotation = rotate(1.0, 0.0, 0.0, 2.0 * PI);
453 test_decompose_rotation(rotation);
454 }
455
456 #[test]
457 fn decompose_rotation_random0() {
458 let rotation = rotate(1.0, 1.0, 1.0, PI / 3.0);
459 test_decompose_rotation(rotation);
460 }
461
462 #[test]
463 fn decompose_rotation_random1() {
464 let rotation = rotate(1.0, -1.0, 1.0, -PI / 6.0);
465 test_decompose_rotation(rotation);
466 }
467
468 #[test]
469 fn decompose_uniform_scale_up() {
470 let scale = [100.0, 100.0, 100.0];
471 test_decompose_scale(scale);
472 }
473
474 #[test]
475 fn decompose_uniform_scale_down() {
476 let scale = [0.01, 0.01, 0.01];
477 test_decompose_scale(scale);
478 }
479
480 #[test]
481 fn decompose_xscale_up() {
482 let scale = [100.0, 1.0, 1.0];
483 test_decompose_scale(scale);
484 }
485
486 #[test]
487 fn decompose_xscale_down() {
488 let scale = [0.001, 1.0, 1.0];
489 test_decompose_scale(scale);
490 }
491
492 #[test]
493 fn decompose_yscale_up() {
494 let scale = [1.0, 100.0, 1.0];
495 test_decompose_scale(scale);
496 }
497
498 #[test]
499 fn decompose_yscale_down() {
500 let scale = [1.0, 0.001, 1.0];
501 test_decompose_scale(scale);
502 }
503
504 #[test]
505 fn decompose_zscale_up() {
506 let scale = [1.0, 1.0, 100.0];
507 test_decompose_scale(scale);
508 }
509
510 #[test]
511 fn decompose_zscale_down() {
512 let scale = [1.0, 1.0, 0.001];
513 test_decompose_scale(scale);
514 }
515
516 #[test]
517 fn decompose_negative_xscale_unit() {
518 let scale = [-1.0, 1.0, 1.0];
519 test_decompose_scale(scale);
520 }
521
522 #[test]
523 fn decompose_negative_xscale_up() {
524 let scale = [-10.0, 1.0, 1.0];
525 test_decompose_scale(scale);
526 }
527
528 #[test]
529 fn decompose_negative_xscale_down() {
530 let scale = [-0.1, 1.0, 1.0];
531 test_decompose_scale(scale);
532 }
533
534 #[test]
535 fn decompose_negative_yscale_unit() {
536 let scale = [1.0, -1.0, 1.0];
537 test_decompose_scale(scale);
538 }
539
540 #[test]
541 fn decompose_negative_yscale_up() {
542 let scale = [1.0, -10.0, 1.0];
543 test_decompose_scale(scale);
544 }
545
546 #[test]
547 fn decompose_negative_yscale_down() {
548 let scale = [1.0, -0.1, 1.0];
549 test_decompose_scale(scale);
550 }
551
552 #[test]
553 fn decompose_negative_zscale_unit() {
554 let scale = [1.0, 1.0, -1.0];
555 test_decompose_scale(scale);
556 }
557
558 #[test]
559 fn decompose_negative_zscale_up() {
560 let scale = [1.0, 1.0, -10.0];
561 test_decompose_scale(scale);
562 }
563
564 #[test]
565 fn decompose_negative_zscale_down() {
566 let scale = [1.0, 1.0, -0.1];
567 test_decompose_scale(scale);
568 }
569
570 #[test]
571 fn decompose_nonuniform_scale_up_sml() {
572 let scale = [10.0, 100.0, 1000.0];
573 test_decompose_scale(scale);
574 }
575
576 #[test]
577 fn decompose_nonuniform_scale_up_mls() {
578 let scale = [100.0, 1000.0, 10.0];
579 test_decompose_scale(scale);
580 }
581
582 #[test]
583 fn decompose_nonuniform_scale_up_lsm() {
584 let scale = [1000.0, 10.0, 100.0];
585 test_decompose_scale(scale);
586 }
587
588 #[test]
589 fn decompose_nonuniform_scale_down_sml() {
590 let scale = [0.01, 0.001, 0.0001];
591 test_decompose_scale(scale);
592 }
593
594 #[test]
595 fn decompose_nonuniform_scale_down_mls() {
596 let scale = [0.001, 0.0001, 0.01];
597 test_decompose_scale(scale);
598 }
599
600 #[test]
601 fn decompose_nonuniform_scale_down_lsm() {
602 let scale = [0.0001, 0.01, 0.01];
603 test_decompose_scale(scale);
604 }
605
606 #[test]
607 fn decompose_nonuniform_scale_unit_ls() {
608 let scale = [1.0, 100000.0, 0.000001];
609 test_decompose_scale(scale);
610 }
611
612 #[test]
613 fn decompose_nonuniform_scale_ms_negative_unit() {
614 let scale = [10.0, 0.1, -1.0];
615 test_decompose_scale(scale);
616 }
617
618 #[test]
619 fn decompose_nonuniform_scale_ms_negative_up() {
620 let scale = [10.0, 0.1, -10.0];
621 test_decompose_scale(scale);
622 }
623
624 #[test]
625 fn decompose_nonuniform_scale_ms_negative_down() {
626 let scale = [10.0, 0.1, -0.1];
627 test_decompose_scale(scale);
628 }
629}