pub mod blur;
pub mod brightness;
pub mod hsv;
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use crate::entities::attrs::{AttrDef, AttrSchema, AttrType, AttrValue, Attrs, FLAG_DAG, FLAG_DISPLAY, FLAG_KEYABLE};
use crate::entities::frame::Frame;
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum EffectType {
GaussianBlur,
BrightnessContrast,
AdjustHSV,
}
impl EffectType {
pub fn display_name(&self) -> &'static str {
match self {
EffectType::GaussianBlur => "Gaussian Blur",
EffectType::BrightnessContrast => "Brightness/Contrast",
EffectType::AdjustHSV => "Adjust HSV",
}
}
pub fn schema(&self) -> &'static AttrSchema {
match self {
EffectType::GaussianBlur => &FX_GAUSSIAN_BLUR_SCHEMA,
EffectType::BrightnessContrast => &FX_BRIGHTNESS_CONTRAST_SCHEMA,
EffectType::AdjustHSV => &FX_HSV_ADJUST_SCHEMA,
}
}
pub fn all() -> &'static [EffectType] {
&[
EffectType::GaussianBlur,
EffectType::BrightnessContrast,
EffectType::AdjustHSV,
]
}
}
use std::sync::LazyLock;
const FX: u8 = FLAG_DAG | FLAG_DISPLAY | FLAG_KEYABLE;
const BLUR_ATTRS: &[AttrDef] = &[
AttrDef::with_ui_order("radius", AttrType::Float, FX, &["0", "100", "0.5"], 0.0),
];
const BC_ATTRS: &[AttrDef] = &[
AttrDef::with_ui_order("brightness", AttrType::Float, FX, &["-1", "1", "0.01"], 0.0),
AttrDef::with_ui_order("contrast", AttrType::Float, FX, &["-1", "1", "0.01"], 1.0),
];
const HSV_ATTRS: &[AttrDef] = &[
AttrDef::with_ui_order("hue_shift", AttrType::Float, FX, &["-180", "180", "1"], 0.0),
AttrDef::with_ui_order("saturation", AttrType::Float, FX, &["0", "2", "0.01"], 1.0),
AttrDef::with_ui_order("value", AttrType::Float, FX, &["0", "2", "0.01"], 2.0),
];
pub static FX_GAUSSIAN_BLUR_SCHEMA: LazyLock<AttrSchema> = LazyLock::new(|| {
AttrSchema::new("FX_GaussianBlur", BLUR_ATTRS)
});
pub static FX_BRIGHTNESS_CONTRAST_SCHEMA: LazyLock<AttrSchema> = LazyLock::new(|| {
AttrSchema::new("FX_BrightnessContrast", BC_ATTRS)
});
pub static FX_HSV_ADJUST_SCHEMA: LazyLock<AttrSchema> = LazyLock::new(|| {
AttrSchema::new("FX_AdjustHSV", HSV_ATTRS)
});
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Effect {
pub uuid: Uuid,
pub effect_type: EffectType,
pub attrs: Attrs,
pub enabled: bool,
#[serde(default)]
pub collapsed: bool,
}
impl Effect {
pub fn new(effect_type: EffectType) -> Self {
let mut attrs = Attrs::with_schema(effect_type.schema());
match effect_type {
EffectType::GaussianBlur => {
attrs.set("radius", AttrValue::Float(5.0));
}
EffectType::BrightnessContrast => {
attrs.set("brightness", AttrValue::Float(0.0));
attrs.set("contrast", AttrValue::Float(0.0));
}
EffectType::AdjustHSV => {
attrs.set("hue_shift", AttrValue::Float(0.0));
attrs.set("saturation", AttrValue::Float(1.0));
attrs.set("value", AttrValue::Float(1.0));
}
}
attrs.clear_dirty();
Self {
uuid: Uuid::new_v4(),
effect_type,
attrs,
enabled: true,
collapsed: false,
}
}
pub fn name(&self) -> &'static str {
self.effect_type.display_name()
}
}
pub fn apply(frame: &Frame, effect: &Effect) -> Option<Frame> {
if !effect.enabled {
return Some(frame.clone());
}
match effect.effect_type {
EffectType::GaussianBlur => blur::apply(frame, &effect.attrs),
EffectType::BrightnessContrast => brightness::apply(frame, &effect.attrs),
EffectType::AdjustHSV => hsv::apply(frame, &effect.attrs),
}
}
pub fn apply_all(mut frame: Frame, effects: &[Effect]) -> Option<Frame> {
for effect in effects {
frame = apply(&frame, effect)?;
}
Some(frame)
}