diff options
author | 2020-05-29 02:00:28 +0200 | |
---|---|---|
committer | 2020-05-29 02:00:28 +0200 | |
commit | 0cde20b3550ede81bc7ddef628b91eec225aa8af (patch) | |
tree | 56920437979012cceb49718f2dd4ce27d5ba5d40 /wgpu | |
parent | 67b6f044e870df41be92cdc79f571682b97a5d0d (diff) | |
parent | e11b5c614f5bf73c137b8b4f24f56047617527eb (diff) | |
download | iced-0cde20b3550ede81bc7ddef628b91eec225aa8af.tar.gz iced-0cde20b3550ede81bc7ddef628b91eec225aa8af.tar.bz2 iced-0cde20b3550ede81bc7ddef628b91eec225aa8af.zip |
Merge branch 'master' into improvement/update-wgpu_glyph
Diffstat (limited to 'wgpu')
60 files changed, 415 insertions, 3635 deletions
diff --git a/wgpu/Cargo.toml b/wgpu/Cargo.toml index 5f86972d..3bbc57a0 100644 --- a/wgpu/Cargo.toml +++ b/wgpu/Cargo.toml @@ -9,16 +9,16 @@ repository = "https://github.com/hecrj/iced" [features] svg = ["resvg"] -canvas = ["lyon"] +canvas = ["iced_graphics/canvas"] [dependencies] wgpu = "0.5" wgpu_glyph = "0.9" -zerocopy = "0.3" glyph_brush = "0.7" +zerocopy = "0.3" +bytemuck = "1.2" raw-window-handle = "0.3" glam = "0.8" -font-kit = "0.6" log = "0.4" guillotiere = "0.5" # Pin `gfx-memory` until https://github.com/gfx-rs/wgpu-rs/issues/261 is @@ -29,9 +29,10 @@ gfx-memory = "=0.1.1" version = "0.2" path = "../native" -[dependencies.iced_style] +[dependencies.iced_graphics] version = "0.1" -path = "../style" +path = "../graphics" +features = ["font-source", "font-fallback", "font-icons"] [dependencies.image] version = "0.23" @@ -42,10 +43,6 @@ version = "0.9" features = ["raqote-backend"] optional = true -[dependencies.lyon] -version = "0.15" -optional = true - [package.metadata.docs.rs] rustdoc-args = ["--cfg", "docsrs"] all-features = true diff --git a/wgpu/fonts/Lato-Regular.ttf b/wgpu/fonts/Lato-Regular.ttf Binary files differdeleted file mode 100644 index 33eba8b1..00000000 --- a/wgpu/fonts/Lato-Regular.ttf +++ /dev/null diff --git a/wgpu/fonts/OFL.txt b/wgpu/fonts/OFL.txt deleted file mode 100644 index dfca0da4..00000000 --- a/wgpu/fonts/OFL.txt +++ /dev/null @@ -1,93 +0,0 @@ -Copyright (c) 2010-2014 by tyPoland Lukasz Dziedzic (team@latofonts.com) with Reserved Font Name "Lato"
-
-This Font Software is licensed under the SIL Open Font License, Version 1.1.
-This license is copied below, and is also available with a FAQ at:
-http://scripts.sil.org/OFL
-
-
------------------------------------------------------------
-SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
------------------------------------------------------------
-
-PREAMBLE
-The goals of the Open Font License (OFL) are to stimulate worldwide
-development of collaborative font projects, to support the font creation
-efforts of academic and linguistic communities, and to provide a free and
-open framework in which fonts may be shared and improved in partnership
-with others.
-
-The OFL allows the licensed fonts to be used, studied, modified and
-redistributed freely as long as they are not sold by themselves. The
-fonts, including any derivative works, can be bundled, embedded,
-redistributed and/or sold with any software provided that any reserved
-names are not used by derivative works. The fonts and derivatives,
-however, cannot be released under any other type of license. The
-requirement for fonts to remain under this license does not apply
-to any document created using the fonts or their derivatives.
-
-DEFINITIONS
-"Font Software" refers to the set of files released by the Copyright
-Holder(s) under this license and clearly marked as such. This may
-include source files, build scripts and documentation.
-
-"Reserved Font Name" refers to any names specified as such after the
-copyright statement(s).
-
-"Original Version" refers to the collection of Font Software components as
-distributed by the Copyright Holder(s).
-
-"Modified Version" refers to any derivative made by adding to, deleting,
-or substituting -- in part or in whole -- any of the components of the
-Original Version, by changing formats or by porting the Font Software to a
-new environment.
-
-"Author" refers to any designer, engineer, programmer, technical
-writer or other person who contributed to the Font Software.
-
-PERMISSION & CONDITIONS
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of the Font Software, to use, study, copy, merge, embed, modify,
-redistribute, and sell modified and unmodified copies of the Font
-Software, subject to the following conditions:
-
-1) Neither the Font Software nor any of its individual components,
-in Original or Modified Versions, may be sold by itself.
-
-2) Original or Modified Versions of the Font Software may be bundled,
-redistributed and/or sold with any software, provided that each copy
-contains the above copyright notice and this license. These can be
-included either as stand-alone text files, human-readable headers or
-in the appropriate machine-readable metadata fields within text or
-binary files as long as those fields can be easily viewed by the user.
-
-3) No Modified Version of the Font Software may use the Reserved Font
-Name(s) unless explicit written permission is granted by the corresponding
-Copyright Holder. This restriction only applies to the primary font name as
-presented to the users.
-
-4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
-Software shall not be used to promote, endorse or advertise any
-Modified Version, except to acknowledge the contribution(s) of the
-Copyright Holder(s) and the Author(s) or with their explicit written
-permission.
-
-5) The Font Software, modified or unmodified, in part or in whole,
-must be distributed entirely under this license, and must not be
-distributed under any other license. The requirement for fonts to
-remain under this license does not apply to any document created
-using the Font Software.
-
-TERMINATION
-This license becomes null and void if any of the above conditions are
-not met.
-
-DISCLAIMER
-THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
-OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
-COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
-DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
-OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/wgpu/src/backend.rs b/wgpu/src/backend.rs new file mode 100644 index 00000000..29fc8677 --- /dev/null +++ b/wgpu/src/backend.rs @@ -0,0 +1,276 @@ +use crate::quad; +use crate::text; +use crate::triangle; +use crate::{Settings, Transformation}; +use iced_graphics::backend; +use iced_graphics::font; +use iced_graphics::layer::Layer; +use iced_graphics::{Primitive, Viewport}; +use iced_native::mouse; +use iced_native::{Font, HorizontalAlignment, Size, VerticalAlignment}; + +#[cfg(any(feature = "image", feature = "svg"))] +use crate::image; + +/// A [`wgpu`] graphics backend for [`iced`]. +/// +/// [`wgpu`]: https://github.com/gfx-rs/wgpu-rs +/// [`iced`]: https://github.com/hecrj/iced +#[derive(Debug)] +pub struct Backend { + quad_pipeline: quad::Pipeline, + text_pipeline: text::Pipeline, + triangle_pipeline: triangle::Pipeline, + + #[cfg(any(feature = "image", feature = "svg"))] + image_pipeline: image::Pipeline, +} + +impl Backend { + /// Creates a new [`Renderer`]. + /// + /// [`Renderer`]: struct.Renderer.html + pub fn new(device: &wgpu::Device, settings: Settings) -> Self { + let text_pipeline = + text::Pipeline::new(device, settings.format, settings.default_font); + let quad_pipeline = quad::Pipeline::new(device, settings.format); + let triangle_pipeline = triangle::Pipeline::new( + device, + settings.format, + settings.antialiasing, + ); + + #[cfg(any(feature = "image", feature = "svg"))] + let image_pipeline = image::Pipeline::new(device, settings.format); + + Self { + quad_pipeline, + text_pipeline, + triangle_pipeline, + + #[cfg(any(feature = "image", feature = "svg"))] + image_pipeline, + } + } + + /// Draws the provided primitives in the given [`Target`]. + /// + /// The text provided as overlay will be renderer on top of the primitives. + /// This is useful for rendering debug information. + /// + /// [`Target`]: struct.Target.html + pub fn draw<T: AsRef<str>>( + &mut self, + device: &wgpu::Device, + encoder: &mut wgpu::CommandEncoder, + frame: &wgpu::TextureView, + viewport: &Viewport, + (primitive, mouse_interaction): &(Primitive, mouse::Interaction), + overlay_text: &[T], + ) -> mouse::Interaction { + log::debug!("Drawing"); + + let target_size = viewport.physical_size(); + let scale_factor = viewport.scale_factor() as f32; + let transformation = viewport.projection(); + + let mut layers = Layer::generate(primitive, viewport); + layers.push(Layer::overlay(overlay_text, viewport)); + + for layer in layers { + self.flush( + device, + scale_factor, + transformation, + &layer, + encoder, + &frame, + target_size.width, + target_size.height, + ); + } + + #[cfg(any(feature = "image", feature = "svg"))] + self.image_pipeline.trim_cache(); + + *mouse_interaction + } + + fn flush( + &mut self, + device: &wgpu::Device, + scale_factor: f32, + transformation: Transformation, + layer: &Layer<'_>, + encoder: &mut wgpu::CommandEncoder, + target: &wgpu::TextureView, + target_width: u32, + target_height: u32, + ) { + let bounds = (layer.bounds * scale_factor).round(); + + if !layer.quads.is_empty() { + self.quad_pipeline.draw( + device, + encoder, + &layer.quads, + transformation, + scale_factor, + bounds, + target, + ); + } + + if !layer.meshes.is_empty() { + let scaled = transformation + * Transformation::scale(scale_factor, scale_factor); + + self.triangle_pipeline.draw( + device, + encoder, + target, + target_width, + target_height, + scaled, + scale_factor, + &layer.meshes, + ); + } + + #[cfg(any(feature = "image", feature = "svg"))] + { + if !layer.images.is_empty() { + let scaled = transformation + * Transformation::scale(scale_factor, scale_factor); + + self.image_pipeline.draw( + device, + encoder, + &layer.images, + scaled, + bounds, + target, + scale_factor, + ); + } + } + + if !layer.text.is_empty() { + for text in layer.text.iter() { + // Target physical coordinates directly to avoid blurry text + let text = wgpu_glyph::Section { + // TODO: We `round` here to avoid rerasterizing text when + // its position changes slightly. This can make text feel a + // bit "jumpy". We may be able to do better once we improve + // our text rendering/caching pipeline. + screen_position: ( + (text.bounds.x * scale_factor).round(), + (text.bounds.y * scale_factor).round(), + ), + // TODO: Fix precision issues with some scale factors. + // + // The `ceil` here can cause some words to render on the + // same line when they should not. + // + // Ideally, `wgpu_glyph` should be able to compute layout + // using logical positions, and then apply the proper + // scaling when rendering. This would ensure that both + // measuring and rendering follow the same layout rules. + bounds: ( + (text.bounds.width * scale_factor).ceil(), + (text.bounds.height * scale_factor).ceil(), + ), + text: vec![wgpu_glyph::Text { + text: text.content, + scale: wgpu_glyph::ab_glyph::PxScale { + x: text.size * scale_factor, + y: text.size * scale_factor, + }, + font_id: self.text_pipeline.find_font(text.font), + extra: wgpu_glyph::Extra { + color: text.color, + z: 0.0, + }, + }], + layout: wgpu_glyph::Layout::default() + .h_align(match text.horizontal_alignment { + HorizontalAlignment::Left => { + wgpu_glyph::HorizontalAlign::Left + } + HorizontalAlignment::Center => { + wgpu_glyph::HorizontalAlign::Center + } + HorizontalAlignment::Right => { + wgpu_glyph::HorizontalAlign::Right + } + }) + .v_align(match text.vertical_alignment { + VerticalAlignment::Top => { + wgpu_glyph::VerticalAlign::Top + } + VerticalAlignment::Center => { + wgpu_glyph::VerticalAlign::Center + } + VerticalAlignment::Bottom => { + wgpu_glyph::VerticalAlign::Bottom + } + }), + ..Default::default() + }; + + self.text_pipeline.queue(text); + } + + self.text_pipeline.draw_queued( + device, + encoder, + target, + transformation, + wgpu_glyph::Region { + x: bounds.x, + y: bounds.y, + width: bounds.width, + height: bounds.height, + }, + ); + } + } +} + +impl iced_graphics::Backend for Backend { + fn trim_measurements(&mut self) { + self.text_pipeline.trim_measurement_cache() + } +} + +impl backend::Text for Backend { + const ICON_FONT: Font = font::ICONS; + const CHECKMARK_ICON: char = font::CHECKMARK_ICON; + + fn measure( + &self, + contents: &str, + size: f32, + font: Font, + bounds: Size, + ) -> (f32, f32) { + self.text_pipeline.measure(contents, size, font, bounds) + } +} + +#[cfg(feature = "image")] +impl backend::Image for Backend { + fn dimensions(&self, handle: &iced_native::image::Handle) -> (u32, u32) { + self.image_pipeline.dimensions(handle) + } +} + +#[cfg(feature = "svg")] +impl backend::Svg for Backend { + fn viewport_dimensions( + &self, + handle: &iced_native::svg::Handle, + ) -> (u32, u32) { + self.image_pipeline.viewport_dimensions(handle) + } +} diff --git a/wgpu/src/defaults.rs b/wgpu/src/defaults.rs deleted file mode 100644 index 11718a87..00000000 --- a/wgpu/src/defaults.rs +++ /dev/null @@ -1,32 +0,0 @@ -//! Use default styling attributes to inherit styles. -use iced_native::Color; - -/// Some default styling attributes. -#[derive(Debug, Clone, Copy)] -pub struct Defaults { - /// Text styling - pub text: Text, -} - -impl Default for Defaults { - fn default() -> Defaults { - Defaults { - text: Text::default(), - } - } -} - -/// Some default text styling attributes. -#[derive(Debug, Clone, Copy)] -pub struct Text { - /// The default color of text - pub color: Color, -} - -impl Default for Text { - fn default() -> Text { - Text { - color: Color::BLACK, - } - } -} diff --git a/wgpu/src/image.rs b/wgpu/src/image.rs index ea5dc09d..49f1d29c 100644 --- a/wgpu/src/image.rs +++ b/wgpu/src/image.rs @@ -9,6 +9,7 @@ mod vector; use crate::Transformation; use atlas::Atlas; +use iced_graphics::layer; use iced_native::Rectangle; use std::cell::RefCell; use std::mem; @@ -282,7 +283,7 @@ impl Pipeline { &mut self, device: &wgpu::Device, encoder: &mut wgpu::CommandEncoder, - images: &[Image], + images: &[layer::Image], transformation: Transformation, bounds: Rectangle<u32>, target: &wgpu::TextureView, @@ -297,31 +298,48 @@ impl Pipeline { let mut vector_cache = self.vector_cache.borrow_mut(); for image in images { - match &image.handle { + match &image { #[cfg(feature = "image")] - Handle::Raster(handle) => { + layer::Image::Raster { handle, bounds } => { if let Some(atlas_entry) = raster_cache.upload( handle, device, encoder, &mut self.texture_atlas, ) { - add_instances(image, atlas_entry, instances); + add_instances( + [bounds.x, bounds.y], + [bounds.width, bounds.height], + atlas_entry, + instances, + ); } } + #[cfg(not(feature = "image"))] + layer::Image::Raster { .. } => {} + #[cfg(feature = "svg")] - Handle::Vector(handle) => { + layer::Image::Vector { handle, bounds } => { + let size = [bounds.width, bounds.height]; + if let Some(atlas_entry) = vector_cache.upload( handle, - image.size, + size, _scale, device, encoder, &mut self.texture_atlas, ) { - add_instances(image, atlas_entry, instances); + add_instances( + [bounds.x, bounds.y], + size, + atlas_entry, + instances, + ); } } + #[cfg(not(feature = "svg"))] + layer::Image::Vector { .. } => {} } } @@ -437,20 +455,6 @@ impl Pipeline { } } -pub struct Image { - pub handle: Handle, - pub position: [f32; 2], - pub size: [f32; 2], -} - -pub enum Handle { - #[cfg(feature = "image")] - Raster(image::Handle), - - #[cfg(feature = "svg")] - Vector(svg::Handle), -} - #[repr(C)] #[derive(Clone, Copy, AsBytes)] pub struct Vertex { @@ -495,22 +499,23 @@ struct Uniforms { } fn add_instances( - image: &Image, + image_position: [f32; 2], + image_size: [f32; 2], entry: &atlas::Entry, instances: &mut Vec<Instance>, ) { match entry { atlas::Entry::Contiguous(allocation) => { - add_instance(image.position, image.size, allocation, instances); + add_instance(image_position, image_size, allocation, instances); } atlas::Entry::Fragmented { fragments, size } => { - let scaling_x = image.size[0] / size.0 as f32; - let scaling_y = image.size[1] / size.1 as f32; + let scaling_x = image_size[0] / size.0 as f32; + let scaling_y = image_size[1] / size.1 as f32; for fragment in fragments { let allocation = &fragment.allocation; - let [x, y] = image.position; + let [x, y] = image_position; let (fragment_x, fragment_y) = fragment.position; let (fragment_width, fragment_height) = allocation.size(); diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 799c1f34..0c351eea 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -27,34 +27,31 @@ #![forbid(rust_2018_idioms)] #![cfg_attr(docsrs, feature(doc_cfg))] -pub mod defaults; pub mod settings; pub mod triangle; pub mod widget; pub mod window; -mod primitive; +mod backend; mod quad; -mod renderer; -mod target; mod text; -mod transformation; -mod viewport; +pub use iced_graphics::{Defaults, Primitive, Viewport}; pub use wgpu; -pub use defaults::Defaults; -pub use primitive::Primitive; -pub use renderer::Renderer; +pub use backend::Backend; pub use settings::Settings; -pub use target::Target; -pub use viewport::Viewport; #[doc(no_inline)] pub use widget::*; -pub(crate) use quad::Quad; -pub(crate) use transformation::Transformation; +pub(crate) use iced_graphics::Transformation; #[cfg(any(feature = "image", feature = "svg"))] mod image; + +/// A [`wgpu`] graphics renderer for [`iced`]. +/// +/// [`wgpu`]: https://github.com/gfx-rs/wgpu-rs +/// [`iced`]: https://github.com/hecrj/iced +pub type Renderer = iced_graphics::Renderer<Backend>; diff --git a/wgpu/src/primitive.rs b/wgpu/src/primitive.rs deleted file mode 100644 index e73227ef..00000000 --- a/wgpu/src/primitive.rs +++ /dev/null @@ -1,107 +0,0 @@ -use iced_native::{ - image, svg, Background, Color, Font, HorizontalAlignment, Rectangle, Size, - Vector, VerticalAlignment, -}; - -use crate::triangle; -use std::sync::Arc; - -/// A rendering primitive. -#[derive(Debug, Clone)] -pub enum Primitive { - /// An empty primitive - None, - /// A group of primitives - Group { - /// The primitives of the group - primitives: Vec<Primitive>, - }, - /// A text primitive - Text { - /// The contents of the text - content: String, - /// The bounds of the text - bounds: Rectangle, - /// The color of the text - color: Color, - /// The size of the text - size: f32, - /// The font of the text - font: Font, - /// The horizontal alignment of the text - horizontal_alignment: HorizontalAlignment, - /// The vertical alignment of the text - vertical_alignment: VerticalAlignment, - }, - /// A quad primitive - Quad { - /// The bounds of the quad - bounds: Rectangle, - /// The background of the quad - background: Background, - /// The border radius of the quad - border_radius: u16, - /// The border width of the quad - border_width: u16, - /// The border color of the quad - border_color: Color, - }, - /// An image primitive - Image { - /// The handle of the image - handle: image::Handle, - /// The bounds of the image - bounds: Rectangle, - }, - /// An SVG primitive - Svg { - /// The path of the SVG file - handle: svg::Handle, - - /// The bounds of the viewport - bounds: Rectangle, - }, - /// A clip primitive - Clip { - /// The bounds of the clip - bounds: Rectangle, - /// The offset transformation of the clip - offset: Vector<u32>, - /// 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 low-level primitive to render a mesh of triangles. - /// - /// It can be used to render many kinds of geometry freely. - Mesh2D { - /// The size of the drawable region of the mesh. - /// - /// Any geometry that falls out of this region will be clipped. - size: Size, - - /// The vertex and index buffers of the mesh - buffers: triangle::Mesh2D, - }, - /// 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>, - }, -} - -impl Default for Primitive { - fn default() -> Primitive { - Primitive::None - } -} diff --git a/wgpu/src/quad.rs b/wgpu/src/quad.rs index 0c2d2244..0b62f44f 100644 --- a/wgpu/src/quad.rs +++ b/wgpu/src/quad.rs @@ -1,4 +1,5 @@ use crate::Transformation; +use iced_graphics::layer; use iced_native::Rectangle; use std::mem; @@ -107,7 +108,7 @@ impl Pipeline { }], }, wgpu::VertexBufferDescriptor { - stride: mem::size_of::<Quad>() as u64, + stride: mem::size_of::<layer::Quad>() as u64, step_mode: wgpu::InputStepMode::Instance, attributes: &[ wgpu::VertexAttributeDescriptor { @@ -161,7 +162,7 @@ impl Pipeline { let instances = device.create_buffer(&wgpu::BufferDescriptor { label: None, - size: mem::size_of::<Quad>() as u64 * Quad::MAX as u64, + size: mem::size_of::<layer::Quad>() as u64 * MAX_INSTANCES as u64, usage: wgpu::BufferUsage::VERTEX | wgpu::BufferUsage::COPY_DST, }); @@ -179,7 +180,7 @@ impl Pipeline { &mut self, device: &wgpu::Device, encoder: &mut wgpu::CommandEncoder, - instances: &[Quad], + instances: &[layer::Quad], transformation: Transformation, scale: f32, bounds: Rectangle<u32>, @@ -204,11 +205,11 @@ impl Pipeline { let total = instances.len(); while i < total { - let end = (i + Quad::MAX).min(total); + let end = (i + MAX_INSTANCES).min(total); let amount = end - i; let instance_buffer = device.create_buffer_with_data( - &instances[i..end].as_bytes(), + bytemuck::cast_slice(&instances[i..end]), wgpu::BufferUsage::COPY_SRC, ); @@ -217,7 +218,7 @@ impl Pipeline { 0, &self.instances, 0, - (mem::size_of::<Quad>() * amount) as u64, + (mem::size_of::<layer::Quad>() * amount) as u64, ); { @@ -260,7 +261,7 @@ impl Pipeline { ); } - i += Quad::MAX; + i += MAX_INSTANCES; } } } @@ -288,20 +289,7 @@ const QUAD_VERTS: [Vertex; 4] = [ }, ]; -#[repr(C)] -#[derive(Debug, Clone, Copy, AsBytes)] -pub struct Quad { - pub position: [f32; 2], - pub scale: [f32; 2], - pub color: [f32; 4], - pub border_color: [f32; 4], - pub border_radius: f32, - pub border_width: f32, -} - -impl Quad { - const MAX: usize = 100_000; -} +const MAX_INSTANCES: usize = 100_000; #[repr(C)] #[derive(Debug, Clone, Copy, AsBytes)] diff --git a/wgpu/src/renderer.rs b/wgpu/src/renderer.rs deleted file mode 100644 index f3a7c288..00000000 --- a/wgpu/src/renderer.rs +++ /dev/null @@ -1,524 +0,0 @@ -use crate::{ - quad, text, triangle, Defaults, Primitive, Quad, Settings, Target, - Transformation, -}; - -#[cfg(any(feature = "image", feature = "svg"))] -use crate::image::{self, Image}; - -use iced_native::{ - layout, mouse, Background, Color, Font, HorizontalAlignment, Layout, Point, - Rectangle, Size, Vector, VerticalAlignment, Widget, -}; - -mod widget; - -/// A [`wgpu`] renderer. -/// -/// [`wgpu`]: https://github.com/gfx-rs/wgpu-rs -#[derive(Debug)] -pub struct Renderer { - quad_pipeline: quad::Pipeline, - text_pipeline: text::Pipeline, - triangle_pipeline: triangle::Pipeline, - - #[cfg(any(feature = "image", feature = "svg"))] - image_pipeline: image::Pipeline, -} - -struct Layer<'a> { - bounds: Rectangle<u32>, - quads: Vec<Quad>, - meshes: Vec<(Vector, Rectangle<u32>, &'a triangle::Mesh2D)>, - text: Vec<Text<'a>>, - - #[cfg(any(feature = "image", feature = "svg"))] - images: Vec<Image>, -} - -#[derive(Debug, Clone, Copy)] -pub struct Text<'a> { - pub content: &'a str, - pub bounds: Rectangle, - pub color: [f32; 4], - pub size: f32, - pub font: Font, - pub horizontal_alignment: HorizontalAlignment, - pub vertical_alignment: VerticalAlignment, -} - -impl<'a> Layer<'a> { - pub fn new(bounds: Rectangle<u32>) -> Self { - Self { - bounds, - quads: Vec::new(), - text: Vec::new(), - meshes: Vec::new(), - - #[cfg(any(feature = "image", feature = "svg"))] - images: Vec::new(), - } - } - - pub fn intersection(&self, rectangle: Rectangle) -> Option<Rectangle<u32>> { - let layer_bounds: Rectangle<f32> = self.bounds.into(); - - layer_bounds.intersection(&rectangle).map(Into::into) - } -} - -impl Renderer { - /// Creates a new [`Renderer`]. - /// - /// [`Renderer`]: struct.Renderer.html - pub fn new(device: &wgpu::Device, settings: Settings) -> Self { - let text_pipeline = - text::Pipeline::new(device, settings.format, settings.default_font); - let quad_pipeline = quad::Pipeline::new(device, settings.format); - let triangle_pipeline = triangle::Pipeline::new( - device, - settings.format, - settings.antialiasing, - ); - - #[cfg(any(feature = "image", feature = "svg"))] - let image_pipeline = image::Pipeline::new(device, settings.format); - - Self { - quad_pipeline, - text_pipeline, - triangle_pipeline, - - #[cfg(any(feature = "image", feature = "svg"))] - image_pipeline, - } - } - - /// Draws the provided primitives in the given [`Target`]. - /// - /// The text provided as overlay will be renderer on top of the primitives. - /// This is useful for rendering debug information. - /// - /// [`Target`]: struct.Target.html - pub fn draw<T: AsRef<str>>( - &mut self, - device: &wgpu::Device, - encoder: &mut wgpu::CommandEncoder, - target: Target<'_>, - (primitive, mouse_interaction): &(Primitive, mouse::Interaction), - scale_factor: f64, - overlay: &[T], - ) -> mouse::Interaction { - log::debug!("Drawing"); - - let (width, height) = target.viewport.dimensions(); - let scale_factor = scale_factor as f32; - let transformation = target.viewport.transformation(); - - let mut layers = Vec::new(); - - layers.push(Layer::new(Rectangle { - x: 0, - y: 0, - width, - height, - })); - - self.draw_primitive(Vector::new(0.0, 0.0), primitive, &mut layers); - self.draw_overlay(overlay, &mut layers); - - for layer in layers { - self.flush( - device, - scale_factor, - transformation, - &layer, - encoder, - target.texture, - width, - height, - ); - } - - #[cfg(any(feature = "image", feature = "svg"))] - self.image_pipeline.trim_cache(); - - *mouse_interaction - } - - fn draw_primitive<'a>( - &mut self, - translation: Vector, - primitive: &'a Primitive, - layers: &mut Vec<Layer<'a>>, - ) { - match primitive { - Primitive::None => {} - Primitive::Group { primitives } => { - // TODO: Inspect a bit and regroup (?) - for primitive in primitives { - self.draw_primitive(translation, primitive, layers) - } - } - Primitive::Text { - content, - bounds, - size, - color, - font, - horizontal_alignment, - vertical_alignment, - } => { - let layer = layers.last_mut().unwrap(); - - layer.text.push(Text { - content, - bounds: *bounds + translation, - size: *size, - color: color.into_linear(), - font: *font, - horizontal_alignment: *horizontal_alignment, - vertical_alignment: *vertical_alignment, - }); - } - Primitive::Quad { - bounds, - background, - border_radius, - border_width, - border_color, - } => { - let layer = layers.last_mut().unwrap(); - - // TODO: Move some of these computations to the GPU (?) - layer.quads.push(Quad { - position: [ - bounds.x + translation.x, - bounds.y + translation.y, - ], - scale: [bounds.width, bounds.height], - color: match background { - Background::Color(color) => color.into_linear(), - }, - border_radius: *border_radius as f32, - border_width: *border_width as f32, - border_color: border_color.into_linear(), - }); - } - Primitive::Mesh2D { size, buffers } => { - let layer = layers.last_mut().unwrap(); - - // Only draw visible content - if let Some(clip_bounds) = layer.intersection(Rectangle::new( - Point::new(translation.x, translation.y), - *size, - )) { - layer.meshes.push(( - translation, - clip_bounds.into(), - buffers, - )); - } - } - Primitive::Clip { - bounds, - offset, - content, - } => { - let layer = layers.last_mut().unwrap(); - - // Only draw visible content - if let Some(clip_bounds) = - layer.intersection(*bounds + translation) - { - let clip_layer = Layer::new(clip_bounds.into()); - let new_layer = Layer::new(layer.bounds); - - layers.push(clip_layer); - self.draw_primitive( - translation - - Vector::new(offset.x as f32, offset.y as f32), - content, - layers, - ); - layers.push(new_layer); - } - } - Primitive::Translate { - translation: new_translation, - content, - } => { - self.draw_primitive( - translation + *new_translation, - &content, - layers, - ); - } - - Primitive::Cached { cache } => { - self.draw_primitive(translation, &cache, layers); - } - - #[cfg(feature = "image")] - Primitive::Image { handle, bounds } => { - let layer = layers.last_mut().unwrap(); - - layer.images.push(Image { - handle: image::Handle::Raster(handle.clone()), - position: [ - bounds.x + translation.x, - bounds.y + translation.y, - ], - size: [bounds.width, bounds.height], - }); - } - #[cfg(not(feature = "image"))] - Primitive::Image { .. } => {} - - #[cfg(feature = "svg")] - Primitive::Svg { handle, bounds } => { - let layer = layers.last_mut().unwrap(); - - layer.images.push(Image { - handle: image::Handle::Vector(handle.clone()), - position: [ - bounds.x + translation.x, - bounds.y + translation.y, - ], - size: [bounds.width, bounds.height], - }); - } - #[cfg(not(feature = "svg"))] - Primitive::Svg { .. } => {} - } - } - - fn draw_overlay<'a, T: AsRef<str>>( - &mut self, - lines: &'a [T], - layers: &mut Vec<Layer<'a>>, - ) { - let first = layers.first().unwrap(); - let mut overlay = Layer::new(first.bounds); - - for (i, line) in lines.iter().enumerate() { - let text = Text { - content: line.as_ref(), - bounds: Rectangle::new( - Point::new(11.0, 11.0 + 25.0 * i as f32), - Size::INFINITY, - ), - color: [0.9, 0.9, 0.9, 1.0], - size: 20.0, - font: Font::Default, - horizontal_alignment: HorizontalAlignment::Left, - vertical_alignment: VerticalAlignment::Top, - }; - - overlay.text.push(text); - - overlay.text.push(Text { - bounds: text.bounds + Vector::new(-1.0, -1.0), - color: [0.0, 0.0, 0.0, 1.0], - ..text - }); - } - - layers.push(overlay); - } - - fn flush( - &mut self, - device: &wgpu::Device, - scale_factor: f32, - transformation: Transformation, - layer: &Layer<'_>, - encoder: &mut wgpu::CommandEncoder, - target: &wgpu::TextureView, - target_width: u32, - target_height: u32, - ) { - let bounds = layer.bounds * scale_factor; - - if !layer.quads.is_empty() { - self.quad_pipeline.draw( - device, - encoder, - &layer.quads, - transformation, - scale_factor, - bounds, - target, - ); - } - - if !layer.meshes.is_empty() { - let scaled = transformation - * Transformation::scale(scale_factor, scale_factor); - - self.triangle_pipeline.draw( - device, - encoder, - target, - target_width, - target_height, - scaled, - scale_factor, - &layer.meshes, - ); - } - - #[cfg(any(feature = "image", feature = "svg"))] - { - if !layer.images.is_empty() { - let scaled = transformation - * Transformation::scale(scale_factor, scale_factor); - - self.image_pipeline.draw( - device, - encoder, - &layer.images, - scaled, - bounds, - target, - scale_factor, - ); - } - } - - if !layer.text.is_empty() { - for text in layer.text.iter() { - // Target physical coordinates directly to avoid blurry text - let text = wgpu_glyph::Section { - // TODO: We `round` here to avoid rerasterizing text when - // its position changes slightly. This can make text feel a - // bit "jumpy". We may be able to do better once we improve - // our text rendering/caching pipeline. - screen_position: ( - (text.bounds.x * scale_factor).round(), - (text.bounds.y * scale_factor).round(), - ), - // TODO: Fix precision issues with some scale factors. - // - // The `ceil` here can cause some words to render on the - // same line when they should not. - // - // Ideally, `wgpu_glyph` should be able to compute layout - // using logical positions, and then apply the proper - // scaling when rendering. This would ensure that both - // measuring and rendering follow the same layout rules. - bounds: ( - (text.bounds.width * scale_factor).ceil(), - (text.bounds.height * scale_factor).ceil(), - ), - text: vec![wgpu_glyph::Text { - text: text.content, - scale: wgpu_glyph::ab_glyph::PxScale { - x: text.size * scale_factor, - y: text.size * scale_factor, - }, - font_id: self.text_pipeline.find_font(text.font), - extra: wgpu_glyph::Extra { - color: text.color, - z: 0.0, - }, - }], - layout: wgpu_glyph::Layout::default() - .h_align(match text.horizontal_alignment { - HorizontalAlignment::Left => { - wgpu_glyph::HorizontalAlign::Left - } - HorizontalAlignment::Center => { - wgpu_glyph::HorizontalAlign::Center - } - HorizontalAlignment::Right => { - wgpu_glyph::HorizontalAlign::Right - } - }) - .v_align(match text.vertical_alignment { - VerticalAlignment::Top => { - wgpu_glyph::VerticalAlign::Top - } - VerticalAlignment::Center => { - wgpu_glyph::VerticalAlign::Center - } - VerticalAlignment::Bottom => { - wgpu_glyph::VerticalAlign::Bottom - } - }), - ..Default::default() - }; - - self.text_pipeline.queue(text); - } - - self.text_pipeline.draw_queued( - device, - encoder, - target, - transformation, - wgpu_glyph::Region { - x: bounds.x, - y: bounds.y, - width: bounds.width, - height: bounds.height, - }, - ); - } - } -} - -impl iced_native::Renderer for Renderer { - type Output = (Primitive, mouse::Interaction); - type Defaults = Defaults; - - fn layout<'a, Message>( - &mut self, - element: &iced_native::Element<'a, Message, Self>, - limits: &iced_native::layout::Limits, - ) -> iced_native::layout::Node { - let node = element.layout(self, limits); - - self.text_pipeline.clear_measurement_cache(); - - node - } -} - -impl layout::Debugger for Renderer { - fn explain<Message>( - &mut self, - defaults: &Defaults, - widget: &dyn Widget<Message, Self>, - layout: Layout<'_>, - cursor_position: Point, - color: Color, - ) -> Self::Output { - let mut primitives = Vec::new(); - let (primitive, cursor) = - widget.draw(self, defaults, layout, cursor_position); - - explain_layout(layout, color, &mut primitives); - primitives.push(primitive); - - (Primitive::Group { primitives }, cursor) - } -} - -fn explain_layout( - layout: Layout<'_>, - color: Color, - primitives: &mut Vec<Primitive>, -) { - primitives.push(Primitive::Quad { - bounds: layout.bounds(), - background: Background::Color(Color::TRANSPARENT), - border_radius: 0, - border_width: 1, - border_color: [0.6, 0.6, 0.6, 0.5].into(), - }); - - for child in layout.children() { - explain_layout(child, color, primitives); - } -} diff --git a/wgpu/src/renderer/widget.rs b/wgpu/src/renderer/widget.rs deleted file mode 100644 index 37421fbe..00000000 --- a/wgpu/src/renderer/widget.rs +++ /dev/null @@ -1,19 +0,0 @@ -mod button; -mod checkbox; -mod column; -mod container; -mod pane_grid; -mod progress_bar; -mod radio; -mod row; -mod scrollable; -mod slider; -mod space; -mod text; -mod text_input; - -#[cfg(feature = "svg")] -mod svg; - -#[cfg(feature = "image")] -mod image; diff --git a/wgpu/src/renderer/widget/button.rs b/wgpu/src/renderer/widget/button.rs deleted file mode 100644 index eb225038..00000000 --- a/wgpu/src/renderer/widget/button.rs +++ /dev/null @@ -1,93 +0,0 @@ -use crate::{button::StyleSheet, defaults, Defaults, Primitive, Renderer}; -use iced_native::{ - mouse, Background, Color, Element, Layout, Point, Rectangle, Vector, -}; - -impl iced_native::button::Renderer for Renderer { - const DEFAULT_PADDING: u16 = 5; - - type Style = Box<dyn StyleSheet>; - - fn draw<Message>( - &mut self, - _defaults: &Defaults, - bounds: Rectangle, - cursor_position: Point, - is_disabled: bool, - is_pressed: bool, - style: &Box<dyn StyleSheet>, - content: &Element<'_, Message, Self>, - content_layout: Layout<'_>, - ) -> Self::Output { - let is_mouse_over = bounds.contains(cursor_position); - - let styling = if is_disabled { - style.disabled() - } else if is_mouse_over { - if is_pressed { - style.pressed() - } else { - style.hovered() - } - } else { - style.active() - }; - - let (content, _) = content.draw( - self, - &Defaults { - text: defaults::Text { - color: styling.text_color, - }, - }, - content_layout, - cursor_position, - ); - - ( - if styling.background.is_some() || styling.border_width > 0 { - let background = Primitive::Quad { - bounds, - background: styling - .background - .unwrap_or(Background::Color(Color::TRANSPARENT)), - border_radius: styling.border_radius, - border_width: styling.border_width, - border_color: styling.border_color, - }; - - if styling.shadow_offset == Vector::default() { - Primitive::Group { - primitives: vec![background, content], - } - } else { - // TODO: Implement proper shadow support - let shadow = Primitive::Quad { - bounds: Rectangle { - x: bounds.x + styling.shadow_offset.x, - y: bounds.y + styling.shadow_offset.y, - ..bounds - }, - background: Background::Color( - [0.0, 0.0, 0.0, 0.5].into(), - ), - border_radius: styling.border_radius, - border_width: 0, - border_color: Color::TRANSPARENT, - }; - - Primitive::Group { - primitives: vec![shadow, background, content], - } - } - } else { - content - }, - if is_mouse_over { - mouse::Interaction::Pointer - } else { - mouse::Interaction::default() - }, - ) - } -} diff --git a/wgpu/src/renderer/widget/checkbox.rs b/wgpu/src/renderer/widget/checkbox.rs deleted file mode 100644 index 0340bf62..00000000 --- a/wgpu/src/renderer/widget/checkbox.rs +++ /dev/null @@ -1,63 +0,0 @@ -use crate::{checkbox::StyleSheet, Primitive, Renderer}; -use iced_native::{ - checkbox, mouse, HorizontalAlignment, Rectangle, VerticalAlignment, -}; - -impl checkbox::Renderer for Renderer { - type Style = Box<dyn StyleSheet>; - - const DEFAULT_SIZE: u16 = 20; - const DEFAULT_SPACING: u16 = 15; - - fn draw( - &mut self, - bounds: Rectangle, - is_checked: bool, - is_mouse_over: bool, - (label, _): Self::Output, - style_sheet: &Self::Style, - ) -> Self::Output { - let style = if is_mouse_over { - style_sheet.hovered(is_checked) - } else { - style_sheet.active(is_checked) - }; - - let checkbox = Primitive::Quad { - bounds, - background: style.background, - border_radius: style.border_radius, - border_width: style.border_width, - border_color: style.border_color, - }; - - ( - Primitive::Group { - primitives: if is_checked { - let check = Primitive::Text { - content: crate::text::CHECKMARK_ICON.to_string(), - font: crate::text::BUILTIN_ICONS, - size: bounds.height * 0.7, - bounds: Rectangle { - x: bounds.center_x(), - y: bounds.center_y(), - ..bounds - }, - color: style.checkmark_color, - horizontal_alignment: HorizontalAlignment::Center, - vertical_alignment: VerticalAlignment::Center, - }; - - vec![checkbox, check, label] - } else { - vec![checkbox, label] - }, - }, - if is_mouse_over { - mouse::Interaction::Pointer - } else { - mouse::Interaction::default() - }, - ) - } -} diff --git a/wgpu/src/renderer/widget/column.rs b/wgpu/src/renderer/widget/column.rs deleted file mode 100644 index b853276d..00000000 --- a/wgpu/src/renderer/widget/column.rs +++ /dev/null @@ -1,34 +0,0 @@ -use crate::{Primitive, Renderer}; -use iced_native::{column, mouse, Element, Layout, Point}; - -impl column::Renderer for Renderer { - fn draw<Message>( - &mut self, - defaults: &Self::Defaults, - content: &[Element<'_, Message, Self>], - layout: Layout<'_>, - cursor_position: Point, - ) -> Self::Output { - let mut mouse_interaction = mouse::Interaction::default(); - - ( - Primitive::Group { - primitives: content - .iter() - .zip(layout.children()) - .map(|(child, layout)| { - let (primitive, new_mouse_interaction) = - child.draw(self, defaults, layout, cursor_position); - - if new_mouse_interaction > mouse_interaction { - mouse_interaction = new_mouse_interaction; - } - - primitive - }) - .collect(), - }, - mouse_interaction, - ) - } -} diff --git a/wgpu/src/renderer/widget/container.rs b/wgpu/src/renderer/widget/container.rs deleted file mode 100644 index 30cc3f07..00000000 --- a/wgpu/src/renderer/widget/container.rs +++ /dev/null @@ -1,48 +0,0 @@ -use crate::{container, defaults, Defaults, Primitive, Renderer}; -use iced_native::{Background, Color, Element, Layout, Point, Rectangle}; - -impl iced_native::container::Renderer for Renderer { - type Style = Box<dyn container::StyleSheet>; - - fn draw<Message>( - &mut self, - defaults: &Defaults, - bounds: Rectangle, - cursor_position: Point, - style_sheet: &Self::Style, - content: &Element<'_, Message, Self>, - content_layout: Layout<'_>, - ) -> Self::Output { - let style = style_sheet.style(); - - let defaults = Defaults { - text: defaults::Text { - color: style.text_color.unwrap_or(defaults.text.color), - }, - }; - - let (content, mouse_interaction) = - content.draw(self, &defaults, content_layout, cursor_position); - - if style.background.is_some() || style.border_width > 0 { - let quad = Primitive::Quad { - bounds, - background: style - .background - .unwrap_or(Background::Color(Color::TRANSPARENT)), - border_radius: style.border_radius, - border_width: style.border_width, - border_color: style.border_color, - }; - - ( - Primitive::Group { - primitives: vec![quad, content], - }, - mouse_interaction, - ) - } else { - (content, mouse_interaction) - } - } -} diff --git a/wgpu/src/renderer/widget/image.rs b/wgpu/src/renderer/widget/image.rs deleted file mode 100644 index c4c04984..00000000 --- a/wgpu/src/renderer/widget/image.rs +++ /dev/null @@ -1,22 +0,0 @@ -use crate::{Primitive, Renderer}; -use iced_native::{image, mouse, Layout}; - -impl image::Renderer for Renderer { - fn dimensions(&self, handle: &image::Handle) -> (u32, u32) { - self.image_pipeline.dimensions(handle) - } - - fn draw( - &mut self, - handle: image::Handle, - layout: Layout<'_>, - ) -> Self::Output { - ( - Primitive::Image { - handle, - bounds: layout.bounds(), - }, - mouse::Interaction::default(), - ) - } -} diff --git a/wgpu/src/renderer/widget/pane_grid.rs b/wgpu/src/renderer/widget/pane_grid.rs deleted file mode 100644 index 2253e4af..00000000 --- a/wgpu/src/renderer/widget/pane_grid.rs +++ /dev/null @@ -1,93 +0,0 @@ -use crate::{Primitive, Renderer}; -use iced_native::{ - mouse, - pane_grid::{self, Axis, Pane}, - Element, Layout, Point, Rectangle, Vector, -}; - -impl pane_grid::Renderer for Renderer { - fn draw<Message>( - &mut self, - defaults: &Self::Defaults, - content: &[(Pane, Element<'_, Message, Self>)], - dragging: Option<Pane>, - resizing: Option<Axis>, - layout: Layout<'_>, - cursor_position: Point, - ) -> Self::Output { - let pane_cursor_position = if dragging.is_some() { - // TODO: Remove once cursor availability is encoded in the type - // system - Point::new(-1.0, -1.0) - } else { - cursor_position - }; - - let mut mouse_interaction = mouse::Interaction::default(); - let mut dragged_pane = None; - - let mut panes: Vec<_> = content - .iter() - .zip(layout.children()) - .enumerate() - .map(|(i, ((id, pane), layout))| { - let (primitive, new_mouse_interaction) = - pane.draw(self, defaults, layout, pane_cursor_position); - - if new_mouse_interaction > mouse_interaction { - mouse_interaction = new_mouse_interaction; - } - - if Some(*id) == dragging { - dragged_pane = Some((i, layout)); - } - - primitive - }) - .collect(); - - let primitives = if let Some((index, layout)) = dragged_pane { - let pane = panes.remove(index); - let bounds = layout.bounds(); - - // TODO: Fix once proper layering is implemented. - // This is a pretty hacky way to achieve layering. - let clip = Primitive::Clip { - bounds: Rectangle { - x: cursor_position.x - bounds.width / 2.0, - y: cursor_position.y - bounds.height / 2.0, - width: bounds.width + 0.5, - height: bounds.height + 0.5, - }, - offset: Vector::new(0, 0), - content: Box::new(Primitive::Translate { - translation: Vector::new( - cursor_position.x - bounds.x - bounds.width / 2.0, - cursor_position.y - bounds.y - bounds.height / 2.0, - ), - content: Box::new(pane), - }), - }; - - panes.push(clip); - - panes - } else { - panes - }; - - ( - Primitive::Group { primitives }, - if dragging.is_some() { - mouse::Interaction::Grabbing - } else if let Some(axis) = resizing { - match axis { - Axis::Horizontal => mouse::Interaction::ResizingVertically, - Axis::Vertical => mouse::Interaction::ResizingHorizontally, - } - } else { - mouse_interaction - }, - ) - } -} diff --git a/wgpu/src/renderer/widget/progress_bar.rs b/wgpu/src/renderer/widget/progress_bar.rs deleted file mode 100644 index 2baeeb14..00000000 --- a/wgpu/src/renderer/widget/progress_bar.rs +++ /dev/null @@ -1,54 +0,0 @@ -use crate::{progress_bar::StyleSheet, Primitive, Renderer}; -use iced_native::{mouse, progress_bar, Color, Rectangle}; - -impl progress_bar::Renderer for Renderer { - type Style = Box<dyn StyleSheet>; - - const DEFAULT_HEIGHT: u16 = 30; - - fn draw( - &self, - bounds: Rectangle, - range: std::ops::RangeInclusive<f32>, - value: f32, - style_sheet: &Self::Style, - ) -> Self::Output { - let style = style_sheet.style(); - - let (range_start, range_end) = range.into_inner(); - let active_progress_width = bounds.width - * ((value - range_start) / (range_end - range_start).max(1.0)); - - let background = Primitive::Group { - primitives: vec![Primitive::Quad { - bounds: Rectangle { ..bounds }, - background: style.background, - border_radius: style.border_radius, - border_width: 0, - border_color: Color::TRANSPARENT, - }], - }; - - ( - if active_progress_width > 0.0 { - let bar = Primitive::Quad { - bounds: Rectangle { - width: active_progress_width, - ..bounds - }, - background: style.bar, - border_radius: style.border_radius, - border_width: 0, - border_color: Color::TRANSPARENT, - }; - - Primitive::Group { - primitives: vec![background, bar], - } - } else { - background - }, - mouse::Interaction::default(), - ) - } -} diff --git a/wgpu/src/renderer/widget/radio.rs b/wgpu/src/renderer/widget/radio.rs deleted file mode 100644 index cee0deb6..00000000 --- a/wgpu/src/renderer/widget/radio.rs +++ /dev/null @@ -1,63 +0,0 @@ -use crate::{radio::StyleSheet, Primitive, Renderer}; -use iced_native::{mouse, radio, Background, Color, Rectangle}; - -const SIZE: f32 = 28.0; -const DOT_SIZE: f32 = SIZE / 2.0; - -impl radio::Renderer for Renderer { - type Style = Box<dyn StyleSheet>; - - const DEFAULT_SIZE: u16 = SIZE as u16; - const DEFAULT_SPACING: u16 = 15; - - fn draw( - &mut self, - bounds: Rectangle, - is_selected: bool, - is_mouse_over: bool, - (label, _): Self::Output, - style_sheet: &Self::Style, - ) -> Self::Output { - let style = if is_mouse_over { - style_sheet.hovered() - } else { - style_sheet.active() - }; - - let radio = Primitive::Quad { - bounds, - background: style.background, - border_radius: (SIZE / 2.0) as u16, - border_width: style.border_width, - border_color: style.border_color, - }; - - ( - Primitive::Group { - primitives: if is_selected { - let radio_circle = Primitive::Quad { - bounds: Rectangle { - x: bounds.x + DOT_SIZE / 2.0, - y: bounds.y + DOT_SIZE / 2.0, - width: bounds.width - DOT_SIZE, - height: bounds.height - DOT_SIZE, - }, - background: Background::Color(style.dot_color), - border_radius: (DOT_SIZE / 2.0) as u16, - border_width: 0, - border_color: Color::TRANSPARENT, - }; - - vec![radio, radio_circle, label] - } else { - vec![radio, label] - }, - }, - if is_mouse_over { - mouse::Interaction::Pointer - } else { - mouse::Interaction::default() - }, - ) - } -} diff --git a/wgpu/src/renderer/widget/row.rs b/wgpu/src/renderer/widget/row.rs deleted file mode 100644 index d0b7ef09..00000000 --- a/wgpu/src/renderer/widget/row.rs +++ /dev/null @@ -1,34 +0,0 @@ -use crate::{Primitive, Renderer}; -use iced_native::{mouse, row, Element, Layout, Point}; - -impl row::Renderer for Renderer { - fn draw<Message>( - &mut self, - defaults: &Self::Defaults, - children: &[Element<'_, Message, Self>], - layout: Layout<'_>, - cursor_position: Point, - ) -> Self::Output { - let mut mouse_interaction = mouse::Interaction::default(); - - ( - Primitive::Group { - primitives: children - .iter() - .zip(layout.children()) - .map(|(child, layout)| { - let (primitive, new_mouse_interaction) = - child.draw(self, defaults, layout, cursor_position); - - if new_mouse_interaction > mouse_interaction { - mouse_interaction = new_mouse_interaction; - } - - primitive - }) - .collect(), - }, - mouse_interaction, - ) - } -} diff --git a/wgpu/src/renderer/widget/scrollable.rs b/wgpu/src/renderer/widget/scrollable.rs deleted file mode 100644 index 8a400b82..00000000 --- a/wgpu/src/renderer/widget/scrollable.rs +++ /dev/null @@ -1,125 +0,0 @@ -use crate::{Primitive, Renderer}; -use iced_native::{mouse, scrollable, Background, Color, Rectangle, Vector}; - -const SCROLLBAR_WIDTH: u16 = 10; -const SCROLLBAR_MARGIN: u16 = 2; - -impl scrollable::Renderer for Renderer { - type Style = Box<dyn iced_style::scrollable::StyleSheet>; - - fn scrollbar( - &self, - bounds: Rectangle, - content_bounds: Rectangle, - offset: u32, - ) -> Option<scrollable::Scrollbar> { - if content_bounds.height > bounds.height { - let scrollbar_bounds = Rectangle { - x: bounds.x + bounds.width - - f32::from(SCROLLBAR_WIDTH + 2 * SCROLLBAR_MARGIN), - y: bounds.y, - width: f32::from(SCROLLBAR_WIDTH + 2 * SCROLLBAR_MARGIN), - height: bounds.height, - }; - - let ratio = bounds.height / content_bounds.height; - let scrollbar_height = bounds.height * ratio; - let y_offset = offset as f32 * ratio; - - let scroller_bounds = Rectangle { - x: scrollbar_bounds.x + f32::from(SCROLLBAR_MARGIN), - y: scrollbar_bounds.y + y_offset, - width: scrollbar_bounds.width - f32::from(2 * SCROLLBAR_MARGIN), - height: scrollbar_height, - }; - - Some(scrollable::Scrollbar { - bounds: scrollbar_bounds, - scroller: scrollable::Scroller { - bounds: scroller_bounds, - }, - }) - } else { - None - } - } - - fn draw( - &mut self, - state: &scrollable::State, - bounds: Rectangle, - _content_bounds: Rectangle, - is_mouse_over: bool, - is_mouse_over_scrollbar: bool, - scrollbar: Option<scrollable::Scrollbar>, - offset: u32, - style_sheet: &Self::Style, - (content, mouse_interaction): Self::Output, - ) -> Self::Output { - ( - if let Some(scrollbar) = scrollbar { - let clip = Primitive::Clip { - bounds, - offset: Vector::new(0, offset), - content: Box::new(content), - }; - - let style = if state.is_scroller_grabbed() { - style_sheet.dragging() - } else if is_mouse_over_scrollbar { - style_sheet.hovered() - } else { - style_sheet.active() - }; - - let is_scrollbar_visible = - style.background.is_some() || style.border_width > 0; - - let scroller = if is_mouse_over - || state.is_scroller_grabbed() - || is_scrollbar_visible - { - Primitive::Quad { - bounds: scrollbar.scroller.bounds, - background: Background::Color(style.scroller.color), - border_radius: style.scroller.border_radius, - border_width: style.scroller.border_width, - border_color: style.scroller.border_color, - } - } else { - Primitive::None - }; - - let scrollbar = if is_scrollbar_visible { - Primitive::Quad { - bounds: Rectangle { - x: scrollbar.bounds.x + f32::from(SCROLLBAR_MARGIN), - width: scrollbar.bounds.width - - f32::from(2 * SCROLLBAR_MARGIN), - ..scrollbar.bounds - }, - background: style - .background - .unwrap_or(Background::Color(Color::TRANSPARENT)), - border_radius: style.border_radius, - border_width: style.border_width, - border_color: style.border_color, - } - } else { - Primitive::None - }; - - Primitive::Group { - primitives: vec![clip, scrollbar, scroller], - } - } else { - content - }, - if is_mouse_over_scrollbar || state.is_scroller_grabbed() { - mouse::Interaction::Idle - } else { - mouse_interaction - }, - ) - } -} diff --git a/wgpu/src/renderer/widget/slider.rs b/wgpu/src/renderer/widget/slider.rs deleted file mode 100644 index 220feace..00000000 --- a/wgpu/src/renderer/widget/slider.rs +++ /dev/null @@ -1,106 +0,0 @@ -use crate::{ - slider::{HandleShape, StyleSheet}, - Primitive, Renderer, -}; -use iced_native::{mouse, slider, Background, Color, Point, Rectangle}; - -const HANDLE_HEIGHT: f32 = 22.0; - -impl slider::Renderer for Renderer { - type Style = Box<dyn StyleSheet>; - - fn height(&self) -> u32 { - 30 - } - - fn draw( - &mut self, - bounds: Rectangle, - cursor_position: Point, - range: std::ops::RangeInclusive<f32>, - value: f32, - is_dragging: bool, - style_sheet: &Self::Style, - ) -> Self::Output { - let is_mouse_over = bounds.contains(cursor_position); - - let style = if is_dragging { - style_sheet.dragging() - } else if is_mouse_over { - style_sheet.hovered() - } else { - style_sheet.active() - }; - - let rail_y = bounds.y + (bounds.height / 2.0).round(); - - let (rail_top, rail_bottom) = ( - Primitive::Quad { - bounds: Rectangle { - x: bounds.x, - y: rail_y, - width: bounds.width, - height: 2.0, - }, - background: Background::Color(style.rail_colors.0), - border_radius: 0, - border_width: 0, - border_color: Color::TRANSPARENT, - }, - Primitive::Quad { - bounds: Rectangle { - x: bounds.x, - y: rail_y + 2.0, - width: bounds.width, - height: 2.0, - }, - background: Background::Color(style.rail_colors.1), - border_radius: 0, - border_width: 0, - border_color: Color::TRANSPARENT, - }, - ); - - let (range_start, range_end) = range.into_inner(); - - let (handle_width, handle_height, handle_border_radius) = - match style.handle.shape { - HandleShape::Circle { radius } => { - (f32::from(radius * 2), f32::from(radius * 2), radius) - } - HandleShape::Rectangle { - width, - border_radius, - } => (f32::from(width), HANDLE_HEIGHT, border_radius), - }; - - let handle_offset = (bounds.width - handle_width) - * ((value - range_start) / (range_end - range_start).max(1.0)); - - let handle = Primitive::Quad { - bounds: Rectangle { - x: bounds.x + handle_offset.round(), - y: rail_y - handle_height / 2.0, - width: handle_width, - height: handle_height, - }, - background: Background::Color(style.handle.color), - border_radius: handle_border_radius, - border_width: style.handle.border_width, - border_color: style.handle.border_color, - }; - - ( - Primitive::Group { - primitives: vec![rail_top, rail_bottom, handle], - }, - if is_dragging { - mouse::Interaction::Grabbing - } else if is_mouse_over { - mouse::Interaction::Grab - } else { - mouse::Interaction::default() - }, - ) - } -} diff --git a/wgpu/src/renderer/widget/space.rs b/wgpu/src/renderer/widget/space.rs deleted file mode 100644 index 225f7e6c..00000000 --- a/wgpu/src/renderer/widget/space.rs +++ /dev/null @@ -1,8 +0,0 @@ -use crate::{Primitive, Renderer}; -use iced_native::{mouse, space, Rectangle}; - -impl space::Renderer for Renderer { - fn draw(&mut self, _bounds: Rectangle) -> Self::Output { - (Primitive::None, mouse::Interaction::default()) - } -} diff --git a/wgpu/src/renderer/widget/svg.rs b/wgpu/src/renderer/widget/svg.rs deleted file mode 100644 index f6d6d0ba..00000000 --- a/wgpu/src/renderer/widget/svg.rs +++ /dev/null @@ -1,22 +0,0 @@ -use crate::{Primitive, Renderer}; -use iced_native::{mouse, svg, Layout}; - -impl svg::Renderer for Renderer { - fn dimensions(&self, handle: &svg::Handle) -> (u32, u32) { - self.image_pipeline.viewport_dimensions(handle) - } - - fn draw( - &mut self, - handle: svg::Handle, - layout: Layout<'_>, - ) -> Self::Output { - ( - Primitive::Svg { - handle, - bounds: layout.bounds(), - }, - mouse::Interaction::default(), - ) - } -} diff --git a/wgpu/src/renderer/widget/text.rs b/wgpu/src/renderer/widget/text.rs deleted file mode 100644 index 4605ed06..00000000 --- a/wgpu/src/renderer/widget/text.rs +++ /dev/null @@ -1,61 +0,0 @@ -use crate::{Primitive, Renderer}; -use iced_native::{ - mouse, text, Color, Font, HorizontalAlignment, Rectangle, Size, - VerticalAlignment, -}; - -use std::f32; - -impl text::Renderer for Renderer { - type Font = Font; - - const DEFAULT_SIZE: u16 = 20; - - fn measure( - &self, - content: &str, - size: u16, - font: Font, - bounds: Size, - ) -> (f32, f32) { - self.text_pipeline - .measure(content, f32::from(size), font, bounds) - } - - fn draw( - &mut self, - defaults: &Self::Defaults, - bounds: Rectangle, - content: &str, - size: u16, - font: Font, - color: Option<Color>, - horizontal_alignment: HorizontalAlignment, - vertical_alignment: VerticalAlignment, - ) -> Self::Output { - let x = match horizontal_alignment { - iced_native::HorizontalAlignment::Left => bounds.x, - iced_native::HorizontalAlignment::Center => bounds.center_x(), - iced_native::HorizontalAlignment::Right => bounds.x + bounds.width, - }; - - let y = match vertical_alignment { - iced_native::VerticalAlignment::Top => bounds.y, - iced_native::VerticalAlignment::Center => bounds.center_y(), - iced_native::VerticalAlignment::Bottom => bounds.y + bounds.height, - }; - - ( - Primitive::Text { - content: content.to_string(), - size: f32::from(size), - bounds: Rectangle { x, y, ..bounds }, - color: color.unwrap_or(defaults.text.color), - font, - horizontal_alignment, - vertical_alignment, - }, - mouse::Interaction::default(), - ) - } -} diff --git a/wgpu/src/renderer/widget/text_input.rs b/wgpu/src/renderer/widget/text_input.rs deleted file mode 100644 index 5799dba7..00000000 --- a/wgpu/src/renderer/widget/text_input.rs +++ /dev/null @@ -1,254 +0,0 @@ -use crate::{text_input::StyleSheet, Primitive, Renderer}; - -use iced_native::{ - mouse, - text_input::{self, cursor}, - Background, Color, Font, HorizontalAlignment, Point, Rectangle, Size, - Vector, VerticalAlignment, -}; -use std::f32; - -impl text_input::Renderer for Renderer { - type Style = Box<dyn StyleSheet>; - - fn default_size(&self) -> u16 { - // TODO: Make this configurable - 20 - } - - fn measure_value(&self, value: &str, size: u16, font: Font) -> f32 { - let (width, _) = self.text_pipeline.measure( - value, - f32::from(size), - font, - Size::INFINITY, - ); - - width - } - - fn offset( - &self, - text_bounds: Rectangle, - font: Font, - size: u16, - value: &text_input::Value, - state: &text_input::State, - ) -> f32 { - if state.is_focused() { - let cursor = state.cursor(); - - let focus_position = match cursor.state(value) { - cursor::State::Index(i) => i, - cursor::State::Selection { end, .. } => end, - }; - - let (_, offset) = measure_cursor_and_scroll_offset( - self, - text_bounds, - value, - size, - focus_position, - font, - ); - - offset - } else { - 0.0 - } - } - - fn draw( - &mut self, - bounds: Rectangle, - text_bounds: Rectangle, - cursor_position: Point, - font: Font, - size: u16, - placeholder: &str, - value: &text_input::Value, - state: &text_input::State, - style_sheet: &Self::Style, - ) -> Self::Output { - let is_mouse_over = bounds.contains(cursor_position); - - let style = if state.is_focused() { - style_sheet.focused() - } else if is_mouse_over { - style_sheet.hovered() - } else { - style_sheet.active() - }; - - let input = Primitive::Quad { - bounds, - background: style.background, - border_radius: style.border_radius, - border_width: style.border_width, - border_color: style.border_color, - }; - - let text = value.to_string(); - - let text_value = Primitive::Text { - content: if text.is_empty() { - placeholder.to_string() - } else { - text.clone() - }, - color: if text.is_empty() { - style_sheet.placeholder_color() - } else { - style_sheet.value_color() - }, - font, - bounds: Rectangle { - y: text_bounds.center_y(), - width: f32::INFINITY, - ..text_bounds - }, - size: f32::from(size), - horizontal_alignment: HorizontalAlignment::Left, - vertical_alignment: VerticalAlignment::Center, - }; - - let (contents_primitive, offset) = if state.is_focused() { - let cursor = state.cursor(); - - let (cursor_primitive, offset) = match cursor.state(value) { - cursor::State::Index(position) => { - let (text_value_width, offset) = - measure_cursor_and_scroll_offset( - self, - text_bounds, - value, - size, - position, - font, - ); - - ( - Primitive::Quad { - bounds: Rectangle { - x: text_bounds.x + text_value_width, - y: text_bounds.y, - width: 1.0, - height: text_bounds.height, - }, - background: Background::Color( - style_sheet.value_color(), - ), - border_radius: 0, - border_width: 0, - border_color: Color::TRANSPARENT, - }, - offset, - ) - } - cursor::State::Selection { start, end } => { - let left = start.min(end); - let right = end.max(start); - - let (left_position, left_offset) = - measure_cursor_and_scroll_offset( - self, - text_bounds, - value, - size, - left, - font, - ); - - let (right_position, right_offset) = - measure_cursor_and_scroll_offset( - self, - text_bounds, - value, - size, - right, - font, - ); - - let width = right_position - left_position; - - ( - Primitive::Quad { - bounds: Rectangle { - x: text_bounds.x + left_position, - y: text_bounds.y, - width, - height: text_bounds.height, - }, - background: Background::Color( - style_sheet.selection_color(), - ), - border_radius: 0, - border_width: 0, - border_color: Color::TRANSPARENT, - }, - if end == right { - right_offset - } else { - left_offset - }, - ) - } - }; - - ( - Primitive::Group { - primitives: vec![cursor_primitive, text_value], - }, - Vector::new(offset as u32, 0), - ) - } else { - (text_value, Vector::new(0, 0)) - }; - - let text_width = self.measure_value( - if text.is_empty() { placeholder } else { &text }, - size, - font, - ); - - let contents = if text_width > text_bounds.width { - Primitive::Clip { - bounds: text_bounds, - offset, - content: Box::new(contents_primitive), - } - } else { - contents_primitive - }; - - ( - Primitive::Group { - primitives: vec![input, contents], - }, - if is_mouse_over { - mouse::Interaction::Text - } else { - mouse::Interaction::default() - }, - ) - } -} - -fn measure_cursor_and_scroll_offset( - renderer: &Renderer, - text_bounds: Rectangle, - value: &text_input::Value, - size: u16, - cursor_index: usize, - font: Font, -) -> (f32, f32) { - use iced_native::text_input::Renderer; - - let text_before_cursor = value.until(cursor_index).to_string(); - - let text_value_width = - renderer.measure_value(&text_before_cursor, size, font); - let offset = ((text_value_width + 5.0) - text_bounds.width).max(0.0); - - (text_value_width, offset) -} diff --git a/wgpu/src/settings.rs b/wgpu/src/settings.rs index 5ee245b6..8378d734 100644 --- a/wgpu/src/settings.rs +++ b/wgpu/src/settings.rs @@ -1,6 +1,5 @@ -//! Configure a [`Renderer`]. -//! -//! [`Renderer`]: struct.Renderer.html +//! Configure a renderer. +pub use iced_graphics::Antialiasing; /// The settings of a [`Renderer`]. /// @@ -30,27 +29,3 @@ impl Default for Settings { } } } - -/// An antialiasing strategy. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum Antialiasing { - /// Multisample AA with 2 samples - MSAAx2, - /// Multisample AA with 4 samples - MSAAx4, - /// Multisample AA with 8 samples - MSAAx8, - /// Multisample AA with 16 samples - MSAAx16, -} - -impl Antialiasing { - pub(crate) fn sample_count(self) -> u32 { - match self { - Antialiasing::MSAAx2 => 2, - Antialiasing::MSAAx4 => 4, - Antialiasing::MSAAx8 => 8, - Antialiasing::MSAAx16 => 16, - } - } -} diff --git a/wgpu/src/target.rs b/wgpu/src/target.rs deleted file mode 100644 index 1e72c0c3..00000000 --- a/wgpu/src/target.rs +++ /dev/null @@ -1,14 +0,0 @@ -use crate::Viewport; - -/// A rendering target. -#[derive(Debug)] -pub struct Target<'a> { - /// The texture where graphics will be rendered. - pub texture: &'a wgpu::TextureView, - - /// The viewport of the target. - /// - /// Most of the time, you will want this to match the dimensions of the - /// texture. - pub viewport: &'a Viewport, -} diff --git a/wgpu/src/text.rs b/wgpu/src/text.rs index 7b6bef6c..5ee7b856 100644 --- a/wgpu/src/text.rs +++ b/wgpu/src/text.rs @@ -1,24 +1,12 @@ -mod font; - use crate::Transformation; - +use iced_graphics::font; use std::{cell::RefCell, collections::HashMap}; use wgpu_glyph::ab_glyph; -pub const BUILTIN_ICONS: iced_native::Font = iced_native::Font::External { - name: "iced_wgpu icons", - bytes: include_bytes!("text/icons.ttf"), -}; - -pub const CHECKMARK_ICON: char = '\u{F00C}'; - -const FALLBACK_FONT: &[u8] = include_bytes!("../fonts/Lato-Regular.ttf"); - #[derive(Debug)] pub struct Pipeline { draw_brush: RefCell<wgpu_glyph::GlyphBrush<()>>, draw_font_map: RefCell<HashMap<String, wgpu_glyph::FontId>>, - measure_brush: RefCell<glyph_brush::GlyphBrush<()>>, } @@ -35,7 +23,7 @@ impl Pipeline { default_font.map(|slice| slice.to_vec()).unwrap_or_else(|| { font_source .load(&[font::Family::SansSerif, font::Family::Serif]) - .unwrap_or_else(|_| FALLBACK_FONT.to_vec()) + .unwrap_or_else(|_| font::FALLBACK.to_vec()) }); let font = ab_glyph::FontArc::try_from_vec(default_font) @@ -45,7 +33,7 @@ impl Pipeline { embedded font..." ); - ab_glyph::FontArc::try_from_slice(FALLBACK_FONT) + ab_glyph::FontArc::try_from_slice(font::FALLBACK) .expect("Load fallback font") }); @@ -61,7 +49,6 @@ impl Pipeline { Pipeline { draw_brush: RefCell::new(draw_brush), draw_font_map: RefCell::new(HashMap::new()), - measure_brush: RefCell::new(measure_brush), } } @@ -121,7 +108,7 @@ impl Pipeline { } } - pub fn clear_measurement_cache(&mut self) { + pub fn trim_measurement_cache(&mut self) { // TODO: We should probably use a `GlyphCalculator` for this. However, // it uses a lifetimed `GlyphCalculatorGuard` with side-effects on drop. // This makes stuff quite inconvenient. A manual method for trimming the diff --git a/wgpu/src/text/font.rs b/wgpu/src/text/font.rs deleted file mode 100644 index 7346ccdb..00000000 --- a/wgpu/src/text/font.rs +++ /dev/null @@ -1,37 +0,0 @@ -pub use font_kit::{ - error::SelectionError as LoadError, family_name::FamilyName as Family, -}; - -pub struct Source { - raw: font_kit::source::SystemSource, -} - -impl Source { - pub fn new() -> Self { - Source { - raw: font_kit::source::SystemSource::new(), - } - } - - pub fn load(&self, families: &[Family]) -> Result<Vec<u8>, LoadError> { - let font = self.raw.select_best_match( - families, - &font_kit::properties::Properties::default(), - )?; - - match font { - font_kit::handle::Handle::Path { path, .. } => { - use std::io::Read; - - let mut buf = Vec::new(); - let mut reader = std::fs::File::open(path).expect("Read font"); - let _ = reader.read_to_end(&mut buf); - - Ok(buf) - } - font_kit::handle::Handle::Memory { bytes, .. } => { - Ok(bytes.as_ref().clone()) - } - } - } -} diff --git a/wgpu/src/text/icons.ttf b/wgpu/src/text/icons.ttf Binary files differdeleted file mode 100644 index 1c832f86..00000000 --- a/wgpu/src/text/icons.ttf +++ /dev/null diff --git a/wgpu/src/transformation.rs b/wgpu/src/transformation.rs deleted file mode 100644 index ff3b1d00..00000000 --- a/wgpu/src/transformation.rs +++ /dev/null @@ -1,54 +0,0 @@ -use glam::{Mat4, Vec3, Vec4}; -use std::ops::Mul; - -/// A 2D transformation matrix. -#[derive(Debug, Clone, Copy, PartialEq)] -pub struct Transformation(Mat4); - -impl Transformation { - /// Get the identity transformation. - pub fn identity() -> Transformation { - Transformation(Mat4::identity()) - } - - /// Creates an orthographic projection. - #[rustfmt::skip] - pub fn orthographic(width: u32, height: u32) -> Transformation { - Transformation(Mat4::from_cols( - Vec4::new(2.0 / width as f32, 0.0, 0.0, 0.0), - Vec4::new(0.0, -2.0 / height as f32, 0.0, 0.0), - Vec4::new(0.0, 0.0, -1.0, 0.0), - Vec4::new(-1.0, 1.0, 0.0, 1.0) - )) - } - - /// Creates a translate transformation. - pub fn translate(x: f32, y: f32) -> Transformation { - Transformation(Mat4::from_translation(Vec3::new(x, y, 0.0))) - } - - /// Creates a scale transformation. - pub fn scale(x: f32, y: f32) -> Transformation { - Transformation(Mat4::from_scale(Vec3::new(x, y, 1.0))) - } -} - -impl Mul for Transformation { - type Output = Self; - - fn mul(self, rhs: Self) -> Self { - Transformation(self.0 * rhs.0) - } -} - -impl AsRef<[f32; 16]> for Transformation { - fn as_ref(&self) -> &[f32; 16] { - self.0.as_ref() - } -} - -impl From<Transformation> for [f32; 16] { - fn from(t: Transformation) -> [f32; 16] { - *t.as_ref() - } -} diff --git a/wgpu/src/triangle.rs b/wgpu/src/triangle.rs index 3e68a269..22a27143 100644 --- a/wgpu/src/triangle.rs +++ b/wgpu/src/triangle.rs @@ -1,9 +1,11 @@ //! Draw meshes of triangles. use crate::{settings, Transformation}; -use iced_native::{Rectangle, Vector}; +use iced_graphics::layer; use std::mem; use zerocopy::AsBytes; +pub use iced_graphics::triangle::{Mesh2D, Vertex2D}; + mod msaa; const UNIFORM_BUFFER_SIZE: usize = 100; @@ -168,9 +170,9 @@ impl Pipeline { ], }], }, - sample_count: antialiasing - .map(|a| a.sample_count()) - .unwrap_or(1), + sample_count: u32::from( + antialiasing.map(|a| a.sample_count()).unwrap_or(1), + ), sample_mask: !0, alpha_to_coverage_enabled: false, }); @@ -202,14 +204,16 @@ impl Pipeline { target_height: u32, transformation: Transformation, scale_factor: f32, - meshes: &[(Vector, Rectangle<u32>, &Mesh2D)], + meshes: &[layer::Mesh<'_>], ) { // This looks a bit crazy, but we are just counting how many vertices // and indices we will need to handle. // TODO: Improve readability let (total_vertices, total_indices) = meshes .iter() - .map(|(_, _, mesh)| (mesh.vertices.len(), mesh.indices.len())) + .map(|layer::Mesh { buffers, .. }| { + (buffers.vertices.len(), buffers.indices.len()) + }) .fold((0, 0), |(total_v, total_i), (v, i)| { (total_v + v, total_i + i) }); @@ -230,18 +234,18 @@ impl Pipeline { let mut last_index = 0; // We upload everything upfront - for (origin, _, mesh) in meshes { + for mesh in meshes { let transform = (transformation - * Transformation::translate(origin.x, origin.y)) + * Transformation::translate(mesh.origin.x, mesh.origin.y)) .into(); let vertex_buffer = device.create_buffer_with_data( - mesh.vertices.as_bytes(), + bytemuck::cast_slice(&mesh.buffers.vertices), wgpu::BufferUsage::COPY_SRC, ); let index_buffer = device.create_buffer_with_data( - mesh.indices.as_bytes(), + mesh.buffers.indices.as_bytes(), wgpu::BufferUsage::COPY_SRC, ); @@ -250,7 +254,8 @@ impl Pipeline { 0, &self.vertex_buffer.raw, (std::mem::size_of::<Vertex2D>() * last_vertex) as u64, - (std::mem::size_of::<Vertex2D>() * mesh.vertices.len()) as u64, + (std::mem::size_of::<Vertex2D>() * mesh.buffers.vertices.len()) + as u64, ); encoder.copy_buffer_to_buffer( @@ -258,18 +263,19 @@ impl Pipeline { 0, &self.index_buffer.raw, (std::mem::size_of::<u32>() * last_index) as u64, - (std::mem::size_of::<u32>() * mesh.indices.len()) as u64, + (std::mem::size_of::<u32>() * mesh.buffers.indices.len()) + as u64, ); uniforms.push(transform); offsets.push(( last_vertex as u64, last_index as u64, - mesh.indices.len(), + mesh.buffers.indices.len(), )); - last_vertex += mesh.vertices.len(); - last_index += mesh.indices.len(); + last_vertex += mesh.buffers.vertices.len(); + last_index += mesh.buffers.indices.len(); } let uniforms_buffer = device.create_buffer_with_data( @@ -320,13 +326,14 @@ impl Pipeline { for (i, (vertex_offset, index_offset, indices)) in offsets.into_iter().enumerate() { - let bounds = meshes[i].1 * scale_factor; + let clip_bounds = + (meshes[i].clip_bounds * scale_factor).round(); render_pass.set_scissor_rect( - bounds.x, - bounds.y, - bounds.width, - bounds.height, + clip_bounds.x, + clip_bounds.y, + clip_bounds.width, + clip_bounds.height, ); render_pass.set_bind_group( @@ -387,26 +394,3 @@ impl From<Transformation> for Uniforms { } } } - -/// A two-dimensional vertex with some color in __linear__ RGBA. -#[repr(C)] -#[derive(Copy, Clone, Debug, AsBytes)] -pub struct Vertex2D { - /// The vertex position - pub position: [f32; 2], - /// The vertex color in __linear__ RGBA. - pub color: [f32; 4], -} - -/// A set of [`Vertex2D`] and indices representing a list of triangles. -/// -/// [`Vertex2D`]: struct.Vertex2D.html -#[derive(Clone, Debug)] -pub struct Mesh2D { - /// The vertices of the mesh - pub vertices: Vec<Vertex2D>, - /// The list of vertex indices that defines the triangles of the mesh. - /// - /// Therefore, this list should always have a length that is a multiple of 3. - pub indices: Vec<u32>, -} diff --git a/wgpu/src/viewport.rs b/wgpu/src/viewport.rs deleted file mode 100644 index 66242468..00000000 --- a/wgpu/src/viewport.rs +++ /dev/null @@ -1,29 +0,0 @@ -use crate::Transformation; - -/// A viewing region for displaying computer graphics. -#[derive(Debug)] -pub struct Viewport { - width: u32, - height: u32, - transformation: Transformation, -} - -impl Viewport { - /// Creates a new [`Viewport`] with the given dimensions. - pub fn new(width: u32, height: u32) -> Viewport { - Viewport { - width, - height, - transformation: Transformation::orthographic(width, height), - } - } - - /// Returns the dimensions of the [`Viewport`]. - pub fn dimensions(&self) -> (u32, u32) { - (self.width, self.height) - } - - pub(crate) fn transformation(&self) -> Transformation { - self.transformation - } -} diff --git a/wgpu/src/widget.rs b/wgpu/src/widget.rs index 32ccad17..d17b7a5d 100644 --- a/wgpu/src/widget.rs +++ b/wgpu/src/widget.rs @@ -7,6 +7,8 @@ //! ``` //! use iced_wgpu::{button, Button}; //! ``` +use crate::Renderer; + pub mod button; pub mod checkbox; pub mod container; @@ -17,8 +19,6 @@ pub mod scrollable; pub mod slider; pub mod text_input; -mod text; - #[doc(no_inline)] pub use button::Button; #[doc(no_inline)] @@ -38,8 +38,6 @@ pub use slider::Slider; #[doc(no_inline)] pub use text_input::TextInput; -pub use text::Text; - #[cfg(feature = "canvas")] #[cfg_attr(docsrs, doc(cfg(feature = "canvas")))] pub mod canvas; @@ -47,3 +45,14 @@ pub mod canvas; #[cfg(feature = "canvas")] #[doc(no_inline)] pub use canvas::Canvas; + +pub use iced_native::Space; + +/// A container that distributes its contents vertically. +pub type Column<'a, Message> = iced_native::Column<'a, Message, Renderer>; + +/// A container that distributes its contents horizontally. +pub type Row<'a, Message> = iced_native::Row<'a, Message, Renderer>; + +/// A paragraph of text. +pub type Text = iced_native::Text<Renderer>; diff --git a/wgpu/src/widget/button.rs b/wgpu/src/widget/button.rs index b738c55e..fee7a7f8 100644 --- a/wgpu/src/widget/button.rs +++ b/wgpu/src/widget/button.rs @@ -6,8 +6,8 @@ //! [`State`]: struct.State.html use crate::Renderer; +pub use iced_graphics::button::{Style, StyleSheet}; pub use iced_native::button::State; -pub use iced_style::button::{Style, StyleSheet}; /// A widget that produces a message when clicked. /// diff --git a/wgpu/src/widget/canvas.rs b/wgpu/src/widget/canvas.rs index 2fc10ea0..bef34857 100644 --- a/wgpu/src/widget/canvas.rs +++ b/wgpu/src/widget/canvas.rs @@ -6,228 +6,4 @@ //! //! [`Canvas`]: struct.Canvas.html //! [`Frame`]: struct.Frame.html -use crate::{Defaults, Primitive, Renderer}; - -use iced_native::{ - layout, mouse, Clipboard, Element, Hasher, Layout, Length, Point, Size, - Vector, Widget, -}; -use std::hash::Hash; -use std::marker::PhantomData; - -pub mod path; - -mod cache; -mod cursor; -mod event; -mod fill; -mod frame; -mod geometry; -mod program; -mod stroke; -mod text; - -pub use cache::Cache; -pub use cursor::Cursor; -pub use event::Event; -pub use fill::Fill; -pub use frame::Frame; -pub use geometry::Geometry; -pub use path::Path; -pub use program::Program; -pub use stroke::{LineCap, LineJoin, Stroke}; -pub use text::Text; - -/// A widget capable of drawing 2D graphics. -/// -/// [`Canvas`]: struct.Canvas.html -/// -/// # Examples -/// The repository has a couple of [examples] showcasing how to use a -/// [`Canvas`]: -/// -/// - [`clock`], an application that uses the [`Canvas`] widget to draw a clock -/// and its hands to display the current time. -/// - [`game_of_life`], an interactive version of the Game of Life, invented by -/// John Conway. -/// - [`solar_system`], an animated solar system drawn using the [`Canvas`] widget -/// and showcasing how to compose different transforms. -/// -/// [examples]: https://github.com/hecrj/iced/tree/master/examples -/// [`clock`]: https://github.com/hecrj/iced/tree/master/examples/clock -/// [`game_of_life`]: https://github.com/hecrj/iced/tree/master/examples/game_of_life -/// [`solar_system`]: https://github.com/hecrj/iced/tree/master/examples/solar_system -/// -/// ## Drawing a simple circle -/// If you want to get a quick overview, here's how we can draw a simple circle: -/// -/// ```no_run -/// # mod iced { -/// # pub use iced_wgpu::canvas; -/// # pub use iced_native::{Color, Rectangle}; -/// # } -/// use iced::canvas::{self, Canvas, Cursor, Fill, Frame, Geometry, Path, Program}; -/// use iced::{Color, Rectangle}; -/// -/// // First, we define the data we need for drawing -/// #[derive(Debug)] -/// struct Circle { -/// radius: f32, -/// } -/// -/// // Then, we implement the `Program` trait -/// impl Program<()> for Circle { -/// fn draw(&self, bounds: Rectangle, _cursor: Cursor) -> Vec<Geometry>{ -/// // We prepare a new `Frame` -/// let mut frame = Frame::new(bounds.size()); -/// -/// // We create a `Path` representing a simple circle -/// let circle = Path::circle(frame.center(), self.radius); -/// -/// // And fill it with some color -/// frame.fill(&circle, Fill::Color(Color::BLACK)); -/// -/// // Finally, we produce the geometry -/// vec![frame.into_geometry()] -/// } -/// } -/// -/// // Finally, we simply use our `Circle` to create the `Canvas`! -/// let canvas = Canvas::new(Circle { radius: 50.0 }); -/// ``` -#[derive(Debug)] -pub struct Canvas<Message, P: Program<Message>> { - width: Length, - height: Length, - program: P, - phantom: PhantomData<Message>, -} - -impl<Message, P: Program<Message>> Canvas<Message, P> { - const DEFAULT_SIZE: u16 = 100; - - /// Creates a new [`Canvas`]. - /// - /// [`Canvas`]: struct.Canvas.html - pub fn new(program: P) -> Self { - Canvas { - width: Length::Units(Self::DEFAULT_SIZE), - height: Length::Units(Self::DEFAULT_SIZE), - program, - phantom: PhantomData, - } - } - - /// Sets the width of the [`Canvas`]. - /// - /// [`Canvas`]: struct.Canvas.html - pub fn width(mut self, width: Length) -> Self { - self.width = width; - self - } - - /// Sets the height of the [`Canvas`]. - /// - /// [`Canvas`]: struct.Canvas.html - pub fn height(mut self, height: Length) -> Self { - self.height = height; - self - } -} - -impl<Message, P: Program<Message>> Widget<Message, Renderer> - for Canvas<Message, P> -{ - fn width(&self) -> Length { - self.width - } - - fn height(&self) -> Length { - self.height - } - - fn layout( - &self, - _renderer: &Renderer, - limits: &layout::Limits, - ) -> layout::Node { - let limits = limits.width(self.width).height(self.height); - let size = limits.resolve(Size::ZERO); - - layout::Node::new(size) - } - - fn on_event( - &mut self, - event: iced_native::Event, - layout: Layout<'_>, - cursor_position: Point, - messages: &mut Vec<Message>, - _renderer: &Renderer, - _clipboard: Option<&dyn Clipboard>, - ) { - let bounds = layout.bounds(); - - let canvas_event = match event { - iced_native::Event::Mouse(mouse_event) => { - Some(Event::Mouse(mouse_event)) - } - _ => None, - }; - - let cursor = Cursor::from_window_position(cursor_position); - - if let Some(canvas_event) = canvas_event { - if let Some(message) = - self.program.update(canvas_event, bounds, cursor) - { - messages.push(message); - } - } - } - - fn draw( - &self, - _renderer: &mut Renderer, - _defaults: &Defaults, - layout: Layout<'_>, - cursor_position: Point, - ) -> (Primitive, mouse::Interaction) { - let bounds = layout.bounds(); - let translation = Vector::new(bounds.x, bounds.y); - let cursor = Cursor::from_window_position(cursor_position); - - ( - Primitive::Translate { - translation, - content: Box::new(Primitive::Group { - primitives: self - .program - .draw(bounds, cursor) - .into_iter() - .map(Geometry::into_primitive) - .collect(), - }), - }, - self.program.mouse_interaction(bounds, cursor), - ) - } - - fn hash_layout(&self, state: &mut Hasher) { - struct Marker; - std::any::TypeId::of::<Marker>().hash(state); - - self.width.hash(state); - self.height.hash(state); - } -} - -impl<'a, Message, P: Program<Message> + 'a> From<Canvas<Message, P>> - for Element<'a, Message, Renderer> -where - Message: 'static, -{ - fn from(canvas: Canvas<Message, P>) -> Element<'a, Message, Renderer> { - Element::new(canvas) - } -} +pub use iced_graphics::canvas::*; diff --git a/wgpu/src/widget/canvas/cache.rs b/wgpu/src/widget/canvas/cache.rs deleted file mode 100644 index 4b28d164..00000000 --- a/wgpu/src/widget/canvas/cache.rs +++ /dev/null @@ -1,108 +0,0 @@ -use crate::{ - canvas::{Frame, Geometry}, - Primitive, -}; - -use iced_native::Size; -use std::{cell::RefCell, sync::Arc}; - -enum State { - Empty, - Filled { - bounds: Size, - primitive: Arc<Primitive>, - }, -} - -impl Default for State { - fn default() -> Self { - State::Empty - } -} -/// A simple cache that stores generated [`Geometry`] to avoid recomputation. -/// -/// A [`Cache`] will not redraw its geometry unless the dimensions of its layer -/// change or it is explicitly cleared. -/// -/// [`Layer`]: ../trait.Layer.html -/// [`Cache`]: struct.Cache.html -/// [`Geometry`]: struct.Geometry.html -#[derive(Debug, Default)] -pub struct Cache { - state: RefCell<State>, -} - -impl Cache { - /// Creates a new empty [`Cache`]. - /// - /// [`Cache`]: struct.Cache.html - pub fn new() -> Self { - Cache { - state: Default::default(), - } - } - - /// Clears the [`Cache`], forcing a redraw the next time it is used. - /// - /// [`Cache`]: struct.Cache.html - pub fn clear(&mut self) { - *self.state.borrow_mut() = State::Empty; - } - - /// Draws [`Geometry`] using the provided closure and stores it in the - /// [`Cache`]. - /// - /// The closure will only be called when - /// - the bounds have changed since the previous draw call. - /// - the [`Cache`] is empty or has been explicitly cleared. - /// - /// Otherwise, the previously stored [`Geometry`] will be returned. The - /// [`Cache`] is not cleared in this case. In other words, it will keep - /// returning the stored [`Geometry`] if needed. - /// - /// [`Cache`]: struct.Cache.html - pub fn draw(&self, bounds: Size, draw_fn: impl Fn(&mut Frame)) -> Geometry { - use std::ops::Deref; - - if let State::Filled { - bounds: cached_bounds, - primitive, - } = self.state.borrow().deref() - { - if *cached_bounds == bounds { - return Geometry::from_primitive(Primitive::Cached { - cache: primitive.clone(), - }); - } - } - - let mut frame = Frame::new(bounds); - draw_fn(&mut frame); - - let primitive = { - let geometry = frame.into_geometry(); - - Arc::new(geometry.into_primitive()) - }; - - *self.state.borrow_mut() = State::Filled { - bounds, - primitive: primitive.clone(), - }; - - Geometry::from_primitive(Primitive::Cached { cache: primitive }) - } -} - -impl std::fmt::Debug for State { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - State::Empty => write!(f, "Empty"), - State::Filled { primitive, bounds } => f - .debug_struct("Filled") - .field("primitive", primitive) - .field("bounds", bounds) - .finish(), - } - } -} diff --git a/wgpu/src/widget/canvas/cursor.rs b/wgpu/src/widget/canvas/cursor.rs deleted file mode 100644 index 456760ea..00000000 --- a/wgpu/src/widget/canvas/cursor.rs +++ /dev/null @@ -1,72 +0,0 @@ -use iced_native::{Point, Rectangle}; - -/// The mouse cursor state. -#[derive(Debug, Clone, Copy, PartialEq)] -pub enum Cursor { - /// The cursor has a defined position. - Available(Point), - - /// The cursor is currently unavailable (i.e. out of bounds or busy). - Unavailable, -} - -impl Cursor { - // TODO: Remove this once this type is used in `iced_native` to encode - // proper cursor availability - pub(crate) fn from_window_position(position: Point) -> Self { - if position.x < 0.0 || position.y < 0.0 { - Cursor::Unavailable - } else { - Cursor::Available(position) - } - } - - /// Returns the absolute position of the [`Cursor`], if available. - /// - /// [`Cursor`]: enum.Cursor.html - pub fn position(&self) -> Option<Point> { - match self { - Cursor::Available(position) => Some(*position), - Cursor::Unavailable => None, - } - } - - /// Returns the relative position of the [`Cursor`] inside the given bounds, - /// if available. - /// - /// If the [`Cursor`] is not over the provided bounds, this method will - /// return `None`. - /// - /// [`Cursor`]: enum.Cursor.html - pub fn position_in(&self, bounds: &Rectangle) -> Option<Point> { - if self.is_over(bounds) { - self.position_from(bounds.position()) - } else { - None - } - } - - /// Returns the relative position of the [`Cursor`] from the given origin, - /// if available. - /// - /// [`Cursor`]: enum.Cursor.html - pub fn position_from(&self, origin: Point) -> Option<Point> { - match self { - Cursor::Available(position) => { - Some(Point::new(position.x - origin.x, position.y - origin.y)) - } - Cursor::Unavailable => None, - } - } - - /// Returns whether the [`Cursor`] is currently over the provided bounds - /// or not. - /// - /// [`Cursor`]: enum.Cursor.html - pub fn is_over(&self, bounds: &Rectangle) -> bool { - match self { - Cursor::Available(position) => bounds.contains(*position), - Cursor::Unavailable => false, - } - } -} diff --git a/wgpu/src/widget/canvas/event.rs b/wgpu/src/widget/canvas/event.rs deleted file mode 100644 index ad11f51e..00000000 --- a/wgpu/src/widget/canvas/event.rs +++ /dev/null @@ -1,10 +0,0 @@ -use iced_native::mouse; - -/// A [`Canvas`] event. -/// -/// [`Canvas`]: struct.Event.html -#[derive(Debug, Clone, Copy, PartialEq)] -pub enum Event { - /// A mouse event. - Mouse(mouse::Event), -} diff --git a/wgpu/src/widget/canvas/fill.rs b/wgpu/src/widget/canvas/fill.rs deleted file mode 100644 index a2010e45..00000000 --- a/wgpu/src/widget/canvas/fill.rs +++ /dev/null @@ -1,20 +0,0 @@ -use iced_native::Color; - -/// The style used to fill geometry. -#[derive(Debug, Clone, Copy)] -pub enum Fill { - /// Fill with a color. - Color(Color), -} - -impl Default for Fill { - fn default() -> Fill { - Fill::Color(Color::BLACK) - } -} - -impl From<Color> for Fill { - fn from(color: Color) -> Fill { - Fill::Color(color) - } -} diff --git a/wgpu/src/widget/canvas/frame.rs b/wgpu/src/widget/canvas/frame.rs deleted file mode 100644 index 5262ab4e..00000000 --- a/wgpu/src/widget/canvas/frame.rs +++ /dev/null @@ -1,367 +0,0 @@ -use iced_native::{Point, Rectangle, Size, Vector}; - -use crate::{ - canvas::{Fill, Geometry, Path, Stroke, Text}, - triangle, Primitive, -}; - -/// The frame of a [`Canvas`]. -/// -/// [`Canvas`]: struct.Canvas.html -#[derive(Debug)] -pub struct Frame { - size: Size, - buffers: lyon::tessellation::VertexBuffers<triangle::Vertex2D, u32>, - primitives: Vec<Primitive>, - transforms: Transforms, -} - -#[derive(Debug)] -struct Transforms { - previous: Vec<Transform>, - current: Transform, -} - -#[derive(Debug, Clone, Copy)] -struct Transform { - raw: lyon::math::Transform, - is_identity: bool, -} - -impl Frame { - /// Creates a new empty [`Frame`] with the given dimensions. - /// - /// The default coordinate system of a [`Frame`] has its origin at the - /// top-left corner of its bounds. - /// - /// [`Frame`]: struct.Frame.html - pub fn new(size: Size) -> Frame { - Frame { - size, - buffers: lyon::tessellation::VertexBuffers::new(), - primitives: Vec::new(), - transforms: Transforms { - previous: Vec::new(), - current: Transform { - raw: lyon::math::Transform::identity(), - is_identity: true, - }, - }, - } - } - - /// Returns the width of the [`Frame`]. - /// - /// [`Frame`]: struct.Frame.html - #[inline] - pub fn width(&self) -> f32 { - self.size.width - } - - /// Returns the width of the [`Frame`]. - /// - /// [`Frame`]: struct.Frame.html - #[inline] - pub fn height(&self) -> f32 { - self.size.height - } - - /// Returns the dimensions of the [`Frame`]. - /// - /// [`Frame`]: struct.Frame.html - #[inline] - pub fn size(&self) -> Size { - self.size - } - - /// Returns the coordinate of the center of the [`Frame`]. - /// - /// [`Frame`]: struct.Frame.html - #[inline] - pub fn center(&self) -> Point { - Point::new(self.size.width / 2.0, self.size.height / 2.0) - } - - /// Draws the given [`Path`] on the [`Frame`] by filling it with the - /// provided style. - /// - /// [`Path`]: path/struct.Path.html - /// [`Frame`]: struct.Frame.html - pub fn fill(&mut self, path: &Path, fill: impl Into<Fill>) { - use lyon::tessellation::{ - BuffersBuilder, FillOptions, FillTessellator, - }; - - let mut buffers = BuffersBuilder::new( - &mut self.buffers, - FillVertex(match fill.into() { - Fill::Color(color) => color.into_linear(), - }), - ); - - let mut tessellator = FillTessellator::new(); - - let result = if self.transforms.current.is_identity { - tessellator.tessellate_path( - path.raw(), - &FillOptions::default(), - &mut buffers, - ) - } else { - let path = path.transformed(&self.transforms.current.raw); - - tessellator.tessellate_path( - path.raw(), - &FillOptions::default(), - &mut buffers, - ) - }; - - let _ = result.expect("Tessellate path"); - } - - /// Draws an axis-aligned rectangle given its top-left corner coordinate and - /// its `Size` on the [`Frame`] by filling it with the provided style. - /// - /// [`Frame`]: struct.Frame.html - pub fn fill_rectangle( - &mut self, - top_left: Point, - size: Size, - fill: impl Into<Fill>, - ) { - use lyon::tessellation::{BuffersBuilder, FillOptions}; - - let mut buffers = BuffersBuilder::new( - &mut self.buffers, - FillVertex(match fill.into() { - Fill::Color(color) => color.into_linear(), - }), - ); - - let top_left = - self.transforms.current.raw.transform_point( - lyon::math::Point::new(top_left.x, top_left.y), - ); - - let size = - self.transforms.current.raw.transform_vector( - lyon::math::Vector::new(size.width, size.height), - ); - - let _ = lyon::tessellation::basic_shapes::fill_rectangle( - &lyon::math::Rect::new(top_left, size.into()), - &FillOptions::default(), - &mut buffers, - ) - .expect("Fill rectangle"); - } - - /// Draws the stroke of the given [`Path`] on the [`Frame`] with the - /// provided style. - /// - /// [`Path`]: path/struct.Path.html - /// [`Frame`]: struct.Frame.html - pub fn stroke(&mut self, path: &Path, stroke: impl Into<Stroke>) { - use lyon::tessellation::{ - BuffersBuilder, StrokeOptions, StrokeTessellator, - }; - - let stroke = stroke.into(); - - let mut buffers = BuffersBuilder::new( - &mut self.buffers, - StrokeVertex(stroke.color.into_linear()), - ); - - let mut tessellator = StrokeTessellator::new(); - - let mut options = StrokeOptions::default(); - options.line_width = stroke.width; - options.start_cap = stroke.line_cap.into(); - options.end_cap = stroke.line_cap.into(); - options.line_join = stroke.line_join.into(); - - let result = if self.transforms.current.is_identity { - tessellator.tessellate_path(path.raw(), &options, &mut buffers) - } else { - let path = path.transformed(&self.transforms.current.raw); - - tessellator.tessellate_path(path.raw(), &options, &mut buffers) - }; - - let _ = result.expect("Stroke path"); - } - - /// Draws the characters of the given [`Text`] on the [`Frame`], filling - /// them with the given color. - /// - /// __Warning:__ Text currently does not work well with rotations and scale - /// transforms! The position will be correctly transformed, but the - /// resulting glyphs will not be rotated or scaled properly. - /// - /// Additionally, all text will be rendered on top of all the layers of - /// a [`Canvas`]. Therefore, it is currently only meant to be used for - /// overlays, which is the most common use case. - /// - /// Support for vectorial text is planned, and should address all these - /// limitations. - /// - /// [`Text`]: struct.Text.html - /// [`Frame`]: struct.Frame.html - /// [`Canvas`]: struct.Canvas.html - pub fn fill_text(&mut self, text: impl Into<Text>) { - use std::f32; - - let text = text.into(); - - let position = if self.transforms.current.is_identity { - text.position - } else { - let transformed = self.transforms.current.raw.transform_point( - lyon::math::Point::new(text.position.x, text.position.y), - ); - - Point::new(transformed.x, transformed.y) - }; - - // TODO: Use vectorial text instead of primitive - self.primitives.push(Primitive::Text { - content: text.content, - bounds: Rectangle { - x: position.x, - y: position.y, - width: f32::INFINITY, - height: f32::INFINITY, - }, - color: text.color, - size: text.size, - font: text.font, - horizontal_alignment: text.horizontal_alignment, - vertical_alignment: text.vertical_alignment, - }); - } - - /// Stores the current transform of the [`Frame`] and executes the given - /// drawing operations, restoring the transform afterwards. - /// - /// This method is useful to compose transforms and perform drawing - /// operations in different coordinate systems. - /// - /// [`Frame`]: struct.Frame.html - #[inline] - pub fn with_save(&mut self, f: impl FnOnce(&mut Frame)) { - self.transforms.previous.push(self.transforms.current); - - f(self); - - self.transforms.current = self.transforms.previous.pop().unwrap(); - } - - /// Applies a translation to the current transform of the [`Frame`]. - /// - /// [`Frame`]: struct.Frame.html - #[inline] - pub fn translate(&mut self, translation: Vector) { - self.transforms.current.raw = self - .transforms - .current - .raw - .pre_translate(lyon::math::Vector::new( - translation.x, - translation.y, - )); - self.transforms.current.is_identity = false; - } - - /// Applies a rotation to the current transform of the [`Frame`]. - /// - /// [`Frame`]: struct.Frame.html - #[inline] - pub fn rotate(&mut self, angle: f32) { - self.transforms.current.raw = self - .transforms - .current - .raw - .pre_rotate(lyon::math::Angle::radians(-angle)); - self.transforms.current.is_identity = false; - } - - /// Applies a scaling to the current transform of the [`Frame`]. - /// - /// [`Frame`]: struct.Frame.html - #[inline] - pub fn scale(&mut self, scale: f32) { - self.transforms.current.raw = - self.transforms.current.raw.pre_scale(scale, scale); - self.transforms.current.is_identity = false; - } - - /// Produces the [`Geometry`] representing everything drawn on the [`Frame`]. - /// - /// [`Frame`]: struct.Frame.html - /// [`Geometry`]: struct.Geometry.html - pub fn into_geometry(mut self) -> Geometry { - if !self.buffers.indices.is_empty() { - self.primitives.push(Primitive::Mesh2D { - size: self.size, - buffers: triangle::Mesh2D { - vertices: self.buffers.vertices, - indices: self.buffers.indices, - }, - }); - } - - Geometry::from_primitive(Primitive::Group { - primitives: self.primitives, - }) - } -} - -struct FillVertex([f32; 4]); - -impl lyon::tessellation::BasicVertexConstructor<triangle::Vertex2D> - for FillVertex -{ - fn new_vertex( - &mut self, - position: lyon::math::Point, - ) -> triangle::Vertex2D { - triangle::Vertex2D { - position: [position.x, position.y], - color: self.0, - } - } -} - -impl lyon::tessellation::FillVertexConstructor<triangle::Vertex2D> - for FillVertex -{ - fn new_vertex( - &mut self, - position: lyon::math::Point, - _attributes: lyon::tessellation::FillAttributes<'_>, - ) -> triangle::Vertex2D { - triangle::Vertex2D { - position: [position.x, position.y], - color: self.0, - } - } -} - -struct StrokeVertex([f32; 4]); - -impl lyon::tessellation::StrokeVertexConstructor<triangle::Vertex2D> - for StrokeVertex -{ - fn new_vertex( - &mut self, - position: lyon::math::Point, - _attributes: lyon::tessellation::StrokeAttributes<'_, '_>, - ) -> triangle::Vertex2D { - triangle::Vertex2D { - position: [position.x, position.y], - color: self.0, - } - } -} diff --git a/wgpu/src/widget/canvas/geometry.rs b/wgpu/src/widget/canvas/geometry.rs deleted file mode 100644 index 4cadee39..00000000 --- a/wgpu/src/widget/canvas/geometry.rs +++ /dev/null @@ -1,34 +0,0 @@ -use crate::Primitive; - -/// A bunch of shapes that can be drawn. -/// -/// [`Geometry`] can be easily generated with a [`Frame`] or stored in a -/// [`Cache`]. -/// -/// [`Geometry`]: struct.Geometry.html -/// [`Frame`]: struct.Frame.html -/// [`Cache`]: struct.Cache.html -#[derive(Debug, Clone)] -pub struct Geometry(Primitive); - -impl Geometry { - pub(crate) fn from_primitive(primitive: Primitive) -> Self { - Self(primitive) - } - - /// Turns the [`Geometry`] into a [`Primitive`]. - /// - /// This can be useful if you are building a custom widget. - /// - /// [`Geometry`]: struct.Geometry.html - /// [`Primitive`]: ../enum.Primitive.html - pub fn into_primitive(self) -> Primitive { - self.0 - } -} - -impl From<Geometry> for Primitive { - fn from(geometry: Geometry) -> Primitive { - geometry.0 - } -} diff --git a/wgpu/src/widget/canvas/path.rs b/wgpu/src/widget/canvas/path.rs deleted file mode 100644 index c26bf187..00000000 --- a/wgpu/src/widget/canvas/path.rs +++ /dev/null @@ -1,79 +0,0 @@ -//! Build different kinds of 2D shapes. -pub mod arc; - -mod builder; - -#[doc(no_inline)] -pub use arc::Arc; -pub use builder::Builder; - -use iced_native::{Point, Size}; - -/// An immutable set of points that may or may not be connected. -/// -/// A single [`Path`] can represent different kinds of 2D shapes! -/// -/// [`Path`]: struct.Path.html -#[derive(Debug, Clone)] -pub struct Path { - raw: lyon::path::Path, -} - -impl Path { - /// Creates a new [`Path`] with the provided closure. - /// - /// Use the [`Builder`] to configure your [`Path`]. - /// - /// [`Path`]: struct.Path.html - /// [`Builder`]: struct.Builder.html - pub fn new(f: impl FnOnce(&mut Builder)) -> Self { - let mut builder = Builder::new(); - - // TODO: Make it pure instead of side-effect-based (?) - f(&mut builder); - - builder.build() - } - - /// Creates a new [`Path`] representing a line segment given its starting - /// and end points. - /// - /// [`Path`]: struct.Path.html - pub fn line(from: Point, to: Point) -> Self { - Self::new(|p| { - p.move_to(from); - p.line_to(to); - }) - } - - /// Creates a new [`Path`] representing a rectangle given its top-left - /// corner coordinate and its `Size`. - /// - /// [`Path`]: struct.Path.html - pub fn rectangle(top_left: Point, size: Size) -> Self { - Self::new(|p| p.rectangle(top_left, size)) - } - - /// Creates a new [`Path`] representing a circle given its center - /// coordinate and its radius. - /// - /// [`Path`]: struct.Path.html - pub fn circle(center: Point, radius: f32) -> Self { - Self::new(|p| p.circle(center, radius)) - } - - #[inline] - pub(crate) fn raw(&self) -> &lyon::path::Path { - &self.raw - } - - #[inline] - pub(crate) fn transformed( - &self, - transform: &lyon::math::Transform, - ) -> Path { - Path { - raw: self.raw.transformed(transform), - } - } -} diff --git a/wgpu/src/widget/canvas/path/arc.rs b/wgpu/src/widget/canvas/path/arc.rs deleted file mode 100644 index 343191f1..00000000 --- a/wgpu/src/widget/canvas/path/arc.rs +++ /dev/null @@ -1,44 +0,0 @@ -//! Build and draw curves. -use iced_native::{Point, Vector}; - -/// A segment of a differentiable curve. -#[derive(Debug, Clone, Copy)] -pub struct Arc { - /// The center of the arc. - pub center: Point, - /// The radius of the arc. - pub radius: f32, - /// The start of the segment's angle, clockwise rotation. - pub start_angle: f32, - /// The end of the segment's angle, clockwise rotation. - pub end_angle: f32, -} - -/// An elliptical [`Arc`]. -/// -/// [`Arc`]: struct.Arc.html -#[derive(Debug, Clone, Copy)] -pub struct Elliptical { - /// The center of the arc. - pub center: Point, - /// The radii of the arc's ellipse, defining its axes. - pub radii: Vector, - /// The rotation of the arc's ellipse. - pub rotation: f32, - /// The start of the segment's angle, clockwise rotation. - pub start_angle: f32, - /// The end of the segment's angle, clockwise rotation. - pub end_angle: f32, -} - -impl From<Arc> for Elliptical { - fn from(arc: Arc) -> Elliptical { - Elliptical { - center: arc.center, - radii: Vector::new(arc.radius, arc.radius), - rotation: 0.0, - start_angle: arc.start_angle, - end_angle: arc.end_angle, - } - } -} diff --git a/wgpu/src/widget/canvas/path/builder.rs b/wgpu/src/widget/canvas/path/builder.rs deleted file mode 100644 index 6511fa52..00000000 --- a/wgpu/src/widget/canvas/path/builder.rs +++ /dev/null @@ -1,180 +0,0 @@ -use crate::canvas::path::{arc, Arc, Path}; - -use iced_native::{Point, Size}; -use lyon::path::builder::{Build, FlatPathBuilder, PathBuilder, SvgBuilder}; - -/// A [`Path`] builder. -/// -/// Once a [`Path`] is built, it can no longer be mutated. -/// -/// [`Path`]: struct.Path.html -#[allow(missing_debug_implementations)] -pub struct Builder { - raw: lyon::path::builder::SvgPathBuilder<lyon::path::Builder>, -} - -impl Builder { - /// Creates a new [`Builder`]. - /// - /// [`Builder`]: struct.Builder.html - pub fn new() -> Builder { - Builder { - raw: lyon::path::Path::builder().with_svg(), - } - } - - /// Moves the starting point of a new sub-path to the given `Point`. - #[inline] - pub fn move_to(&mut self, point: Point) { - let _ = self.raw.move_to(lyon::math::Point::new(point.x, point.y)); - } - - /// Connects the last point in the [`Path`] to the given `Point` with a - /// straight line. - /// - /// [`Path`]: struct.Path.html - #[inline] - pub fn line_to(&mut self, point: Point) { - let _ = self.raw.line_to(lyon::math::Point::new(point.x, point.y)); - } - - /// Adds an [`Arc`] to the [`Path`] from `start_angle` to `end_angle` in - /// a clockwise direction. - /// - /// [`Arc`]: struct.Arc.html - /// [`Path`]: struct.Path.html - #[inline] - pub fn arc(&mut self, arc: Arc) { - self.ellipse(arc.into()); - } - - /// Adds a circular arc to the [`Path`] with the given control points and - /// radius. - /// - /// The arc is connected to the previous point by a straight line, if - /// necessary. - /// - /// [`Path`]: struct.Path.html - pub fn arc_to(&mut self, a: Point, b: Point, radius: f32) { - use lyon::{math, path}; - - let a = math::Point::new(a.x, a.y); - - if self.raw.current_position() != a { - let _ = self.raw.line_to(a); - } - - let _ = self.raw.arc_to( - math::Vector::new(radius, radius), - math::Angle::radians(0.0), - path::ArcFlags::default(), - math::Point::new(b.x, b.y), - ); - } - - /// Adds an [`Ellipse`] to the [`Path`] using a clockwise direction. - /// - /// [`Ellipse`]: struct.Arc.html - /// [`Path`]: struct.Path.html - pub fn ellipse(&mut self, arc: arc::Elliptical) { - use lyon::{geom, math}; - - let arc = geom::Arc { - center: math::Point::new(arc.center.x, arc.center.y), - radii: math::Vector::new(arc.radii.x, arc.radii.y), - x_rotation: math::Angle::radians(arc.rotation), - start_angle: math::Angle::radians(arc.start_angle), - sweep_angle: math::Angle::radians(arc.end_angle), - }; - - let _ = self.raw.move_to(arc.sample(0.0)); - - arc.for_each_quadratic_bezier(&mut |curve| { - let _ = self.raw.quadratic_bezier_to(curve.ctrl, curve.to); - }); - } - - /// Adds a cubic Bézier curve to the [`Path`] given its two control points - /// and its end point. - /// - /// [`Path`]: struct.Path.html - #[inline] - pub fn bezier_curve_to( - &mut self, - control_a: Point, - control_b: Point, - to: Point, - ) { - use lyon::math; - - let _ = self.raw.cubic_bezier_to( - math::Point::new(control_a.x, control_a.y), - math::Point::new(control_b.x, control_b.y), - math::Point::new(to.x, to.y), - ); - } - - /// Adds a quadratic Bézier curve to the [`Path`] given its control point - /// and its end point. - /// - /// [`Path`]: struct.Path.html - #[inline] - pub fn quadratic_curve_to(&mut self, control: Point, to: Point) { - use lyon::math; - - let _ = self.raw.quadratic_bezier_to( - math::Point::new(control.x, control.y), - math::Point::new(to.x, to.y), - ); - } - - /// Adds a rectangle to the [`Path`] given its top-left corner coordinate - /// and its `Size`. - /// - /// [`Path`]: struct.Path.html - #[inline] - pub fn rectangle(&mut self, top_left: Point, size: Size) { - self.move_to(top_left); - self.line_to(Point::new(top_left.x + size.width, top_left.y)); - self.line_to(Point::new( - top_left.x + size.width, - top_left.y + size.height, - )); - self.line_to(Point::new(top_left.x, top_left.y + size.height)); - self.close(); - } - - /// Adds a circle to the [`Path`] given its center coordinate and its - /// radius. - /// - /// [`Path`]: struct.Path.html - #[inline] - pub fn circle(&mut self, center: Point, radius: f32) { - self.arc(Arc { - center, - radius, - start_angle: 0.0, - end_angle: 2.0 * std::f32::consts::PI, - }); - } - - /// Closes the current sub-path in the [`Path`] with a straight line to - /// the starting point. - /// - /// [`Path`]: struct.Path.html - #[inline] - pub fn close(&mut self) { - self.raw.close() - } - - /// Builds the [`Path`] of this [`Builder`]. - /// - /// [`Path`]: struct.Path.html - /// [`Builder`]: struct.Builder.html - #[inline] - pub fn build(self) -> Path { - Path { - raw: self.raw.build(), - } - } -} diff --git a/wgpu/src/widget/canvas/program.rs b/wgpu/src/widget/canvas/program.rs deleted file mode 100644 index 725d9d72..00000000 --- a/wgpu/src/widget/canvas/program.rs +++ /dev/null @@ -1,85 +0,0 @@ -use crate::canvas::{Cursor, Event, Geometry}; -use iced_native::{mouse, Rectangle}; - -/// The state and logic of a [`Canvas`]. -/// -/// A [`Program`] can mutate internal state and produce messages for an -/// application. -/// -/// [`Canvas`]: struct.Canvas.html -/// [`Program`]: trait.Program.html -pub trait Program<Message> { - /// Updates the state of the [`Program`]. - /// - /// When a [`Program`] is used in a [`Canvas`], the runtime will call this - /// method for each [`Event`]. - /// - /// This method can optionally return a `Message` to notify an application - /// of any meaningful interactions. - /// - /// By default, this method does and returns nothing. - /// - /// [`Program`]: trait.Program.html - /// [`Canvas`]: struct.Canvas.html - /// [`Event`]: enum.Event.html - fn update( - &mut self, - _event: Event, - _bounds: Rectangle, - _cursor: Cursor, - ) -> Option<Message> { - None - } - - /// Draws the state of the [`Program`], producing a bunch of [`Geometry`]. - /// - /// [`Geometry`] can be easily generated with a [`Frame`] or stored in a - /// [`Cache`]. - /// - /// [`Program`]: trait.Program.html - /// [`Geometry`]: struct.Geometry.html - /// [`Frame`]: struct.Frame.html - /// [`Cache`]: struct.Cache.html - fn draw(&self, bounds: Rectangle, cursor: Cursor) -> Vec<Geometry>; - - /// Returns the current mouse interaction of the [`Program`]. - /// - /// The interaction returned will be in effect even if the cursor position - /// is out of bounds of the program's [`Canvas`]. - /// - /// [`Program`]: trait.Program.html - /// [`Canvas`]: struct.Canvas.html - fn mouse_interaction( - &self, - _bounds: Rectangle, - _cursor: Cursor, - ) -> mouse::Interaction { - mouse::Interaction::default() - } -} - -impl<T, Message> Program<Message> for &mut T -where - T: Program<Message>, -{ - fn update( - &mut self, - event: Event, - bounds: Rectangle, - cursor: Cursor, - ) -> Option<Message> { - T::update(self, event, bounds, cursor) - } - - fn draw(&self, bounds: Rectangle, cursor: Cursor) -> Vec<Geometry> { - T::draw(self, bounds, cursor) - } - - fn mouse_interaction( - &self, - bounds: Rectangle, - cursor: Cursor, - ) -> mouse::Interaction { - T::mouse_interaction(self, bounds, cursor) - } -} diff --git a/wgpu/src/widget/canvas/stroke.rs b/wgpu/src/widget/canvas/stroke.rs deleted file mode 100644 index 5b6fc56a..00000000 --- a/wgpu/src/widget/canvas/stroke.rs +++ /dev/null @@ -1,115 +0,0 @@ -use iced_native::Color; - -/// The style of a stroke. -#[derive(Debug, Clone, Copy)] -pub struct Stroke { - /// The color of the stroke. - pub color: Color, - /// The distance between the two edges of the stroke. - pub width: f32, - /// The shape to be used at the end of open subpaths when they are stroked. - pub line_cap: LineCap, - /// The shape to be used at the corners of paths or basic shapes when they - /// are stroked. - pub line_join: LineJoin, -} - -impl Stroke { - /// Sets the color of the [`Stroke`]. - /// - /// [`Stroke`]: struct.Stroke.html - pub fn with_color(self, color: Color) -> Stroke { - Stroke { color, ..self } - } - - /// Sets the width of the [`Stroke`]. - /// - /// [`Stroke`]: struct.Stroke.html - pub fn with_width(self, width: f32) -> Stroke { - Stroke { width, ..self } - } - - /// Sets the [`LineCap`] of the [`Stroke`]. - /// - /// [`LineCap`]: enum.LineCap.html - /// [`Stroke`]: struct.Stroke.html - pub fn with_line_cap(self, line_cap: LineCap) -> Stroke { - Stroke { line_cap, ..self } - } - - /// Sets the [`LineJoin`] of the [`Stroke`]. - /// - /// [`LineJoin`]: enum.LineJoin.html - /// [`Stroke`]: struct.Stroke.html - pub fn with_line_join(self, line_join: LineJoin) -> Stroke { - Stroke { line_join, ..self } - } -} - -impl Default for Stroke { - fn default() -> Stroke { - Stroke { - color: Color::BLACK, - width: 1.0, - line_cap: LineCap::default(), - line_join: LineJoin::default(), - } - } -} - -/// The shape used at the end of open subpaths when they are stroked. -#[derive(Debug, Clone, Copy)] -pub enum LineCap { - /// The stroke for each sub-path does not extend beyond its two endpoints. - Butt, - /// At the end of each sub-path, the shape representing the stroke will be - /// extended by a square. - Square, - /// At the end of each sub-path, the shape representing the stroke will be - /// extended by a semicircle. - Round, -} - -impl Default for LineCap { - fn default() -> LineCap { - LineCap::Butt - } -} - -impl From<LineCap> for lyon::tessellation::LineCap { - fn from(line_cap: LineCap) -> lyon::tessellation::LineCap { - match line_cap { - LineCap::Butt => lyon::tessellation::LineCap::Butt, - LineCap::Square => lyon::tessellation::LineCap::Square, - LineCap::Round => lyon::tessellation::LineCap::Round, - } - } -} - -/// The shape used at the corners of paths or basic shapes when they are -/// stroked. -#[derive(Debug, Clone, Copy)] -pub enum LineJoin { - /// A sharp corner. - Miter, - /// A round corner. - Round, - /// A bevelled corner. - Bevel, -} - -impl Default for LineJoin { - fn default() -> LineJoin { - LineJoin::Miter - } -} - -impl From<LineJoin> for lyon::tessellation::LineJoin { - fn from(line_join: LineJoin) -> lyon::tessellation::LineJoin { - match line_join { - LineJoin::Miter => lyon::tessellation::LineJoin::Miter, - LineJoin::Round => lyon::tessellation::LineJoin::Round, - LineJoin::Bevel => lyon::tessellation::LineJoin::Bevel, - } - } -} diff --git a/wgpu/src/widget/canvas/text.rs b/wgpu/src/widget/canvas/text.rs deleted file mode 100644 index c4cae30e..00000000 --- a/wgpu/src/widget/canvas/text.rs +++ /dev/null @@ -1,49 +0,0 @@ -use iced_native::{Color, Font, HorizontalAlignment, Point, VerticalAlignment}; - -/// A bunch of text that can be drawn to a canvas -#[derive(Debug, Clone)] -pub struct Text { - /// The contents of the text - pub content: String, - /// The position where to begin drawing the text (top-left corner coordinates) - pub position: Point, - /// The color of the text - pub color: Color, - /// The size of the text - pub size: f32, - /// The font of the text - pub font: Font, - /// The horizontal alignment of the text - pub horizontal_alignment: HorizontalAlignment, - /// The vertical alignment of the text - pub vertical_alignment: VerticalAlignment, -} - -impl Default for Text { - fn default() -> Text { - Text { - content: String::new(), - position: Point::ORIGIN, - color: Color::BLACK, - size: 16.0, - font: Font::Default, - horizontal_alignment: HorizontalAlignment::Left, - vertical_alignment: VerticalAlignment::Top, - } - } -} - -impl From<String> for Text { - fn from(content: String) -> Text { - Text { - content, - ..Default::default() - } - } -} - -impl From<&str> for Text { - fn from(content: &str) -> Text { - String::from(content).into() - } -} diff --git a/wgpu/src/widget/checkbox.rs b/wgpu/src/widget/checkbox.rs index da0d7a84..d27d77cc 100644 --- a/wgpu/src/widget/checkbox.rs +++ b/wgpu/src/widget/checkbox.rs @@ -1,7 +1,7 @@ //! Show toggle controls using checkboxes. use crate::Renderer; -pub use iced_style::checkbox::{Style, StyleSheet}; +pub use iced_graphics::checkbox::{Style, StyleSheet}; /// A box that can be checked. /// diff --git a/wgpu/src/widget/container.rs b/wgpu/src/widget/container.rs index 9a93a246..bc26cef2 100644 --- a/wgpu/src/widget/container.rs +++ b/wgpu/src/widget/container.rs @@ -1,7 +1,7 @@ //! Decorate content and apply alignment. use crate::Renderer; -pub use iced_style::container::{Style, StyleSheet}; +pub use iced_graphics::container::{Style, StyleSheet}; /// An element decorating some content. /// diff --git a/wgpu/src/widget/progress_bar.rs b/wgpu/src/widget/progress_bar.rs index 770bcea8..a636a3a6 100644 --- a/wgpu/src/widget/progress_bar.rs +++ b/wgpu/src/widget/progress_bar.rs @@ -6,7 +6,7 @@ //! [`ProgressBar`]: type.ProgressBar.html use crate::Renderer; -pub use iced_style::progress_bar::{Style, StyleSheet}; +pub use iced_graphics::progress_bar::{Style, StyleSheet}; /// A bar that displays progress. /// diff --git a/wgpu/src/widget/radio.rs b/wgpu/src/widget/radio.rs index 6e5cf042..0b843d1f 100644 --- a/wgpu/src/widget/radio.rs +++ b/wgpu/src/widget/radio.rs @@ -1,7 +1,7 @@ //! Create choices using radio buttons. use crate::Renderer; -pub use iced_style::radio::{Style, StyleSheet}; +pub use iced_graphics::radio::{Style, StyleSheet}; /// A circular button representing a choice. /// diff --git a/wgpu/src/widget/scrollable.rs b/wgpu/src/widget/scrollable.rs index 1d236105..fabb4318 100644 --- a/wgpu/src/widget/scrollable.rs +++ b/wgpu/src/widget/scrollable.rs @@ -1,8 +1,8 @@ //! Navigate an endless amount of content with a scrollbar. use crate::Renderer; +pub use iced_graphics::scrollable::{Scrollbar, Scroller, StyleSheet}; pub use iced_native::scrollable::State; -pub use iced_style::scrollable::{Scrollbar, Scroller, StyleSheet}; /// A widget that can vertically display an infinite amount of content /// with a scrollbar. diff --git a/wgpu/src/widget/slider.rs b/wgpu/src/widget/slider.rs index 4e47978f..cf036829 100644 --- a/wgpu/src/widget/slider.rs +++ b/wgpu/src/widget/slider.rs @@ -6,8 +6,8 @@ //! [`State`]: struct.State.html use crate::Renderer; +pub use iced_graphics::slider::{Handle, HandleShape, Style, StyleSheet}; pub use iced_native::slider::State; -pub use iced_style::slider::{Handle, HandleShape, Style, StyleSheet}; /// An horizontal bar and a handle that selects a single value from a range of /// values. diff --git a/wgpu/src/widget/text.rs b/wgpu/src/widget/text.rs deleted file mode 100644 index 1053ea97..00000000 --- a/wgpu/src/widget/text.rs +++ /dev/null @@ -1,7 +0,0 @@ -//! Write some text for your users to read. -use crate::Renderer; - -/// A paragraph of text. -/// -/// This is an alias of an `iced_native` text with an `iced_wgpu::Renderer`. -pub type Text = iced_native::Text<Renderer>; diff --git a/wgpu/src/widget/text_input.rs b/wgpu/src/widget/text_input.rs index 260fe3a6..1da3fbe6 100644 --- a/wgpu/src/widget/text_input.rs +++ b/wgpu/src/widget/text_input.rs @@ -6,8 +6,8 @@ //! [`State`]: struct.State.html use crate::Renderer; +pub use iced_graphics::text_input::{Style, StyleSheet}; pub use iced_native::text_input::State; -pub use iced_style::text_input::{Style, StyleSheet}; /// A field that can be filled with text. /// diff --git a/wgpu/src/window.rs b/wgpu/src/window.rs index b7adad82..aac5fb9e 100644 --- a/wgpu/src/window.rs +++ b/wgpu/src/window.rs @@ -1,6 +1,4 @@ //! Display rendering results on windows. -mod backend; -mod swap_chain; +mod compositor; -pub use backend::Backend; -pub use swap_chain::SwapChain; +pub use compositor::Compositor; diff --git a/wgpu/src/window/backend.rs b/wgpu/src/window/compositor.rs index 2924ce5d..600bc81c 100644 --- a/wgpu/src/window/backend.rs +++ b/wgpu/src/window/compositor.rs @@ -1,23 +1,24 @@ -use crate::{window::SwapChain, Renderer, Settings, Target}; +use crate::{Renderer, Settings}; +use iced_graphics::Viewport; use iced_native::{futures, mouse}; use raw_window_handle::HasRawWindowHandle; /// A window graphics backend for iced powered by `wgpu`. #[derive(Debug)] -pub struct Backend { +pub struct Compositor { device: wgpu::Device, queue: wgpu::Queue, format: wgpu::TextureFormat, } -impl iced_native::window::Backend for Backend { +impl iced_graphics::window::Compositor for Compositor { type Settings = Settings; type Renderer = Renderer; type Surface = wgpu::Surface; - type SwapChain = SwapChain; + type SwapChain = wgpu::SwapChain; - fn new(settings: Self::Settings) -> (Backend, Renderer) { + fn new(settings: Self::Settings) -> (Self, Renderer) { let (mut device, queue) = futures::executor::block_on(async { let adapter = wgpu::Adapter::request( &wgpu::RequestAdapterOptions { @@ -43,10 +44,11 @@ impl iced_native::window::Backend for Backend { .await }); - let renderer = Renderer::new(&mut device, settings); + let renderer = + Renderer::new(crate::Backend::new(&mut device, settings)); ( - Backend { + Self { device, queue, format: settings.format, @@ -67,19 +69,28 @@ impl iced_native::window::Backend for Backend { surface: &Self::Surface, width: u32, height: u32, - ) -> SwapChain { - SwapChain::new(&self.device, surface, self.format, width, height) + ) -> Self::SwapChain { + self.device.create_swap_chain( + surface, + &wgpu::SwapChainDescriptor { + usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT, + format: self.format, + width, + height, + present_mode: wgpu::PresentMode::Mailbox, + }, + ) } fn draw<T: AsRef<str>>( &mut self, renderer: &mut Self::Renderer, - swap_chain: &mut SwapChain, + swap_chain: &mut Self::SwapChain, + viewport: &Viewport, output: &<Self::Renderer as iced_native::Renderer>::Output, - scale_factor: f64, overlay: &[T], ) -> mouse::Interaction { - let (frame, viewport) = swap_chain.next_frame().expect("Next frame"); + let frame = swap_chain.get_next_texture().expect("Next frame"); let mut encoder = self.device.create_command_encoder( &wgpu::CommandEncoderDescriptor { label: None }, @@ -101,15 +112,12 @@ impl iced_native::window::Backend for Backend { depth_stencil_attachment: None, }); - let mouse_interaction = renderer.draw( + let mouse_interaction = renderer.backend_mut().draw( &mut self.device, &mut encoder, - Target { - texture: &frame.view, - viewport, - }, + &frame.view, + viewport, output, - scale_factor, overlay, ); diff --git a/wgpu/src/window/swap_chain.rs b/wgpu/src/window/swap_chain.rs deleted file mode 100644 index 72e58a50..00000000 --- a/wgpu/src/window/swap_chain.rs +++ /dev/null @@ -1,61 +0,0 @@ -use crate::Viewport; - -/// The rendering target of a window. -/// -/// It represents a series of virtual framebuffers with a scale factor. -#[derive(Debug)] -pub struct SwapChain { - raw: wgpu::SwapChain, - viewport: Viewport, -} - -impl SwapChain {} - -impl SwapChain { - /// Creates a new [`SwapChain`] for the given surface. - /// - /// [`SwapChain`]: struct.SwapChain.html - pub fn new( - device: &wgpu::Device, - surface: &wgpu::Surface, - format: wgpu::TextureFormat, - width: u32, - height: u32, - ) -> SwapChain { - SwapChain { - raw: new_swap_chain(surface, format, width, height, device), - viewport: Viewport::new(width, height), - } - } - - /// Returns the next frame of the [`SwapChain`] alongside its [`Viewport`]. - /// - /// [`SwapChain`]: struct.SwapChain.html - /// [`Viewport`]: ../struct.Viewport.html - pub fn next_frame( - &mut self, - ) -> Result<(wgpu::SwapChainOutput, &Viewport), wgpu::TimeOut> { - let viewport = &self.viewport; - - self.raw.get_next_texture().map(|output| (output, viewport)) - } -} - -fn new_swap_chain( - surface: &wgpu::Surface, - format: wgpu::TextureFormat, - width: u32, - height: u32, - device: &wgpu::Device, -) -> wgpu::SwapChain { - device.create_swap_chain( - &surface, - &wgpu::SwapChainDescriptor { - usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT, - format, - width, - height, - present_mode: wgpu::PresentMode::Mailbox, - }, - ) -} |