use std::hash::Hash;
use crate::dyn_compare::{DynEq, DynHash};
use crate::geometry::{Rect, Vec2};
use crate::layer::composite_children;
use crate::raster::{RasterComponent, RasterImage, Resolution};
use crate::render_context::RenderContext;
use super::*;
pub trait TimelineComponent: DynEq + DynHash {
fn duration(&self) -> Option<f32> {
None
}
fn measure(&self) -> Option<f32> {
self.duration()
}
fn resolve(&self, abs_start: f32, out: &mut ResolveCtx) -> f32 {
let _ = (abs_start, out);
self.duration().unwrap_or(0.0)
}
fn frame(
&self,
clock: Clock<'_>,
canvas: Vec2,
target: Resolution,
ctx: &mut dyn RenderContext,
) -> Option<RasterImage> {
let _ = (clock, canvas, target, ctx);
None
}
fn samples(&self, clock: Clock<'_>, window: f32) -> Option<AudioBuffer> {
let _ = (clock, window);
None
}
fn mix_into(&self, mix: &mut crate::audio::AudioMix, start_secs: f32, speed: f32) {
let _ = (mix, start_secs, speed);
}
fn cues(&self, offset: f32) -> Vec<Cue> {
let _ = offset;
Vec::new()
}
fn arrangement(&self, offset: f32) -> Arrangement;
fn structural_any(&self) -> &dyn std::any::Any {
self.as_any()
}
}
const _: Option<&(dyn TimelineComponent + Send)> = None;
impl PartialEq for dyn TimelineComponent + Send {
fn eq(&self, other: &Self) -> bool {
DynEq::dyn_eq(self, other.as_any())
}
}
impl Eq for dyn TimelineComponent + Send {}
impl Hash for dyn TimelineComponent + Send {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
DynHash::dyn_hash(self, state);
}
}
impl<C> TimelineComponent for C
where
C: RasterComponent + 'static,
{
fn duration(&self) -> Option<f32> {
None
}
fn frame(
&self,
clock: Clock<'_>,
canvas: Vec2,
target: Resolution,
ctx: &mut dyn RenderContext,
) -> Option<RasterImage> {
let _ = clock;
let canvas_rect = Rect {
origin: Vec2::ZERO,
size: canvas,
};
if self.paint_bounds(canvas) == canvas_rect {
return Some(ctx.render(self, canvas, target));
}
Some(composite_children(
canvas_rect,
target,
&[(Vec2::ZERO, canvas, self as &dyn RasterComponent)],
ctx,
))
}
fn samples(&self, _clock: Clock<'_>, _window: f32) -> Option<AudioBuffer> {
None
}
fn cues(&self, _offset: f32) -> Vec<Cue> {
Vec::new()
}
fn arrangement(&self, offset: f32) -> Arrangement {
Arrangement {
kind: NodeKind::Video,
label: String::new(),
name: self.arrangement_name(),
source: None,
start: offset,
end: offset + self.duration().unwrap_or(0.0),
trim: None,
triggers: Vec::new(),
children: Vec::new(),
}
}
}
pub trait TimelineBuilder: Sized {
type Output: TimelineComponent + PartialEq + Hash + 'static;
fn build_component(self) -> Self::Output;
}