Skip to main content

pfx_load/scene/
pose.rs

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(&current) {
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}