smpl_gloss_integration/
scene.rs

1use crate::components::GlossInterop;
2use gloss_hecs::EntityBuilder;
3use gloss_renderer::components::{Name, VisMesh};
4use log::info;
5use ndarray::s;
6use smpl_core::{
7    codec::scene::McsCodec,
8    common::{
9        animation::{AnimWrap, Animation, AnimationConfig, AnimationRunner},
10        betas::Betas,
11        pose_override::PoseOverride,
12        smpl_params::SmplParams,
13    },
14};
15use smpl_utils::numerical::hex_to_rgb_f32;
16use std::time::Duration;
17const COLOR_CODES: [&str; 4] = ["#63D4BF", "#BAC2F7", "#FFEF9E", "#72B0C5"];
18/// creates a ``Vec<gloss_hecs::EntityBuilder>`` from the ``McsCodec``
19pub trait McsCodecGloss {
20    fn to_entity_builders(&mut self) -> Vec<EntityBuilder>;
21}
22/// Trait implementation for `McsCodec`
23impl McsCodecGloss for McsCodec {
24    #[allow(clippy::cast_precision_loss)]
25    fn to_entity_builders(&mut self) -> Vec<EntityBuilder> {
26        let mut builders: Vec<EntityBuilder> = Vec::new();
27        if let Some(camera_track) = &self.camera_track {
28            let mut camera_builder = EntityBuilder::new();
29            camera_builder.add(Name("TrackedCamera".to_string()));
30            camera_builder.add(camera_track.clone());
31            builders.push(camera_builder);
32        }
33        for (i, smpl_body) in self.smpl_bodies.iter().enumerate() {
34            let start_offset = smpl_body.frame_presence[0];
35            let fps = smpl_body.codec.frame_rate.unwrap();
36            self.frame_rate = fps;
37            let color = hex_to_rgb_f32(COLOR_CODES[i % COLOR_CODES.len()]);
38            let mut builder = EntityBuilder::new();
39            let smpl_params = SmplParams::new_from_smpl_codec(&smpl_body.codec);
40            info!("Found smpl_params in the .smpl file");
41            builder.add(smpl_params);
42            if let Some(mut betas) = Betas::new_from_smpl_codec(&smpl_body.codec) {
43                info!("Found betas in the .smpl file");
44                let trimmed_betas = betas.betas.slice(s![..10]).to_owned();
45                betas.betas = trimmed_betas;
46                builder.add(betas);
47            }
48            if let Some(mut anim) = Animation::new_from_smpl_codec(&smpl_body.codec, AnimWrap::Clamp) {
49                anim.start_offset = start_offset;
50                builder.add(anim);
51            }
52            let pose_override = PoseOverride::allow_all();
53            builder.add(pose_override);
54            builder.add(GlossInterop { with_uv: true });
55            builder.add(VisMesh {
56                solid_color: nalgebra::Vector4::<f32>::new(color.0, color.1, color.2, 1.0),
57                ..Default::default()
58            });
59            builders.push(builder);
60        }
61        builders
62    }
63}
64#[derive(Default)]
65pub struct SceneAnimation {
66    pub num_frames: usize,
67    pub runner: AnimationRunner,
68    pub config: AnimationConfig,
69}
70impl SceneAnimation {
71    pub fn new(num_frames: usize) -> Self {
72        Self {
73            num_frames,
74            runner: AnimationRunner::default(),
75            config: AnimationConfig::default(),
76        }
77    }
78    pub fn new_with_fps(num_frames: usize, fps: f32) -> Self {
79        Self {
80            num_frames,
81            runner: AnimationRunner::default(),
82            config: AnimationConfig { fps, ..Default::default() },
83        }
84    }
85    pub fn new_with_config(num_frames: usize, config: AnimationConfig) -> Self {
86        Self {
87            num_frames,
88            runner: AnimationRunner::default(),
89            config,
90        }
91    }
92    #[allow(clippy::cast_precision_loss)]
93    pub fn duration(&self) -> Duration {
94        Duration::from_secs_f32(self.num_frames as f32 / self.config.fps)
95    }
96    pub fn get_cur_time(&self) -> Duration {
97        self.runner.anim_current_time
98    }
99    pub fn set_cur_time_as_sec(&mut self, time_sec: f32) {
100        self.runner.anim_current_time = Duration::from_secs_f32(time_sec);
101    }
102    pub fn is_finished(&self) -> bool {
103        self.config.wrap_behaviour == AnimWrap::Clamp && self.runner.anim_current_time >= self.duration()
104    }
105    /// Advances the animation by the amount of time elapsed since last time we
106    /// got the current pose
107    pub fn advance(&mut self, dt_raw: Duration, first_time: bool) {
108        let duration = self.duration();
109        let runner = &mut self.runner;
110        let config = &self.config;
111        let mut dt = dt_raw;
112        if first_time {
113            dt = Duration::ZERO;
114        }
115        let will_overflow = runner.anim_current_time + dt > duration;
116        let will_underflow = runner.anim_current_time < dt && runner.anim_reversed;
117        if will_overflow || will_underflow {
118            if will_overflow {
119                match config.wrap_behaviour {
120                    AnimWrap::Clamp => {
121                        dt = Duration::ZERO;
122                        runner.anim_current_time = duration;
123                    }
124                    AnimWrap::Loop => {
125                        dt = Duration::from_secs_f64(dt.as_secs_f64() % duration.as_secs_f64());
126                        runner.anim_current_time = Duration::ZERO;
127                        runner.nr_repetitions += 1;
128                    }
129                    AnimWrap::Reverse => {
130                        dt = Duration::from_secs_f64(dt.as_secs_f64() % duration.as_secs_f64());
131                        runner.anim_current_time = duration;
132                        runner.anim_reversed = !runner.anim_reversed;
133                        runner.nr_repetitions += 1;
134                    }
135                }
136            } else {
137                match config.wrap_behaviour {
138                    AnimWrap::Clamp => {
139                        dt = Duration::ZERO;
140                        runner.anim_current_time = Duration::ZERO;
141                    }
142                    AnimWrap::Loop => {
143                        dt = Duration::from_secs_f64(dt.as_secs_f64() % duration.as_secs_f64());
144                        runner.anim_current_time = duration;
145                        runner.nr_repetitions += 1;
146                    }
147                    AnimWrap::Reverse => {
148                        dt = Duration::from_secs_f64(dt.as_secs_f64() % duration.as_secs_f64());
149                        runner.anim_reversed = !runner.anim_reversed;
150                        runner.nr_repetitions += 1;
151                    }
152                }
153            }
154        }
155        if runner.anim_reversed {
156            runner.anim_current_time = runner.anim_current_time.saturating_sub(dt);
157        } else {
158            runner.anim_current_time = runner.anim_current_time.saturating_add(dt);
159        }
160    }
161}