diff options
author | 2022-11-03 18:57:09 +0100 | |
---|---|---|
committer | 2022-11-03 18:57:09 +0100 | |
commit | d222b5c8b0befab665c20ba0112b28199df0ae44 (patch) | |
tree | 0ac3a59f04e1c1ca89ff43800efbefd825b015ea /glow/src/triangle | |
parent | a8f510c39917b2ac42fcc854f0a7eff13aee9838 (diff) | |
parent | f31c8f2504ea7c004c5caed8913e5da28d2e50e2 (diff) | |
download | iced-d222b5c8b0befab665c20ba0112b28199df0ae44.tar.gz iced-d222b5c8b0befab665c20ba0112b28199df0ae44.tar.bz2 iced-d222b5c8b0befab665c20ba0112b28199df0ae44.zip |
Merge pull request #1448 from bungoboingo/fear/linear-gradients
Add linear gradient support to canvas widget
Diffstat (limited to 'glow/src/triangle')
-rw-r--r-- | glow/src/triangle/gradient.rs | 162 | ||||
-rw-r--r-- | glow/src/triangle/solid.rs | 91 |
2 files changed, 253 insertions, 0 deletions
diff --git a/glow/src/triangle/gradient.rs b/glow/src/triangle/gradient.rs new file mode 100644 index 00000000..5225612e --- /dev/null +++ b/glow/src/triangle/gradient.rs @@ -0,0 +1,162 @@ +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: <Context as HasContext>::Program, + pub uniform_data: UniformData, +} + +#[derive(Debug)] +pub struct UniformData { + gradient: Gradient, + transform: Transformation, + uniform_locations: UniformLocations, +} + +#[derive(Debug)] +struct UniformLocations { + gradient_direction_location: <Context as HasContext>::UniformLocation, + color_stops_size_location: <Context as HasContext>::UniformLocation, + //currently the maximum number of stops is 16 due to lack of SSBO in GL2.1 + color_stops_location: <Context as HasContext>::UniformLocation, + transform_location: <Context as HasContext>::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_u32( + Some( + &self + .uniform_data + .uniform_locations + .color_stops_size_location, + ), + (linear.color_stops.len() * 2) as u32, + ); + + 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 new file mode 100644 index 00000000..fb3d40c3 --- /dev/null +++ b/glow/src/triangle/solid.rs @@ -0,0 +1,91 @@ +use crate::program::Version; +use crate::{triangle, Color}; +use glow::{Context, HasContext, NativeProgram}; +use iced_graphics::Transformation; + +#[derive(Debug)] +pub struct Program { + program: <Context as HasContext>::Program, + uniform_data: UniformData, +} + +#[derive(Debug)] +struct UniformData { + pub color: Color, + pub color_location: <Context as HasContext>::UniformLocation, + pub transform: Transformation, + pub transform_location: <Context as HasContext>::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) + } +} |