ferroui_base/rendering/composition/animations/
subchannel_animation_instance.rs1use super::{AnimationInstanceFactory, IAnimationInstance, ICompositionAnimation, ICompositionAnimationBase};
19use crate::numerics::{Vector2, Vector3, Vector4};
20use crate::rendering::composition::expressions::ExpressionVariant;
21use crate::rendering::composition::server::{CompositionProperty, IServerClockItem, ServerCompositor, ServerObjectId};
22use crate::{Vector, Vector3D};
23use std::cell::{Cell, RefCell};
24use std::rc::Rc;
25use std::time::Duration;
26
27pub(crate) fn parse_subchannel(property_name: &str) -> Option<(&str, Vec<usize>)> {
39 let (property, channel) = property_name.split_once('.')?;
40 if channel.is_empty() || !channel.chars().all(|c| matches!(c.to_ascii_uppercase(), 'X' | 'Y' | 'Z' | 'W')) {
41 return None;
42 }
43 let mut components = Vec::with_capacity(channel.len());
44 for c in channel.chars() {
45 let index = match c.to_ascii_uppercase() {
46 'X' => 0,
47 'Y' => 1,
48 'Z' => 2,
49 'W' => 3,
50 _ => panic!("Unknown property {property_name}"),
51 };
52 if components.contains(&index) {
53 panic!("Unknown property {property_name}");
54 }
55 components.push(index);
56 }
57 if components.is_empty() || components.len() > 4 || property.is_empty() {
58 panic!("Unknown property {property_name}");
59 }
60 Some((property, components))
61}
62
63fn vector_components(value: &ExpressionVariant) -> Option<([f64; 4], usize)> {
65 match *value {
66 ExpressionVariant::Vector2(v) => Some(([v.x as f64, v.y as f64, 0.0, 0.0], 2)),
67 ExpressionVariant::Vector(v) => Some(([v.x, v.y, 0.0, 0.0], 2)),
68 ExpressionVariant::Vector3(v) => Some(([v.x as f64, v.y as f64, v.z as f64, 0.0], 3)),
69 ExpressionVariant::Vector3D(v) => Some(([v.x, v.y, v.z, 0.0], 3)),
70 ExpressionVariant::Vector4(v) => Some(([v.x as f64, v.y as f64, v.z as f64, v.w as f64], 4)),
71 _ => None,
72 }
73}
74
75fn channel_components(value: &ExpressionVariant) -> Option<([f64; 4], usize)> {
77 match *value {
78 ExpressionVariant::Double(v) => Some(([v, 0.0, 0.0, 0.0], 1)),
79 _ => vector_components(value),
80 }
81}
82
83fn with_components(value: ExpressionVariant, c: [f64; 4]) -> ExpressionVariant {
85 match value {
86 ExpressionVariant::Vector2(_) => Vector2::new(c[0] as f32, c[1] as f32).into(),
87 ExpressionVariant::Vector(_) => Vector::new(c[0], c[1]).into(),
88 ExpressionVariant::Vector3(_) => Vector3::new(c[0] as f32, c[1] as f32, c[2] as f32).into(),
89 ExpressionVariant::Vector3D(_) => Vector3D::new(c[0], c[1], c[2]).into(),
90 ExpressionVariant::Vector4(_) => Vector4::new(c[0] as f32, c[1] as f32, c[2] as f32, c[3] as f32).into(),
91 other => other,
92 }
93}
94
95pub(crate) fn extract_subchannel(value: ExpressionVariant, components: &[usize]) -> ExpressionVariant {
99 let Some((c, n)) = vector_components(&value) else { return ExpressionVariant::Invalid };
100 if components.iter().any(|&i| i >= n) {
101 return ExpressionVariant::Invalid;
102 }
103 let at = |k: usize| c[components[k]];
104 match components.len() {
105 1 => ExpressionVariant::Double(at(0)),
106 2 => Vector2::new(at(0) as f32, at(1) as f32).into(),
107 3 => Vector3::new(at(0) as f32, at(1) as f32, at(2) as f32).into(),
108 4 => Vector4::new(at(0) as f32, at(1) as f32, at(2) as f32, at(3) as f32).into(),
109 _ => ExpressionVariant::Invalid,
110 }
111}
112
113pub(crate) fn write_subchannel(
117 value: ExpressionVariant,
118 components: &[usize],
119 channel_value: ExpressionVariant,
120) -> ExpressionVariant {
121 let Some((mut c, n)) = vector_components(&value) else { return value };
122 let Some((o, on)) = channel_components(&channel_value) else { return value };
123 for (k, &i) in components.iter().enumerate() {
124 if k < on && i < n {
125 c[i] = o[k];
126 }
127 }
128 with_components(value, c)
129}
130
131pub(crate) struct SubchannelAnimation {
142 components: Vec<usize>,
143 inner: RefCell<Option<AnimationInstanceFactory>>,
144 previous: RefCell<Option<AnimationInstanceFactory>>,
145}
146
147impl SubchannelAnimation {
148 pub(crate) fn new(
149 components: Vec<usize>,
150 inner: AnimationInstanceFactory,
151 previous: Option<AnimationInstanceFactory>,
152 ) -> SubchannelAnimation {
153 SubchannelAnimation { components, inner: RefCell::new(Some(inner)), previous: RefCell::new(previous) }
154 }
155}
156
157impl ICompositionAnimationBase for SubchannelAnimation {
158 fn as_composition_animation(&self) -> Option<&dyn ICompositionAnimation> {
159 Some(self)
160 }
161}
162
163impl ICompositionAnimation for SubchannelAnimation {
164 fn target(&self) -> Option<String> {
165 None
166 }
167
168 fn create_instance(&self, target_object: ServerObjectId, _final_value: Option<ExpressionVariant>) -> AnimationInstanceFactory {
171 let Some(inner) = self.inner.borrow_mut().take() else {
172 panic!("the instance of a sub-channel animation is created once");
173 };
174 let previous = self.previous.borrow_mut().take();
175 let components = self.components.clone();
176 AnimationInstanceFactory::new(move || {
177 let instance = SubchannelAnimationInstance::new(target_object, components, inner.create());
178 if let Some(previous) = previous {
179 let previous = previous.create();
182 let merged = match previous.as_subchannel() {
183 Some(running) => {
184 running.absorb(&instance);
185 true
186 }
187 None => false,
188 };
189 if merged {
190 return previous;
191 }
192 }
193 let instance: Rc<dyn IAnimationInstance> = instance;
194 instance
195 })
196 }
197}
198
199struct Subchannel {
201 components: Vec<usize>,
202 instance: Rc<dyn IAnimationInstance>,
203}
204
205pub struct SubchannelAnimationInstance {
212 target: ServerObjectId,
213 channels: RefCell<Vec<Subchannel>>,
214 property: Cell<Option<&'static CompositionProperty>>,
215 starting_value: Cell<ExpressionVariant>,
216 active: Cell<bool>,
217}
218
219impl SubchannelAnimationInstance {
220 pub fn new(
223 target: ServerObjectId,
224 components: Vec<usize>,
225 instance: Rc<dyn IAnimationInstance>,
226 ) -> Rc<SubchannelAnimationInstance> {
227 Rc::new(SubchannelAnimationInstance {
228 target,
229 channels: RefCell::new(vec![Subchannel { components, instance }]),
230 property: Cell::new(None),
231 starting_value: Cell::new(ExpressionVariant::Invalid),
232 active: Cell::new(false),
233 })
234 }
235
236 pub fn components(&self) -> Vec<Vec<usize>> {
238 self.channels.borrow().iter().map(|c| c.components.clone()).collect()
239 }
240
241 fn drop_overlapping(&self, components: &[usize]) {
247 let removed: Vec<Subchannel> = {
248 let mut channels = self.channels.borrow_mut();
249 let (removed, kept) = std::mem::take(&mut *channels)
250 .into_iter()
251 .partition(|c| c.components.iter().any(|i| components.contains(i)));
252 *channels = kept;
253 removed
254 };
255 for channel in removed {
256 if self.active.get() {
257 channel.instance.deactivate();
258 }
259 channel.instance.release_completion();
260 }
261 }
262
263 pub(crate) fn absorb(&self, other: &SubchannelAnimationInstance) {
266 let incoming = std::mem::take(&mut *other.channels.borrow_mut());
267 for channel in incoming {
268 self.drop_overlapping(&channel.components);
269 self.channels.borrow_mut().push(channel);
270 }
271 }
272
273 pub(crate) fn merge(&self, other: &SubchannelAnimationInstance, committed_at: Duration, current_value: ExpressionVariant) {
277 let incoming = std::mem::take(&mut *other.channels.borrow_mut());
278 for channel in incoming {
279 self.drop_overlapping(&channel.components);
280 if let Some(property) = self.property.get() {
281 channel.instance.initialize(
282 committed_at,
283 extract_subchannel(current_value, &channel.components),
284 property,
285 );
286 }
287 if self.active.get() {
288 channel.instance.activate();
289 }
290 self.channels.borrow_mut().push(channel);
291 }
292 }
293
294 pub(crate) fn stop_components(
299 &self,
300 components: &[usize],
301 current_value: ExpressionVariant,
302 ) -> (Option<ExpressionVariant>, bool) {
303 let removed: Vec<Subchannel> = {
304 let mut channels = self.channels.borrow_mut();
305 let (removed, kept) = std::mem::take(&mut *channels)
306 .into_iter()
307 .partition(|c| c.components.iter().any(|i| components.contains(i)));
308 *channels = kept;
309 removed
310 };
311 let mut value = current_value;
312 let mut changed = false;
313 for channel in removed {
314 let channel_value = extract_subchannel(value, &channel.components);
315 if let Some(stop) = channel.instance.value_on_stop(channel_value) {
316 value = write_subchannel(value, &channel.components, stop);
317 changed = true;
318 }
319 if self.active.get() {
320 channel.instance.deactivate();
321 }
322 channel.instance.release_completion();
323 }
324 (changed.then_some(value), self.channels.borrow().is_empty())
325 }
326}
327
328impl IServerClockItem for SubchannelAnimationInstance {
329 fn on_tick(&self) {}
331}
332
333impl IAnimationInstance for SubchannelAnimationInstance {
334 fn target_object(&self) -> ServerObjectId {
335 self.target
336 }
337
338 fn resolve(&self, compositor: &Rc<ServerCompositor>) {
339 for channel in self.channels.borrow().iter() {
340 channel.instance.resolve(compositor);
341 }
342 }
343
344 fn evaluate(&self, now: Duration, current_value: ExpressionVariant) -> ExpressionVariant {
345 let mut value = if current_value == ExpressionVariant::Invalid { self.starting_value.get() } else { current_value };
348 let channels: Vec<(Vec<usize>, Rc<dyn IAnimationInstance>)> =
349 self.channels.borrow().iter().map(|c| (c.components.clone(), c.instance.clone())).collect();
350 for (components, instance) in channels {
351 let channel_value = instance.evaluate(now, extract_subchannel(value, &components));
352 value = write_subchannel(value, &components, channel_value);
353 }
354 value
355 }
356
357 fn initialize(&self, started_at: Duration, starting_value: ExpressionVariant, property: &'static CompositionProperty) {
358 self.property.set(Some(property));
359 self.starting_value.set(starting_value);
360 for channel in self.channels.borrow().iter() {
361 channel.instance.initialize(started_at, extract_subchannel(starting_value, &channel.components), property);
362 }
363 }
364
365 fn activate(&self) {
366 self.active.set(true);
367 let instances: Vec<_> = self.channels.borrow().iter().map(|c| c.instance.clone()).collect();
368 for instance in instances {
369 instance.activate();
370 }
371 }
372
373 fn deactivate(&self) {
374 self.active.set(false);
375 let instances: Vec<_> = self.channels.borrow().iter().map(|c| c.instance.clone()).collect();
376 for instance in instances {
377 instance.deactivate();
378 }
379 }
380
381 fn invalidate(&self) {
382 let instances: Vec<_> = self.channels.borrow().iter().map(|c| c.instance.clone()).collect();
383 for instance in instances {
384 instance.invalidate();
385 }
386 }
387
388 fn value_on_stop(&self, current_value: ExpressionVariant) -> Option<ExpressionVariant> {
389 let mut value = current_value;
390 let mut changed = false;
391 for channel in self.channels.borrow().iter() {
392 let channel_value = extract_subchannel(value, &channel.components);
393 if let Some(stop) = channel.instance.value_on_stop(channel_value) {
394 value = write_subchannel(value, &channel.components, stop);
395 changed = true;
396 }
397 }
398 changed.then_some(value)
399 }
400
401 fn release_completion(&self) {
402 let instances: Vec<_> = self.channels.borrow().iter().map(|c| c.instance.clone()).collect();
403 for instance in instances {
404 instance.release_completion();
405 }
406 }
407
408 fn attach_controller(&self, controller: ServerObjectId) {
410 let instances: Vec<_> = self.channels.borrow().iter().map(|c| c.instance.clone()).collect();
411 for instance in instances {
412 instance.attach_controller(controller);
413 }
414 }
415
416 fn as_subchannel(&self) -> Option<&SubchannelAnimationInstance> {
417 Some(self)
418 }
419}