Add support for stroking paths

This will make it easier to visualize the path for layouts.
This commit is contained in:
Simon Hausmann 2020-07-09 09:36:16 +02:00
parent dfe95a2f6d
commit f45ff6ce79
6 changed files with 101 additions and 8 deletions

View file

@ -75,6 +75,8 @@ fn main() {
y: 300.,
elements: PathElements::StaticElements(TRIANGLE_PATH.into()),
fill_color: Color::from_rgb(0, 128, 255),
stroke_color: Color::BLACK,
stroke_width: 2.0,
});
render_cache.allocate_entry(path_primitive)
};

View file

@ -279,6 +279,8 @@ impl TypeRegister {
path.properties.insert("x".to_owned(), Type::Float32);
path.properties.insert("y".to_owned(), Type::Float32);
path.properties.insert("fill_color".to_owned(), Type::Color);
path.properties.insert("stroke_color".to_owned(), Type::Color);
path.properties.insert("stroke_width".to_owned(), Type::Float32);
path.disallow_global_types_as_child_elements = true;
let path_elements = {

View file

@ -207,6 +207,8 @@ impl Color {
pub const BLACK: Color = Color::from_rgb(0, 0, 0);
/// A constant for the white color
pub const WHITE: Color = Color::from_rgb(255, 255, 255);
/// A constant for the transparent color
pub const TRANSPARENT: Color = Color::from_rgba(0, 0, 0, 0);
}
impl From<u32> for Color {
@ -428,6 +430,8 @@ pub enum RenderingPrimitive {
y: f32,
elements: crate::PathElements,
fill_color: Color,
stroke_color: Color,
stroke_width: f32,
},
}

View file

@ -270,6 +270,8 @@ pub struct Path {
pub y: Property<f32>,
pub elements: Property<PathElements>,
pub fill_color: Property<Color>,
pub stroke_color: Property<Color>,
pub stroke_width: Property<f32>,
pub cached_rendering_data: CachedRenderingData,
}
@ -291,6 +293,8 @@ impl Item for Path {
y: Self::field_offsets().y.apply_pin(self).get(context),
elements: Self::field_offsets().elements.apply_pin(self).get(context),
fill_color: Self::field_offsets().fill_color.apply_pin(self).get(context),
stroke_color: Self::field_offsets().stroke_color.apply_pin(self).get(context),
stroke_width: Self::field_offsets().stroke_width.apply_pin(self).get(context),
}
}

View file

@ -3,7 +3,10 @@ use glow::{Context as GLContext, HasContext};
#[cfg(not(target_arch = "wasm32"))]
use itertools::Itertools;
use lyon::tessellation::geometry_builder::{BuffersBuilder, VertexBuffers};
use lyon::tessellation::{FillAttributes, FillOptions, FillTessellator};
use lyon::tessellation::{
FillAttributes, FillOptions, FillTessellator, StrokeAttributes, StrokeOptions,
StrokeTessellator,
};
use sixtyfps_corelib::abi::datastructures::{
Color, ComponentWindow, ComponentWindowOpaque, Point, Rect, RenderingPrimitive, Resource, Size,
};
@ -111,6 +114,7 @@ pub struct GLRenderer {
pub struct GLRenderingPrimitivesBuilder {
context: Rc<glow::Context>,
fill_tesselator: FillTessellator,
stroke_tesselator: StrokeTessellator,
texture_atlas: Rc<RefCell<TextureAtlas>>,
#[cfg(not(target_arch = "wasm32"))]
platform_data: Rc<RefCell<PlatformData>>,
@ -226,6 +230,7 @@ impl GraphicsBackend for GLRenderer {
GLRenderingPrimitivesBuilder {
context: self.context.clone(),
fill_tesselator: FillTessellator::new(),
stroke_tesselator: StrokeTessellator::new(),
texture_atlas: self.texture_atlas.clone(),
#[cfg(not(target_arch = "wasm32"))]
platform_data: self.platform_data.clone(),
@ -306,7 +311,9 @@ impl RenderingPrimitivesBuilder for GLRenderingPrimitivesBuilder {
rect_path.line_to(Point::new(*width, *height));
rect_path.line_to(Point::new(0.0, *height));
rect_path.close();
self.create_path(&rect_path.build(), FillStyle::SolidColor(*color))
self.fill_path(&rect_path.build(), FillStyle::SolidColor(*color))
.into_iter()
.collect()
}
RenderingPrimitive::Image { x: _, y: _, source } => {
match source {
@ -337,8 +344,39 @@ impl RenderingPrimitivesBuilder for GLRenderingPrimitivesBuilder {
if *font_pixel_size != 0. { *font_pixel_size } else { 48.0 * 72. / 96. };
smallvec![self.create_glyph_runs(text, font_family, pixel_size, *color)]
}
RenderingPrimitive::Path { x: _, y: _, elements, fill_color } => self
.create_path(elements.build_path().iter(), FillStyle::SolidColor(*fill_color)),
RenderingPrimitive::Path {
x: _,
y: _,
elements,
fill_color,
stroke_color,
stroke_width,
} => {
let mut primitives = SmallVec::new();
if *fill_color != Color::TRANSPARENT {
primitives.extend(
self.fill_path(
elements.build_path().iter(),
FillStyle::SolidColor(*fill_color),
)
.into_iter(),
);
}
if *stroke_color != Color::TRANSPARENT {
primitives.extend(
self.stroke_path(
elements.build_path().iter(),
*stroke_color,
*stroke_width,
)
.into_iter(),
);
}
primitives
}
},
rendering_primitive: primitive,
}
@ -346,11 +384,11 @@ impl RenderingPrimitivesBuilder for GLRenderingPrimitivesBuilder {
}
impl GLRenderingPrimitivesBuilder {
fn create_path(
fn fill_path(
&mut self,
path: impl IntoIterator<Item = lyon::path::PathEvent>,
style: FillStyle,
) -> GLRenderingPrimitives {
) -> Option<GLRenderingPrimitive> {
let mut geometry: VertexBuffers<Vertex, u16> = VertexBuffers::new();
let fill_opts = FillOptions::default();
@ -368,13 +406,53 @@ impl GLRenderingPrimitivesBuilder {
.unwrap();
if geometry.vertices.len() == 0 || geometry.indices.len() == 0 {
return SmallVec::new();
return None;
}
let vertices = GLArrayBuffer::new(&self.context, &geometry.vertices);
let indices = GLIndexBuffer::new(&self.context, &geometry.indices);
smallvec![GLRenderingPrimitive::FillPath { vertices, indices, style }.into()]
Some(GLRenderingPrimitive::FillPath { vertices, indices, style }.into())
}
fn stroke_path(
&mut self,
path: impl IntoIterator<Item = lyon::path::PathEvent>,
stroke_color: Color,
stroke_width: f32,
) -> Option<GLRenderingPrimitive> {
let mut geometry: VertexBuffers<Vertex, u16> = VertexBuffers::new();
let stroke_opts = StrokeOptions::DEFAULT.with_line_width(stroke_width);
self.stroke_tesselator
.tessellate(
path,
&stroke_opts,
&mut BuffersBuilder::new(
&mut geometry,
|pos: lyon::math::Point, _: StrokeAttributes| Vertex {
_pos: [pos.x as f32, pos.y as f32],
},
),
)
.unwrap();
if geometry.vertices.len() == 0 || geometry.indices.len() == 0 {
return None;
}
let vertices = GLArrayBuffer::new(&self.context, &geometry.vertices);
let indices = GLIndexBuffer::new(&self.context, &geometry.indices);
Some(
GLRenderingPrimitive::FillPath {
vertices,
indices,
style: FillStyle::SolidColor(stroke_color),
}
.into(),
)
}
fn create_image(

View file

@ -106,6 +106,9 @@ Hello := Rectangle {
x: 100;
y: 300;
fill_color: green;
stroke_color: black;
stroke_width: 2.0;
LineTo {
x: 100;
y: 50;