diff options
author | 2024-03-21 05:52:48 +0100 | |
---|---|---|
committer | 2024-03-21 05:52:48 +0100 | |
commit | 188db4da48954b95a3fe79bcd22689ffc3a661e0 (patch) | |
tree | 8af47544c98c212b50c15e66458518974139b796 /renderer | |
parent | 2b00e8b1457b0ccbafe12db3dbd6431c2c72f275 (diff) | |
download | iced-188db4da48954b95a3fe79bcd22689ffc3a661e0.tar.gz iced-188db4da48954b95a3fe79bcd22689ffc3a661e0.tar.bz2 iced-188db4da48954b95a3fe79bcd22689ffc3a661e0.zip |
Draft support for dynamic custom renderer injection
Diffstat (limited to 'renderer')
-rw-r--r-- | renderer/src/compositor.rs | 25 | ||||
-rw-r--r-- | renderer/src/custom.rs | 164 | ||||
-rw-r--r-- | renderer/src/geometry.rs | 33 | ||||
-rw-r--r-- | renderer/src/geometry/cache.rs | 9 | ||||
-rw-r--r-- | renderer/src/lib.rs | 74 |
5 files changed, 289 insertions, 16 deletions
diff --git a/renderer/src/compositor.rs b/renderer/src/compositor.rs index c23a814c..058fa36d 100644 --- a/renderer/src/compositor.rs +++ b/renderer/src/compositor.rs @@ -1,4 +1,5 @@ use crate::core::Color; +use crate::custom; use crate::graphics::compositor::{Information, SurfaceError, Window}; use crate::graphics::{Error, Viewport}; use crate::{Renderer, Settings}; @@ -10,12 +11,14 @@ pub enum Compositor { TinySkia(iced_tiny_skia::window::Compositor), #[cfg(feature = "wgpu")] Wgpu(iced_wgpu::window::Compositor), + Custom(Box<dyn custom::Compositor>), } pub enum Surface { TinySkia(iced_tiny_skia::window::Surface), #[cfg(feature = "wgpu")] Wgpu(iced_wgpu::window::Surface<'static>), + Custom(Box<dyn custom::Surface>), } impl crate::graphics::Compositor for Compositor { @@ -56,6 +59,9 @@ impl crate::graphics::Compositor for Compositor { Compositor::Wgpu(compositor) => { Renderer::Wgpu(compositor.create_renderer()) } + Compositor::Custom(compositor) => { + Renderer::Custom(compositor.create_renderer()) + } } } @@ -73,6 +79,9 @@ impl crate::graphics::Compositor for Compositor { Self::Wgpu(compositor) => { Surface::Wgpu(compositor.create_surface(window, width, height)) } + Self::Custom(compositor) => Surface::Custom( + compositor.create_surface(Box::new(window), width, height), + ), } } @@ -90,6 +99,9 @@ impl crate::graphics::Compositor for Compositor { (Self::Wgpu(compositor), Surface::Wgpu(surface)) => { compositor.configure_surface(surface, width, height); } + (Self::Custom(compositor), Surface::Custom(surface)) => { + compositor.configure_surface(surface, width, height); + } #[allow(unreachable_patterns)] _ => panic!( "The provided surface is not compatible with the compositor." @@ -102,6 +114,7 @@ impl crate::graphics::Compositor for Compositor { Self::TinySkia(compositor) => compositor.fetch_information(), #[cfg(feature = "wgpu")] Self::Wgpu(compositor) => compositor.fetch_information(), + Self::Custom(compositor) => compositor.fetch_information(), } } @@ -144,6 +157,18 @@ impl crate::graphics::Compositor for Compositor { overlay, ) }), + + #[cfg(feature = "wgpu")] + ( + Self::Custom(compositor), + crate::Renderer::Custom(renderer), + Surface::Custom(surface), + ) => renderer.present( + surface.as_mut(), + viewport, + background_color, + compositor.as_mut(), + ), #[allow(unreachable_patterns)] _ => panic!( "The provided renderer or surface are not compatible \ diff --git a/renderer/src/custom.rs b/renderer/src/custom.rs new file mode 100644 index 00000000..680aa0b5 --- /dev/null +++ b/renderer/src/custom.rs @@ -0,0 +1,164 @@ +use crate::core::image; +use crate::core::renderer; +use crate::core::svg; +use crate::core::text::Text; +use crate::core::{ + Background, Color, Font, Pixels, Point, Rectangle, Size, Transformation, +}; +use crate::graphics::compositor; +use crate::graphics::text::{Editor, Paragraph}; +use crate::graphics::{Mesh, Viewport}; + +#[cfg(feature = "geometry")] +use crate::graphics::geometry::{self, Fill, Path, Stroke}; + +use std::borrow::Cow; + +pub trait Renderer { + fn draw_mesh(&mut self, mesh: Mesh); + + fn start_layer(&mut self); + + fn end_layer(&mut self, bounds: Rectangle); + + fn start_transformation(&mut self); + + fn end_transformation(&mut self, transformation: Transformation); + + fn fill_quad(&mut self, quad: renderer::Quad, background: Background); + + fn clear(&mut self); + + fn default_font(&self) -> Font; + + fn default_size(&self) -> Pixels; + + fn load_font(&mut self, bytes: Cow<'static, [u8]>); + + fn fill_paragraph( + &mut self, + paragraph: &Paragraph, + position: Point, + color: Color, + clip_bounds: Rectangle, + ); + + fn fill_editor( + &mut self, + editor: &Editor, + position: Point, + color: Color, + clip_bounds: Rectangle, + ); + + fn fill_text( + &mut self, + text: Text<'_, Font>, + position: Point, + color: Color, + clip_bounds: Rectangle, + ); + + fn measure_image(&self, handle: &image::Handle) -> Size<u32>; + + fn draw_image( + &mut self, + handle: image::Handle, + filter_method: image::FilterMethod, + bounds: Rectangle, + ); + + fn measure_svg(&self, handle: &svg::Handle) -> Size<u32>; + + fn draw_svg( + &mut self, + handle: crate::core::svg::Handle, + color: Option<crate::core::Color>, + bounds: Rectangle, + ); + + #[cfg(feature = "geometry")] + fn new_frame(&self, size: Size) -> Box<dyn Frame>; + + #[cfg(feature = "geometry")] + fn draw_geometry(&mut self, geometry: Box<dyn Geometry>); + + fn present( + &mut self, + surface: &mut dyn Surface, + viewport: &Viewport, + background_color: Color, + compositor: &mut dyn Compositor, + ) -> Result<(), compositor::SurfaceError>; +} + +#[cfg(feature = "geometry")] +pub trait Frame: std::any::Any { + fn new(&self, size: Size) -> Box<dyn Frame>; + + fn width(&self) -> f32; + + fn height(&self) -> f32; + + fn size(&self) -> Size; + + fn center(&self) -> Point; + + fn fill(&mut self, path: &Path, fill: Fill); + + fn fill_rectangle(&mut self, top_left: Point, size: Size, fill: Fill); + + fn stroke<'a>(&mut self, path: &Path, stroke: Stroke<'a>); + + fn fill_text(&mut self, text: geometry::Text); + + fn translate(&mut self, translation: crate::core::Vector); + + fn rotate(&mut self, angle: crate::core::Radians); + + fn scale(&mut self, scale: f32); + + fn scale_nonuniform(&mut self, scale: crate::core::Vector); + + fn push_transform(&mut self); + + fn pop_transform(&mut self); + + fn clip(&mut self, frame: Box<dyn Frame>, origin: Point); + + fn into_geometry(self: Box<Self>) -> Box<dyn Geometry>; +} + +#[cfg(feature = "geometry")] +pub trait Geometry: std::any::Any + std::fmt::Debug { + fn transform( + self: Box<Self>, + transformation: Transformation, + ) -> Box<dyn Geometry>; + + fn cache(self: Box<Self>) -> std::sync::Arc<dyn Geometry>; + + fn load(self: std::sync::Arc<Self>) -> Box<dyn Geometry>; +} + +pub trait Compositor: std::any::Any { + fn create_renderer(&self) -> Box<dyn Renderer>; + + fn create_surface( + &mut self, + window: Box<dyn compositor::Window>, + width: u32, + height: u32, + ) -> Box<dyn Surface>; + + fn configure_surface( + &mut self, + surface: &mut Box<dyn Surface>, + width: u32, + height: u32, + ); + + fn fetch_information(&self) -> compositor::Information; +} + +pub trait Surface: std::any::Any {} diff --git a/renderer/src/geometry.rs b/renderer/src/geometry.rs index 36435148..bf70c7fa 100644 --- a/renderer/src/geometry.rs +++ b/renderer/src/geometry.rs @@ -3,6 +3,7 @@ mod cache; pub use cache::Cache; use crate::core::{Point, Radians, Rectangle, Size, Transformation, Vector}; +use crate::custom; use crate::graphics::geometry::{Fill, Path, Stroke, Text}; use crate::Renderer; @@ -12,6 +13,7 @@ macro_rules! delegate { Self::TinySkia($name) => $body, #[cfg(feature = "wgpu")] Self::Wgpu($name) => $body, + Self::Custom($name) => $body, } }; } @@ -20,6 +22,7 @@ pub enum Geometry { TinySkia(iced_tiny_skia::Primitive), #[cfg(feature = "wgpu")] Wgpu(iced_wgpu::Primitive), + Custom(Box<dyn custom::Geometry>), } impl Geometry { @@ -32,6 +35,9 @@ impl Geometry { Self::Wgpu(primitive) => { Self::Wgpu(primitive.transform(transformation)) } + Self::Custom(geometry) => { + Self::Custom(geometry.transform(transformation)) + } } } } @@ -40,6 +46,7 @@ pub enum Frame { TinySkia(iced_tiny_skia::geometry::Frame), #[cfg(feature = "wgpu")] Wgpu(iced_wgpu::geometry::Frame), + Custom(Box<dyn custom::Frame>), } impl Frame { @@ -52,6 +59,9 @@ impl Frame { Renderer::Wgpu(_) => { Frame::Wgpu(iced_wgpu::geometry::Frame::new(size)) } + Renderer::Custom(renderer) => { + Frame::Custom(renderer.new_frame(size)) + } } } @@ -82,7 +92,7 @@ impl Frame { /// Draws the given [`Path`] on the [`Frame`] by filling it with the /// provided style. pub fn fill(&mut self, path: &Path, fill: impl Into<Fill>) { - delegate!(self, frame, frame.fill(path, fill)); + delegate!(self, frame, frame.fill(path, fill.into())); } /// Draws an axis-aligned rectangle given its top-left corner coordinate and @@ -93,13 +103,17 @@ impl Frame { size: Size, fill: impl Into<Fill>, ) { - delegate!(self, frame, frame.fill_rectangle(top_left, size, fill)); + delegate!( + self, + frame, + frame.fill_rectangle(top_left, size, fill.into()) + ); } /// Draws the stroke of the given [`Path`] on the [`Frame`] with the /// provided style. pub fn stroke<'a>(&mut self, path: &Path, stroke: impl Into<Stroke<'a>>) { - delegate!(self, frame, frame.stroke(path, stroke)); + delegate!(self, frame, frame.stroke(path, stroke.into())); } /// Draws the characters of the given [`Text`] on the [`Frame`], filling @@ -116,7 +130,7 @@ impl Frame { /// Support for vectorial text is planned, and should address all these /// limitations. pub fn fill_text(&mut self, text: impl Into<Text>) { - delegate!(self, frame, frame.fill_text(text)); + delegate!(self, frame, frame.fill_text(text.into())); } /// Stores the current transform of the [`Frame`] and executes the given @@ -155,6 +169,7 @@ impl Frame { Self::Wgpu(_) => { Self::Wgpu(iced_wgpu::geometry::Frame::new(region.size())) } + Self::Custom(frame) => Self::Custom(frame.new(region.size())), }; let result = f(&mut frame); @@ -169,6 +184,9 @@ impl Frame { (Self::Wgpu(target), Self::Wgpu(frame)) => { target.clip(frame, origin); } + (Self::Custom(target), Self::Custom(frame)) => { + target.clip(frame, origin); + } #[allow(unreachable_patterns)] _ => unreachable!(), }; @@ -185,19 +203,19 @@ impl Frame { /// Applies a rotation in radians to the current transform of the [`Frame`]. #[inline] pub fn rotate(&mut self, angle: impl Into<Radians>) { - delegate!(self, frame, frame.rotate(angle)); + delegate!(self, frame, frame.rotate(angle.into())); } /// Applies a uniform scaling to the current transform of the [`Frame`]. #[inline] pub fn scale(&mut self, scale: impl Into<f32>) { - delegate!(self, frame, frame.scale(scale)); + delegate!(self, frame, frame.scale(scale.into())); } /// Applies a non-uniform scaling to the current transform of the [`Frame`]. #[inline] pub fn scale_nonuniform(&mut self, scale: impl Into<Vector>) { - delegate!(self, frame, frame.scale_nonuniform(scale)); + delegate!(self, frame, frame.scale_nonuniform(scale.into())); } pub fn into_geometry(self) -> Geometry { @@ -205,6 +223,7 @@ impl Frame { Self::TinySkia(frame) => Geometry::TinySkia(frame.into_primitive()), #[cfg(feature = "wgpu")] Self::Wgpu(frame) => Geometry::Wgpu(frame.into_primitive()), + Self::Custom(frame) => Geometry::Custom(frame.into_geometry()), } } } diff --git a/renderer/src/geometry/cache.rs b/renderer/src/geometry/cache.rs index 3aff76b9..6a43ddb6 100644 --- a/renderer/src/geometry/cache.rs +++ b/renderer/src/geometry/cache.rs @@ -1,4 +1,5 @@ use crate::core::Size; +use crate::custom; use crate::geometry::{Frame, Geometry}; use crate::Renderer; @@ -29,6 +30,7 @@ enum Internal { TinySkia(Arc<iced_tiny_skia::Primitive>), #[cfg(feature = "wgpu")] Wgpu(Arc<iced_wgpu::Primitive>), + Custom(Arc<dyn custom::Geometry>), } impl Cache { @@ -82,6 +84,9 @@ impl Cache { content: primitive.clone(), }); } + Internal::Custom(geometry) => { + return Geometry::Custom(geometry.clone().load()) + } } } } @@ -100,6 +105,9 @@ impl Cache { Geometry::Wgpu(primitive) => { Internal::Wgpu(Arc::new(primitive)) } + Geometry::Custom(geometry) => { + Internal::Custom(geometry.cache()) + } } }; @@ -120,6 +128,7 @@ impl Cache { content: primitive, }) } + Internal::Custom(geometry) => Geometry::Custom(geometry.load()), } } } diff --git a/renderer/src/lib.rs b/renderer/src/lib.rs index 757c264d..70741356 100644 --- a/renderer/src/lib.rs +++ b/renderer/src/lib.rs @@ -5,6 +5,7 @@ pub use iced_wgpu as wgpu; pub mod compositor; +pub mod custom; #[cfg(feature = "geometry")] pub mod geometry; @@ -38,6 +39,7 @@ pub enum Renderer { TinySkia(iced_tiny_skia::Renderer), #[cfg(feature = "wgpu")] Wgpu(iced_wgpu::Renderer), + Custom(Box<dyn custom::Renderer>), } macro_rules! delegate { @@ -46,6 +48,7 @@ macro_rules! delegate { Self::TinySkia($name) => $body, #[cfg(feature = "wgpu")] Self::Wgpu($name) => $body, + Self::Custom($name) => $body, } }; } @@ -62,6 +65,9 @@ impl Renderer { iced_wgpu::primitive::Custom::Mesh(mesh), )); } + Self::Custom(renderer) => { + renderer.draw_mesh(mesh); + } } } } @@ -96,6 +102,18 @@ impl core::Renderer for Renderer { _ => unreachable!(), } } + Self::Custom(renderer) => { + renderer.start_layer(); + + f(self); + + match self { + Self::Custom(renderer) => { + renderer.end_layer(bounds); + } + _ => unreachable!(), + } + } } } @@ -132,6 +150,18 @@ impl core::Renderer for Renderer { _ => unreachable!(), } } + Self::Custom(renderer) => { + renderer.start_transformation(); + + f(self); + + match self { + Self::Custom(renderer) => { + renderer.end_transformation(transformation); + } + _ => unreachable!(), + } + } } } @@ -140,7 +170,7 @@ impl core::Renderer for Renderer { quad: renderer::Quad, background: impl Into<Background>, ) { - delegate!(self, renderer, renderer.fill_quad(quad, background)); + delegate!(self, renderer, renderer.fill_quad(quad, background.into())); } fn clear(&mut self) { @@ -216,36 +246,43 @@ impl text::Renderer for Renderer { impl crate::core::image::Renderer for Renderer { type Handle = crate::core::image::Handle; - fn dimensions( + fn measure_image( &self, handle: &crate::core::image::Handle, ) -> core::Size<u32> { - delegate!(self, renderer, renderer.dimensions(handle)) + delegate!(self, renderer, renderer.measure_image(handle)) } - fn draw( + fn draw_image( &mut self, handle: crate::core::image::Handle, filter_method: crate::core::image::FilterMethod, bounds: Rectangle, ) { - delegate!(self, renderer, renderer.draw(handle, filter_method, bounds)); + delegate!( + self, + renderer, + renderer.draw_image(handle, filter_method, bounds) + ); } } #[cfg(feature = "svg")] impl crate::core::svg::Renderer for Renderer { - fn dimensions(&self, handle: &crate::core::svg::Handle) -> core::Size<u32> { - delegate!(self, renderer, renderer.dimensions(handle)) + fn measure_svg( + &self, + handle: &crate::core::svg::Handle, + ) -> core::Size<u32> { + delegate!(self, renderer, renderer.measure_svg(handle)) } - fn draw( + fn draw_svg( &mut self, handle: crate::core::svg::Handle, color: Option<crate::core::Color>, bounds: Rectangle, ) { - delegate!(self, renderer, renderer.draw(handle, color, bounds)); + delegate!(self, renderer, renderer.draw_svg(handle, color, bounds)); } } @@ -263,6 +300,7 @@ impl crate::graphics::geometry::Renderer for Renderer { } #[cfg(feature = "wgpu")] crate::Geometry::Wgpu(_) => unreachable!(), + crate::Geometry::Custom(_) => unreachable!(), } } } @@ -274,6 +312,19 @@ impl crate::graphics::geometry::Renderer for Renderer { renderer.draw_primitive(primitive); } crate::Geometry::TinySkia(_) => unreachable!(), + crate::Geometry::Custom(_) => unreachable!(), + } + } + } + Self::Custom(renderer) => { + for layer in layers { + match layer { + crate::Geometry::Custom(geometry) => { + renderer.draw_geometry(geometry); + } + crate::Geometry::TinySkia(_) => unreachable!(), + #[cfg(feature = "wgpu")] + crate::Geometry::Wgpu(_) => unreachable!(), } } } @@ -297,6 +348,11 @@ impl iced_wgpu::primitive::pipeline::Renderer for Renderer { Self::Wgpu(renderer) => { renderer.draw_pipeline_primitive(bounds, primitive); } + Self::Custom(_renderer) => { + log::warn!( + "Custom shader primitive is unavailable with custom renderer." + ); + } } } } |