Draft (very) basic incremental rendering for iced_tiny_skia
This commit is contained in:
parent
6fae8bf6cb
commit
0f7abffc0e
10 changed files with 286 additions and 92 deletions
|
|
@ -86,3 +86,6 @@ incremental = false
|
||||||
opt-level = 3
|
opt-level = 3
|
||||||
overflow-checks = false
|
overflow-checks = false
|
||||||
strip = "debuginfo"
|
strip = "debuginfo"
|
||||||
|
|
||||||
|
[patch.crates-io]
|
||||||
|
tiny-skia = { version = "0.8", git = "https://github.com/hecrj/tiny-skia.git", rev = "213890dcbb3754d51533f5b558d9f5ffa3bf6da1" }
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// A handle of some image data.
|
/// A handle of some image data.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct Handle {
|
pub struct Handle {
|
||||||
id: u64,
|
id: u64,
|
||||||
data: Data,
|
data: Data,
|
||||||
|
|
@ -156,6 +156,34 @@ impl std::fmt::Debug for Data {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PartialEq for Data {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
match (self, other) {
|
||||||
|
(Self::Path(a), Self::Path(b)) => a == b,
|
||||||
|
(Self::Bytes(a), Self::Bytes(b)) => a.as_ref() == b.as_ref(),
|
||||||
|
(
|
||||||
|
Self::Rgba {
|
||||||
|
width: width_a,
|
||||||
|
height: height_a,
|
||||||
|
pixels: pixels_a,
|
||||||
|
},
|
||||||
|
Self::Rgba {
|
||||||
|
width: width_b,
|
||||||
|
height: height_b,
|
||||||
|
pixels: pixels_b,
|
||||||
|
},
|
||||||
|
) => {
|
||||||
|
width_a == width_b
|
||||||
|
&& height_a == height_b
|
||||||
|
&& pixels_a.as_ref() == pixels_b.as_ref()
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for Data {}
|
||||||
|
|
||||||
/// A [`Renderer`] that can render raster graphics.
|
/// A [`Renderer`] that can render raster graphics.
|
||||||
///
|
///
|
||||||
/// [renderer]: crate::renderer
|
/// [renderer]: crate::renderer
|
||||||
|
|
|
||||||
|
|
@ -100,6 +100,30 @@ impl Rectangle<f32> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns whether the [`Rectangle`] intersects with the given one.
|
||||||
|
pub fn intersects(&self, other: &Self) -> bool {
|
||||||
|
self.intersection(other).is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Computes the union with the given [`Rectangle`].
|
||||||
|
pub fn union(&self, other: &Self) -> Self {
|
||||||
|
let x = self.x.min(other.x);
|
||||||
|
let y = self.y.min(other.y);
|
||||||
|
|
||||||
|
let lower_right_x = (self.x + self.width).max(other.x + other.width);
|
||||||
|
let lower_right_y = (self.y + self.height).max(other.y + other.height);
|
||||||
|
|
||||||
|
let width = lower_right_x - x;
|
||||||
|
let height = lower_right_y - y;
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Snaps the [`Rectangle`] to __unsigned__ integer coordinates.
|
/// Snaps the [`Rectangle`] to __unsigned__ integer coordinates.
|
||||||
pub fn snap(self) -> Rectangle<u32> {
|
pub fn snap(self) -> Rectangle<u32> {
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
|
@ -109,6 +133,16 @@ impl Rectangle<f32> {
|
||||||
height: self.height as u32,
|
height: self.height as u32,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Expands the [`Rectangle`] a given amount.
|
||||||
|
pub fn expand(self, amount: f32) -> Self {
|
||||||
|
Self {
|
||||||
|
x: self.x - amount,
|
||||||
|
y: self.y - amount,
|
||||||
|
width: self.width + amount * 2.0,
|
||||||
|
height: self.height + amount * 2.0,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::ops::Mul<f32> for Rectangle<f32> {
|
impl std::ops::Mul<f32> for Rectangle<f32> {
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// A handle of Svg data.
|
/// A handle of Svg data.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct Handle {
|
pub struct Handle {
|
||||||
id: u64,
|
id: u64,
|
||||||
data: Arc<Data>,
|
data: Arc<Data>,
|
||||||
|
|
@ -57,7 +57,7 @@ impl Hash for Handle {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The data of a vectorial image.
|
/// The data of a vectorial image.
|
||||||
#[derive(Clone, Hash)]
|
#[derive(Clone, Hash, PartialEq, Eq)]
|
||||||
pub enum Data {
|
pub enum Data {
|
||||||
/// File data
|
/// File data
|
||||||
Path(PathBuf),
|
Path(PathBuf),
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ use bytemuck::{Pod, Zeroable};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// A rendering primitive.
|
/// A rendering primitive.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub enum Primitive {
|
pub enum Primitive {
|
||||||
/// A text primitive
|
/// A text primitive
|
||||||
|
|
@ -147,10 +147,153 @@ impl Primitive {
|
||||||
content: Box::new(self),
|
content: Box::new(self),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn bounds(&self) -> Rectangle {
|
||||||
|
match self {
|
||||||
|
Self::Text {
|
||||||
|
bounds,
|
||||||
|
horizontal_alignment,
|
||||||
|
vertical_alignment,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
let mut bounds = *bounds;
|
||||||
|
|
||||||
|
bounds.x = match horizontal_alignment {
|
||||||
|
alignment::Horizontal::Left => bounds.x,
|
||||||
|
alignment::Horizontal::Center => {
|
||||||
|
bounds.x - bounds.width / 2.0
|
||||||
|
}
|
||||||
|
alignment::Horizontal::Right => bounds.x - bounds.width,
|
||||||
|
};
|
||||||
|
|
||||||
|
bounds.y = match vertical_alignment {
|
||||||
|
alignment::Vertical::Top => bounds.y,
|
||||||
|
alignment::Vertical::Center => {
|
||||||
|
bounds.y - bounds.height / 2.0
|
||||||
|
}
|
||||||
|
alignment::Vertical::Bottom => bounds.y - bounds.height,
|
||||||
|
};
|
||||||
|
|
||||||
|
bounds.expand(1.0)
|
||||||
|
}
|
||||||
|
Self::Quad { bounds, .. }
|
||||||
|
| Self::Image { bounds, .. }
|
||||||
|
| Self::Svg { bounds, .. }
|
||||||
|
| Self::Clip { bounds, .. } => bounds.expand(1.0),
|
||||||
|
Self::SolidMesh { size, .. } | Self::GradientMesh { size, .. } => {
|
||||||
|
Rectangle::with_size(*size)
|
||||||
|
}
|
||||||
|
#[cfg(feature = "tiny-skia")]
|
||||||
|
Self::Fill { path, .. } | Self::Stroke { path, .. } => {
|
||||||
|
let bounds = path.bounds();
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
x: bounds.x(),
|
||||||
|
y: bounds.y(),
|
||||||
|
width: bounds.width(),
|
||||||
|
height: bounds.height(),
|
||||||
|
}
|
||||||
|
.expand(1.0)
|
||||||
|
}
|
||||||
|
Self::Group { primitives } => primitives
|
||||||
|
.iter()
|
||||||
|
.map(Self::bounds)
|
||||||
|
.fold(Rectangle::with_size(Size::ZERO), |a, b| {
|
||||||
|
Rectangle::union(&a, &b)
|
||||||
|
}),
|
||||||
|
Self::Translate {
|
||||||
|
translation,
|
||||||
|
content,
|
||||||
|
} => content.bounds() + *translation,
|
||||||
|
Self::Cache { content } => content.bounds(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn damage(&self, other: &Self) -> Vec<Rectangle> {
|
||||||
|
match (self, other) {
|
||||||
|
(
|
||||||
|
Primitive::Group {
|
||||||
|
primitives: primitives_a,
|
||||||
|
},
|
||||||
|
Primitive::Group {
|
||||||
|
primitives: primitives_b,
|
||||||
|
},
|
||||||
|
) => return Self::damage_list(primitives_a, primitives_b),
|
||||||
|
(
|
||||||
|
Primitive::Clip {
|
||||||
|
bounds: bounds_a,
|
||||||
|
content: content_a,
|
||||||
|
},
|
||||||
|
Primitive::Clip {
|
||||||
|
bounds: bounds_b,
|
||||||
|
content: content_b,
|
||||||
|
},
|
||||||
|
) => {
|
||||||
|
if bounds_a == bounds_b {
|
||||||
|
return content_a.damage(content_b);
|
||||||
|
} else {
|
||||||
|
return vec![*bounds_a, *bounds_b];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(
|
||||||
|
Primitive::Translate {
|
||||||
|
translation: translation_a,
|
||||||
|
content: content_a,
|
||||||
|
},
|
||||||
|
Primitive::Translate {
|
||||||
|
translation: translation_b,
|
||||||
|
content: content_b,
|
||||||
|
},
|
||||||
|
) => {
|
||||||
|
if translation_a == translation_b {
|
||||||
|
return content_a.damage(content_b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(
|
||||||
|
Primitive::Cache { content: content_a },
|
||||||
|
Primitive::Cache { content: content_b },
|
||||||
|
) => {
|
||||||
|
if Arc::ptr_eq(content_a, content_b) {
|
||||||
|
return vec![];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ if self == other => return vec![],
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
let bounds_a = self.bounds();
|
||||||
|
let bounds_b = other.bounds();
|
||||||
|
|
||||||
|
if bounds_a == bounds_b {
|
||||||
|
vec![bounds_a]
|
||||||
|
} else {
|
||||||
|
vec![bounds_a, bounds_b]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn damage_list(previous: &[Self], current: &[Self]) -> Vec<Rectangle> {
|
||||||
|
let damage =
|
||||||
|
previous.iter().zip(current).flat_map(|(a, b)| a.damage(b));
|
||||||
|
|
||||||
|
if previous.len() == current.len() {
|
||||||
|
damage.collect()
|
||||||
|
} else {
|
||||||
|
let (smaller, bigger) = if previous.len() < current.len() {
|
||||||
|
(previous, current)
|
||||||
|
} else {
|
||||||
|
(current, previous)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Extend damage by the added/removed primitives
|
||||||
|
damage
|
||||||
|
.chain(bigger[smaller.len()..].iter().map(Primitive::bounds))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A set of [`Vertex2D`] and indices representing a list of triangles.
|
/// A set of [`Vertex2D`] and indices representing a list of triangles.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct Mesh2D<T> {
|
pub struct Mesh2D<T> {
|
||||||
/// The vertices of the mesh
|
/// The vertices of the mesh
|
||||||
pub vertices: Vec<T>,
|
pub vertices: Vec<T>,
|
||||||
|
|
@ -162,7 +305,7 @@ pub struct Mesh2D<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A two-dimensional vertex.
|
/// A two-dimensional vertex.
|
||||||
#[derive(Copy, Clone, Debug, Zeroable, Pod)]
|
#[derive(Copy, Clone, Debug, PartialEq, Zeroable, Pod)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct Vertex2D {
|
pub struct Vertex2D {
|
||||||
/// The vertex position in 2D space.
|
/// The vertex position in 2D space.
|
||||||
|
|
@ -170,7 +313,7 @@ pub struct Vertex2D {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A two-dimensional vertex with a color.
|
/// A two-dimensional vertex with a color.
|
||||||
#[derive(Copy, Clone, Debug, Zeroable, Pod)]
|
#[derive(Copy, Clone, Debug, PartialEq, Zeroable, Pod)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct ColoredVertex2D {
|
pub struct ColoredVertex2D {
|
||||||
/// The vertex position in 2D space.
|
/// The vertex position in 2D space.
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ impl<B: Backend, T> Renderer<B, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the [`Backend`] of the [`Renderer`].
|
/// Returns a reference to the [`Backend`] of the [`Renderer`].
|
||||||
pub fn backend(&self) -> &B {
|
pub fn backend(&self) -> &B {
|
||||||
&self.backend
|
&self.backend
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -129,7 +129,7 @@ impl Debug {
|
||||||
|
|
||||||
pub fn render_finished(&mut self) {
|
pub fn render_finished(&mut self) {
|
||||||
self.render_durations
|
self.render_durations
|
||||||
.push(time::Instant::now() - self.render_start);
|
.push(dbg!(time::Instant::now() - self.render_start));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn log_message<Message: std::fmt::Debug>(&mut self, message: &Message) {
|
pub fn log_message<Message: std::fmt::Debug>(&mut self, message: &Message) {
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,9 @@ pub struct Backend {
|
||||||
|
|
||||||
#[cfg(feature = "svg")]
|
#[cfg(feature = "svg")]
|
||||||
vector_pipeline: crate::vector::Pipeline,
|
vector_pipeline: crate::vector::Pipeline,
|
||||||
|
|
||||||
|
last_primitives: Vec<Primitive>,
|
||||||
|
last_background_color: Color,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Backend {
|
impl Backend {
|
||||||
|
|
@ -31,6 +34,9 @@ impl Backend {
|
||||||
|
|
||||||
#[cfg(feature = "svg")]
|
#[cfg(feature = "svg")]
|
||||||
vector_pipeline: crate::vector::Pipeline::new(),
|
vector_pipeline: crate::vector::Pipeline::new(),
|
||||||
|
|
||||||
|
last_primitives: Vec::new(),
|
||||||
|
last_background_color: Color::BLACK,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -43,10 +49,48 @@ impl Backend {
|
||||||
background_color: Color,
|
background_color: Color,
|
||||||
overlay: &[T],
|
overlay: &[T],
|
||||||
) {
|
) {
|
||||||
pixels.fill(into_color(background_color));
|
let damage = if self.last_background_color == background_color {
|
||||||
|
Primitive::damage_list(&self.last_primitives, primitives)
|
||||||
|
} else {
|
||||||
|
vec![Rectangle::with_size(viewport.logical_size())]
|
||||||
|
};
|
||||||
|
|
||||||
|
if damage.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.last_primitives = primitives.to_vec();
|
||||||
|
self.last_background_color = background_color;
|
||||||
|
|
||||||
let scale_factor = viewport.scale_factor() as f32;
|
let scale_factor = viewport.scale_factor() as f32;
|
||||||
|
|
||||||
|
dbg!(&damage);
|
||||||
|
|
||||||
|
for region in &damage {
|
||||||
|
let region = *region * scale_factor;
|
||||||
|
|
||||||
|
pixels.fill_path(
|
||||||
|
&tiny_skia::PathBuilder::from_rect(
|
||||||
|
tiny_skia::Rect::from_xywh(
|
||||||
|
region.x,
|
||||||
|
region.y,
|
||||||
|
region.width.min(viewport.physical_width() as f32),
|
||||||
|
region.height.min(viewport.physical_height() as f32),
|
||||||
|
)
|
||||||
|
.expect("Create damage rectangle"),
|
||||||
|
),
|
||||||
|
&tiny_skia::Paint {
|
||||||
|
shader: tiny_skia::Shader::SolidColor(into_color(
|
||||||
|
background_color,
|
||||||
|
)),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
tiny_skia::FillRule::default(),
|
||||||
|
tiny_skia::Transform::identity(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
for primitive in primitives {
|
for primitive in primitives {
|
||||||
self.draw_primitive(
|
self.draw_primitive(
|
||||||
primitive,
|
primitive,
|
||||||
|
|
@ -55,6 +99,7 @@ impl Backend {
|
||||||
None,
|
None,
|
||||||
scale_factor,
|
scale_factor,
|
||||||
Vector::ZERO,
|
Vector::ZERO,
|
||||||
|
&damage,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -81,6 +126,7 @@ impl Backend {
|
||||||
None,
|
None,
|
||||||
scale_factor,
|
scale_factor,
|
||||||
Vector::ZERO,
|
Vector::ZERO,
|
||||||
|
&[],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -101,6 +147,7 @@ impl Backend {
|
||||||
clip_bounds: Option<Rectangle>,
|
clip_bounds: Option<Rectangle>,
|
||||||
scale_factor: f32,
|
scale_factor: f32,
|
||||||
translation: Vector,
|
translation: Vector,
|
||||||
|
damage: &[Rectangle],
|
||||||
) {
|
) {
|
||||||
match primitive {
|
match primitive {
|
||||||
Primitive::Quad {
|
Primitive::Quad {
|
||||||
|
|
@ -110,6 +157,10 @@ impl Backend {
|
||||||
border_width,
|
border_width,
|
||||||
border_color,
|
border_color,
|
||||||
} => {
|
} => {
|
||||||
|
if !damage.iter().any(|damage| damage.intersects(bounds)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let transform = tiny_skia::Transform::from_translate(
|
let transform = tiny_skia::Transform::from_translate(
|
||||||
translation.x,
|
translation.x,
|
||||||
translation.y,
|
translation.y,
|
||||||
|
|
@ -165,6 +216,13 @@ impl Backend {
|
||||||
horizontal_alignment,
|
horizontal_alignment,
|
||||||
vertical_alignment,
|
vertical_alignment,
|
||||||
} => {
|
} => {
|
||||||
|
if !damage
|
||||||
|
.iter()
|
||||||
|
.any(|damage| damage.intersects(&primitive.bounds()))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
self.text_pipeline.draw(
|
self.text_pipeline.draw(
|
||||||
content,
|
content,
|
||||||
(*bounds + translation) * scale_factor,
|
(*bounds + translation) * scale_factor,
|
||||||
|
|
@ -179,6 +237,10 @@ impl Backend {
|
||||||
}
|
}
|
||||||
#[cfg(feature = "image")]
|
#[cfg(feature = "image")]
|
||||||
Primitive::Image { handle, bounds } => {
|
Primitive::Image { handle, bounds } => {
|
||||||
|
if !damage.iter().any(|damage| damage.intersects(bounds)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let transform = tiny_skia::Transform::from_translate(
|
let transform = tiny_skia::Transform::from_translate(
|
||||||
translation.x,
|
translation.x,
|
||||||
translation.y,
|
translation.y,
|
||||||
|
|
@ -248,6 +310,7 @@ impl Backend {
|
||||||
clip_bounds,
|
clip_bounds,
|
||||||
scale_factor,
|
scale_factor,
|
||||||
translation,
|
translation,
|
||||||
|
damage,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -262,6 +325,7 @@ impl Backend {
|
||||||
clip_bounds,
|
clip_bounds,
|
||||||
scale_factor,
|
scale_factor,
|
||||||
translation + *offset,
|
translation + *offset,
|
||||||
|
damage,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Primitive::Clip { bounds, content } => {
|
Primitive::Clip { bounds, content } => {
|
||||||
|
|
@ -284,6 +348,7 @@ impl Backend {
|
||||||
Some(bounds),
|
Some(bounds),
|
||||||
scale_factor,
|
scale_factor,
|
||||||
translation,
|
translation,
|
||||||
|
damage,
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Some(bounds) = clip_bounds {
|
if let Some(bounds) = clip_bounds {
|
||||||
|
|
@ -300,6 +365,7 @@ impl Backend {
|
||||||
clip_bounds,
|
clip_bounds,
|
||||||
scale_factor,
|
scale_factor,
|
||||||
translation,
|
translation,
|
||||||
|
damage,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Primitive::SolidMesh { .. } | Primitive::GradientMesh { .. } => {
|
Primitive::SolidMesh { .. } | Primitive::GradientMesh { .. } => {
|
||||||
|
|
|
||||||
|
|
@ -1,82 +0,0 @@
|
||||||
use crate::{Rectangle, Vector};
|
|
||||||
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum Primitive {
|
|
||||||
/// A group of primitives
|
|
||||||
Group {
|
|
||||||
/// The primitives of the group
|
|
||||||
primitives: Vec<Primitive>,
|
|
||||||
},
|
|
||||||
/// A clip primitive
|
|
||||||
Clip {
|
|
||||||
/// The bounds of the clip
|
|
||||||
bounds: Rectangle,
|
|
||||||
/// The content of the clip
|
|
||||||
content: Box<Primitive>,
|
|
||||||
},
|
|
||||||
/// A primitive that applies a translation
|
|
||||||
Translate {
|
|
||||||
/// The translation vector
|
|
||||||
translation: Vector,
|
|
||||||
|
|
||||||
/// The primitive to translate
|
|
||||||
content: Box<Primitive>,
|
|
||||||
},
|
|
||||||
/// A cached primitive.
|
|
||||||
///
|
|
||||||
/// This can be useful if you are implementing a widget where primitive
|
|
||||||
/// generation is expensive.
|
|
||||||
Cached {
|
|
||||||
/// The cached primitive
|
|
||||||
cache: Arc<Primitive>,
|
|
||||||
},
|
|
||||||
/// A basic primitive.
|
|
||||||
Basic(iced_graphics::Primitive),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl iced_graphics::backend::Primitive for Primitive {
|
|
||||||
fn translate(self, translation: Vector) -> Self {
|
|
||||||
Self::Translate {
|
|
||||||
translation,
|
|
||||||
content: Box::new(self),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clip(self, bounds: Rectangle) -> Self {
|
|
||||||
Self::Clip {
|
|
||||||
bounds,
|
|
||||||
content: Box::new(self),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default)]
|
|
||||||
pub struct Recording(pub(crate) Vec<Primitive>);
|
|
||||||
|
|
||||||
impl iced_graphics::backend::Recording for Recording {
|
|
||||||
type Primitive = Primitive;
|
|
||||||
|
|
||||||
fn push(&mut self, primitive: Primitive) {
|
|
||||||
self.0.push(primitive);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn push_basic(&mut self, basic: iced_graphics::Primitive) {
|
|
||||||
self.0.push(Primitive::Basic(basic));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn group(self) -> Self::Primitive {
|
|
||||||
Primitive::Group { primitives: self.0 }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clear(&mut self) {
|
|
||||||
self.0.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Recording {
|
|
||||||
pub fn primitives(&self) -> &[Primitive] {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -953,6 +953,8 @@ pub fn draw<Renderer>(
|
||||||
let render = |renderer: &mut Renderer| {
|
let render = |renderer: &mut Renderer| {
|
||||||
if let Some((cursor, color)) = cursor {
|
if let Some((cursor, color)) = cursor {
|
||||||
renderer.fill_quad(cursor, color);
|
renderer.fill_quad(cursor, color);
|
||||||
|
} else {
|
||||||
|
renderer.with_translation(Vector::ZERO, |_| {});
|
||||||
}
|
}
|
||||||
|
|
||||||
renderer.fill_text(Text {
|
renderer.fill_text(Text {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue