mirror of
https://github.com/italicsjenga/vello.git
synced 2025-01-10 20:51:29 +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>,
|
builder: *mut PgpuSceneBuilder<'static>,
|
||||||
transform: *const PgpuTransform,
|
transform: *const PgpuTransform,
|
||||||
) {
|
) {
|
||||||
if !transform.is_null() {
|
if let Some(transform) = transform.as_ref() {
|
||||||
(*builder).0.transform((*transform).into())
|
(*builder).transform = (*transform).into();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -308,9 +308,13 @@ pub unsafe extern "C" fn pgpu_scene_builder_fill_path(
|
||||||
} else {
|
} else {
|
||||||
Some((*brush_transform).into())
|
Some((*brush_transform).into())
|
||||||
};
|
};
|
||||||
(*builder)
|
(*builder).builder.fill(
|
||||||
.0
|
fill,
|
||||||
.fill(fill, &brush, brush_transform, (*path).clone());
|
(*builder).transform,
|
||||||
|
&brush,
|
||||||
|
brush_transform,
|
||||||
|
(*path).clone(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Appends a scene fragment to the underlying scene or fragment. The
|
/// 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 {
|
} else {
|
||||||
Some((*transform).into())
|
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
|
/// 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.
|
/// Encoded streams and resources describing a vector graphics scene.
|
||||||
pub struct PgpuScene {
|
pub struct PgpuScene(pub Scene);
|
||||||
scene: Scene,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PgpuScene {
|
impl PgpuScene {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self(Scene::default())
|
||||||
scene: Scene::default(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn builder(&mut self) -> PgpuSceneBuilder {
|
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 {
|
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.
|
/// 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> {
|
impl<'a> PgpuSceneBuilder<'a> {
|
||||||
pub fn add_glyph(&mut self, glyph: &PgpuGlyph, transform: &piet_scene::Affine) {
|
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) {
|
pub fn finish(self) {
|
||||||
self.0.finish();
|
self.builder.finish();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -122,7 +122,7 @@ fn main() -> Result<(), Error> {
|
||||||
} else {
|
} else {
|
||||||
let mut builder = SceneBuilder::for_scene(&mut scene);
|
let mut builder = SceneBuilder::for_scene(&mut scene);
|
||||||
|
|
||||||
const N_SAMPLES: usize = 4;
|
const N_SAMPLES: usize = 5;
|
||||||
match sample_index % N_SAMPLES {
|
match sample_index % N_SAMPLES {
|
||||||
0 => samples::render_anim_frame(
|
0 => samples::render_anim_frame(
|
||||||
&mut builder,
|
&mut builder,
|
||||||
|
@ -131,6 +131,7 @@ fn main() -> Result<(), Error> {
|
||||||
),
|
),
|
||||||
1 => samples::render_blend_grid(&mut builder),
|
1 => samples::render_blend_grid(&mut builder),
|
||||||
2 => samples::render_tiger(&mut builder, false),
|
2 => samples::render_tiger(&mut builder, false),
|
||||||
|
3 => samples::render_brush_transform(&mut builder, current_frame),
|
||||||
_ => samples::render_scene(&mut builder),
|
_ => samples::render_scene(&mut builder),
|
||||||
}
|
}
|
||||||
render_info(&mut simple_text, &mut builder, &info_string);
|
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) => {
|
Item::Fill(fill) => {
|
||||||
sb.fill(
|
sb.fill(
|
||||||
Fill::NonZero,
|
Fill::NonZero,
|
||||||
|
Affine::IDENTITY,
|
||||||
&fill.color.into(),
|
&fill.color.into(),
|
||||||
None,
|
None,
|
||||||
convert_bez_path(&fill.path),
|
convert_bez_path(&fill.path),
|
||||||
|
@ -24,6 +25,7 @@ pub fn render_svg(sb: &mut SceneBuilder, svg: &PicoSvg, print_stats: bool) {
|
||||||
Item::Stroke(stroke) => {
|
Item::Stroke(stroke) => {
|
||||||
sb.stroke(
|
sb.stroke(
|
||||||
&simple_stroke(stroke.width as f32),
|
&simple_stroke(stroke.width as f32),
|
||||||
|
Affine::IDENTITY,
|
||||||
&stroke.color.into(),
|
&stroke.color.into(),
|
||||||
None,
|
None,
|
||||||
convert_bez_path(&stroke.path),
|
convert_bez_path(&stroke.path),
|
||||||
|
@ -76,6 +78,7 @@ fn render_cardioid(sb: &mut SceneBuilder) {
|
||||||
}
|
}
|
||||||
sb.stroke(
|
sb.stroke(
|
||||||
&simple_stroke(2.0),
|
&simple_stroke(2.0),
|
||||||
|
Affine::IDENTITY,
|
||||||
&Brush::Solid(Color::rgb8(0, 0, 0)),
|
&Brush::Solid(Color::rgb8(0, 0, 0)),
|
||||||
None,
|
None,
|
||||||
&path,
|
&path,
|
||||||
|
@ -102,7 +105,7 @@ fn render_clip_test(sb: &mut SceneBuilder) {
|
||||||
PathElement::LineTo((X0, Y1).into()),
|
PathElement::LineTo((X0, Y1).into()),
|
||||||
PathElement::Close,
|
PathElement::Close,
|
||||||
];
|
];
|
||||||
sb.push_layer(Mix::Clip.into(), path);
|
sb.push_layer(Mix::Clip.into(), Affine::IDENTITY, path);
|
||||||
}
|
}
|
||||||
let rect = Rect {
|
let rect = Rect {
|
||||||
min: Point::new(X0, Y0),
|
min: Point::new(X0, Y0),
|
||||||
|
@ -110,6 +113,7 @@ fn render_clip_test(sb: &mut SceneBuilder) {
|
||||||
};
|
};
|
||||||
sb.fill(
|
sb.fill(
|
||||||
Fill::NonZero,
|
Fill::NonZero,
|
||||||
|
Affine::IDENTITY,
|
||||||
&Brush::Solid(Color::rgb8(0, 0, 0)),
|
&Brush::Solid(Color::rgb8(0, 0, 0)),
|
||||||
None,
|
None,
|
||||||
rect.elements(),
|
rect.elements(),
|
||||||
|
@ -124,22 +128,29 @@ fn render_alpha_test(sb: &mut SceneBuilder) {
|
||||||
// Alpha compositing tests.
|
// Alpha compositing tests.
|
||||||
sb.fill(
|
sb.fill(
|
||||||
Fill::NonZero,
|
Fill::NonZero,
|
||||||
|
Affine::IDENTITY,
|
||||||
&Color::rgb8(255, 0, 0).into(),
|
&Color::rgb8(255, 0, 0).into(),
|
||||||
None,
|
None,
|
||||||
make_diamond(Point::new(1024.0, 100.0)),
|
make_diamond(1024.0, 100.0),
|
||||||
);
|
);
|
||||||
sb.fill(
|
sb.fill(
|
||||||
Fill::NonZero,
|
Fill::NonZero,
|
||||||
|
Affine::IDENTITY,
|
||||||
&Color::rgba8(0, 255, 0, 0x80).into(),
|
&Color::rgba8(0, 255, 0, 0x80).into(),
|
||||||
None,
|
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(
|
sb.fill(
|
||||||
Fill::NonZero,
|
Fill::NonZero,
|
||||||
|
Affine::IDENTITY,
|
||||||
&Color::rgba8(0, 0, 255, 0x80).into(),
|
&Color::rgba8(0, 0, 255, 0x80).into(),
|
||||||
None,
|
None,
|
||||||
make_diamond(Point::new(1024.0, 175.0)),
|
make_diamond(1024.0, 175.0),
|
||||||
);
|
);
|
||||||
sb.pop_layer();
|
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 transform = Affine::translate(i as f32 * 225., j as f32 * 225.);
|
||||||
let square = blend_square(blend.into());
|
let square = blend_square(blend.into());
|
||||||
sb.append(&square, Some(transform));
|
sb.append(&square, Some(transform));
|
||||||
// sb.append(&square, Some(transform));
|
|
||||||
// render_blend_square(sb, blend.into(), transform);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
fn render_blend_square(sb: &mut SceneBuilder, blend: BlendMode, transform: Affine) {
|
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
|
// 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 rect = Rect::from_origin_size(Point::new(0., 0.), 200., 200.);
|
||||||
let stops = &[
|
let stops = &[
|
||||||
GradientStop {
|
GradientStop {
|
||||||
|
@ -196,7 +204,7 @@ fn render_blend_square(sb: &mut SceneBuilder, blend: BlendMode, transform: Affin
|
||||||
stops: stops.into(),
|
stops: stops.into(),
|
||||||
extend: ExtendMode::Pad,
|
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)] = &[
|
const GRADIENTS: &[(f32, f32, Color)] = &[
|
||||||
(150., 0., Color::rgb8(64, 240, 255)),
|
(150., 0., Color::rgb8(64, 240, 255)),
|
||||||
(175., 100., Color::rgb8(240, 96, 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(),
|
stops: stops.into(),
|
||||||
extend: ExtendMode::Pad,
|
extend: ExtendMode::Pad,
|
||||||
});
|
});
|
||||||
sb.fill(Fill::NonZero, &rad, None, rect.elements());
|
sb.fill(Fill::NonZero, transform, &rad, None, rect.elements());
|
||||||
}
|
}
|
||||||
const COLORS: &[Color] = &[
|
const COLORS: &[Color] = &[
|
||||||
Color::rgb8(0, 0, 255),
|
Color::rgb8(0, 0, 255),
|
||||||
Color::rgb8(0, 255, 0),
|
Color::rgb8(0, 255, 0),
|
||||||
Color::rgb8(255, 0, 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() {
|
for (i, c) in COLORS.iter().enumerate() {
|
||||||
let stops = &[
|
let stops = &[
|
||||||
GradientStop {
|
GradientStop {
|
||||||
|
@ -248,17 +256,16 @@ fn render_blend_square(sb: &mut SceneBuilder, blend: BlendMode, transform: Affin
|
||||||
stops: stops.into(),
|
stops: stops.into(),
|
||||||
extend: ExtendMode::Pad,
|
extend: ExtendMode::Pad,
|
||||||
});
|
});
|
||||||
sb.transform(transform);
|
sb.push_layer(blend, transform, rect.elements());
|
||||||
sb.push_layer(blend, rect.elements());
|
|
||||||
// squash the ellipse
|
// squash the ellipse
|
||||||
let a = transform
|
let a = transform
|
||||||
* Affine::translate(100., 100.)
|
* Affine::translate(100., 100.)
|
||||||
* Affine::rotate(std::f32::consts::FRAC_PI_3 * (i * 2 + 1) as f32)
|
* Affine::rotate(std::f32::consts::FRAC_PI_3 * (i * 2 + 1) as f32)
|
||||||
* Affine::scale(1.0, 0.357)
|
* Affine::scale(1.0, 0.357)
|
||||||
* Affine::translate(-100., -100.);
|
* Affine::translate(-100., -100.);
|
||||||
sb.transform(a);
|
|
||||||
sb.fill(
|
sb.fill(
|
||||||
Fill::NonZero,
|
Fill::NonZero,
|
||||||
|
a,
|
||||||
&linear,
|
&linear,
|
||||||
None,
|
None,
|
||||||
make_ellipse(100., 100., 90., 90.),
|
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 {
|
fn blend_square(blend: BlendMode) -> SceneFragment {
|
||||||
let mut fragment = SceneFragment::default();
|
let mut fragment = SceneFragment::default();
|
||||||
let mut sb = SceneBuilder::for_fragment(&mut fragment);
|
let mut sb = SceneBuilder::for_fragment(&mut fragment);
|
||||||
// Inspired by https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode
|
render_blend_square(&mut sb, blend, Affine::IDENTITY);
|
||||||
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();
|
|
||||||
sb.finish();
|
sb.finish();
|
||||||
fragment
|
fragment
|
||||||
}
|
}
|
||||||
|
@ -367,6 +288,7 @@ fn blend_square(blend: BlendMode) -> SceneFragment {
|
||||||
pub fn render_anim_frame(sb: &mut SceneBuilder, text: &mut SimpleText, i: usize) {
|
pub fn render_anim_frame(sb: &mut SceneBuilder, text: &mut SimpleText, i: usize) {
|
||||||
sb.fill(
|
sb.fill(
|
||||||
Fill::NonZero,
|
Fill::NonZero,
|
||||||
|
Affine::IDENTITY,
|
||||||
&Brush::Solid(Color::rgb8(128, 128, 128)),
|
&Brush::Solid(Color::rgb8(128, 128, 128)),
|
||||||
None,
|
None,
|
||||||
Rect::from_origin_size(Point::new(0.0, 0.0), 1000.0, 1000.0).elements(),
|
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),
|
Affine::translate(110.0, 700.0),
|
||||||
s,
|
s,
|
||||||
);
|
);
|
||||||
sb.transform(Affine::IDENTITY);
|
|
||||||
let th = (std::f32::consts::PI / 180.0) * (i as f32);
|
let th = (std::f32::consts::PI / 180.0) * (i as f32);
|
||||||
let center = Point::new(500.0, 500.0);
|
let center = Point::new(500.0, 500.0);
|
||||||
let mut p1 = center;
|
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();
|
p1.y += 400.0 * th.sin();
|
||||||
sb.stroke(
|
sb.stroke(
|
||||||
&simple_stroke(5.0),
|
&simple_stroke(5.0),
|
||||||
|
Affine::IDENTITY,
|
||||||
&Brush::Solid(Color::rgb8(128, 0, 0)),
|
&Brush::Solid(Color::rgb8(128, 0, 0)),
|
||||||
None,
|
None,
|
||||||
&[PathElement::MoveTo(center), PathElement::LineTo(p1)],
|
&[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 {
|
fn convert_bez_path<'a>(path: &'a BezPath) -> impl Iterator<Item = PathElement> + 'a + Clone {
|
||||||
path.elements()
|
path.elements()
|
||||||
.iter()
|
.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])
|
(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;
|
const SIZE: f32 = 50.0;
|
||||||
let elements = [
|
let elements = [
|
||||||
PathElement::MoveTo(Point::new(origin.x, origin.y - SIZE)),
|
PathElement::MoveTo(Point::new(cx, cy - SIZE)),
|
||||||
PathElement::LineTo(Point::new(origin.x + SIZE, origin.y)),
|
PathElement::LineTo(Point::new(cx + SIZE, cy)),
|
||||||
PathElement::LineTo(Point::new(origin.x, origin.y + SIZE)),
|
PathElement::LineTo(Point::new(cx, cy + SIZE)),
|
||||||
PathElement::LineTo(Point::new(origin.x - SIZE, origin.y)),
|
PathElement::LineTo(Point::new(cx - SIZE, cy)),
|
||||||
PathElement::Close,
|
PathElement::Close,
|
||||||
];
|
];
|
||||||
(0..elements.len()).map(move |i| elements[i])
|
(0..elements.len()).map(move |i| elements[i])
|
||||||
|
|
|
@ -90,6 +90,7 @@ impl<'a> GlyphProvider<'a> {
|
||||||
let mut builder = SceneBuilder::for_fragment(&mut fragment);
|
let mut builder = SceneBuilder::for_fragment(&mut fragment);
|
||||||
builder.fill(
|
builder.fill(
|
||||||
Fill::NonZero,
|
Fill::NonZero,
|
||||||
|
Affine::IDENTITY,
|
||||||
brush.unwrap_or(&Brush::Solid(Color::rgb8(255, 255, 255))),
|
brush.unwrap_or(&Brush::Solid(Color::rgb8(255, 255, 255))),
|
||||||
None,
|
None,
|
||||||
convert_path(path.elements()),
|
convert_path(path.elements()),
|
||||||
|
@ -125,10 +126,15 @@ impl<'a> GlyphProvider<'a> {
|
||||||
if let Some(xform) = xform_stack.last() {
|
if let Some(xform) = xform_stack.last() {
|
||||||
builder.push_layer(
|
builder.push_layer(
|
||||||
Default::default(),
|
Default::default(),
|
||||||
|
Affine::IDENTITY,
|
||||||
convert_transformed_path(path.elements(), xform),
|
convert_transformed_path(path.elements(), xform),
|
||||||
);
|
);
|
||||||
} else {
|
} 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(),
|
Command::PopClip => builder.pop_layer(),
|
||||||
|
@ -140,7 +146,7 @@ impl<'a> GlyphProvider<'a> {
|
||||||
if let Some(xform) = xform_stack.last() {
|
if let Some(xform) = xform_stack.last() {
|
||||||
rect = rect.transform(xform);
|
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::PopLayer => builder.pop_layer(),
|
||||||
Command::BeginBlend(bounds, mode) => {
|
Command::BeginBlend(bounds, mode) => {
|
||||||
|
@ -151,7 +157,7 @@ impl<'a> GlyphProvider<'a> {
|
||||||
if let Some(xform) = xform_stack.last() {
|
if let Some(xform) = xform_stack.last() {
|
||||||
rect = rect.transform(xform);
|
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::EndBlend => builder.pop_layer(),
|
||||||
Command::SimpleFill(path_index, brush, brush_xform) => {
|
Command::SimpleFill(path_index, brush, brush_xform) => {
|
||||||
|
@ -161,6 +167,7 @@ impl<'a> GlyphProvider<'a> {
|
||||||
if let Some(xform) = xform_stack.last() {
|
if let Some(xform) = xform_stack.last() {
|
||||||
builder.fill(
|
builder.fill(
|
||||||
Fill::NonZero,
|
Fill::NonZero,
|
||||||
|
Affine::IDENTITY,
|
||||||
&brush,
|
&brush,
|
||||||
brush_xform.map(|x| x * *xform),
|
brush_xform.map(|x| x * *xform),
|
||||||
convert_transformed_path(path.elements(), xform),
|
convert_transformed_path(path.elements(), xform),
|
||||||
|
@ -168,6 +175,7 @@ impl<'a> GlyphProvider<'a> {
|
||||||
} else {
|
} else {
|
||||||
builder.fill(
|
builder.fill(
|
||||||
Fill::NonZero,
|
Fill::NonZero,
|
||||||
|
Affine::IDENTITY,
|
||||||
&brush,
|
&brush,
|
||||||
brush_xform,
|
brush_xform,
|
||||||
convert_path(path.elements()),
|
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
|
/// Pushes a new layer bound by the specifed shape and composed with
|
||||||
/// previous layers using the specified blend mode.
|
/// 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
|
where
|
||||||
E: IntoIterator,
|
E: IntoIterator,
|
||||||
E::IntoIter: Clone,
|
E::IntoIter: Clone,
|
||||||
E::Item: Borrow<PathElement>,
|
E::Item: Borrow<PathElement>,
|
||||||
{
|
{
|
||||||
|
self.maybe_encode_transform(transform);
|
||||||
self.linewidth(-1.0);
|
self.linewidth(-1.0);
|
||||||
let elements = elements.into_iter();
|
let elements = elements.into_iter();
|
||||||
self.encode_path(elements, true);
|
self.encode_path(elements, true);
|
||||||
|
@ -82,6 +76,7 @@ impl<'a> SceneBuilder<'a> {
|
||||||
pub fn fill<'s, E>(
|
pub fn fill<'s, E>(
|
||||||
&mut self,
|
&mut self,
|
||||||
_style: Fill,
|
_style: Fill,
|
||||||
|
transform: Affine,
|
||||||
brush: &Brush,
|
brush: &Brush,
|
||||||
brush_transform: Option<Affine>,
|
brush_transform: Option<Affine>,
|
||||||
elements: E,
|
elements: E,
|
||||||
|
@ -90,21 +85,14 @@ impl<'a> SceneBuilder<'a> {
|
||||||
E::IntoIter: Clone,
|
E::IntoIter: Clone,
|
||||||
E::Item: Borrow<PathElement>,
|
E::Item: Borrow<PathElement>,
|
||||||
{
|
{
|
||||||
|
self.maybe_encode_transform(transform);
|
||||||
self.linewidth(-1.0);
|
self.linewidth(-1.0);
|
||||||
let elements = elements.into_iter();
|
let elements = elements.into_iter();
|
||||||
if self.encode_path(elements, true) {
|
if self.encode_path(elements, true) {
|
||||||
if let Some(brush_transform) = brush_transform {
|
if let Some(brush_transform) = brush_transform {
|
||||||
if let Some(last_transform) = self.scene.transform_stream.last().copied() {
|
self.encode_transform(transform * brush_transform);
|
||||||
self.encode_transform(brush_transform * last_transform);
|
|
||||||
self.swap_last_tags();
|
self.swap_last_tags();
|
||||||
self.encode_brush(brush);
|
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 {
|
} else {
|
||||||
self.encode_brush(brush);
|
self.encode_brush(brush);
|
||||||
}
|
}
|
||||||
|
@ -115,6 +103,7 @@ impl<'a> SceneBuilder<'a> {
|
||||||
pub fn stroke<'s, D, E>(
|
pub fn stroke<'s, D, E>(
|
||||||
&mut self,
|
&mut self,
|
||||||
style: &Stroke<D>,
|
style: &Stroke<D>,
|
||||||
|
transform: Affine,
|
||||||
brush: &Brush,
|
brush: &Brush,
|
||||||
brush_transform: Option<Affine>,
|
brush_transform: Option<Affine>,
|
||||||
elements: E,
|
elements: E,
|
||||||
|
@ -124,21 +113,14 @@ impl<'a> SceneBuilder<'a> {
|
||||||
E::IntoIter: Clone,
|
E::IntoIter: Clone,
|
||||||
E::Item: Borrow<PathElement>,
|
E::Item: Borrow<PathElement>,
|
||||||
{
|
{
|
||||||
|
self.maybe_encode_transform(transform);
|
||||||
self.linewidth(style.width);
|
self.linewidth(style.width);
|
||||||
let elements = elements.into_iter();
|
let elements = elements.into_iter();
|
||||||
if self.encode_path(elements, false) {
|
if self.encode_path(elements, false) {
|
||||||
if let Some(brush_transform) = brush_transform {
|
if let Some(brush_transform) = brush_transform {
|
||||||
if let Some(last_transform) = self.scene.transform_stream.last().copied() {
|
self.encode_transform(transform * brush_transform);
|
||||||
self.encode_transform(brush_transform * last_transform);
|
|
||||||
self.swap_last_tags();
|
self.swap_last_tags();
|
||||||
self.encode_brush(brush);
|
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 {
|
} else {
|
||||||
self.encode_brush(brush);
|
self.encode_brush(brush);
|
||||||
}
|
}
|
||||||
|
@ -147,20 +129,7 @@ impl<'a> SceneBuilder<'a> {
|
||||||
|
|
||||||
/// Appends a fragment to the scene.
|
/// Appends a fragment to the scene.
|
||||||
pub fn append(&mut self, fragment: &SceneFragment, transform: Option<Affine>) {
|
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);
|
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.
|
/// Completes construction and finalizes the underlying scene.
|
||||||
|
@ -218,6 +187,12 @@ impl<'a> SceneBuilder<'a> {
|
||||||
has_els
|
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) {
|
fn encode_transform(&mut self, transform: Affine) {
|
||||||
self.scene.tag_stream.push(0x20);
|
self.scene.tag_stream.push(0x20);
|
||||||
self.scene.transform_stream.push(transform);
|
self.scene.transform_stream.push(transform);
|
||||||
|
|
Loading…
Reference in a new issue