From 5575e6ea0897e406674e7e4239808fbf9daa07c3 Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Mon, 24 Oct 2022 17:06:02 -0700 Subject: Add image/svg support to `iced_glow` https://github.com/iced-rs/iced/issues/674 Uses image/svg support in `iced_graphics`. The is not currently using an atlas, and uses one texture/draw per image. This should be good enough for now; supporting images with glow is better than not supporting them, and if something else performs better, that improvement can be made without any change to the public API. --- glow/src/backend.rs | 26 ++++- glow/src/image.rs | 212 ++++++++++++++++++++++++++++++++++++++ glow/src/image/textures.rs | 82 +++++++++++++++ glow/src/lib.rs | 2 + glow/src/shader/common/image.frag | 22 ++++ glow/src/shader/common/image.vert | 9 ++ 6 files changed, 350 insertions(+), 3 deletions(-) create mode 100644 glow/src/image.rs create mode 100644 glow/src/image/textures.rs create mode 100644 glow/src/shader/common/image.frag create mode 100644 glow/src/shader/common/image.vert (limited to 'glow/src') diff --git a/glow/src/backend.rs b/glow/src/backend.rs index 21af2ecf..1ba70a49 100644 --- a/glow/src/backend.rs +++ b/glow/src/backend.rs @@ -1,3 +1,5 @@ +#[cfg(any(feature = "image_rs", feature = "svg"))] +use crate::image; use crate::quad; use crate::text; use crate::{program, triangle}; @@ -15,6 +17,8 @@ use iced_native::{Font, Size}; /// [`iced`]: https://github.com/iced-rs/iced #[derive(Debug)] pub struct Backend { + #[cfg(any(feature = "image_rs", feature = "svg"))] + image_pipeline: image::Pipeline, quad_pipeline: quad::Pipeline, text_pipeline: text::Pipeline, triangle_pipeline: triangle::Pipeline, @@ -32,10 +36,14 @@ impl Backend { let shader_version = program::Version::new(gl); + #[cfg(any(feature = "image_rs", feature = "svg"))] + let image_pipeline = image::Pipeline::new(gl, &shader_version); let quad_pipeline = quad::Pipeline::new(gl, &shader_version); let triangle_pipeline = triangle::Pipeline::new(gl, &shader_version); Self { + #[cfg(any(feature = "image_rs", feature = "svg"))] + image_pipeline, quad_pipeline, text_pipeline, triangle_pipeline, @@ -70,6 +78,9 @@ impl Backend { viewport_size.height, ); } + + #[cfg(any(feature = "image_rs", feature = "svg"))] + self.image_pipeline.trim_cache(gl); } fn flush( @@ -112,6 +123,15 @@ impl Backend { ); } + #[cfg(any(feature = "image_rs", feature = "svg"))] + if !layer.images.is_empty() { + let scaled = transformation + * Transformation::scale(scale_factor, scale_factor); + + self.image_pipeline + .draw(gl, scaled, scale_factor, &layer.images); + } + if !layer.text.is_empty() { for text in layer.text.iter() { // Target physical coordinates directly to avoid blurry text @@ -236,10 +256,10 @@ impl backend::Text for Backend { } } -#[cfg(feature = "image")] +#[cfg(feature = "image_rs")] impl backend::Image for Backend { - fn dimensions(&self, _handle: &iced_native::image::Handle) -> (u32, u32) { - (50, 50) + fn dimensions(&self, handle: &iced_native::image::Handle) -> (u32, u32) { + self.image_pipeline.dimensions(handle) } } diff --git a/glow/src/image.rs b/glow/src/image.rs new file mode 100644 index 00000000..51e3016e --- /dev/null +++ b/glow/src/image.rs @@ -0,0 +1,212 @@ +use crate::program::{self, Shader}; +use crate::Transformation; +use glow::HasContext; +use iced_graphics::layer; +#[cfg(feature = "image_rs")] +use std::cell::RefCell; + +pub use iced_graphics::triangle::{Mesh2D, Vertex2D}; + +#[cfg(feature = "image_rs")] +use iced_graphics::image::raster; + +#[cfg(feature = "svg")] +use iced_graphics::image::vector; + +mod textures; +use textures::{Entry, Textures}; + +#[derive(Debug)] +pub(crate) struct Pipeline { + program: ::Program, + vertex_array: ::VertexArray, + vertex_buffer: ::Buffer, + transform_location: ::UniformLocation, + textures: Textures, + #[cfg(feature = "image_rs")] + raster_cache: RefCell>, + #[cfg(feature = "svg")] + vector_cache: vector::Cache, +} + +impl Pipeline { + pub fn new( + gl: &glow::Context, + shader_version: &program::Version, + ) -> Pipeline { + let program = unsafe { + let vertex_shader = Shader::vertex( + gl, + shader_version, + include_str!("shader/common/image.vert"), + ); + let fragment_shader = Shader::fragment( + gl, + shader_version, + include_str!("shader/common/image.frag"), + ); + + program::create( + gl, + &[vertex_shader, fragment_shader], + &[(0, "i_Position")], + ) + }; + + let transform_location = + unsafe { gl.get_uniform_location(program, "u_Transform") } + .expect("Get transform location"); + + unsafe { + gl.use_program(Some(program)); + + let transform: [f32; 16] = Transformation::identity().into(); + gl.uniform_matrix_4_f32_slice( + Some(&transform_location), + false, + &transform, + ); + + gl.use_program(None); + } + + let vertex_buffer = + unsafe { gl.create_buffer().expect("Create vertex buffer") }; + let vertex_array = + unsafe { gl.create_vertex_array().expect("Create vertex array") }; + + unsafe { + gl.bind_vertex_array(Some(vertex_array)); + gl.bind_buffer(glow::ARRAY_BUFFER, Some(vertex_buffer)); + + let vertices = &[0u8, 0, 1, 0, 0, 1, 1, 1]; + gl.buffer_data_size( + glow::ARRAY_BUFFER, + vertices.len() as i32, + glow::STATIC_DRAW, + ); + gl.buffer_sub_data_u8_slice( + glow::ARRAY_BUFFER, + 0, + bytemuck::cast_slice(vertices), + ); + + gl.enable_vertex_attrib_array(0); + gl.vertex_attrib_pointer_f32( + 0, + 2, + glow::UNSIGNED_BYTE, + false, + 0, + 0, + ); + + gl.bind_buffer(glow::ARRAY_BUFFER, None); + gl.bind_vertex_array(None); + } + + Pipeline { + program, + vertex_array, + vertex_buffer, + transform_location, + textures: Textures::new(), + #[cfg(feature = "image_rs")] + raster_cache: RefCell::new(raster::Cache::default()), + #[cfg(feature = "svg")] + vector_cache: vector::Cache::default(), + } + } + + #[cfg(feature = "image_rs")] + pub fn dimensions( + &self, + handle: &iced_native::image::Handle, + ) -> (u32, u32) { + self.raster_cache.borrow_mut().load(handle).dimensions() + } + + pub fn draw( + &mut self, + mut gl: &glow::Context, + transformation: Transformation, + _scale_factor: f32, + images: &[layer::Image], + ) { + unsafe { + gl.use_program(Some(self.program)); + gl.bind_vertex_array(Some(self.vertex_array)); + gl.bind_buffer(glow::ARRAY_BUFFER, Some(self.vertex_buffer)); + } + + #[cfg(feature = "image_rs")] + let mut raster_cache = self.raster_cache.borrow_mut(); + for image in images { + let (entry, bounds) = match &image { + #[cfg(feature = "image_rs")] + layer::Image::Raster { handle, bounds } => ( + raster_cache.upload(handle, &mut gl, &mut self.textures), + bounds, + ), + #[cfg(not(feature = "image_rs"))] + layer::Image::Raster { handle: _, bounds } => (None, bounds), + + #[cfg(feature = "svg")] + layer::Image::Vector { handle, bounds } => { + let size = [bounds.width, bounds.height]; + ( + self.vector_cache.upload( + handle, + size, + _scale_factor, + &mut gl, + &mut self.textures, + ), + bounds, + ) + } + + #[cfg(not(feature = "svg"))] + layer::Image::Vector { handle: _, bounds } => (None, bounds), + }; + + unsafe { + if let Some(Entry { texture, .. }) = entry { + gl.bind_texture(glow::TEXTURE_2D, Some(*texture)) + } else { + continue; + } + + let translate = Transformation::translate(bounds.x, bounds.y); + let scale = Transformation::scale(bounds.width, bounds.height); + let transformation = transformation * translate * scale; + let matrix: [f32; 16] = transformation.into(); + gl.uniform_matrix_4_f32_slice( + Some(&self.transform_location), + false, + &matrix, + ); + + gl.draw_arrays(glow::TRIANGLE_STRIP, 0, 4); + + gl.bind_texture(glow::TEXTURE_2D, None); + } + } + + unsafe { + gl.bind_buffer(glow::ARRAY_BUFFER, None); + gl.bind_vertex_array(None); + gl.use_program(None); + } + } + + pub fn trim_cache(&mut self, mut gl: &glow::Context) { + #[cfg(feature = "image_rs")] + self.raster_cache + .borrow_mut() + .trim(&mut self.textures, &mut gl); + + #[cfg(feature = "svg")] + self.vector_cache.trim(&mut self.textures, &mut gl); + } +} diff --git a/glow/src/image/textures.rs b/glow/src/image/textures.rs new file mode 100644 index 00000000..f43cae1c --- /dev/null +++ b/glow/src/image/textures.rs @@ -0,0 +1,82 @@ +use glow::HasContext; +use iced_graphics::image::{TextureStore, TextureStoreEntry}; + +#[derive(Debug)] +pub struct Textures; + +impl Textures { + pub fn new() -> Self { + Self + } +} + +impl TextureStore for Textures { + type Entry = Entry; + type State<'a> = &'a glow::Context; + + fn upload( + &mut self, + width: u32, + height: u32, + data: &[u8], + gl: &mut &glow::Context, + ) -> Option { + unsafe { + let texture = gl.create_texture().expect("create texture"); + gl.bind_texture(glow::TEXTURE_2D, Some(texture)); + gl.tex_image_2d( + glow::TEXTURE_2D, + 0, + glow::SRGB8_ALPHA8 as i32, + width as i32, + height as i32, + 0, + glow::BGRA, + glow::UNSIGNED_BYTE, + Some(data), + ); + gl.tex_parameter_i32( + glow::TEXTURE_2D, + glow::TEXTURE_WRAP_S, + glow::CLAMP_TO_EDGE as _, + ); + gl.tex_parameter_i32( + glow::TEXTURE_2D, + glow::TEXTURE_WRAP_T, + glow::CLAMP_TO_EDGE as _, + ); + gl.tex_parameter_i32( + glow::TEXTURE_2D, + glow::TEXTURE_MIN_FILTER, + glow::LINEAR as _, + ); + gl.tex_parameter_i32( + glow::TEXTURE_2D, + glow::TEXTURE_MAG_FILTER, + glow::LINEAR as _, + ); + gl.bind_texture(glow::TEXTURE_2D, None); + + Some(Entry { + size: (width, height), + texture, + }) + } + } + + fn remove(&mut self, entry: &Entry, gl: &mut &glow::Context) { + unsafe { gl.delete_texture(entry.texture) } + } +} + +#[derive(Debug)] +pub struct Entry { + size: (u32, u32), + pub texture: glow::NativeTexture, +} + +impl TextureStoreEntry for Entry { + fn size(&self) -> (u32, u32) { + self.size + } +} diff --git a/glow/src/lib.rs b/glow/src/lib.rs index de9c0002..daeb3e32 100644 --- a/glow/src/lib.rs +++ b/glow/src/lib.rs @@ -24,6 +24,8 @@ pub use glow; mod backend; +#[cfg(any(feature = "image_rs", feature = "svg"))] +mod image; mod program; mod quad; mod text; diff --git a/glow/src/shader/common/image.frag b/glow/src/shader/common/image.frag new file mode 100644 index 00000000..5e05abdf --- /dev/null +++ b/glow/src/shader/common/image.frag @@ -0,0 +1,22 @@ +#ifdef GL_ES +#ifdef GL_FRAGMENT_PRECISION_HIGH +precision highp float; +#else +precision mediump float; +#endif +#endif + +uniform sampler2D tex; +in vec2 tex_pos; + +#ifdef HIGHER_THAN_300 +out vec4 fragColor; +#define gl_FragColor fragColor +#endif +#ifdef GL_ES +#define texture texture2D +#endif + +void main() { + gl_FragColor = texture(tex, tex_pos); +} diff --git a/glow/src/shader/common/image.vert b/glow/src/shader/common/image.vert new file mode 100644 index 00000000..93e541f2 --- /dev/null +++ b/glow/src/shader/common/image.vert @@ -0,0 +1,9 @@ +uniform mat4 u_Transform; + +in vec2 i_Position; +out vec2 tex_pos; + +void main() { + gl_Position = u_Transform * vec4(i_Position, 0.0, 1.0); + tex_pos = i_Position; +} -- cgit From 8ce8d374b1e8d1d394a42a5ee2bca8af790f0b71 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sat, 5 Nov 2022 03:13:04 +0100 Subject: Refactor some `image` traits a bit - Use `Size` were applicable. - Rename `TextureStore` to `image::Storage`. - Rename `TextureStoreEntry` to `image::storage::Entry`. - Wire up `viewport_dimensions` to `iced_glow` for `Svg`. --- glow/src/backend.rs | 8 ++--- glow/src/image.rs | 64 +++++++++++++++++++++++------------- glow/src/image/storage.rs | 78 +++++++++++++++++++++++++++++++++++++++++++ glow/src/image/textures.rs | 82 ---------------------------------------------- 4 files changed, 123 insertions(+), 109 deletions(-) create mode 100644 glow/src/image/storage.rs delete mode 100644 glow/src/image/textures.rs (limited to 'glow/src') diff --git a/glow/src/backend.rs b/glow/src/backend.rs index 1ba70a49..35a82c0f 100644 --- a/glow/src/backend.rs +++ b/glow/src/backend.rs @@ -258,7 +258,7 @@ impl backend::Text for Backend { #[cfg(feature = "image_rs")] impl backend::Image for Backend { - fn dimensions(&self, handle: &iced_native::image::Handle) -> (u32, u32) { + fn dimensions(&self, handle: &iced_native::image::Handle) -> Size { self.image_pipeline.dimensions(handle) } } @@ -267,8 +267,8 @@ impl backend::Image for Backend { impl backend::Svg for Backend { fn viewport_dimensions( &self, - _handle: &iced_native::svg::Handle, - ) -> (u32, u32) { - (50, 50) + handle: &iced_native::svg::Handle, + ) -> Size { + self.image_pipeline.viewport_dimensions(handle) } } diff --git a/glow/src/image.rs b/glow/src/image.rs index 51e3016e..66620537 100644 --- a/glow/src/image.rs +++ b/glow/src/image.rs @@ -1,20 +1,24 @@ -use crate::program::{self, Shader}; -use crate::Transformation; -use glow::HasContext; -use iced_graphics::layer; -#[cfg(feature = "image_rs")] -use std::cell::RefCell; +mod storage; + +use storage::Storage; pub use iced_graphics::triangle::{Mesh2D, Vertex2D}; +use crate::program::{self, Shader}; +use crate::Transformation; + #[cfg(feature = "image_rs")] use iced_graphics::image::raster; #[cfg(feature = "svg")] use iced_graphics::image::vector; -mod textures; -use textures::{Entry, Textures}; +use iced_graphics::layer; +use iced_graphics::Size; + +use glow::HasContext; + +use std::cell::RefCell; #[derive(Debug)] pub(crate) struct Pipeline { @@ -22,11 +26,11 @@ pub(crate) struct Pipeline { vertex_array: ::VertexArray, vertex_buffer: ::Buffer, transform_location: ::UniformLocation, - textures: Textures, + storage: Storage, #[cfg(feature = "image_rs")] - raster_cache: RefCell>, + raster_cache: RefCell>, #[cfg(feature = "svg")] - vector_cache: vector::Cache, + vector_cache: RefCell>, } impl Pipeline { @@ -110,22 +114,30 @@ impl Pipeline { vertex_array, vertex_buffer, transform_location, - textures: Textures::new(), + storage: Storage::default(), #[cfg(feature = "image_rs")] raster_cache: RefCell::new(raster::Cache::default()), #[cfg(feature = "svg")] - vector_cache: vector::Cache::default(), + vector_cache: RefCell::new(vector::Cache::default()), } } #[cfg(feature = "image_rs")] - pub fn dimensions( - &self, - handle: &iced_native::image::Handle, - ) -> (u32, u32) { + pub fn dimensions(&self, handle: &iced_native::image::Handle) -> Size { self.raster_cache.borrow_mut().load(handle).dimensions() } + #[cfg(feature = "svg")] + pub fn viewport_dimensions( + &self, + handle: &iced_native::svg::Handle, + ) -> Size { + let mut cache = self.vector_cache.borrow_mut(); + let svg = cache.load(handle); + + svg.viewport_dimensions() + } + pub fn draw( &mut self, mut gl: &glow::Context, @@ -141,11 +153,15 @@ impl Pipeline { #[cfg(feature = "image_rs")] let mut raster_cache = self.raster_cache.borrow_mut(); + + #[cfg(feature = "svg")] + let mut vector_cache = self.vector_cache.borrow_mut(); + for image in images { let (entry, bounds) = match &image { #[cfg(feature = "image_rs")] layer::Image::Raster { handle, bounds } => ( - raster_cache.upload(handle, &mut gl, &mut self.textures), + raster_cache.upload(handle, &mut gl, &mut self.storage), bounds, ), #[cfg(not(feature = "image_rs"))] @@ -155,12 +171,12 @@ impl Pipeline { layer::Image::Vector { handle, bounds } => { let size = [bounds.width, bounds.height]; ( - self.vector_cache.upload( + vector_cache.upload( handle, size, _scale_factor, &mut gl, - &mut self.textures, + &mut self.storage, ), bounds, ) @@ -171,7 +187,7 @@ impl Pipeline { }; unsafe { - if let Some(Entry { texture, .. }) = entry { + if let Some(storage::Entry { texture, .. }) = entry { gl.bind_texture(glow::TEXTURE_2D, Some(*texture)) } else { continue; @@ -204,9 +220,11 @@ impl Pipeline { #[cfg(feature = "image_rs")] self.raster_cache .borrow_mut() - .trim(&mut self.textures, &mut gl); + .trim(&mut self.storage, &mut gl); #[cfg(feature = "svg")] - self.vector_cache.trim(&mut self.textures, &mut gl); + self.vector_cache + .borrow_mut() + .trim(&mut self.storage, &mut gl); } } diff --git a/glow/src/image/storage.rs b/glow/src/image/storage.rs new file mode 100644 index 00000000..e2171fb5 --- /dev/null +++ b/glow/src/image/storage.rs @@ -0,0 +1,78 @@ +use iced_graphics::image; +use iced_graphics::Size; + +use glow::HasContext; + +#[derive(Debug, Default)] +pub struct Storage; + +impl image::Storage for Storage { + type Entry = Entry; + type State<'a> = &'a glow::Context; + + fn upload( + &mut self, + width: u32, + height: u32, + data: &[u8], + gl: &mut &glow::Context, + ) -> Option { + unsafe { + let texture = gl.create_texture().expect("create texture"); + gl.bind_texture(glow::TEXTURE_2D, Some(texture)); + gl.tex_image_2d( + glow::TEXTURE_2D, + 0, + glow::SRGB8_ALPHA8 as i32, + width as i32, + height as i32, + 0, + glow::BGRA, + glow::UNSIGNED_BYTE, + Some(data), + ); + gl.tex_parameter_i32( + glow::TEXTURE_2D, + glow::TEXTURE_WRAP_S, + glow::CLAMP_TO_EDGE as _, + ); + gl.tex_parameter_i32( + glow::TEXTURE_2D, + glow::TEXTURE_WRAP_T, + glow::CLAMP_TO_EDGE as _, + ); + gl.tex_parameter_i32( + glow::TEXTURE_2D, + glow::TEXTURE_MIN_FILTER, + glow::LINEAR as _, + ); + gl.tex_parameter_i32( + glow::TEXTURE_2D, + glow::TEXTURE_MAG_FILTER, + glow::LINEAR as _, + ); + gl.bind_texture(glow::TEXTURE_2D, None); + + Some(Entry { + size: Size::new(width, height), + texture, + }) + } + } + + fn remove(&mut self, entry: &Entry, gl: &mut &glow::Context) { + unsafe { gl.delete_texture(entry.texture) } + } +} + +#[derive(Debug)] +pub struct Entry { + size: Size, + pub(super) texture: glow::NativeTexture, +} + +impl image::storage::Entry for Entry { + fn size(&self) -> Size { + self.size + } +} diff --git a/glow/src/image/textures.rs b/glow/src/image/textures.rs deleted file mode 100644 index f43cae1c..00000000 --- a/glow/src/image/textures.rs +++ /dev/null @@ -1,82 +0,0 @@ -use glow::HasContext; -use iced_graphics::image::{TextureStore, TextureStoreEntry}; - -#[derive(Debug)] -pub struct Textures; - -impl Textures { - pub fn new() -> Self { - Self - } -} - -impl TextureStore for Textures { - type Entry = Entry; - type State<'a> = &'a glow::Context; - - fn upload( - &mut self, - width: u32, - height: u32, - data: &[u8], - gl: &mut &glow::Context, - ) -> Option { - unsafe { - let texture = gl.create_texture().expect("create texture"); - gl.bind_texture(glow::TEXTURE_2D, Some(texture)); - gl.tex_image_2d( - glow::TEXTURE_2D, - 0, - glow::SRGB8_ALPHA8 as i32, - width as i32, - height as i32, - 0, - glow::BGRA, - glow::UNSIGNED_BYTE, - Some(data), - ); - gl.tex_parameter_i32( - glow::TEXTURE_2D, - glow::TEXTURE_WRAP_S, - glow::CLAMP_TO_EDGE as _, - ); - gl.tex_parameter_i32( - glow::TEXTURE_2D, - glow::TEXTURE_WRAP_T, - glow::CLAMP_TO_EDGE as _, - ); - gl.tex_parameter_i32( - glow::TEXTURE_2D, - glow::TEXTURE_MIN_FILTER, - glow::LINEAR as _, - ); - gl.tex_parameter_i32( - glow::TEXTURE_2D, - glow::TEXTURE_MAG_FILTER, - glow::LINEAR as _, - ); - gl.bind_texture(glow::TEXTURE_2D, None); - - Some(Entry { - size: (width, height), - texture, - }) - } - } - - fn remove(&mut self, entry: &Entry, gl: &mut &glow::Context) { - unsafe { gl.delete_texture(entry.texture) } - } -} - -#[derive(Debug)] -pub struct Entry { - size: (u32, u32), - pub texture: glow::NativeTexture, -} - -impl TextureStoreEntry for Entry { - fn size(&self) -> (u32, u32) { - self.size - } -} -- cgit From 438f97a6d00ad0312e7c84b4c1529968bdfba849 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sat, 5 Nov 2022 03:18:13 +0100 Subject: Use RGBA texture for `image` and `svg` pipelines --- glow/src/image/storage.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'glow/src') diff --git a/glow/src/image/storage.rs b/glow/src/image/storage.rs index e2171fb5..9bc20641 100644 --- a/glow/src/image/storage.rs +++ b/glow/src/image/storage.rs @@ -27,7 +27,7 @@ impl image::Storage for Storage { width as i32, height as i32, 0, - glow::BGRA, + glow::RGBA, glow::UNSIGNED_BYTE, Some(data), ); -- cgit From 0a23f518c70d27f2e44af38e5d3be2a0ab1a9bc1 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sat, 5 Nov 2022 03:26:19 +0100 Subject: Remove redundant features in `iced_wgpu` and `iced_glow` --- glow/src/backend.rs | 14 +++++++------- glow/src/image.rs | 16 ++++++++-------- glow/src/lib.rs | 2 +- 3 files changed, 16 insertions(+), 16 deletions(-) (limited to 'glow/src') diff --git a/glow/src/backend.rs b/glow/src/backend.rs index 35a82c0f..1a41d540 100644 --- a/glow/src/backend.rs +++ b/glow/src/backend.rs @@ -1,4 +1,4 @@ -#[cfg(any(feature = "image_rs", feature = "svg"))] +#[cfg(any(feature = "image", feature = "svg"))] use crate::image; use crate::quad; use crate::text; @@ -17,7 +17,7 @@ use iced_native::{Font, Size}; /// [`iced`]: https://github.com/iced-rs/iced #[derive(Debug)] pub struct Backend { - #[cfg(any(feature = "image_rs", feature = "svg"))] + #[cfg(any(feature = "image", feature = "svg"))] image_pipeline: image::Pipeline, quad_pipeline: quad::Pipeline, text_pipeline: text::Pipeline, @@ -36,13 +36,13 @@ impl Backend { let shader_version = program::Version::new(gl); - #[cfg(any(feature = "image_rs", feature = "svg"))] + #[cfg(any(feature = "image", feature = "svg"))] let image_pipeline = image::Pipeline::new(gl, &shader_version); let quad_pipeline = quad::Pipeline::new(gl, &shader_version); let triangle_pipeline = triangle::Pipeline::new(gl, &shader_version); Self { - #[cfg(any(feature = "image_rs", feature = "svg"))] + #[cfg(any(feature = "image", feature = "svg"))] image_pipeline, quad_pipeline, text_pipeline, @@ -79,7 +79,7 @@ impl Backend { ); } - #[cfg(any(feature = "image_rs", feature = "svg"))] + #[cfg(any(feature = "image", feature = "svg"))] self.image_pipeline.trim_cache(gl); } @@ -123,7 +123,7 @@ impl Backend { ); } - #[cfg(any(feature = "image_rs", feature = "svg"))] + #[cfg(any(feature = "image", feature = "svg"))] if !layer.images.is_empty() { let scaled = transformation * Transformation::scale(scale_factor, scale_factor); @@ -256,7 +256,7 @@ impl backend::Text for Backend { } } -#[cfg(feature = "image_rs")] +#[cfg(feature = "image")] impl backend::Image for Backend { fn dimensions(&self, handle: &iced_native::image::Handle) -> Size { self.image_pipeline.dimensions(handle) diff --git a/glow/src/image.rs b/glow/src/image.rs index 66620537..f906cd4c 100644 --- a/glow/src/image.rs +++ b/glow/src/image.rs @@ -7,7 +7,7 @@ pub use iced_graphics::triangle::{Mesh2D, Vertex2D}; use crate::program::{self, Shader}; use crate::Transformation; -#[cfg(feature = "image_rs")] +#[cfg(feature = "image")] use iced_graphics::image::raster; #[cfg(feature = "svg")] @@ -27,7 +27,7 @@ pub(crate) struct Pipeline { vertex_buffer: ::Buffer, transform_location: ::UniformLocation, storage: Storage, - #[cfg(feature = "image_rs")] + #[cfg(feature = "image")] raster_cache: RefCell>, #[cfg(feature = "svg")] vector_cache: RefCell>, @@ -115,14 +115,14 @@ impl Pipeline { vertex_buffer, transform_location, storage: Storage::default(), - #[cfg(feature = "image_rs")] + #[cfg(feature = "image")] raster_cache: RefCell::new(raster::Cache::default()), #[cfg(feature = "svg")] vector_cache: RefCell::new(vector::Cache::default()), } } - #[cfg(feature = "image_rs")] + #[cfg(feature = "image")] pub fn dimensions(&self, handle: &iced_native::image::Handle) -> Size { self.raster_cache.borrow_mut().load(handle).dimensions() } @@ -151,7 +151,7 @@ impl Pipeline { gl.bind_buffer(glow::ARRAY_BUFFER, Some(self.vertex_buffer)); } - #[cfg(feature = "image_rs")] + #[cfg(feature = "image")] let mut raster_cache = self.raster_cache.borrow_mut(); #[cfg(feature = "svg")] @@ -159,12 +159,12 @@ impl Pipeline { for image in images { let (entry, bounds) = match &image { - #[cfg(feature = "image_rs")] + #[cfg(feature = "image")] layer::Image::Raster { handle, bounds } => ( raster_cache.upload(handle, &mut gl, &mut self.storage), bounds, ), - #[cfg(not(feature = "image_rs"))] + #[cfg(not(feature = "image"))] layer::Image::Raster { handle: _, bounds } => (None, bounds), #[cfg(feature = "svg")] @@ -217,7 +217,7 @@ impl Pipeline { } pub fn trim_cache(&mut self, mut gl: &glow::Context) { - #[cfg(feature = "image_rs")] + #[cfg(feature = "image")] self.raster_cache .borrow_mut() .trim(&mut self.storage, &mut gl); diff --git a/glow/src/lib.rs b/glow/src/lib.rs index daeb3e32..e3690a69 100644 --- a/glow/src/lib.rs +++ b/glow/src/lib.rs @@ -24,7 +24,7 @@ pub use glow; mod backend; -#[cfg(any(feature = "image_rs", feature = "svg"))] +#[cfg(any(feature = "image", feature = "svg"))] mod image; mod program; mod quad; -- cgit From 9841d1938142cb453495a50e4a88059c6eae3074 Mon Sep 17 00:00:00 2001 From: bungoboingo Date: Tue, 8 Nov 2022 11:32:27 -0800 Subject: Fixed issues with old GL versions ( <= 2.1 ) --- glow/src/shader/common/gradient.frag | 32 ++++++++++++++++---------------- glow/src/shader/common/triangle.frag | 2 +- glow/src/triangle/gradient.rs | 4 ++-- 3 files changed, 19 insertions(+), 19 deletions(-) (limited to 'glow/src') diff --git a/glow/src/shader/common/gradient.frag b/glow/src/shader/common/gradient.frag index 42d0201f..9af0cb6e 100644 --- a/glow/src/shader/common/gradient.frag +++ b/glow/src/shader/common/gradient.frag @@ -1,20 +1,20 @@ #ifdef GL_ES - #ifdef GL_FRAGMENT_PRECISION_HIGH - precision highp float; - #else - precision mediump float; - #endif +#ifdef GL_FRAGMENT_PRECISION_HIGH +precision highp float; +#else +precision mediump float; +#endif #endif #ifdef HIGHER_THAN_300 - layout (location = 0) out vec4 fragColor; - #define gl_FragColor fragColor +layout (location = 0) out vec4 fragColor; +#define gl_FragColor fragColor #endif in vec2 raw_position; uniform vec4 gradient_direction; -uniform uint color_stops_size; +uniform int color_stops_size; // GLSL does not support dynamically sized arrays without SSBOs so this is capped to 16 stops //stored as color(vec4) -> offset(vec4) sequentially; uniform vec4 color_stops[32]; @@ -28,23 +28,23 @@ void main() { vec2 unit = normalize(gradient_vec); float coord_offset = dot(unit, current_vec) / length(gradient_vec); //if a gradient has a start/end stop that is identical, the mesh will have a transparent fill - fragColor = vec4(0.0, 0.0, 0.0, 0.0); + gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0); float min_offset = color_stops[1].x; - float max_offset = color_stops[color_stops_size - 1u].x; + float max_offset = color_stops[color_stops_size - 1].x; - for (uint i = 0u; i < color_stops_size - 2u; i += 2u) { - float curr_offset = color_stops[i+1u].x; - float next_offset = color_stops[i+3u].x; + for (int i = 0; i < color_stops_size - 2; i += 2) { + float curr_offset = color_stops[i+1].x; + float next_offset = color_stops[i+3].x; if (coord_offset <= min_offset) { //current coordinate is before the first defined offset, set it to the start color - fragColor = color_stops[0]; + gl_FragColor = color_stops[0]; } if (curr_offset <= coord_offset && coord_offset <= next_offset) { //current fragment is between the current offset processing & the next one, interpolate colors - fragColor = mix(color_stops[i], color_stops[i+2u], smoothstep( + gl_FragColor = mix(color_stops[i], color_stops[i+2], smoothstep( curr_offset, next_offset, coord_offset @@ -53,7 +53,7 @@ void main() { if (coord_offset >= max_offset) { //current coordinate is before the last defined offset, set it to the last color - fragColor = color_stops[color_stops_size - 2u]; + gl_FragColor = color_stops[color_stops_size - 2]; } } } diff --git a/glow/src/shader/common/triangle.frag b/glow/src/shader/common/triangle.frag index ead40fe5..8260f6a6 100644 --- a/glow/src/shader/common/triangle.frag +++ b/glow/src/shader/common/triangle.frag @@ -14,5 +14,5 @@ out vec4 fragColor; uniform vec4 color; void main() { - fragColor = color; + gl_FragColor = color; } diff --git a/glow/src/triangle/gradient.rs b/glow/src/triangle/gradient.rs index 5225612e..d5f26877 100644 --- a/glow/src/triangle/gradient.rs +++ b/glow/src/triangle/gradient.rs @@ -71,14 +71,14 @@ impl Program { linear.end.y, ); - gl.uniform_1_u32( + gl.uniform_1_i32( Some( &self .uniform_data .uniform_locations .color_stops_size_location, ), - (linear.color_stops.len() * 2) as u32, + (linear.color_stops.len() * 2) as i32, ); let mut stops = [0.0; 128]; -- cgit From a6298ba12c038d5eaddca9327abb385aa72a82e9 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 10 Nov 2022 18:14:40 +0100 Subject: Fix outdated links in documentation --- glow/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'glow/src') diff --git a/glow/src/lib.rs b/glow/src/lib.rs index e3690a69..e6ca0562 100644 --- a/glow/src/lib.rs +++ b/glow/src/lib.rs @@ -3,7 +3,7 @@ //! ![The native path of the Iced ecosystem](https://github.com/iced-rs/iced/blob/0525d76ff94e828b7b21634fa94a747022001c83/docs/graphs/native.png?raw=true) //! //! [`glow`]: https://github.com/grovesNL/glow -//! [`iced_native`]: https://github.com/iced-rs/iced/tree/0.4/native +//! [`iced_native`]: https://github.com/iced-rs/iced/tree/0.5/native #![doc( html_logo_url = "https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg" )] -- cgit From 365f37a3ae10e7aff407b84050f77da10820866e Mon Sep 17 00:00:00 2001 From: bungoboingo Date: Thu, 10 Nov 2022 14:43:38 -0800 Subject: Added conditional configurations for WASM target for gradients & storage buffers, since storage buffers are not supported on wgpu WASM target at the moment. --- glow/src/triangle.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'glow/src') diff --git a/glow/src/triangle.rs b/glow/src/triangle.rs index 0e27bcf2..cb7ab055 100644 --- a/glow/src/triangle.rs +++ b/glow/src/triangle.rs @@ -141,6 +141,7 @@ impl Pipeline { triangle::Style::Solid(color) => { self.programs.solid.use_program(gl, color, &transform); } + #[cfg(not(target_arch = "wasm32"))] triangle::Style::Gradient(gradient) => { self.programs .gradient -- cgit From 33c3c0c0aa774bb7462e3c42aa04c591a66376a7 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Mon, 14 Nov 2022 00:02:42 +0100 Subject: Group all solid triangles independently of color --- glow/src/shader/common/gradient.vert | 9 + glow/src/shader/common/solid.frag | 18 ++ glow/src/shader/common/solid.vert | 11 + glow/src/shader/common/triangle.frag | 18 -- glow/src/shader/common/triangle.vert | 9 - glow/src/triangle.rs | 562 +++++++++++++++++++++++++++-------- glow/src/triangle/gradient.rs | 162 ---------- glow/src/triangle/solid.rs | 91 ------ 8 files changed, 484 insertions(+), 396 deletions(-) create mode 100644 glow/src/shader/common/gradient.vert create mode 100644 glow/src/shader/common/solid.frag create mode 100644 glow/src/shader/common/solid.vert delete mode 100644 glow/src/shader/common/triangle.frag delete mode 100644 glow/src/shader/common/triangle.vert delete mode 100644 glow/src/triangle/gradient.rs delete mode 100644 glow/src/triangle/solid.rs (limited to 'glow/src') diff --git a/glow/src/shader/common/gradient.vert b/glow/src/shader/common/gradient.vert new file mode 100644 index 00000000..fe505997 --- /dev/null +++ b/glow/src/shader/common/gradient.vert @@ -0,0 +1,9 @@ +uniform mat4 u_Transform; + +in vec2 i_Position; +out vec2 raw_position; + +void main() { + gl_Position = u_Transform * vec4(i_Position, 0.0, 1.0); + raw_position = i_Position; +} diff --git a/glow/src/shader/common/solid.frag b/glow/src/shader/common/solid.frag new file mode 100644 index 00000000..174ffdd3 --- /dev/null +++ b/glow/src/shader/common/solid.frag @@ -0,0 +1,18 @@ +#ifdef GL_ES +#ifdef GL_FRAGMENT_PRECISION_HIGH +precision highp float; +#else +precision mediump float; +#endif +#endif + +#ifdef HIGHER_THAN_300 +out vec4 fragColor; +#define gl_FragColor fragColor +#endif + +in vec4 v_Color; + +void main() { + gl_FragColor = v_Color; +} diff --git a/glow/src/shader/common/solid.vert b/glow/src/shader/common/solid.vert new file mode 100644 index 00000000..59ed88e5 --- /dev/null +++ b/glow/src/shader/common/solid.vert @@ -0,0 +1,11 @@ +uniform mat4 u_Transform; + +in vec2 i_Position; +in vec4 i_Color; + +out vec4 v_Color; + +void main() { + gl_Position = u_Transform * vec4(i_Position, 0.0, 1.0); + v_Color = i_Color; +} diff --git a/glow/src/shader/common/triangle.frag b/glow/src/shader/common/triangle.frag deleted file mode 100644 index 8260f6a6..00000000 --- a/glow/src/shader/common/triangle.frag +++ /dev/null @@ -1,18 +0,0 @@ -#ifdef GL_ES -#ifdef GL_FRAGMENT_PRECISION_HIGH -precision highp float; -#else -precision mediump float; -#endif -#endif - -#ifdef HIGHER_THAN_300 -out vec4 fragColor; -#define gl_FragColor fragColor -#endif - -uniform vec4 color; - -void main() { - gl_FragColor = color; -} diff --git a/glow/src/shader/common/triangle.vert b/glow/src/shader/common/triangle.vert deleted file mode 100644 index fe505997..00000000 --- a/glow/src/shader/common/triangle.vert +++ /dev/null @@ -1,9 +0,0 @@ -uniform mat4 u_Transform; - -in vec2 i_Position; -out vec2 raw_position; - -void main() { - gl_Position = u_Transform * vec4(i_Position, 0.0, 1.0); - raw_position = i_Position; -} diff --git a/glow/src/triangle.rs b/glow/src/triangle.rs index cb7ab055..849a7272 100644 --- a/glow/src/triangle.rs +++ b/glow/src/triangle.rs @@ -1,74 +1,49 @@ //! Draw meshes of triangles. -mod gradient; -mod solid; - use crate::program; use crate::Transformation; +use iced_graphics::gradient::Gradient; use iced_graphics::layer::mesh::{self, Mesh}; -use iced_graphics::triangle::{self, Vertex2D}; +use iced_graphics::triangle::{ColoredVertex2D, Vertex2D}; use glow::HasContext; use std::marker::PhantomData; #[derive(Debug)] pub(crate) struct Pipeline { - vertex_array: ::VertexArray, - vertices: Buffer, indices: Buffer, - programs: ProgramList, -} - -#[derive(Debug)] -struct ProgramList { solid: solid::Program, gradient: gradient::Program, } impl Pipeline { pub fn new(gl: &glow::Context, shader_version: &program::Version) -> Self { - let vertex_array = - unsafe { gl.create_vertex_array().expect("Create vertex array") }; - - unsafe { - gl.bind_vertex_array(Some(vertex_array)); - } - - let vertices = unsafe { - Buffer::new( - gl, - glow::ARRAY_BUFFER, - glow::DYNAMIC_DRAW, - std::mem::size_of::() as usize, - ) - }; - - let indices = unsafe { + let mut indices = unsafe { Buffer::new( gl, glow::ELEMENT_ARRAY_BUFFER, glow::DYNAMIC_DRAW, - std::mem::size_of::() as usize, + 1000, ) }; + let solid = solid::Program::new(gl, shader_version); + let gradient = gradient::Program::new(gl, shader_version); + unsafe { - let stride = std::mem::size_of::() as i32; + gl.bind_vertex_array(Some(solid.vertex_array)); + indices.bind(gl, 0); - gl.enable_vertex_attrib_array(0); - gl.vertex_attrib_pointer_f32(0, 2, glow::FLOAT, false, stride, 0); + gl.bind_vertex_array(Some(gradient.vertex_array)); + indices.bind(gl, 0); gl.bind_vertex_array(None); - }; + } Self { - vertex_array, - vertices, indices, - programs: ProgramList { - solid: solid::Program::new(gl, shader_version), - gradient: gradient::Program::new(gl, shader_version), - }, + solid, + gradient, } } @@ -83,50 +58,83 @@ impl Pipeline { unsafe { gl.enable(glow::MULTISAMPLE); gl.enable(glow::SCISSOR_TEST); - gl.bind_vertex_array(Some(self.vertex_array)) } - //count the total amount of vertices & indices we need to handle - let (total_vertices, total_indices) = mesh::attribute_count_of(meshes); + // Count the total amount of vertices & indices we need to handle + let count = mesh::attribute_count_of(meshes); // Then we ensure the current attribute buffers are big enough, resizing if necessary unsafe { - self.vertices.bind(gl, total_vertices); - self.indices.bind(gl, total_indices); + self.indices.bind(gl, count.indices); } // We upload all the vertices and indices upfront - let mut vertex_offset = 0; + let mut solid_vertex_offset = 0; + let mut gradient_vertex_offset = 0; let mut index_offset = 0; for mesh in meshes { - unsafe { - gl.buffer_sub_data_u8_slice( - glow::ARRAY_BUFFER, - (vertex_offset * std::mem::size_of::()) as i32, - bytemuck::cast_slice(&mesh.buffers.vertices), - ); + let indices = mesh.indices(); + unsafe { gl.buffer_sub_data_u8_slice( glow::ELEMENT_ARRAY_BUFFER, (index_offset * std::mem::size_of::()) as i32, - bytemuck::cast_slice(&mesh.buffers.indices), + bytemuck::cast_slice(indices), ); - vertex_offset += mesh.buffers.vertices.len(); - index_offset += mesh.buffers.indices.len(); + index_offset += indices.len(); + } + + match mesh { + Mesh::Solid { buffers, .. } => { + unsafe { + self.solid.vertices.bind(gl, count.solid_vertices); + + gl.buffer_sub_data_u8_slice( + glow::ARRAY_BUFFER, + (solid_vertex_offset + * std::mem::size_of::()) + as i32, + bytemuck::cast_slice(&buffers.vertices), + ); + } + + solid_vertex_offset += buffers.vertices.len(); + } + Mesh::Gradient { buffers, .. } => { + unsafe { + self.gradient + .vertices + .bind(gl, count.gradient_vertices); + + gl.buffer_sub_data_u8_slice( + glow::ARRAY_BUFFER, + (gradient_vertex_offset + * std::mem::size_of::()) + as i32, + bytemuck::cast_slice(&buffers.vertices), + ); + } + + gradient_vertex_offset += buffers.vertices.len(); + } } } // Then we draw each mesh using offsets - let mut last_vertex = 0; + let mut last_solid_vertex = 0; + let mut last_gradient_vertex = 0; let mut last_index = 0; for mesh in meshes { - let transform = transformation - * Transformation::translate(mesh.origin.x, mesh.origin.y); + let indices = mesh.indices(); + let origin = mesh.origin(); - let clip_bounds = (mesh.clip_bounds * scale_factor).snap(); + let transform = + transformation * Transformation::translate(origin.x, origin.y); + + let clip_bounds = (mesh.clip_bounds() * scale_factor).snap(); unsafe { gl.scissor( @@ -136,30 +144,126 @@ impl Pipeline { clip_bounds.width as i32, clip_bounds.height as i32, ); + } + + match mesh { + Mesh::Solid { buffers, .. } => unsafe { + gl.use_program(Some(self.solid.program)); + gl.bind_vertex_array(Some(self.solid.vertex_array)); + + if transform != self.solid.uniforms.transform { + gl.uniform_matrix_4_f32_slice( + Some(&self.solid.uniforms.transform_location), + false, + transform.as_ref(), + ); - match mesh.style { - triangle::Style::Solid(color) => { - self.programs.solid.use_program(gl, color, &transform); + self.solid.uniforms.transform = transform; } - #[cfg(not(target_arch = "wasm32"))] - triangle::Style::Gradient(gradient) => { - self.programs - .gradient - .use_program(gl, gradient, &transform); + + gl.draw_elements_base_vertex( + glow::TRIANGLES, + indices.len() as i32, + glow::UNSIGNED_INT, + (last_index * std::mem::size_of::()) as i32, + last_solid_vertex as i32, + ); + + last_solid_vertex += buffers.vertices.len(); + }, + Mesh::Gradient { + buffers, gradient, .. + } => unsafe { + gl.use_program(Some(self.gradient.program)); + gl.bind_vertex_array(Some(self.gradient.vertex_array)); + + if transform != self.gradient.uniforms.transform { + gl.uniform_matrix_4_f32_slice( + Some(&self.gradient.uniforms.locations.transform), + false, + transform.as_ref(), + ); + + self.gradient.uniforms.transform = transform; } - } - gl.draw_elements_base_vertex( - glow::TRIANGLES, - mesh.buffers.indices.len() as i32, - glow::UNSIGNED_INT, - (last_index * std::mem::size_of::()) as i32, - last_vertex as i32, - ); + if &self.gradient.uniforms.gradient != *gradient { + match gradient { + Gradient::Linear(linear) => { + gl.uniform_4_f32( + Some( + &self + .gradient + .uniforms + .locations + .gradient_direction, + ), + linear.start.x, + linear.start.y, + linear.end.x, + linear.end.y, + ); + + gl.uniform_1_i32( + Some( + &self + .gradient + .uniforms + .locations + .color_stops_size, + ), + (linear.color_stops.len() * 2) as i32, + ); + + let mut stops = [0.0; 128]; + + for (index, stop) in linear + .color_stops + .iter() + .enumerate() + .take(16) + { + let [r, g, b, a] = stop.color.into_linear(); + + stops[index * 8] = r; + stops[(index * 8) + 1] = g; + stops[(index * 8) + 2] = b; + stops[(index * 8) + 3] = a; + stops[(index * 8) + 4] = stop.offset; + stops[(index * 8) + 5] = 0.; + stops[(index * 8) + 6] = 0.; + stops[(index * 8) + 7] = 0.; + } + + gl.uniform_4_f32_slice( + Some( + &self + .gradient + .uniforms + .locations + .color_stops, + ), + &stops, + ); + } + } + + self.gradient.uniforms.gradient = (*gradient).clone(); + } - last_vertex += mesh.buffers.vertices.len(); - last_index += mesh.buffers.indices.len(); + gl.draw_elements_base_vertex( + glow::TRIANGLES, + indices.len() as i32, + glow::UNSIGNED_INT, + (last_index * std::mem::size_of::()) as i32, + last_gradient_vertex as i32, + ); + + last_gradient_vertex += buffers.vertices.len(); + }, } + + last_index += indices.len(); } unsafe { @@ -170,47 +274,8 @@ impl Pipeline { } } -/// A simple shader program. Uses [`triangle.vert`] for its vertex shader and only binds position -/// attribute location. -pub(super) fn program( - gl: &glow::Context, - shader_version: &program::Version, - fragment_shader: &'static str, -) -> ::Program { - unsafe { - let vertex_shader = program::Shader::vertex( - gl, - shader_version, - include_str!("shader/common/triangle.vert"), - ); - - let fragment_shader = - program::Shader::fragment(gl, shader_version, fragment_shader); - - program::create( - gl, - &[vertex_shader, fragment_shader], - &[(0, "i_Position")], - ) - } -} - -pub fn set_transform( - gl: &glow::Context, - location: ::UniformLocation, - transform: Transformation, -) { - unsafe { - gl.uniform_matrix_4_f32_slice( - Some(&location), - false, - transform.as_ref(), - ); - } -} - #[derive(Debug)] -struct Buffer { +pub struct Buffer { raw: ::Buffer, target: u32, usage: u32, @@ -254,3 +319,268 @@ impl Buffer { } } } + +mod solid { + use crate::program; + use crate::triangle; + use glow::{Context, HasContext, NativeProgram}; + use iced_graphics::triangle::ColoredVertex2D; + use iced_graphics::Transformation; + + #[derive(Debug)] + pub struct Program { + pub program: ::Program, + pub vertex_array: ::VertexArray, + pub vertices: triangle::Buffer, + pub uniforms: Uniforms, + } + + impl Program { + pub fn new(gl: &Context, shader_version: &program::Version) -> Self { + let program = unsafe { + let vertex_shader = program::Shader::vertex( + gl, + shader_version, + include_str!("shader/common/solid.vert"), + ); + + let fragment_shader = program::Shader::fragment( + gl, + shader_version, + include_str!("shader/common/solid.frag"), + ); + + program::create( + gl, + &[vertex_shader, fragment_shader], + &[(0, "i_Position"), (1, "i_Color")], + ) + }; + + let vertex_array = unsafe { + gl.create_vertex_array().expect("Create vertex array") + }; + + let vertices = unsafe { + triangle::Buffer::new( + gl, + glow::ARRAY_BUFFER, + glow::DYNAMIC_DRAW, + 1000, + ) + }; + + unsafe { + gl.bind_vertex_array(Some(vertex_array)); + + let stride = std::mem::size_of::() as i32; + + gl.enable_vertex_attrib_array(0); + gl.vertex_attrib_pointer_f32( + 0, + 2, + glow::FLOAT, + false, + stride, + 0, + ); + + gl.enable_vertex_attrib_array(1); + gl.vertex_attrib_pointer_f32( + 1, + 4, + glow::FLOAT, + false, + stride, + 4 * 2, + ); + + gl.bind_vertex_array(None); + }; + + Self { + program, + vertex_array, + vertices, + uniforms: Uniforms::new(gl, program), + } + } + } + + #[derive(Debug)] + pub struct Uniforms { + pub transform: Transformation, + pub transform_location: ::UniformLocation, + } + + impl Uniforms { + fn new(gl: &Context, program: NativeProgram) -> Self { + let transform = Transformation::identity(); + let transform_location = + unsafe { gl.get_uniform_location(program, "u_Transform") } + .expect("Solid - Get u_Transform."); + + unsafe { + gl.use_program(Some(program)); + + gl.uniform_matrix_4_f32_slice( + Some(&transform_location), + false, + transform.as_ref(), + ); + + gl.use_program(None); + } + + Self { + transform, + transform_location, + } + } + } +} + +mod gradient { + use crate::program; + use crate::triangle; + use glow::{Context, HasContext, NativeProgram}; + use iced_graphics::gradient::{self, Gradient}; + use iced_graphics::triangle::Vertex2D; + use iced_graphics::Transformation; + + #[derive(Debug)] + pub struct Program { + pub program: ::Program, + pub vertex_array: ::VertexArray, + pub vertices: triangle::Buffer, + pub uniforms: Uniforms, + } + + impl Program { + pub fn new(gl: &Context, shader_version: &program::Version) -> Self { + let program = unsafe { + let vertex_shader = program::Shader::vertex( + gl, + shader_version, + include_str!("shader/common/gradient.vert"), + ); + + let fragment_shader = program::Shader::fragment( + gl, + shader_version, + include_str!("shader/common/gradient.frag"), + ); + + program::create( + gl, + &[vertex_shader, fragment_shader], + &[(0, "i_Position")], + ) + }; + + let vertex_array = unsafe { + gl.create_vertex_array().expect("Create vertex array") + }; + + let vertices = unsafe { + triangle::Buffer::new( + gl, + glow::ARRAY_BUFFER, + glow::DYNAMIC_DRAW, + 1000, + ) + }; + + unsafe { + gl.bind_vertex_array(Some(vertex_array)); + + let stride = std::mem::size_of::() as i32; + + gl.enable_vertex_attrib_array(0); + gl.vertex_attrib_pointer_f32( + 0, + 2, + glow::FLOAT, + false, + stride, + 0, + ); + + gl.bind_vertex_array(None); + }; + + Self { + program, + vertex_array, + vertices, + uniforms: Uniforms::new(gl, program), + } + } + } + + #[derive(Debug)] + pub struct Uniforms { + pub gradient: Gradient, + pub transform: Transformation, + pub locations: Locations, + } + + #[derive(Debug)] + pub struct Locations { + pub gradient_direction: ::UniformLocation, + pub color_stops_size: ::UniformLocation, + //currently the maximum number of stops is 16 due to lack of SSBO in GL2.1 + pub color_stops: ::UniformLocation, + pub transform: ::UniformLocation, + } + + impl Uniforms { + fn new(gl: &Context, program: NativeProgram) -> Self { + let gradient_direction = unsafe { + gl.get_uniform_location(program, "gradient_direction") + } + .expect("Gradient - Get gradient_direction."); + + let color_stops_size = + unsafe { gl.get_uniform_location(program, "color_stops_size") } + .expect("Gradient - Get color_stops_size."); + + let color_stops = unsafe { + gl.get_uniform_location(program, "color_stops") + .expect("Gradient - Get color_stops.") + }; + + let transform = Transformation::identity(); + let transform_location = + unsafe { gl.get_uniform_location(program, "u_Transform") } + .expect("Solid - Get u_Transform."); + + unsafe { + gl.use_program(Some(program)); + + gl.uniform_matrix_4_f32_slice( + Some(&transform_location), + false, + transform.as_ref(), + ); + + gl.use_program(None); + } + + Self { + gradient: Gradient::Linear(gradient::Linear { + start: Default::default(), + end: Default::default(), + color_stops: vec![], + }), + transform: Transformation::identity(), + locations: Locations { + gradient_direction, + color_stops_size, + color_stops, + transform: transform_location, + }, + } + } + } +} diff --git a/glow/src/triangle/gradient.rs b/glow/src/triangle/gradient.rs deleted file mode 100644 index d5f26877..00000000 --- a/glow/src/triangle/gradient.rs +++ /dev/null @@ -1,162 +0,0 @@ -use crate::program::Version; -use crate::triangle; -use glow::{Context, HasContext, NativeProgram}; -use iced_graphics::gradient::Gradient; -use iced_graphics::gradient::Linear; -use iced_graphics::Transformation; - -#[derive(Debug)] -pub struct Program { - pub program: ::Program, - pub uniform_data: UniformData, -} - -#[derive(Debug)] -pub struct UniformData { - gradient: Gradient, - transform: Transformation, - uniform_locations: UniformLocations, -} - -#[derive(Debug)] -struct UniformLocations { - gradient_direction_location: ::UniformLocation, - color_stops_size_location: ::UniformLocation, - //currently the maximum number of stops is 16 due to lack of SSBO in GL2.1 - color_stops_location: ::UniformLocation, - transform_location: ::UniformLocation, -} - -impl Program { - pub fn new(gl: &Context, shader_version: &Version) -> Self { - let program = triangle::program( - gl, - shader_version, - include_str!("../shader/common/gradient.frag"), - ); - - Self { - program, - uniform_data: UniformData::new(gl, program), - } - } - - pub fn write_uniforms( - &mut self, - gl: &Context, - gradient: &Gradient, - transform: &Transformation, - ) { - if transform != &self.uniform_data.transform { - triangle::set_transform( - gl, - self.uniform_data.uniform_locations.transform_location, - *transform, - ); - } - - if &self.uniform_data.gradient != gradient { - match gradient { - Gradient::Linear(linear) => unsafe { - gl.uniform_4_f32( - Some( - &self - .uniform_data - .uniform_locations - .gradient_direction_location, - ), - linear.start.x, - linear.start.y, - linear.end.x, - linear.end.y, - ); - - gl.uniform_1_i32( - Some( - &self - .uniform_data - .uniform_locations - .color_stops_size_location, - ), - (linear.color_stops.len() * 2) as i32, - ); - - let mut stops = [0.0; 128]; - - for (index, stop) in - linear.color_stops.iter().enumerate().take(16) - { - let [r, g, b, a] = stop.color.into_linear(); - - stops[index * 8] = r; - stops[(index * 8) + 1] = g; - stops[(index * 8) + 2] = b; - stops[(index * 8) + 3] = a; - stops[(index * 8) + 4] = stop.offset; - stops[(index * 8) + 5] = 0.; - stops[(index * 8) + 6] = 0.; - stops[(index * 8) + 7] = 0.; - } - - gl.uniform_4_f32_slice( - Some( - &self - .uniform_data - .uniform_locations - .color_stops_location, - ), - &stops, - ); - }, - } - - self.uniform_data.gradient = gradient.clone(); - } - } - - pub fn use_program( - &mut self, - gl: &Context, - gradient: &Gradient, - transform: &Transformation, - ) { - unsafe { gl.use_program(Some(self.program)) } - self.write_uniforms(gl, gradient, transform); - } -} - -impl UniformData { - fn new(gl: &Context, program: NativeProgram) -> Self { - let gradient_direction_location = - unsafe { gl.get_uniform_location(program, "gradient_direction") } - .expect("Gradient - Get gradient_direction."); - - let color_stops_size_location = - unsafe { gl.get_uniform_location(program, "color_stops_size") } - .expect("Gradient - Get color_stops_size."); - - let color_stops_location = unsafe { - gl.get_uniform_location(program, "color_stops") - .expect("Gradient - Get color_stops.") - }; - - let transform_location = - unsafe { gl.get_uniform_location(program, "u_Transform") } - .expect("Gradient - Get u_Transform."); - - Self { - gradient: Gradient::Linear(Linear { - start: Default::default(), - end: Default::default(), - color_stops: vec![], - }), - transform: Transformation::identity(), - uniform_locations: UniformLocations { - gradient_direction_location, - color_stops_size_location, - color_stops_location, - transform_location, - }, - } - } -} diff --git a/glow/src/triangle/solid.rs b/glow/src/triangle/solid.rs deleted file mode 100644 index fb3d40c3..00000000 --- a/glow/src/triangle/solid.rs +++ /dev/null @@ -1,91 +0,0 @@ -use crate::program::Version; -use crate::{triangle, Color}; -use glow::{Context, HasContext, NativeProgram}; -use iced_graphics::Transformation; - -#[derive(Debug)] -pub struct Program { - program: ::Program, - uniform_data: UniformData, -} - -#[derive(Debug)] -struct UniformData { - pub color: Color, - pub color_location: ::UniformLocation, - pub transform: Transformation, - pub transform_location: ::UniformLocation, -} - -impl UniformData { - fn new(gl: &Context, program: NativeProgram) -> Self { - Self { - color: Color::TRANSPARENT, - color_location: unsafe { - gl.get_uniform_location(program, "color") - } - .expect("Solid - Get color."), - transform: Transformation::identity(), - transform_location: unsafe { - gl.get_uniform_location(program, "u_Transform") - } - .expect("Solid - Get u_Transform."), - } - } -} - -impl Program { - pub fn new(gl: &Context, shader_version: &Version) -> Self { - let program = triangle::program( - gl, - shader_version, - include_str!("../shader/common/triangle.frag"), - ); - - Self { - program, - uniform_data: UniformData::new(gl, program), - } - } - - pub fn write_uniforms( - &mut self, - gl: &Context, - color: &Color, - transform: &Transformation, - ) { - if transform != &self.uniform_data.transform { - triangle::set_transform( - gl, - self.uniform_data.transform_location, - *transform, - ) - } - - if color != &self.uniform_data.color { - let [r, g, b, a] = color.into_linear(); - - unsafe { - gl.uniform_4_f32( - Some(&self.uniform_data.color_location), - r, - g, - b, - a, - ); - } - - self.uniform_data.color = *color; - } - } - - pub fn use_program( - &mut self, - gl: &Context, - color: &Color, - transform: &Transformation, - ) { - unsafe { gl.use_program(Some(self.program)) } - self.write_uniforms(gl, color, transform) - } -} -- cgit From c81eaf5f8d8db41e9bb96419bc39684a9978c232 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 16 Nov 2022 09:31:29 +0100 Subject: Replace magic constants in `glow::triangle` --- glow/src/triangle.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'glow/src') diff --git a/glow/src/triangle.rs b/glow/src/triangle.rs index 849a7272..d0205e08 100644 --- a/glow/src/triangle.rs +++ b/glow/src/triangle.rs @@ -9,6 +9,9 @@ use iced_graphics::triangle::{ColoredVertex2D, Vertex2D}; use glow::HasContext; use std::marker::PhantomData; +const DEFAULT_VERTICES: usize = 1_000; +const DEFAULT_INDICES: usize = 1_000; + #[derive(Debug)] pub(crate) struct Pipeline { indices: Buffer, @@ -23,7 +26,7 @@ impl Pipeline { gl, glow::ELEMENT_ARRAY_BUFFER, glow::DYNAMIC_DRAW, - 1000, + DEFAULT_INDICES, ) }; @@ -366,7 +369,7 @@ mod solid { gl, glow::ARRAY_BUFFER, glow::DYNAMIC_DRAW, - 1000, + super::DEFAULT_VERTICES, ) }; @@ -487,7 +490,7 @@ mod gradient { gl, glow::ARRAY_BUFFER, glow::DYNAMIC_DRAW, - 1000, + super::DEFAULT_VERTICES, ) }; -- cgit From 751ffb590053d713ea376893a1d9050514b8ffe1 Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Wed, 23 Nov 2022 13:37:59 -0500 Subject: fix: scissor layout bounds for images --- glow/src/backend.rs | 2 +- glow/src/image.rs | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) (limited to 'glow/src') diff --git a/glow/src/backend.rs b/glow/src/backend.rs index 1a41d540..c663869e 100644 --- a/glow/src/backend.rs +++ b/glow/src/backend.rs @@ -129,7 +129,7 @@ impl Backend { * Transformation::scale(scale_factor, scale_factor); self.image_pipeline - .draw(gl, scaled, scale_factor, &layer.images); + .draw(gl, scaled, scale_factor, &layer.images, bounds); } if !layer.text.is_empty() { diff --git a/glow/src/image.rs b/glow/src/image.rs index f906cd4c..234583e9 100644 --- a/glow/src/image.rs +++ b/glow/src/image.rs @@ -14,6 +14,7 @@ use iced_graphics::image::raster; use iced_graphics::image::vector; use iced_graphics::layer; +use iced_graphics::Rectangle; use iced_graphics::Size; use glow::HasContext; @@ -144,11 +145,13 @@ impl Pipeline { transformation: Transformation, _scale_factor: f32, images: &[layer::Image], + layer_bounds: Rectangle, ) { unsafe { gl.use_program(Some(self.program)); gl.bind_vertex_array(Some(self.vertex_array)); gl.bind_buffer(glow::ARRAY_BUFFER, Some(self.vertex_buffer)); + gl.enable(glow::SCISSOR_TEST); } #[cfg(feature = "image")] @@ -187,6 +190,13 @@ impl Pipeline { }; unsafe { + gl.scissor( + layer_bounds.x as i32, + layer_bounds.y as i32, + layer_bounds.width as i32, + layer_bounds.height as i32, + ); + if let Some(storage::Entry { texture, .. }) = entry { gl.bind_texture(glow::TEXTURE_2D, Some(*texture)) } else { @@ -213,6 +223,7 @@ impl Pipeline { gl.bind_buffer(glow::ARRAY_BUFFER, None); gl.bind_vertex_array(None); gl.use_program(None); + gl.disable(glow::SCISSOR_TEST); } } -- cgit From 84c5ee7fb2d716e1d3c35a53a2cd33fcc6fafc3a Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Wed, 23 Nov 2022 13:40:06 -0500 Subject: cargo fmt --- glow/src/backend.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'glow/src') diff --git a/glow/src/backend.rs b/glow/src/backend.rs index c663869e..645c5faf 100644 --- a/glow/src/backend.rs +++ b/glow/src/backend.rs @@ -128,8 +128,13 @@ impl Backend { let scaled = transformation * Transformation::scale(scale_factor, scale_factor); - self.image_pipeline - .draw(gl, scaled, scale_factor, &layer.images, bounds); + self.image_pipeline.draw( + gl, + scaled, + scale_factor, + &layer.images, + bounds, + ); } if !layer.text.is_empty() { -- cgit From efc00b2f412865b975088002cbe3c927ef662e10 Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Wed, 23 Nov 2022 14:46:57 -0500 Subject: fix: adjust y position of scissor rectangle --- glow/src/backend.rs | 1 + glow/src/image.rs | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'glow/src') diff --git a/glow/src/backend.rs b/glow/src/backend.rs index 645c5faf..416c3b94 100644 --- a/glow/src/backend.rs +++ b/glow/src/backend.rs @@ -130,6 +130,7 @@ impl Backend { self.image_pipeline.draw( gl, + target_height, scaled, scale_factor, &layer.images, diff --git a/glow/src/image.rs b/glow/src/image.rs index 234583e9..955fd1ab 100644 --- a/glow/src/image.rs +++ b/glow/src/image.rs @@ -142,6 +142,7 @@ impl Pipeline { pub fn draw( &mut self, mut gl: &glow::Context, + target_height: u32, transformation: Transformation, _scale_factor: f32, images: &[layer::Image], @@ -192,7 +193,8 @@ impl Pipeline { unsafe { gl.scissor( layer_bounds.x as i32, - layer_bounds.y as i32, + (target_height - (layer_bounds.y + layer_bounds.height)) + as i32, layer_bounds.width as i32, layer_bounds.height as i32, ); -- cgit