1use crate::{
11 SealedRanimScene, TimeMark,
12 animation::{
13 eval::OutputContext,
14 node::{AnimNode, AnimationInfo},
15 },
16 audio::MASTER_SAMPLE_RATE,
17 frame::EvaluatedFrame,
18};
19
20pub struct SceneEvaluator {
22 cells: Vec<AnimNode>,
23 total_secs: f64,
24 audio: std::sync::Arc<[f32]>,
25 time_marks: Vec<(f64, TimeMark)>,
26 clock: f64,
27}
28
29impl SceneEvaluator {
30 #[allow(unused_variables)]
35 pub fn new(scene: SealedRanimScene, logic_fps: f64) -> Self {
36 Self {
37 cells: scene.animations,
38 total_secs: scene.total_secs,
39 audio: scene.audio,
40 time_marks: scene.time_marks,
41 clock: 0.0,
42 }
43 }
44
45 pub fn total_secs(&self) -> f64 {
47 self.total_secs
48 }
49
50 #[cfg(test)]
55 pub(crate) fn cells(&self) -> &[AnimNode] {
56 &self.cells
57 }
58
59 pub fn has_audio(&self) -> bool {
61 self.cells.iter().any(AnimNode::has_audio)
62 }
63
64 pub fn audio(&self) -> &std::sync::Arc<[f32]> {
68 &self.audio
69 }
70
71 pub fn mix_audio(&self, out_secs: f64, sample_rate: u32) -> Vec<f32> {
78 assert_eq!(
79 sample_rate, MASTER_SAMPLE_RATE,
80 "the baked audio lives at the master sample rate"
81 );
82 let out_frames = (out_secs * sample_rate as f64).ceil() as usize;
83 let baked_frames = self.audio.len() / 2;
84 let copy = out_frames.min(baked_frames);
85 let mut out = Vec::with_capacity(out_frames * 2);
86 out.extend_from_slice(&self.audio[..copy * 2]);
87 out.resize(out_frames * 2, 0.0);
88 out
89 }
90
91 pub fn time_marks(&self) -> &[(f64, TimeMark)] {
93 &self.time_marks
94 }
95
96 pub fn animation_infos(&self) -> Vec<AnimationInfo> {
98 self.cells.iter().map(AnimNode::animation_info).collect()
99 }
100
101 pub fn clock(&self) -> f64 {
103 self.clock
104 }
105
106 pub fn sample_at(&mut self, render_secs: f64, out: &mut EvaluatedFrame) {
113 out.clear();
114 for (source_id, cell) in self.cells.iter().enumerate() {
115 cell.eval_at(render_secs, &mut OutputContext::new(out, source_id));
116 }
117 self.clock = render_secs;
118 }
119}
120
121#[cfg(test)]
122mod tests {
123 use super::*;
124 use crate::{
125 RanimScene, SealedRanimScene,
126 animation::{
127 build::{PlaybackExt, Unplaced},
128 eval::{Eval, iterative::Iterative},
129 },
130 seq,
131 };
132
133 #[derive(Clone, Default)]
134 struct PositionX(f32);
135
136 struct ProgressX;
138
139 impl Eval for ProgressX {
140 type Output = PositionX;
141
142 fn eval_alpha(&self, alpha: f64) -> PositionX {
143 PositionX(alpha as f32)
144 }
145 }
146
147 fn xs_of(frame: &EvaluatedFrame) -> Vec<f32> {
148 frame
149 .items::<PositionX>()
150 .iter()
151 .map(|item| item.value.0)
152 .collect()
153 }
154
155 fn cv(v: f64, logical_secs: f64) -> impl Unplaced {
156 Iterative::from_fn(
157 PositionX::default(),
158 move |state: &mut PositionX, _, delta| {
159 state.0 += (v * logical_secs * delta) as f32;
160 },
161 )
162 .with_steps(120)
163 }
164
165 fn assert_x(frame: &EvaluatedFrame, expected: f32) {
166 let values = xs_of(frame);
167 assert_eq!(values.len(), 1);
168 assert!(
169 (values[0] - expected).abs() < 1e-5,
170 "{values:?} vs {expected}"
171 );
172 }
173
174 #[test]
175 fn functional_scene_matches_pure_eval() {
176 let mut scene = RanimScene::new();
177 scene.play(ProgressX.with_duration(2.0));
178 let sealed = scene.seal();
179
180 let mut ev = SceneEvaluator::new(sealed, 120.0);
181 for sec in [0.0, 0.25, 0.5, 1.0, 1.5, 2.0] {
182 let mut frame = EvaluatedFrame::new();
183 ev.sample_at(sec, &mut frame);
184 let expected = (sec / 2.0) as f32;
185 let got = xs_of(&frame);
186 assert_eq!(got, vec![expected], "at sec={sec}");
187 }
188 }
189
190 #[test]
191 fn repeated_samples_replace_the_whole_output_frame() {
192 let mut scene = RanimScene::new();
193 scene.play(ProgressX.with_duration(2.0));
194 let mut ev = SceneEvaluator::new(scene.seal(), 120.0);
195 let mut frame = EvaluatedFrame::new();
196 frame.push((99, 0), String::from("previous output"));
197
198 for sec in [0.5, 1.5, 0.25, 1.5] {
199 ev.sample_at(sec, &mut frame);
200
201 assert_eq!(frame.len(), 1);
202 assert!(frame.items::<String>().is_empty());
203 let items = frame.items::<PositionX>();
204 assert_eq!(items[0].id, (0, 0));
205 assert_eq!(items[0].order, 0);
206 assert_x(&frame, (sec / 2.0) as f32);
207 }
208 }
209
210 #[test]
211 fn ordinary_samples_move_complete_outputs_and_holds_replay_original_types() {
212 use crate::animation::{compose::sequence::AnimSequence, eval::pure::Pure};
213 use std::sync::{
214 Arc,
215 atomic::{AtomicUsize, Ordering},
216 };
217
218 struct Raw {
219 values: Vec<u32>,
220 clones: Arc<AtomicUsize>,
221 }
222 impl Clone for Raw {
223 fn clone(&self) -> Self {
224 self.clones.fetch_add(1, Ordering::SeqCst);
225 Self {
226 values: self.values.clone(),
227 clones: Arc::clone(&self.clones),
228 }
229 }
230 }
231
232 let clones = Arc::new(AtomicUsize::new(0));
233 let animation = {
234 let clones = Arc::clone(&clones);
235 Pure::new(move |_| Raw {
236 values: vec![42, 43],
237 clones: Arc::clone(&clones),
238 })
239 };
240 let mut sequence = AnimSequence::new();
241 sequence.push(animation.with_duration(1.0)).hold(1.0);
242 assert_eq!(clones.load(Ordering::SeqCst), 0);
243 let mut scene = RanimScene::new();
244 scene.play(sequence);
245 let mut evaluator = scene.seal().into_evaluator(120.0);
246 let mut frame = EvaluatedFrame::new();
247
248 evaluator.sample_at(0.5, &mut frame);
249 assert_eq!(clones.load(Ordering::SeqCst), 0);
250 assert_eq!(frame.items::<Raw>()[0].value.values, [42, 43]);
251 evaluator.sample_at(1.5, &mut frame);
252 assert_eq!(clones.load(Ordering::SeqCst), 1);
253 assert_eq!(frame.items::<Raw>()[0].id, (0, 0));
254 assert_eq!(frame.items::<Raw>()[0].value.values, [42, 43]);
255 }
256
257 #[test]
258 fn repeated_holds_preserve_heterogeneous_container_and_transform_outputs() {
259 use crate::{
260 animation::{compose::sequence::AnimSequence, eval::Static},
261 glam::DVec3,
262 stack,
263 traits::Translation,
264 transformed::Transformed,
265 };
266
267 type Wrapped = Transformed<Vec<(u32, String)>, Translation>;
268 let wrapped = Wrapped::new(vec![(7, String::from("nested"))], Translation(DVec3::X));
269 let mut sequence = AnimSequence::new();
270 sequence
271 .push(stack![
272 Static(vec![10_u32, 20]).with_duration(1.0),
273 Static(wrapped.clone()).with_duration(1.0),
274 ])
275 .hold(1.0)
276 .hold(1.0);
277 let mut scene = RanimScene::new();
278 scene.play(sequence);
279 let mut evaluator = scene.seal().into_evaluator(120.0);
280 let mut frame = EvaluatedFrame::new();
281
282 for sec in [0.5, 1.5, 2.5] {
283 evaluator.sample_at(sec, &mut frame);
284 assert_eq!(frame.len(), 2);
285 let vector = &frame.items::<Vec<u32>>()[0];
286 assert_eq!(vector.value, [10, 20]);
287 assert_eq!((vector.id, vector.order), ((0, 0), 0));
288 let item = &frame.items::<Wrapped>()[0];
289 assert_eq!(item.value, wrapped);
290 assert_eq!((item.id, item.order), ((0, 1), 1));
291 assert!(frame.items::<u32>().is_empty());
292 assert!(frame.items::<(u32, String)>().is_empty());
293 }
294 }
295
296 #[test]
297 fn iterative_leaves_step_along_the_logic_grid() {
298 let mut scene = RanimScene::new();
299 scene.play(cv(1.0, 2.0).with_duration(2.0).at(0.0));
300 let mut ev = SceneEvaluator::new(scene.seal(), 120.0);
301 for sec in [0.0, 0.5, 1.0, 1.5, 2.0] {
302 let mut frame = EvaluatedFrame::new();
303 ev.sample_at(sec, &mut frame);
304 assert_x(&frame, sec as f32);
305 }
306
307 let mut scene = RanimScene::new();
309 scene.play(
310 seq![
311 cv(1.0, 1.0).with_duration(1.0),
312 cv(1.0, 1.0).with_duration(1.0)
313 ]
314 .at(0.0),
315 );
316 let mut ev = SceneEvaluator::new(scene.seal(), 120.0);
317 for (sec, expected) in [(1.5, 0.5), (2.0, 1.0)] {
318 let mut frame = EvaluatedFrame::new();
319 ev.sample_at(sec, &mut frame);
320 assert_x(&frame, expected);
321 }
322 }
323
324 #[test]
325 fn iterative_seek_matches_forward_and_resets_nested_leaves() {
326 fn run(scene: SealedRanimScene, backward: bool) -> Vec<Vec<f32>> {
327 let mut ev = SceneEvaluator::new(scene, 120.0);
328 let mut trace = Vec::new();
329 for sec in [0.3, 0.7, 1.1, 1.9, 2.6] {
330 if backward {
331 ev.sample_at(0.2, &mut EvaluatedFrame::new());
334 }
335 let mut frame = EvaluatedFrame::new();
336 ev.sample_at(sec, &mut frame);
337 trace.push(xs_of(&frame));
338 }
339 trace
340 }
341
342 let single = || {
343 let mut scene = RanimScene::new();
344 scene.play(cv(2.0, 3.0).with_duration(3.0).at(0.0));
345 scene.seal()
346 };
347 let forward = run(single(), false);
348 assert_eq!(forward, run(single(), true));
349 assert!((forward[2][0] - 2.2).abs() < 1e-5);
350
351 let nested = || {
352 let mut scene = RanimScene::new();
353 scene.play(
354 seq![
355 cv(1.0, 1.0).with_duration(1.0),
356 cv(1.0, 1.0).with_duration(1.0)
357 ]
358 .at(0.0),
359 );
360 scene.seal()
361 };
362 assert_eq!(run(nested(), false), run(nested(), true));
363 }
364}