///|
/// Lightweight asset descriptors for animation tools. The catalog deliberately
/// stores no file handles; it can be serialized by a host application and
/// reused for preview or final export.
pub enum MediaKind2 {
VectorAsset
RasterAsset
AudioAsset
CameraAsset
CompositeAsset
} derive(Debug)
///|
pub fn media_kinds2() -> Array[MediaKind2] {
[VectorAsset, RasterAsset, AudioAsset, CameraAsset, CompositeAsset]
}
///|
pub struct MediaAsset2 {
id : Int
name : String
kind : MediaKind2
start : Double
duration : Double
bounds : Bounds2D
tags : Array[String]
enabled : Bool
} derive(Debug)
///|
pub fn media_asset2(
id : Int,
name : String,
kind : MediaKind2,
start : Double,
duration : Double,
bounds : Bounds2D,
) -> MediaAsset2 {
{
id,
name,
kind,
start,
duration: duration.max(0.0),
bounds,
tags: [],
enabled: true,
}
}
///|
pub fn MediaAsset2::id(self : MediaAsset2) -> Int {
self.id
}
///|
pub fn MediaAsset2::name(self : MediaAsset2) -> String {
self.name
}
///|
pub fn MediaAsset2::kind(self : MediaAsset2) -> MediaKind2 {
self.kind
}
///|
pub fn MediaAsset2::start(self : MediaAsset2) -> Double {
self.start
}
///|
pub fn MediaAsset2::duration(self : MediaAsset2) -> Double {
self.duration
}
///|
pub fn MediaAsset2::end(self : MediaAsset2) -> Double {
self.start + self.duration
}
///|
pub fn MediaAsset2::bounds(self : MediaAsset2) -> Bounds2D {
self.bounds
}
///|
pub fn MediaAsset2::tags(self : MediaAsset2) -> Array[String] {
self.tags.copy()
}
///|
pub fn MediaAsset2::enabled(self : MediaAsset2) -> Bool {
self.enabled
}
///|
pub fn MediaAsset2::with_tag(self : MediaAsset2, tag : String) -> MediaAsset2 {
let tags = self.tags.copy()
if !tags.contains(tag) {
tags.push(tag)
}
{
id: self.id,
name: self.name,
kind: self.kind,
start: self.start,
duration: self.duration,
bounds: self.bounds,
tags,
enabled: self.enabled,
}
}
///|
pub fn MediaAsset2::with_enabled(
self : MediaAsset2,
enabled : Bool,
) -> MediaAsset2 {
{
id: self.id,
name: self.name,
kind: self.kind,
start: self.start,
duration: self.duration,
bounds: self.bounds,
tags: self.tags,
enabled,
}
}
///|
pub fn MediaAsset2::active_at(self : MediaAsset2, time : Double) -> Bool {
self.enabled && time >= self.start && time <= self.end()
}
///|
pub struct MediaCatalog2 {
assets : Array[MediaAsset2]
mut revision : Int
} derive(Debug)
///|
pub fn media_catalog2() -> MediaCatalog2 {
{ assets: [], revision: 0 }
}
///|
pub fn MediaCatalog2::assets(self : MediaCatalog2) -> Array[MediaAsset2] {
self.assets.copy()
}
///|
pub fn MediaCatalog2::revision(self : MediaCatalog2) -> Int {
self.revision
}
///|
pub fn MediaCatalog2::length(self : MediaCatalog2) -> Int {
self.assets.length()
}
///|
pub fn MediaCatalog2::add(self : MediaCatalog2, asset : MediaAsset2) -> Bool {
for existing in self.assets {
if existing.id == asset.id {
return false
}
}
self.assets.push(asset)
self.revision = self.revision + 1
true
}
///|
pub fn MediaCatalog2::replace(
self : MediaCatalog2,
asset : MediaAsset2,
) -> Bool {
for index in 0.. Bool {
for index in 0.. MediaAsset2? {
for asset in self.assets {
if asset.id == id {
return Some(asset)
}
}
None
}
///|
pub fn MediaCatalog2::find_name(
self : MediaCatalog2,
name : String,
) -> Array[MediaAsset2] {
let result : Array[MediaAsset2] = []
for asset in self.assets {
if asset.name == name {
result.push(asset)
}
}
result
}
///|
pub fn MediaCatalog2::find_tag(
self : MediaCatalog2,
tag : String,
) -> Array[MediaAsset2] {
let result : Array[MediaAsset2] = []
for asset in self.assets {
if asset.tags.contains(tag) {
result.push(asset)
}
}
result
}
///|
pub fn MediaCatalog2::active_at(
self : MediaCatalog2,
time : Double,
) -> Array[MediaAsset2] {
let result : Array[MediaAsset2] = []
for asset in self.assets {
if asset.active_at(time) {
result.push(asset)
}
}
result.sort_by(fn(left, right) { left.start.compare(right.start) })
result
}
///|
pub fn MediaCatalog2::time_range(self : MediaCatalog2) -> (Double, Double) {
if self.assets.length() == 0 {
return (0.0, 0.0)
}
let mut first = self.assets[0].start
let mut last = self.assets[0].end()
for asset in self.assets {
first = first.min(asset.start)
last = last.max(asset.end())
}
(first, last)
}
///|
pub fn MediaCatalog2::bounds(self : MediaCatalog2) -> Bounds2D {
if self.assets.length() == 0 {
return { minimum: point2(x=0.0, y=0.0), maximum: point2(x=0.0, y=0.0) }
}
let mut result = self.assets[0].bounds
for index in 1.. Array[MediaAsset2] {
let result : Array[MediaAsset2] = []
for asset in self.assets {
let same = match (asset.kind, kind) {
(VectorAsset, VectorAsset)
| (RasterAsset, RasterAsset)
| (AudioAsset, AudioAsset)
| (CameraAsset, CameraAsset)
| (CompositeAsset, CompositeAsset) => true
(_, _) => false
}
if same {
result.push(asset)
}
}
result
}
///|
pub fn MediaCatalog2::shift(
self : MediaCatalog2,
delta : Double,
) -> MediaCatalog2 {
let result = media_catalog2()
for asset in self.assets {
ignore(
result.add({
id: asset.id,
name: asset.name,
kind: asset.kind,
start: asset.start + delta,
duration: asset.duration,
bounds: asset.bounds,
tags: asset.tags,
enabled: asset.enabled,
}),
)
}
result
}