Port iced_tiny_skia to new layering architecture
This commit is contained in:
parent
2c6fd9ac14
commit
6ad5bb3597
28 changed files with 1948 additions and 1935 deletions
|
|
@ -2,7 +2,8 @@
|
|||
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||
pub mod window;
|
||||
|
||||
mod backend;
|
||||
mod engine;
|
||||
mod layer;
|
||||
mod primitive;
|
||||
mod settings;
|
||||
mod text;
|
||||
|
|
@ -19,12 +20,388 @@ pub mod geometry;
|
|||
pub use iced_graphics as graphics;
|
||||
pub use iced_graphics::core;
|
||||
|
||||
pub use backend::Backend;
|
||||
pub use layer::Layer;
|
||||
pub use primitive::Primitive;
|
||||
pub use settings::Settings;
|
||||
|
||||
#[cfg(feature = "geometry")]
|
||||
pub use geometry::Geometry;
|
||||
|
||||
use crate::core::renderer;
|
||||
use crate::core::{
|
||||
Background, Color, Font, Pixels, Point, Rectangle, Size, Transformation,
|
||||
};
|
||||
use crate::engine::Engine;
|
||||
use crate::graphics::compositor;
|
||||
use crate::graphics::text::{Editor, Paragraph};
|
||||
use crate::graphics::Viewport;
|
||||
|
||||
/// A [`tiny-skia`] graphics renderer for [`iced`].
|
||||
///
|
||||
/// [`tiny-skia`]: https://github.com/RazrFalcon/tiny-skia
|
||||
/// [`iced`]: https://github.com/iced-rs/iced
|
||||
pub type Renderer = iced_graphics::Renderer<Backend>;
|
||||
#[derive(Debug)]
|
||||
pub struct Renderer {
|
||||
default_font: Font,
|
||||
default_text_size: Pixels,
|
||||
layers: layer::Stack,
|
||||
engine: Engine, // TODO: Shared engine
|
||||
}
|
||||
|
||||
impl Renderer {
|
||||
pub fn new(default_font: Font, default_text_size: Pixels) -> Self {
|
||||
Self {
|
||||
default_font,
|
||||
default_text_size,
|
||||
layers: layer::Stack::new(),
|
||||
engine: Engine::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn layers(&mut self) -> impl Iterator<Item = &Layer> {
|
||||
self.layers.flush();
|
||||
self.layers.iter()
|
||||
}
|
||||
|
||||
pub fn draw<T: AsRef<str>>(
|
||||
&mut self,
|
||||
pixels: &mut tiny_skia::PixmapMut<'_>,
|
||||
clip_mask: &mut tiny_skia::Mask,
|
||||
viewport: &Viewport,
|
||||
damage: &[Rectangle],
|
||||
background_color: Color,
|
||||
overlay: &[T],
|
||||
) {
|
||||
let physical_size = viewport.physical_size();
|
||||
let scale_factor = viewport.scale_factor() as f32;
|
||||
|
||||
if !overlay.is_empty() {
|
||||
let path = tiny_skia::PathBuilder::from_rect(
|
||||
tiny_skia::Rect::from_xywh(
|
||||
0.0,
|
||||
0.0,
|
||||
physical_size.width as f32,
|
||||
physical_size.height as f32,
|
||||
)
|
||||
.expect("Create damage rectangle"),
|
||||
);
|
||||
|
||||
pixels.fill_path(
|
||||
&path,
|
||||
&tiny_skia::Paint {
|
||||
shader: tiny_skia::Shader::SolidColor(engine::into_color(
|
||||
Color {
|
||||
a: 0.1,
|
||||
..background_color
|
||||
},
|
||||
)),
|
||||
anti_alias: false,
|
||||
..Default::default()
|
||||
},
|
||||
tiny_skia::FillRule::default(),
|
||||
tiny_skia::Transform::identity(),
|
||||
None,
|
||||
);
|
||||
}
|
||||
|
||||
self.layers.flush();
|
||||
|
||||
for ®ion in damage {
|
||||
let region = region * scale_factor;
|
||||
|
||||
let path = tiny_skia::PathBuilder::from_rect(
|
||||
tiny_skia::Rect::from_xywh(
|
||||
region.x,
|
||||
region.y,
|
||||
region.width,
|
||||
region.height,
|
||||
)
|
||||
.expect("Create damage rectangle"),
|
||||
);
|
||||
|
||||
pixels.fill_path(
|
||||
&path,
|
||||
&tiny_skia::Paint {
|
||||
shader: tiny_skia::Shader::SolidColor(engine::into_color(
|
||||
background_color,
|
||||
)),
|
||||
anti_alias: false,
|
||||
blend_mode: tiny_skia::BlendMode::Source,
|
||||
..Default::default()
|
||||
},
|
||||
tiny_skia::FillRule::default(),
|
||||
tiny_skia::Transform::identity(),
|
||||
None,
|
||||
);
|
||||
|
||||
for layer in self.layers.iter() {
|
||||
let Some(clip_bounds) = region.intersection(&layer.bounds)
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let clip_bounds = clip_bounds * scale_factor;
|
||||
engine::adjust_clip_mask(clip_mask, clip_bounds);
|
||||
|
||||
for (quad, background) in &layer.quads {
|
||||
self.engine.draw_quad(
|
||||
quad,
|
||||
background,
|
||||
Transformation::scale(scale_factor),
|
||||
pixels,
|
||||
clip_mask,
|
||||
clip_bounds,
|
||||
);
|
||||
}
|
||||
|
||||
for group in &layer.text {
|
||||
for text in group.as_slice() {
|
||||
self.engine.draw_text(
|
||||
text,
|
||||
group.transformation()
|
||||
* Transformation::scale(scale_factor),
|
||||
pixels,
|
||||
clip_mask,
|
||||
clip_bounds,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for group in &layer.primitives {
|
||||
let Some(new_clip_bounds) =
|
||||
group.clip_bounds().intersection(&layer.bounds)
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
|
||||
engine::adjust_clip_mask(
|
||||
clip_mask,
|
||||
new_clip_bounds * scale_factor,
|
||||
);
|
||||
|
||||
for primitive in group.as_slice() {
|
||||
self.engine.draw_primitive(
|
||||
primitive,
|
||||
group.transformation()
|
||||
* Transformation::scale(scale_factor),
|
||||
pixels,
|
||||
clip_mask,
|
||||
clip_bounds,
|
||||
);
|
||||
}
|
||||
|
||||
engine::adjust_clip_mask(clip_mask, clip_bounds);
|
||||
}
|
||||
|
||||
for image in &layer.images {
|
||||
self.engine.draw_image(
|
||||
image,
|
||||
Transformation::scale(scale_factor),
|
||||
pixels,
|
||||
clip_mask,
|
||||
clip_bounds,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if !overlay.is_empty() {
|
||||
pixels.stroke_path(
|
||||
&path,
|
||||
&tiny_skia::Paint {
|
||||
shader: tiny_skia::Shader::SolidColor(
|
||||
engine::into_color(Color::from_rgb(1.0, 0.0, 0.0)),
|
||||
),
|
||||
anti_alias: false,
|
||||
..tiny_skia::Paint::default()
|
||||
},
|
||||
&tiny_skia::Stroke {
|
||||
width: 1.0,
|
||||
..tiny_skia::Stroke::default()
|
||||
},
|
||||
tiny_skia::Transform::identity(),
|
||||
None,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
self.engine.trim();
|
||||
}
|
||||
}
|
||||
|
||||
impl core::Renderer for Renderer {
|
||||
fn start_layer(&mut self, bounds: Rectangle) {
|
||||
self.layers.push_clip(bounds);
|
||||
}
|
||||
|
||||
fn end_layer(&mut self) {
|
||||
self.layers.pop_clip();
|
||||
}
|
||||
|
||||
fn start_transformation(&mut self, transformation: Transformation) {
|
||||
self.layers.push_transformation(transformation);
|
||||
}
|
||||
|
||||
fn end_transformation(&mut self) {
|
||||
self.layers.pop_transformation();
|
||||
}
|
||||
|
||||
fn fill_quad(
|
||||
&mut self,
|
||||
quad: renderer::Quad,
|
||||
background: impl Into<Background>,
|
||||
) {
|
||||
let (layer, transformation) = self.layers.current_mut();
|
||||
layer.draw_quad(quad, background.into(), transformation);
|
||||
}
|
||||
|
||||
fn clear(&mut self) {
|
||||
self.layers.clear();
|
||||
}
|
||||
}
|
||||
|
||||
impl core::text::Renderer for Renderer {
|
||||
type Font = Font;
|
||||
type Paragraph = Paragraph;
|
||||
type Editor = Editor;
|
||||
|
||||
const ICON_FONT: Font = Font::with_name("Iced-Icons");
|
||||
const CHECKMARK_ICON: char = '\u{f00c}';
|
||||
const ARROW_DOWN_ICON: char = '\u{e800}';
|
||||
|
||||
fn default_font(&self) -> Self::Font {
|
||||
self.default_font
|
||||
}
|
||||
|
||||
fn default_size(&self) -> Pixels {
|
||||
self.default_text_size
|
||||
}
|
||||
|
||||
fn fill_paragraph(
|
||||
&mut self,
|
||||
text: &Self::Paragraph,
|
||||
position: Point,
|
||||
color: Color,
|
||||
clip_bounds: Rectangle,
|
||||
) {
|
||||
let (layer, transformation) = self.layers.current_mut();
|
||||
|
||||
layer.draw_paragraph(
|
||||
text,
|
||||
position,
|
||||
color,
|
||||
clip_bounds,
|
||||
transformation,
|
||||
);
|
||||
}
|
||||
|
||||
fn fill_editor(
|
||||
&mut self,
|
||||
editor: &Self::Editor,
|
||||
position: Point,
|
||||
color: Color,
|
||||
clip_bounds: Rectangle,
|
||||
) {
|
||||
let (layer, transformation) = self.layers.current_mut();
|
||||
layer.draw_editor(editor, position, color, clip_bounds, transformation);
|
||||
}
|
||||
|
||||
fn fill_text(
|
||||
&mut self,
|
||||
text: core::Text,
|
||||
position: Point,
|
||||
color: Color,
|
||||
clip_bounds: Rectangle,
|
||||
) {
|
||||
let (layer, transformation) = self.layers.current_mut();
|
||||
layer.draw_text(text, position, color, clip_bounds, transformation);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "geometry")]
|
||||
impl graphics::geometry::Renderer for Renderer {
|
||||
type Geometry = Geometry;
|
||||
type Frame = geometry::Frame;
|
||||
|
||||
fn new_frame(&self, size: core::Size) -> Self::Frame {
|
||||
geometry::Frame::new(size)
|
||||
}
|
||||
|
||||
fn draw_geometry(&mut self, geometry: Self::Geometry) {
|
||||
let (layer, transformation) = self.layers.current_mut();
|
||||
|
||||
match geometry {
|
||||
Geometry::Live {
|
||||
primitives,
|
||||
text,
|
||||
clip_bounds,
|
||||
} => {
|
||||
layer.draw_primitive_group(
|
||||
primitives,
|
||||
clip_bounds,
|
||||
transformation,
|
||||
);
|
||||
|
||||
layer.draw_text_group(text, clip_bounds, transformation);
|
||||
}
|
||||
Geometry::Cache(cache) => {
|
||||
layer.draw_primitive_cache(
|
||||
cache.primitives,
|
||||
cache.clip_bounds,
|
||||
transformation,
|
||||
);
|
||||
|
||||
layer.draw_text_cache(
|
||||
cache.text,
|
||||
cache.clip_bounds,
|
||||
transformation,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl graphics::mesh::Renderer for Renderer {
|
||||
fn draw_mesh(&mut self, _mesh: graphics::Mesh) {
|
||||
log::warn!("iced_tiny_skia does not support drawing meshes");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "image")]
|
||||
impl core::image::Renderer for Renderer {
|
||||
type Handle = core::image::Handle;
|
||||
|
||||
fn measure_image(&self, handle: &Self::Handle) -> Size<u32> {
|
||||
self.engine.raster_pipeline.dimensions(handle)
|
||||
}
|
||||
|
||||
fn draw_image(
|
||||
&mut self,
|
||||
handle: Self::Handle,
|
||||
filter_method: core::image::FilterMethod,
|
||||
bounds: Rectangle,
|
||||
) {
|
||||
let (layer, transformation) = self.layers.current_mut();
|
||||
layer.draw_image(handle, filter_method, bounds, transformation);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "svg")]
|
||||
impl core::svg::Renderer for Renderer {
|
||||
fn measure_svg(&self, handle: &core::svg::Handle) -> Size<u32> {
|
||||
self.engine.vector_pipeline.viewport_dimensions(handle)
|
||||
}
|
||||
|
||||
fn draw_svg(
|
||||
&mut self,
|
||||
handle: core::svg::Handle,
|
||||
color: Option<Color>,
|
||||
bounds: Rectangle,
|
||||
) {
|
||||
let (layer, transformation) = self.layers.current_mut();
|
||||
layer.draw_svg(handle, color, bounds, transformation);
|
||||
}
|
||||
}
|
||||
|
||||
impl compositor::Default for Renderer {
|
||||
type Compositor = window::Compositor;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue