use crate::{EffectParamValue, sample_effect_param};
use alpha2_media::SourceId;
use alpha2_model::{
BlendSpace, ClipBlendMode, ClipEffect, ClipId, EffectResourceId, Generator, Matte, Rgb,
ShapeMask, TextStyle, TrackId, Vec2,
};
use alpha2_time::MediaTime;
#[derive(Clone, Debug, PartialEq)]
pub struct FrameDesc<'a> {
pub time: MediaTime,
pub background: Rgb,
pub blend_space: BlendSpace,
pub visual: Vec<ActiveClip<'a>>,
pub audio: Vec<ActiveClip<'a>>,
pub transitions: Vec<ActiveTransition<'a>>,
pub captions: Vec<ActiveCaption<'a>>,
}
impl FrameDesc<'_> {
#[must_use]
pub fn draws(&self, clip: &ActiveClip<'_>) -> bool {
!clip.is_matte
|| self.visual.iter().any(|other| {
other
.matte
.is_some_and(|matte| &matte.source == clip.clip_id)
})
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct ActiveCaption<'a> {
pub track_id: &'a TrackId,
pub text: &'a str,
pub style: &'a TextStyle,
pub layers_below: usize,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct ActiveClip<'a> {
pub clip_id: &'a ClipId,
pub source_id: &'a SourceId,
pub track_id: &'a TrackId,
pub source_time: MediaTime,
pub visual: Option<EvaluatedVisual>,
pub composition: Option<crate::ActiveComposition<'a>>,
pub blend_mode: ClipBlendMode,
pub cache: alpha2_model::CacheIntent,
pub masks: &'a [ShapeMask],
pub matte: Option<&'a Matte>,
pub is_matte: bool,
pub generator: Option<&'a Generator>,
pub plan: Option<&'a crate::GeneratorPlan>,
pub source_composition: Option<crate::ActiveComposition<'a>>,
}
impl ActiveClip<'_> {
#[must_use]
pub fn needs_source(&self) -> bool {
self.generator.is_none()
&& self.source_composition.is_none()
&& self
.composition
.is_none_or(|composition| composition.plan().uses_clip())
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct EvaluatedVisual {
pub position: Vec2,
pub anchor: Vec2,
pub scale: Vec2,
pub rotation_degrees: f32,
pub opacity: f32,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct FrameNeed {
pub clip_id: ClipId,
pub reader: Option<alpha2_model::NodeId>,
pub source_id: SourceId,
pub media_time: MediaTime,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct ActiveTransition<'a> {
pub from_clip: &'a ClipId,
pub to_clip: &'a ClipId,
pub effect: ActiveEffect<'a>,
pub progress: f32,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct ActiveEffect<'a> {
effect: &'a ClipEffect,
time: MediaTime,
}
impl<'a> ActiveEffect<'a> {
#[must_use]
pub const fn new(effect: &'a ClipEffect, time: MediaTime) -> Self {
Self { effect, time }
}
#[must_use]
pub fn id(&self) -> &'a str {
&self.effect.id
}
#[must_use]
pub const fn version(&self) -> u32 {
self.effect.version
}
pub fn params(&self) -> impl Iterator<Item = (&'a str, EffectParamValue)> + 'a {
let time = self.time;
self.effect
.params
.iter()
.map(move |(name, animation)| (name.as_str(), sample_effect_param(animation, time)))
}
#[must_use]
pub fn param(&self, name: &str) -> Option<EffectParamValue> {
self.effect
.params
.get(name)
.map(|animation| sample_effect_param(animation, self.time))
}
pub fn resources(&self) -> impl Iterator<Item = (&'a str, &'a EffectResourceId)> + 'a {
self.effect
.resources
.iter()
.map(|(name, id)| (name.as_str(), id))
}
#[must_use]
pub const fn authored(&self) -> &'a ClipEffect {
self.effect
}
}