From e1b9d42bf1443ae4958aa9303255ef19c635debb Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 3 Oct 2019 00:01:45 +0200 Subject: Start `iced_winit` and `iced_wgpu` --- wgpu/Cargo.toml | 12 ++++++++ wgpu/src/lib.rs | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 wgpu/Cargo.toml create mode 100644 wgpu/src/lib.rs (limited to 'wgpu') diff --git a/wgpu/Cargo.toml b/wgpu/Cargo.toml new file mode 100644 index 00000000..0ab7a955 --- /dev/null +++ b/wgpu/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "iced_wgpu" +version = "0.1.0-alpha" +authors = ["Héctor Ramón Jiménez "] +edition = "2018" +description = "A wgpu renderer for Iced" +license = "MIT" +repository = "https://github.com/hecrj/iced" + +[dependencies] +iced_native = { version = "0.1.0-alpha", path = "../native" } +wgpu = "0.3" diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs new file mode 100644 index 00000000..7aa053bc --- /dev/null +++ b/wgpu/src/lib.rs @@ -0,0 +1,87 @@ +use iced_native::{ + button, checkbox, image, radio, renderer::Debugger, slider, text, Button, + Checkbox, Color, Image, Layout, MouseCursor, Node, Point, Radio, Slider, + Style, Text, +}; + +pub struct Renderer; + +impl text::Renderer for Renderer { + fn node(&self, _text: &Text) -> Node { + Node::new(Style::default()) + } + + fn draw(&mut self, _text: &Text, _layout: Layout<'_>) {} +} + +impl checkbox::Renderer for Renderer { + fn node(&mut self, _checkbox: &Checkbox) -> Node { + Node::new(Style::default()) + } + + fn draw( + &mut self, + _checkbox: &Checkbox, + _layout: Layout<'_>, + _cursor_position: Point, + ) -> MouseCursor { + MouseCursor::OutOfBounds + } +} + +impl radio::Renderer for Renderer { + fn node(&mut self, _checkbox: &Radio) -> Node { + Node::new(Style::default()) + } + + fn draw( + &mut self, + _radio: &Radio, + _layout: Layout<'_>, + _cursor_position: Point, + ) -> MouseCursor { + MouseCursor::OutOfBounds + } +} + +impl slider::Renderer for Renderer { + fn node(&self, _slider: &Slider) -> Node { + Node::new(Style::default()) + } + + fn draw( + &mut self, + _slider: &Slider, + _layout: Layout<'_>, + _cursor_position: Point, + ) -> MouseCursor { + MouseCursor::OutOfBounds + } +} + +impl image::Renderer<&str> for Renderer { + fn node(&mut self, _image: &Image<&str>) -> Node { + Node::new(Style::default()) + } + + fn draw(&mut self, _checkbox: &Image<&str>, _layout: Layout<'_>) {} +} + +impl button::Renderer for Renderer { + fn node(&self, _button: &Button) -> Node { + Node::new(Style::default()) + } + + fn draw( + &mut self, + _button: &Button, + _layout: Layout<'_>, + _cursor_position: Point, + ) -> MouseCursor { + MouseCursor::OutOfBounds + } +} + +impl Debugger for Renderer { + fn explain(&mut self, _layout: &Layout<'_>, _color: Color) {} +} -- cgit From 8bb33cd5a0b876a5e24108604be2cecd4efad3ef Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 3 Oct 2019 00:23:08 +0200 Subject: Initialize `wgpu` We only enable the `vulkan` feature for now. --- wgpu/Cargo.toml | 4 ++++ wgpu/src/lib.rs | 39 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 42 insertions(+), 1 deletion(-) (limited to 'wgpu') diff --git a/wgpu/Cargo.toml b/wgpu/Cargo.toml index 0ab7a955..879def28 100644 --- a/wgpu/Cargo.toml +++ b/wgpu/Cargo.toml @@ -7,6 +7,10 @@ description = "A wgpu renderer for Iced" license = "MIT" repository = "https://github.com/hecrj/iced" +[features] +vulkan = ["wgpu/vulkan"] + [dependencies] iced_native = { version = "0.1.0-alpha", path = "../native" } wgpu = "0.3" +raw-window-handle = "0.1" diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 7aa053bc..502a2614 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -4,7 +4,44 @@ use iced_native::{ Style, Text, }; -pub struct Renderer; +use raw_window_handle::HasRawWindowHandle; +use wgpu::{ + Adapter, Device, DeviceDescriptor, Extensions, Instance, Limits, + PowerPreference, RequestAdapterOptions, Surface, +}; + +pub struct Renderer { + instance: Instance, + surface: Surface, + adapter: Adapter, + device: Device, +} + +impl Renderer { + pub fn new(window: &W) -> Self { + let instance = Instance::new(); + + let adapter = instance.request_adapter(&RequestAdapterOptions { + power_preference: PowerPreference::LowPower, + }); + + let device = adapter.request_device(&DeviceDescriptor { + extensions: Extensions { + anisotropic_filtering: false, + }, + limits: Limits { max_bind_groups: 1 }, + }); + + let surface = instance.create_surface(window.raw_window_handle()); + + Self { + instance, + surface, + adapter, + device, + } + } +} impl text::Renderer for Renderer { fn node(&self, _text: &Text) -> Node { -- cgit From fc38119be3ffccc35c90971e956e8866e8b97e85 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 3 Oct 2019 00:34:15 +0200 Subject: Clear the window properly on redraw --- wgpu/src/lib.rs | 50 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 47 insertions(+), 3 deletions(-) (limited to 'wgpu') diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 502a2614..1e11749b 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -6,8 +6,9 @@ use iced_native::{ use raw_window_handle::HasRawWindowHandle; use wgpu::{ - Adapter, Device, DeviceDescriptor, Extensions, Instance, Limits, - PowerPreference, RequestAdapterOptions, Surface, + Adapter, CommandEncoderDescriptor, Device, DeviceDescriptor, Extensions, + Instance, Limits, PowerPreference, RequestAdapterOptions, Surface, + SwapChain, SwapChainDescriptor, TextureFormat, TextureUsage, }; pub struct Renderer { @@ -15,10 +16,15 @@ pub struct Renderer { surface: Surface, adapter: Adapter, device: Device, + swap_chain: SwapChain, } impl Renderer { - pub fn new(window: &W) -> Self { + pub fn new( + window: &W, + width: u32, + height: u32, + ) -> Self { let instance = Instance::new(); let adapter = instance.request_adapter(&RequestAdapterOptions { @@ -34,13 +40,51 @@ impl Renderer { let surface = instance.create_surface(window.raw_window_handle()); + let swap_chain = device.create_swap_chain( + &surface, + &SwapChainDescriptor { + usage: TextureUsage::OUTPUT_ATTACHMENT, + format: TextureFormat::Bgra8UnormSrgb, + width, + height, + present_mode: wgpu::PresentMode::Vsync, + }, + ); + Self { instance, surface, adapter, device, + swap_chain, } } + + pub fn draw(&mut self) { + let frame = self.swap_chain.get_next_texture(); + + let mut encoder = self + .device + .create_command_encoder(&CommandEncoderDescriptor { todo: 0 }); + + let _ = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor { + attachment: &frame.view, + resolve_target: None, + load_op: wgpu::LoadOp::Clear, + store_op: wgpu::StoreOp::Store, + clear_color: wgpu::Color { + r: 1.0, + g: 1.0, + b: 1.0, + a: 1.0, + }, + }], + depth_stencil_attachment: None, + }); + + self.device.get_queue().submit(&[encoder.finish()]); + } } impl text::Renderer for Renderer { -- cgit From a7d11944039a1b5ea5b72256e8d15367d99e6010 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sat, 5 Oct 2019 03:56:18 +0200 Subject: Add `Renderer` and `Primitive` concepts --- wgpu/src/lib.rs | 70 +++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 56 insertions(+), 14 deletions(-) (limited to 'wgpu') diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 1e11749b..28964858 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -1,7 +1,7 @@ use iced_native::{ - button, checkbox, image, radio, renderer::Debugger, slider, text, Button, - Checkbox, Color, Image, Layout, MouseCursor, Node, Point, Radio, Slider, - Style, Text, + button, checkbox, column, image, radio, renderer::Debugger, row, slider, + text, Button, Checkbox, Color, Column, Image, Layout, Node, Point, Radio, + Row, Slider, Style, Text, Widget, }; use raw_window_handle::HasRawWindowHandle; @@ -87,12 +87,36 @@ impl Renderer { } } +impl column::Renderer for Renderer { + fn draw( + &mut self, + _column: &Column<'_, Message, Self>, + _layout: Layout<'_>, + _cursor_position: Point, + ) -> Self::Primitive { + () + } +} + +impl row::Renderer for Renderer { + fn draw( + &mut self, + _column: &Row<'_, Message, Self>, + _layout: Layout<'_>, + _cursor_position: Point, + ) -> Self::Primitive { + () + } +} + impl text::Renderer for Renderer { fn node(&self, _text: &Text) -> Node { Node::new(Style::default()) } - fn draw(&mut self, _text: &Text, _layout: Layout<'_>) {} + fn draw(&mut self, _text: &Text, _layout: Layout<'_>) -> Self::Primitive { + () + } } impl checkbox::Renderer for Renderer { @@ -105,8 +129,8 @@ impl checkbox::Renderer for Renderer { _checkbox: &Checkbox, _layout: Layout<'_>, _cursor_position: Point, - ) -> MouseCursor { - MouseCursor::OutOfBounds + ) -> Self::Primitive { + () } } @@ -120,8 +144,8 @@ impl radio::Renderer for Renderer { _radio: &Radio, _layout: Layout<'_>, _cursor_position: Point, - ) -> MouseCursor { - MouseCursor::OutOfBounds + ) -> Self::Primitive { + () } } @@ -135,8 +159,8 @@ impl slider::Renderer for Renderer { _slider: &Slider, _layout: Layout<'_>, _cursor_position: Point, - ) -> MouseCursor { - MouseCursor::OutOfBounds + ) -> Self::Primitive { + () } } @@ -145,7 +169,13 @@ impl image::Renderer<&str> for Renderer { Node::new(Style::default()) } - fn draw(&mut self, _checkbox: &Image<&str>, _layout: Layout<'_>) {} + fn draw( + &mut self, + _checkbox: &Image<&str>, + _layout: Layout<'_>, + ) -> Self::Primitive { + () + } } impl button::Renderer for Renderer { @@ -158,11 +188,23 @@ impl button::Renderer for Renderer { _button: &Button, _layout: Layout<'_>, _cursor_position: Point, - ) -> MouseCursor { - MouseCursor::OutOfBounds + ) -> Self::Primitive { + () } } +impl iced_native::Renderer for Renderer { + type Primitive = (); +} + impl Debugger for Renderer { - fn explain(&mut self, _layout: &Layout<'_>, _color: Color) {} + fn explain( + &mut self, + widget: &dyn Widget, + layout: Layout<'_>, + cursor_position: Point, + _color: Color, + ) -> Self::Primitive { + widget.draw(self, layout, cursor_position) + } } -- cgit From a90f7fcb987f667a80038a5e72f379abbd59d932 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sat, 5 Oct 2019 03:58:23 +0200 Subject: Move `MouseCursor` to `iced_wgpu` --- wgpu/src/mouse_cursor.rs | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 wgpu/src/mouse_cursor.rs (limited to 'wgpu') diff --git a/wgpu/src/mouse_cursor.rs b/wgpu/src/mouse_cursor.rs new file mode 100644 index 00000000..4ef6361a --- /dev/null +++ b/wgpu/src/mouse_cursor.rs @@ -0,0 +1,35 @@ +/// The state of the mouse cursor. +#[derive(Debug, Eq, PartialEq, Clone, Copy)] +pub enum MouseCursor { + /// The cursor is out of the bounds of the user interface. + OutOfBounds, + + /// The cursor is over a non-interactive widget. + Idle, + + /// The cursor is over a clickable widget. + Pointer, + + /// The cursor is over a busy widget. + Working, + + /// The cursor is over a grabbable widget. + Grab, + + /// The cursor is grabbing a widget. + Grabbing, +} + +#[cfg(feature = "winit")] +impl From for winit::window::CursorIcon { + fn from(mouse_cursor: MouseCursor) -> winit::window::CursorIcon { + match mouse_cursor { + MouseCursor::OutOfBounds => winit::window::CursorIcon::Default, + MouseCursor::Idle => winit::window::CursorIcon::Default, + MouseCursor::Pointer => winit::window::CursorIcon::Hand, + MouseCursor::Working => winit::window::CursorIcon::Progress, + MouseCursor::Grab => winit::window::CursorIcon::Grab, + MouseCursor::Grabbing => winit::window::CursorIcon::Grabbing, + } + } +} -- cgit From 0c3f78713d24b263e94cf6aebb8862926feaff23 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sat, 5 Oct 2019 05:12:36 +0200 Subject: Draft basic text rendering using `wgpu_glyph` --- wgpu/Cargo.toml | 1 + wgpu/src/lib.rs | 226 ++++++++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 186 insertions(+), 41 deletions(-) (limited to 'wgpu') diff --git a/wgpu/Cargo.toml b/wgpu/Cargo.toml index 879def28..79661baa 100644 --- a/wgpu/Cargo.toml +++ b/wgpu/Cargo.toml @@ -13,4 +13,5 @@ vulkan = ["wgpu/vulkan"] [dependencies] iced_native = { version = "0.1.0-alpha", path = "../native" } wgpu = "0.3" +wgpu_glyph = "0.4" raw-window-handle = "0.1" diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 28964858..d8f727cd 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -1,7 +1,7 @@ use iced_native::{ button, checkbox, column, image, radio, renderer::Debugger, row, slider, text, Button, Checkbox, Color, Column, Image, Layout, Node, Point, Radio, - Row, Slider, Style, Text, Widget, + Rectangle, Row, Slider, Style, Text, Widget, }; use raw_window_handle::HasRawWindowHandle; @@ -10,28 +10,34 @@ use wgpu::{ Instance, Limits, PowerPreference, RequestAdapterOptions, Surface, SwapChain, SwapChainDescriptor, TextureFormat, TextureUsage, }; +use wgpu_glyph::{GlyphBrush, GlyphBrushBuilder, GlyphCruncher, Section}; + +use std::f32; +use std::{cell::RefCell, rc::Rc}; pub struct Renderer { instance: Instance, surface: Surface, adapter: Adapter, device: Device, + glyph_brush: Rc>>, +} + +pub struct Target { + width: u16, + height: u16, swap_chain: SwapChain, } impl Renderer { - pub fn new( - window: &W, - width: u32, - height: u32, - ) -> Self { + pub fn new(window: &W) -> Self { let instance = Instance::new(); let adapter = instance.request_adapter(&RequestAdapterOptions { power_preference: PowerPreference::LowPower, }); - let device = adapter.request_device(&DeviceDescriptor { + let mut device = adapter.request_device(&DeviceDescriptor { extensions: Extensions { anisotropic_filtering: false, }, @@ -40,28 +46,40 @@ impl Renderer { let surface = instance.create_surface(window.raw_window_handle()); - let swap_chain = device.create_swap_chain( - &surface, - &SwapChainDescriptor { - usage: TextureUsage::OUTPUT_ATTACHMENT, - format: TextureFormat::Bgra8UnormSrgb, - width, - height, - present_mode: wgpu::PresentMode::Vsync, - }, - ); + let font: &[u8] = + include_bytes!("../../examples/tour/resources/Roboto-Regular.ttf"); + + let glyph_brush = GlyphBrushBuilder::using_font_bytes(font) + .build(&mut device, TextureFormat::Bgra8UnormSrgb); Self { instance, surface, adapter, device, - swap_chain, + glyph_brush: Rc::new(RefCell::new(glyph_brush)), } } - pub fn draw(&mut self) { - let frame = self.swap_chain.get_next_texture(); + pub fn target(&self, width: u16, height: u16) -> Target { + Target { + width, + height, + swap_chain: self.device.create_swap_chain( + &self.surface, + &SwapChainDescriptor { + usage: TextureUsage::OUTPUT_ATTACHMENT, + format: TextureFormat::Bgra8UnormSrgb, + width: u32::from(width), + height: u32::from(height), + present_mode: wgpu::PresentMode::Vsync, + }, + ), + } + } + + pub fn draw(&mut self, target: &mut Target, primitive: &Primitive) { + let frame = target.swap_chain.get_next_texture(); let mut encoder = self .device @@ -83,39 +101,169 @@ impl Renderer { depth_stencil_attachment: None, }); + self.draw_primitive(primitive); + + self.glyph_brush + .borrow_mut() + .draw_queued( + &mut self.device, + &mut encoder, + &frame.view, + u32::from(target.width), + u32::from(target.height), + ) + .expect("Draw text"); + self.device.get_queue().submit(&[encoder.finish()]); } + + fn draw_primitive(&mut self, primitive: &Primitive) { + match primitive { + Primitive::None => {} + Primitive::Group { primitives } => { + for primitive in primitives { + self.draw_primitive(primitive) + } + } + Primitive::Text { + content, + bounds, + size, + } => self.glyph_brush.borrow_mut().queue(Section { + text: &content, + screen_position: (bounds.x, bounds.y), + bounds: (bounds.width, bounds.height), + scale: wgpu_glyph::Scale { x: *size, y: *size }, + ..Default::default() + }), + } + } +} + +#[derive(Debug, Clone)] +pub enum Primitive { + None, + Group { + primitives: Vec, + }, + Text { + content: String, + bounds: Rectangle, + size: f32, + }, +} + +impl iced_native::Renderer for Renderer { + type Primitive = Primitive; } impl column::Renderer for Renderer { fn draw( &mut self, - _column: &Column<'_, Message, Self>, - _layout: Layout<'_>, - _cursor_position: Point, + column: &Column<'_, Message, Self>, + layout: Layout<'_>, + cursor_position: Point, ) -> Self::Primitive { - () + Primitive::Group { + primitives: column + .children + .iter() + .zip(layout.children()) + .map(|(child, layout)| { + child.draw(self, layout, cursor_position) + }) + .collect(), + } } } impl row::Renderer for Renderer { fn draw( &mut self, - _column: &Row<'_, Message, Self>, - _layout: Layout<'_>, - _cursor_position: Point, + row: &Row<'_, Message, Self>, + layout: Layout<'_>, + cursor_position: Point, ) -> Self::Primitive { - () + Primitive::Group { + primitives: row + .children + .iter() + .zip(layout.children()) + .map(|(child, layout)| { + child.draw(self, layout, cursor_position) + }) + .collect(), + } } } impl text::Renderer for Renderer { - fn node(&self, _text: &Text) -> Node { - Node::new(Style::default()) + fn node(&self, text: &Text) -> Node { + let glyph_brush = self.glyph_brush.clone(); + let content = text.content.clone(); + + // TODO: Investigate why stretch tries to measure this MANY times + // with every ancestor's bounds. + // Bug? Using the library wrong? I should probably open an issue on + // the stretch repository. + // I noticed that the first measure is the one that matters in + // practice. Here, we use a RefCell to store the cached measurement. + let measure = RefCell::new(None); + let size = text.size.map(f32::from).unwrap_or(20.0); + + let style = Style::default().width(text.width); + + iced_native::Node::with_measure(style, move |bounds| { + let mut measure = measure.borrow_mut(); + + if measure.is_none() { + let bounds = ( + match bounds.width { + iced_native::Number::Undefined => f32::INFINITY, + iced_native::Number::Defined(w) => w, + }, + match bounds.height { + iced_native::Number::Undefined => f32::INFINITY, + iced_native::Number::Defined(h) => h, + }, + ); + + let text = Section { + text: &content, + scale: wgpu_glyph::Scale { x: size, y: size }, + bounds, + ..Default::default() + }; + + let (width, height) = if let Some(bounds) = + glyph_brush.borrow_mut().glyph_bounds(&text) + { + (bounds.width(), bounds.height()) + } else { + (0.0, 0.0) + }; + + let size = iced_native::Size { width, height }; + + // If the text has no width boundary we avoid caching as the + // layout engine may just be measuring text in a row. + if bounds.0 == f32::INFINITY { + return size; + } else { + *measure = Some(size); + } + } + + measure.unwrap() + }) } - fn draw(&mut self, _text: &Text, _layout: Layout<'_>) -> Self::Primitive { - () + fn draw(&mut self, text: &Text, layout: Layout<'_>) -> Self::Primitive { + Primitive::Text { + content: text.content.clone(), + size: f32::from(text.size.unwrap_or(20)), + bounds: layout.bounds(), + } } } @@ -130,7 +278,7 @@ impl checkbox::Renderer for Renderer { _layout: Layout<'_>, _cursor_position: Point, ) -> Self::Primitive { - () + Primitive::None } } @@ -145,7 +293,7 @@ impl radio::Renderer for Renderer { _layout: Layout<'_>, _cursor_position: Point, ) -> Self::Primitive { - () + Primitive::None } } @@ -160,7 +308,7 @@ impl slider::Renderer for Renderer { _layout: Layout<'_>, _cursor_position: Point, ) -> Self::Primitive { - () + Primitive::None } } @@ -174,7 +322,7 @@ impl image::Renderer<&str> for Renderer { _checkbox: &Image<&str>, _layout: Layout<'_>, ) -> Self::Primitive { - () + Primitive::None } } @@ -189,14 +337,10 @@ impl button::Renderer for Renderer { _layout: Layout<'_>, _cursor_position: Point, ) -> Self::Primitive { - () + Primitive::None } } -impl iced_native::Renderer for Renderer { - type Primitive = (); -} - impl Debugger for Renderer { fn explain( &mut self, -- cgit From 5a5ca34b5fcab9266359d3f0885782969f8c058e Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sat, 5 Oct 2019 19:22:51 +0200 Subject: Modularize `iced_wgpu` --- wgpu/src/lib.rs | 359 +----------------------------------------- wgpu/src/primitive.rs | 14 ++ wgpu/src/renderer.rs | 167 ++++++++++++++++++++ wgpu/src/renderer/button.rs | 18 +++ wgpu/src/renderer/checkbox.rs | 18 +++ wgpu/src/renderer/column.rs | 22 +++ wgpu/src/renderer/image.rs | 16 ++ wgpu/src/renderer/radio.rs | 17 ++ wgpu/src/renderer/row.rs | 22 +++ wgpu/src/renderer/slider.rs | 17 ++ wgpu/src/renderer/text.rs | 77 +++++++++ 11 files changed, 394 insertions(+), 353 deletions(-) create mode 100644 wgpu/src/primitive.rs create mode 100644 wgpu/src/renderer.rs create mode 100644 wgpu/src/renderer/button.rs create mode 100644 wgpu/src/renderer/checkbox.rs create mode 100644 wgpu/src/renderer/column.rs create mode 100644 wgpu/src/renderer/image.rs create mode 100644 wgpu/src/renderer/radio.rs create mode 100644 wgpu/src/renderer/row.rs create mode 100644 wgpu/src/renderer/slider.rs create mode 100644 wgpu/src/renderer/text.rs (limited to 'wgpu') diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index d8f727cd..9a2a336f 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -1,354 +1,7 @@ -use iced_native::{ - button, checkbox, column, image, radio, renderer::Debugger, row, slider, - text, Button, Checkbox, Color, Column, Image, Layout, Node, Point, Radio, - Rectangle, Row, Slider, Style, Text, Widget, -}; +mod mouse_cursor; +mod primitive; +mod renderer; -use raw_window_handle::HasRawWindowHandle; -use wgpu::{ - Adapter, CommandEncoderDescriptor, Device, DeviceDescriptor, Extensions, - Instance, Limits, PowerPreference, RequestAdapterOptions, Surface, - SwapChain, SwapChainDescriptor, TextureFormat, TextureUsage, -}; -use wgpu_glyph::{GlyphBrush, GlyphBrushBuilder, GlyphCruncher, Section}; - -use std::f32; -use std::{cell::RefCell, rc::Rc}; - -pub struct Renderer { - instance: Instance, - surface: Surface, - adapter: Adapter, - device: Device, - glyph_brush: Rc>>, -} - -pub struct Target { - width: u16, - height: u16, - swap_chain: SwapChain, -} - -impl Renderer { - pub fn new(window: &W) -> Self { - let instance = Instance::new(); - - let adapter = instance.request_adapter(&RequestAdapterOptions { - power_preference: PowerPreference::LowPower, - }); - - let mut device = adapter.request_device(&DeviceDescriptor { - extensions: Extensions { - anisotropic_filtering: false, - }, - limits: Limits { max_bind_groups: 1 }, - }); - - let surface = instance.create_surface(window.raw_window_handle()); - - let font: &[u8] = - include_bytes!("../../examples/tour/resources/Roboto-Regular.ttf"); - - let glyph_brush = GlyphBrushBuilder::using_font_bytes(font) - .build(&mut device, TextureFormat::Bgra8UnormSrgb); - - Self { - instance, - surface, - adapter, - device, - glyph_brush: Rc::new(RefCell::new(glyph_brush)), - } - } - - pub fn target(&self, width: u16, height: u16) -> Target { - Target { - width, - height, - swap_chain: self.device.create_swap_chain( - &self.surface, - &SwapChainDescriptor { - usage: TextureUsage::OUTPUT_ATTACHMENT, - format: TextureFormat::Bgra8UnormSrgb, - width: u32::from(width), - height: u32::from(height), - present_mode: wgpu::PresentMode::Vsync, - }, - ), - } - } - - pub fn draw(&mut self, target: &mut Target, primitive: &Primitive) { - let frame = target.swap_chain.get_next_texture(); - - let mut encoder = self - .device - .create_command_encoder(&CommandEncoderDescriptor { todo: 0 }); - - let _ = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor { - attachment: &frame.view, - resolve_target: None, - load_op: wgpu::LoadOp::Clear, - store_op: wgpu::StoreOp::Store, - clear_color: wgpu::Color { - r: 1.0, - g: 1.0, - b: 1.0, - a: 1.0, - }, - }], - depth_stencil_attachment: None, - }); - - self.draw_primitive(primitive); - - self.glyph_brush - .borrow_mut() - .draw_queued( - &mut self.device, - &mut encoder, - &frame.view, - u32::from(target.width), - u32::from(target.height), - ) - .expect("Draw text"); - - self.device.get_queue().submit(&[encoder.finish()]); - } - - fn draw_primitive(&mut self, primitive: &Primitive) { - match primitive { - Primitive::None => {} - Primitive::Group { primitives } => { - for primitive in primitives { - self.draw_primitive(primitive) - } - } - Primitive::Text { - content, - bounds, - size, - } => self.glyph_brush.borrow_mut().queue(Section { - text: &content, - screen_position: (bounds.x, bounds.y), - bounds: (bounds.width, bounds.height), - scale: wgpu_glyph::Scale { x: *size, y: *size }, - ..Default::default() - }), - } - } -} - -#[derive(Debug, Clone)] -pub enum Primitive { - None, - Group { - primitives: Vec, - }, - Text { - content: String, - bounds: Rectangle, - size: f32, - }, -} - -impl iced_native::Renderer for Renderer { - type Primitive = Primitive; -} - -impl column::Renderer for Renderer { - fn draw( - &mut self, - column: &Column<'_, Message, Self>, - layout: Layout<'_>, - cursor_position: Point, - ) -> Self::Primitive { - Primitive::Group { - primitives: column - .children - .iter() - .zip(layout.children()) - .map(|(child, layout)| { - child.draw(self, layout, cursor_position) - }) - .collect(), - } - } -} - -impl row::Renderer for Renderer { - fn draw( - &mut self, - row: &Row<'_, Message, Self>, - layout: Layout<'_>, - cursor_position: Point, - ) -> Self::Primitive { - Primitive::Group { - primitives: row - .children - .iter() - .zip(layout.children()) - .map(|(child, layout)| { - child.draw(self, layout, cursor_position) - }) - .collect(), - } - } -} - -impl text::Renderer for Renderer { - fn node(&self, text: &Text) -> Node { - let glyph_brush = self.glyph_brush.clone(); - let content = text.content.clone(); - - // TODO: Investigate why stretch tries to measure this MANY times - // with every ancestor's bounds. - // Bug? Using the library wrong? I should probably open an issue on - // the stretch repository. - // I noticed that the first measure is the one that matters in - // practice. Here, we use a RefCell to store the cached measurement. - let measure = RefCell::new(None); - let size = text.size.map(f32::from).unwrap_or(20.0); - - let style = Style::default().width(text.width); - - iced_native::Node::with_measure(style, move |bounds| { - let mut measure = measure.borrow_mut(); - - if measure.is_none() { - let bounds = ( - match bounds.width { - iced_native::Number::Undefined => f32::INFINITY, - iced_native::Number::Defined(w) => w, - }, - match bounds.height { - iced_native::Number::Undefined => f32::INFINITY, - iced_native::Number::Defined(h) => h, - }, - ); - - let text = Section { - text: &content, - scale: wgpu_glyph::Scale { x: size, y: size }, - bounds, - ..Default::default() - }; - - let (width, height) = if let Some(bounds) = - glyph_brush.borrow_mut().glyph_bounds(&text) - { - (bounds.width(), bounds.height()) - } else { - (0.0, 0.0) - }; - - let size = iced_native::Size { width, height }; - - // If the text has no width boundary we avoid caching as the - // layout engine may just be measuring text in a row. - if bounds.0 == f32::INFINITY { - return size; - } else { - *measure = Some(size); - } - } - - measure.unwrap() - }) - } - - fn draw(&mut self, text: &Text, layout: Layout<'_>) -> Self::Primitive { - Primitive::Text { - content: text.content.clone(), - size: f32::from(text.size.unwrap_or(20)), - bounds: layout.bounds(), - } - } -} - -impl checkbox::Renderer for Renderer { - fn node(&mut self, _checkbox: &Checkbox) -> Node { - Node::new(Style::default()) - } - - fn draw( - &mut self, - _checkbox: &Checkbox, - _layout: Layout<'_>, - _cursor_position: Point, - ) -> Self::Primitive { - Primitive::None - } -} - -impl radio::Renderer for Renderer { - fn node(&mut self, _checkbox: &Radio) -> Node { - Node::new(Style::default()) - } - - fn draw( - &mut self, - _radio: &Radio, - _layout: Layout<'_>, - _cursor_position: Point, - ) -> Self::Primitive { - Primitive::None - } -} - -impl slider::Renderer for Renderer { - fn node(&self, _slider: &Slider) -> Node { - Node::new(Style::default()) - } - - fn draw( - &mut self, - _slider: &Slider, - _layout: Layout<'_>, - _cursor_position: Point, - ) -> Self::Primitive { - Primitive::None - } -} - -impl image::Renderer<&str> for Renderer { - fn node(&mut self, _image: &Image<&str>) -> Node { - Node::new(Style::default()) - } - - fn draw( - &mut self, - _checkbox: &Image<&str>, - _layout: Layout<'_>, - ) -> Self::Primitive { - Primitive::None - } -} - -impl button::Renderer for Renderer { - fn node(&self, _button: &Button) -> Node { - Node::new(Style::default()) - } - - fn draw( - &mut self, - _button: &Button, - _layout: Layout<'_>, - _cursor_position: Point, - ) -> Self::Primitive { - Primitive::None - } -} - -impl Debugger for Renderer { - fn explain( - &mut self, - widget: &dyn Widget, - layout: Layout<'_>, - cursor_position: Point, - _color: Color, - ) -> Self::Primitive { - widget.draw(self, layout, cursor_position) - } -} +pub use mouse_cursor::MouseCursor; +pub use primitive::Primitive; +pub use renderer::{Renderer, Target}; diff --git a/wgpu/src/primitive.rs b/wgpu/src/primitive.rs new file mode 100644 index 00000000..04b2e99f --- /dev/null +++ b/wgpu/src/primitive.rs @@ -0,0 +1,14 @@ +use iced_native::Rectangle; + +#[derive(Debug, Clone)] +pub enum Primitive { + None, + Group { + primitives: Vec, + }, + Text { + content: String, + bounds: Rectangle, + size: f32, + }, +} diff --git a/wgpu/src/renderer.rs b/wgpu/src/renderer.rs new file mode 100644 index 00000000..df8887e3 --- /dev/null +++ b/wgpu/src/renderer.rs @@ -0,0 +1,167 @@ +use crate::Primitive; +use iced_native::{renderer::Debugger, Color, Layout, Point, Widget}; + +use raw_window_handle::HasRawWindowHandle; +use wgpu::{ + Adapter, CommandEncoderDescriptor, Device, DeviceDescriptor, Extensions, + Instance, Limits, PowerPreference, RequestAdapterOptions, Surface, + SwapChain, SwapChainDescriptor, TextureFormat, TextureUsage, +}; +use wgpu_glyph::{GlyphBrush, GlyphBrushBuilder, Section}; + +use std::{cell::RefCell, rc::Rc}; + +mod button; +mod checkbox; +mod column; +mod image; +mod radio; +mod row; +mod slider; +mod text; + +pub struct Renderer { + instance: Instance, + surface: Surface, + adapter: Adapter, + device: Device, + glyph_brush: Rc>>, +} + +pub struct Target { + width: u16, + height: u16, + swap_chain: SwapChain, +} + +impl Renderer { + pub fn new(window: &W) -> Self { + let instance = Instance::new(); + + let adapter = instance.request_adapter(&RequestAdapterOptions { + power_preference: PowerPreference::LowPower, + }); + + let mut device = adapter.request_device(&DeviceDescriptor { + extensions: Extensions { + anisotropic_filtering: false, + }, + limits: Limits { max_bind_groups: 1 }, + }); + + let surface = instance.create_surface(window.raw_window_handle()); + + // TODO: Think about font loading strategy + // Loading system fonts with fallback may be a good idea + let font: &[u8] = + include_bytes!("../../examples/tour/resources/Roboto-Regular.ttf"); + + let glyph_brush = GlyphBrushBuilder::using_font_bytes(font) + .build(&mut device, TextureFormat::Bgra8UnormSrgb); + + Self { + instance, + surface, + adapter, + device, + glyph_brush: Rc::new(RefCell::new(glyph_brush)), + } + } + + pub fn target(&self, width: u16, height: u16) -> Target { + Target { + width, + height, + swap_chain: self.device.create_swap_chain( + &self.surface, + &SwapChainDescriptor { + usage: TextureUsage::OUTPUT_ATTACHMENT, + format: TextureFormat::Bgra8UnormSrgb, + width: u32::from(width), + height: u32::from(height), + present_mode: wgpu::PresentMode::Vsync, + }, + ), + } + } + + pub fn draw(&mut self, target: &mut Target, primitive: &Primitive) { + let frame = target.swap_chain.get_next_texture(); + + let mut encoder = self + .device + .create_command_encoder(&CommandEncoderDescriptor { todo: 0 }); + + let _ = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor { + attachment: &frame.view, + resolve_target: None, + load_op: wgpu::LoadOp::Clear, + store_op: wgpu::StoreOp::Store, + clear_color: wgpu::Color { + r: 1.0, + g: 1.0, + b: 1.0, + a: 1.0, + }, + }], + depth_stencil_attachment: None, + }); + + self.draw_primitive(primitive); + + self.glyph_brush + .borrow_mut() + .draw_queued( + &mut self.device, + &mut encoder, + &frame.view, + u32::from(target.width), + u32::from(target.height), + ) + .expect("Draw text"); + + self.device.get_queue().submit(&[encoder.finish()]); + } + + fn draw_primitive(&mut self, primitive: &Primitive) { + match primitive { + Primitive::None => {} + Primitive::Group { primitives } => { + // TODO: Inspect a bit and regroup (?) + for primitive in primitives { + self.draw_primitive(primitive) + } + } + Primitive::Text { + content, + bounds, + size, + } => self.glyph_brush.borrow_mut().queue(Section { + text: &content, + screen_position: (bounds.x, bounds.y), + bounds: (bounds.width, bounds.height), + scale: wgpu_glyph::Scale { x: *size, y: *size }, + ..Default::default() + }), + } + } +} + +impl iced_native::Renderer for Renderer { + // TODO: Add `MouseCursor` here (?) + type Primitive = Primitive; +} + +impl Debugger for Renderer { + fn explain( + &mut self, + widget: &dyn Widget, + layout: Layout<'_>, + cursor_position: Point, + _color: Color, + ) -> Self::Primitive { + // TODO: Include a bordered box to display layout bounds + widget.draw(self, layout, cursor_position) + } +} diff --git a/wgpu/src/renderer/button.rs b/wgpu/src/renderer/button.rs new file mode 100644 index 00000000..24bc1de6 --- /dev/null +++ b/wgpu/src/renderer/button.rs @@ -0,0 +1,18 @@ +use crate::{Primitive, Renderer}; +use iced_native::{button, Button, Layout, Node, Point, Style}; + +impl button::Renderer for Renderer { + fn node(&self, _button: &Button) -> Node { + Node::new(Style::default()) + } + + fn draw( + &mut self, + _button: &Button, + _layout: Layout<'_>, + _cursor_position: Point, + ) -> Self::Primitive { + // TODO + Primitive::None + } +} diff --git a/wgpu/src/renderer/checkbox.rs b/wgpu/src/renderer/checkbox.rs new file mode 100644 index 00000000..c94a2157 --- /dev/null +++ b/wgpu/src/renderer/checkbox.rs @@ -0,0 +1,18 @@ +use crate::{Primitive, Renderer}; +use iced_native::{checkbox, Checkbox, Layout, Node, Point, Style}; + +impl checkbox::Renderer for Renderer { + fn node(&mut self, _checkbox: &Checkbox) -> Node { + Node::new(Style::default()) + } + + fn draw( + &mut self, + _checkbox: &Checkbox, + _layout: Layout<'_>, + _cursor_position: Point, + ) -> Self::Primitive { + // TODO + Primitive::None + } +} diff --git a/wgpu/src/renderer/column.rs b/wgpu/src/renderer/column.rs new file mode 100644 index 00000000..1b9adad6 --- /dev/null +++ b/wgpu/src/renderer/column.rs @@ -0,0 +1,22 @@ +use crate::{Primitive, Renderer}; +use iced_native::{column, Column, Layout, Point}; + +impl column::Renderer for Renderer { + fn draw( + &mut self, + column: &Column<'_, Message, Self>, + layout: Layout<'_>, + cursor_position: Point, + ) -> Self::Primitive { + Primitive::Group { + primitives: column + .children + .iter() + .zip(layout.children()) + .map(|(child, layout)| { + child.draw(self, layout, cursor_position) + }) + .collect(), + } + } +} diff --git a/wgpu/src/renderer/image.rs b/wgpu/src/renderer/image.rs new file mode 100644 index 00000000..6ff39d30 --- /dev/null +++ b/wgpu/src/renderer/image.rs @@ -0,0 +1,16 @@ +use crate::{Primitive, Renderer}; +use iced_native::{image, Image, Layout, Node, Style}; + +impl image::Renderer<&str> for Renderer { + fn node(&mut self, _image: &Image<&str>) -> Node { + Node::new(Style::default()) + } + + fn draw( + &mut self, + _image: &Image<&str>, + _layout: Layout<'_>, + ) -> Self::Primitive { + Primitive::None + } +} diff --git a/wgpu/src/renderer/radio.rs b/wgpu/src/renderer/radio.rs new file mode 100644 index 00000000..ce419ae0 --- /dev/null +++ b/wgpu/src/renderer/radio.rs @@ -0,0 +1,17 @@ +use crate::{Primitive, Renderer}; +use iced_native::{radio, Layout, Node, Point, Radio, Style}; + +impl radio::Renderer for Renderer { + fn node(&mut self, _checkbox: &Radio) -> Node { + Node::new(Style::default()) + } + + fn draw( + &mut self, + _radio: &Radio, + _layout: Layout<'_>, + _cursor_position: Point, + ) -> Self::Primitive { + Primitive::None + } +} diff --git a/wgpu/src/renderer/row.rs b/wgpu/src/renderer/row.rs new file mode 100644 index 00000000..be9e4ede --- /dev/null +++ b/wgpu/src/renderer/row.rs @@ -0,0 +1,22 @@ +use crate::{Primitive, Renderer}; +use iced_native::{row, Layout, Point, Row}; + +impl row::Renderer for Renderer { + fn draw( + &mut self, + row: &Row<'_, Message, Self>, + layout: Layout<'_>, + cursor_position: Point, + ) -> Self::Primitive { + Primitive::Group { + primitives: row + .children + .iter() + .zip(layout.children()) + .map(|(child, layout)| { + child.draw(self, layout, cursor_position) + }) + .collect(), + } + } +} diff --git a/wgpu/src/renderer/slider.rs b/wgpu/src/renderer/slider.rs new file mode 100644 index 00000000..2e76022d --- /dev/null +++ b/wgpu/src/renderer/slider.rs @@ -0,0 +1,17 @@ +use crate::{Primitive, Renderer}; +use iced_native::{slider, Layout, Node, Point, Slider, Style}; + +impl slider::Renderer for Renderer { + fn node(&self, _slider: &Slider) -> Node { + Node::new(Style::default()) + } + + fn draw( + &mut self, + _slider: &Slider, + _layout: Layout<'_>, + _cursor_position: Point, + ) -> Self::Primitive { + Primitive::None + } +} diff --git a/wgpu/src/renderer/text.rs b/wgpu/src/renderer/text.rs new file mode 100644 index 00000000..4434cc22 --- /dev/null +++ b/wgpu/src/renderer/text.rs @@ -0,0 +1,77 @@ +use crate::{Primitive, Renderer}; +use iced_native::{text, Layout, Node, Style, Text}; + +use wgpu_glyph::{GlyphCruncher, Section}; + +use std::cell::RefCell; +use std::f32; + +impl text::Renderer for Renderer { + fn node(&self, text: &Text) -> Node { + let glyph_brush = self.glyph_brush.clone(); + let content = text.content.clone(); + + // TODO: Investigate why stretch tries to measure this MANY times + // with every ancestor's bounds. + // Bug? Using the library wrong? I should probably open an issue on + // the stretch repository. + // I noticed that the first measure is the one that matters in + // practice. Here, we use a RefCell to store the cached measurement. + let measure = RefCell::new(None); + let size = text.size.map(f32::from).unwrap_or(20.0); + + let style = Style::default().width(text.width); + + iced_native::Node::with_measure(style, move |bounds| { + let mut measure = measure.borrow_mut(); + + if measure.is_none() { + let bounds = ( + match bounds.width { + iced_native::Number::Undefined => f32::INFINITY, + iced_native::Number::Defined(w) => w, + }, + match bounds.height { + iced_native::Number::Undefined => f32::INFINITY, + iced_native::Number::Defined(h) => h, + }, + ); + + let text = Section { + text: &content, + scale: wgpu_glyph::Scale { x: size, y: size }, + bounds, + ..Default::default() + }; + + let (width, height) = if let Some(bounds) = + glyph_brush.borrow_mut().glyph_bounds(&text) + { + (bounds.width(), bounds.height()) + } else { + (0.0, 0.0) + }; + + let size = iced_native::Size { width, height }; + + // If the text has no width boundary we avoid caching as the + // layout engine may just be measuring text in a row. + if bounds.0 == f32::INFINITY { + return size; + } else { + *measure = Some(size); + } + } + + measure.unwrap() + }) + } + + fn draw(&mut self, text: &Text, layout: Layout<'_>) -> Self::Primitive { + Primitive::Text { + content: text.content.clone(), + size: f32::from(text.size.unwrap_or(20)), + bounds: layout.bounds(), + } + } +} -- cgit From 7765e6da50a3448501ee1b639e580c94a4fbda8a Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sun, 6 Oct 2019 19:22:25 +0200 Subject: Draft `Box` primitive --- wgpu/src/lib.rs | 2 +- wgpu/src/primitive.rs | 11 ++++++++++- wgpu/src/renderer.rs | 3 +++ wgpu/src/renderer/button.rs | 38 ++++++++++++++++++++++++++++++-------- 4 files changed, 44 insertions(+), 10 deletions(-) (limited to 'wgpu') diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 9a2a336f..d5cfee64 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -3,5 +3,5 @@ mod primitive; mod renderer; pub use mouse_cursor::MouseCursor; -pub use primitive::Primitive; +pub use primitive::{Background, Primitive}; pub use renderer::{Renderer, Target}; diff --git a/wgpu/src/primitive.rs b/wgpu/src/primitive.rs index 04b2e99f..e9ab100e 100644 --- a/wgpu/src/primitive.rs +++ b/wgpu/src/primitive.rs @@ -1,4 +1,4 @@ -use iced_native::Rectangle; +use iced_native::{Color, Rectangle}; #[derive(Debug, Clone)] pub enum Primitive { @@ -11,4 +11,13 @@ pub enum Primitive { bounds: Rectangle, size: f32, }, + Box { + bounds: Rectangle, + background: Background, + }, +} + +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum Background { + Color(Color), } diff --git a/wgpu/src/renderer.rs b/wgpu/src/renderer.rs index df8887e3..56986bd1 100644 --- a/wgpu/src/renderer.rs +++ b/wgpu/src/renderer.rs @@ -144,6 +144,9 @@ impl Renderer { scale: wgpu_glyph::Scale { x: *size, y: *size }, ..Default::default() }), + Primitive::Box { bounds, background } => { + // TODO: Batch boxes and draw them all at once + } } } } diff --git a/wgpu/src/renderer/button.rs b/wgpu/src/renderer/button.rs index 24bc1de6..b9dfb9ac 100644 --- a/wgpu/src/renderer/button.rs +++ b/wgpu/src/renderer/button.rs @@ -1,18 +1,40 @@ -use crate::{Primitive, Renderer}; -use iced_native::{button, Button, Layout, Node, Point, Style}; +use crate::{Background, Primitive, Renderer}; +use iced_native::{button, Button, Color, Layout, Length, Node, Point, Style}; impl button::Renderer for Renderer { - fn node(&self, _button: &Button) -> Node { - Node::new(Style::default()) + fn node(&self, button: &Button) -> Node { + let style = Style::default() + .width(button.width) + .min_height(Length::Units(30)) + .min_width(Length::Units(100)) + .align_self(button.align_self); + + Node::new(style) } fn draw( &mut self, - _button: &Button, - _layout: Layout<'_>, + button: &Button, + layout: Layout<'_>, _cursor_position: Point, ) -> Self::Primitive { - // TODO - Primitive::None + Primitive::Group { + primitives: vec![ + Primitive::Box { + bounds: layout.bounds(), + background: Background::Color(Color { + r: 0.0, + b: 1.0, + g: 0.0, + a: 1.0, + }), + }, + Primitive::Text { + content: button.label.clone(), + size: 20.0, + bounds: layout.bounds(), + }, + ], + } } } -- cgit From 5286ef36b6a5eb6846b5675a7a4aced72601df3b Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sun, 6 Oct 2019 20:06:13 +0200 Subject: Make `tour` a simple example instead of a crate --- wgpu/src/renderer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'wgpu') diff --git a/wgpu/src/renderer.rs b/wgpu/src/renderer.rs index 56986bd1..f8f000f0 100644 --- a/wgpu/src/renderer.rs +++ b/wgpu/src/renderer.rs @@ -54,7 +54,7 @@ impl Renderer { // TODO: Think about font loading strategy // Loading system fonts with fallback may be a good idea let font: &[u8] = - include_bytes!("../../examples/tour/resources/Roboto-Regular.ttf"); + include_bytes!("../../examples/resources/Roboto-Regular.ttf"); let glyph_brush = GlyphBrushBuilder::using_font_bytes(font) .build(&mut device, TextureFormat::Bgra8UnormSrgb); -- cgit From 70c17b053b10741f6018b2559bb46c5f289cadb9 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Mon, 7 Oct 2019 02:17:40 +0200 Subject: Rename `Box` primitive to `Quad` --- wgpu/src/primitive.rs | 2 +- wgpu/src/renderer.rs | 4 ++-- wgpu/src/renderer/button.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'wgpu') diff --git a/wgpu/src/primitive.rs b/wgpu/src/primitive.rs index e9ab100e..91cdfc85 100644 --- a/wgpu/src/primitive.rs +++ b/wgpu/src/primitive.rs @@ -11,7 +11,7 @@ pub enum Primitive { bounds: Rectangle, size: f32, }, - Box { + Quad { bounds: Rectangle, background: Background, }, diff --git a/wgpu/src/renderer.rs b/wgpu/src/renderer.rs index f8f000f0..5db47a8e 100644 --- a/wgpu/src/renderer.rs +++ b/wgpu/src/renderer.rs @@ -144,8 +144,8 @@ impl Renderer { scale: wgpu_glyph::Scale { x: *size, y: *size }, ..Default::default() }), - Primitive::Box { bounds, background } => { - // TODO: Batch boxes and draw them all at once + Primitive::Quad { bounds, background } => { + // TODO: Batch quads and draw them all at once } } } diff --git a/wgpu/src/renderer/button.rs b/wgpu/src/renderer/button.rs index b9dfb9ac..fd874832 100644 --- a/wgpu/src/renderer/button.rs +++ b/wgpu/src/renderer/button.rs @@ -20,7 +20,7 @@ impl button::Renderer for Renderer { ) -> Self::Primitive { Primitive::Group { primitives: vec![ - Primitive::Box { + Primitive::Quad { bounds: layout.bounds(), background: Background::Color(Color { r: 0.0, -- cgit From c9510db551893775d3233340dd114d971e24323a Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Mon, 7 Oct 2019 03:56:16 +0200 Subject: Render colored quads --- wgpu/src/lib.rs | 5 + wgpu/src/primitive.rs | 1 + wgpu/src/quad.rs | 269 ++++++++++++++++++++++++++++++++++++++++++ wgpu/src/renderer.rs | 30 ++++- wgpu/src/renderer/button.rs | 10 +- wgpu/src/shader/quad.frag | 9 ++ wgpu/src/shader/quad.frag.spv | Bin 0 -> 372 bytes wgpu/src/shader/quad.vert | 24 ++++ wgpu/src/shader/quad.vert.spv | Bin 0 -> 2188 bytes wgpu/src/transformation.rs | 30 +++++ 10 files changed, 372 insertions(+), 6 deletions(-) create mode 100644 wgpu/src/quad.rs create mode 100644 wgpu/src/shader/quad.frag create mode 100644 wgpu/src/shader/quad.frag.spv create mode 100644 wgpu/src/shader/quad.vert create mode 100644 wgpu/src/shader/quad.vert.spv create mode 100644 wgpu/src/transformation.rs (limited to 'wgpu') diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index d5cfee64..33d8f5ed 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -1,6 +1,11 @@ mod mouse_cursor; mod primitive; +mod quad; mod renderer; +mod transformation; + +pub(crate) use quad::Quad; +pub(crate) use transformation::Transformation; pub use mouse_cursor::MouseCursor; pub use primitive::{Background, Primitive}; diff --git a/wgpu/src/primitive.rs b/wgpu/src/primitive.rs index 91cdfc85..f6730a1f 100644 --- a/wgpu/src/primitive.rs +++ b/wgpu/src/primitive.rs @@ -20,4 +20,5 @@ pub enum Primitive { #[derive(Debug, Clone, Copy, PartialEq)] pub enum Background { Color(Color), + // TODO: Add gradient and image variants } diff --git a/wgpu/src/quad.rs b/wgpu/src/quad.rs new file mode 100644 index 00000000..d0126bbd --- /dev/null +++ b/wgpu/src/quad.rs @@ -0,0 +1,269 @@ +use crate::Transformation; + +use std::mem; + +pub struct Pipeline { + pipeline: wgpu::RenderPipeline, + constants: wgpu::BindGroup, + transform: wgpu::Buffer, + vertices: wgpu::Buffer, + indices: wgpu::Buffer, + instances: wgpu::Buffer, +} + +impl Pipeline { + pub fn new(device: &mut wgpu::Device) -> Pipeline { + let constant_layout = + device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + bindings: &[wgpu::BindGroupLayoutBinding { + binding: 0, + visibility: wgpu::ShaderStage::VERTEX, + ty: wgpu::BindingType::UniformBuffer { dynamic: false }, + }], + }); + + let matrix: [f32; 16] = Transformation::identity().into(); + + let transform = device + .create_buffer_mapped( + 16, + wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST, + ) + .fill_from_slice(&matrix[..]); + + let constants = device.create_bind_group(&wgpu::BindGroupDescriptor { + layout: &constant_layout, + bindings: &[wgpu::Binding { + binding: 0, + resource: wgpu::BindingResource::Buffer { + buffer: &transform, + range: 0..64, + }, + }], + }); + + let layout = + device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + bind_group_layouts: &[&constant_layout], + }); + + let vs = include_bytes!("shader/quad.vert.spv"); + let vs_module = device.create_shader_module( + &wgpu::read_spirv(std::io::Cursor::new(&vs[..])) + .expect("Read quad vertex shader as SPIR-V"), + ); + + let fs = include_bytes!("shader/quad.frag.spv"); + let fs_module = device.create_shader_module( + &wgpu::read_spirv(std::io::Cursor::new(&fs[..])) + .expect("Read quad fragment shader as SPIR-V"), + ); + + let pipeline = + device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { + layout: &layout, + vertex_stage: wgpu::ProgrammableStageDescriptor { + module: &vs_module, + entry_point: "main", + }, + fragment_stage: Some(wgpu::ProgrammableStageDescriptor { + module: &fs_module, + entry_point: "main", + }), + rasterization_state: Some(wgpu::RasterizationStateDescriptor { + front_face: wgpu::FrontFace::Cw, + cull_mode: wgpu::CullMode::None, + depth_bias: 0, + depth_bias_slope_scale: 0.0, + depth_bias_clamp: 0.0, + }), + primitive_topology: wgpu::PrimitiveTopology::TriangleList, + color_states: &[wgpu::ColorStateDescriptor { + format: wgpu::TextureFormat::Bgra8UnormSrgb, + color_blend: wgpu::BlendDescriptor { + src_factor: wgpu::BlendFactor::SrcAlpha, + dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha, + operation: wgpu::BlendOperation::Add, + }, + alpha_blend: wgpu::BlendDescriptor { + src_factor: wgpu::BlendFactor::One, + dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha, + operation: wgpu::BlendOperation::Add, + }, + write_mask: wgpu::ColorWrite::ALL, + }], + depth_stencil_state: None, + index_format: wgpu::IndexFormat::Uint16, + vertex_buffers: &[ + wgpu::VertexBufferDescriptor { + stride: mem::size_of::() as u64, + step_mode: wgpu::InputStepMode::Vertex, + attributes: &[wgpu::VertexAttributeDescriptor { + shader_location: 0, + format: wgpu::VertexFormat::Float2, + offset: 0, + }], + }, + wgpu::VertexBufferDescriptor { + stride: mem::size_of::() as u64, + step_mode: wgpu::InputStepMode::Instance, + attributes: &[ + wgpu::VertexAttributeDescriptor { + shader_location: 1, + format: wgpu::VertexFormat::Float2, + offset: 0, + }, + wgpu::VertexAttributeDescriptor { + shader_location: 2, + format: wgpu::VertexFormat::Float2, + offset: 4 * 2, + }, + wgpu::VertexAttributeDescriptor { + shader_location: 3, + format: wgpu::VertexFormat::Float4, + offset: 4 * (2 + 2), + }, + ], + }, + ], + sample_count: 1, + sample_mask: !0, + alpha_to_coverage_enabled: false, + }); + + let vertices = device + .create_buffer_mapped(QUAD_VERTS.len(), wgpu::BufferUsage::VERTEX) + .fill_from_slice(&QUAD_VERTS); + + let indices = device + .create_buffer_mapped(QUAD_INDICES.len(), wgpu::BufferUsage::INDEX) + .fill_from_slice(&QUAD_INDICES); + + let instances = device.create_buffer(&wgpu::BufferDescriptor { + size: mem::size_of::() as u64 * Quad::MAX as u64, + usage: wgpu::BufferUsage::VERTEX | wgpu::BufferUsage::COPY_DST, + }); + + Pipeline { + pipeline, + constants, + transform, + vertices, + indices, + instances, + } + } + + pub fn draw( + &mut self, + device: &mut wgpu::Device, + encoder: &mut wgpu::CommandEncoder, + instances: &[Quad], + transformation: Transformation, + target: &wgpu::TextureView, + ) { + let matrix: [f32; 16] = transformation.into(); + + let transform_buffer = device + .create_buffer_mapped(16, wgpu::BufferUsage::COPY_SRC) + .fill_from_slice(&matrix[..]); + + encoder.copy_buffer_to_buffer( + &transform_buffer, + 0, + &self.transform, + 0, + 16 * 4, + ); + + let mut i = 0; + let total = instances.len(); + + while i < total { + let end = (i + Quad::MAX).min(total); + let amount = end - i; + + let instance_buffer = device + .create_buffer_mapped(amount, wgpu::BufferUsage::COPY_SRC) + .fill_from_slice(&instances[i..end]); + + encoder.copy_buffer_to_buffer( + &instance_buffer, + 0, + &self.instances, + 0, + (mem::size_of::() * amount) as u64, + ); + + { + let mut render_pass = + encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + color_attachments: &[ + wgpu::RenderPassColorAttachmentDescriptor { + attachment: target, + resolve_target: None, + load_op: wgpu::LoadOp::Load, + store_op: wgpu::StoreOp::Store, + clear_color: wgpu::Color { + r: 0.0, + g: 0.0, + b: 0.0, + a: 0.0, + }, + }, + ], + depth_stencil_attachment: None, + }); + + render_pass.set_pipeline(&self.pipeline); + render_pass.set_bind_group(0, &self.constants, &[]); + render_pass.set_index_buffer(&self.indices, 0); + render_pass.set_vertex_buffers( + 0, + &[(&self.vertices, 0), (&self.instances, 0)], + ); + + render_pass.draw_indexed( + 0..QUAD_INDICES.len() as u32, + 0, + 0..amount as u32, + ); + } + + i += Quad::MAX; + } + } +} + +#[derive(Clone, Copy)] +pub struct Vertex { + _position: [f32; 2], +} + +const QUAD_INDICES: [u16; 6] = [0, 1, 2, 0, 2, 3]; + +const QUAD_VERTS: [Vertex; 4] = [ + Vertex { + _position: [0.0, 0.0], + }, + Vertex { + _position: [1.0, 0.0], + }, + Vertex { + _position: [1.0, 1.0], + }, + Vertex { + _position: [0.0, 1.0], + }, +]; + +#[derive(Debug, Clone, Copy)] +pub struct Quad { + pub position: [f32; 2], + pub scale: [f32; 2], + pub color: [f32; 4], +} + +impl Quad { + const MAX: usize = 100_000; +} diff --git a/wgpu/src/renderer.rs b/wgpu/src/renderer.rs index 5db47a8e..8e69a91a 100644 --- a/wgpu/src/renderer.rs +++ b/wgpu/src/renderer.rs @@ -1,4 +1,4 @@ -use crate::Primitive; +use crate::{quad, Background, Primitive, Quad, Transformation}; use iced_native::{renderer::Debugger, Color, Layout, Point, Widget}; use raw_window_handle::HasRawWindowHandle; @@ -25,12 +25,16 @@ pub struct Renderer { surface: Surface, adapter: Adapter, device: Device, + quad_pipeline: quad::Pipeline, + + quads: Vec, glyph_brush: Rc>>, } pub struct Target { width: u16, height: u16, + transformation: Transformation, swap_chain: SwapChain, } @@ -59,11 +63,16 @@ impl Renderer { let glyph_brush = GlyphBrushBuilder::using_font_bytes(font) .build(&mut device, TextureFormat::Bgra8UnormSrgb); + let quad_pipeline = quad::Pipeline::new(&mut device); + Self { instance, surface, adapter, device, + quad_pipeline, + + quads: Vec::new(), glyph_brush: Rc::new(RefCell::new(glyph_brush)), } } @@ -72,6 +81,7 @@ impl Renderer { Target { width, height, + transformation: Transformation::orthographic(width, height), swap_chain: self.device.create_swap_chain( &self.surface, &SwapChainDescriptor { @@ -110,6 +120,16 @@ impl Renderer { self.draw_primitive(primitive); + self.quad_pipeline.draw( + &mut self.device, + &mut encoder, + &self.quads, + target.transformation, + &frame.view, + ); + + self.quads.clear(); + self.glyph_brush .borrow_mut() .draw_queued( @@ -145,7 +165,13 @@ impl Renderer { ..Default::default() }), Primitive::Quad { bounds, background } => { - // TODO: Batch quads and draw them all at once + self.quads.push(Quad { + position: [bounds.x, bounds.y], + scale: [bounds.width, bounds.height], + color: match background { + Background::Color(color) => color.into_linear(), + }, + }); } } } diff --git a/wgpu/src/renderer/button.rs b/wgpu/src/renderer/button.rs index fd874832..f75b44f7 100644 --- a/wgpu/src/renderer/button.rs +++ b/wgpu/src/renderer/button.rs @@ -18,14 +18,16 @@ impl button::Renderer for Renderer { layout: Layout<'_>, _cursor_position: Point, ) -> Self::Primitive { + let bounds = layout.bounds(); + Primitive::Group { primitives: vec![ Primitive::Quad { - bounds: layout.bounds(), + bounds, background: Background::Color(Color { - r: 0.0, - b: 1.0, - g: 0.0, + r: 0.8, + b: 0.8, + g: 0.8, a: 1.0, }), }, diff --git a/wgpu/src/shader/quad.frag b/wgpu/src/shader/quad.frag new file mode 100644 index 00000000..1aca250f --- /dev/null +++ b/wgpu/src/shader/quad.frag @@ -0,0 +1,9 @@ +#version 450 + +layout(location = 0) in vec4 v_Color; + +layout(location = 0) out vec4 o_Color; + +void main() { + o_Color = v_Color; +} diff --git a/wgpu/src/shader/quad.frag.spv b/wgpu/src/shader/quad.frag.spv new file mode 100644 index 00000000..33218c83 Binary files /dev/null and b/wgpu/src/shader/quad.frag.spv differ diff --git a/wgpu/src/shader/quad.vert b/wgpu/src/shader/quad.vert new file mode 100644 index 00000000..3392d43d --- /dev/null +++ b/wgpu/src/shader/quad.vert @@ -0,0 +1,24 @@ +#version 450 + +layout(location = 0) in vec2 v_Pos; +layout(location = 1) in vec2 i_Pos; +layout(location = 2) in vec2 i_Scale; +layout(location = 3) in vec4 i_Color; + +layout (set = 0, binding = 0) uniform Globals { + mat4 u_Transform; +}; + +layout(location = 0) out vec4 o_Color; + +void main() { + mat4 i_Transform = mat4( + vec4(i_Scale.x, 0.0, 0.0, 0.0), + vec4(0.0, i_Scale.y, 0.0, 0.0), + vec4(0.0, 0.0, 1.0, 0.0), + vec4(i_Pos, 0.0, 1.0) + ); + + o_Color = i_Color; + gl_Position = u_Transform * i_Transform * vec4(v_Pos, 0.0, 1.0); +} diff --git a/wgpu/src/shader/quad.vert.spv b/wgpu/src/shader/quad.vert.spv new file mode 100644 index 00000000..d517796b Binary files /dev/null and b/wgpu/src/shader/quad.vert.spv differ diff --git a/wgpu/src/transformation.rs b/wgpu/src/transformation.rs new file mode 100644 index 00000000..1101e135 --- /dev/null +++ b/wgpu/src/transformation.rs @@ -0,0 +1,30 @@ +#[derive(Debug, Clone, Copy)] +pub struct Transformation([f32; 16]); + +impl Transformation { + #[rustfmt::skip] + pub fn identity() -> Self { + Transformation([ + 1.0, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0, + ]) + } + + #[rustfmt::skip] + pub fn orthographic(width: u16, height: u16) -> Self { + Transformation([ + 2.0 / width as f32, 0.0, 0.0, 0.0, + 0.0, 2.0 / height as f32, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + -1.0, -1.0, 0.0, 1.0, + ]) + } +} + +impl From for [f32; 16] { + fn from(transformation: Transformation) -> [f32; 16] { + transformation.0 + } +} -- cgit From c9da3a10d9c4fcc9504b25eed873708406e3a9c7 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Mon, 7 Oct 2019 04:05:40 +0200 Subject: Use `log` crate instead of `dbg!` --- wgpu/Cargo.toml | 1 + wgpu/src/renderer.rs | 2 ++ 2 files changed, 3 insertions(+) (limited to 'wgpu') diff --git a/wgpu/Cargo.toml b/wgpu/Cargo.toml index 79661baa..20fe9ae9 100644 --- a/wgpu/Cargo.toml +++ b/wgpu/Cargo.toml @@ -15,3 +15,4 @@ iced_native = { version = "0.1.0-alpha", path = "../native" } wgpu = "0.3" wgpu_glyph = "0.4" raw-window-handle = "0.1" +log = "0.4" diff --git a/wgpu/src/renderer.rs b/wgpu/src/renderer.rs index 8e69a91a..926f12ae 100644 --- a/wgpu/src/renderer.rs +++ b/wgpu/src/renderer.rs @@ -96,6 +96,8 @@ impl Renderer { } pub fn draw(&mut self, target: &mut Target, primitive: &Primitive) { + log::debug!("Drawing"); + let frame = target.swap_chain.get_next_texture(); let mut encoder = self -- cgit From 0995950526bb605ddef5621c6e0590bb3232c1cb Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Mon, 7 Oct 2019 19:50:04 +0200 Subject: Use latest `wgpu` --- wgpu/Cargo.toml | 7 ++----- wgpu/src/renderer.rs | 22 +++++++++++----------- 2 files changed, 13 insertions(+), 16 deletions(-) (limited to 'wgpu') diff --git a/wgpu/Cargo.toml b/wgpu/Cargo.toml index 20fe9ae9..dbc1ddb9 100644 --- a/wgpu/Cargo.toml +++ b/wgpu/Cargo.toml @@ -7,12 +7,9 @@ description = "A wgpu renderer for Iced" license = "MIT" repository = "https://github.com/hecrj/iced" -[features] -vulkan = ["wgpu/vulkan"] - [dependencies] iced_native = { version = "0.1.0-alpha", path = "../native" } -wgpu = "0.3" -wgpu_glyph = "0.4" +wgpu = { version = "0.3", git = "https://github.com/gfx-rs/wgpu-rs", rev = "cb25914b95b58fee0dc139b400867e7a731d98f4" } +wgpu_glyph = { version = "0.4", git = "https://github.com/hecrj/wgpu_glyph", branch = "improvement/update-wgpu" } raw-window-handle = "0.1" log = "0.4" diff --git a/wgpu/src/renderer.rs b/wgpu/src/renderer.rs index 926f12ae..9883943b 100644 --- a/wgpu/src/renderer.rs +++ b/wgpu/src/renderer.rs @@ -3,8 +3,8 @@ use iced_native::{renderer::Debugger, Color, Layout, Point, Widget}; use raw_window_handle::HasRawWindowHandle; use wgpu::{ - Adapter, CommandEncoderDescriptor, Device, DeviceDescriptor, Extensions, - Instance, Limits, PowerPreference, RequestAdapterOptions, Surface, + Adapter, BackendBit, CommandEncoderDescriptor, Device, DeviceDescriptor, + Extensions, Limits, PowerPreference, Queue, RequestAdapterOptions, Surface, SwapChain, SwapChainDescriptor, TextureFormat, TextureUsage, }; use wgpu_glyph::{GlyphBrush, GlyphBrushBuilder, Section}; @@ -21,10 +21,10 @@ mod slider; mod text; pub struct Renderer { - instance: Instance, surface: Surface, adapter: Adapter, device: Device, + queue: Queue, quad_pipeline: quad::Pipeline, quads: Vec, @@ -40,20 +40,20 @@ pub struct Target { impl Renderer { pub fn new(window: &W) -> Self { - let instance = Instance::new(); - - let adapter = instance.request_adapter(&RequestAdapterOptions { + let adapter = Adapter::request(&RequestAdapterOptions { power_preference: PowerPreference::LowPower, - }); + backends: BackendBit::all(), + }) + .expect("Request adapter"); - let mut device = adapter.request_device(&DeviceDescriptor { + let (mut device, queue) = adapter.request_device(&DeviceDescriptor { extensions: Extensions { anisotropic_filtering: false, }, limits: Limits { max_bind_groups: 1 }, }); - let surface = instance.create_surface(window.raw_window_handle()); + let surface = Surface::create(window); // TODO: Think about font loading strategy // Loading system fonts with fallback may be a good idea @@ -66,10 +66,10 @@ impl Renderer { let quad_pipeline = quad::Pipeline::new(&mut device); Self { - instance, surface, adapter, device, + queue, quad_pipeline, quads: Vec::new(), @@ -143,7 +143,7 @@ impl Renderer { ) .expect("Draw text"); - self.device.get_queue().submit(&[encoder.finish()]); + self.queue.submit(&[encoder.finish()]); } fn draw_primitive(&mut self, primitive: &Primitive) { -- cgit From a0234d5bcea5b25f575af01d3a8e0296b2d0395c Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 8 Oct 2019 00:14:11 +0200 Subject: Draft fragment shader for rounded rectangles --- wgpu/src/shader/quad.frag | 26 +++++++++++++++++++++++++- wgpu/src/shader/quad.frag.spv | Bin 372 -> 2900 bytes wgpu/src/shader/quad.vert | 5 +++++ wgpu/src/shader/quad.vert.spv | Bin 2188 -> 2364 bytes 4 files changed, 30 insertions(+), 1 deletion(-) (limited to 'wgpu') diff --git a/wgpu/src/shader/quad.frag b/wgpu/src/shader/quad.frag index 1aca250f..1fc28bc1 100644 --- a/wgpu/src/shader/quad.frag +++ b/wgpu/src/shader/quad.frag @@ -1,9 +1,33 @@ #version 450 layout(location = 0) in vec4 v_Color; +layout(location = 1) in vec2 v_Pos; +layout(location = 2) in vec2 v_Scale; layout(location = 0) out vec4 o_Color; +float rounded(in vec2 frag_coord, in vec2 position, in vec2 size, float radius, float s) +{ + vec2 inner_size = size - vec2(radius, radius) * 2.0; + vec2 top_left = position + vec2(radius, radius); + vec2 bottom_right = top_left + inner_size; + + vec2 top_left_distance = top_left - frag_coord; + vec2 bottom_right_distance = frag_coord - bottom_right; + + vec2 distance = vec2( + max(max(top_left_distance.x, bottom_right_distance.x), 0), + max(max(top_left_distance.y, bottom_right_distance.y), 0) + ); + + float d = sqrt(distance.x * distance.x + distance.y * distance.y); + + return 1.0 - smoothstep(radius - s, radius + s, d); +} + void main() { - o_Color = v_Color; + o_Color = vec4( + v_Color.xyz, + v_Color.w * rounded(gl_FragCoord.xy, v_Pos, v_Scale, 5.0, 1.0) + ); } diff --git a/wgpu/src/shader/quad.frag.spv b/wgpu/src/shader/quad.frag.spv index 33218c83..19733ecf 100644 Binary files a/wgpu/src/shader/quad.frag.spv and b/wgpu/src/shader/quad.frag.spv differ diff --git a/wgpu/src/shader/quad.vert b/wgpu/src/shader/quad.vert index 3392d43d..87f6cc53 100644 --- a/wgpu/src/shader/quad.vert +++ b/wgpu/src/shader/quad.vert @@ -10,6 +10,8 @@ layout (set = 0, binding = 0) uniform Globals { }; layout(location = 0) out vec4 o_Color; +layout(location = 1) out vec2 o_Pos; +layout(location = 2) out vec2 o_Scale; void main() { mat4 i_Transform = mat4( @@ -20,5 +22,8 @@ void main() { ); o_Color = i_Color; + o_Pos = i_Pos; + o_Scale = i_Scale; + gl_Position = u_Transform * i_Transform * vec4(v_Pos, 0.0, 1.0); } diff --git a/wgpu/src/shader/quad.vert.spv b/wgpu/src/shader/quad.vert.spv index d517796b..0d13df6c 100644 Binary files a/wgpu/src/shader/quad.vert.spv and b/wgpu/src/shader/quad.vert.spv differ -- cgit From 10e10e5e06841574425d2633f1c2916733f7b4ff Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 8 Oct 2019 03:13:41 +0200 Subject: Make `iced_core::Button` customizable Now it supports: - Any kind of content - Custom border radius - Custom background --- wgpu/src/lib.rs | 2 +- wgpu/src/primitive.rs | 12 +++---- wgpu/src/quad.rs | 6 ++++ wgpu/src/renderer.rs | 76 ++++++++++++++++++++++++++++++++++++------ wgpu/src/renderer/button.rs | 45 ++++++++++++++----------- wgpu/src/renderer/checkbox.rs | 2 +- wgpu/src/renderer/image.rs | 2 +- wgpu/src/renderer/radio.rs | 2 +- wgpu/src/renderer/text.rs | 5 ++- wgpu/src/shader/quad.frag | 12 ++++--- wgpu/src/shader/quad.frag.spv | Bin 2900 -> 3196 bytes wgpu/src/shader/quad.vert | 3 ++ wgpu/src/shader/quad.vert.spv | Bin 2364 -> 2544 bytes 13 files changed, 122 insertions(+), 45 deletions(-) (limited to 'wgpu') diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 33d8f5ed..8f8d50e9 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -8,5 +8,5 @@ pub(crate) use quad::Quad; pub(crate) use transformation::Transformation; pub use mouse_cursor::MouseCursor; -pub use primitive::{Background, Primitive}; +pub use primitive::Primitive; pub use renderer::{Renderer, Target}; diff --git a/wgpu/src/primitive.rs b/wgpu/src/primitive.rs index f6730a1f..b664689b 100644 --- a/wgpu/src/primitive.rs +++ b/wgpu/src/primitive.rs @@ -1,4 +1,4 @@ -use iced_native::{Color, Rectangle}; +use iced_native::{text, Background, Color, Rectangle}; #[derive(Debug, Clone)] pub enum Primitive { @@ -9,16 +9,14 @@ pub enum Primitive { Text { content: String, bounds: Rectangle, + color: Color, size: f32, + horizontal_alignment: text::HorizontalAlignment, + vertical_alignment: text::VerticalAlignment, }, Quad { bounds: Rectangle, background: Background, + border_radius: u16, }, } - -#[derive(Debug, Clone, Copy, PartialEq)] -pub enum Background { - Color(Color), - // TODO: Add gradient and image variants -} diff --git a/wgpu/src/quad.rs b/wgpu/src/quad.rs index d0126bbd..adb294f0 100644 --- a/wgpu/src/quad.rs +++ b/wgpu/src/quad.rs @@ -123,6 +123,11 @@ impl Pipeline { format: wgpu::VertexFormat::Float4, offset: 4 * (2 + 2), }, + wgpu::VertexAttributeDescriptor { + shader_location: 4, + format: wgpu::VertexFormat::Uint, + offset: 4 * (2 + 2 + 4), + }, ], }, ], @@ -262,6 +267,7 @@ pub struct Quad { pub position: [f32; 2], pub scale: [f32; 2], pub color: [f32; 4], + pub border_radius: u32, } impl Quad { diff --git a/wgpu/src/renderer.rs b/wgpu/src/renderer.rs index 9883943b..ae5692e3 100644 --- a/wgpu/src/renderer.rs +++ b/wgpu/src/renderer.rs @@ -1,5 +1,7 @@ -use crate::{quad, Background, Primitive, Quad, Transformation}; -use iced_native::{renderer::Debugger, Color, Layout, Point, Widget}; +use crate::{quad, Primitive, Quad, Transformation}; +use iced_native::{ + renderer::Debugger, Background, Color, Layout, Point, Widget, +}; use raw_window_handle::HasRawWindowHandle; use wgpu::{ @@ -159,20 +161,74 @@ impl Renderer { content, bounds, size, - } => self.glyph_brush.borrow_mut().queue(Section { - text: &content, - screen_position: (bounds.x, bounds.y), - bounds: (bounds.width, bounds.height), - scale: wgpu_glyph::Scale { x: *size, y: *size }, - ..Default::default() - }), - Primitive::Quad { bounds, background } => { + color, + horizontal_alignment, + vertical_alignment, + } => { + let x = match horizontal_alignment { + iced_native::text::HorizontalAlignment::Left => bounds.x, + iced_native::text::HorizontalAlignment::Center => { + bounds.x + bounds.width / 2.0 + } + iced_native::text::HorizontalAlignment::Right => { + bounds.x + bounds.width + } + }; + + let y = match vertical_alignment { + iced_native::text::VerticalAlignment::Top => bounds.y, + iced_native::text::VerticalAlignment::Center => { + bounds.y + bounds.height / 2.0 + } + iced_native::text::VerticalAlignment::Bottom => { + bounds.y + bounds.height + } + }; + + self.glyph_brush.borrow_mut().queue(Section { + text: &content, + screen_position: (x, y), + bounds: (bounds.width, bounds.height), + scale: wgpu_glyph::Scale { x: *size, y: *size }, + color: color.into_linear(), + layout: wgpu_glyph::Layout::default() + .h_align(match horizontal_alignment { + iced_native::text::HorizontalAlignment::Left => { + wgpu_glyph::HorizontalAlign::Left + } + iced_native::text::HorizontalAlignment::Center => { + wgpu_glyph::HorizontalAlign::Center + } + iced_native::text::HorizontalAlignment::Right => { + wgpu_glyph::HorizontalAlign::Right + } + }) + .v_align(match vertical_alignment { + iced_native::text::VerticalAlignment::Top => { + wgpu_glyph::VerticalAlign::Top + } + iced_native::text::VerticalAlignment::Center => { + wgpu_glyph::VerticalAlign::Center + } + iced_native::text::VerticalAlignment::Bottom => { + wgpu_glyph::VerticalAlign::Bottom + } + }), + ..Default::default() + }) + } + Primitive::Quad { + bounds, + background, + border_radius, + } => { self.quads.push(Quad { position: [bounds.x, bounds.y], scale: [bounds.width, bounds.height], color: match background { Background::Color(color) => color.into_linear(), }, + border_radius: u32::from(*border_radius), }); } } diff --git a/wgpu/src/renderer/button.rs b/wgpu/src/renderer/button.rs index f75b44f7..00fcd0eb 100644 --- a/wgpu/src/renderer/button.rs +++ b/wgpu/src/renderer/button.rs @@ -1,22 +1,26 @@ -use crate::{Background, Primitive, Renderer}; -use iced_native::{button, Button, Color, Layout, Length, Node, Point, Style}; +use crate::{Primitive, Renderer}; +use iced_native::{ + button, Align, Background, Button, Color, Layout, Length, Node, Point, + Style, +}; impl button::Renderer for Renderer { - fn node(&self, button: &Button) -> Node { + fn node(&self, button: &Button) -> Node { let style = Style::default() .width(button.width) - .min_height(Length::Units(30)) + .padding(button.padding) .min_width(Length::Units(100)) - .align_self(button.align_self); + .align_self(button.align_self) + .align_items(Align::Stretch); - Node::new(style) + Node::with_children(style, vec![button.content.node(self)]) } fn draw( &mut self, - button: &Button, + button: &Button, layout: Layout<'_>, - _cursor_position: Point, + cursor_position: Point, ) -> Self::Primitive { let bounds = layout.bounds(); @@ -24,18 +28,21 @@ impl button::Renderer for Renderer { primitives: vec![ Primitive::Quad { bounds, - background: Background::Color(Color { - r: 0.8, - b: 0.8, - g: 0.8, - a: 1.0, - }), - }, - Primitive::Text { - content: button.label.clone(), - size: 20.0, - bounds: layout.bounds(), + background: button.background.unwrap_or(Background::Color( + Color { + r: 0.8, + b: 0.8, + g: 0.8, + a: 1.0, + }, + )), + border_radius: button.border_radius, }, + button.content.draw( + self, + layout.children().next().unwrap(), + cursor_position, + ), ], } } diff --git a/wgpu/src/renderer/checkbox.rs b/wgpu/src/renderer/checkbox.rs index c94a2157..16d5734f 100644 --- a/wgpu/src/renderer/checkbox.rs +++ b/wgpu/src/renderer/checkbox.rs @@ -2,7 +2,7 @@ use crate::{Primitive, Renderer}; use iced_native::{checkbox, Checkbox, Layout, Node, Point, Style}; impl checkbox::Renderer for Renderer { - fn node(&mut self, _checkbox: &Checkbox) -> Node { + fn node(&self, _checkbox: &Checkbox) -> Node { Node::new(Style::default()) } diff --git a/wgpu/src/renderer/image.rs b/wgpu/src/renderer/image.rs index 6ff39d30..bacc430d 100644 --- a/wgpu/src/renderer/image.rs +++ b/wgpu/src/renderer/image.rs @@ -2,7 +2,7 @@ use crate::{Primitive, Renderer}; use iced_native::{image, Image, Layout, Node, Style}; impl image::Renderer<&str> for Renderer { - fn node(&mut self, _image: &Image<&str>) -> Node { + fn node(&self, _image: &Image<&str>) -> Node { Node::new(Style::default()) } diff --git a/wgpu/src/renderer/radio.rs b/wgpu/src/renderer/radio.rs index ce419ae0..fdc0a0fc 100644 --- a/wgpu/src/renderer/radio.rs +++ b/wgpu/src/renderer/radio.rs @@ -2,7 +2,7 @@ use crate::{Primitive, Renderer}; use iced_native::{radio, Layout, Node, Point, Radio, Style}; impl radio::Renderer for Renderer { - fn node(&mut self, _checkbox: &Radio) -> Node { + fn node(&self, _checkbox: &Radio) -> Node { Node::new(Style::default()) } diff --git a/wgpu/src/renderer/text.rs b/wgpu/src/renderer/text.rs index 4434cc22..c89c0b3e 100644 --- a/wgpu/src/renderer/text.rs +++ b/wgpu/src/renderer/text.rs @@ -1,5 +1,5 @@ use crate::{Primitive, Renderer}; -use iced_native::{text, Layout, Node, Style, Text}; +use iced_native::{text, Color, Layout, Node, Style, Text}; use wgpu_glyph::{GlyphCruncher, Section}; @@ -72,6 +72,9 @@ impl text::Renderer for Renderer { content: text.content.clone(), size: f32::from(text.size.unwrap_or(20)), bounds: layout.bounds(), + color: text.color.unwrap_or(Color::BLACK), + horizontal_alignment: text.horizontal_alignment, + vertical_alignment: text.vertical_alignment, } } } diff --git a/wgpu/src/shader/quad.frag b/wgpu/src/shader/quad.frag index 1fc28bc1..987744db 100644 --- a/wgpu/src/shader/quad.frag +++ b/wgpu/src/shader/quad.frag @@ -3,6 +3,7 @@ layout(location = 0) in vec4 v_Color; layout(location = 1) in vec2 v_Pos; layout(location = 2) in vec2 v_Scale; +layout(location = 3) in flat uint v_BorderRadius; layout(location = 0) out vec4 o_Color; @@ -26,8 +27,11 @@ float rounded(in vec2 frag_coord, in vec2 position, in vec2 size, float radius, } void main() { - o_Color = vec4( - v_Color.xyz, - v_Color.w * rounded(gl_FragCoord.xy, v_Pos, v_Scale, 5.0, 1.0) - ); + float radius_alpha = 1.0; + + if(v_BorderRadius > 0.0) { + radius_alpha = rounded(gl_FragCoord.xy, v_Pos, v_Scale, v_BorderRadius, 1.0); + } + + o_Color = vec4(v_Color.xyz, v_Color.w * radius_alpha); } diff --git a/wgpu/src/shader/quad.frag.spv b/wgpu/src/shader/quad.frag.spv index 19733ecf..063287b3 100644 Binary files a/wgpu/src/shader/quad.frag.spv and b/wgpu/src/shader/quad.frag.spv differ diff --git a/wgpu/src/shader/quad.vert b/wgpu/src/shader/quad.vert index 87f6cc53..b7c5cf3e 100644 --- a/wgpu/src/shader/quad.vert +++ b/wgpu/src/shader/quad.vert @@ -4,6 +4,7 @@ layout(location = 0) in vec2 v_Pos; layout(location = 1) in vec2 i_Pos; layout(location = 2) in vec2 i_Scale; layout(location = 3) in vec4 i_Color; +layout(location = 4) in uint i_BorderRadius; layout (set = 0, binding = 0) uniform Globals { mat4 u_Transform; @@ -12,6 +13,7 @@ layout (set = 0, binding = 0) uniform Globals { layout(location = 0) out vec4 o_Color; layout(location = 1) out vec2 o_Pos; layout(location = 2) out vec2 o_Scale; +layout(location = 3) out uint o_BorderRadius; void main() { mat4 i_Transform = mat4( @@ -24,6 +26,7 @@ void main() { o_Color = i_Color; o_Pos = i_Pos; o_Scale = i_Scale; + o_BorderRadius = i_BorderRadius; gl_Position = u_Transform * i_Transform * vec4(v_Pos, 0.0, 1.0); } diff --git a/wgpu/src/shader/quad.vert.spv b/wgpu/src/shader/quad.vert.spv index 0d13df6c..f62a160c 100644 Binary files a/wgpu/src/shader/quad.vert.spv and b/wgpu/src/shader/quad.vert.spv differ -- cgit From a92a0b73ed7ed935df762d06c4249894fd35b227 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 9 Oct 2019 05:36:49 +0200 Subject: Move `winit` logic from `iced` to `iced_winit` - Added new `renderer::Windowed` trait. This shoud allow users to easily try different renderers by simply changing one line. - Renamed `UserInterface` traits to `Application`, as the `run` method takes total control of the current thread. - Moved `MouseCursor` back to `iced_native`. The new `renderer::Windowed` trait returns one on `draw`. - Split `iced_native` renderer in multiple modules, for consistency. --- wgpu/src/lib.rs | 2 -- wgpu/src/mouse_cursor.rs | 35 ----------------------------------- wgpu/src/renderer.rs | 36 +++++++++++++++++++++++++++++++----- 3 files changed, 31 insertions(+), 42 deletions(-) delete mode 100644 wgpu/src/mouse_cursor.rs (limited to 'wgpu') diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 8f8d50e9..46849aab 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -1,4 +1,3 @@ -mod mouse_cursor; mod primitive; mod quad; mod renderer; @@ -7,6 +6,5 @@ mod transformation; pub(crate) use quad::Quad; pub(crate) use transformation::Transformation; -pub use mouse_cursor::MouseCursor; pub use primitive::Primitive; pub use renderer::{Renderer, Target}; diff --git a/wgpu/src/mouse_cursor.rs b/wgpu/src/mouse_cursor.rs deleted file mode 100644 index 4ef6361a..00000000 --- a/wgpu/src/mouse_cursor.rs +++ /dev/null @@ -1,35 +0,0 @@ -/// The state of the mouse cursor. -#[derive(Debug, Eq, PartialEq, Clone, Copy)] -pub enum MouseCursor { - /// The cursor is out of the bounds of the user interface. - OutOfBounds, - - /// The cursor is over a non-interactive widget. - Idle, - - /// The cursor is over a clickable widget. - Pointer, - - /// The cursor is over a busy widget. - Working, - - /// The cursor is over a grabbable widget. - Grab, - - /// The cursor is grabbing a widget. - Grabbing, -} - -#[cfg(feature = "winit")] -impl From for winit::window::CursorIcon { - fn from(mouse_cursor: MouseCursor) -> winit::window::CursorIcon { - match mouse_cursor { - MouseCursor::OutOfBounds => winit::window::CursorIcon::Default, - MouseCursor::Idle => winit::window::CursorIcon::Default, - MouseCursor::Pointer => winit::window::CursorIcon::Hand, - MouseCursor::Working => winit::window::CursorIcon::Progress, - MouseCursor::Grab => winit::window::CursorIcon::Grab, - MouseCursor::Grabbing => winit::window::CursorIcon::Grabbing, - } - } -} diff --git a/wgpu/src/renderer.rs b/wgpu/src/renderer.rs index ae5692e3..036efd27 100644 --- a/wgpu/src/renderer.rs +++ b/wgpu/src/renderer.rs @@ -1,6 +1,7 @@ use crate::{quad, Primitive, Quad, Transformation}; use iced_native::{ - renderer::Debugger, Background, Color, Layout, Point, Widget, + renderer::Debugger, renderer::Windowed, Background, Color, Layout, + MouseCursor, Point, Widget, }; use raw_window_handle::HasRawWindowHandle; @@ -41,7 +42,7 @@ pub struct Target { } impl Renderer { - pub fn new(window: &W) -> Self { + fn new(window: &W) -> Self { let adapter = Adapter::request(&RequestAdapterOptions { power_preference: PowerPreference::LowPower, backends: BackendBit::all(), @@ -79,7 +80,7 @@ impl Renderer { } } - pub fn target(&self, width: u16, height: u16) -> Target { + fn target(&self, width: u16, height: u16) -> Target { Target { width, height, @@ -97,7 +98,11 @@ impl Renderer { } } - pub fn draw(&mut self, target: &mut Target, primitive: &Primitive) { + fn draw( + &mut self, + target: &mut Target, + primitive: &Primitive, + ) -> MouseCursor { log::debug!("Drawing"); let frame = target.swap_chain.get_next_texture(); @@ -146,8 +151,9 @@ impl Renderer { .expect("Draw text"); self.queue.submit(&[encoder.finish()]); - } + MouseCursor::OutOfBounds + } fn draw_primitive(&mut self, primitive: &Primitive) { match primitive { Primitive::None => {} @@ -240,6 +246,26 @@ impl iced_native::Renderer for Renderer { type Primitive = Primitive; } +impl Windowed for Renderer { + type Target = Target; + + fn new(window: &W) -> Self { + Self::new(window) + } + + fn target(&self, width: u16, height: u16) -> Target { + self.target(width, height) + } + + fn draw( + &mut self, + target: &mut Target, + primitive: &Primitive, + ) -> MouseCursor { + self.draw(target, primitive) + } +} + impl Debugger for Renderer { fn explain( &mut self, -- cgit From 8846a239cf14edd464b1d09f6d6d57ad9b5c9fc7 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 11 Oct 2019 22:15:39 +0200 Subject: Rename `Renderer::Primitive` to `Renderer::Output` --- wgpu/src/renderer.rs | 11 ++++++----- wgpu/src/renderer/button.rs | 2 +- wgpu/src/renderer/checkbox.rs | 2 +- wgpu/src/renderer/column.rs | 2 +- wgpu/src/renderer/image.rs | 2 +- wgpu/src/renderer/radio.rs | 2 +- wgpu/src/renderer/row.rs | 2 +- wgpu/src/renderer/slider.rs | 2 +- wgpu/src/renderer/text.rs | 2 +- 9 files changed, 14 insertions(+), 13 deletions(-) (limited to 'wgpu') diff --git a/wgpu/src/renderer.rs b/wgpu/src/renderer.rs index 036efd27..cdb44554 100644 --- a/wgpu/src/renderer.rs +++ b/wgpu/src/renderer.rs @@ -100,8 +100,8 @@ impl Renderer { fn draw( &mut self, - target: &mut Target, primitive: &Primitive, + target: &mut Target, ) -> MouseCursor { log::debug!("Drawing"); @@ -154,6 +154,7 @@ impl Renderer { MouseCursor::OutOfBounds } + fn draw_primitive(&mut self, primitive: &Primitive) { match primitive { Primitive::None => {} @@ -243,7 +244,7 @@ impl Renderer { impl iced_native::Renderer for Renderer { // TODO: Add `MouseCursor` here (?) - type Primitive = Primitive; + type Output = Primitive; } impl Windowed for Renderer { @@ -259,10 +260,10 @@ impl Windowed for Renderer { fn draw( &mut self, + output: &Self::Output, target: &mut Target, - primitive: &Primitive, ) -> MouseCursor { - self.draw(target, primitive) + self.draw(output, target) } } @@ -273,7 +274,7 @@ impl Debugger for Renderer { layout: Layout<'_>, cursor_position: Point, _color: Color, - ) -> Self::Primitive { + ) -> Self::Output { // TODO: Include a bordered box to display layout bounds widget.draw(self, layout, cursor_position) } diff --git a/wgpu/src/renderer/button.rs b/wgpu/src/renderer/button.rs index 00fcd0eb..33789379 100644 --- a/wgpu/src/renderer/button.rs +++ b/wgpu/src/renderer/button.rs @@ -21,7 +21,7 @@ impl button::Renderer for Renderer { button: &Button, layout: Layout<'_>, cursor_position: Point, - ) -> Self::Primitive { + ) -> Self::Output { let bounds = layout.bounds(); Primitive::Group { diff --git a/wgpu/src/renderer/checkbox.rs b/wgpu/src/renderer/checkbox.rs index 16d5734f..003df7e5 100644 --- a/wgpu/src/renderer/checkbox.rs +++ b/wgpu/src/renderer/checkbox.rs @@ -11,7 +11,7 @@ impl checkbox::Renderer for Renderer { _checkbox: &Checkbox, _layout: Layout<'_>, _cursor_position: Point, - ) -> Self::Primitive { + ) -> Self::Output { // TODO Primitive::None } diff --git a/wgpu/src/renderer/column.rs b/wgpu/src/renderer/column.rs index 1b9adad6..c83a7de1 100644 --- a/wgpu/src/renderer/column.rs +++ b/wgpu/src/renderer/column.rs @@ -7,7 +7,7 @@ impl column::Renderer for Renderer { column: &Column<'_, Message, Self>, layout: Layout<'_>, cursor_position: Point, - ) -> Self::Primitive { + ) -> Self::Output { Primitive::Group { primitives: column .children diff --git a/wgpu/src/renderer/image.rs b/wgpu/src/renderer/image.rs index bacc430d..f77a95db 100644 --- a/wgpu/src/renderer/image.rs +++ b/wgpu/src/renderer/image.rs @@ -10,7 +10,7 @@ impl image::Renderer<&str> for Renderer { &mut self, _image: &Image<&str>, _layout: Layout<'_>, - ) -> Self::Primitive { + ) -> Self::Output { Primitive::None } } diff --git a/wgpu/src/renderer/radio.rs b/wgpu/src/renderer/radio.rs index fdc0a0fc..0a34fee9 100644 --- a/wgpu/src/renderer/radio.rs +++ b/wgpu/src/renderer/radio.rs @@ -11,7 +11,7 @@ impl radio::Renderer for Renderer { _radio: &Radio, _layout: Layout<'_>, _cursor_position: Point, - ) -> Self::Primitive { + ) -> Self::Output { Primitive::None } } diff --git a/wgpu/src/renderer/row.rs b/wgpu/src/renderer/row.rs index be9e4ede..b6baf61f 100644 --- a/wgpu/src/renderer/row.rs +++ b/wgpu/src/renderer/row.rs @@ -7,7 +7,7 @@ impl row::Renderer for Renderer { row: &Row<'_, Message, Self>, layout: Layout<'_>, cursor_position: Point, - ) -> Self::Primitive { + ) -> Self::Output { Primitive::Group { primitives: row .children diff --git a/wgpu/src/renderer/slider.rs b/wgpu/src/renderer/slider.rs index 2e76022d..2eacdc89 100644 --- a/wgpu/src/renderer/slider.rs +++ b/wgpu/src/renderer/slider.rs @@ -11,7 +11,7 @@ impl slider::Renderer for Renderer { _slider: &Slider, _layout: Layout<'_>, _cursor_position: Point, - ) -> Self::Primitive { + ) -> Self::Output { Primitive::None } } diff --git a/wgpu/src/renderer/text.rs b/wgpu/src/renderer/text.rs index c89c0b3e..61349533 100644 --- a/wgpu/src/renderer/text.rs +++ b/wgpu/src/renderer/text.rs @@ -67,7 +67,7 @@ impl text::Renderer for Renderer { }) } - fn draw(&mut self, text: &Text, layout: Layout<'_>) -> Self::Primitive { + fn draw(&mut self, text: &Text, layout: Layout<'_>) -> Self::Output { Primitive::Text { content: text.content.clone(), size: f32::from(text.size.unwrap_or(20)), -- cgit From a031a6f2130b3913a2419e4cea859c22aa388213 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 11 Oct 2019 23:30:53 +0200 Subject: Handle mouse cursor in `iced_wgpu` --- wgpu/src/renderer.rs | 7 +++--- wgpu/src/renderer/button.rs | 55 +++++++++++++++++++++++++------------------ wgpu/src/renderer/checkbox.rs | 6 +++-- wgpu/src/renderer/column.rs | 34 +++++++++++++++++--------- wgpu/src/renderer/image.rs | 4 ++-- wgpu/src/renderer/radio.rs | 4 ++-- wgpu/src/renderer/row.rs | 34 +++++++++++++++++--------- wgpu/src/renderer/slider.rs | 4 ++-- wgpu/src/renderer/text.rs | 21 ++++++++++------- 9 files changed, 103 insertions(+), 66 deletions(-) (limited to 'wgpu') diff --git a/wgpu/src/renderer.rs b/wgpu/src/renderer.rs index cdb44554..8d54b2c7 100644 --- a/wgpu/src/renderer.rs +++ b/wgpu/src/renderer.rs @@ -100,7 +100,7 @@ impl Renderer { fn draw( &mut self, - primitive: &Primitive, + (primitive, mouse_cursor): &(Primitive, MouseCursor), target: &mut Target, ) -> MouseCursor { log::debug!("Drawing"); @@ -152,7 +152,7 @@ impl Renderer { self.queue.submit(&[encoder.finish()]); - MouseCursor::OutOfBounds + *mouse_cursor } fn draw_primitive(&mut self, primitive: &Primitive) { @@ -243,8 +243,7 @@ impl Renderer { } impl iced_native::Renderer for Renderer { - // TODO: Add `MouseCursor` here (?) - type Output = Primitive; + type Output = (Primitive, MouseCursor); } impl Windowed for Renderer { diff --git a/wgpu/src/renderer/button.rs b/wgpu/src/renderer/button.rs index 33789379..275c870f 100644 --- a/wgpu/src/renderer/button.rs +++ b/wgpu/src/renderer/button.rs @@ -1,7 +1,7 @@ use crate::{Primitive, Renderer}; use iced_native::{ - button, Align, Background, Button, Color, Layout, Length, Node, Point, - Style, + button, Align, Background, Button, Color, Layout, Length, MouseCursor, + Node, Point, Style, }; impl button::Renderer for Renderer { @@ -24,26 +24,35 @@ impl button::Renderer for Renderer { ) -> Self::Output { let bounds = layout.bounds(); - Primitive::Group { - primitives: vec![ - Primitive::Quad { - bounds, - background: button.background.unwrap_or(Background::Color( - Color { - r: 0.8, - b: 0.8, - g: 0.8, - a: 1.0, - }, - )), - border_radius: button.border_radius, - }, - button.content.draw( - self, - layout.children().next().unwrap(), - cursor_position, - ), - ], - } + let (content, _) = button.content.draw( + self, + layout.children().next().unwrap(), + cursor_position, + ); + + ( + Primitive::Group { + primitives: vec![ + Primitive::Quad { + bounds, + background: button.background.unwrap_or( + Background::Color(Color { + r: 0.8, + b: 0.8, + g: 0.8, + a: 1.0, + }), + ), + border_radius: button.border_radius, + }, + content, + ], + }, + if bounds.contains(cursor_position) { + MouseCursor::Pointer + } else { + MouseCursor::OutOfBounds + }, + ) } } diff --git a/wgpu/src/renderer/checkbox.rs b/wgpu/src/renderer/checkbox.rs index 003df7e5..7b06d397 100644 --- a/wgpu/src/renderer/checkbox.rs +++ b/wgpu/src/renderer/checkbox.rs @@ -1,5 +1,7 @@ use crate::{Primitive, Renderer}; -use iced_native::{checkbox, Checkbox, Layout, Node, Point, Style}; +use iced_native::{ + checkbox, Checkbox, Layout, MouseCursor, Node, Point, Style, +}; impl checkbox::Renderer for Renderer { fn node(&self, _checkbox: &Checkbox) -> Node { @@ -13,6 +15,6 @@ impl checkbox::Renderer for Renderer { _cursor_position: Point, ) -> Self::Output { // TODO - Primitive::None + (Primitive::None, MouseCursor::OutOfBounds) } } diff --git a/wgpu/src/renderer/column.rs b/wgpu/src/renderer/column.rs index c83a7de1..cac6da77 100644 --- a/wgpu/src/renderer/column.rs +++ b/wgpu/src/renderer/column.rs @@ -1,5 +1,5 @@ use crate::{Primitive, Renderer}; -use iced_native::{column, Column, Layout, Point}; +use iced_native::{column, Column, Layout, MouseCursor, Point}; impl column::Renderer for Renderer { fn draw( @@ -8,15 +8,27 @@ impl column::Renderer for Renderer { layout: Layout<'_>, cursor_position: Point, ) -> Self::Output { - Primitive::Group { - primitives: column - .children - .iter() - .zip(layout.children()) - .map(|(child, layout)| { - child.draw(self, layout, cursor_position) - }) - .collect(), - } + let mut mouse_cursor = MouseCursor::OutOfBounds; + + ( + Primitive::Group { + primitives: column + .children + .iter() + .zip(layout.children()) + .map(|(child, layout)| { + let (primitive, new_mouse_cursor) = + child.draw(self, layout, cursor_position); + + if new_mouse_cursor > mouse_cursor { + mouse_cursor = new_mouse_cursor; + } + + primitive + }) + .collect(), + }, + mouse_cursor, + ) } } diff --git a/wgpu/src/renderer/image.rs b/wgpu/src/renderer/image.rs index f77a95db..a29a3d49 100644 --- a/wgpu/src/renderer/image.rs +++ b/wgpu/src/renderer/image.rs @@ -1,5 +1,5 @@ use crate::{Primitive, Renderer}; -use iced_native::{image, Image, Layout, Node, Style}; +use iced_native::{image, Image, Layout, MouseCursor, Node, Style}; impl image::Renderer<&str> for Renderer { fn node(&self, _image: &Image<&str>) -> Node { @@ -11,6 +11,6 @@ impl image::Renderer<&str> for Renderer { _image: &Image<&str>, _layout: Layout<'_>, ) -> Self::Output { - Primitive::None + (Primitive::None, MouseCursor::OutOfBounds) } } diff --git a/wgpu/src/renderer/radio.rs b/wgpu/src/renderer/radio.rs index 0a34fee9..712a7104 100644 --- a/wgpu/src/renderer/radio.rs +++ b/wgpu/src/renderer/radio.rs @@ -1,5 +1,5 @@ use crate::{Primitive, Renderer}; -use iced_native::{radio, Layout, Node, Point, Radio, Style}; +use iced_native::{radio, Layout, MouseCursor, Node, Point, Radio, Style}; impl radio::Renderer for Renderer { fn node(&self, _checkbox: &Radio) -> Node { @@ -12,6 +12,6 @@ impl radio::Renderer for Renderer { _layout: Layout<'_>, _cursor_position: Point, ) -> Self::Output { - Primitive::None + (Primitive::None, MouseCursor::OutOfBounds) } } diff --git a/wgpu/src/renderer/row.rs b/wgpu/src/renderer/row.rs index b6baf61f..bbfef9a1 100644 --- a/wgpu/src/renderer/row.rs +++ b/wgpu/src/renderer/row.rs @@ -1,5 +1,5 @@ use crate::{Primitive, Renderer}; -use iced_native::{row, Layout, Point, Row}; +use iced_native::{row, Layout, MouseCursor, Point, Row}; impl row::Renderer for Renderer { fn draw( @@ -8,15 +8,27 @@ impl row::Renderer for Renderer { layout: Layout<'_>, cursor_position: Point, ) -> Self::Output { - Primitive::Group { - primitives: row - .children - .iter() - .zip(layout.children()) - .map(|(child, layout)| { - child.draw(self, layout, cursor_position) - }) - .collect(), - } + let mut mouse_cursor = MouseCursor::OutOfBounds; + + ( + Primitive::Group { + primitives: row + .children + .iter() + .zip(layout.children()) + .map(|(child, layout)| { + let (primitive, new_mouse_cursor) = + child.draw(self, layout, cursor_position); + + if new_mouse_cursor > mouse_cursor { + mouse_cursor = new_mouse_cursor; + } + + primitive + }) + .collect(), + }, + mouse_cursor, + ) } } diff --git a/wgpu/src/renderer/slider.rs b/wgpu/src/renderer/slider.rs index 2eacdc89..d1a30244 100644 --- a/wgpu/src/renderer/slider.rs +++ b/wgpu/src/renderer/slider.rs @@ -1,5 +1,5 @@ use crate::{Primitive, Renderer}; -use iced_native::{slider, Layout, Node, Point, Slider, Style}; +use iced_native::{slider, Layout, MouseCursor, Node, Point, Slider, Style}; impl slider::Renderer for Renderer { fn node(&self, _slider: &Slider) -> Node { @@ -12,6 +12,6 @@ impl slider::Renderer for Renderer { _layout: Layout<'_>, _cursor_position: Point, ) -> Self::Output { - Primitive::None + (Primitive::None, MouseCursor::OutOfBounds) } } diff --git a/wgpu/src/renderer/text.rs b/wgpu/src/renderer/text.rs index 61349533..8fbade4e 100644 --- a/wgpu/src/renderer/text.rs +++ b/wgpu/src/renderer/text.rs @@ -1,5 +1,5 @@ use crate::{Primitive, Renderer}; -use iced_native::{text, Color, Layout, Node, Style, Text}; +use iced_native::{text, Color, Layout, MouseCursor, Node, Style, Text}; use wgpu_glyph::{GlyphCruncher, Section}; @@ -68,13 +68,16 @@ impl text::Renderer for Renderer { } fn draw(&mut self, text: &Text, layout: Layout<'_>) -> Self::Output { - Primitive::Text { - content: text.content.clone(), - size: f32::from(text.size.unwrap_or(20)), - bounds: layout.bounds(), - color: text.color.unwrap_or(Color::BLACK), - horizontal_alignment: text.horizontal_alignment, - vertical_alignment: text.vertical_alignment, - } + ( + Primitive::Text { + content: text.content.clone(), + size: f32::from(text.size.unwrap_or(20)), + bounds: layout.bounds(), + color: text.color.unwrap_or(Color::BLACK), + horizontal_alignment: text.horizontal_alignment, + vertical_alignment: text.vertical_alignment, + }, + MouseCursor::OutOfBounds, + ) } } -- cgit From e74f1179769cc4dc3e91cb0b5794526b3a8c0dcd Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sat, 12 Oct 2019 02:32:16 +0200 Subject: Add a slight shadow to buttons for feedback --- wgpu/src/renderer/button.rs | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) (limited to 'wgpu') diff --git a/wgpu/src/renderer/button.rs b/wgpu/src/renderer/button.rs index 275c870f..aa48da93 100644 --- a/wgpu/src/renderer/button.rs +++ b/wgpu/src/renderer/button.rs @@ -1,7 +1,7 @@ use crate::{Primitive, Renderer}; use iced_native::{ button, Align, Background, Button, Color, Layout, Length, MouseCursor, - Node, Point, Style, + Node, Point, Rectangle, Style, }; impl button::Renderer for Renderer { @@ -30,9 +30,35 @@ impl button::Renderer for Renderer { cursor_position, ); + let is_hover = bounds.contains(cursor_position); + + // TODO: Render proper shadows + // TODO: Make hovering and pressed styles configurable + let shadow_offset = if button.state.is_pressed { + 0.0 + } else if is_hover { + 2.0 + } else { + 1.0 + }; + ( Primitive::Group { primitives: vec![ + Primitive::Quad { + bounds: Rectangle { + x: bounds.x + 1.0, + y: bounds.y + shadow_offset, + ..bounds + }, + background: Background::Color(Color { + r: 0.0, + b: 0.0, + g: 0.0, + a: 0.5, + }), + border_radius: button.border_radius, + }, Primitive::Quad { bounds, background: button.background.unwrap_or( @@ -48,7 +74,7 @@ impl button::Renderer for Renderer { content, ], }, - if bounds.contains(cursor_position) { + if is_hover { MouseCursor::Pointer } else { MouseCursor::OutOfBounds -- cgit From afacb35f9bf87ae10f59091b18b001a4c114a589 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sat, 12 Oct 2019 05:07:00 +0200 Subject: Draw sliders in `iced_wgpu` --- wgpu/src/renderer/slider.rs | 125 +++++++++++++++++++++++++++++++++++++++--- wgpu/src/shader/quad.frag | 2 +- wgpu/src/shader/quad.frag.spv | Bin 3196 -> 3212 bytes 3 files changed, 119 insertions(+), 8 deletions(-) (limited to 'wgpu') diff --git a/wgpu/src/renderer/slider.rs b/wgpu/src/renderer/slider.rs index d1a30244..4ae3abc4 100644 --- a/wgpu/src/renderer/slider.rs +++ b/wgpu/src/renderer/slider.rs @@ -1,17 +1,128 @@ use crate::{Primitive, Renderer}; -use iced_native::{slider, Layout, MouseCursor, Node, Point, Slider, Style}; +use iced_native::{ + slider, Background, Color, Layout, Length, MouseCursor, Node, Point, + Rectangle, Slider, Style, +}; + +const HANDLE_WIDTH: f32 = 8.0; +const HANDLE_HEIGHT: f32 = 22.0; impl slider::Renderer for Renderer { - fn node(&self, _slider: &Slider) -> Node { - Node::new(Style::default()) + fn node(&self, slider: &Slider) -> Node { + let style = Style::default() + .width(slider.width) + .height(Length::Units(HANDLE_HEIGHT as u16)) + .min_width(Length::Units(100)); + + Node::new(style) } fn draw( &mut self, - _slider: &Slider, - _layout: Layout<'_>, - _cursor_position: Point, + slider: &Slider, + layout: Layout<'_>, + cursor_position: Point, ) -> Self::Output { - (Primitive::None, MouseCursor::OutOfBounds) + let bounds = layout.bounds(); + + let is_mouse_over = bounds.contains(cursor_position); + + 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(Color { + r: 0.6, + g: 0.6, + b: 0.6, + a: 1.0, + }), + border_radius: 0, + }, + Primitive::Quad { + bounds: Rectangle { + x: bounds.x, + y: rail_y + 2.0, + width: bounds.width, + height: 2.0, + }, + background: Background::Color(Color::WHITE), + border_radius: 0, + }, + ); + + let (range_start, range_end) = slider.range.clone().into_inner(); + + let handle_offset = (bounds.width - HANDLE_WIDTH) + * ((slider.value - range_start) + / (range_end - range_start).max(1.0)); + + let (handle_border, handle) = ( + Primitive::Quad { + bounds: Rectangle { + x: bounds.x + handle_offset.round() - 1.0, + y: rail_y - HANDLE_HEIGHT / 2.0 - 1.0, + width: HANDLE_WIDTH + 2.0, + height: HANDLE_HEIGHT + 2.0, + }, + background: Background::Color(Color { + r: 0.6, + g: 0.6, + b: 0.6, + a: 1.0, + }), + border_radius: 5, + }, + 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(if slider.state.is_dragging() { + Color { + r: 0.85, + g: 0.85, + b: 0.85, + a: 1.0, + } + } else if is_mouse_over { + Color { + r: 0.9, + g: 0.9, + b: 0.9, + a: 1.0, + } + } else { + Color { + r: 0.95, + g: 0.95, + b: 0.95, + a: 1.0, + } + }), + border_radius: 4, + }, + ); + + ( + Primitive::Group { + primitives: vec![rail_top, rail_bottom, handle_border, handle], + }, + if slider.state.is_dragging() { + MouseCursor::Grabbing + } else if is_mouse_over { + MouseCursor::Grab + } else { + MouseCursor::OutOfBounds + }, + ) } } diff --git a/wgpu/src/shader/quad.frag b/wgpu/src/shader/quad.frag index 987744db..849f581e 100644 --- a/wgpu/src/shader/quad.frag +++ b/wgpu/src/shader/quad.frag @@ -30,7 +30,7 @@ void main() { float radius_alpha = 1.0; if(v_BorderRadius > 0.0) { - radius_alpha = rounded(gl_FragCoord.xy, v_Pos, v_Scale, v_BorderRadius, 1.0); + radius_alpha = rounded(gl_FragCoord.xy, v_Pos, v_Scale, v_BorderRadius, 0.5); } o_Color = vec4(v_Color.xyz, v_Color.w * radius_alpha); diff --git a/wgpu/src/shader/quad.frag.spv b/wgpu/src/shader/quad.frag.spv index 063287b3..71b91b44 100644 Binary files a/wgpu/src/shader/quad.frag.spv and b/wgpu/src/shader/quad.frag.spv differ -- cgit From a444819799345d12ab74b09fc8c82ba360b9eeeb Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sat, 12 Oct 2019 05:07:29 +0200 Subject: Fix button shadow feedback in `iced_wgpu` --- wgpu/src/renderer/button.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'wgpu') diff --git a/wgpu/src/renderer/button.rs b/wgpu/src/renderer/button.rs index aa48da93..ad2186d6 100644 --- a/wgpu/src/renderer/button.rs +++ b/wgpu/src/renderer/button.rs @@ -30,14 +30,16 @@ impl button::Renderer for Renderer { cursor_position, ); - let is_hover = bounds.contains(cursor_position); + let is_mouse_over = bounds.contains(cursor_position); // TODO: Render proper shadows // TODO: Make hovering and pressed styles configurable - let shadow_offset = if button.state.is_pressed { - 0.0 - } else if is_hover { - 2.0 + let shadow_offset = if is_mouse_over { + if button.state.is_pressed { + 0.0 + } else { + 2.0 + } } else { 1.0 }; @@ -74,7 +76,7 @@ impl button::Renderer for Renderer { content, ], }, - if is_hover { + if is_mouse_over { MouseCursor::Pointer } else { MouseCursor::OutOfBounds -- cgit From 8c3dabb5a1640ed77c35f895ca866262bb4f885c Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sat, 12 Oct 2019 18:48:35 +0200 Subject: Draw radio buttons in `iced_wgpu` --- wgpu/src/renderer/radio.rs | 106 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 99 insertions(+), 7 deletions(-) (limited to 'wgpu') diff --git a/wgpu/src/renderer/radio.rs b/wgpu/src/renderer/radio.rs index 712a7104..97b4f70e 100644 --- a/wgpu/src/renderer/radio.rs +++ b/wgpu/src/renderer/radio.rs @@ -1,17 +1,109 @@ use crate::{Primitive, Renderer}; -use iced_native::{radio, Layout, MouseCursor, Node, Point, Radio, Style}; +use iced_native::{ + radio, text, Align, Background, Color, Column, Layout, Length, MouseCursor, + Node, Point, Radio, Rectangle, Row, Text, Widget, +}; + +const SIZE: f32 = 28.0; +const DOT_SIZE: f32 = SIZE / 2.0; impl radio::Renderer for Renderer { - fn node(&self, _checkbox: &Radio) -> Node { - Node::new(Style::default()) + fn node(&self, radio: &Radio) -> Node { + Row::<(), Self>::new() + .spacing(15) + .align_items(Align::Center) + .push( + Column::new() + .width(Length::Units(SIZE as u16)) + .height(Length::Units(SIZE as u16)), + ) + .push(Text::new(&radio.label)) + .node(self) } fn draw( &mut self, - _radio: &Radio, - _layout: Layout<'_>, - _cursor_position: Point, + radio: &Radio, + layout: Layout<'_>, + cursor_position: Point, ) -> Self::Output { - (Primitive::None, MouseCursor::OutOfBounds) + let bounds = layout.bounds(); + let mut children = layout.children(); + + let radio_bounds = children.next().unwrap().bounds(); + let label_layout = children.next().unwrap(); + + let (label, _) = + text::Renderer::draw(self, &Text::new(&radio.label), label_layout); + + let is_mouse_over = bounds.contains(cursor_position); + + let (radio_border, radio_box) = ( + Primitive::Quad { + bounds: radio_bounds, + background: Background::Color(Color { + r: 0.6, + g: 0.6, + b: 0.6, + a: 1.0, + }), + border_radius: (SIZE / 2.0) as u16, + }, + Primitive::Quad { + bounds: Rectangle { + x: radio_bounds.x + 1.0, + y: radio_bounds.y + 1.0, + width: radio_bounds.width - 2.0, + height: radio_bounds.height - 2.0, + }, + background: Background::Color(if is_mouse_over { + Color { + r: 0.90, + g: 0.90, + b: 0.90, + a: 1.0, + } + } else { + Color { + r: 0.95, + g: 0.95, + b: 0.95, + a: 1.0, + } + }), + border_radius: (SIZE / 2.0 - 1.0) as u16, + }, + ); + + ( + Primitive::Group { + primitives: if radio.is_selected { + let radio_circle = Primitive::Quad { + bounds: Rectangle { + x: radio_bounds.x + DOT_SIZE / 2.0, + y: radio_bounds.y + DOT_SIZE / 2.0, + width: radio_bounds.width - DOT_SIZE, + height: radio_bounds.height - DOT_SIZE, + }, + background: Background::Color(Color { + r: 0.30, + g: 0.30, + b: 0.30, + a: 1.0, + }), + border_radius: (DOT_SIZE / 2.0) as u16, + }; + + vec![radio_border, radio_box, radio_circle, label] + } else { + vec![radio_border, radio_box, label] + }, + }, + if is_mouse_over { + MouseCursor::Pointer + } else { + MouseCursor::OutOfBounds + }, + ) } } -- cgit From ccc463a7c051b1096bc8a9f17ec64c2912a11247 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sun, 13 Oct 2019 18:10:12 +0200 Subject: Draw checkbox in `iced_wgpu` --- wgpu/src/renderer/checkbox.rs | 102 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 94 insertions(+), 8 deletions(-) (limited to 'wgpu') diff --git a/wgpu/src/renderer/checkbox.rs b/wgpu/src/renderer/checkbox.rs index 7b06d397..fd3f08b1 100644 --- a/wgpu/src/renderer/checkbox.rs +++ b/wgpu/src/renderer/checkbox.rs @@ -1,20 +1,106 @@ use crate::{Primitive, Renderer}; use iced_native::{ - checkbox, Checkbox, Layout, MouseCursor, Node, Point, Style, + checkbox, text, text::HorizontalAlignment, text::VerticalAlignment, Align, + Background, Checkbox, Color, Column, Layout, Length, MouseCursor, Node, + Point, Rectangle, Row, Text, Widget, }; +const SIZE: f32 = 28.0; + impl checkbox::Renderer for Renderer { - fn node(&self, _checkbox: &Checkbox) -> Node { - Node::new(Style::default()) + fn node(&self, checkbox: &Checkbox) -> Node { + Row::<(), Self>::new() + .spacing(15) + .align_items(Align::Center) + .push( + Column::new() + .width(Length::Units(SIZE as u16)) + .height(Length::Units(SIZE as u16)), + ) + .push(Text::new(&checkbox.label)) + .node(self) } fn draw( &mut self, - _checkbox: &Checkbox, - _layout: Layout<'_>, - _cursor_position: Point, + checkbox: &Checkbox, + layout: Layout<'_>, + cursor_position: Point, ) -> Self::Output { - // TODO - (Primitive::None, MouseCursor::OutOfBounds) + let bounds = layout.bounds(); + let mut children = layout.children(); + + let checkbox_layout = children.next().unwrap(); + let label_layout = children.next().unwrap(); + let checkbox_bounds = checkbox_layout.bounds(); + + let (label, _) = text::Renderer::draw( + self, + &Text::new(&checkbox.label), + label_layout, + ); + + let is_mouse_over = bounds.contains(cursor_position); + + let (checkbox_border, checkbox_box) = ( + Primitive::Quad { + bounds: checkbox_bounds, + background: Background::Color(Color { + r: 0.6, + g: 0.6, + b: 0.6, + a: 1.0, + }), + border_radius: 6, + }, + Primitive::Quad { + bounds: Rectangle { + x: checkbox_bounds.x + 1.0, + y: checkbox_bounds.y + 1.0, + width: checkbox_bounds.width - 2.0, + height: checkbox_bounds.height - 2.0, + }, + background: Background::Color(if is_mouse_over { + Color { + r: 0.90, + g: 0.90, + b: 0.90, + a: 1.0, + } + } else { + Color { + r: 0.95, + g: 0.95, + b: 0.95, + a: 1.0, + } + }), + border_radius: 6, + }, + ); + + ( + Primitive::Group { + primitives: if checkbox.is_checked { + // TODO: Draw an actual icon + let (check, _) = text::Renderer::draw( + self, + &Text::new("X") + .horizontal_alignment(HorizontalAlignment::Center) + .vertical_alignment(VerticalAlignment::Center), + checkbox_layout, + ); + + vec![checkbox_border, checkbox_box, check, label] + } else { + vec![checkbox_border, checkbox_box, label] + }, + }, + if is_mouse_over { + MouseCursor::Pointer + } else { + MouseCursor::OutOfBounds + }, + ) } } -- cgit From 734e80dea6cd39923aaa0d2f27c7368c9cbc5d62 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sun, 13 Oct 2019 18:22:26 +0200 Subject: Draft `Debugger` implementation in `iced_wgpu` --- wgpu/src/renderer.rs | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) (limited to 'wgpu') diff --git a/wgpu/src/renderer.rs b/wgpu/src/renderer.rs index 8d54b2c7..8930e9df 100644 --- a/wgpu/src/renderer.rs +++ b/wgpu/src/renderer.rs @@ -272,9 +272,36 @@ impl Debugger for Renderer { widget: &dyn Widget, layout: Layout<'_>, cursor_position: Point, - _color: Color, + color: Color, ) -> Self::Output { - // TODO: Include a bordered box to display layout bounds - widget.draw(self, layout, cursor_position) + let mut primitives = Vec::new(); + let (primitive, cursor) = widget.draw(self, 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, +) { + // TODO: Draw borders instead + primitives.push(Primitive::Quad { + bounds: layout.bounds(), + background: Background::Color(Color { + r: 0.0, + g: 0.0, + b: 0.0, + a: 0.05, + }), + border_radius: 0, + }); + + for child in layout.children() { + explain_layout(child, color, primitives); } } -- cgit From 523736f08b1d452e4d3405a68b267c6f44adc22b Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sun, 13 Oct 2019 18:57:34 +0200 Subject: Fix `wgpu_glyph` dependency in `iced_wgpu` --- wgpu/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'wgpu') diff --git a/wgpu/Cargo.toml b/wgpu/Cargo.toml index dbc1ddb9..781abec2 100644 --- a/wgpu/Cargo.toml +++ b/wgpu/Cargo.toml @@ -10,6 +10,6 @@ repository = "https://github.com/hecrj/iced" [dependencies] iced_native = { version = "0.1.0-alpha", path = "../native" } wgpu = { version = "0.3", git = "https://github.com/gfx-rs/wgpu-rs", rev = "cb25914b95b58fee0dc139b400867e7a731d98f4" } -wgpu_glyph = { version = "0.4", git = "https://github.com/hecrj/wgpu_glyph", branch = "improvement/update-wgpu" } +wgpu_glyph = { version = "0.4", git = "https://github.com/hecrj/wgpu_glyph", rev = "48daa98f5f785963838b4345e86ac40eac095ba9" } raw-window-handle = "0.1" log = "0.4" -- cgit From f8a232c8af4c50557fbf0c2e0b2ba46fb63f6adc Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 22 Oct 2019 23:20:24 +0200 Subject: Remove generic handle in `Image` For now, we will simply assume images will be loaded from a given path. --- wgpu/src/renderer/image.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'wgpu') diff --git a/wgpu/src/renderer/image.rs b/wgpu/src/renderer/image.rs index a29a3d49..85ac3ad5 100644 --- a/wgpu/src/renderer/image.rs +++ b/wgpu/src/renderer/image.rs @@ -1,16 +1,12 @@ use crate::{Primitive, Renderer}; use iced_native::{image, Image, Layout, MouseCursor, Node, Style}; -impl image::Renderer<&str> for Renderer { - fn node(&self, _image: &Image<&str>) -> Node { +impl image::Renderer for Renderer { + fn node(&self, _image: &Image) -> Node { Node::new(Style::default()) } - fn draw( - &mut self, - _image: &Image<&str>, - _layout: Layout<'_>, - ) -> Self::Output { + fn draw(&mut self, _image: &Image, _layout: Layout<'_>) -> Self::Output { (Primitive::None, MouseCursor::OutOfBounds) } } -- cgit From 38b6c84e7761c049b17d178deb9c866386a53946 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 23 Oct 2019 01:21:23 +0200 Subject: Implement basic image rendering in `iced_wgpu` --- wgpu/Cargo.toml | 1 + wgpu/src/image.rs | 438 +++++++++++++++++++++++++++++++++++++++++ wgpu/src/lib.rs | 2 + wgpu/src/primitive.rs | 4 + wgpu/src/renderer.rs | 24 ++- wgpu/src/renderer/image.rs | 31 ++- wgpu/src/shader/image.frag | 12 ++ wgpu/src/shader/image.frag.spv | Bin 0 -> 684 bytes wgpu/src/shader/image.vert | 24 +++ wgpu/src/shader/image.vert.spv | Bin 0 -> 2136 bytes 10 files changed, 530 insertions(+), 6 deletions(-) create mode 100644 wgpu/src/image.rs create mode 100644 wgpu/src/shader/image.frag create mode 100644 wgpu/src/shader/image.frag.spv create mode 100644 wgpu/src/shader/image.vert create mode 100644 wgpu/src/shader/image.vert.spv (limited to 'wgpu') diff --git a/wgpu/Cargo.toml b/wgpu/Cargo.toml index 781abec2..cac5e113 100644 --- a/wgpu/Cargo.toml +++ b/wgpu/Cargo.toml @@ -12,4 +12,5 @@ iced_native = { version = "0.1.0-alpha", path = "../native" } wgpu = { version = "0.3", git = "https://github.com/gfx-rs/wgpu-rs", rev = "cb25914b95b58fee0dc139b400867e7a731d98f4" } wgpu_glyph = { version = "0.4", git = "https://github.com/hecrj/wgpu_glyph", rev = "48daa98f5f785963838b4345e86ac40eac095ba9" } raw-window-handle = "0.1" +image = "0.22" log = "0.4" diff --git a/wgpu/src/image.rs b/wgpu/src/image.rs new file mode 100644 index 00000000..18889faf --- /dev/null +++ b/wgpu/src/image.rs @@ -0,0 +1,438 @@ +use crate::Transformation; + +use std::cell::RefCell; +use std::collections::HashMap; +use std::mem; +use std::rc::Rc; + +pub struct Pipeline { + cache: RefCell>, + + pipeline: wgpu::RenderPipeline, + transform: wgpu::Buffer, + vertices: wgpu::Buffer, + indices: wgpu::Buffer, + instances: wgpu::Buffer, + constants: wgpu::BindGroup, + texture_layout: wgpu::BindGroupLayout, +} + +impl Pipeline { + pub fn new(device: &wgpu::Device) -> Self { + let sampler = device.create_sampler(&wgpu::SamplerDescriptor { + address_mode_u: wgpu::AddressMode::ClampToEdge, + address_mode_v: wgpu::AddressMode::ClampToEdge, + address_mode_w: wgpu::AddressMode::ClampToEdge, + mag_filter: wgpu::FilterMode::Linear, + min_filter: wgpu::FilterMode::Linear, + mipmap_filter: wgpu::FilterMode::Linear, + lod_min_clamp: -100.0, + lod_max_clamp: 100.0, + compare_function: wgpu::CompareFunction::Always, + }); + + let constant_layout = + device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + bindings: &[ + wgpu::BindGroupLayoutBinding { + binding: 0, + visibility: wgpu::ShaderStage::VERTEX, + ty: wgpu::BindingType::UniformBuffer { dynamic: false }, + }, + wgpu::BindGroupLayoutBinding { + binding: 1, + visibility: wgpu::ShaderStage::FRAGMENT, + ty: wgpu::BindingType::Sampler, + }, + ], + }); + + let matrix: [f32; 16] = Transformation::identity().into(); + + let transform_buffer = device + .create_buffer_mapped( + 16, + wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST, + ) + .fill_from_slice(&matrix[..]); + + let constant_bind_group = + device.create_bind_group(&wgpu::BindGroupDescriptor { + layout: &constant_layout, + bindings: &[ + wgpu::Binding { + binding: 0, + resource: wgpu::BindingResource::Buffer { + buffer: &transform_buffer, + range: 0..64, + }, + }, + wgpu::Binding { + binding: 1, + resource: wgpu::BindingResource::Sampler(&sampler), + }, + ], + }); + + let texture_layout = + device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + bindings: &[wgpu::BindGroupLayoutBinding { + binding: 0, + visibility: wgpu::ShaderStage::FRAGMENT, + ty: wgpu::BindingType::SampledTexture { + multisampled: false, + dimension: wgpu::TextureViewDimension::D2, + }, + }], + }); + + let layout = + device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + bind_group_layouts: &[&constant_layout, &texture_layout], + }); + + let vs = include_bytes!("shader/image.vert.spv"); + let vs_module = device.create_shader_module( + &wgpu::read_spirv(std::io::Cursor::new(&vs[..])) + .expect("Read image vertex shader as SPIR-V"), + ); + + let fs = include_bytes!("shader/image.frag.spv"); + let fs_module = device.create_shader_module( + &wgpu::read_spirv(std::io::Cursor::new(&fs[..])) + .expect("Read image fragment shader as SPIR-V"), + ); + + let pipeline = + device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { + layout: &layout, + vertex_stage: wgpu::ProgrammableStageDescriptor { + module: &vs_module, + entry_point: "main", + }, + fragment_stage: Some(wgpu::ProgrammableStageDescriptor { + module: &fs_module, + entry_point: "main", + }), + rasterization_state: Some(wgpu::RasterizationStateDescriptor { + front_face: wgpu::FrontFace::Cw, + cull_mode: wgpu::CullMode::None, + depth_bias: 0, + depth_bias_slope_scale: 0.0, + depth_bias_clamp: 0.0, + }), + primitive_topology: wgpu::PrimitiveTopology::TriangleList, + color_states: &[wgpu::ColorStateDescriptor { + format: wgpu::TextureFormat::Bgra8UnormSrgb, + color_blend: wgpu::BlendDescriptor { + src_factor: wgpu::BlendFactor::SrcAlpha, + dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha, + operation: wgpu::BlendOperation::Add, + }, + alpha_blend: wgpu::BlendDescriptor { + src_factor: wgpu::BlendFactor::One, + dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha, + operation: wgpu::BlendOperation::Add, + }, + write_mask: wgpu::ColorWrite::ALL, + }], + depth_stencil_state: None, + index_format: wgpu::IndexFormat::Uint16, + vertex_buffers: &[ + wgpu::VertexBufferDescriptor { + stride: mem::size_of::() as u64, + step_mode: wgpu::InputStepMode::Vertex, + attributes: &[wgpu::VertexAttributeDescriptor { + shader_location: 0, + format: wgpu::VertexFormat::Float2, + offset: 0, + }], + }, + wgpu::VertexBufferDescriptor { + stride: mem::size_of::() as u64, + step_mode: wgpu::InputStepMode::Instance, + attributes: &[ + wgpu::VertexAttributeDescriptor { + shader_location: 1, + format: wgpu::VertexFormat::Float2, + offset: 0, + }, + wgpu::VertexAttributeDescriptor { + shader_location: 2, + format: wgpu::VertexFormat::Float2, + offset: 4 * 2, + }, + ], + }, + ], + sample_count: 1, + sample_mask: !0, + alpha_to_coverage_enabled: false, + }); + + let vertices = device + .create_buffer_mapped(QUAD_VERTS.len(), wgpu::BufferUsage::VERTEX) + .fill_from_slice(&QUAD_VERTS); + + let indices = device + .create_buffer_mapped(QUAD_INDICES.len(), wgpu::BufferUsage::INDEX) + .fill_from_slice(&QUAD_INDICES); + + let instances = device.create_buffer(&wgpu::BufferDescriptor { + size: mem::size_of::() as u64, + usage: wgpu::BufferUsage::VERTEX | wgpu::BufferUsage::COPY_DST, + }); + + Pipeline { + cache: RefCell::new(HashMap::new()), + + pipeline, + transform: transform_buffer, + vertices, + indices, + instances, + constants: constant_bind_group, + texture_layout, + } + } + + pub fn dimensions(&self, path: &str) -> (u32, u32) { + self.load(path); + + self.cache.borrow().get(path).unwrap().dimensions() + } + + fn load(&self, path: &str) { + if !self.cache.borrow().contains_key(path) { + let image = image::open(path).expect("Load image").to_bgra(); + + self.cache + .borrow_mut() + .insert(path.to_string(), Memory::Host { image }); + } + } + + pub fn draw( + &mut self, + device: &mut wgpu::Device, + encoder: &mut wgpu::CommandEncoder, + instances: &[Image], + transformation: Transformation, + target: &wgpu::TextureView, + ) { + let matrix: [f32; 16] = transformation.into(); + + let transform_buffer = device + .create_buffer_mapped(16, wgpu::BufferUsage::COPY_SRC) + .fill_from_slice(&matrix[..]); + + encoder.copy_buffer_to_buffer( + &transform_buffer, + 0, + &self.transform, + 0, + 16 * 4, + ); + + // TODO: Batch draw calls using a texture atlas + // Guillotière[1] by @nical can help us a lot here. + // + // [1]: https://github.com/nical/guillotiere + for image in instances { + self.load(&image.path); + + let texture = self + .cache + .borrow_mut() + .get_mut(&image.path) + .unwrap() + .upload(device, encoder, &self.texture_layout); + + let instance_buffer = device + .create_buffer_mapped(1, wgpu::BufferUsage::COPY_SRC) + .fill_from_slice(&[Instance { + position: image.position, + scale: image.scale, + }]); + + encoder.copy_buffer_to_buffer( + &instance_buffer, + 0, + &self.instances, + 0, + mem::size_of::() as u64, + ); + + { + let mut render_pass = + encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + color_attachments: &[ + wgpu::RenderPassColorAttachmentDescriptor { + attachment: target, + resolve_target: None, + load_op: wgpu::LoadOp::Load, + store_op: wgpu::StoreOp::Store, + clear_color: wgpu::Color { + r: 0.0, + g: 0.0, + b: 0.0, + a: 0.0, + }, + }, + ], + depth_stencil_attachment: None, + }); + + render_pass.set_pipeline(&self.pipeline); + render_pass.set_bind_group(0, &self.constants, &[]); + render_pass.set_bind_group(1, &texture, &[]); + render_pass.set_index_buffer(&self.indices, 0); + render_pass.set_vertex_buffers( + 0, + &[(&self.vertices, 0), (&self.instances, 0)], + ); + + render_pass.draw_indexed( + 0..QUAD_INDICES.len() as u32, + 0, + 0..1 as u32, + ); + } + } + } +} + +enum Memory { + Host { + image: image::ImageBuffer, Vec>, + }, + Device { + bind_group: Rc, + width: u32, + height: u32, + }, +} + +impl Memory { + fn dimensions(&self) -> (u32, u32) { + match self { + Memory::Host { image } => image.dimensions(), + Memory::Device { width, height, .. } => (*width, *height), + } + } + + fn upload( + &mut self, + device: &wgpu::Device, + encoder: &mut wgpu::CommandEncoder, + texture_layout: &wgpu::BindGroupLayout, + ) -> Rc { + match self { + Memory::Host { image } => { + let (width, height) = image.dimensions(); + + let extent = wgpu::Extent3d { + width, + height, + depth: 1, + }; + + let texture = device.create_texture(&wgpu::TextureDescriptor { + size: extent, + array_layer_count: 1, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: wgpu::TextureFormat::Bgra8UnormSrgb, + usage: wgpu::TextureUsage::COPY_DST + | wgpu::TextureUsage::SAMPLED, + }); + + let slice = image.clone().into_raw(); + + let temp_buf = device + .create_buffer_mapped( + slice.len(), + wgpu::BufferUsage::COPY_SRC, + ) + .fill_from_slice(&slice[..]); + + encoder.copy_buffer_to_texture( + wgpu::BufferCopyView { + buffer: &temp_buf, + offset: 0, + row_pitch: 4 * width as u32, + image_height: height as u32, + }, + wgpu::TextureCopyView { + texture: &texture, + array_layer: 0, + mip_level: 0, + origin: wgpu::Origin3d { + x: 0.0, + y: 0.0, + z: 0.0, + }, + }, + extent, + ); + + let bind_group = + device.create_bind_group(&wgpu::BindGroupDescriptor { + layout: texture_layout, + bindings: &[wgpu::Binding { + binding: 0, + resource: wgpu::BindingResource::TextureView( + &texture.create_default_view(), + ), + }], + }); + + let bind_group = Rc::new(bind_group); + + *self = Memory::Device { + bind_group: bind_group.clone(), + width, + height, + }; + + bind_group + } + Memory::Device { bind_group, .. } => bind_group.clone(), + } + } +} + +pub struct Image { + pub path: String, + pub position: [f32; 2], + pub scale: [f32; 2], +} + +#[derive(Clone, Copy)] +pub struct Vertex { + _position: [f32; 2], +} + +const QUAD_INDICES: [u16; 6] = [0, 1, 2, 0, 2, 3]; + +const QUAD_VERTS: [Vertex; 4] = [ + Vertex { + _position: [0.0, 0.0], + }, + Vertex { + _position: [1.0, 0.0], + }, + Vertex { + _position: [1.0, 1.0], + }, + Vertex { + _position: [0.0, 1.0], + }, +]; + +#[derive(Clone, Copy)] +struct Instance { + position: [f32; 2], + scale: [f32; 2], +} diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 46849aab..01dc4c20 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -1,8 +1,10 @@ +mod image; mod primitive; mod quad; mod renderer; mod transformation; +pub(crate) use crate::image::Image; pub(crate) use quad::Quad; pub(crate) use transformation::Transformation; diff --git a/wgpu/src/primitive.rs b/wgpu/src/primitive.rs index b664689b..0b9e2c41 100644 --- a/wgpu/src/primitive.rs +++ b/wgpu/src/primitive.rs @@ -19,4 +19,8 @@ pub enum Primitive { background: Background, border_radius: u16, }, + Image { + path: String, + bounds: Rectangle, + }, } diff --git a/wgpu/src/renderer.rs b/wgpu/src/renderer.rs index 8930e9df..ab6f744f 100644 --- a/wgpu/src/renderer.rs +++ b/wgpu/src/renderer.rs @@ -1,4 +1,4 @@ -use crate::{quad, Primitive, Quad, Transformation}; +use crate::{quad, Image, Primitive, Quad, Transformation}; use iced_native::{ renderer::Debugger, renderer::Windowed, Background, Color, Layout, MouseCursor, Point, Widget, @@ -29,8 +29,10 @@ pub struct Renderer { device: Device, queue: Queue, quad_pipeline: quad::Pipeline, + image_pipeline: crate::image::Pipeline, quads: Vec, + images: Vec, glyph_brush: Rc>>, } @@ -67,6 +69,7 @@ impl Renderer { .build(&mut device, TextureFormat::Bgra8UnormSrgb); let quad_pipeline = quad::Pipeline::new(&mut device); + let image_pipeline = crate::image::Pipeline::new(&mut device); Self { surface, @@ -74,8 +77,10 @@ impl Renderer { device, queue, quad_pipeline, + image_pipeline, quads: Vec::new(), + images: Vec::new(), glyph_brush: Rc::new(RefCell::new(glyph_brush)), } } @@ -139,6 +144,16 @@ impl Renderer { self.quads.clear(); + self.image_pipeline.draw( + &mut self.device, + &mut encoder, + &self.images, + target.transformation, + &frame.view, + ); + + self.images.clear(); + self.glyph_brush .borrow_mut() .draw_queued( @@ -238,6 +253,13 @@ impl Renderer { border_radius: u32::from(*border_radius), }); } + Primitive::Image { path, bounds } => { + self.images.push(Image { + path: path.clone(), + position: [bounds.x, bounds.y], + scale: [bounds.width, bounds.height], + }); + } } } } diff --git a/wgpu/src/renderer/image.rs b/wgpu/src/renderer/image.rs index 85ac3ad5..1a9b01bb 100644 --- a/wgpu/src/renderer/image.rs +++ b/wgpu/src/renderer/image.rs @@ -1,12 +1,33 @@ use crate::{Primitive, Renderer}; -use iced_native::{image, Image, Layout, MouseCursor, Node, Style}; +use iced_native::{image, Image, Layout, Length, MouseCursor, Node, Style}; impl image::Renderer for Renderer { - fn node(&self, _image: &Image) -> Node { - Node::new(Style::default()) + fn node(&self, image: &Image) -> Node { + let (width, height) = self.image_pipeline.dimensions(&image.path); + + let aspect_ratio = width as f32 / height as f32; + + let mut style = Style::default().align_self(image.align_self); + + style = match (image.width, image.height) { + (Length::Units(width), _) => style.width(image.width).height( + Length::Units((width as f32 / aspect_ratio).round() as u16), + ), + (_, _) => style + .width(Length::Units(width as u16)) + .height(Length::Units(height as u16)), + }; + + Node::new(style) } - fn draw(&mut self, _image: &Image, _layout: Layout<'_>) -> Self::Output { - (Primitive::None, MouseCursor::OutOfBounds) + fn draw(&mut self, image: &Image, layout: Layout<'_>) -> Self::Output { + ( + Primitive::Image { + path: image.path.clone(), + bounds: layout.bounds(), + }, + MouseCursor::OutOfBounds, + ) } } diff --git a/wgpu/src/shader/image.frag b/wgpu/src/shader/image.frag new file mode 100644 index 00000000..e35e455a --- /dev/null +++ b/wgpu/src/shader/image.frag @@ -0,0 +1,12 @@ +#version 450 + +layout(location = 0) in vec2 v_Uv; + +layout(set = 0, binding = 1) uniform sampler u_Sampler; +layout(set = 1, binding = 0) uniform texture2D u_Texture; + +layout(location = 0) out vec4 o_Color; + +void main() { + o_Color = texture(sampler2D(u_Texture, u_Sampler), v_Uv); +} diff --git a/wgpu/src/shader/image.frag.spv b/wgpu/src/shader/image.frag.spv new file mode 100644 index 00000000..ebee82ac Binary files /dev/null and b/wgpu/src/shader/image.frag.spv differ diff --git a/wgpu/src/shader/image.vert b/wgpu/src/shader/image.vert new file mode 100644 index 00000000..688c2311 --- /dev/null +++ b/wgpu/src/shader/image.vert @@ -0,0 +1,24 @@ +#version 450 + +layout(location = 0) in vec2 v_Pos; +layout(location = 1) in vec2 i_Pos; +layout(location = 2) in vec2 i_Scale; + +layout (set = 0, binding = 0) uniform Globals { + mat4 u_Transform; +}; + +layout(location = 0) out vec2 o_Uv; + +void main() { + o_Uv = v_Pos; + + mat4 i_Transform = mat4( + vec4(i_Scale.x, 0.0, 0.0, 0.0), + vec4(0.0, i_Scale.y, 0.0, 0.0), + vec4(0.0, 0.0, 1.0, 0.0), + vec4(i_Pos, 0.0, 1.0) + ); + + gl_Position = u_Transform * i_Transform * vec4(v_Pos, 0.0, 1.0); +} diff --git a/wgpu/src/shader/image.vert.spv b/wgpu/src/shader/image.vert.spv new file mode 100644 index 00000000..9ba702bc Binary files /dev/null and b/wgpu/src/shader/image.vert.spv differ -- cgit From 871eb414303804233ed50d43bb9b98a7037cbd4c Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 23 Oct 2019 01:34:58 +0200 Subject: Add `TODO` to `image::Renderer::node` --- wgpu/src/renderer/image.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'wgpu') diff --git a/wgpu/src/renderer/image.rs b/wgpu/src/renderer/image.rs index 1a9b01bb..0e312706 100644 --- a/wgpu/src/renderer/image.rs +++ b/wgpu/src/renderer/image.rs @@ -9,6 +9,7 @@ impl image::Renderer for Renderer { let mut style = Style::default().align_self(image.align_self); + // TODO: Deal with additional cases style = match (image.width, image.height) { (Length::Units(width), _) => style.width(image.width).height( Length::Units((width as f32 / aspect_ratio).round() as u16), -- cgit From 2f8e9dbe59e0d91832ab14f8fc0ad7e18ff61ebe Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 23 Oct 2019 02:34:30 +0200 Subject: Remove warnings in `wgpu::image` --- wgpu/src/image.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'wgpu') diff --git a/wgpu/src/image.rs b/wgpu/src/image.rs index 18889faf..c883eaa8 100644 --- a/wgpu/src/image.rs +++ b/wgpu/src/image.rs @@ -251,8 +251,8 @@ impl Pipeline { let instance_buffer = device .create_buffer_mapped(1, wgpu::BufferUsage::COPY_SRC) .fill_from_slice(&[Instance { - position: image.position, - scale: image.scale, + _position: image.position, + _scale: image.scale, }]); encoder.copy_buffer_to_buffer( @@ -433,6 +433,6 @@ const QUAD_VERTS: [Vertex; 4] = [ #[derive(Clone, Copy)] struct Instance { - position: [f32; 2], - scale: [f32; 2], + _position: [f32; 2], + _scale: [f32; 2], } -- cgit