use crate::{AnimatedDataSystem, DataSystem, GenericValue, Time, ToF32};
#[cfg(feature = "builtin-types")]
use crate::{Data, Value};
use egui_keyframe::{
BezierHandles, KeyframeId, KeyframeSource, KeyframeType, KeyframeView, TimeTick, uuid,
};
fn time_to_keyframe_id(time: Time) -> KeyframeId {
let raw: i64 = time.into();
let mut uuid_bytes = [0u8; 16];
uuid_bytes[..8].copy_from_slice(&raw.to_le_bytes());
uuid_bytes[8..16].copy_from_slice(b"tvmtime\0");
KeyframeId(uuid::Uuid::from_bytes(uuid_bytes))
}
fn time_to_timetick(time: Time) -> TimeTick {
TimeTick::new(time.to_secs())
}
#[cfg(feature = "builtin-types")]
fn data_to_f32(data: &Data) -> Option<f32> {
data.to_f32().ok()
}
impl<D> KeyframeSource for GenericValue<D>
where
D: DataSystem + ToF32,
{
fn keyframes_sorted(&self) -> Vec<KeyframeView> {
match self {
GenericValue::Uniform(data) => {
if let Some(value) = data.to_f32() {
vec![KeyframeView::new(
time_to_keyframe_id(Time::from_secs(0.0)),
TimeTick::new(0.0),
value,
BezierHandles::linear(),
true,
KeyframeType::Linear,
)]
} else {
vec![]
}
}
GenericValue::Animated(animated) => {
let times = animated.times();
let mut keyframes: Vec<_> = times
.into_iter()
.filter_map(|time| {
let data = animated.sample_at(time)?;
let value = data.to_f32()?;
Some(KeyframeView::new(
time_to_keyframe_id(time),
time_to_timetick(time),
value,
BezierHandles::linear(),
true,
KeyframeType::Linear,
))
})
.collect();
keyframes.sort_by(|a, b| {
a.position
.partial_cmp(&b.position)
.unwrap_or(std::cmp::Ordering::Equal)
});
keyframes
}
}
}
fn value_range(&self) -> Option<(f32, f32)> {
match self {
GenericValue::Uniform(data) => {
let value = data.to_f32()?;
Some((value, value))
}
GenericValue::Animated(animated) => {
let times = animated.times();
if times.is_empty() {
return None;
}
let mut min = f32::MAX;
let mut max = f32::MIN;
for time in times {
if let Some(data) = animated.sample_at(time)
&& let Some(value) = data.to_f32()
{
min = min.min(value);
max = max.max(value);
}
}
if min > max { None } else { Some((min, max)) }
}
}
}
fn len(&self) -> usize {
match self {
GenericValue::Uniform(_) => 1,
GenericValue::Animated(animated) => animated.times().len(),
}
}
}
#[cfg(feature = "builtin-types")]
impl KeyframeSource for Value {
fn keyframes_sorted(&self) -> Vec<KeyframeView> {
match self {
Value::Uniform(data) => {
if let Some(value) = data_to_f32(data) {
vec![KeyframeView::new(
time_to_keyframe_id(Time::from_secs(0.0)),
TimeTick::new(0.0),
value,
BezierHandles::linear(),
true,
KeyframeType::Linear,
)]
} else {
vec![]
}
}
Value::Animated(animated) => {
let times = animated.times();
let mut keyframes: Vec<_> = times
.into_iter()
.filter_map(|time| {
let data = animated.sample_at(time)?;
let value = data_to_f32(&data)?;
#[cfg(feature = "interpolation")]
let (handles, keyframe_type) = {
let handles = animated
.bezier_handles(&time)
.unwrap_or_else(BezierHandles::linear);
let kf_type = if handles.left_x == 0.0
&& handles.left_y == 0.0
&& handles.right_x == 0.0
&& handles.right_y == 0.0
{
KeyframeType::Linear
} else {
KeyframeType::Bezier
};
(handles, kf_type)
};
#[cfg(not(feature = "interpolation"))]
let (handles, keyframe_type) =
(BezierHandles::linear(), KeyframeType::Linear);
Some(KeyframeView::new(
time_to_keyframe_id(time),
time_to_timetick(time),
value,
handles,
true,
keyframe_type,
))
})
.collect();
keyframes.sort_by(|a, b| {
a.position
.partial_cmp(&b.position)
.unwrap_or(std::cmp::Ordering::Equal)
});
keyframes
}
}
}
fn value_range(&self) -> Option<(f32, f32)> {
match self {
Value::Uniform(data) => {
let value = data_to_f32(data)?;
Some((value, value))
}
Value::Animated(animated) => {
let times = animated.times();
if times.is_empty() {
return None;
}
let mut min = f32::MAX;
let mut max = f32::MIN;
for time in times {
if let Some(data) = animated.sample_at(time)
&& let Some(value) = data_to_f32(&data)
{
min = min.min(value);
max = max.max(value);
}
}
if min > max { None } else { Some((min, max)) }
}
}
}
fn len(&self) -> usize {
match self {
Value::Uniform(_) => 1,
Value::Animated(animated) => animated.times().len(),
}
}
}
#[cfg(all(test, feature = "builtin-types"))]
mod tests {
use super::*;
use crate::Real;
#[test]
fn uniform_value_keyframe_source() {
let value = Value::uniform(Data::Real(Real(42.0)));
let keyframes = value.keyframes_sorted();
assert_eq!(keyframes.len(), 1);
assert_eq!(keyframes[0].value, 42.0);
}
#[test]
fn animated_value_keyframe_source() {
let value = Value::animated(vec![
(Time::from_secs(0.0), 0.0),
(Time::from_secs(1.0), 10.0),
(Time::from_secs(2.0), 5.0),
])
.unwrap();
let keyframes = value.keyframes_sorted();
assert_eq!(keyframes.len(), 3);
assert_eq!(keyframes[0].value, 0.0);
assert_eq!(keyframes[1].value, 10.0);
assert_eq!(keyframes[2].value, 5.0);
let (min, max) = value.value_range().unwrap();
assert_eq!(min, 0.0);
assert_eq!(max, 10.0);
}
}