summaryrefslogtreecommitdiffstats
path: root/glow/src/image.rs
diff options
context:
space:
mode:
authorLibravatar Ian Douglas Scott <idscott@system76.com>2022-10-24 17:06:02 -0700
committerLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2022-11-05 03:19:38 +0100
commit5575e6ea0897e406674e7e4239808fbf9daa07c3 (patch)
tree888f1b22926a304e7e280710312727fc4137e373 /glow/src/image.rs
parent2c7c42ee93a61f39562590f6a75eb2dd8b220fb8 (diff)
downloadiced-5575e6ea0897e406674e7e4239808fbf9daa07c3.tar.gz
iced-5575e6ea0897e406674e7e4239808fbf9daa07c3.tar.bz2
iced-5575e6ea0897e406674e7e4239808fbf9daa07c3.zip
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.
Diffstat (limited to 'glow/src/image.rs')
-rw-r--r--glow/src/image.rs212
1 files changed, 212 insertions, 0 deletions
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: <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,
+ textures: Textures,
+ #[cfg(feature = "image_rs")]
+ raster_cache: RefCell<raster::Cache<Textures>>,
+ #[cfg(feature = "svg")]
+ vector_cache: vector::Cache<Textures>,
+}
+
+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);
+ }
+}