2020-11-15 03:22:56 +11:00
|
|
|
use std::{borrow::Cow, ops::RangeBounds};
|
2020-04-23 03:28:38 +10:00
|
|
|
|
2020-06-11 07:10:28 +10:00
|
|
|
use piet_gpu_types::encoder::{Encode, Encoder};
|
2020-05-12 13:01:06 +10:00
|
|
|
|
|
|
|
use piet_gpu_types::scene::{CubicSeg, Element, Fill, LineSeg, QuadSeg, SetLineWidth, Stroke};
|
2020-04-23 03:28:38 +10:00
|
|
|
|
2020-11-15 03:22:56 +11:00
|
|
|
use piet::{
|
|
|
|
kurbo::Size,
|
|
|
|
kurbo::{Affine, PathEl, Point, Rect, Shape},
|
|
|
|
HitTestPosition, TextAttribute, TextStorage,
|
|
|
|
};
|
2020-04-23 03:28:38 +10:00
|
|
|
|
|
|
|
use piet::{
|
2020-11-15 03:22:56 +11:00
|
|
|
Color, Error, FixedGradient, FontFamily, HitTestPoint, ImageFormat, InterpolationMode,
|
|
|
|
IntoBrush, LineMetric, RenderContext, StrokeStyle, Text, TextLayout, TextLayoutBuilder,
|
2020-04-23 03:28:38 +10:00
|
|
|
};
|
|
|
|
|
|
|
|
pub struct PietGpuImage;
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct PietGpuTextLayout;
|
|
|
|
|
|
|
|
pub struct PietGpuTextLayoutBuilder;
|
|
|
|
|
2020-11-15 03:22:56 +11:00
|
|
|
#[derive(Clone)]
|
2020-04-23 03:28:38 +10:00
|
|
|
pub struct PietGpuText;
|
|
|
|
|
|
|
|
pub struct PietGpuRenderContext {
|
|
|
|
encoder: Encoder,
|
2020-05-12 13:01:06 +10:00
|
|
|
elements: Vec<Element>,
|
2020-04-23 03:28:38 +10:00
|
|
|
// Will probably need direct accesss to hal Device to create images etc.
|
|
|
|
inner_text: PietGpuText,
|
2020-05-12 13:01:06 +10:00
|
|
|
stroke_width: f32,
|
2020-06-03 10:10:20 +10:00
|
|
|
// We're tallying these cpu-side for expedience, but will probably
|
|
|
|
// move this to some kind of readback from element processing.
|
|
|
|
path_count: usize,
|
|
|
|
pathseg_count: usize,
|
2020-04-23 03:28:38 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub enum PietGpuBrush {
|
|
|
|
Solid(u32),
|
|
|
|
Gradient,
|
|
|
|
}
|
|
|
|
|
2020-05-03 02:50:36 +10:00
|
|
|
const TOLERANCE: f64 = 0.25;
|
2020-04-25 06:06:47 +10:00
|
|
|
|
2020-04-23 03:28:38 +10:00
|
|
|
impl PietGpuRenderContext {
|
|
|
|
pub fn new() -> PietGpuRenderContext {
|
2020-05-12 13:01:06 +10:00
|
|
|
let encoder = Encoder::new();
|
|
|
|
let elements = Vec::new();
|
2020-04-23 03:28:38 +10:00
|
|
|
let inner_text = PietGpuText;
|
2020-05-12 13:01:06 +10:00
|
|
|
let stroke_width = 0.0;
|
2020-04-23 03:28:38 +10:00
|
|
|
PietGpuRenderContext {
|
|
|
|
encoder,
|
2020-05-12 13:01:06 +10:00
|
|
|
elements,
|
2020-04-23 03:28:38 +10:00
|
|
|
inner_text,
|
2020-05-12 13:01:06 +10:00
|
|
|
stroke_width,
|
2020-06-03 10:10:20 +10:00
|
|
|
path_count: 0,
|
|
|
|
pathseg_count: 0,
|
2020-04-23 03:28:38 +10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_scene_buf(&mut self) -> &[u8] {
|
2020-05-12 13:01:06 +10:00
|
|
|
self.elements.encode(&mut self.encoder);
|
2020-04-23 03:28:38 +10:00
|
|
|
self.encoder.buf()
|
|
|
|
}
|
2020-06-03 10:10:20 +10:00
|
|
|
|
|
|
|
pub fn path_count(&self) -> usize {
|
|
|
|
self.path_count
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn pathseg_count(&self) -> usize {
|
|
|
|
self.pathseg_count
|
|
|
|
}
|
2020-04-23 03:28:38 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
impl RenderContext for PietGpuRenderContext {
|
|
|
|
type Brush = PietGpuBrush;
|
|
|
|
type Image = PietGpuImage;
|
|
|
|
type Text = PietGpuText;
|
|
|
|
type TextLayout = PietGpuTextLayout;
|
|
|
|
|
|
|
|
fn status(&mut self) -> Result<(), Error> {
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn solid_brush(&mut self, color: Color) -> Self::Brush {
|
|
|
|
PietGpuBrush::Solid(color.as_rgba_u32())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn gradient(&mut self, _gradient: impl Into<FixedGradient>) -> Result<Self::Brush, Error> {
|
|
|
|
Ok(Self::Brush::Gradient)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn clear(&mut self, _color: Color) {}
|
|
|
|
|
2020-04-25 06:06:47 +10:00
|
|
|
fn stroke(&mut self, shape: impl Shape, brush: &impl IntoBrush<Self>, width: f64) {
|
2020-05-12 13:01:06 +10:00
|
|
|
let width = width as f32;
|
|
|
|
if self.stroke_width != width {
|
|
|
|
self.elements
|
|
|
|
.push(Element::SetLineWidth(SetLineWidth { width }));
|
|
|
|
self.stroke_width = width;
|
|
|
|
}
|
|
|
|
let brush = brush.make_brush(self, || shape.bounding_box()).into_owned();
|
2020-11-15 03:22:56 +11:00
|
|
|
let path = shape.path_elements(TOLERANCE);
|
2020-05-21 00:38:52 +10:00
|
|
|
self.encode_path(path, false);
|
2020-04-25 06:06:47 +10:00
|
|
|
match brush {
|
|
|
|
PietGpuBrush::Solid(rgba_color) => {
|
2020-05-12 13:01:06 +10:00
|
|
|
let stroke = Stroke { rgba_color };
|
|
|
|
self.elements.push(Element::Stroke(stroke));
|
2020-06-03 10:10:20 +10:00
|
|
|
self.path_count += 1;
|
2020-04-25 06:06:47 +10:00
|
|
|
}
|
|
|
|
_ => (),
|
|
|
|
}
|
|
|
|
}
|
2020-04-23 03:28:38 +10:00
|
|
|
|
|
|
|
fn stroke_styled(
|
|
|
|
&mut self,
|
|
|
|
_shape: impl Shape,
|
|
|
|
_brush: &impl IntoBrush<Self>,
|
|
|
|
_width: f64,
|
|
|
|
_style: &StrokeStyle,
|
|
|
|
) {
|
|
|
|
}
|
|
|
|
|
|
|
|
fn fill(&mut self, shape: impl Shape, brush: &impl IntoBrush<Self>) {
|
2020-04-25 06:06:47 +10:00
|
|
|
let brush = brush.make_brush(self, || shape.bounding_box()).into_owned();
|
2020-11-15 03:22:56 +11:00
|
|
|
let path = shape.path_elements(TOLERANCE);
|
2020-05-21 00:38:52 +10:00
|
|
|
self.encode_path(path, true);
|
2020-05-01 10:06:01 +10:00
|
|
|
match brush {
|
|
|
|
PietGpuBrush::Solid(rgba_color) => {
|
2020-05-12 13:01:06 +10:00
|
|
|
let fill = Fill { rgba_color };
|
|
|
|
self.elements.push(Element::Fill(fill));
|
2020-06-03 10:10:20 +10:00
|
|
|
self.path_count += 1;
|
2020-05-01 10:06:01 +10:00
|
|
|
}
|
|
|
|
_ => (),
|
2020-04-23 03:28:38 +10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn fill_even_odd(&mut self, _shape: impl Shape, _brush: &impl IntoBrush<Self>) {}
|
|
|
|
|
|
|
|
fn clip(&mut self, _shape: impl Shape) {}
|
|
|
|
|
|
|
|
fn text(&mut self) -> &mut Self::Text {
|
|
|
|
&mut self.inner_text
|
|
|
|
}
|
|
|
|
|
2020-11-15 03:22:56 +11:00
|
|
|
fn draw_text(&mut self, _layout: &Self::TextLayout, _pos: impl Into<Point>) {}
|
2020-04-23 03:28:38 +10:00
|
|
|
|
|
|
|
fn save(&mut self) -> Result<(), Error> {
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
fn restore(&mut self) -> Result<(), Error> {
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
fn finish(&mut self) -> Result<(), Error> {
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
fn transform(&mut self, _transform: Affine) {}
|
|
|
|
|
|
|
|
fn make_image(
|
|
|
|
&mut self,
|
|
|
|
_width: usize,
|
|
|
|
_height: usize,
|
|
|
|
_buf: &[u8],
|
|
|
|
_format: ImageFormat,
|
|
|
|
) -> Result<Self::Image, Error> {
|
|
|
|
Ok(PietGpuImage)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn draw_image(
|
|
|
|
&mut self,
|
|
|
|
_image: &Self::Image,
|
|
|
|
_rect: impl Into<Rect>,
|
|
|
|
_interp: InterpolationMode,
|
|
|
|
) {
|
|
|
|
}
|
|
|
|
|
|
|
|
fn draw_image_area(
|
|
|
|
&mut self,
|
|
|
|
_image: &Self::Image,
|
|
|
|
_src_rect: impl Into<Rect>,
|
|
|
|
_dst_rect: impl Into<Rect>,
|
|
|
|
_interp: InterpolationMode,
|
|
|
|
) {
|
|
|
|
}
|
|
|
|
|
|
|
|
fn blurred_rect(&mut self, _rect: Rect, _blur_radius: f64, _brush: &impl IntoBrush<Self>) {}
|
|
|
|
|
|
|
|
fn current_transform(&self) -> Affine {
|
|
|
|
Default::default()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-12 13:01:06 +10:00
|
|
|
impl PietGpuRenderContext {
|
2020-05-21 00:38:52 +10:00
|
|
|
fn encode_line_seg(&mut self, seg: LineSeg, is_fill: bool) {
|
|
|
|
if is_fill {
|
|
|
|
self.elements.push(Element::FillLine(seg));
|
|
|
|
} else {
|
|
|
|
self.elements.push(Element::StrokeLine(seg));
|
|
|
|
}
|
2020-06-03 10:10:20 +10:00
|
|
|
self.pathseg_count += 1;
|
2020-05-21 00:38:52 +10:00
|
|
|
}
|
|
|
|
|
2020-06-10 09:01:47 +10:00
|
|
|
fn encode_quad_seg(&mut self, seg: QuadSeg, is_fill: bool) {
|
|
|
|
if is_fill {
|
|
|
|
self.elements.push(Element::FillQuad(seg));
|
|
|
|
} else {
|
|
|
|
self.elements.push(Element::StrokeQuad(seg));
|
|
|
|
}
|
|
|
|
self.pathseg_count += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn encode_cubic_seg(&mut self, seg: CubicSeg, is_fill: bool) {
|
|
|
|
if is_fill {
|
|
|
|
self.elements.push(Element::FillCubic(seg));
|
|
|
|
} else {
|
|
|
|
self.elements.push(Element::StrokeCubic(seg));
|
|
|
|
}
|
|
|
|
self.pathseg_count += 1;
|
|
|
|
}
|
|
|
|
|
2020-05-21 00:38:52 +10:00
|
|
|
fn encode_path(&mut self, path: impl Iterator<Item = PathEl>, is_fill: bool) {
|
2020-06-10 10:20:58 +10:00
|
|
|
let flatten = false;
|
2020-05-12 13:01:06 +10:00
|
|
|
if flatten {
|
|
|
|
let mut start_pt = None;
|
|
|
|
let mut last_pt = None;
|
|
|
|
piet::kurbo::flatten(path, TOLERANCE, |el| {
|
|
|
|
match el {
|
|
|
|
PathEl::MoveTo(p) => {
|
|
|
|
let scene_pt = to_f32_2(p);
|
2020-05-21 09:36:09 +10:00
|
|
|
start_pt = Some(scene_pt);
|
2020-05-12 13:01:06 +10:00
|
|
|
last_pt = Some(scene_pt);
|
|
|
|
}
|
|
|
|
PathEl::LineTo(p) => {
|
|
|
|
let scene_pt = to_f32_2(p);
|
|
|
|
let seg = LineSeg {
|
|
|
|
p0: last_pt.unwrap(),
|
|
|
|
p1: scene_pt,
|
|
|
|
};
|
2020-05-21 00:38:52 +10:00
|
|
|
self.encode_line_seg(seg, is_fill);
|
2020-05-12 13:01:06 +10:00
|
|
|
last_pt = Some(scene_pt);
|
|
|
|
}
|
|
|
|
PathEl::ClosePath => {
|
|
|
|
if let (Some(start), Some(last)) = (start_pt.take(), last_pt.take()) {
|
2020-05-21 09:36:09 +10:00
|
|
|
if last != start {
|
|
|
|
let seg = LineSeg {
|
|
|
|
p0: last,
|
|
|
|
p1: start,
|
|
|
|
};
|
|
|
|
self.encode_line_seg(seg, is_fill);
|
|
|
|
}
|
2020-05-12 13:01:06 +10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => (),
|
2020-04-25 06:06:47 +10:00
|
|
|
}
|
2020-05-12 13:01:06 +10:00
|
|
|
//println!("{:?}", el);
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
let mut start_pt = None;
|
|
|
|
let mut last_pt = None;
|
|
|
|
for el in path {
|
|
|
|
match el {
|
|
|
|
PathEl::MoveTo(p) => {
|
|
|
|
let scene_pt = to_f32_2(p);
|
2020-05-21 09:36:09 +10:00
|
|
|
start_pt = Some(scene_pt);
|
2020-05-12 13:01:06 +10:00
|
|
|
last_pt = Some(scene_pt);
|
|
|
|
}
|
|
|
|
PathEl::LineTo(p) => {
|
|
|
|
let scene_pt = to_f32_2(p);
|
|
|
|
let seg = LineSeg {
|
|
|
|
p0: last_pt.unwrap(),
|
|
|
|
p1: scene_pt,
|
|
|
|
};
|
2020-05-21 00:38:52 +10:00
|
|
|
self.encode_line_seg(seg, is_fill);
|
2020-05-12 13:01:06 +10:00
|
|
|
last_pt = Some(scene_pt);
|
|
|
|
}
|
|
|
|
PathEl::QuadTo(p1, p2) => {
|
|
|
|
let scene_p1 = to_f32_2(p1);
|
|
|
|
let scene_p2 = to_f32_2(p2);
|
|
|
|
let seg = QuadSeg {
|
|
|
|
p0: last_pt.unwrap(),
|
|
|
|
p1: scene_p1,
|
|
|
|
p2: scene_p2,
|
|
|
|
};
|
2020-06-10 09:01:47 +10:00
|
|
|
self.encode_quad_seg(seg, is_fill);
|
2020-05-12 13:01:06 +10:00
|
|
|
last_pt = Some(scene_p2);
|
|
|
|
}
|
|
|
|
PathEl::CurveTo(p1, p2, p3) => {
|
|
|
|
let scene_p1 = to_f32_2(p1);
|
|
|
|
let scene_p2 = to_f32_2(p2);
|
|
|
|
let scene_p3 = to_f32_2(p3);
|
|
|
|
let seg = CubicSeg {
|
|
|
|
p0: last_pt.unwrap(),
|
|
|
|
p1: scene_p1,
|
|
|
|
p2: scene_p2,
|
|
|
|
p3: scene_p3,
|
|
|
|
};
|
2020-06-10 09:01:47 +10:00
|
|
|
self.encode_cubic_seg(seg, is_fill);
|
2020-05-12 13:01:06 +10:00
|
|
|
last_pt = Some(scene_p3);
|
|
|
|
}
|
|
|
|
PathEl::ClosePath => {
|
|
|
|
if let (Some(start), Some(last)) = (start_pt.take(), last_pt.take()) {
|
2020-05-21 09:36:09 +10:00
|
|
|
if last != start {
|
|
|
|
let seg = LineSeg {
|
|
|
|
p0: last,
|
|
|
|
p1: start,
|
|
|
|
};
|
|
|
|
self.encode_line_seg(seg, is_fill);
|
|
|
|
}
|
2020-05-12 13:01:06 +10:00
|
|
|
}
|
2020-04-25 06:06:47 +10:00
|
|
|
}
|
|
|
|
}
|
2020-05-12 13:01:06 +10:00
|
|
|
//println!("{:?}", el);
|
2020-04-25 06:06:47 +10:00
|
|
|
}
|
|
|
|
}
|
2020-05-12 13:01:06 +10:00
|
|
|
}
|
2020-04-25 06:06:47 +10:00
|
|
|
}
|
|
|
|
|
2020-04-23 03:28:38 +10:00
|
|
|
impl Text for PietGpuText {
|
|
|
|
type TextLayout = PietGpuTextLayout;
|
|
|
|
type TextLayoutBuilder = PietGpuTextLayoutBuilder;
|
|
|
|
|
2020-11-15 03:22:56 +11:00
|
|
|
fn load_font(&mut self, _data: &[u8]) -> Result<FontFamily, Error> {
|
|
|
|
Ok(FontFamily::default())
|
2020-04-23 03:28:38 +10:00
|
|
|
}
|
|
|
|
|
2020-11-15 03:22:56 +11:00
|
|
|
fn new_text_layout(&mut self, _text: impl TextStorage) -> Self::TextLayoutBuilder {
|
|
|
|
PietGpuTextLayoutBuilder
|
2020-04-23 03:28:38 +10:00
|
|
|
}
|
|
|
|
|
2020-11-15 03:22:56 +11:00
|
|
|
fn font_family(&mut self, _family_name: &str) -> Option<FontFamily> {
|
|
|
|
Some(FontFamily::default())
|
2020-04-23 03:28:38 +10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TextLayoutBuilder for PietGpuTextLayoutBuilder {
|
|
|
|
type Out = PietGpuTextLayout;
|
|
|
|
|
2020-11-15 03:22:56 +11:00
|
|
|
fn max_width(self, _width: f64) -> Self {
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
fn alignment(self, _alignment: piet::TextAlignment) -> Self {
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
fn default_attribute(self, _attribute: impl Into<TextAttribute>) -> Self {
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
fn range_attribute(
|
|
|
|
self,
|
|
|
|
_range: impl RangeBounds<usize>,
|
|
|
|
_attribute: impl Into<TextAttribute>,
|
|
|
|
) -> Self {
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2020-04-23 03:28:38 +10:00
|
|
|
fn build(self) -> Result<Self::Out, Error> {
|
2020-11-15 03:22:56 +11:00
|
|
|
Ok(PietGpuTextLayout)
|
2020-04-23 03:28:38 +10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TextLayout for PietGpuTextLayout {
|
2020-11-15 03:22:56 +11:00
|
|
|
fn size(&self) -> Size {
|
|
|
|
Size::ZERO
|
2020-04-23 03:28:38 +10:00
|
|
|
}
|
|
|
|
|
2020-11-15 03:22:56 +11:00
|
|
|
fn image_bounds(&self) -> Rect {
|
|
|
|
Rect::ZERO
|
2020-04-23 03:28:38 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
fn line_text(&self, _line_number: usize) -> Option<&str> {
|
2020-11-15 03:22:56 +11:00
|
|
|
None
|
2020-04-23 03:28:38 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
fn line_metric(&self, _line_number: usize) -> Option<LineMetric> {
|
2020-11-15 03:22:56 +11:00
|
|
|
None
|
2020-04-23 03:28:38 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
fn line_count(&self) -> usize {
|
2020-11-15 03:22:56 +11:00
|
|
|
0
|
2020-04-23 03:28:38 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
fn hit_test_point(&self, _point: Point) -> HitTestPoint {
|
2020-11-15 03:22:56 +11:00
|
|
|
HitTestPoint::default()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn hit_test_text_position(&self, _text_position: usize) -> HitTestPosition {
|
|
|
|
HitTestPosition::default()
|
2020-04-23 03:28:38 +10:00
|
|
|
}
|
|
|
|
|
2020-11-15 03:22:56 +11:00
|
|
|
fn text(&self) -> &str {
|
|
|
|
""
|
2020-04-23 03:28:38 +10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl IntoBrush<PietGpuRenderContext> for PietGpuBrush {
|
|
|
|
fn make_brush<'b>(
|
|
|
|
&'b self,
|
|
|
|
_piet: &mut PietGpuRenderContext,
|
|
|
|
_bbox: impl FnOnce() -> Rect,
|
|
|
|
) -> std::borrow::Cow<'b, PietGpuBrush> {
|
|
|
|
Cow::Borrowed(self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-12 13:01:06 +10:00
|
|
|
fn to_f32_2(point: Point) -> [f32; 2] {
|
|
|
|
[point.x as f32, point.y as f32]
|
2020-04-25 06:06:47 +10:00
|
|
|
}
|