rive_rs/animation/
key_frame.rs
1use std::any::TypeId;
6use std::cell::Cell;
7
8use crate::animation::{
9 CubicInterpolator, KeyFrameColor, KeyFrameDouble, KeyFrameId, KeyedProperty,
10};
11use crate::core::{Core, CoreContext, Object, ObjectRef, OnAdded, Property};
12use crate::importers::{ImportStack, KeyedPropertyImporter};
13use crate::option_cell::OptionCell;
14use crate::status_code::StatusCode;
15
16#[derive(Debug, Default)]
17pub struct KeyFrame {
18 frame: Property<u64>,
19 interpolation_type: Property<u64>,
20 interpolator_id: Property<u64>,
21 cubic_interpolator: OptionCell<Object<CubicInterpolator>>,
22 seconds: Cell<f32>,
23}
24
25impl ObjectRef<'_, KeyFrame> {
26 pub fn frame(&self) -> u64 {
27 self.frame.get()
28 }
29
30 pub fn set_frame(&self, frame: u64) {
31 self.frame.set(frame);
32 }
33
34 pub fn interpolation_type(&self) -> u64 {
35 self.interpolation_type.get()
36 }
37
38 pub fn set_interpolation_type(&self, interpolation_type: u64) {
39 self.interpolation_type.set(interpolation_type);
40 }
41
42 pub fn interpolator_id(&self) -> u64 {
43 self.interpolator_id.get()
44 }
45
46 pub fn set_interpolator_id(&self, interpolator_id: u64) {
47 self.interpolator_id.set(interpolator_id);
48 }
49}
50
51impl ObjectRef<'_, KeyFrame> {
52 pub fn seconds(&self) -> f32 {
53 self.seconds.get()
54 }
55
56 pub fn interpolator(&self) -> Option<Object<CubicInterpolator>> {
57 self.cubic_interpolator.get()
58 }
59
60 pub fn compute_seconds(&self, fps: u64) {
61 self.seconds.set(self.frame() as f32 / fps as f32);
62 }
63
64 pub fn apply(&self, core: Object, property_key: u64, mix: f32) {
65 if let Some(key_frame_color) = self.try_cast::<KeyFrameColor>() {
66 return key_frame_color.apply(core, property_key, mix);
67 }
68
69 if let Some(key_frame_double) = self.try_cast::<KeyFrameDouble>() {
70 return key_frame_double.apply(core, property_key, mix);
71 }
72
73 if let Some(key_frame_id) = self.try_cast::<KeyFrameId>() {
74 return key_frame_id.apply(core, property_key, mix);
75 }
76
77 unreachable!();
78 }
79
80 pub fn apply_interpolation(
81 &self,
82 core: Object,
83 property_key: u64,
84 seconds: f32,
85 next_frame: ObjectRef<'_, KeyFrame>,
86 mix: f32,
87 ) {
88 if let Some(key_frame_color) = self.try_cast::<KeyFrameColor>() {
89 return key_frame_color.apply_interpolation(
90 core,
91 property_key,
92 seconds,
93 next_frame,
94 mix,
95 );
96 }
97
98 if let Some(key_frame_double) = self.try_cast::<KeyFrameDouble>() {
99 return key_frame_double.apply_interpolation(
100 core,
101 property_key,
102 seconds,
103 next_frame,
104 mix,
105 );
106 }
107
108 if let Some(key_frame_id) = self.try_cast::<KeyFrameId>() {
109 return key_frame_id.apply_interpolation(core, property_key, seconds, next_frame, mix);
110 }
111
112 unreachable!();
113 }
114}
115
116impl Core for KeyFrame {
117 properties![
118 (67, frame, set_frame),
119 (68, interpolation_type, set_interpolation_type),
120 (69, interpolator_id, set_interpolator_id)
121 ];
122}
123
124impl OnAdded for ObjectRef<'_, KeyFrame> {
125 on_added!([on_added_clean]);
126
127 fn on_added_dirty(&self, context: &dyn CoreContext) -> StatusCode {
128 if self.interpolator_id() != 0 {
129 if let Some(cubic_interpolator) =
130 context.resolve(self.interpolator_id() as usize).and_then(|core| core.try_cast())
131 {
132 self.cubic_interpolator.set(Some(cubic_interpolator));
133 } else {
134 return StatusCode::MissingObject;
135 }
136 }
137
138 StatusCode::Ok
139 }
140
141 fn import(&self, object: Object, import_stack: &ImportStack) -> StatusCode {
142 if let Some(importer) =
143 import_stack.latest::<KeyedPropertyImporter>(TypeId::of::<KeyedProperty>())
144 {
145 importer.push_key_frame(object.as_ref().cast::<KeyFrame>().as_object());
146 StatusCode::Ok
147 } else {
148 StatusCode::MissingObject
149 }
150 }
151}