Revert #200 (text always continuously rasterised): breaks kinetic_typography

The QA test's time-remapped precomp no longer matches the precomp rendered
directly (crates/automation/tests/qa/kinetic.rs:78); FreeBSD CI has been red
since. Reverting until the PR is reworked against that test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Brandon Thomas 2026-10-09 08:22:58 -04:00
parent d5f78f3fc0
commit 29c4d3ad15
3 changed files with 11 additions and 44 deletions

View File

@ -667,21 +667,18 @@ impl<'a> Renderer<'a> {
Region::Full Region::Full
} }
/// Rasterisation scale of a layer's source: the output scale, or — for text layers, which are /// Rasterisation scale of a layer's source: the output scale, or — for Continuously
/// always continuously rasterised, and Continuously Rasterize shape layers and vector footage — /// Rasterize text and shape layers — the output scale times the layer's on-screen scale
/// the output scale times the layer's on-screen scale (quarter-octave steps, rounded up, so /// (quarter-octave steps, rounded up, so vector content is drawn at its final size and
/// vector content is drawn at its final size and stays sharp when scaled up). /// stays sharp when scaled up).
pub fn raster_scale(&self, ctx: &EvalCtx, layer: &Layer) -> f64 { pub fn raster_scale(&self, ctx: &EvalCtx, layer: &Layer) -> f64 {
let s = self.opts.scale; let s = self.opts.scale;
let continuous = match layer.source { let vector = match layer.source {
LayerSource::Text => true, LayerSource::Text | LayerSource::Shape => true,
LayerSource::Shape => layer.switches.collapse, LayerSource::Footage { item } => matches!(self.project.item(item).map(|i| &i.kind), Some(ItemKind::Footage(f)) if is_vector_footage(f)),
LayerSource::Footage { item } => {
layer.switches.collapse && matches!(self.project.item(item).map(|i| &i.kind), Some(ItemKind::Footage(f)) if is_vector_footage(f))
}
_ => false, _ => false,
}; };
if !continuous { if !layer.switches.collapse || !vector {
return s; return s;
} }
let (l2c, _) = ctx.layer_to_comp(layer); let (l2c, _) = ctx.layer_to_comp(layer);

View File

@ -1,7 +1,7 @@
//! Collapse Transformations, Continuously Rasterize and the Quality switch. //! Collapse Transformations, Continuously Rasterize and the Quality switch.
use effectcraft_color::{BlendMode, Label}; use effectcraft_color::{BlendMode, Label};
use effectcraft_keyframe::{TextDoc, Value}; use effectcraft_keyframe::Value;
use effectcraft_project::build::{self, Ids}; use effectcraft_project::build::{self, Ids};
use effectcraft_project::{BitDepth, Comp, ItemId, ItemKind, Layer, LayerSource, Project, Quality, Solid}; use effectcraft_project::{BitDepth, Comp, ItemId, ItemKind, Layer, LayerSource, Project, Quality, Solid};
use effectcraft_time::{FrameRate, Tick}; use effectcraft_time::{FrameRate, Tick};
@ -234,32 +234,3 @@ fn collapsed_precomp_of_another_size_renders_through_the_parent_camera() {
assert!(img.get(100, 100)[3] < 0.01, "only the 40 px solid is drawn"); assert!(img.get(100, 100)[3] < 0.01, "only the 40 px solid is drawn");
} }
} }
/// Text layers are always continuously rasterised (#194): text scaled up with the layer's Scale is drawn
/// at its on-screen size, as sharp as text set at that font size, without the switch.
#[test]
fn text_scaled_up_stays_sharp_without_the_switch() {
let run = |size: f64, scale: f64| {
let mut p = project();
let comp = Comp::new(240, 160, FrameRate::FPS_30, Tick::from_seconds_f64(2.0));
let mut l = build::layer(&mut p, &comp, "Text", LayerSource::Text, (240, 160), None);
l.props.prop_mut("text/sourceText").unwrap().value = Value::Text(Box::new(TextDoc { text: "HE".into(), size, ..Default::default() }));
set(&mut l, "transform/anchor", Value::Vec3([0.0, 0.0, 0.0]));
set(&mut l, "transform/position", Value::Vec3([40.0, 120.0, 0.0]));
set(&mut l, "transform/scale", Value::Vec3([scale, scale, 100.0]));
assert!(!l.switches.collapse);
let mut c = comp;
c.layers = vec![l];
let cid = p.add_item("Comp", Label::Sandstone, None, ItemKind::Comp(c.into()));
render_frame(&p, cid, Tick::ZERO, 1.0)
};
let partial = |img: &Image| img.data.iter().filter(|px| (0.02..0.98).contains(&px[3])).count();
let scaled = run(10.0, 800.0);
let native = run(80.0, 100.0);
let (ps, pn) = (partial(&scaled), partial(&native));
let d = max_diff(&scaled, &native);
eprintln!("partially covered pixels: scaled {ps}, native {pn}; max difference {d}");
assert!(native.data.iter().filter(|px| px[3] > 0.98).count() > 1000, "the text renders");
assert!(ps <= pn + pn / 2, "scaled text is blurred: {ps} soft pixels against {pn}");
assert!(d < 0.05, "scaled text differs from text set at that size by {d}");
}

View File

@ -318,9 +318,8 @@ hierarchical block-matching optical flow and a bidirectional warp (Pixel Motion,
its nested layers straight into the parent with concatenated transforms (one resample), so its nested layers straight into the parent with concatenated transforms (one resample), so
nested blend modes and adjustment layers act on the parent's layers; nested 3D layers use the nested blend modes and adjustment layers act on the parent's layers; nested 3D layers use the
parent's camera and lights and, when the precomp layer is 3D, are depth-sorted with the parent's parent's camera and lights and, when the precomp layer is 3D, are depth-sorted with the parent's
3D run. Masks, effects or styles force a flattened render. Text layers are always rasterised at 3D run. Masks, effects or styles force a flattened render. On text and shape layers the switch is
their on-screen scale; on shape layers and vector footage the switch is Continuously Rasterize and Continuously Rasterize: the source is rasterised at its on-screen scale. Quality: Draft samples
does the same. Quality: Draft samples
nearest-neighbour, Wireframe draws the layer bounds. Slip edit (`layer.slip`, Alt+PageUp/Down, nearest-neighbour, Wireframe draws the layer bounds. Slip edit (`layer.slip`, Alt+PageUp/Down,
dragging the source bar in the timeline) moves the source under fixed in/out points. dragging the source bar in the timeline) moves the source under fixed in/out points.