use crate::{Animated, ClipId, Vec2};
use serde::{Deserialize, Serialize};
pub const MAX_CLIP_MASKS: usize = 8;
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[serde(deny_unknown_fields)]
pub struct ShapeMask {
pub shape: MaskShape,
pub center: Animated<Vec2>,
pub size: Animated<Vec2>,
#[serde(default = "zero")]
pub rotation_degrees: Animated<f32>,
#[serde(default = "zero")]
pub feather: Animated<f32>,
#[serde(default)]
pub invert: bool,
#[serde(default)]
pub mode: MaskMode,
}
fn zero() -> Animated<f32> {
Animated::Constant { value: 0.0 }
}
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[serde(tag = "type", rename_all = "snake_case", from = "MaskShapeWire")]
pub enum MaskShape {
Rectangle {
corner_radius: Animated<f32>,
},
Ellipse,
}
#[derive(Deserialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[cfg_attr(feature = "schema", schemars(rename = "MaskShape"))]
#[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)]
pub(crate) enum MaskShapeWire {
Rectangle {
#[serde(default = "zero")]
corner_radius: Animated<f32>,
},
Ellipse {},
}
impl From<MaskShapeWire> for MaskShape {
fn from(wire: MaskShapeWire) -> Self {
match wire {
MaskShapeWire::Rectangle { corner_radius } => Self::Rectangle { corner_radius },
MaskShapeWire::Ellipse {} => Self::Ellipse,
}
}
}
#[derive(Copy, Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[serde(rename_all = "snake_case")]
pub enum MaskMode {
#[default]
Add,
Subtract,
Intersect,
}
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[serde(deny_unknown_fields)]
pub struct Matte {
pub source: ClipId,
pub mode: MatteMode,
}
#[derive(Copy, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[serde(rename_all = "snake_case")]
pub enum MatteMode {
Alpha,
AlphaInverted,
Luma,
LumaInverted,
}
impl ShapeMask {
pub(crate) fn is_valid(&self) -> bool {
let non_negative = |animation: &Animated<f32>| {
crate::animation::valid_scalar_values(animation, |value| value >= 0.0)
};
let sizes = crate::animation::valid_vec2_values(&self.size, |value| {
value.x >= 0.0 && value.y >= 0.0
});
let shape = match &self.shape {
MaskShape::Rectangle { corner_radius } => non_negative(corner_radius),
MaskShape::Ellipse => true,
};
shape
&& sizes
&& crate::animation::valid_vec2_values(&self.center, |_| true)
&& crate::animation::valid_scalar_values(&self.rotation_degrees, |_| true)
&& non_negative(&self.feather)
}
}