update for improved kurbo/peniko ergonomics

also removes some annoying lingering tabs from blend.wgsl
This commit is contained in:
Chad Brokaw 2022-11-23 12:50:28 -05:00
parent c1e91cb233
commit fc1a6e9e4e
6 changed files with 68 additions and 59 deletions

9
Cargo.lock generated
View file

@ -710,8 +710,9 @@ dependencies = [
[[package]] [[package]]
name = "kurbo" name = "kurbo"
version = "0.8.3" version = "0.9.0"
source = "git+https://github.com/linebender/kurbo#79e5787a57f12d4965fcea01ab9442ecf6795775" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e119590a03caff1f7a582e8ee8c2164ddcc975791701188132fd1d1b518d3871"
dependencies = [ dependencies = [
"arrayvec 0.7.2", "arrayvec 0.7.2",
] ]
@ -1070,9 +1071,9 @@ dependencies = [
[[package]] [[package]]
name = "peniko" name = "peniko"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/linebender/peniko?rev=aca2934#aca29349e7dcbd31f598172953ea88b5ddcd86df" source = "git+https://github.com/linebender/peniko#b83821720aa51a3942be5d20c71525a1ae61ac0a"
dependencies = [ dependencies = [
"kurbo 0.8.3", "kurbo 0.9.0",
"smallvec", "smallvec",
] ]

View file

@ -1,45 +1,45 @@
use crate::PicoSvg; use crate::PicoSvg;
use piet_scene::kurbo::{Affine, BezPath, Ellipse, PathEl, Point, Rect}; use piet_scene::kurbo::{Affine, Ellipse, PathEl, Point, Rect};
use piet_scene::*; use piet_scene::*;
use crate::SimpleText; use crate::SimpleText;
pub fn render_funky_paths(sb: &mut SceneBuilder) { pub fn render_funky_paths(sb: &mut SceneBuilder) {
use PathEl::*; use PathEl::*;
let missing_movetos = &[ let missing_movetos = [
LineTo((100.0, 100.0).into()), LineTo((100.0, 100.0).into()),
LineTo((100.0, 200.0).into()), LineTo((100.0, 200.0).into()),
ClosePath, ClosePath,
LineTo((0.0, 400.0).into()), LineTo((0.0, 400.0).into()),
LineTo((100.0, 400.0).into()), LineTo((100.0, 400.0).into()),
][..]; ];
let only_movetos = &[MoveTo((0.0, 0.0).into()), MoveTo((100.0, 100.0).into())][..]; let only_movetos = [MoveTo((0.0, 0.0).into()), MoveTo((100.0, 100.0).into())];
let empty: &[PathEl] = &[]; let empty: [PathEl; 0] = [];
sb.fill( sb.fill(
Fill::NonZero, Fill::NonZero,
Affine::translate((100.0, 100.0)), Affine::translate((100.0, 100.0)),
&Color::rgb8(0, 0, 255).into(), Color::rgb8(0, 0, 255),
None, None,
&missing_movetos, &missing_movetos,
); );
sb.fill( sb.fill(
Fill::NonZero, Fill::NonZero,
Affine::IDENTITY, Affine::IDENTITY,
&Color::rgb8(0, 0, 255).into(), Color::rgb8(0, 0, 255),
None, None,
&empty, &empty,
); );
sb.fill( sb.fill(
Fill::NonZero, Fill::NonZero,
Affine::IDENTITY, Affine::IDENTITY,
&Color::rgb8(0, 0, 255).into(), Color::rgb8(0, 0, 255),
None, None,
&only_movetos, &only_movetos,
); );
sb.stroke( sb.stroke(
&Stroke::new(8.0), &Stroke::new(8.0),
Affine::translate((100.0, 100.0)), Affine::translate((100.0, 100.0)),
&Color::rgb8(0, 255, 255).into(), Color::rgb8(0, 255, 255),
None, None,
&missing_movetos, &missing_movetos,
); );
@ -58,7 +58,7 @@ pub fn render_svg(sb: &mut SceneBuilder, svg: &PicoSvg, print_stats: bool) {
sb.fill( sb.fill(
Fill::NonZero, Fill::NonZero,
Affine::IDENTITY, Affine::IDENTITY,
&fill.color.into(), fill.color,
None, None,
&fill.path, &fill.path,
); );
@ -67,7 +67,7 @@ pub fn render_svg(sb: &mut SceneBuilder, svg: &PicoSvg, print_stats: bool) {
sb.stroke( sb.stroke(
&Stroke::new(stroke.width as f32), &Stroke::new(stroke.width as f32),
Affine::IDENTITY, Affine::IDENTITY,
&stroke.color.into(), stroke.color,
None, None,
&stroke.path, &stroke.path,
); );
@ -120,7 +120,7 @@ fn render_cardioid(sb: &mut SceneBuilder) {
sb.stroke( sb.stroke(
&Stroke::new(2.0), &Stroke::new(2.0),
Affine::IDENTITY, Affine::IDENTITY,
&Brush::Solid(Color::rgb8(0, 0, 0)), Color::rgb8(0, 0, 0),
None, None,
&&path[..], &&path[..],
); );
@ -138,15 +138,15 @@ fn render_clip_test(sb: &mut SceneBuilder) {
let step = 1.0 / ((N + 1) as f64); let step = 1.0 / ((N + 1) as f64);
for i in 0..N { for i in 0..N {
let t = ((i + 1) as f64) * step; let t = ((i + 1) as f64) * step;
let path = &[ let path = [
PathEl::MoveTo((X0, Y0).into()), PathEl::MoveTo((X0, Y0).into()),
PathEl::LineTo((X1, Y0).into()), PathEl::LineTo((X1, Y0).into()),
PathEl::LineTo((X1, Y0 + t * (Y1 - Y0)).into()), PathEl::LineTo((X1, Y0 + t * (Y1 - Y0)).into()),
PathEl::LineTo((X1 + t * (X0 - X1), Y1).into()), PathEl::LineTo((X1 + t * (X0 - X1), Y1).into()),
PathEl::LineTo((X0, Y1).into()), PathEl::LineTo((X0, Y1).into()),
PathEl::ClosePath, PathEl::ClosePath,
][..]; ];
sb.push_layer(Mix::Clip.into(), Affine::IDENTITY, &path); sb.push_layer(Mix::Clip, Affine::IDENTITY, &path);
} }
let rect = Rect::new(X0, Y0, X1, Y1); let rect = Rect::new(X0, Y0, X1, Y1);
sb.fill( sb.fill(
@ -167,26 +167,26 @@ fn render_alpha_test(sb: &mut SceneBuilder) {
sb.fill( sb.fill(
Fill::NonZero, Fill::NonZero,
Affine::IDENTITY, Affine::IDENTITY,
&Color::rgb8(255, 0, 0).into(), Color::rgb8(255, 0, 0),
None, None,
&&make_diamond(1024.0, 100.0)[..], &&make_diamond(1024.0, 100.0)[..],
); );
sb.fill( sb.fill(
Fill::NonZero, Fill::NonZero,
Affine::IDENTITY, Affine::IDENTITY,
&Color::rgba8(0, 255, 0, 0x80).into(), Color::rgba8(0, 255, 0, 0x80),
None, None,
&&make_diamond(1024.0, 125.0)[..], &&make_diamond(1024.0, 125.0)[..],
); );
sb.push_layer( sb.push_layer(
Mix::Clip.into(), Mix::Clip,
Affine::IDENTITY, Affine::IDENTITY,
&&make_diamond(1024.0, 150.0)[..], &&make_diamond(1024.0, 150.0)[..],
); );
sb.fill( sb.fill(
Fill::NonZero, Fill::NonZero,
Affine::IDENTITY, Affine::IDENTITY,
&Color::rgba8(0, 0, 255, 0x80).into(), Color::rgba8(0, 0, 255, 0x80),
None, None,
&&make_diamond(1024.0, 175.0)[..], &&make_diamond(1024.0, 175.0)[..],
); );
@ -227,7 +227,7 @@ fn render_blend_square(sb: &mut SceneBuilder, blend: BlendMode, transform: Affin
// 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
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 linear = LinearGradient::new((0.0, 0.0), (200.0, 0.0)).stops([Color::BLACK, Color::WHITE]); let linear = LinearGradient::new((0.0, 0.0), (200.0, 0.0)).stops([Color::BLACK, Color::WHITE]);
sb.fill(Fill::NonZero, transform, &linear.into(), None, &rect); sb.fill(Fill::NonZero, transform, &linear, None, &rect);
const GRADIENTS: &[(f64, f64, Color)] = &[ const GRADIENTS: &[(f64, f64, Color)] = &[
(150., 0., Color::rgb8(255, 240, 64)), (150., 0., Color::rgb8(255, 240, 64)),
(175., 100., Color::rgb8(255, 96, 240)), (175., 100., Color::rgb8(255, 96, 240)),
@ -237,14 +237,14 @@ fn render_blend_square(sb: &mut SceneBuilder, blend: BlendMode, transform: Affin
let mut color2 = c.clone(); let mut color2 = c.clone();
color2.a = 0; color2.a = 0;
let radial = RadialGradient::new((*x, *y), 100.0).stops([*c, color2]); let radial = RadialGradient::new((*x, *y), 100.0).stops([*c, color2]);
sb.fill(Fill::NonZero, transform, &radial.into(), None, &rect); sb.fill(Fill::NonZero, transform, &radial, None, &rect);
} }
const COLORS: &[Color] = &[ const COLORS: &[Color] = &[
Color::rgb8(255, 0, 0), Color::rgb8(255, 0, 0),
Color::rgb8(0, 255, 0), Color::rgb8(0, 255, 0),
Color::rgb8(0, 0, 255), Color::rgb8(0, 0, 255),
]; ];
sb.push_layer(Mix::Normal.into(), transform, &rect); sb.push_layer(Mix::Normal, transform, &rect);
for (i, c) in COLORS.iter().enumerate() { for (i, c) in COLORS.iter().enumerate() {
let linear = LinearGradient::new((0.0, 0.0), (0.0, 200.0)).stops([Color::WHITE, *c]); let linear = LinearGradient::new((0.0, 0.0), (0.0, 200.0)).stops([Color::WHITE, *c]);
sb.push_layer(blend, transform, &rect); sb.push_layer(blend, transform, &rect);
@ -257,7 +257,7 @@ fn render_blend_square(sb: &mut SceneBuilder, blend: BlendMode, transform: Affin
sb.fill( sb.fill(
Fill::NonZero, Fill::NonZero,
a, a,
&linear.into(), &linear,
None, None,
&Ellipse::new((100., 100.), (90., 90.), 0.), &Ellipse::new((100., 100.), (90., 90.), 0.),
); );
@ -319,9 +319,11 @@ pub fn render_anim_frame(sb: &mut SceneBuilder, text: &mut SimpleText, i: usize)
#[allow(unused)] #[allow(unused)]
pub fn render_brush_transform(sb: &mut SceneBuilder, i: usize) { pub fn render_brush_transform(sb: &mut SceneBuilder, i: usize) {
let th = (std::f64::consts::PI / 180.0) * (i as f64); let th = (std::f64::consts::PI / 180.0) * (i as f64);
let linear = LinearGradient::new((0.0, 0.0), (0.0, 200.0)) let linear = LinearGradient::new((0.0, 0.0), (0.0, 200.0)).stops([
.stops([Color::RED, Color::GREEN, Color::BLUE]) Color::RED,
.into(); Color::GREEN,
Color::BLUE,
]);
sb.fill( sb.fill(
Fill::NonZero, Fill::NonZero,
Affine::translate((200.0, 200.0)), Affine::translate((200.0, 200.0)),

View file

@ -20,7 +20,7 @@ pub use moscato::pinot;
use crate::scene::{SceneBuilder, SceneFragment}; use crate::scene::{SceneBuilder, SceneFragment};
use peniko::kurbo::{Affine, Rect}; use peniko::kurbo::{Affine, Rect};
use peniko::{Brush, Color, Fill}; use peniko::{Brush, Color, Fill, Mix};
use moscato::{Context, Scaler}; use moscato::{Context, Scaler};
use pinot::{types::Tag, FontRef}; use pinot::{types::Tag, FontRef};
@ -123,13 +123,13 @@ impl<'a> GlyphProvider<'a> {
let path = glyph.path(*path_index)?; let path = glyph.path(*path_index)?;
if let Some(xform) = xform_stack.last() { if let Some(xform) = xform_stack.last() {
builder.push_layer( builder.push_layer(
Default::default(), Mix::Clip,
Affine::IDENTITY, Affine::IDENTITY,
&convert_transformed_path(path.elements(), xform), &convert_transformed_path(path.elements(), xform),
); );
} else { } else {
builder.push_layer( builder.push_layer(
Default::default(), Mix::Clip,
Affine::IDENTITY, Affine::IDENTITY,
&convert_path(path.elements()), &convert_path(path.elements()),
); );
@ -144,7 +144,7 @@ impl<'a> GlyphProvider<'a> {
max = *xform * max; max = *xform * max;
} }
let rect = Rect::from_points(min, max); let rect = Rect::from_points(min, max);
builder.push_layer(Default::default(), Affine::IDENTITY, &rect); builder.push_layer(Mix::Normal, Affine::IDENTITY, &rect);
} }
Command::PopLayer => builder.pop_layer(), Command::PopLayer => builder.pop_layer(),
Command::BeginBlend(bounds, mode) => { Command::BeginBlend(bounds, mode) => {
@ -212,7 +212,7 @@ fn convert_transformed_path(
fn convert_blend(mode: moscato::CompositeMode) -> peniko::BlendMode { fn convert_blend(mode: moscato::CompositeMode) -> peniko::BlendMode {
use moscato::CompositeMode; use moscato::CompositeMode;
use peniko::{BlendMode, Compose, Mix}; use peniko::{BlendMode, Compose};
let mut mix = Mix::Normal; let mut mix = Mix::Normal;
let mut compose = Compose::SrcOver; let mut compose = Compose::SrcOver;
match mode { match mode {

View file

@ -18,7 +18,7 @@ use super::{conv, Scene, SceneData, SceneFragment};
use crate::ResourcePatch; use crate::ResourcePatch;
use bytemuck::{Pod, Zeroable}; use bytemuck::{Pod, Zeroable};
use peniko::kurbo::{Affine, PathEl, Shape}; use peniko::kurbo::{Affine, PathEl, Shape};
use peniko::{BlendMode, Brush, ColorStop, Fill, Stroke}; use peniko::{BlendMode, BrushRef, ColorStop, Fill, Stroke};
use smallvec::SmallVec; use smallvec::SmallVec;
/// Builder for constructing a scene or scene fragment. /// Builder for constructing a scene or scene fragment.
@ -51,7 +51,13 @@ impl<'a> SceneBuilder<'a> {
/// 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(&mut self, blend: BlendMode, transform: Affine, shape: &impl Shape) { pub fn push_layer(
&mut self,
blend: impl Into<BlendMode>,
transform: Affine,
shape: &impl Shape,
) {
let blend = blend.into();
self.maybe_encode_transform(transform); self.maybe_encode_transform(transform);
self.linewidth(-1.0); self.linewidth(-1.0);
if self.encode_path(shape, true) { if self.encode_path(shape, true) {
@ -75,11 +81,11 @@ impl<'a> SceneBuilder<'a> {
} }
/// Fills a shape using the specified style and brush. /// Fills a shape using the specified style and brush.
pub fn fill( pub fn fill<'b>(
&mut self, &mut self,
_style: Fill, _style: Fill,
transform: Affine, transform: Affine,
brush: &Brush, brush: impl Into<BrushRef<'b>>,
brush_transform: Option<Affine>, brush_transform: Option<Affine>,
shape: &impl Shape, shape: &impl Shape,
) { ) {
@ -97,11 +103,11 @@ impl<'a> SceneBuilder<'a> {
} }
/// Strokes a shape using the specified style and brush. /// Strokes a shape using the specified style and brush.
pub fn stroke( pub fn stroke<'b>(
&mut self, &mut self,
style: &Stroke, style: &Stroke,
transform: Affine, transform: Affine,
brush: &Brush, brush: impl Into<BrushRef<'b>>,
brush_transform: Option<Affine>, brush_transform: Option<Affine>,
shape: &impl Shape, shape: &impl Shape,
) { ) {
@ -194,16 +200,16 @@ impl<'a> SceneBuilder<'a> {
} }
} }
fn encode_brush(&mut self, brush: &Brush) { fn encode_brush<'b>(&mut self, brush: impl Into<BrushRef<'b>>) {
match brush { match brush.into() {
Brush::Solid(color) => { BrushRef::Solid(color) => {
self.scene.drawtag_stream.push(DRAWTAG_FILLCOLOR); self.scene.drawtag_stream.push(DRAWTAG_FILLCOLOR);
let rgba_color = color.to_premul_u32(); let rgba_color = color.to_premul_u32();
self.scene self.scene
.drawdata_stream .drawdata_stream
.extend(bytemuck::bytes_of(&FillColor { rgba_color })); .extend(bytemuck::bytes_of(&FillColor { rgba_color }));
} }
Brush::LinearGradient(gradient) => { BrushRef::LinearGradient(gradient) => {
let index = self.add_ramp(&gradient.stops); let index = self.add_ramp(&gradient.stops);
self.scene.drawtag_stream.push(DRAWTAG_FILLLINGRADIENT); self.scene.drawtag_stream.push(DRAWTAG_FILLLINGRADIENT);
self.scene self.scene
@ -214,7 +220,7 @@ impl<'a> SceneBuilder<'a> {
p1: conv::point_to_f32(gradient.end), p1: conv::point_to_f32(gradient.end),
})); }));
} }
Brush::RadialGradient(gradient) => { BrushRef::RadialGradient(gradient) => {
let index = self.add_ramp(&gradient.stops); let index = self.add_ramp(&gradient.stops);
self.scene.drawtag_stream.push(DRAWTAG_FILLRADGRADIENT); self.scene.drawtag_stream.push(DRAWTAG_FILLRADGRADIENT);
self.scene self.scene
@ -227,7 +233,7 @@ impl<'a> SceneBuilder<'a> {
r1: gradient.end_radius, r1: gradient.end_radius,
})); }));
} }
Brush::SweepGradient(_gradient) => todo!("sweep gradients aren't done yet!"), BrushRef::SweepGradient(_gradient) => todo!("sweep gradients aren't done yet!"),
} }
} }

View file

@ -28,13 +28,13 @@ pub fn gen_test_scene() -> Scene {
let scene_ix = 1; let scene_ix = 1;
match scene_ix { match scene_ix {
0 => { 0 => {
let path = &[ let path = [
PathEl::MoveTo(Point::new(100.0, 100.0)), PathEl::MoveTo(Point::new(100.0, 100.0)),
PathEl::LineTo(Point::new(500.0, 120.0)), PathEl::LineTo(Point::new(500.0, 120.0)),
PathEl::LineTo(Point::new(300.0, 150.0)), PathEl::LineTo(Point::new(300.0, 150.0)),
PathEl::LineTo(Point::new(200.0, 260.0)), PathEl::LineTo(Point::new(200.0, 260.0)),
PathEl::LineTo(Point::new(150.0, 210.0)), PathEl::LineTo(Point::new(150.0, 210.0)),
][..]; ];
let brush = Brush::Solid(Color::rgb8(0x40, 0x40, 0xff)); let brush = Brush::Solid(Color::rgb8(0x40, 0x40, 0xff));
builder.fill(Fill::NonZero, Affine::IDENTITY, &brush, None, &path); builder.fill(Fill::NonZero, Affine::IDENTITY, &brush, None, &path);
let transform = Affine::translate((50.0, 50.0)); let transform = Affine::translate((50.0, 50.0));
@ -79,7 +79,7 @@ pub fn render_svg(sb: &mut SceneBuilder, svg: &PicoSvg, print_stats: bool) {
sb.fill( sb.fill(
Fill::NonZero, Fill::NonZero,
Affine::IDENTITY, Affine::IDENTITY,
&fill.color.into(), fill.color,
None, None,
&fill.path, &fill.path,
); );
@ -88,7 +88,7 @@ pub fn render_svg(sb: &mut SceneBuilder, svg: &PicoSvg, print_stats: bool) {
sb.stroke( sb.stroke(
&Stroke::new(stroke.width as f32), &Stroke::new(stroke.width as f32),
Affine::IDENTITY, Affine::IDENTITY,
&stroke.color.into(), stroke.color,
None, None,
&stroke.path, &stroke.path,
); );
@ -134,7 +134,7 @@ fn render_blend_square(sb: &mut SceneBuilder, blend: BlendMode, transform: Affin
// 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
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 linear = LinearGradient::new((0.0, 0.0), (200.0, 0.0)).stops([Color::BLACK, Color::WHITE]); let linear = LinearGradient::new((0.0, 0.0), (200.0, 0.0)).stops([Color::BLACK, Color::WHITE]);
sb.fill(Fill::NonZero, transform, &linear.into(), None, &rect); sb.fill(Fill::NonZero, transform, &linear, None, &rect);
const GRADIENTS: &[(f64, f64, Color)] = &[ const GRADIENTS: &[(f64, f64, Color)] = &[
(150., 0., Color::rgb8(255, 240, 64)), (150., 0., Color::rgb8(255, 240, 64)),
(175., 100., Color::rgb8(255, 96, 240)), (175., 100., Color::rgb8(255, 96, 240)),
@ -144,14 +144,14 @@ fn render_blend_square(sb: &mut SceneBuilder, blend: BlendMode, transform: Affin
let mut color2 = c.clone(); let mut color2 = c.clone();
color2.a = 0; color2.a = 0;
let radial = RadialGradient::new((*x, *y), 100.0).stops([*c, color2]); let radial = RadialGradient::new((*x, *y), 100.0).stops([*c, color2]);
sb.fill(Fill::NonZero, transform, &radial.into(), None, &rect); sb.fill(Fill::NonZero, transform, &radial, None, &rect);
} }
const COLORS: &[Color] = &[ const COLORS: &[Color] = &[
Color::rgb8(255, 0, 0), Color::rgb8(255, 0, 0),
Color::rgb8(0, 255, 0), Color::rgb8(0, 255, 0),
Color::rgb8(0, 0, 255), Color::rgb8(0, 0, 255),
]; ];
sb.push_layer(Mix::Normal.into(), transform, &rect); sb.push_layer(Mix::Normal, transform, &rect);
for (i, c) in COLORS.iter().enumerate() { for (i, c) in COLORS.iter().enumerate() {
let linear = LinearGradient::new((0.0, 0.0), (0.0, 200.0)).stops([Color::WHITE, *c]); let linear = LinearGradient::new((0.0, 0.0), (0.0, 200.0)).stops([Color::WHITE, *c]);
sb.push_layer(blend, transform, &rect); sb.push_layer(blend, transform, &rect);
@ -164,7 +164,7 @@ fn render_blend_square(sb: &mut SceneBuilder, blend: BlendMode, transform: Affin
sb.fill( sb.fill(
Fill::NonZero, Fill::NonZero,
a, a,
&linear.into(), &linear,
None, None,
&Ellipse::new((100., 100.), (90., 90.), 0.), &Ellipse::new((100., 100.), (90., 90.), 0.),
); );