Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 🎸 safe thorvg wrapper #19

Merged
merged 4 commits into from
Dec 14, 2023
Merged
Changes from 2 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
283 changes: 196 additions & 87 deletions dotlottie-rs/src/dotlottie_player.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,153 @@ include!(concat!(env!("OUT_DIR"), "/bindings.rs"));

use std::ffi::CString;
use std::sync::atomic::AtomicI8;
use std::sync::{Arc, Mutex, RwLock};
use std::sync::Mutex;

pub mod thorvg {
use super::*;

pub struct Canvas {
raw_canvas: *mut Tvg_Canvas,
}

impl Canvas {
pub fn new(engine_method: Tvg_Engine, threads: u32) -> Self {
Canvas {
raw_canvas: unsafe {
tvg_engine_init(engine_method, threads);

tvg_swcanvas_create()
},
}
}

pub fn set_target(
&self,
buffer: *mut u32,
stride: u32,
width: u32,
height: u32,
color_space: Tvg_Colorspace,
) -> Tvg_Result {
unsafe {
tvg_swcanvas_set_target(self.raw_canvas, buffer, stride, width, height, color_space)
}
}

pub fn clear(&self, paints: bool, buffer: bool) -> Tvg_Result {
unsafe { tvg_canvas_clear(self.raw_canvas, paints, buffer) }
}

pub fn push(&self, picture: *mut Tvg_Paint) -> Tvg_Result {
unsafe { tvg_canvas_push(self.raw_canvas, picture) }
}

pub fn draw(&self) -> Tvg_Result {
unsafe { tvg_canvas_draw(self.raw_canvas) }
}

pub fn sync(&self) -> Tvg_Result {
unsafe { tvg_canvas_sync(self.raw_canvas) }
}

pub fn update(&self) -> Tvg_Result {
unsafe { tvg_canvas_update(self.raw_canvas) }
}

pub fn destroy(&self) -> Tvg_Result {
unsafe { tvg_canvas_destroy(self.raw_canvas) }
}

pub fn set_mempool(&self, policy: Tvg_Mempool_Policy) -> Tvg_Result {
unsafe { tvg_swcanvas_set_mempool(self.raw_canvas, policy) }
}
}

impl Drop for Canvas {
fn drop(&mut self) {
self.destroy();

self.raw_canvas = std::ptr::null_mut();
}
}

pub struct Animation {
raw_animation: *mut Tvg_Animation,
}

impl Animation {
pub fn new() -> Self {
Animation {
raw_animation: unsafe { tvg_animation_new() },
}
}

pub fn get_picture(&self) -> *mut Tvg_Paint {
unsafe { tvg_animation_get_picture(self.raw_animation) }
}

pub fn get_total_frame(&self) -> Result<f32, Tvg_Result> {
unsafe {
let mut total_frame: f32 = 0.0;

let result =
tvg_animation_get_total_frame(self.raw_animation, &mut total_frame as *mut f32);

if result != Tvg_Result_TVG_RESULT_SUCCESS {
return Err(result);
}

return Ok(total_frame);
}
}

pub fn get_duration(&self) -> Result<f32, Tvg_Result> {
unsafe {
let mut duration: f32 = 0.0;

let result =
tvg_animation_get_duration(self.raw_animation, &mut duration as *mut f32);

if result != Tvg_Result_TVG_RESULT_SUCCESS {
return Err(result);
}

return Ok(duration);
}
}

pub fn set_frame(&self, frame_no: f32) -> Tvg_Result {
unsafe { tvg_animation_set_frame(self.raw_animation, frame_no) }
}

pub fn get_frame(&self) -> Result<f32, Tvg_Result> {
unsafe {
let mut curr_frame: f32 = 0.0;

let result =
tvg_animation_get_frame(self.raw_animation, &mut curr_frame as *mut f32);

if result != Tvg_Result_TVG_RESULT_SUCCESS {
return Err(result);
}

Ok(curr_frame)
}
}

pub fn del(&self) -> Tvg_Result {
unsafe { tvg_animation_del(self.raw_animation) }
}
}

impl Drop for Animation {
fn drop(&mut self) {
self.del();

self.raw_animation = std::ptr::null_mut();
}
}
}

#[allow(dead_code)]
pub struct DotLottiePlayer {
Expand All @@ -16,67 +162,64 @@ pub struct DotLottiePlayer {
speed: i32,
direction: AtomicI8,

// Animation information related
current_frame: Arc<RwLock<f32>>,
total_frames: Arc<RwLock<f32>>,
duration: Arc<RwLock<f32>>,

// Data
animation: Arc<RwLock<*mut Tvg_Animation>>,
canvas: Arc<RwLock<*mut Tvg_Canvas>>,
animation: thorvg::Animation,
canvas: thorvg::Canvas,
buffer: Mutex<Vec<u32>>,
}

impl DotLottiePlayer {
pub fn new() -> Self {
let canvas = thorvg::Canvas::new(Tvg_Engine_TVG_ENGINE_SW, 0);
let animation = thorvg::Animation::new();
let buffer = Mutex::new(vec![]);

DotLottiePlayer {
autoplay: false,
loop_animation: false,
speed: 1,
direction: AtomicI8::new(1),
current_frame: Arc::new(RwLock::new(0.0)),

total_frames: Arc::new(RwLock::new(0.0)),
duration: Arc::new(RwLock::new(0.0)),
animation: Arc::new(RwLock::new(std::ptr::null_mut())),
canvas: Arc::new(RwLock::new(std::ptr::null_mut())),
buffer: Mutex::new(vec![]),
// For some reason initializing here doesn't work
// animation: tvg_animation_new(),
// canvas: tvg_swcanvas_create(),
animation,
canvas,
buffer,
}
}

pub fn frame(&self, no: f32) {
unsafe {
let current_frame = &mut *self.current_frame.write().unwrap();
let animation = self.animation.read().unwrap().as_mut().unwrap();
let canvas = self.canvas.read().unwrap().as_mut().unwrap();

*current_frame = no;

tvg_canvas_clear(canvas, false, true);

tvg_animation_set_frame(animation, *current_frame);
self.canvas.clear(false, true);

tvg_canvas_update(canvas);
self.animation.set_frame(no);

tvg_canvas_draw(canvas);

tvg_canvas_sync(canvas);
}
self.canvas.update();
self.canvas.draw();
self.canvas.sync();
}

pub fn get_total_frame(&self) -> f32 {
return self.total_frames.read().unwrap().clone();
let total_frames = self.animation.get_total_frame();

match total_frames {
Ok(total_frames) => total_frames,
Err(_) => 0.0,
}
}

pub fn get_duration(&self) -> f32 {
return self.duration.read().unwrap().clone();
let duration = self.animation.get_duration();

match duration {
Ok(duration) => duration,
Err(_) => 0.0,
}
}

pub fn get_current_frame(&self) -> f32 {
return self.current_frame.read().unwrap().clone();
let result = self.animation.get_frame();

match result {
Ok(frame) => frame,
Err(_) => 0.0,
}
}

pub fn get_buffer(&self) -> i64 {
Expand All @@ -91,52 +234,33 @@ impl DotLottiePlayer {
}

pub fn clear(&self) {
unsafe {
let canvas = self.canvas.read().unwrap().as_mut().unwrap();

tvg_canvas_clear(canvas, false, true);
}
self.canvas.clear(false, true);
}

pub fn load_animation_from_path(&self, path: &str, width: u32, height: u32) -> bool {
unsafe {
tvg_engine_init(Tvg_Engine_TVG_ENGINE_SW, 0);

*self.canvas.write().unwrap() = tvg_swcanvas_create();

let canvas = self.canvas.read().unwrap().as_mut().unwrap();

let mut buffer_lock = self.buffer.lock().unwrap();

*buffer_lock = vec![0; (width * height * 4) as usize];

// self.buffer.as = vec![width * height];

tvg_swcanvas_set_target(
canvas,
self.canvas.set_target(
buffer_lock.as_ptr() as *mut u32,
width,
width,
height,
Tvg_Colorspace_TVG_COLORSPACE_ABGR8888,
);

*self.animation.write().unwrap() = tvg_animation_new();

let animation = self.animation.read().unwrap().as_mut().unwrap();

let frame_image = tvg_animation_get_picture(animation);
let frame_image = self.animation.get_picture();

let load_result =
tvg_picture_load(frame_image, path.as_ptr() as *const std::os::raw::c_char);

if load_result != Tvg_Result_TVG_RESULT_SUCCESS {
tvg_animation_del(animation);
self.animation.del();

return false;
} else {
let total_frames = &mut *self.total_frames.write().unwrap();
let duration = &mut *self.duration.write().unwrap();
let mut pw: f32 = 0.0;
let mut ph: f32 = 0.0;
let scale: f32;
Expand All @@ -156,12 +280,11 @@ impl DotLottiePlayer {
tvg_paint_scale(frame_image, scale);
tvg_paint_translate(frame_image, shiftX, shiftY);

tvg_animation_get_total_frame(animation, total_frames as *mut f32);
tvg_animation_get_duration(animation, duration as *mut f32);
tvg_animation_set_frame(animation, 0.0);
tvg_canvas_push(canvas, frame_image);
tvg_canvas_draw(canvas);
tvg_canvas_sync(canvas);
self.animation.set_frame(0.0);

self.canvas.push(frame_image);
self.canvas.draw();
self.canvas.sync();
}
}

Expand All @@ -172,30 +295,19 @@ impl DotLottiePlayer {
let mimetype = CString::new("lottie").expect("Failed to create CString");

unsafe {
tvg_engine_init(Tvg_Engine_TVG_ENGINE_SW, 0);

*self.canvas.write().unwrap() = tvg_swcanvas_create();

let canvas = self.canvas.read().unwrap().as_mut().unwrap();

let mut buffer_lock = self.buffer.lock().unwrap();

*buffer_lock = vec![0; (width * height * 4) as usize];

tvg_swcanvas_set_target(
canvas,
self.canvas.set_target(
buffer_lock.as_ptr() as *mut u32,
width,
width,
height,
Tvg_Colorspace_TVG_COLORSPACE_ABGR8888,
);

*self.animation.write().unwrap() = tvg_animation_new();

let animation = self.animation.read().unwrap().as_mut().unwrap();

let frame_image = tvg_animation_get_picture(animation);
let frame_image = self.animation.get_picture();

// resource path (null if not needed)
let rpath = std::ptr::null();
Expand All @@ -210,12 +322,10 @@ impl DotLottiePlayer {
);

if load_result != Tvg_Result_TVG_RESULT_SUCCESS {
tvg_animation_del(animation);
self.animation.del();

return false;
} else {
let total_frames = &mut *self.total_frames.write().unwrap();
let duration = &mut *self.duration.write().unwrap();
let mut pw: f32 = 0.0;
let mut ph: f32 = 0.0;
let scale: f32;
Expand All @@ -235,12 +345,11 @@ impl DotLottiePlayer {
tvg_paint_scale(frame_image, scale);
tvg_paint_translate(frame_image, shiftX, shiftY);

tvg_animation_get_total_frame(animation, total_frames as *mut f32);
tvg_animation_get_duration(animation, duration as *mut f32);
tvg_animation_set_frame(animation, 0.0);
tvg_canvas_push(canvas, frame_image);
tvg_canvas_draw(canvas);
tvg_canvas_sync(canvas);
self.animation.set_frame(0.0);

self.canvas.push(frame_image);
self.canvas.draw();
self.canvas.sync();
}
}

Expand Down