rive_rs/animation/
keyed_property.rs
1use std::any::TypeId;
6
7use crate::animation::{KeyFrame, KeyedObject};
8use crate::core::{Core, CoreContext, Object, ObjectRef, OnAdded, Property};
9use crate::dyn_vec::DynVec;
10use crate::importers::{ImportStack, KeyedObjectImporter};
11use crate::status_code::StatusCode;
12
13#[derive(Debug, Default)]
14pub struct KeyedProperty {
15 property_key: Property<u64>,
16 key_frames: DynVec<Object<KeyFrame>>,
17}
18
19impl ObjectRef<'_, KeyedProperty> {
20 pub fn property_key(&self) -> u64 {
21 self.property_key.get()
22 }
23
24 pub fn set_property_key(&self, property_key: u64) {
25 self.property_key.set(property_key)
26 }
27}
28
29impl ObjectRef<'_, KeyedProperty> {
30 pub fn push_key_frame(&self, key_frame: Object<KeyFrame>) {
31 self.key_frames.push(key_frame);
32 }
33
34 pub fn apply(&self, core: Object, seconds: f32, mix: f32) {
35 assert!(!self.key_frames.is_empty());
36
37 let mut i = 0;
38 let mut mid;
39 let mut closest_seconds;
40 let mut start = 0;
41 let mut end = self.key_frames.len() - 1;
42
43 while start <= end {
44 mid = (start + end) / 2;
45 closest_seconds = self.key_frames.index(mid).as_ref().seconds();
46
47 if closest_seconds < seconds {
48 start = mid + 1;
49 } else if closest_seconds > seconds {
50 if let Some(new_end) = mid.checked_sub(1) {
51 end = new_end;
52 } else {
53 break;
54 }
55 } else {
56 i = mid;
57 break;
58 }
59
60 i = start;
61 }
62
63 let property_key = self.property_key();
64
65 if i == 0 {
66 self.key_frames.index(0).as_ref().apply(core, property_key, mix);
67 return;
68 }
69
70 if i == self.key_frames.len() {
71 self.key_frames.index(i - 1).as_ref().apply(core, property_key, mix);
72 return;
73 }
74
75 let from_frame = self.key_frames.index(i - 1);
76 let from_frame = from_frame.as_ref();
77 let to_frame = self.key_frames.index(i);
78 let to_frame = to_frame.as_ref();
79
80 if seconds == to_frame.seconds() {
81 to_frame.apply(core, property_key, mix);
82 } else if from_frame.interpolation_type() == 0 {
83 from_frame.apply(core, property_key, mix);
84 } else {
85 from_frame.apply_interpolation(core, property_key, seconds, to_frame, mix);
86 }
87 }
88}
89
90impl Core for KeyedProperty {
91 properties![(53, property_key, set_property_key)];
92}
93
94impl OnAdded for ObjectRef<'_, KeyedProperty> {
95 fn on_added_dirty(&self, context: &dyn CoreContext) -> StatusCode {
96 for key_frame in self.key_frames.iter() {
97 let code = key_frame.as_ref().on_added_dirty(context);
98 if code != StatusCode::Ok {
99 return code;
100 }
101 }
102
103 StatusCode::Ok
104 }
105
106 fn on_added_clean(&self, context: &dyn CoreContext) -> StatusCode {
107 for key_frame in self.key_frames.iter() {
108 let code = key_frame.as_ref().on_added_clean(context);
109 if code != StatusCode::Ok {
110 return code;
111 }
112 }
113
114 StatusCode::Ok
115 }
116
117 fn import(&self, object: Object, import_stack: &ImportStack) -> StatusCode {
118 if let Some(importer) =
119 import_stack.latest::<KeyedObjectImporter>(TypeId::of::<KeyedObject>())
120 {
121 importer.push_keyed_property(object.as_ref().cast::<KeyedProperty>().as_object());
122 StatusCode::Ok
123 } else {
124 StatusCode::MissingObject
125 }
126 }
127}