mirror of
https://github.com/storytold/effectcraft.git
synced 2026-10-30 13:08:07 -06:00
Viewer: no proxy notice on a collapsed precomp, which draws its own layers (#1701)
This commit is contained in:
@@ -8,8 +8,8 @@ use effectcraft_engine::commands::shape_tool::PaintKind;
|
||||
use effectcraft_engine::effects::puppet::PinKind;
|
||||
use effectcraft_engine::geom::{Mat3, vec2 as gv2};
|
||||
use effectcraft_engine::project::{Comp, Layer, LayerId, LayerSource};
|
||||
use effectcraft_engine::render::EvalCtx;
|
||||
use effectcraft_engine::render::three_d::{self, CameraState, View3D};
|
||||
use effectcraft_engine::render::{EvalCtx, Renderer};
|
||||
use effectcraft_engine::time::Tick;
|
||||
use egui::{Align2, Color32, Pos2, Rect, Sense, Stroke, StrokeKind, pos2, vec2};
|
||||
use serde_json::json;
|
||||
@@ -1194,16 +1194,21 @@ pub fn show(app: &mut EffectcraftApp, ui: &mut egui::Ui, rect: Rect) {
|
||||
}
|
||||
|
||||
// Footage (or the proxy in use for footage or a precomp) that can't be decoded (no decoder
|
||||
// for its codec / profile): say why on the layer instead of leaving a black picture.
|
||||
let mut notices = 0;
|
||||
for layer in comp.layers.iter().filter(|l| l.is_active_at(time) && l.switches.video) {
|
||||
let (effectcraft_engine::project::LayerSource::Footage { item } | effectcraft_engine::project::LayerSource::Comp { item }) = &layer.source else {
|
||||
continue;
|
||||
};
|
||||
let Some(why) = app.session.project.item(*item).and_then(|i| app.session.footage.item_problem(i)) else { continue };
|
||||
if notices >= 3 {
|
||||
break;
|
||||
}
|
||||
// for its codec / profile): say why on the layer instead of leaving a black picture. A
|
||||
// collapsed precomp draws its own layers, never the comp's proxy.
|
||||
let problems: Vec<(&Layer, String)> = {
|
||||
let r = Renderer::new(&snap_project, &*app.session.footage, Default::default());
|
||||
comp.layers
|
||||
.iter()
|
||||
.filter(|l| l.is_active_at(time) && l.switches.video && r.collapsed(&ectx, l).is_none())
|
||||
.filter_map(|layer| {
|
||||
let (LayerSource::Footage { item } | LayerSource::Comp { item }) = &layer.source else { return None };
|
||||
Some((layer, snap_project.item(*item).and_then(|i| app.session.footage.item_problem(i))?))
|
||||
})
|
||||
.take(3)
|
||||
.collect()
|
||||
};
|
||||
for (notices, (layer, why)) in problems.into_iter().enumerate() {
|
||||
let (m, _) = l2c(&ectx, layer);
|
||||
let (w, h) = effectcraft_engine::render::source_size(&app.session.project, layer);
|
||||
let c = m.apply(effectcraft_engine::geom::vec2(w as f64 / 2.0, h as f64 / 2.0));
|
||||
@@ -1215,7 +1220,6 @@ pub fn show(app: &mut EffectcraftApp, ui: &mut egui::Ui, rect: Rect) {
|
||||
painter.rect_stroke(r, 3.0, Stroke::new(1.0, t.warning), StrokeKind::Inside);
|
||||
painter.galley(pos2(r.min.x + 12.0, r.center().y - galley.size().y / 2.0), galley, Color32::WHITE);
|
||||
app.auto.add(&format!("viewer.footageProblem.{}", layer.id.0), r, &text);
|
||||
notices += 1;
|
||||
}
|
||||
|
||||
// Free transform box of a path (double-click a path with the Selection tool).
|
||||
|
||||
@@ -45,10 +45,14 @@ fn harness(broken: fn(&Footage) -> bool, proxy: Option<Footage>) -> (Harness<'st
|
||||
item.proxy = Some(Box::new(Proxy { footage, enabled: true }));
|
||||
}
|
||||
s.execute("layer.addItem", json!({"item": clip.0})).unwrap();
|
||||
(open(s), clip)
|
||||
}
|
||||
|
||||
fn open(mut s: Session) -> Harness<'static, EffectcraftApp> {
|
||||
s.execute("project.select", json!({"items": []})).unwrap();
|
||||
let mut h = Harness::builder().with_size(egui::vec2(1600.0, 1000.0)).build_eframe(|_| EffectcraftApp::new(s));
|
||||
h.run_steps(4);
|
||||
(h, clip)
|
||||
h
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -78,3 +82,23 @@ fn an_undecodable_proxy_in_use_is_marked_as_the_proxy() {
|
||||
let notice = h.state().auto.query("viewer.footageProblem.").first().copied().expect("a notice in the viewer").clone();
|
||||
assert!(notice.label.contains(&format!("Proxy: {WHY}")), "{notice:?}");
|
||||
}
|
||||
|
||||
/// A precomp whose proxy can't be decoded: the layer says so while it renders through the
|
||||
/// proxy, but not with Collapse Transformations on, which draws the precomp's own layers.
|
||||
#[test]
|
||||
fn a_collapsed_precomp_has_no_notice_for_its_proxy() {
|
||||
for collapse in [false, true] {
|
||||
let mut s = Session { footage: Arc::new(Stub(|f| f.path.ends_with(".avi"))), ..Default::default() };
|
||||
s.execute("comp.new", json!({"name": "Inner", "width": 64, "height": 36, "duration": 4})).unwrap();
|
||||
s.execute("comp.new", json!({"name": "Main", "width": 320, "height": 180, "duration": 4})).unwrap();
|
||||
let p = Arc::make_mut(&mut s.project);
|
||||
let inner = p.items.values_mut().find(|i| i.name == "Inner").unwrap();
|
||||
let proxy = Footage { kind: FootageKind::Video, path: "inner_proxy.avi".into(), width: 64, height: 36, has_video: true, ..Default::default() };
|
||||
inner.proxy = Some(Box::new(Proxy { footage: proxy, enabled: true }));
|
||||
let inner = inner.id;
|
||||
s.execute("layer.addItem", json!({"item": inner.0})).unwrap();
|
||||
s.execute("layer.setSwitch", json!({"layers": ["#1"], "switch": "collapse", "value": collapse})).unwrap();
|
||||
let h = open(s);
|
||||
assert_eq!(h.state().auto.query("viewer.footageProblem.").is_empty(), collapse, "collapse {collapse}");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user