use crate::color::{Rgb, Rgba};
use crate::error::{Error, Result};
use crate::paint::Paint;
use thorvg_sys as sys;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(i32)]
pub enum BlurDirection {
Both = 0,
Horizontal = 1,
Vertical = 2,
}
impl BlurDirection {
fn to_raw(self) -> core::ffi::c_int {
self as core::ffi::c_int
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(i32)]
pub enum BlurBorder {
Duplicate = 0,
Wrap = 1,
}
impl BlurBorder {
fn to_raw(self) -> core::ffi::c_int {
self as core::ffi::c_int
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct GaussianBlur {
pub sigma: f64,
pub direction: BlurDirection,
pub border: BlurBorder,
pub quality: u8,
}
impl GaussianBlur {
#[must_use]
pub const fn new() -> Self {
Self {
sigma: 2.0,
direction: BlurDirection::Both,
border: BlurBorder::Duplicate,
quality: 50,
}
}
#[must_use]
pub const fn sigma(mut self, sigma: f64) -> Self {
self.sigma = sigma;
self
}
#[must_use]
pub const fn direction(mut self, direction: BlurDirection) -> Self {
self.direction = direction;
self
}
#[must_use]
pub const fn border(mut self, border: BlurBorder) -> Self {
self.border = border;
self
}
#[must_use]
pub const fn quality(mut self, quality: u8) -> Self {
self.quality = quality;
self
}
}
impl Default for GaussianBlur {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct DropShadow {
pub color: Rgba,
pub angle: f64,
pub distance: f64,
pub sigma: f64,
pub quality: u8,
}
impl DropShadow {
#[must_use]
pub const fn new() -> Self {
Self {
color: Rgba::new(0, 0, 0, 255),
angle: 0.0,
distance: 4.0,
sigma: 2.0,
quality: 50,
}
}
#[must_use]
pub const fn color(mut self, color: Rgba) -> Self {
self.color = color;
self
}
#[must_use]
pub const fn angle(mut self, angle: f64) -> Self {
self.angle = angle;
self
}
#[must_use]
pub const fn distance(mut self, distance: f64) -> Self {
self.distance = distance;
self
}
#[must_use]
pub const fn sigma(mut self, sigma: f64) -> Self {
self.sigma = sigma;
self
}
#[must_use]
pub const fn quality(mut self, quality: u8) -> Self {
self.quality = quality;
self
}
}
impl Default for DropShadow {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Tritone {
pub shadow: Rgb,
pub midtone: Rgb,
pub highlight: Rgb,
pub blend: u8,
}
impl Tritone {
#[must_use]
pub const fn new() -> Self {
Self {
shadow: Rgb::new(0, 0, 0),
midtone: Rgb::new(128, 128, 128),
highlight: Rgb::new(255, 255, 255),
blend: 128,
}
}
#[must_use]
pub const fn shadow(mut self, shadow: Rgb) -> Self {
self.shadow = shadow;
self
}
#[must_use]
pub const fn midtone(mut self, midtone: Rgb) -> Self {
self.midtone = midtone;
self
}
#[must_use]
pub const fn highlight(mut self, highlight: Rgb) -> Self {
self.highlight = highlight;
self
}
#[must_use]
pub const fn blend(mut self, blend: u8) -> Self {
self.blend = blend;
self
}
}
impl Default for Tritone {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Tint {
pub black: Rgb,
pub white: Rgb,
pub intensity: f64,
}
impl Tint {
#[must_use]
pub const fn new() -> Self {
Self {
black: Rgb::new(0, 0, 0),
white: Rgb::new(255, 255, 255),
intensity: 50.0,
}
}
#[must_use]
pub const fn black(mut self, black: Rgb) -> Self {
self.black = black;
self
}
#[must_use]
pub const fn white(mut self, white: Rgb) -> Self {
self.white = white;
self
}
#[must_use]
pub const fn intensity(mut self, intensity: f64) -> Self {
self.intensity = intensity;
self
}
}
impl Default for Tint {
fn default() -> Self {
Self::new()
}
}
pub struct Scene<'eng> {
raw: sys::Tvg_Paint,
owned: bool,
_engine: core::marker::PhantomData<&'eng ()>,
}
unsafe impl Send for Scene<'_> {}
impl Scene<'_> {
pub(crate) fn new() -> Result<Self> {
let raw = unsafe { sys::tvg_scene_new() };
if raw.is_null() {
return Err(Error::FailedAllocation);
}
Ok(Self {
raw,
owned: true,
_engine: core::marker::PhantomData,
})
}
pub fn add<P: Paint>(&mut self, paint: P) -> Result<()> {
Error::from_raw(unsafe { sys::tvg_scene_add(self.raw, paint.into_raw()) })
}
pub fn insert<P: Paint, Q: Paint>(&mut self, target: P, at: &Q) -> Result<()> {
Error::from_raw(unsafe { sys::tvg_scene_insert(self.raw, target.into_raw(), at.raw()) })
}
pub fn remove<P: Paint>(&mut self, paint: &P) -> Result<()> {
Error::from_raw(unsafe { sys::tvg_scene_remove(self.raw, paint.raw()) })
}
pub fn clear(&mut self) -> Result<()> {
Error::from_raw(unsafe { sys::tvg_scene_remove(self.raw, core::ptr::null_mut()) })
}
pub fn clear_effects(&mut self) -> Result<()> {
Error::from_raw(unsafe { sys::tvg_scene_clear_effects(self.raw) })
}
pub fn add_gaussian_blur_effect(&mut self, params: GaussianBlur) -> Result<()> {
let GaussianBlur {
sigma,
direction,
border,
quality,
} = params;
Error::from_raw(unsafe {
sys::tvg_scene_add_effect_gaussian_blur(
self.raw,
sigma,
direction.to_raw(),
border.to_raw(),
i32::from(quality),
)
})
}
pub fn add_drop_shadow_effect(&mut self, params: DropShadow) -> Result<()> {
let DropShadow {
color: Rgba { r, g, b, a },
angle,
distance,
sigma,
quality,
} = params;
Error::from_raw(unsafe {
sys::tvg_scene_add_effect_drop_shadow(
self.raw,
i32::from(r),
i32::from(g),
i32::from(b),
i32::from(a),
angle,
distance,
sigma,
i32::from(quality),
)
})
}
pub fn add_fill_effect(&mut self, color: Rgba) -> Result<()> {
let Rgba { r, g, b, a } = color;
Error::from_raw(unsafe {
sys::tvg_scene_add_effect_fill(
self.raw,
i32::from(r),
i32::from(g),
i32::from(b),
i32::from(a),
)
})
}
pub fn add_tint_effect(&mut self, params: Tint) -> Result<()> {
let Tint {
black,
white,
intensity,
} = params;
Error::from_raw(unsafe {
sys::tvg_scene_add_effect_tint(
self.raw,
i32::from(black.r),
i32::from(black.g),
i32::from(black.b),
i32::from(white.r),
i32::from(white.g),
i32::from(white.b),
intensity,
)
})
}
pub fn add_tritone_effect(&mut self, params: Tritone) -> Result<()> {
let Tritone {
shadow,
midtone,
highlight,
blend,
} = params;
Error::from_raw(unsafe {
sys::tvg_scene_add_effect_tritone(
self.raw,
i32::from(shadow.r),
i32::from(shadow.g),
i32::from(shadow.b),
i32::from(midtone.r),
i32::from(midtone.g),
i32::from(midtone.b),
i32::from(highlight.r),
i32::from(highlight.g),
i32::from(highlight.b),
i32::from(blend),
)
})
}
}
impl crate::paint::sealed::Sealed for Scene<'_> {}
impl Paint for Scene<'_> {
fn raw(&self) -> sys::Tvg_Paint {
self.raw
}
fn into_raw(mut self) -> sys::Tvg_Paint {
self.owned = false;
self.raw
}
unsafe fn from_raw_paint(raw: sys::Tvg_Paint) -> Self {
Self {
raw,
owned: true,
_engine: core::marker::PhantomData,
}
}
}
impl Drop for Scene<'_> {
fn drop(&mut self) {
if self.owned {
unsafe {
sys::tvg_paint_rel(self.raw);
}
}
}
}
impl core::fmt::Debug for Scene<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Scene").finish_non_exhaustive()
}
}