Skip to content

Commit

Permalink
add animation manager
Browse files Browse the repository at this point in the history
  • Loading branch information
LetsMelon committed Jul 22, 2022
1 parent 825606a commit 43bd2fa
Show file tree
Hide file tree
Showing 8 changed files with 108 additions and 44 deletions.
19 changes: 12 additions & 7 deletions rusvid_cli/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use rusvid_lib::animation::manager::AnimationManager;
use rusvid_lib::prelude::*;
use rusvid_lib::usvg::{
BaseGradient, Color, LinearGradient, NodeKind, Opacity, Paint, Path, SpreadMethod, Stop,
Expand Down Expand Up @@ -71,19 +72,21 @@ fn main() {
));

composition.add_to_root(NodeKind::Path(Path {
id: "circle".to_string(),
stroke: Some(Stroke {
paint: Paint::Link("lg2".into()),
width: StrokeWidth::new(10.0),
..Stroke::default()
}),
rendering_mode: Default::default(),
data: Rc::new(figures::circle(700.0, 850.0, 600.0)),
data: circle_path.clone(),
..Path::default()
}));

let mut path = figures::equilateral_triangle(400.0, 400.0, 350.0);
path.transform(Transform::new_rotate(2.5));
composition.add_to_root(NodeKind::Path(Path {
id: "triangle".to_string(),
fill: composition.fill_with_link("lg1"),
data: Rc::new(path),
..Path::default()
Expand All @@ -99,6 +102,7 @@ fn main() {
));

composition.add_to_root(NodeKind::Path(Path {
id: "rect".to_string(),
fill: match composition.fill_with_link("lg1") {
None => None,
Some(mut f) => {
Expand All @@ -115,21 +119,21 @@ fn main() {

// TODO add builder pattern for video- & image-render
let animation_1 = animation::PositionAnimation::new(
position.clone(),
"rect".to_string(),
Box::new(
animation::functions::Linear::new(0, 200, pixel_position, (1250.0, 500.0).into())
.unwrap(),
),
);
let animation_2 = animation::PositionAnimation::new(
position,
"rect".to_string(),
Box::new(
animation::functions::Linear::new(220, 290, (1250.0, 500.0).into(), (0.0, 0.0).into())
.unwrap(),
),
);
let animation_3 = animation::PositionAnimation::new(
circle_path,
"circle".to_string(),
Box::new(
animation::functions::S::new(
0,
Expand All @@ -146,8 +150,9 @@ fn main() {

let mut renderer = FfmpegRenderer::new(out_path, tmp_path);
renderer.set_image_render(Box::new(PngRender::new()));
renderer.add_animation(Box::new(animation_1));
renderer.add_animation(Box::new(animation_2));
renderer.add_animation(Box::new(animation_3));

composition.animations.add_animation(animation_1);
composition.animations.add_animation(animation_2);
composition.animations.add_animation(animation_3);
renderer.render(composition).unwrap()
}
54 changes: 54 additions & 0 deletions rusvid_lib/src/animation/manager.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
use anyhow::Result;
use std::collections::HashMap;
use std::fmt::{Debug, Formatter};
use std::ops::Deref;
use std::rc::Rc;
use usvg::PathData;

use crate::animation::Animation;

#[derive(Debug)]
pub struct AnimationManager {
reference: HashMap<String, Rc<PathData>>,
animations: Vec<Box<dyn Animation>>,
}

impl Debug for dyn Animation {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
todo!()
}
}

impl AnimationManager {
pub fn new() -> AnimationManager {
AnimationManager {
reference: HashMap::new(),
animations: Vec::new(),
}
}

#[inline]
pub fn add_reference(&mut self, id: String, path: Rc<PathData>) {
self.reference.insert(id, path);
}

#[inline]
pub fn add_animation<T: Animation + 'static>(&mut self, animation: T) {
self.animations.push(Box::new(animation))
}

#[inline]
pub fn update(&mut self, frame_count: usize) -> Result<()> {
for animation in &mut self.animations {
let id = animation.object_id();
let rc = self.reference.get(id);

if let Some(pd) = rc {
unsafe {
let _ = animation.update(pd.clone(), &frame_count)?;
}
}
}
Ok(())
}
}
7 changes: 6 additions & 1 deletion rusvid_lib/src/animation/mod.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
use anyhow::Result;
use std::rc::Rc;
use usvg::PathData;

pub mod curves;
pub mod manager;
pub mod position_animation;

pub trait Animation {
// TODO maybe add internal frame_count state in the animation to track the frame number
/// Called once every frame
unsafe fn update(&mut self, frame_count: usize) -> Result<()>;
unsafe fn update(&mut self, path: Rc<PathData>, frame_count: &usize) -> Result<()>;

fn object_id(&self) -> &str;
}
27 changes: 15 additions & 12 deletions rusvid_lib/src/animation/position_animation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,31 @@ use crate::animation::curves::Function;
use crate::animation::Animation;

pub struct PositionAnimation {
position: Rc<PathData>,
meta: Box<dyn Function>,
object_id: String,
}

impl Debug for PositionAnimation {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str("Position Animation { ")?;
Debug::fmt(&self.position, f)?;
f.write_str(", ")?;
self.meta.internal_debug(f)?;
f.write_str(" }")
todo!()
}
}

impl PositionAnimation {
pub fn new(position: Rc<PathData>, meta: Box<dyn Function>) -> Self {
PositionAnimation { position, meta }
pub fn new(id: String, meta: Box<dyn Function>) -> Self {
PositionAnimation {
meta,
object_id: id,
}
}
}

impl Animation for PositionAnimation {
unsafe fn update(&mut self, frame_count: usize) -> anyhow::Result<()> {
if frame_count >= self.meta.start_frame() && frame_count < self.meta.end_frame() {
let pd = Rc::get_mut_unchecked(&mut self.position);
unsafe fn update(&mut self, mut path: Rc<PathData>, frame_count: &usize) -> anyhow::Result<()> {
if *frame_count >= self.meta.start_frame() && *frame_count < self.meta.end_frame() {
let pd = Rc::get_mut_unchecked(&mut path);

let delta = self.meta.delta(frame_count);
let delta = self.meta.delta(*frame_count);
println!("{} -> {:?}", frame_count, delta);
pd.transform(usvg::Transform::new_translate(delta.x(), delta.y()));
// let pos = self.meta.calc(frame_count);
Expand All @@ -40,4 +39,8 @@ impl Animation for PositionAnimation {
}
Ok(())
}

fn object_id(&self) -> &str {
&self.object_id
}
}
3 changes: 3 additions & 0 deletions rusvid_lib/src/composition/builder.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use crate::animation::manager::AnimationManager;
use debug_ignore::DebugIgnore;
use std::collections::HashMap;
use usvg::{AspectRatio, Size, Svg, Tree, ViewBox};

use crate::composition::Composition;
Expand Down Expand Up @@ -48,6 +50,7 @@ impl CompositionBuilder {
rtree: DebugIgnore(CompositionBuilder::create_tree_from_resolution(
self.resolution,
)),
animations: AnimationManager::new(),
}
}

Expand Down
16 changes: 14 additions & 2 deletions rusvid_lib/src/composition/comp.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use crate::animation::manager::AnimationManager;
use debug_ignore::DebugIgnore;
use std::collections::HashMap;
use std::ops::{Deref, DerefMut};
use usvg::{Fill, Node, NodeExt, NodeKind, Paint, Tree};
use std::rc::Rc;
use usvg::{Fill, Node, NodeExt, NodeKind, Paint, PathData, Tree};

use crate::composition::CompositionBuilder;
use crate::metrics::{MetricsSize, MetricsVideo};
Expand All @@ -21,6 +24,8 @@ pub struct Composition {
pub name: String,

pub(crate) rtree: DebugIgnore<Tree>,

pub animations: AnimationManager,
}

impl Composition {
Expand Down Expand Up @@ -50,7 +55,14 @@ impl Composition {
}

#[inline]
pub fn add_to_root(&self, kind: NodeKind) -> Node {
pub fn add_to_root(&mut self, kind: NodeKind) -> Node {
match &kind {
NodeKind::Path(path) => {
self.animations
.add_reference(path.id.clone(), path.data.clone());
}
_ => {}
}
self.rtree().root().append_kind(kind)
}

Expand Down
25 changes: 4 additions & 21 deletions rusvid_lib/src/renderer/ffmpeg/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ pub struct FfmpegRenderer {
pub image_render: DebugIgnore<Box<dyn ImageRender>>,
out_path: PathBuf,
tmp_dir_path: PathBuf,
animation: DebugIgnore<Vec<Box<dyn Animation>>>,
}

impl Default for FfmpegRenderer {
Expand All @@ -42,7 +41,6 @@ impl Default for FfmpegRenderer {
image_render: DebugIgnore(Box::new(PngRender::new())),
out_path: PathBuf::new(),
tmp_dir_path: PathBuf::new(),
animation: DebugIgnore(Vec::new()),
}
}
}
Expand All @@ -63,14 +61,10 @@ impl FfmpegRenderer {
pub fn set_image_render(&mut self, image_render: Box<dyn ImageRender>) {
self.image_render = DebugIgnore(image_render);
}

pub fn add_animation(&mut self, animation: Box<dyn Animation>) {
self.animation.push(animation)
}
}

impl Renderer for FfmpegRenderer {
fn render(&mut self, composition: Composition) -> Result<()> {
fn render(&mut self, mut composition: Composition) -> Result<()> {
self.framerate = composition.framerate;

let out_path = self.out_path().to_path_buf();
Expand All @@ -85,15 +79,11 @@ impl Renderer for FfmpegRenderer {
for i in 0..frames {
println!("{:03}/{:03}", i + 1, frames);

self.image_render().render(&composition, &tmp_path, i)?;

// TODO: make safe
// Test 1:
// let mut reference_position = box_position.borrow_mut();
// reference_position.transform(UsvgTransform::new_translate(5.0, 4.0));
unsafe {
let _ = &self.update(&i)?;
let _ = &composition.animations.update(*&i)?;
}

self.image_render().render(&composition, &tmp_path, i)?;
}

let mut command = self.build_command(&out_path, &tmp_path);
Expand All @@ -113,13 +103,6 @@ impl Renderer for FfmpegRenderer {
Ok(())
}

unsafe fn update(&mut self, frame_count: &usize) -> Result<()> {
for animation in self.animation.deref_mut() {
animation.update(*frame_count)?;
}
Ok(())
}

#[inline]
fn out_path(&self) -> &Path {
self.out_path.as_path()
Expand Down
1 change: 0 additions & 1 deletion rusvid_lib/src/renderer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ pub mod raw;

pub trait Renderer {
fn render(&mut self, composition: Composition) -> anyhow::Result<()>;
unsafe fn update(&mut self, frame_count: &usize) -> anyhow::Result<()>;

fn out_path(&self) -> &Path;
fn tmp_dir_path(&self) -> &Path;
Expand Down

0 comments on commit 43bd2fa

Please sign in to comment.