blob: 295c8558a31555d4a2cfc7fa5e45de73ae97cfda [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use std::{any::TypeId, cell::Cell};
use crate::{
animation::{CubicInterpolator, KeyFrameColor, KeyFrameDouble, KeyFrameId, KeyedProperty},
core::{Core, CoreContext, Object, ObjectRef, OnAdded, Property},
importers::{ImportStack, KeyedPropertyImporter},
option_cell::OptionCell,
status_code::StatusCode,
};
#[derive(Debug, Default)]
pub struct KeyFrame {
frame: Property<u64>,
interpolation_type: Property<u64>,
interpolator_id: Property<u64>,
cubic_interpolator: OptionCell<Object<CubicInterpolator>>,
seconds: Cell<f32>,
}
impl ObjectRef<'_, KeyFrame> {
pub fn frame(&self) -> u64 {
self.frame.get()
}
pub fn set_frame(&self, frame: u64) {
self.frame.set(frame);
}
pub fn interpolation_type(&self) -> u64 {
self.interpolation_type.get()
}
pub fn set_interpolation_type(&self, interpolation_type: u64) {
self.interpolation_type.set(interpolation_type);
}
pub fn interpolator_id(&self) -> u64 {
self.interpolator_id.get()
}
pub fn set_interpolator_id(&self, interpolator_id: u64) {
self.interpolator_id.set(interpolator_id);
}
}
impl ObjectRef<'_, KeyFrame> {
pub fn seconds(&self) -> f32 {
self.seconds.get()
}
pub fn interpolator(&self) -> Option<Object<CubicInterpolator>> {
self.cubic_interpolator.get()
}
pub fn compute_seconds(&self, fps: u64) {
self.seconds.set(self.frame() as f32 / fps as f32);
}
pub fn apply(&self, core: Object, property_key: u64, mix: f32) {
if let Some(key_frame_color) = self.try_cast::<KeyFrameColor>() {
return key_frame_color.apply(core, property_key, mix);
}
if let Some(key_frame_double) = self.try_cast::<KeyFrameDouble>() {
return key_frame_double.apply(core, property_key, mix);
}
if let Some(key_frame_id) = self.try_cast::<KeyFrameId>() {
return key_frame_id.apply(core, property_key, mix);
}
unreachable!();
}
pub fn apply_interpolation(
&self,
core: Object,
property_key: u64,
seconds: f32,
next_frame: ObjectRef<'_, KeyFrame>,
mix: f32,
) {
if let Some(key_frame_color) = self.try_cast::<KeyFrameColor>() {
return key_frame_color.apply_interpolation(
core,
property_key,
seconds,
next_frame,
mix,
);
}
if let Some(key_frame_double) = self.try_cast::<KeyFrameDouble>() {
return key_frame_double.apply_interpolation(
core,
property_key,
seconds,
next_frame,
mix,
);
}
if let Some(key_frame_id) = self.try_cast::<KeyFrameId>() {
return key_frame_id.apply_interpolation(core, property_key, seconds, next_frame, mix);
}
unreachable!();
}
}
impl Core for KeyFrame {
properties![
(67, frame, set_frame),
(68, interpolation_type, set_interpolation_type),
(69, interpolator_id, set_interpolator_id)
];
}
impl OnAdded for ObjectRef<'_, KeyFrame> {
on_added!([on_added_clean]);
fn on_added_dirty(&self, context: &dyn CoreContext) -> StatusCode {
if self.interpolator_id() != 0 {
if let Some(cubic_interpolator) =
context.resolve(self.interpolator_id() as usize).and_then(|core| core.try_cast())
{
self.cubic_interpolator.set(Some(cubic_interpolator));
} else {
return StatusCode::MissingObject;
}
}
StatusCode::Ok
}
fn import(&self, object: Object, import_stack: &ImportStack) -> StatusCode {
if let Some(importer) =
import_stack.latest::<KeyedPropertyImporter>(TypeId::of::<KeyedProperty>())
{
importer.push_key_frame(object.as_ref().cast::<KeyFrame>().as_object());
StatusCode::Ok
} else {
StatusCode::MissingObject
}
}
}