Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions rusvid_lib/benches/image_render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,18 @@ use rusvid_lib::utils::color_from_hex;
use std::rc::Rc;

#[inline(always)]
fn raw(comp: &Composition) {
let image_render = RawRender::new();
fn raw(comp: &mut Composition) {
let mut image_render = RawRender::new();

let data = image_render.calculate_image_buffer(&comp).unwrap();
let data = image_render.calculate_image_buffer(comp, &0).unwrap();
assert_eq!(data.pixels().len(), 10_000);
}

#[inline(always)]
fn png(comp: &Composition) {
let image_render = PngRender::new();
fn png(comp: &mut Composition) {
let mut image_render = PngRender::new();

let pixmap = image_render.render_pixmap(&comp).unwrap();
let pixmap = image_render.render_pixmap(comp, &0).unwrap();
let data = pixmap.encode_png().unwrap();
assert_eq!(data.len(), 735);
}
Expand Down Expand Up @@ -78,8 +78,8 @@ fn criterion_benchmark(c: &mut Criterion) {
.unwrap();
composition.add_layer(layer);

c.bench_function("raw", |b| b.iter(|| raw(black_box(&composition))));
c.bench_function("png", |b| b.iter(|| png(black_box(&composition))));
c.bench_function("raw", |b| b.iter(|| raw(black_box(&mut composition))));
c.bench_function("png", |b| b.iter(|| png(black_box(&mut composition))));
}

criterion_group!(benches, criterion_benchmark);
Expand Down
38 changes: 36 additions & 2 deletions rusvid_lib/src/animation/curves/linear.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ use std::fmt::{Debug, Formatter};
use crate::animation::curves::Points::*;
use crate::animation::curves::{Function, Points};

use super::has_update_function;

#[derive(Debug, Copy, Clone)]
pub struct Linear {
start_frame: usize,
Expand All @@ -28,8 +30,14 @@ impl Function for Linear {
let start_frame_point = Point2d(start_frame as f64, start_frame as f64);
let end_frame_point = Point2d(end_frame as f64, end_frame as f64);

let k = (end - start) / (end_frame_point - start_frame_point);
let d = end - k * end_frame_point;
let (k, d) = if start == end && start == Points::zero_2d() {
(Points::zero_2d(), Points::zero_2d())
} else {
let k = (end - start) / (end_frame_point - start_frame_point);
let d = end - k * end_frame_point;

(k, d)
};

Ok(Linear {
start_frame,
Expand Down Expand Up @@ -61,6 +69,15 @@ impl Function for Linear {
self.end
}

fn has_update(&self, frame_number: &usize) -> bool {
let linear_change = self.k == self.d && self.k == Points::zero_2d();
if linear_change {
return false;
}

has_update_function(self.start_frame(), self.end_frame(), frame_number)
}

#[inline]
fn calc_raw(&self, frame_number: usize) -> Points {
let frame_number = frame_number as f64;
Expand Down Expand Up @@ -159,4 +176,21 @@ mod tests {
assert_eq!(linear.calc(5), Point1d(15.0));
assert_eq!(linear.calc(10), Point1d(20.0));
}

#[test]
fn has_update() {
let linear = Linear::new(30, 90, Point1d(0.0), Point1d(100.0)).unwrap();

assert!(!linear.has_update(&0));
assert!(linear.has_update(&30));
assert!(linear.has_update(&90));
assert!(!linear.has_update(&100));

let linear = Linear::new(30, 90, Point1d(0.0), Point1d(0.0)).unwrap();

assert!(!linear.has_update(&0));
assert!(!linear.has_update(&30));
assert!(!linear.has_update(&90));
assert!(!linear.has_update(&100));
}
}
86 changes: 86 additions & 0 deletions rusvid_lib/src/animation/curves/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ use std::ops::{Add, Div, Mul, Neg, Sub};
pub mod linear;
pub mod s;

#[inline(always)]
pub(crate) fn has_update_function(
start_frame: usize,
end_frame: usize,
frame_number: &usize,
) -> bool {
*frame_number >= start_frame && *frame_number <= end_frame
}

/// ```rust
/// use rusvid_lib::animation::curves::linear::Linear;
/// use rusvid_lib::animation::curves::Function;
Expand All @@ -26,6 +35,10 @@ pub trait Function: std::fmt::Debug {
fn start(&self) -> Points;
fn end(&self) -> Points;

fn has_update(&self, frame_number: &usize) -> bool {
has_update_function(self.start_frame(), self.end_frame(), frame_number)
}

fn calc_raw(&self, frame_number: usize) -> Points;
fn calc(&self, frame_number: usize) -> Points {
if frame_number <= self.start_frame() {
Expand Down Expand Up @@ -219,6 +232,79 @@ impl Neg for Points {

#[cfg(test)]
mod tests {
mod function {
use anyhow::Result;

use crate::animation::curves::{Function, Points};

#[derive(Debug)]
struct TestFunction {
start_frame: usize,
end_frame: usize,
}

impl Function for TestFunction {
fn new(
start_frame: usize,
end_frame: usize,
_start: Points,
_end: Points,
) -> Result<Self>
where
Self: Sized,
{
Ok(TestFunction {
start_frame,
end_frame,
})
}

fn start_frame(&self) -> usize {
self.start_frame
}

fn end_frame(&self) -> usize {
self.end_frame
}

fn start(&self) -> crate::prelude::animation::Points {
todo!()
}

fn end(&self) -> crate::prelude::animation::Points {
todo!()
}

fn calc_raw(&self, _frame_number: usize) -> crate::prelude::animation::Points {
todo!()
}

fn delta_raw(&self, _frame_number: usize) -> crate::prelude::animation::Points {
todo!()
}

fn internal_debug(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
todo!()
}
}

mod has_update {
use super::*;

#[test]
fn is_only_true_if_updated() {
let item = TestFunction::new(10, 20, (0.0, 0.0).into(), (0.0, 0.0).into()).unwrap();

assert!(!item.has_update(&0));
assert!(!item.has_update(&50));

assert!(item.has_update(&10));
assert!(item.has_update(&15));
assert!(item.has_update(&20));
}
}
}

mod points {
use crate::animation::curves::Points::*;

Expand Down
75 changes: 75 additions & 0 deletions rusvid_lib/src/animation/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use std::rc::Rc;
use usvg::PathData;

use crate::animation::Animation;
use crate::layer::CacheLogic;

#[derive(Debug)]
pub struct AnimationManager {
Expand Down Expand Up @@ -45,3 +46,77 @@ impl AnimationManager {
Ok(())
}
}

impl CacheLogic for AnimationManager {
fn has_update(&self, frame_count: &usize) -> bool {
if self.animations.len() == 0 {
return false;
}

self.animations
.iter()
.map(|animation| animation.has_update(&frame_count))
.reduce(|accum, item| accum | item)
.unwrap_or(false)
}
}

#[cfg(test)]
mod tests {
mod cache_logic {
mod has_update {
use crate::animation::curves::Function;
use crate::animation::manager::{AnimationManager, CacheLogic};
use crate::prelude::animation::functions::Linear;
use crate::prelude::animation::PositionAnimation;

#[test]
fn return_false_if_no_animation() {
let manager = AnimationManager::new();

assert!(!manager.has_update(&0));
assert!(!manager.has_update(&1_000));
}

#[test]
fn works_with_multiple_animations() {
let mut manager = AnimationManager::new();

// dry run
assert!(!manager.has_update(&0));
assert!(!manager.has_update(&20));
assert!(!manager.has_update(&25));
assert!(!manager.has_update(&35));
assert!(!manager.has_update(&50));
assert!(!manager.has_update(&55));
assert!(!manager.has_update(&60));
assert!(!manager.has_update(&65));
assert!(!manager.has_update(&75));

manager.add_animation(PositionAnimation::new(
"test_1".to_string(),
Linear::new(25, 50, (0.0, 0.0).into(), (1.0, 0.0).into()).unwrap(),
));
manager.add_animation(PositionAnimation::new(
"test_2".to_string(),
Linear::new(35, 55, (0.0, 0.0).into(), (1.0, 0.0).into()).unwrap(),
));
manager.add_animation(PositionAnimation::new(
"test_3".to_string(),
Linear::new(65, 70, (0.0, 0.0).into(), (1.0, 0.0).into()).unwrap(),
));

// check values
assert!(!manager.has_update(&0));
assert!(!manager.has_update(&20));
assert!(manager.has_update(&25));
assert!(manager.has_update(&35));
assert!(manager.has_update(&50));
assert!(manager.has_update(&55));
assert!(!manager.has_update(&60));
assert!(manager.has_update(&65));
assert!(!manager.has_update(&75));
}
}
}
}
4 changes: 3 additions & 1 deletion rusvid_lib/src/animation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ use anyhow::Result;
use std::rc::Rc;
use usvg::PathData;

use crate::layer::CacheLogic;

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

pub trait Animation: std::fmt::Debug {
pub trait Animation: std::fmt::Debug + CacheLogic {
// TODO maybe add internal frame_count state in the animation to track the frame number
/// Called once every frame
unsafe fn update(&mut self, path: Rc<PathData>, frame_count: &usize) -> Result<()>;
Expand Down
9 changes: 8 additions & 1 deletion rusvid_lib/src/animation/position_animation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use usvg::PathData;

use crate::animation::curves::Function;
use crate::animation::Animation;
use crate::layer::CacheLogic;

#[derive(Debug)]
pub struct PositionAnimation {
Expand All @@ -22,7 +23,7 @@ impl PositionAnimation {

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

let delta = self.curve.delta(*frame_count);
Expand All @@ -39,3 +40,9 @@ impl Animation for PositionAnimation {
&self.object_id
}
}

impl CacheLogic for PositionAnimation {
fn has_update(&self, frame_count: &usize) -> bool {
self.curve.has_update(frame_count)
}
}
5 changes: 5 additions & 0 deletions rusvid_lib/src/composition/comp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ impl Composition {
&self.layers
}

#[inline]
pub fn get_layers_mut(&mut self) -> &mut Vec<Layer> {
&mut self.layers
}

#[inline]
pub fn update(&mut self, frame_count: usize) -> Result<()> {
for layer in &mut self.layers {
Expand Down
15 changes: 15 additions & 0 deletions rusvid_lib/src/layer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use debug_ignore::DebugIgnore;
use std::fs::{canonicalize, read};
use std::ops::{Deref, DerefMut};
use std::path::Path;
use tiny_skia::Pixmap;
use usvg::{Fill, Node, NodeExt, NodeKind, Options, Paint, Tree};

use crate::animation::manager::AnimationManager;
Expand All @@ -19,13 +20,20 @@ pub trait LayerLogic {
fn add_animation<T: Animation + 'static>(&mut self, animation: T);
}

pub trait CacheLogic {
/// returns `false` if no animation happens between `frame_count - 1` and `frame_count`, otherwise returns `true`
fn has_update(&self, frame_count: &usize) -> bool;
}

#[derive(Debug)]
pub struct Layer {
name: String,

rtree: DebugIgnore<Tree>,

animations: AnimationManager,

pub(crate) cache: Option<Pixmap>,
}

impl Layer {
Expand All @@ -35,6 +43,7 @@ impl Layer {
name: "layer_0".to_string(),
rtree: DebugIgnore(CompositionBuilder::create_tree_from_resolution(resolution)),
animations: AnimationManager::new(),
cache: None,
}
}

Expand Down Expand Up @@ -125,3 +134,9 @@ impl LayerLogic for Layer {
self.animations.add_animation(animation);
}
}

impl CacheLogic for Layer {
fn has_update(&self, frame_count: &usize) -> bool {
self.animations.has_update(frame_count)
}
}
1 change: 1 addition & 0 deletions rusvid_lib/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#![feature(get_mut_unchecked)]
#![feature(let_chains)]

pub mod animation;
pub mod composition;
Expand Down
Loading