2022-10-25 08:53:12 +11:00
|
|
|
// Copyright 2022 Google LLC
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// https://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
//
|
|
|
|
// Also licensed under MIT license, at your choice.
|
|
|
|
|
2022-11-23 06:49:51 +11:00
|
|
|
use piet_scene::kurbo::{Affine, Ellipse, PathEl, Point, Rect};
|
2022-11-17 04:02:11 +11:00
|
|
|
use piet_scene::{
|
2022-11-23 06:49:51 +11:00
|
|
|
BlendMode, Brush, Color, Fill, LinearGradient, Mix, RadialGradient, Scene, SceneBuilder,
|
|
|
|
SceneFragment, Stroke,
|
2022-11-17 04:02:11 +11:00
|
|
|
};
|
2022-10-25 08:53:12 +11:00
|
|
|
|
2022-11-05 07:15:05 +11:00
|
|
|
use crate::pico_svg::PicoSvg;
|
|
|
|
|
2022-10-25 08:53:12 +11:00
|
|
|
pub fn gen_test_scene() -> Scene {
|
|
|
|
let mut scene = Scene::default();
|
|
|
|
let mut builder = SceneBuilder::for_scene(&mut scene);
|
2022-11-17 02:49:38 +11:00
|
|
|
let scene_ix = 1;
|
|
|
|
match scene_ix {
|
|
|
|
0 => {
|
2022-11-23 06:49:51 +11:00
|
|
|
let path = &[
|
|
|
|
PathEl::MoveTo(Point::new(100.0, 100.0)),
|
|
|
|
PathEl::LineTo(Point::new(500.0, 120.0)),
|
|
|
|
PathEl::LineTo(Point::new(300.0, 150.0)),
|
|
|
|
PathEl::LineTo(Point::new(200.0, 260.0)),
|
|
|
|
PathEl::LineTo(Point::new(150.0, 210.0)),
|
|
|
|
][..];
|
2022-11-17 02:49:38 +11:00
|
|
|
let brush = Brush::Solid(Color::rgb8(0x40, 0x40, 0xff));
|
|
|
|
builder.fill(Fill::NonZero, Affine::IDENTITY, &brush, None, &path);
|
2022-11-23 06:49:51 +11:00
|
|
|
let transform = Affine::translate((50.0, 50.0));
|
2022-11-17 02:49:38 +11:00
|
|
|
let brush = Brush::Solid(Color::rgba8(0xff, 0xff, 0x00, 0x80));
|
|
|
|
builder.fill(Fill::NonZero, transform, &brush, None, &path);
|
2022-11-23 06:49:51 +11:00
|
|
|
let transform = Affine::translate((100.0, 100.0));
|
|
|
|
let style = Stroke::new(1.0);
|
2022-11-17 02:49:38 +11:00
|
|
|
let brush = Brush::Solid(Color::rgb8(0xa0, 0x00, 0x00));
|
|
|
|
builder.stroke(&style, transform, &brush, None, &path);
|
|
|
|
}
|
|
|
|
1 => {
|
2022-11-19 09:26:26 +11:00
|
|
|
render_blend_grid(&mut builder);
|
2022-11-17 02:49:38 +11:00
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
let xml_str =
|
|
|
|
std::str::from_utf8(include_bytes!("../../piet-gpu/Ghostscript_Tiger.svg"))
|
|
|
|
.unwrap();
|
|
|
|
let svg = PicoSvg::load(xml_str, 6.0).unwrap();
|
|
|
|
render_svg(&mut builder, &svg, false);
|
|
|
|
}
|
2022-11-05 07:15:05 +11:00
|
|
|
}
|
2022-11-19 09:26:26 +11:00
|
|
|
builder.finish();
|
2022-10-25 08:53:12 +11:00
|
|
|
scene
|
|
|
|
}
|
|
|
|
|
2022-11-05 15:41:37 +11:00
|
|
|
#[allow(unused)]
|
2022-10-25 08:53:12 +11:00
|
|
|
pub fn dump_scene_info(scene: &Scene) {
|
|
|
|
let data = scene.data();
|
|
|
|
println!("tags {:?}", data.tag_stream);
|
2022-10-25 09:17:51 +11:00
|
|
|
println!(
|
|
|
|
"pathsegs {:?}",
|
|
|
|
bytemuck::cast_slice::<u8, f32>(&data.pathseg_stream)
|
|
|
|
);
|
2022-10-25 08:53:12 +11:00
|
|
|
}
|
2022-11-05 07:15:05 +11:00
|
|
|
|
|
|
|
pub fn render_svg(sb: &mut SceneBuilder, svg: &PicoSvg, print_stats: bool) {
|
|
|
|
use crate::pico_svg::*;
|
|
|
|
let start = std::time::Instant::now();
|
|
|
|
for item in svg.items.iter() {
|
|
|
|
match item {
|
|
|
|
Item::Fill(fill) => {
|
|
|
|
sb.fill(
|
|
|
|
Fill::NonZero,
|
|
|
|
Affine::IDENTITY,
|
|
|
|
&fill.color.into(),
|
|
|
|
None,
|
2022-11-23 06:49:51 +11:00
|
|
|
&fill.path,
|
2022-11-05 07:15:05 +11:00
|
|
|
);
|
|
|
|
}
|
|
|
|
Item::Stroke(stroke) => {
|
|
|
|
sb.stroke(
|
2022-11-23 06:49:51 +11:00
|
|
|
&Stroke::new(stroke.width as f32),
|
2022-11-05 07:15:05 +11:00
|
|
|
Affine::IDENTITY,
|
|
|
|
&stroke.color.into(),
|
|
|
|
None,
|
2022-11-23 06:49:51 +11:00
|
|
|
&stroke.path,
|
2022-11-05 07:15:05 +11:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if print_stats {
|
|
|
|
println!("flattening and encoding time: {:?}", start.elapsed());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-19 09:26:26 +11:00
|
|
|
#[allow(unused)]
|
|
|
|
pub fn render_blend_grid(sb: &mut SceneBuilder) {
|
|
|
|
const BLEND_MODES: &[Mix] = &[
|
|
|
|
Mix::Normal,
|
|
|
|
Mix::Multiply,
|
|
|
|
Mix::Darken,
|
|
|
|
Mix::Screen,
|
|
|
|
Mix::Lighten,
|
|
|
|
Mix::Overlay,
|
|
|
|
Mix::ColorDodge,
|
|
|
|
Mix::ColorBurn,
|
|
|
|
Mix::HardLight,
|
|
|
|
Mix::SoftLight,
|
|
|
|
Mix::Difference,
|
|
|
|
Mix::Exclusion,
|
|
|
|
Mix::Hue,
|
|
|
|
Mix::Saturation,
|
|
|
|
Mix::Color,
|
|
|
|
Mix::Luminosity,
|
|
|
|
];
|
|
|
|
for (ix, &blend) in BLEND_MODES.iter().enumerate() {
|
|
|
|
let i = ix % 4;
|
|
|
|
let j = ix / 4;
|
2022-11-23 06:49:51 +11:00
|
|
|
let transform = Affine::translate((i as f64 * 225., j as f64 * 225.));
|
2022-11-19 09:26:26 +11:00
|
|
|
let square = blend_square(blend.into());
|
|
|
|
sb.append(&square, Some(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
|
2022-11-23 06:49:51 +11:00
|
|
|
let rect = Rect::from_origin_size(Point::new(0., 0.), (200., 200.));
|
2022-11-23 07:17:50 +11:00
|
|
|
let linear = LinearGradient::new((0.0, 0.0), (200.0, 0.0)).stops([Color::BLACK, Color::WHITE]);
|
2022-11-23 06:49:51 +11:00
|
|
|
sb.fill(Fill::NonZero, transform, &linear.into(), None, &rect);
|
|
|
|
const GRADIENTS: &[(f64, f64, Color)] = &[
|
2022-11-19 09:26:26 +11:00
|
|
|
(150., 0., Color::rgb8(255, 240, 64)),
|
|
|
|
(175., 100., Color::rgb8(255, 96, 240)),
|
|
|
|
(125., 200., Color::rgb8(64, 192, 255)),
|
|
|
|
];
|
|
|
|
for (x, y, c) in GRADIENTS {
|
|
|
|
let mut color2 = c.clone();
|
|
|
|
color2.a = 0;
|
2022-11-23 07:17:50 +11:00
|
|
|
let radial = RadialGradient::new((*x, *y), 100.0).stops([*c, color2]);
|
2022-11-23 06:49:51 +11:00
|
|
|
sb.fill(Fill::NonZero, transform, &radial.into(), None, &rect);
|
2022-11-19 09:26:26 +11:00
|
|
|
}
|
|
|
|
const COLORS: &[Color] = &[
|
|
|
|
Color::rgb8(255, 0, 0),
|
|
|
|
Color::rgb8(0, 255, 0),
|
|
|
|
Color::rgb8(0, 0, 255),
|
|
|
|
];
|
2022-11-23 06:49:51 +11:00
|
|
|
sb.push_layer(Mix::Normal.into(), transform, &rect);
|
2022-11-19 09:26:26 +11:00
|
|
|
for (i, c) in COLORS.iter().enumerate() {
|
2022-11-23 07:17:50 +11:00
|
|
|
let linear = LinearGradient::new((0.0, 0.0), (0.0, 200.0)).stops([Color::WHITE, *c]);
|
2022-11-23 06:49:51 +11:00
|
|
|
sb.push_layer(blend, transform, &rect);
|
2022-11-19 09:26:26 +11:00
|
|
|
// squash the ellipse
|
|
|
|
let a = transform
|
2022-11-23 06:49:51 +11:00
|
|
|
* Affine::translate((100., 100.))
|
|
|
|
* Affine::rotate(std::f64::consts::FRAC_PI_3 * (i * 2 + 1) as f64)
|
|
|
|
* Affine::scale_non_uniform(1.0, 0.357)
|
|
|
|
* Affine::translate((-100., -100.));
|
2022-11-19 09:26:26 +11:00
|
|
|
sb.fill(
|
|
|
|
Fill::NonZero,
|
|
|
|
a,
|
2022-11-23 06:49:51 +11:00
|
|
|
&linear.into(),
|
2022-11-19 09:26:26 +11:00
|
|
|
None,
|
2022-11-23 06:49:51 +11:00
|
|
|
&Ellipse::new((100., 100.), (90., 90.), 0.),
|
2022-11-19 09:26:26 +11:00
|
|
|
);
|
|
|
|
sb.pop_layer();
|
|
|
|
}
|
|
|
|
sb.pop_layer();
|
|
|
|
}
|
|
|
|
|
|
|
|
#[allow(unused)]
|
|
|
|
fn blend_square(blend: BlendMode) -> SceneFragment {
|
|
|
|
let mut fragment = SceneFragment::default();
|
|
|
|
let mut sb = SceneBuilder::for_fragment(&mut fragment);
|
|
|
|
render_blend_square(&mut sb, blend, Affine::IDENTITY);
|
|
|
|
sb.finish();
|
|
|
|
fragment
|
|
|
|
}
|