summaryrefslogtreecommitdiffstats
path: root/glow
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2022-12-02 18:53:21 +0100
committerLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2022-12-02 18:53:21 +0100
commit4029a1cdaaac1abbdcc141b20469a49670cd99b6 (patch)
tree71fa9d9c4aa1f02ce05771db43a4bb7bc6570e77 /glow
parent676d8efe03ebdbeeb95aef96b8097395b788b1ab (diff)
parent8b55e9b9e6ba0b83038dd491dd34d95b4f9a381b (diff)
downloadiced-4029a1cdaaac1abbdcc141b20469a49670cd99b6.tar.gz
iced-4029a1cdaaac1abbdcc141b20469a49670cd99b6.tar.bz2
iced-4029a1cdaaac1abbdcc141b20469a49670cd99b6.zip
Merge branch 'master' into non-uniform-border-radius-for-quads
Diffstat (limited to 'glow')
-rw-r--r--glow/Cargo.toml22
-rw-r--r--glow/src/backend.rs36
-rw-r--r--glow/src/image.rs243
-rw-r--r--glow/src/image/storage.rs78
-rw-r--r--glow/src/lib.rs4
-rw-r--r--glow/src/shader/common/gradient.frag32
-rw-r--r--glow/src/shader/common/gradient.vert (renamed from glow/src/shader/common/triangle.vert)0
-rw-r--r--glow/src/shader/common/image.frag22
-rw-r--r--glow/src/shader/common/image.vert9
-rw-r--r--glow/src/shader/common/solid.frag (renamed from glow/src/shader/common/triangle.frag)4
-rw-r--r--glow/src/shader/common/solid.vert11
-rw-r--r--glow/src/triangle.rs564
-rw-r--r--glow/src/triangle/gradient.rs162
-rw-r--r--glow/src/triangle/solid.rs91
14 files changed, 880 insertions, 398 deletions
diff --git a/glow/Cargo.toml b/glow/Cargo.toml
index 18215e9b..1977f4b6 100644
--- a/glow/Cargo.toml
+++ b/glow/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "iced_glow"
-version = "0.3.0"
+version = "0.4.1"
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
edition = "2021"
description = "A glow renderer for iced"
@@ -8,12 +8,22 @@ license = "MIT AND OFL-1.1"
repository = "https://github.com/iced-rs/iced"
[features]
+svg = ["iced_graphics/svg"]
+image = ["iced_graphics/image"]
+png = ["iced_graphics/png"]
+jpeg = ["iced_graphics/jpeg"]
+jpeg_rayon = ["iced_graphics/jpeg_rayon"]
+gif = ["iced_graphics/gif"]
+webp = ["iced_graphics/webp"]
+pnm = ["iced_graphics/pnm"]
+ico = ["iced_graphics/ico"]
+bmp = ["iced_graphics/bmp"]
+hdr = ["iced_graphics/hdr"]
+dds = ["iced_graphics/dds"]
+farbfeld = ["iced_graphics/farbfeld"]
canvas = ["iced_graphics/canvas"]
qr_code = ["iced_graphics/qr_code"]
default_system_font = ["iced_graphics/font-source"]
-# Not supported yet!
-image = []
-svg = []
[dependencies]
glow = "0.11.1"
@@ -24,11 +34,11 @@ bytemuck = "1.4"
log = "0.4"
[dependencies.iced_native]
-version = "0.5"
+version = "0.6"
path = "../native"
[dependencies.iced_graphics]
-version = "0.3"
+version = "0.4"
path = "../graphics"
features = ["font-fallback", "font-icons", "opengl"]
diff --git a/glow/src/backend.rs b/glow/src/backend.rs
index 21af2ecf..416c3b94 100644
--- a/glow/src/backend.rs
+++ b/glow/src/backend.rs
@@ -1,3 +1,5 @@
+#[cfg(any(feature = "image", 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", 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", 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", feature = "svg"))]
+ image_pipeline,
quad_pipeline,
text_pipeline,
triangle_pipeline,
@@ -70,6 +78,9 @@ impl Backend {
viewport_size.height,
);
}
+
+ #[cfg(any(feature = "image", feature = "svg"))]
+ self.image_pipeline.trim_cache(gl);
}
fn flush(
@@ -112,6 +123,21 @@ impl Backend {
);
}
+ #[cfg(any(feature = "image", feature = "svg"))]
+ if !layer.images.is_empty() {
+ let scaled = transformation
+ * Transformation::scale(scale_factor, scale_factor);
+
+ self.image_pipeline.draw(
+ gl,
+ target_height,
+ scaled,
+ scale_factor,
+ &layer.images,
+ bounds,
+ );
+ }
+
if !layer.text.is_empty() {
for text in layer.text.iter() {
// Target physical coordinates directly to avoid blurry text
@@ -238,8 +264,8 @@ impl backend::Text for Backend {
#[cfg(feature = "image")]
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) -> Size<u32> {
+ self.image_pipeline.dimensions(handle)
}
}
@@ -247,8 +273,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<u32> {
+ self.image_pipeline.viewport_dimensions(handle)
}
}
diff --git a/glow/src/image.rs b/glow/src/image.rs
new file mode 100644
index 00000000..955fd1ab
--- /dev/null
+++ b/glow/src/image.rs
@@ -0,0 +1,243 @@
+mod storage;
+
+use storage::Storage;
+
+pub use iced_graphics::triangle::{Mesh2D, Vertex2D};
+
+use crate::program::{self, Shader};
+use crate::Transformation;
+
+#[cfg(feature = "image")]
+use iced_graphics::image::raster;
+
+#[cfg(feature = "svg")]
+use iced_graphics::image::vector;
+
+use iced_graphics::layer;
+use iced_graphics::Rectangle;
+use iced_graphics::Size;
+
+use glow::HasContext;
+
+use std::cell::RefCell;
+
+#[derive(Debug)]
+pub(crate) struct Pipeline {
+ program: <glow::Context as HasContext>::Program,
+ vertex_array: <glow::Context as HasContext>::VertexArray,
+ vertex_buffer: <glow::Context as HasContext>::Buffer,
+ transform_location: <glow::Context as HasContext>::UniformLocation,
+ storage: Storage,
+ #[cfg(feature = "image")]
+ raster_cache: RefCell<raster::Cache<Storage>>,
+ #[cfg(feature = "svg")]
+ vector_cache: RefCell<vector::Cache<Storage>>,
+}
+
+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,
+ storage: Storage::default(),
+ #[cfg(feature = "image")]
+ raster_cache: RefCell::new(raster::Cache::default()),
+ #[cfg(feature = "svg")]
+ vector_cache: RefCell::new(vector::Cache::default()),
+ }
+ }
+
+ #[cfg(feature = "image")]
+ pub fn dimensions(&self, handle: &iced_native::image::Handle) -> Size<u32> {
+ self.raster_cache.borrow_mut().load(handle).dimensions()
+ }
+
+ #[cfg(feature = "svg")]
+ pub fn viewport_dimensions(
+ &self,
+ handle: &iced_native::svg::Handle,
+ ) -> Size<u32> {
+ 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,
+ target_height: u32,
+ transformation: Transformation,
+ _scale_factor: f32,
+ images: &[layer::Image],
+ layer_bounds: Rectangle<u32>,
+ ) {
+ 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")]
+ 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")]
+ layer::Image::Raster { handle, bounds } => (
+ raster_cache.upload(handle, &mut gl, &mut self.storage),
+ bounds,
+ ),
+ #[cfg(not(feature = "image"))]
+ layer::Image::Raster { handle: _, bounds } => (None, bounds),
+
+ #[cfg(feature = "svg")]
+ layer::Image::Vector { handle, bounds } => {
+ let size = [bounds.width, bounds.height];
+ (
+ vector_cache.upload(
+ handle,
+ size,
+ _scale_factor,
+ &mut gl,
+ &mut self.storage,
+ ),
+ bounds,
+ )
+ }
+
+ #[cfg(not(feature = "svg"))]
+ layer::Image::Vector { handle: _, bounds } => (None, bounds),
+ };
+
+ unsafe {
+ gl.scissor(
+ layer_bounds.x as i32,
+ (target_height - (layer_bounds.y + layer_bounds.height))
+ 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 {
+ 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);
+ gl.disable(glow::SCISSOR_TEST);
+ }
+ }
+
+ pub fn trim_cache(&mut self, mut gl: &glow::Context) {
+ #[cfg(feature = "image")]
+ self.raster_cache
+ .borrow_mut()
+ .trim(&mut self.storage, &mut gl);
+
+ #[cfg(feature = "svg")]
+ 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..9bc20641
--- /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<Self::Entry> {
+ 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::RGBA,
+ 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<u32>,
+ pub(super) texture: glow::NativeTexture,
+}
+
+impl image::storage::Entry for Entry {
+ fn size(&self) -> Size<u32> {
+ self.size
+ }
+}
diff --git a/glow/src/lib.rs b/glow/src/lib.rs
index de9c0002..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"
)]
@@ -24,6 +24,8 @@
pub use glow;
mod backend;
+#[cfg(any(feature = "image", feature = "svg"))]
+mod image;
mod program;
mod quad;
mod text;
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.vert b/glow/src/shader/common/gradient.vert
index fe505997..fe505997 100644
--- a/glow/src/shader/common/triangle.vert
+++ b/glow/src/shader/common/gradient.vert
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;
+}
diff --git a/glow/src/shader/common/triangle.frag b/glow/src/shader/common/solid.frag
index ead40fe5..174ffdd3 100644
--- a/glow/src/shader/common/triangle.frag
+++ b/glow/src/shader/common/solid.frag
@@ -11,8 +11,8 @@ out vec4 fragColor;
#define gl_FragColor fragColor
#endif
-uniform vec4 color;
+in vec4 v_Color;
void main() {
- fragColor = color;
+ 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/triangle.rs b/glow/src/triangle.rs
index 0e27bcf2..d0205e08 100644
--- a/glow/src/triangle.rs
+++ b/glow/src/triangle.rs
@@ -1,74 +1,52 @@
//! 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;
+const DEFAULT_VERTICES: usize = 1_000;
+const DEFAULT_INDICES: usize = 1_000;
+
#[derive(Debug)]
pub(crate) struct Pipeline {
- vertex_array: <glow::Context as HasContext>::VertexArray,
- vertices: Buffer<Vertex2D>,
indices: Buffer<u32>,
- 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::<Vertex2D>() as usize,
- )
- };
-
- let indices = unsafe {
+ let mut indices = unsafe {
Buffer::new(
gl,
glow::ELEMENT_ARRAY_BUFFER,
glow::DYNAMIC_DRAW,
- std::mem::size_of::<u32>() as usize,
+ DEFAULT_INDICES,
)
};
+ let solid = solid::Program::new(gl, shader_version);
+ let gradient = gradient::Program::new(gl, shader_version);
+
unsafe {
- let stride = std::mem::size_of::<Vertex2D>() 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 +61,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::<Vertex2D>()) 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::<u32>()) 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::<ColoredVertex2D>())
+ 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::<Vertex2D>())
+ 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 transform =
+ transformation * Transformation::translate(origin.x, origin.y);
- let clip_bounds = (mesh.clip_bounds * scale_factor).snap();
+ let clip_bounds = (mesh.clip_bounds() * scale_factor).snap();
unsafe {
gl.scissor(
@@ -136,29 +147,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));
- match mesh.style {
- triangle::Style::Solid(color) => {
- self.programs.solid.use_program(gl, color, &transform);
+ if transform != self.solid.uniforms.transform {
+ gl.uniform_matrix_4_f32_slice(
+ Some(&self.solid.uniforms.transform_location),
+ false,
+ transform.as_ref(),
+ );
+
+ self.solid.uniforms.transform = transform;
}
- 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::<u32>()) 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::<u32>()) 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();
+ }
+
+ gl.draw_elements_base_vertex(
+ glow::TRIANGLES,
+ indices.len() as i32,
+ glow::UNSIGNED_INT,
+ (last_index * std::mem::size_of::<u32>()) as i32,
+ last_gradient_vertex as i32,
+ );
- last_vertex += mesh.buffers.vertices.len();
- last_index += mesh.buffers.indices.len();
+ last_gradient_vertex += buffers.vertices.len();
+ },
}
+
+ last_index += indices.len();
}
unsafe {
@@ -169,47 +277,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,
-) -> <glow::Context as HasContext>::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: <glow::Context as HasContext>::UniformLocation,
- transform: Transformation,
-) {
- unsafe {
- gl.uniform_matrix_4_f32_slice(
- Some(&location),
- false,
- transform.as_ref(),
- );
- }
-}
-
#[derive(Debug)]
-struct Buffer<T> {
+pub struct Buffer<T> {
raw: <glow::Context as HasContext>::Buffer,
target: u32,
usage: u32,
@@ -253,3 +322,268 @@ impl<T> Buffer<T> {
}
}
}
+
+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: <Context as HasContext>::Program,
+ pub vertex_array: <glow::Context as HasContext>::VertexArray,
+ pub vertices: triangle::Buffer<ColoredVertex2D>,
+ 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,
+ super::DEFAULT_VERTICES,
+ )
+ };
+
+ unsafe {
+ gl.bind_vertex_array(Some(vertex_array));
+
+ let stride = std::mem::size_of::<ColoredVertex2D>() 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: <Context as HasContext>::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: <Context as HasContext>::Program,
+ pub vertex_array: <glow::Context as HasContext>::VertexArray,
+ pub vertices: triangle::Buffer<Vertex2D>,
+ 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,
+ super::DEFAULT_VERTICES,
+ )
+ };
+
+ unsafe {
+ gl.bind_vertex_array(Some(vertex_array));
+
+ let stride = std::mem::size_of::<Vertex2D>() 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: <Context as HasContext>::UniformLocation,
+ pub color_stops_size: <Context as HasContext>::UniformLocation,
+ //currently the maximum number of stops is 16 due to lack of SSBO in GL2.1
+ pub color_stops: <Context as HasContext>::UniformLocation,
+ pub transform: <Context as HasContext>::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 5225612e..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: <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
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: <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)
- }
-}