use std::str::FromStr; use crate::animation::primitives::{ interpolations::{EasingFunction, InterpolationType, SpringProperties}, keyframe::{Keyframe, Keyframes}, }; use rayon::prelude::*; use serde::{Deserialize, Serialize}; use super::primitives::{ entities::{ common::{AnimatedEntity, AnimationData, Cache, Entity}, rect::AnimatedRectEntity, text::AnimatedTextEntity, }, paint::{Color, FillStyle, Paint, PaintStyle, StrokeStyle, TextAlign, TextPaint}, values::{AnimatedFloat, AnimatedFloatVec2}, }; #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Input { pub title: String, pub sub_title: String, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Timeline { entities: Vec, pub render_state: RenderState, pub duration: f32, pub fps: i16, pub size: (i32, i32), } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct RenderState { pub curr_frame: i32, } impl Timeline { fn calculate(&self) -> Vec { let mut entities = self.entities.clone(); let entities = entities .par_iter_mut() .map(|entity| entity.calculate(self)) .filter(|entity| entity.is_some()) .map(|entity| entity.unwrap()) .collect(); return entities; } } fn build_bg(offset: f32, paint: Paint, size: (i32, i32)) -> AnimatedRectEntity { let bg_box = AnimatedRectEntity { id: String::from_str("1").unwrap(), paint, animation_data: AnimationData { offset: 0.0 + offset, duration: 5.0, visible: true, }, cache: Cache { valid: false }, transform: None, origin: AnimatedFloatVec2::new(1280.0 / 2.0, 720.0 / 2.0), position: AnimatedFloatVec2 { keyframes: ( AnimatedFloat { keyframes: Keyframes { values: vec![ Keyframe { id: "1".into(), value: (size.0 * -1) as f32, offset: 0.0, interpolation: Some(InterpolationType::EasingFunction( EasingFunction::QuintOut, )), }, Keyframe { id: "2".into(), value: 0.0, offset: 5.0, interpolation: None, }, ], }, }, AnimatedFloat { keyframes: Keyframes { values: vec![Keyframe { id: "3".into(), value: 0.0, offset: 0.0, interpolation: None, }], }, }, ), }, size: AnimatedFloatVec2 { keyframes: ( AnimatedFloat { keyframes: Keyframes { values: vec![Keyframe { id: "4".into(), interpolation: None, value: size.0 as f32, offset: 0.0, }], }, }, AnimatedFloat { keyframes: Keyframes { values: vec![Keyframe { id: "5".into(), value: size.1 as f32, offset: 0.0, interpolation: None, }], }, }, ), }, }; return bg_box; } #[tauri::command] pub fn calculate_timeline_entities_at_frame(timeline: Timeline) -> Vec { timeline.calculate() } pub fn test_timeline_entities_at_frame( render_state: RenderState, size: (i32, i32), input: Input, ) -> Vec { let rect1_paint = Paint { style: PaintStyle::Fill(FillStyle { color: Color::new(34, 189, 58, 1.0), }), }; let rect2_paint = Paint { style: PaintStyle::Fill(FillStyle { color: Color::new(23, 178, 28, 1.0), }), }; let rect3_paint = Paint { style: PaintStyle::Fill(FillStyle { color: Color::new(43, 128, 98, 1.0), }), }; let title_paint = TextPaint { style: PaintStyle::Stroke(StrokeStyle { color: Color::new(0, 0, 0, 1.0), width: 10.0, }), font_name: "Arial".into(), align: TextAlign::Center, size: 20.0, }; let sub_title_paint = TextPaint { style: PaintStyle::Fill(FillStyle { color: Color::new(0, 0, 0, 1.0), }), font_name: "Arial".into(), align: TextAlign::Center, size: 10.0, }; let timeline = Timeline { fps: 60, duration: 5.0, size, entities: vec![ AnimatedEntity::Rect(build_bg(0.0, rect1_paint, size)), AnimatedEntity::Rect(build_bg(0.5, rect2_paint, size)), AnimatedEntity::Rect(build_bg(1.0, rect3_paint, size)), AnimatedEntity::Text(AnimatedTextEntity { id: String::from_str("2").unwrap(), paint: title_paint, cache: Cache { valid: false }, text: input.title, animation_data: AnimationData { offset: 0.0, duration: 6.0, visible: true, }, transform: None, origin: AnimatedFloatVec2 { keyframes: ( AnimatedFloat { keyframes: Keyframes { values: vec![ Keyframe { id: "1".into(), value: 0.0, offset: 0.0, interpolation: Some(InterpolationType::Spring( SpringProperties { mass: 1.0, damping: 20.0, stiffness: 200.0, }, )), }, Keyframe { id: "2".into(), value: (size.0 / 2) as f32, offset: 2.0, interpolation: None, }, ], }, }, AnimatedFloat { keyframes: Keyframes { values: vec![Keyframe { id: "3".into(), value: (size.1 / 2) as f32, offset: 0.0, interpolation: None, }], }, }, ), }, }), AnimatedEntity::Text(AnimatedTextEntity { id: String::from_str("3").unwrap(), paint: sub_title_paint, text: input.sub_title, cache: Cache { valid: false }, animation_data: AnimationData { offset: 0.5, duration: 6.0, visible: true, }, transform: None, origin: AnimatedFloatVec2 { keyframes: ( AnimatedFloat { keyframes: Keyframes { values: vec![ Keyframe { id: "5".into(), value: 0.0, offset: 0.0, interpolation: Some(InterpolationType::Spring( SpringProperties { mass: 1.0, damping: 20.0, stiffness: 200.0, }, )), }, Keyframe { id: "6".into(), value: (size.0 / 2) as f32, offset: 2.0, interpolation: None, }, ], }, }, AnimatedFloat { keyframes: Keyframes { values: vec![Keyframe { id: "7".into(), value: ((size.1 / 2) as f32) + 80.0, offset: 0.0, interpolation: None, }], }, }, ), }, }), ], render_state: render_state, }; timeline.calculate() }