1use std::collections::BTreeMap;
2
3use super::{Camera, IDENTITY, Matrix, Scene, dot, multiply};
4
5pub fn billboard(model: Matrix, camera: &Camera) -> Matrix {
6 let (forward, right, up) = camera.axes();
7 let length = |column: [f32; 4]| {
8 let axis = [column[0], column[1], column[2]];
9 dot(axis, axis).sqrt()
10 };
11 let [sx, sy, sz] = [length(model[0]), length(model[1]), length(model[2])];
12 [
13 [right[0] * sx, right[1] * sx, right[2] * sx, 0.0],
14 [up[0] * sy, up[1] * sy, up[2] * sy, 0.0],
15 [-forward[0] * sz, -forward[1] * sz, -forward[2] * sz, 0.0],
16 model[3],
17 ]
18}
19
20pub(super) fn movers_of(scene: &Scene) -> BTreeMap<&str, &str> {
21 let mut owner = BTreeMap::new();
22 for (name, mover) in &scene.movers {
23 for object in &mover.objects {
24 owner.insert(object.as_str(), name.as_str());
25 }
26 }
27 owner
28}
29
30pub(super) fn objects(scene: &Scene, camera: &Camera, time: f32) -> Vec<Matrix> {
31 let index: BTreeMap<&str, usize> = scene
32 .objects
33 .iter()
34 .enumerate()
35 .map(|(place, object)| (object.name.as_str(), place))
36 .collect();
37 let owner = movers_of(scene);
38 let moves: BTreeMap<&str, Matrix> = scene
39 .movers
40 .iter()
41 .map(|(name, mover)| (name.as_str(), mover.transform(time)))
42 .collect();
43 let mut chains: Vec<Option<Matrix>> = vec![None; scene.objects.len()];
44 let mut chain = |start: usize| -> Matrix {
45 let mut path = Vec::new();
46 let mut at = Some(start);
47 while let Some(place) = at {
48 if chains[place].is_some() || path.contains(&place) {
49 break;
50 }
51 path.push(place);
52 at = scene.objects[place]
53 .parent
54 .as_deref()
55 .and_then(|parent| index.get(parent).copied());
56 }
57 let mut above = at.and_then(|place| chains[place]).unwrap_or(IDENTITY);
58 for &place in path.iter().rev() {
59 let own = owner
60 .get(scene.objects[place].name.as_str())
61 .and_then(|mover| moves.get(mover))
62 .copied()
63 .unwrap_or(IDENTITY);
64 above = multiply(above, own);
65 chains[place] = Some(above);
66 }
67 above
68 };
69 (0..scene.objects.len())
70 .map(|place| {
71 let object = &scene.objects[place];
72 let moved = if moves.is_empty() {
73 object.model
74 } else {
75 multiply(chain(place), object.model)
76 };
77 if object.face_camera {
78 billboard(moved, camera)
79 } else {
80 moved
81 }
82 })
83 .collect()
84}
85
86pub(super) fn clips(scene: &Scene, place: usize) -> Vec<[f32; 4]> {
87 let owner = movers_of(scene);
88 let mut planes = scene.objects[place].clip.clone();
89 let mut seen = Vec::new();
90 let mut at = Some(place);
91 while let Some(current) = at {
92 if seen.contains(¤t) {
93 break;
94 }
95 seen.push(current);
96 let object = &scene.objects[current];
97 if let Some(mover) = owner
98 .get(object.name.as_str())
99 .and_then(|name| scene.movers.get(*name))
100 {
101 for plane in &mover.clip {
102 if !planes.contains(plane) {
103 planes.push(*plane);
104 }
105 }
106 }
107 at = object
108 .parent
109 .as_deref()
110 .and_then(|parent| scene.objects.iter().position(|o| o.name == parent));
111 }
112 planes
113}