diff options
Diffstat (limited to '')
| -rw-r--r-- | glow/src/backend.rs | 7 | ||||
| -rw-r--r-- | glow/src/shader/common/gradient.frag | 48 | ||||
| -rw-r--r-- | glow/src/shader/common/triangle.frag | 4 | ||||
| -rw-r--r-- | glow/src/shader/common/triangle.vert | 6 | ||||
| -rw-r--r-- | glow/src/triangle.rs | 228 | ||||
| -rw-r--r-- | glow/src/triangle/gradient.rs | 189 | ||||
| -rw-r--r-- | glow/src/triangle/solid.rs | 67 | ||||
| -rw-r--r-- | glow/src/window/compositor.rs | 3 | 
8 files changed, 429 insertions, 123 deletions
diff --git a/glow/src/backend.rs b/glow/src/backend.rs index 78d4229e..6fc4fb38 100644 --- a/glow/src/backend.rs +++ b/glow/src/backend.rs @@ -1,7 +1,6 @@ -use crate::program; +use crate::{program, triangle};  use crate::quad;  use crate::text; -use crate::triangle;  use crate::{Settings, Transformation, Viewport};  use iced_graphics::backend; @@ -100,16 +99,16 @@ impl Backend {              );          } -        if !layer.meshes.is_empty() { +        if !layer.meshes.0.is_empty() {              let scaled = transformation                  * Transformation::scale(scale_factor, scale_factor);              self.triangle_pipeline.draw( +                &layer.meshes,                  gl,                  target_height,                  scaled,                  scale_factor, -                &layer.meshes,              );          } diff --git a/glow/src/shader/common/gradient.frag b/glow/src/shader/common/gradient.frag new file mode 100644 index 00000000..588f63e0 --- /dev/null +++ b/glow/src/shader/common/gradient.frag @@ -0,0 +1,48 @@ +// GLSL does not support dynamically sized arrays without SSBOs +#define MAX_STOPS 64 + +#ifdef GL_ES +#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 +#endif + +in vec2 raw_position; + +uniform vec2 gradient_start; +uniform vec2 gradient_end; + +uniform uint color_stops_size; +uniform float color_stop_offsets[MAX_STOPS]; +uniform vec4 color_stop_colors[MAX_STOPS]; + +void main() { +    vec2 gradient_vec = vec2(gradient_end - gradient_start); +    vec2 current_vec = vec2(raw_position.xy - gradient_start); +    vec2 unit = normalize(gradient_vec); +    float coord_offset = dot(unit, current_vec) / length(gradient_vec); + +    for (uint i = 0; i < color_stops_size - 1; i++) { +        float stop_offset = color_stop_offsets[i]; +        float next_stop_offset = color_stop_offsets[i + 1]; + +        if (stop_offset <= coord_offset && coord_offset <= next_stop_offset) { +            fragColor = mix(color_stop_colors[i], color_stop_colors[i+1], smoothstep( +                stop_offset, +                next_stop_offset, +                coord_offset +            )); +        } else if (coord_offset < color_stop_offsets[0]) { +            fragColor = color_stop_colors[0]; +        } else if (coord_offset > color_stop_offsets[color_stops_size - 1]) { +            fragColor = color_stop_colors[color_stops_size - 1]; +        } +    } +}
\ No newline at end of file diff --git a/glow/src/shader/common/triangle.frag b/glow/src/shader/common/triangle.frag index e8689f2e..0ee65239 100644 --- a/glow/src/shader/common/triangle.frag +++ b/glow/src/shader/common/triangle.frag @@ -11,8 +11,8 @@ out vec4 fragColor;  #define gl_FragColor fragColor  #endif -in vec4 v_Color; +uniform vec4 color;  void main() { -    gl_FragColor = v_Color; +    fragColor = color;  }
\ No newline at end of file diff --git a/glow/src/shader/common/triangle.vert b/glow/src/shader/common/triangle.vert index d0494a5f..09a4e324 100644 --- a/glow/src/shader/common/triangle.vert +++ b/glow/src/shader/common/triangle.vert @@ -1,11 +1,9 @@  uniform mat4 u_Transform;  in vec2 i_Position; -in vec4 i_Color; - -out vec4 v_Color; +out vec2 raw_position;  void main() {      gl_Position = u_Transform * vec4(i_Position, 0.0, 1.0); -    v_Color = i_Color; +    raw_position = i_Position;  }
\ No newline at end of file diff --git a/glow/src/triangle.rs b/glow/src/triangle.rs index ae4f83ef..7d0e14c7 100644 --- a/glow/src/triangle.rs +++ b/glow/src/triangle.rs @@ -1,66 +1,41 @@ -//! Draw meshes of triangles. +//! Draw meshes of triangle. +mod gradient; +mod solid; +  use crate::program::{self, Shader};  use crate::Transformation;  use glow::HasContext; -use iced_graphics::layer; +use iced_graphics::layer::{Mesh, Meshes}; +use iced_graphics::shader;  use std::marker::PhantomData; +use crate::triangle::gradient::GradientProgram; +use crate::triangle::solid::SolidProgram;  pub use iced_graphics::triangle::{Mesh2D, Vertex2D}; -const VERTEX_BUFFER_SIZE: usize = 10_000; -const INDEX_BUFFER_SIZE: usize = 10_000; -  #[derive(Debug)]  pub(crate) struct Pipeline { -    program: <glow::Context as HasContext>::Program,      vertex_array: <glow::Context as HasContext>::VertexArray,      vertices: Buffer<Vertex2D>,      indices: Buffer<u32>, -    transform_location: <glow::Context as HasContext>::UniformLocation,      current_transform: Transformation, +    programs: TrianglePrograms,  } -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/triangle.vert"), -            ); -            let fragment_shader = Shader::fragment( -                gl, -                shader_version, -                include_str!("shader/common/triangle.frag"), -            ); - -            program::create( -                gl, -                &[vertex_shader, fragment_shader], -                &[(0, "i_Position"), (1, "i_Color")], -            ) -        }; - -        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, -            ); +#[derive(Debug)] +struct TrianglePrograms { +    solid: TriangleProgram, +    gradient: TriangleProgram, +} -            gl.use_program(None); -        } +#[derive(Debug)] +enum TriangleProgram { +    Solid(SolidProgram), +    Gradient(GradientProgram), +} +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") }; @@ -73,7 +48,7 @@ impl Pipeline {                  gl,                  glow::ARRAY_BUFFER,                  glow::DYNAMIC_DRAW, -                VERTEX_BUFFER_SIZE, +                std::mem::size_of::<Vertex2D>() as usize,              )          }; @@ -82,7 +57,7 @@ impl Pipeline {                  gl,                  glow::ELEMENT_ARRAY_BUFFER,                  glow::DYNAMIC_DRAW, -                INDEX_BUFFER_SIZE, +                std::mem::size_of::<u32>() as usize,              )          }; @@ -92,58 +67,45 @@ impl Pipeline {              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); -        } +        }; -        Pipeline { -            program, +        Self {              vertex_array,              vertices,              indices, -            transform_location,              current_transform: Transformation::identity(), +            programs: TrianglePrograms { +                solid: TriangleProgram::Solid(SolidProgram::new( +                    gl, +                    shader_version, +                )), +                gradient: TriangleProgram::Gradient(GradientProgram::new( +                    gl, +                    shader_version, +                )), +            },          }      }      pub fn draw(          &mut self, +        meshes: &Meshes<'_>,          gl: &glow::Context,          target_height: u32,          transformation: Transformation,          scale_factor: f32, -        meshes: &[layer::Mesh<'_>],      ) {          unsafe {              gl.enable(glow::MULTISAMPLE);              gl.enable(glow::SCISSOR_TEST); -            gl.use_program(Some(self.program)); -            gl.bind_vertex_array(Some(self.vertex_array)); +            gl.bind_vertex_array(Some(self.vertex_array))          } -        // This looks a bit crazy, but we are just counting how many vertices -        // and indices we will need to handle. -        // TODO: Improve readability -        let (total_vertices, total_indices) = meshes -            .iter() -            .map(|layer::Mesh { buffers, .. }| { -                (buffers.vertices.len(), buffers.indices.len()) -            }) -            .fold((0, 0), |(total_v, total_i), (v, i)| { -                (total_v + v, total_i + i) -            }); - -        // Then we ensure the current buffers are big enough, resizing if -        // necessary +        //count the total number of vertices & indices we need to handle for all meshes +        let (total_vertices, total_indices) = meshes.attribute_count(); + +        // 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); @@ -153,7 +115,7 @@ impl Pipeline {          let mut last_vertex = 0;          let mut last_index = 0; -        for layer::Mesh { buffers, .. } in meshes { +        for Mesh { buffers, .. } in meshes.0.iter() {              unsafe {                  gl.buffer_sub_data_u8_slice(                      glow::ARRAY_BUFFER, @@ -176,11 +138,12 @@ impl Pipeline {          let mut last_vertex = 0;          let mut last_index = 0; -        for layer::Mesh { +        for Mesh {              buffers,              origin,              clip_bounds, -        } in meshes +            shader, +        } in meshes.0.iter()          {              let transform =                  transformation * Transformation::translate(origin.x, origin.y); @@ -188,17 +151,6 @@ impl Pipeline {              let clip_bounds = (*clip_bounds * scale_factor).snap();              unsafe { -                if self.current_transform != transform { -                    let matrix: [f32; 16] = transform.into(); -                    gl.uniform_matrix_4_f32_slice( -                        Some(&self.transform_location), -                        false, -                        &matrix, -                    ); - -                    self.current_transform = transform; -                } -                  gl.scissor(                      clip_bounds.x as i32,                      (target_height - (clip_bounds.y + clip_bounds.height)) @@ -207,6 +159,15 @@ impl Pipeline {                      clip_bounds.height as i32,                  ); +                let t = if self.current_transform != transform { +                    self.current_transform = transform; +                    Some(transform) +                } else { +                    None +                }; + +                self.use_with_shader(gl, shader, t); +                  gl.draw_elements_base_vertex(                      glow::TRIANGLES,                      buffers.indices.len() as i32, @@ -222,34 +183,79 @@ impl Pipeline {          unsafe {              gl.bind_vertex_array(None); -            gl.use_program(None);              gl.disable(glow::SCISSOR_TEST);              gl.disable(glow::MULTISAMPLE);          }      } -} -#[repr(C)] -#[derive(Debug, Clone, Copy)] -struct Uniforms { -    transform: [f32; 16], +    fn use_with_shader( +        &mut self, +        gl: &glow::Context, +        shader: &shader::Shader, +        transform: Option<Transformation>, +    ) { +        match shader { +            shader::Shader::Solid(color) => { +                if let TriangleProgram::Solid(solid_program) = +                    &mut self.programs.solid +                { +                    unsafe { gl.use_program(Some(solid_program.program)) } +                    solid_program.set_uniforms(gl, color, transform); +                } +            } +            shader::Shader::Gradient(gradient) => { +                if let TriangleProgram::Gradient(gradient_program) = +                    &mut self.programs.gradient +                { +                    unsafe { gl.use_program(Some(gradient_program.program)) } +                    gradient_program.set_uniforms(gl, gradient, transform); +                } +            } +        } +    }  } -unsafe impl bytemuck::Zeroable for Uniforms {} -unsafe impl bytemuck::Pod for Uniforms {} - -impl Default for Uniforms { -    fn default() -> Self { -        Self { -            transform: *Transformation::identity().as_ref(), -        } +/// A simple shader program. Uses [`triangle.vert`] for its vertex shader and only binds position +/// attribute location. +pub(super) fn simple_triangle_program( +    gl: &glow::Context, +    shader_version: &program::Version, +    fragment_shader: &'static str, +) -> <glow::Context as HasContext>::Program { +    unsafe { +        let vertex_shader = Shader::vertex( +            gl, +            shader_version, +            include_str!("shader/common/triangle.vert"), +        ); + +        let fragment_shader = +            Shader::fragment(gl, shader_version, fragment_shader); + +        program::create( +            gl, +            &[vertex_shader, fragment_shader], +            &[(0, "i_Position")], +        )      }  } -impl From<Transformation> for Uniforms { -    fn from(transformation: Transformation) -> Uniforms { -        Self { -            transform: transformation.into(), +pub(super) fn update_transform( +    gl: &glow::Context, +    program: <glow::Context as HasContext>::Program, +    transform: Option<Transformation> +) { +    if let Some(t) = transform { +        let transform_location = +            unsafe { gl.get_uniform_location(program, "u_Transform") } +                .expect("Get transform location."); + +        unsafe { +            gl.uniform_matrix_4_f32_slice( +                Some(&transform_location), +                false, +                t.as_ref(), +            );          }      }  } diff --git a/glow/src/triangle/gradient.rs b/glow/src/triangle/gradient.rs new file mode 100644 index 00000000..d1b10d77 --- /dev/null +++ b/glow/src/triangle/gradient.rs @@ -0,0 +1,189 @@ +use crate::program::Version; +use crate::triangle::{simple_triangle_program, update_transform}; +use glow::{Context, HasContext, NativeProgram}; +use iced_graphics::gradient::Gradient; +use iced_graphics::widget::canvas::gradient::Linear; +use iced_graphics::Transformation; + +#[derive(Debug)] +pub(super) struct GradientProgram { +    pub(super) program: <Context as HasContext>::Program, +    pub(super) uniform_data: GradientUniformData, +} + +impl GradientProgram { +    pub(super) fn new(gl: &Context, shader_version: &Version) -> Self { +        let program = simple_triangle_program( +            gl, +            shader_version, +            include_str!("../shader/common/gradient.frag"), +        ); + +        Self { +            program, +            uniform_data: GradientUniformData::new(gl, program), +        } +    } + +    pub(super) fn set_uniforms<'a>( +        &mut self, +        gl: &Context, +        gradient: &Gradient, +        transform: Option<Transformation>, +    ) { +        update_transform(gl, self.program, transform); + +        if &self.uniform_data.current_gradient != gradient { +            match gradient { +                Gradient::Linear(linear) => { +                    let gradient_start: [f32; 2] = (linear.start).into(); +                    let gradient_end: [f32; 2] = (linear.end).into(); + +                    unsafe { +                        gl.uniform_2_f32( +                            Some( +                                &self +                                    .uniform_data +                                    .uniform_locations +                                    .gradient_start_location, +                            ), +                            gradient_start[0], +                            gradient_start[1], +                        ); + +                        gl.uniform_2_f32( +                            Some( +                                &self +                                    .uniform_data +                                    .uniform_locations +                                    .gradient_end_location, +                            ), +                            gradient_end[0], +                            gradient_end[1], +                        ); + +                        gl.uniform_1_u32( +                            Some( +                                &self +                                    .uniform_data +                                    .uniform_locations +                                    .color_stops_size_location, +                            ), +                            linear.color_stops.len() as u32, +                        ); + +                        for (index, stop) in +                            linear.color_stops.iter().enumerate() +                        { +                            gl.uniform_1_f32( +                                Some( +                                    &self +                                        .uniform_data +                                        .uniform_locations +                                        .color_stops_locations[index] +                                        .offset, +                                ), +                                stop.offset, +                            ); + +                            gl.uniform_4_f32( +                                Some( +                                    &self +                                        .uniform_data +                                        .uniform_locations +                                        .color_stops_locations[index] +                                        .color, +                                ), +                                stop.color.r, +                                stop.color.g, +                                stop.color.b, +                                stop.color.a, +                            ); +                        } +                    } +                } +            } + +            self.uniform_data.current_gradient = gradient.clone(); +        } +    } +} + +#[derive(Debug)] +pub(super) struct GradientUniformData { +    current_gradient: Gradient, +    uniform_locations: GradientUniformLocations, +} + +#[derive(Debug)] +struct GradientUniformLocations { +    gradient_start_location: <Context as HasContext>::UniformLocation, +    gradient_end_location: <Context as HasContext>::UniformLocation, +    color_stops_size_location: <Context as HasContext>::UniformLocation, +    //currently the maximum number of stops is 64 due to needing to allocate the +    //memory for the array of stops with a const value in GLSL +    color_stops_locations: [ColorStopLocation; 64], +} + +#[derive(Copy, Debug, Clone)] +struct ColorStopLocation { +    color: <Context as HasContext>::UniformLocation, +    offset: <Context as HasContext>::UniformLocation, +} + +impl GradientUniformData { +    fn new(gl: &Context, program: NativeProgram) -> Self { +        let gradient_start_location = +            unsafe { gl.get_uniform_location(program, "gradient_start") } +                .expect("Gradient - Get gradient_start."); + +        let gradient_end_location = +            unsafe { gl.get_uniform_location(program, "gradient_end") } +                .expect("Gradient - Get gradient_end."); + +        let color_stops_size_location = +            unsafe { gl.get_uniform_location(program, "color_stops_size") } +                .expect("Gradient - Get color_stops_size."); + +        let color_stops_locations: [ColorStopLocation; 64] = +            core::array::from_fn(|index| { +                let offset = unsafe { +                    gl.get_uniform_location( +                        program, +                        &format!("color_stop_offsets[{}]", index), +                    ) +                } +                .expect(&format!( +                    "Gradient - Color stop offset with index {}", +                    index +                )); + +                let color = unsafe { +                    gl.get_uniform_location( +                        program, +                        &format!("color_stop_colors[{}]", index), +                    ) +                } +                .expect(&format!( +                    "Gradient - Color stop colors with index {}", +                    index +                )); + +                ColorStopLocation { color, offset } +            }); + +        GradientUniformData { +            current_gradient: Gradient::Linear(Linear { +                start: Default::default(), +                end: Default::default(), +                color_stops: vec![], +            }), +            uniform_locations: GradientUniformLocations { +                gradient_start_location, +                gradient_end_location, +                color_stops_size_location, +                color_stops_locations, +            }, +        } +    } +} diff --git a/glow/src/triangle/solid.rs b/glow/src/triangle/solid.rs new file mode 100644 index 00000000..3a33cea8 --- /dev/null +++ b/glow/src/triangle/solid.rs @@ -0,0 +1,67 @@ +use crate::program::Version; +use crate::triangle::{simple_triangle_program, update_transform}; +use crate::Color; +use glow::{Context, HasContext, NativeProgram}; +use iced_graphics::Transformation; + +#[derive(Debug)] +pub struct SolidProgram { +    pub(crate) program: <Context as HasContext>::Program, +    pub(crate) uniform_data: SolidUniformData, +} + +impl SolidProgram { +    pub fn new(gl: &Context, shader_version: &Version) -> Self { +        let program = simple_triangle_program( +            gl, +            shader_version, +            include_str!("../shader/common/triangle.frag"), +        ); + +        Self { +            program, +            uniform_data: SolidUniformData::new(gl, program), +        } +    } + +    pub fn set_uniforms<'a>( +        &mut self, +        gl: &Context, +        color: &Color, +        transform: Option<Transformation>, +    ) { +        update_transform(gl, self.program, transform); + +        if &self.uniform_data.color != color { +            unsafe { +                gl.uniform_4_f32( +                    Some(&self.uniform_data.color_location), +                    color.r, +                    color.g, +                    color.b, +                    color.a, +                ); +            } + +            self.uniform_data.color = *color; +        } +    } +} + +#[derive(Debug)] +pub(crate) struct SolidUniformData { +    pub color: Color, +    pub color_location: <Context as HasContext>::UniformLocation, +} + +impl SolidUniformData { +    fn new(gl: &Context, program: NativeProgram) -> Self { +        Self { +            color: Color::TRANSPARENT, +            color_location: unsafe { +                gl.get_uniform_location(program, "color") +            } +            .expect("Solid - Color uniform location."), +        } +    } +} diff --git a/glow/src/window/compositor.rs b/glow/src/window/compositor.rs index f6afaa68..e9cf6015 100644 --- a/glow/src/window/compositor.rs +++ b/glow/src/window/compositor.rs @@ -26,8 +26,7 @@ impl<Theme> iced_graphics::window::GLCompositor for Compositor<Theme> {          log::info!("{:#?}", settings);          let version = gl.version(); -        log::info!("Version: {:?}", version); -        log::info!("Embedded: {}", version.is_embedded); +        log::info!("OpenGL version: {:?} (Embedded: {}", version, version.is_embedded);          let renderer = gl.get_parameter_string(glow::RENDERER);          log::info!("Renderer: {}", renderer);  | 
