mirror of
https://github.com/italicsjenga/vello.git
synced 2025-01-10 12:41:30 +11:00
Make transforms stateless
Removes the transform state mutator from SceneBuilder and adds transform parameters to push_layer, fill and stroke methods.
This commit is contained in:
parent
cd25528abd
commit
7fe022228a
|
@ -273,8 +273,8 @@ pub unsafe extern "C" fn pgpu_scene_builder_transform(
|
|||
builder: *mut PgpuSceneBuilder<'static>,
|
||||
transform: *const PgpuTransform,
|
||||
) {
|
||||
if !transform.is_null() {
|
||||
(*builder).0.transform((*transform).into())
|
||||
if let Some(transform) = transform.as_ref() {
|
||||
(*builder).transform = (*transform).into();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -308,9 +308,13 @@ pub unsafe extern "C" fn pgpu_scene_builder_fill_path(
|
|||
} else {
|
||||
Some((*brush_transform).into())
|
||||
};
|
||||
(*builder)
|
||||
.0
|
||||
.fill(fill, &brush, brush_transform, (*path).clone());
|
||||
(*builder).builder.fill(
|
||||
fill,
|
||||
(*builder).transform,
|
||||
&brush,
|
||||
brush_transform,
|
||||
(*path).clone(),
|
||||
);
|
||||
}
|
||||
|
||||
/// Appends a scene fragment to the underlying scene or fragment. The
|
||||
|
@ -329,7 +333,7 @@ pub unsafe extern "C" fn pgpu_scene_builder_append_fragment(
|
|||
} else {
|
||||
Some((*transform).into())
|
||||
};
|
||||
(*builder).0.append(&(*fragment).0, transform);
|
||||
(*builder).builder.append(&(*fragment).0, transform);
|
||||
}
|
||||
|
||||
/// Finalizes the scene builder, making the underlying scene ready for
|
||||
|
|
|
@ -103,19 +103,18 @@ impl PgpuRenderer {
|
|||
}
|
||||
|
||||
/// Encoded streams and resources describing a vector graphics scene.
|
||||
pub struct PgpuScene {
|
||||
scene: Scene,
|
||||
}
|
||||
pub struct PgpuScene(pub Scene);
|
||||
|
||||
impl PgpuScene {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
scene: Scene::default(),
|
||||
}
|
||||
Self(Scene::default())
|
||||
}
|
||||
|
||||
pub fn builder(&mut self) -> PgpuSceneBuilder {
|
||||
PgpuSceneBuilder(piet_scene::SceneBuilder::for_scene(&mut self.scene))
|
||||
PgpuSceneBuilder {
|
||||
builder: piet_scene::SceneBuilder::for_scene(&mut self.0),
|
||||
transform: Affine::IDENTITY,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -128,20 +127,26 @@ impl PgpuSceneFragment {
|
|||
}
|
||||
|
||||
pub fn builder(&mut self) -> PgpuSceneBuilder {
|
||||
PgpuSceneBuilder(piet_scene::SceneBuilder::for_fragment(&mut self.0))
|
||||
PgpuSceneBuilder {
|
||||
builder: piet_scene::SceneBuilder::for_fragment(&mut self.0),
|
||||
transform: Affine::IDENTITY,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Builder for constructing an encoded scene.
|
||||
pub struct PgpuSceneBuilder<'a>(pub piet_scene::SceneBuilder<'a>);
|
||||
pub struct PgpuSceneBuilder<'a> {
|
||||
pub builder: piet_scene::SceneBuilder<'a>,
|
||||
pub transform: Affine,
|
||||
}
|
||||
|
||||
impl<'a> PgpuSceneBuilder<'a> {
|
||||
pub fn add_glyph(&mut self, glyph: &PgpuGlyph, transform: &piet_scene::Affine) {
|
||||
self.0.append(&glyph.fragment, Some(*transform));
|
||||
self.builder.append(&glyph.fragment, Some(*transform));
|
||||
}
|
||||
|
||||
pub fn finish(self) {
|
||||
self.0.finish();
|
||||
self.builder.finish();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -122,7 +122,7 @@ fn main() -> Result<(), Error> {
|
|||
} else {
|
||||
let mut builder = SceneBuilder::for_scene(&mut scene);
|
||||
|
||||
const N_SAMPLES: usize = 4;
|
||||
const N_SAMPLES: usize = 5;
|
||||
match sample_index % N_SAMPLES {
|
||||
0 => samples::render_anim_frame(
|
||||
&mut builder,
|
||||
|
@ -131,6 +131,7 @@ fn main() -> Result<(), Error> {
|
|||
),
|
||||
1 => samples::render_blend_grid(&mut builder),
|
||||
2 => samples::render_tiger(&mut builder, false),
|
||||
3 => samples::render_brush_transform(&mut builder, current_frame),
|
||||
_ => samples::render_scene(&mut builder),
|
||||
}
|
||||
render_info(&mut simple_text, &mut builder, &info_string);
|
||||
|
|
|
@ -16,6 +16,7 @@ pub fn render_svg(sb: &mut SceneBuilder, svg: &PicoSvg, print_stats: bool) {
|
|||
Item::Fill(fill) => {
|
||||
sb.fill(
|
||||
Fill::NonZero,
|
||||
Affine::IDENTITY,
|
||||
&fill.color.into(),
|
||||
None,
|
||||
convert_bez_path(&fill.path),
|
||||
|
@ -24,6 +25,7 @@ pub fn render_svg(sb: &mut SceneBuilder, svg: &PicoSvg, print_stats: bool) {
|
|||
Item::Stroke(stroke) => {
|
||||
sb.stroke(
|
||||
&simple_stroke(stroke.width as f32),
|
||||
Affine::IDENTITY,
|
||||
&stroke.color.into(),
|
||||
None,
|
||||
convert_bez_path(&stroke.path),
|
||||
|
@ -76,6 +78,7 @@ fn render_cardioid(sb: &mut SceneBuilder) {
|
|||
}
|
||||
sb.stroke(
|
||||
&simple_stroke(2.0),
|
||||
Affine::IDENTITY,
|
||||
&Brush::Solid(Color::rgb8(0, 0, 0)),
|
||||
None,
|
||||
&path,
|
||||
|
@ -102,7 +105,7 @@ fn render_clip_test(sb: &mut SceneBuilder) {
|
|||
PathElement::LineTo((X0, Y1).into()),
|
||||
PathElement::Close,
|
||||
];
|
||||
sb.push_layer(Mix::Clip.into(), path);
|
||||
sb.push_layer(Mix::Clip.into(), Affine::IDENTITY, path);
|
||||
}
|
||||
let rect = Rect {
|
||||
min: Point::new(X0, Y0),
|
||||
|
@ -110,6 +113,7 @@ fn render_clip_test(sb: &mut SceneBuilder) {
|
|||
};
|
||||
sb.fill(
|
||||
Fill::NonZero,
|
||||
Affine::IDENTITY,
|
||||
&Brush::Solid(Color::rgb8(0, 0, 0)),
|
||||
None,
|
||||
rect.elements(),
|
||||
|
@ -124,22 +128,29 @@ fn render_alpha_test(sb: &mut SceneBuilder) {
|
|||
// Alpha compositing tests.
|
||||
sb.fill(
|
||||
Fill::NonZero,
|
||||
Affine::IDENTITY,
|
||||
&Color::rgb8(255, 0, 0).into(),
|
||||
None,
|
||||
make_diamond(Point::new(1024.0, 100.0)),
|
||||
make_diamond(1024.0, 100.0),
|
||||
);
|
||||
sb.fill(
|
||||
Fill::NonZero,
|
||||
Affine::IDENTITY,
|
||||
&Color::rgba8(0, 255, 0, 0x80).into(),
|
||||
None,
|
||||
make_diamond(Point::new(1024.0, 125.0)),
|
||||
make_diamond(1024.0, 125.0),
|
||||
);
|
||||
sb.push_layer(
|
||||
Mix::Clip.into(),
|
||||
Affine::IDENTITY,
|
||||
make_diamond(1024.0, 150.0),
|
||||
);
|
||||
sb.push_layer(Mix::Clip.into(), make_diamond(Point::new(1024.0, 150.0)));
|
||||
sb.fill(
|
||||
Fill::NonZero,
|
||||
Affine::IDENTITY,
|
||||
&Color::rgba8(0, 0, 255, 0x80).into(),
|
||||
None,
|
||||
make_diamond(Point::new(1024.0, 175.0)),
|
||||
make_diamond(1024.0, 175.0),
|
||||
);
|
||||
sb.pop_layer();
|
||||
}
|
||||
|
@ -170,15 +181,12 @@ pub fn render_blend_grid(sb: &mut SceneBuilder) {
|
|||
let transform = Affine::translate(i as f32 * 225., j as f32 * 225.);
|
||||
let square = blend_square(blend.into());
|
||||
sb.append(&square, Some(transform));
|
||||
// sb.append(&square, Some(transform));
|
||||
// render_blend_square(sb, blend.into(), transform);
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
fn render_blend_square(sb: &mut SceneBuilder, blend: BlendMode, transform: Affine) {
|
||||
// Inspired by https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode
|
||||
sb.transform(transform);
|
||||
let rect = Rect::from_origin_size(Point::new(0., 0.), 200., 200.);
|
||||
let stops = &[
|
||||
GradientStop {
|
||||
|
@ -196,7 +204,7 @@ fn render_blend_square(sb: &mut SceneBuilder, blend: BlendMode, transform: Affin
|
|||
stops: stops.into(),
|
||||
extend: ExtendMode::Pad,
|
||||
});
|
||||
sb.fill(Fill::NonZero, &linear, None, rect.elements());
|
||||
sb.fill(Fill::NonZero, transform, &linear, None, rect.elements());
|
||||
const GRADIENTS: &[(f32, f32, Color)] = &[
|
||||
(150., 0., Color::rgb8(64, 240, 255)),
|
||||
(175., 100., Color::rgb8(240, 96, 255)),
|
||||
|
@ -223,14 +231,14 @@ fn render_blend_square(sb: &mut SceneBuilder, blend: BlendMode, transform: Affin
|
|||
stops: stops.into(),
|
||||
extend: ExtendMode::Pad,
|
||||
});
|
||||
sb.fill(Fill::NonZero, &rad, None, rect.elements());
|
||||
sb.fill(Fill::NonZero, transform, &rad, None, rect.elements());
|
||||
}
|
||||
const COLORS: &[Color] = &[
|
||||
Color::rgb8(0, 0, 255),
|
||||
Color::rgb8(0, 255, 0),
|
||||
Color::rgb8(255, 0, 0),
|
||||
];
|
||||
sb.push_layer(Mix::Normal.into(), rect.elements());
|
||||
sb.push_layer(Mix::Normal.into(), transform, rect.elements());
|
||||
for (i, c) in COLORS.iter().enumerate() {
|
||||
let stops = &[
|
||||
GradientStop {
|
||||
|
@ -248,17 +256,16 @@ fn render_blend_square(sb: &mut SceneBuilder, blend: BlendMode, transform: Affin
|
|||
stops: stops.into(),
|
||||
extend: ExtendMode::Pad,
|
||||
});
|
||||
sb.transform(transform);
|
||||
sb.push_layer(blend, rect.elements());
|
||||
sb.push_layer(blend, transform, rect.elements());
|
||||
// squash the ellipse
|
||||
let a = transform
|
||||
* Affine::translate(100., 100.)
|
||||
* Affine::rotate(std::f32::consts::FRAC_PI_3 * (i * 2 + 1) as f32)
|
||||
* Affine::scale(1.0, 0.357)
|
||||
* Affine::translate(-100., -100.);
|
||||
sb.transform(a);
|
||||
sb.fill(
|
||||
Fill::NonZero,
|
||||
a,
|
||||
&linear,
|
||||
None,
|
||||
make_ellipse(100., 100., 90., 90.),
|
||||
|
@ -272,93 +279,7 @@ fn render_blend_square(sb: &mut SceneBuilder, blend: BlendMode, transform: Affin
|
|||
fn blend_square(blend: BlendMode) -> SceneFragment {
|
||||
let mut fragment = SceneFragment::default();
|
||||
let mut sb = SceneBuilder::for_fragment(&mut fragment);
|
||||
// Inspired by https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode
|
||||
let rect = Rect::from_origin_size(Point::new(0., 0.), 200., 200.);
|
||||
let stops = &[
|
||||
GradientStop {
|
||||
color: Color::rgb8(0, 0, 0),
|
||||
offset: 0.0,
|
||||
},
|
||||
GradientStop {
|
||||
color: Color::rgb8(255, 255, 255),
|
||||
offset: 1.0,
|
||||
},
|
||||
][..];
|
||||
let linear = Brush::LinearGradient(LinearGradient {
|
||||
start: Point::new(0.0, 0.0),
|
||||
end: Point::new(200.0, 0.0),
|
||||
stops: stops.into(),
|
||||
extend: ExtendMode::Pad,
|
||||
});
|
||||
sb.fill(Fill::NonZero, &linear, None, rect.elements());
|
||||
const GRADIENTS: &[(f32, f32, Color)] = &[
|
||||
(150., 0., Color::rgb8(64, 240, 255)),
|
||||
(175., 100., Color::rgb8(240, 96, 255)),
|
||||
(125., 200., Color::rgb8(255, 192, 64)),
|
||||
];
|
||||
for (x, y, c) in GRADIENTS {
|
||||
let mut color2 = c.clone();
|
||||
color2.a = 0;
|
||||
let stops = &[
|
||||
GradientStop {
|
||||
color: c.clone(),
|
||||
offset: 0.0,
|
||||
},
|
||||
GradientStop {
|
||||
color: color2,
|
||||
offset: 1.0,
|
||||
},
|
||||
][..];
|
||||
let rad = Brush::RadialGradient(RadialGradient {
|
||||
center0: Point::new(*x, *y),
|
||||
center1: Point::new(*x, *y),
|
||||
radius0: 0.0,
|
||||
radius1: 100.0,
|
||||
stops: stops.into(),
|
||||
extend: ExtendMode::Pad,
|
||||
});
|
||||
sb.fill(Fill::NonZero, &rad, None, rect.elements());
|
||||
}
|
||||
const COLORS: &[Color] = &[
|
||||
Color::rgb8(0, 0, 255),
|
||||
Color::rgb8(0, 255, 0),
|
||||
Color::rgb8(255, 0, 0),
|
||||
];
|
||||
sb.push_layer(Mix::Normal.into(), rect.elements());
|
||||
for (i, c) in COLORS.iter().enumerate() {
|
||||
let stops = &[
|
||||
GradientStop {
|
||||
color: Color::rgb8(255, 255, 255),
|
||||
offset: 0.0,
|
||||
},
|
||||
GradientStop {
|
||||
color: c.clone(),
|
||||
offset: 1.0,
|
||||
},
|
||||
][..];
|
||||
let linear = Brush::LinearGradient(LinearGradient {
|
||||
start: Point::new(0.0, 0.0),
|
||||
end: Point::new(0.0, 200.0),
|
||||
stops: stops.into(),
|
||||
extend: ExtendMode::Pad,
|
||||
});
|
||||
sb.transform(Affine::IDENTITY);
|
||||
sb.push_layer(blend, rect.elements());
|
||||
// squash the ellipse
|
||||
let a = Affine::translate(100., 100.)
|
||||
* Affine::rotate(std::f32::consts::FRAC_PI_3 * (i * 2 + 1) as f32)
|
||||
* Affine::scale(1.0, 0.357)
|
||||
* Affine::translate(-100., -100.);
|
||||
sb.transform(a);
|
||||
sb.fill(
|
||||
Fill::NonZero,
|
||||
&linear,
|
||||
None,
|
||||
make_ellipse(100., 100., 90., 90.),
|
||||
);
|
||||
sb.pop_layer();
|
||||
}
|
||||
sb.pop_layer();
|
||||
render_blend_square(&mut sb, blend, Affine::IDENTITY);
|
||||
sb.finish();
|
||||
fragment
|
||||
}
|
||||
|
@ -367,6 +288,7 @@ fn blend_square(blend: BlendMode) -> SceneFragment {
|
|||
pub fn render_anim_frame(sb: &mut SceneBuilder, text: &mut SimpleText, i: usize) {
|
||||
sb.fill(
|
||||
Fill::NonZero,
|
||||
Affine::IDENTITY,
|
||||
&Brush::Solid(Color::rgb8(128, 128, 128)),
|
||||
None,
|
||||
Rect::from_origin_size(Point::new(0.0, 0.0), 1000.0, 1000.0).elements(),
|
||||
|
@ -389,7 +311,6 @@ pub fn render_anim_frame(sb: &mut SceneBuilder, text: &mut SimpleText, i: usize)
|
|||
Affine::translate(110.0, 700.0),
|
||||
s,
|
||||
);
|
||||
sb.transform(Affine::IDENTITY);
|
||||
let th = (std::f32::consts::PI / 180.0) * (i as f32);
|
||||
let center = Point::new(500.0, 500.0);
|
||||
let mut p1 = center;
|
||||
|
@ -397,12 +318,54 @@ pub fn render_anim_frame(sb: &mut SceneBuilder, text: &mut SimpleText, i: usize)
|
|||
p1.y += 400.0 * th.sin();
|
||||
sb.stroke(
|
||||
&simple_stroke(5.0),
|
||||
Affine::IDENTITY,
|
||||
&Brush::Solid(Color::rgb8(128, 0, 0)),
|
||||
None,
|
||||
&[PathElement::MoveTo(center), PathElement::LineTo(p1)],
|
||||
);
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn render_brush_transform(sb: &mut SceneBuilder, i: usize) {
|
||||
let th = (std::f32::consts::PI / 180.0) * (i as f32);
|
||||
let stops = &[
|
||||
GradientStop {
|
||||
color: Color::rgb8(255, 0, 0),
|
||||
offset: 0.0,
|
||||
},
|
||||
GradientStop {
|
||||
color: Color::rgb8(0, 255, 0),
|
||||
offset: 0.5,
|
||||
},
|
||||
GradientStop {
|
||||
color: Color::rgb8(0, 0, 255),
|
||||
offset: 1.0,
|
||||
},
|
||||
][..];
|
||||
let linear = LinearGradient {
|
||||
start: Point::new(0.0, 0.0),
|
||||
end: Point::new(0.0, 200.0),
|
||||
stops: stops.into(),
|
||||
extend: ExtendMode::Pad,
|
||||
}
|
||||
.into();
|
||||
sb.fill(
|
||||
Fill::NonZero,
|
||||
Affine::translate(200.0, 200.0),
|
||||
&linear,
|
||||
Some(Affine::rotate(th).around_center(200.0, 100.0)),
|
||||
Rect::from_origin_size(Point::default(), 400.0, 200.0).elements(),
|
||||
);
|
||||
sb.stroke(
|
||||
&simple_stroke(40.0),
|
||||
Affine::translate(800.0, 200.0),
|
||||
&linear,
|
||||
Some(Affine::rotate(th).around_center(200.0, 100.0)),
|
||||
Rect::from_origin_size(Point::default(), 400.0, 200.0).elements(),
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
fn convert_bez_path<'a>(path: &'a BezPath) -> impl Iterator<Item = PathElement> + 'a + Clone {
|
||||
path.elements()
|
||||
.iter()
|
||||
|
@ -440,13 +403,13 @@ fn make_ellipse(cx: f32, cy: f32, rx: f32, ry: f32) -> impl Iterator<Item = Path
|
|||
(0..elements.len()).map(move |i| elements[i])
|
||||
}
|
||||
|
||||
fn make_diamond(origin: Point) -> impl Iterator<Item = PathElement> + Clone {
|
||||
fn make_diamond(cx: f32, cy: f32) -> impl Iterator<Item = PathElement> + Clone {
|
||||
const SIZE: f32 = 50.0;
|
||||
let elements = [
|
||||
PathElement::MoveTo(Point::new(origin.x, origin.y - SIZE)),
|
||||
PathElement::LineTo(Point::new(origin.x + SIZE, origin.y)),
|
||||
PathElement::LineTo(Point::new(origin.x, origin.y + SIZE)),
|
||||
PathElement::LineTo(Point::new(origin.x - SIZE, origin.y)),
|
||||
PathElement::MoveTo(Point::new(cx, cy - SIZE)),
|
||||
PathElement::LineTo(Point::new(cx + SIZE, cy)),
|
||||
PathElement::LineTo(Point::new(cx, cy + SIZE)),
|
||||
PathElement::LineTo(Point::new(cx - SIZE, cy)),
|
||||
PathElement::Close,
|
||||
];
|
||||
(0..elements.len()).map(move |i| elements[i])
|
||||
|
|
|
@ -90,6 +90,7 @@ impl<'a> GlyphProvider<'a> {
|
|||
let mut builder = SceneBuilder::for_fragment(&mut fragment);
|
||||
builder.fill(
|
||||
Fill::NonZero,
|
||||
Affine::IDENTITY,
|
||||
brush.unwrap_or(&Brush::Solid(Color::rgb8(255, 255, 255))),
|
||||
None,
|
||||
convert_path(path.elements()),
|
||||
|
@ -125,10 +126,15 @@ impl<'a> GlyphProvider<'a> {
|
|||
if let Some(xform) = xform_stack.last() {
|
||||
builder.push_layer(
|
||||
Default::default(),
|
||||
Affine::IDENTITY,
|
||||
convert_transformed_path(path.elements(), xform),
|
||||
);
|
||||
} else {
|
||||
builder.push_layer(Default::default(), convert_path(path.elements()));
|
||||
builder.push_layer(
|
||||
Default::default(),
|
||||
Affine::IDENTITY,
|
||||
convert_path(path.elements()),
|
||||
);
|
||||
}
|
||||
}
|
||||
Command::PopClip => builder.pop_layer(),
|
||||
|
@ -140,7 +146,7 @@ impl<'a> GlyphProvider<'a> {
|
|||
if let Some(xform) = xform_stack.last() {
|
||||
rect = rect.transform(xform);
|
||||
}
|
||||
builder.push_layer(Default::default(), rect.elements());
|
||||
builder.push_layer(Default::default(), Affine::IDENTITY, rect.elements());
|
||||
}
|
||||
Command::PopLayer => builder.pop_layer(),
|
||||
Command::BeginBlend(bounds, mode) => {
|
||||
|
@ -151,7 +157,7 @@ impl<'a> GlyphProvider<'a> {
|
|||
if let Some(xform) = xform_stack.last() {
|
||||
rect = rect.transform(xform);
|
||||
}
|
||||
builder.push_layer(convert_blend(*mode), rect.elements())
|
||||
builder.push_layer(convert_blend(*mode), Affine::IDENTITY, rect.elements())
|
||||
}
|
||||
Command::EndBlend => builder.pop_layer(),
|
||||
Command::SimpleFill(path_index, brush, brush_xform) => {
|
||||
|
@ -161,6 +167,7 @@ impl<'a> GlyphProvider<'a> {
|
|||
if let Some(xform) = xform_stack.last() {
|
||||
builder.fill(
|
||||
Fill::NonZero,
|
||||
Affine::IDENTITY,
|
||||
&brush,
|
||||
brush_xform.map(|x| x * *xform),
|
||||
convert_transformed_path(path.elements(), xform),
|
||||
|
@ -168,6 +175,7 @@ impl<'a> GlyphProvider<'a> {
|
|||
} else {
|
||||
builder.fill(
|
||||
Fill::NonZero,
|
||||
Affine::IDENTITY,
|
||||
&brush,
|
||||
brush_xform,
|
||||
convert_path(path.elements()),
|
||||
|
|
|
@ -49,21 +49,15 @@ impl<'a> SceneBuilder<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Sets the current transformation.
|
||||
pub fn transform(&mut self, transform: Affine) {
|
||||
if self.scene.transform_stream.last() != Some(&transform) {
|
||||
self.encode_transform(transform);
|
||||
}
|
||||
}
|
||||
|
||||
/// Pushes a new layer bound by the specifed shape and composed with
|
||||
/// previous layers using the specified blend mode.
|
||||
pub fn push_layer<'s, E>(&mut self, blend: BlendMode, elements: E)
|
||||
pub fn push_layer<'s, E>(&mut self, blend: BlendMode, transform: Affine, elements: E)
|
||||
where
|
||||
E: IntoIterator,
|
||||
E::IntoIter: Clone,
|
||||
E::Item: Borrow<PathElement>,
|
||||
{
|
||||
self.maybe_encode_transform(transform);
|
||||
self.linewidth(-1.0);
|
||||
let elements = elements.into_iter();
|
||||
self.encode_path(elements, true);
|
||||
|
@ -82,6 +76,7 @@ impl<'a> SceneBuilder<'a> {
|
|||
pub fn fill<'s, E>(
|
||||
&mut self,
|
||||
_style: Fill,
|
||||
transform: Affine,
|
||||
brush: &Brush,
|
||||
brush_transform: Option<Affine>,
|
||||
elements: E,
|
||||
|
@ -90,21 +85,14 @@ impl<'a> SceneBuilder<'a> {
|
|||
E::IntoIter: Clone,
|
||||
E::Item: Borrow<PathElement>,
|
||||
{
|
||||
self.maybe_encode_transform(transform);
|
||||
self.linewidth(-1.0);
|
||||
let elements = elements.into_iter();
|
||||
if self.encode_path(elements, true) {
|
||||
if let Some(brush_transform) = brush_transform {
|
||||
if let Some(last_transform) = self.scene.transform_stream.last().copied() {
|
||||
self.encode_transform(brush_transform * last_transform);
|
||||
self.encode_transform(transform * brush_transform);
|
||||
self.swap_last_tags();
|
||||
self.encode_brush(brush);
|
||||
self.encode_transform(last_transform);
|
||||
} else {
|
||||
self.encode_transform(brush_transform);
|
||||
self.swap_last_tags();
|
||||
self.encode_brush(brush);
|
||||
self.encode_transform(Affine::IDENTITY);
|
||||
}
|
||||
} else {
|
||||
self.encode_brush(brush);
|
||||
}
|
||||
|
@ -115,6 +103,7 @@ impl<'a> SceneBuilder<'a> {
|
|||
pub fn stroke<'s, D, E>(
|
||||
&mut self,
|
||||
style: &Stroke<D>,
|
||||
transform: Affine,
|
||||
brush: &Brush,
|
||||
brush_transform: Option<Affine>,
|
||||
elements: E,
|
||||
|
@ -124,21 +113,14 @@ impl<'a> SceneBuilder<'a> {
|
|||
E::IntoIter: Clone,
|
||||
E::Item: Borrow<PathElement>,
|
||||
{
|
||||
self.maybe_encode_transform(transform);
|
||||
self.linewidth(style.width);
|
||||
let elements = elements.into_iter();
|
||||
if self.encode_path(elements, false) {
|
||||
if let Some(brush_transform) = brush_transform {
|
||||
if let Some(last_transform) = self.scene.transform_stream.last().copied() {
|
||||
self.encode_transform(brush_transform * last_transform);
|
||||
self.encode_transform(transform * brush_transform);
|
||||
self.swap_last_tags();
|
||||
self.encode_brush(brush);
|
||||
self.encode_transform(last_transform);
|
||||
} else {
|
||||
self.encode_transform(brush_transform);
|
||||
self.swap_last_tags();
|
||||
self.encode_brush(brush);
|
||||
self.encode_transform(Affine::IDENTITY);
|
||||
}
|
||||
} else {
|
||||
self.encode_brush(brush);
|
||||
}
|
||||
|
@ -147,20 +129,7 @@ impl<'a> SceneBuilder<'a> {
|
|||
|
||||
/// Appends a fragment to the scene.
|
||||
pub fn append(&mut self, fragment: &SceneFragment, transform: Option<Affine>) {
|
||||
let mut cur_transform = self.scene.transform_stream.last().copied();
|
||||
if let Some(transform) = transform {
|
||||
if cur_transform.is_none() {
|
||||
cur_transform = Some(Affine::IDENTITY);
|
||||
}
|
||||
self.transform(transform);
|
||||
} else if cur_transform != Some(Affine::IDENTITY) {
|
||||
self.encode_transform(Affine::IDENTITY);
|
||||
}
|
||||
self.scene.append(&fragment.data, &transform);
|
||||
// Prevent fragments from affecting transform state. Should we allow this?
|
||||
if let Some(transform) = cur_transform {
|
||||
self.transform(transform);
|
||||
}
|
||||
}
|
||||
|
||||
/// Completes construction and finalizes the underlying scene.
|
||||
|
@ -218,6 +187,12 @@ impl<'a> SceneBuilder<'a> {
|
|||
has_els
|
||||
}
|
||||
|
||||
fn maybe_encode_transform(&mut self, transform: Affine) {
|
||||
if self.scene.transform_stream.last() != Some(&transform) {
|
||||
self.encode_transform(transform);
|
||||
}
|
||||
}
|
||||
|
||||
fn encode_transform(&mut self, transform: Affine) {
|
||||
self.scene.tag_stream.push(0x20);
|
||||
self.scene.transform_stream.push(transform);
|
||||
|
|
Loading…
Reference in a new issue