use kurbo::{Affine, PathEl, Point, Shape as _, Size, Vec2};
use peniko::{BlendMode, Color};
use std::ops::Range;
mod spline;
mod value;
pub mod animated;
pub mod fixed;
pub use value::{Animated, Easing, EasingHandle, Time, Tween, Value, ValueRef};
pub(crate) use spline::SplineToPath;
#[derive(Clone, Debug)]
#[cfg_attr(
not(target_arch = "wasm32"),
expect(
clippy::large_enum_variant,
reason = "Deferred. Furthermore, for some reason, only on wasm32, this isn't triggering clippy."
)
)]
pub enum Transform {
Fixed(fixed::Transform),
Animated(animated::Transform),
}
impl Transform {
pub fn is_fixed(&self) -> bool {
matches!(self, Self::Fixed(_))
}
pub fn evaluate(&self, frame: f64) -> ValueRef<'_, fixed::Transform> {
match self {
Self::Fixed(value) => ValueRef::Borrowed(value),
Self::Animated(value) => ValueRef::Owned(value.evaluate(frame)),
}
}
}
#[derive(Clone, Debug)]
pub enum Stroke {
Fixed(fixed::Stroke),
Animated(animated::Stroke),
}
impl Stroke {
pub fn is_fixed(&self) -> bool {
matches!(self, Self::Fixed(_))
}
pub fn evaluate(&self, frame: f64) -> ValueRef<'_, fixed::Stroke> {
match self {
Self::Fixed(value) => ValueRef::Borrowed(value),
Self::Animated(value) => ValueRef::Owned(value.evaluate(frame)),
}
}
}
#[derive(Clone, Debug)]
#[cfg_attr(
not(target_arch = "wasm32"),
expect(
clippy::large_enum_variant,
reason = "Deferred. Furthermore, for some reason, only on wasm32, this isn't triggering clippy."
)
)]
pub enum Repeater {
Fixed(fixed::Repeater),
Animated(animated::Repeater),
}
impl Repeater {
pub fn is_fixed(&self) -> bool {
matches!(self, Self::Fixed(_))
}
pub fn evaluate(&self, frame: f64) -> ValueRef<'_, fixed::Repeater> {
match self {
Self::Fixed(value) => ValueRef::Borrowed(value),
Self::Animated(value) => ValueRef::Owned(value.evaluate(frame)),
}
}
}
#[derive(Clone, Debug)]
pub enum ColorStops {
Fixed(fixed::ColorStops),
Animated(animated::ColorStops),
}
impl ColorStops {
pub fn is_fixed(&self) -> bool {
matches!(self, Self::Fixed(_))
}
pub fn evaluate(&self, frame: f64) -> ValueRef<'_, fixed::ColorStops> {
match self {
Self::Fixed(value) => ValueRef::Borrowed(value),
Self::Animated(value) => ValueRef::Owned(value.evaluate(frame)),
}
}
}
#[derive(Clone, Debug)]
pub enum Brush {
Fixed(fixed::Brush),
Animated(animated::Brush),
}
impl Brush {
pub fn is_fixed(&self) -> bool {
matches!(self, Self::Fixed(_))
}
pub fn evaluate(&self, alpha: f64, frame: f64) -> ValueRef<'_, fixed::Brush> {
match self {
Self::Fixed(value) => {
if alpha == 1.0 {
ValueRef::Borrowed(value)
} else {
ValueRef::Owned(value.to_owned().multiply_alpha(alpha as _))
}
}
Self::Animated(value) => ValueRef::Owned(value.evaluate(alpha, frame)),
}
}
}
impl Default for Transform {
fn default() -> Self {
Self::Fixed(Affine::IDENTITY)
}
}
#[derive(Clone, Debug)]
pub enum Geometry {
Fixed(Vec<PathEl>),
Rect(animated::Rect),
Ellipse(animated::Ellipse),
Spline(animated::Spline),
Star(animated::Star),
}
impl Geometry {
pub fn evaluate(&self, frame: f64, path: &mut Vec<PathEl>) {
match self {
Self::Fixed(value) => {
path.extend_from_slice(value);
}
Self::Rect(value) => {
path.extend(value.evaluate(frame).path_elements(0.1));
}
Self::Ellipse(value) => {
path.extend(value.evaluate(frame).path_elements(0.1));
}
Self::Spline(value) => {
value.evaluate(frame, path);
}
Self::Star(value) => {
value.evaluate(frame, path);
}
}
}
}
#[derive(Clone, Debug)]
pub struct Draw {
pub stroke: Option<Stroke>,
pub brush: Brush,
pub opacity: Value<f64>,
}
#[derive(Clone, Debug)]
pub enum Shape {
Group(Vec<Shape>, Option<GroupTransform>),
Geometry(Geometry),
Draw(Draw),
Repeater(Repeater),
Trim(Trim),
}
#[derive(Clone, Debug)]
pub struct GroupTransform {
pub transform: Transform,
pub opacity: Value<f64>,
}
#[derive(Clone, Debug, Default)]
pub struct Layer {
pub name: String,
pub parent: Option<usize>,
pub transform: Transform,
pub opacity: Value<f64>,
pub width: f64,
pub height: f64,
pub blend_mode: Option<peniko::BlendMode>,
pub frames: Range<f64>,
pub stretch: f64,
pub start_frame: f64,
pub masks: Vec<Mask>,
pub is_mask: bool,
pub mask_layer: Option<(BlendMode, usize)>,
pub content: Content,
}
#[derive(Copy, Clone, PartialEq, Eq, Default, Debug)]
pub enum Matte {
#[default]
Normal,
}
#[derive(Clone, Debug)]
pub struct Mask {
pub mode: peniko::BlendMode,
pub geometry: Geometry,
pub opacity: Value<f64>,
}
#[derive(Clone, Default, Debug)]
pub enum Content {
#[default]
None,
Instance {
name: String,
time_remap: Option<Value<f64>>,
},
Shape(Vec<Shape>),
}
#[derive(Clone, Debug)]
pub enum Trim {
Fixed(fixed::Trim),
Animated(animated::Trim),
}
impl Trim {
pub fn is_fixed(&self) -> bool {
matches!(self, Self::Fixed(_))
}
pub fn evaluate(&self, frame: f64) -> ValueRef<'_, fixed::Trim> {
match self {
Self::Fixed(value) => ValueRef::Borrowed(value),
Self::Animated(value) => ValueRef::Owned(value.evaluate(frame)),
}
}
}