effectcraft/crates/render/src/tests_nested.rs

91 lines
4.7 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! Nested compositions: Preserve frame rate when nested or in render queue, Preserve resolution
//! when nested.
use effectcraft_color::Label;
use effectcraft_keyframe::{Keyframe, Value};
use effectcraft_project::build;
use effectcraft_project::render_queue::RenderSettings;
use effectcraft_project::{Comp, ItemId, ItemKind, LayerSource, Project, Solid};
use effectcraft_time::{FrameRate, Tick};
use crate::render_frame;
fn s(x: f64) -> Tick {
Tick::from_seconds_f64(x)
}
/// A 30 fps outer comp nesting a 10 fps 100×100 comp whose 10×10 solid moves from x=10 (0 s)
/// to x=90 (2 s). Returns (project, outer, inner).
fn nested(preserve_rate: bool, preserve_res: bool) -> (Project, ItemId, ItemId) {
let mut p = Project::default();
let outer = Comp::new(100, 100, FrameRate::FPS_30, s(4.0));
let mut inner = Comp::new(100, 100, FrameRate::from_f64(10.0), s(4.0));
inner.preserve_frame_rate = preserve_rate;
inner.preserve_resolution = preserve_res;
let sid = p.add_item("S", Label::Red, None, ItemKind::Solid(Solid { color: [1.0, 1.0, 1.0], width: 10, height: 10, pixel_aspect: 1.0 }));
let mut l = build::layer(&mut p, &inner, "S", LayerSource::Solid { item: sid }, (10, 10), None);
l.props.prop_mut("transform/position").unwrap().keys =
vec![Keyframe::new(Tick::ZERO, Value::Vec3([10.0, 50.0, 0.0])), Keyframe::new(s(2.0), Value::Vec3([90.0, 50.0, 0.0]))];
inner.layers.push(l);
let iid = p.add_item("Inner", Label::Sandstone, None, ItemKind::Comp(inner.into()));
let cid = p.add_item("Outer", Label::Sandstone, None, ItemKind::Comp(outer.clone().into()));
let pre = build::layer(&mut p, &outer, "Inner", LayerSource::Comp { item: iid }, (100, 100), None);
p.comp_mut(cid).unwrap().layers.push(pre);
(p, cid, iid)
}
#[test]
fn a_comp_preserving_its_frame_rate_shows_only_its_own_frames_when_nested() {
// 2/30 s falls between the nested comp's frames 0 (0 s) and 1 (0.1 s).
let between = s(2.0 / 30.0);
let (p, cid, _) = nested(false, false);
assert_ne!(render_frame(&p, cid, between, 1.0).data, render_frame(&p, cid, Tick::ZERO, 1.0).data, "follows the outer comp's frames");
let (p, cid, _) = nested(true, false);
assert_eq!(render_frame(&p, cid, between, 1.0).data, render_frame(&p, cid, Tick::ZERO, 1.0).data, "holds its own frame 0");
assert_ne!(render_frame(&p, cid, s(0.1), 1.0).data, render_frame(&p, cid, Tick::ZERO, 1.0).data, "then its frame 1");
}
#[test]
fn the_render_queue_keeps_a_preserved_frame_rate() {
let (p, _, iid) = nested(true, false);
let settings = RenderSettings { frame_rate: Some(FrameRate::FPS_30), ..Default::default() };
assert_eq!(settings.rate(p.comp(iid).unwrap()), FrameRate::from_f64(10.0));
let (p, _, iid) = nested(false, false);
assert_eq!(settings.rate(p.comp(iid).unwrap()), FrameRate::FPS_30);
}
#[test]
fn a_comp_preserving_its_resolution_renders_full_size_and_lands_in_place() {
for preserve in [false, true] {
let (p, cid, _) = nested(false, preserve);
let img = render_frame(&p, cid, Tick::ZERO, 0.5);
assert_eq!((img.width, img.height), (50, 50));
// The solid covers x 5..15, y 45..55 in the 100×100 comp: 2.5..7.5, 22.5..27.5 at half size.
assert!(img.get(5, 25)[3] > 0.99, "preserve {preserve}: inside");
assert!(img.get(20, 25)[3] < 0.01 && img.get(5, 40)[3] < 0.01, "preserve {preserve}: outside");
}
}
#[test]
fn a_nested_comp_shows_nothing_past_its_end() {
for collapse in [false, true] {
let mut p = Project::default();
let outer = Comp::new(100, 100, FrameRate::FPS_30, s(4.0));
// A 1 s comp with a solid covering it for 4 s (longer than the comp itself).
let mut inner = Comp::new(100, 100, FrameRate::FPS_30, s(1.0));
let sid = p.add_item("S", Label::Red, None, ItemKind::Solid(Solid { color: [1.0, 1.0, 1.0], width: 100, height: 100, pixel_aspect: 1.0 }));
let mut l = build::layer(&mut p, &inner, "S", LayerSource::Solid { item: sid }, (100, 100), None);
l.out_point = s(4.0);
inner.layers.push(l);
let iid = p.add_item("Inner", Label::Sandstone, None, ItemKind::Comp(inner.into()));
let cid = p.add_item("Outer", Label::Sandstone, None, ItemKind::Comp(outer.clone().into()));
// The precomp layer is trimmed out to 3 s, past the nested comp's end.
let mut pre = build::layer(&mut p, &outer, "Inner", LayerSource::Comp { item: iid }, (100, 100), None);
pre.out_point = s(3.0);
pre.switches.collapse = collapse;
p.comp_mut(cid).unwrap().layers.push(pre);
assert!(render_frame(&p, cid, s(0.5), 1.0).get(50, 50)[3] > 0.99, "collapse {collapse}: inside its span");
assert!(render_frame(&p, cid, s(2.0), 1.0).get(50, 50)[3] < 0.01, "collapse {collapse}: past its end");
}
}