diff options
author | 2023-01-06 23:29:38 +0100 | |
---|---|---|
committer | 2023-02-24 13:17:58 +0100 | |
commit | b9a9576207ddfc7afd89da30b7cfc7ca0d7e335c (patch) | |
tree | c0b4489f1e547fc335e6b82025891cefdc671274 /glow | |
parent | 573d27eb52bbfacf1b06983b4282f00eb5265bdc (diff) | |
download | iced-b9a9576207ddfc7afd89da30b7cfc7ca0d7e335c.tar.gz iced-b9a9576207ddfc7afd89da30b7cfc7ca0d7e335c.tar.bz2 iced-b9a9576207ddfc7afd89da30b7cfc7ca0d7e335c.zip |
Remove `iced_glow`, `glyph-brush`, and `wgpu_glyph` dependencies
Diffstat (limited to 'glow')
-rw-r--r-- | glow/Cargo.toml | 51 | ||||
-rw-r--r-- | glow/README.md | 51 | ||||
-rw-r--r-- | glow/src/backend.rs | 280 | ||||
-rw-r--r-- | glow/src/image.rs | 254 | ||||
-rw-r--r-- | glow/src/image/storage.rs | 78 | ||||
-rw-r--r-- | glow/src/lib.rs | 53 | ||||
-rw-r--r-- | glow/src/program.rs | 133 | ||||
-rw-r--r-- | glow/src/quad.rs | 74 | ||||
-rw-r--r-- | glow/src/quad/compatibility.rs | 349 | ||||
-rw-r--r-- | glow/src/quad/core.rs | 244 | ||||
-rw-r--r-- | glow/src/settings.rs | 61 | ||||
-rw-r--r-- | glow/src/shader/common/gradient.frag | 59 | ||||
-rw-r--r-- | glow/src/shader/common/gradient.vert | 9 | ||||
-rw-r--r-- | glow/src/shader/common/image.frag | 22 | ||||
-rw-r--r-- | glow/src/shader/common/image.vert | 9 | ||||
-rw-r--r-- | glow/src/shader/common/solid.frag | 18 | ||||
-rw-r--r-- | glow/src/shader/common/solid.vert | 11 | ||||
-rw-r--r-- | glow/src/shader/compatibility/quad.frag | 83 | ||||
-rw-r--r-- | glow/src/shader/compatibility/quad.vert | 46 | ||||
-rw-r--r-- | glow/src/shader/core/quad.frag | 95 | ||||
-rw-r--r-- | glow/src/shader/core/quad.vert | 52 | ||||
-rw-r--r-- | glow/src/text.rs | 257 | ||||
-rw-r--r-- | glow/src/triangle.rs | 595 | ||||
-rw-r--r-- | glow/src/window.rs | 4 | ||||
-rw-r--r-- | glow/src/window/compositor.rs | 111 |
25 files changed, 0 insertions, 2999 deletions
diff --git a/glow/Cargo.toml b/glow/Cargo.toml deleted file mode 100644 index 1a848ab7..00000000 --- a/glow/Cargo.toml +++ /dev/null @@ -1,51 +0,0 @@ -[package] -name = "iced_glow" -version = "0.7.0" -authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"] -edition = "2021" -description = "A glow renderer for iced" -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"] - -[dependencies] -glow = "0.11.1" -glow_glyph = "0.5.0" -glyph_brush = "0.7" -euclid = "0.22" -bytemuck = "1.4" -log = "0.4" - -[dependencies.iced_native] -version = "0.9" -path = "../native" - -[dependencies.iced_graphics] -version = "0.7" -path = "../graphics" -features = ["font-fallback", "font-icons", "opengl"] - -[dependencies.tracing] -version = "0.1.6" -optional = true - -[package.metadata.docs.rs] -rustdoc-args = ["--cfg", "docsrs"] -all-features = true diff --git a/glow/README.md b/glow/README.md deleted file mode 100644 index 95c9d62a..00000000 --- a/glow/README.md +++ /dev/null @@ -1,51 +0,0 @@ -# `iced_glow` -[][documentation] -[](https://crates.io/crates/iced_glow) -[](https://github.com/iced-rs/iced/blob/master/LICENSE) -[](https://discord.gg/3xZJ65GAhd) - -`iced_glow` is a [`glow`] renderer for [`iced_native`]. This renderer supports OpenGL 3.0+ and OpenGL ES 2.0. - -This renderer is mostly used as a fallback for hardware that doesn't support [`wgpu`] (Vulkan, Metal or DX12). - -Currently, `iced_glow` supports the following primitives: -- Text, which is rendered using [`glow_glyph`]. No shaping at all. -- Quads or rectangles, with rounded borders and a solid background color. -- Clip areas, useful to implement scrollables or hide overflowing content. -- Meshes of triangles, useful to draw geometry freely. - -<p align="center"> - <img alt="The native target" src="../docs/graphs/native.png" width="80%"> -</p> - -[documentation]: https://docs.rs/iced_glow -[`iced_native`]: ../native -[`glow`]: https://github.com/grovesNL/glow -[`wgpu`]: https://github.com/gfx-rs/wgpu -[`glow_glyph`]: https://github.com/hecrj/glow_glyph - -## Installation -Add `iced_glow` as a dependency in your `Cargo.toml`: - -```toml -iced_glow = "0.7" -``` - -__Iced moves fast and the `master` branch can contain breaking changes!__ If -you want to learn about a specific release, check out [the release list]. - -[the release list]: https://github.com/iced-rs/iced/releases - -## Current limitations - -The current implementation is quite naive, it uses: - -- A different pipeline/shader for each primitive -- A very simplistic layer model: every `Clip` primitive will generate new layers -- _Many_ render passes instead of preparing everything upfront -- A glyph cache that is trimmed incorrectly when there are multiple layers (a [`glyph_brush`] limitation) - -Some of these issues are already being worked on! If you want to help, [get in touch!] - -[get in touch!]: ../CONTRIBUTING.md -[`glyph_brush`]: https://github.com/alexheretic/glyph-brush diff --git a/glow/src/backend.rs b/glow/src/backend.rs deleted file mode 100644 index 36a34eda..00000000 --- a/glow/src/backend.rs +++ /dev/null @@ -1,280 +0,0 @@ -#[cfg(any(feature = "image", feature = "svg"))] -use crate::image; -use crate::quad; -use crate::text; -use crate::{program, triangle}; -use crate::{Settings, Transformation, Viewport}; - -use iced_graphics::backend; -use iced_graphics::font; -use iced_graphics::{Layer, Primitive}; -use iced_native::alignment; -use iced_native::{Font, Size}; - -/// A [`glow`] graphics backend for [`iced`]. -/// -/// [`glow`]: https://github.com/grovesNL/glow -/// [`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, - default_text_size: f32, -} - -impl Backend { - /// Creates a new [`Backend`]. - pub fn new(gl: &glow::Context, settings: Settings) -> Self { - let text_pipeline = text::Pipeline::new( - gl, - settings.default_font, - settings.text_multithreading, - ); - - 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, - default_text_size: settings.default_text_size, - } - } - - /// Draws the provided primitives in the default framebuffer. - /// - /// The text provided as overlay will be rendered on top of the primitives. - /// This is useful for rendering debug information. - pub fn present<T: AsRef<str>>( - &mut self, - gl: &glow::Context, - primitives: &[Primitive], - viewport: &Viewport, - overlay_text: &[T], - ) { - let viewport_size = viewport.physical_size(); - let scale_factor = viewport.scale_factor() as f32; - let projection = viewport.projection(); - - let mut layers = Layer::generate(primitives, viewport); - layers.push(Layer::overlay(overlay_text, viewport)); - - for layer in layers { - self.flush( - gl, - scale_factor, - projection, - &layer, - viewport_size.height, - ); - } - - #[cfg(any(feature = "image", feature = "svg"))] - self.image_pipeline.trim_cache(gl); - } - - fn flush( - &mut self, - gl: &glow::Context, - scale_factor: f32, - transformation: Transformation, - layer: &Layer<'_>, - target_height: u32, - ) { - let mut bounds = (layer.bounds * scale_factor).snap(); - - if bounds.width < 1 || bounds.height < 1 { - return; - } - - bounds.height = bounds.height.min(target_height); - - if !layer.quads.is_empty() { - self.quad_pipeline.draw( - gl, - target_height, - &layer.quads, - transformation, - scale_factor, - bounds, - ); - } - - if !layer.meshes.is_empty() { - let scaled = transformation - * Transformation::scale(scale_factor, scale_factor); - - self.triangle_pipeline.draw( - &layer.meshes, - gl, - target_height, - scaled, - scale_factor, - ); - } - - #[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 - let text = glow_glyph::Section { - // TODO: We `round` here to avoid rerasterizing text when - // its position changes slightly. This can make text feel a - // bit "jumpy". We may be able to do better once we improve - // our text rendering/caching pipeline. - screen_position: ( - (text.bounds.x * scale_factor).round(), - (text.bounds.y * scale_factor).round(), - ), - // TODO: Fix precision issues with some scale factors. - // - // The `ceil` here can cause some words to render on the - // same line when they should not. - // - // Ideally, `wgpu_glyph` should be able to compute layout - // using logical positions, and then apply the proper - // scaling when rendering. This would ensure that both - // measuring and rendering follow the same layout rules. - bounds: ( - (text.bounds.width * scale_factor).ceil(), - (text.bounds.height * scale_factor).ceil(), - ), - text: vec![glow_glyph::Text { - text: text.content, - scale: glow_glyph::ab_glyph::PxScale { - x: text.size * scale_factor, - y: text.size * scale_factor, - }, - font_id: self.text_pipeline.find_font(text.font), - extra: glow_glyph::Extra { - color: text.color, - z: 0.0, - }, - }], - layout: glow_glyph::Layout::default() - .h_align(match text.horizontal_alignment { - alignment::Horizontal::Left => { - glow_glyph::HorizontalAlign::Left - } - alignment::Horizontal::Center => { - glow_glyph::HorizontalAlign::Center - } - alignment::Horizontal::Right => { - glow_glyph::HorizontalAlign::Right - } - }) - .v_align(match text.vertical_alignment { - alignment::Vertical::Top => { - glow_glyph::VerticalAlign::Top - } - alignment::Vertical::Center => { - glow_glyph::VerticalAlign::Center - } - alignment::Vertical::Bottom => { - glow_glyph::VerticalAlign::Bottom - } - }), - }; - - self.text_pipeline.queue(text); - } - - self.text_pipeline.draw_queued( - gl, - transformation, - glow_glyph::Region { - x: bounds.x, - y: target_height - (bounds.y + bounds.height), - width: bounds.width, - height: bounds.height, - }, - ); - } - } -} - -impl iced_graphics::Backend for Backend { - fn trim_measurements(&mut self) { - self.text_pipeline.trim_measurement_cache() - } -} - -impl backend::Text for Backend { - const ICON_FONT: Font = font::ICONS; - const CHECKMARK_ICON: char = font::CHECKMARK_ICON; - const ARROW_DOWN_ICON: char = font::ARROW_DOWN_ICON; - - fn default_size(&self) -> f32 { - self.default_text_size - } - - fn measure( - &self, - contents: &str, - size: f32, - font: Font, - bounds: Size, - ) -> (f32, f32) { - self.text_pipeline.measure(contents, size, font, bounds) - } - - fn hit_test( - &self, - contents: &str, - size: f32, - font: Font, - bounds: Size, - point: iced_native::Point, - nearest_only: bool, - ) -> Option<text::Hit> { - self.text_pipeline.hit_test( - contents, - size, - font, - bounds, - point, - nearest_only, - ) - } -} - -#[cfg(feature = "image")] -impl backend::Image for Backend { - fn dimensions(&self, handle: &iced_native::image::Handle) -> Size<u32> { - self.image_pipeline.dimensions(handle) - } -} - -#[cfg(feature = "svg")] -impl backend::Svg for Backend { - fn viewport_dimensions( - &self, - 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 deleted file mode 100644 index d3a25b5b..00000000 --- a/glow/src/image.rs +++ /dev/null @@ -1,254 +0,0 @@ -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; - -#[cfg(feature = "tracing")] -use tracing::info_span; - -#[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>, - ) { - #[cfg(feature = "tracing")] - let _ = info_span!("Glow::Image", "DRAW").entered(); - - 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, - color, - bounds, - } => { - let size = [bounds.width, bounds.height]; - ( - vector_cache.upload( - handle, - *color, - size, - _scale_factor, - &mut gl, - &mut self.storage, - ), - bounds, - ) - } - - #[cfg(not(feature = "svg"))] - layer::Image::Vector { 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 deleted file mode 100644 index 9bc20641..00000000 --- a/glow/src/image/storage.rs +++ /dev/null @@ -1,78 +0,0 @@ -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 deleted file mode 100644 index 9e7de0d9..00000000 --- a/glow/src/lib.rs +++ /dev/null @@ -1,53 +0,0 @@ -//! A [`glow`] renderer for [`iced_native`]. -//! -//!  -//! -//! [`glow`]: https://github.com/grovesNL/glow -//! [`iced_native`]: https://github.com/iced-rs/iced/tree/0.8/native -#![doc( - html_logo_url = "https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg" -)] -#![deny( - missing_debug_implementations, - missing_docs, - unused_results, - clippy::extra_unused_lifetimes, - clippy::from_over_into, - clippy::needless_borrow, - clippy::new_without_default, - clippy::useless_conversion -)] -#![forbid(rust_2018_idioms)] -#![allow(clippy::inherent_to_string, clippy::type_complexity)] -#![cfg_attr(docsrs, feature(doc_cfg))] - -pub use glow; - -mod backend; -#[cfg(any(feature = "image", feature = "svg"))] -mod image; -mod program; -mod quad; -mod text; -mod triangle; - -pub mod settings; -pub mod window; - -pub use backend::Backend; -pub use settings::Settings; - -pub(crate) use iced_graphics::Transformation; - -pub use iced_graphics::{Error, Viewport}; -pub use iced_native::Theme; - -pub use iced_native::alignment; -pub use iced_native::{Alignment, Background, Color, Command, Length, Vector}; - -/// A [`glow`] graphics renderer for [`iced`]. -/// -/// [`glow`]: https://github.com/grovesNL/glow -/// [`iced`]: https://github.com/iced-rs/iced -pub type Renderer<Theme = iced_native::Theme> = - iced_graphics::Renderer<Backend, Theme>; diff --git a/glow/src/program.rs b/glow/src/program.rs deleted file mode 100644 index 95437fcd..00000000 --- a/glow/src/program.rs +++ /dev/null @@ -1,133 +0,0 @@ -use glow::HasContext; - -/// The [`Version`] of a `Program`. -pub struct Version { - vertex: String, - fragment: String, -} - -impl Version { - pub fn new(gl: &glow::Context) -> Version { - let version = gl.version(); - - let (vertex, fragment) = match ( - version.major, - version.minor, - version.is_embedded, - ) { - // OpenGL 3.0+ - (3, 0 | 1 | 2, false) => ( - format!("#version 1{}0\n#extension GL_ARB_explicit_attrib_location : enable", version.minor + 3), - format!( - "#version 1{}0\n#extension GL_ARB_explicit_attrib_location : enable\n#define HIGHER_THAN_300 1", - version.minor + 3 - ), - ), - // OpenGL 3.3+ - (3 | 4, _, false) => ( - format!("#version {}{}0\n#extension GL_ARB_explicit_attrib_location : enable", version.major, version.minor), - format!( - "#version {}{}0\n#extension GL_ARB_explicit_attrib_location : enable\n#define HIGHER_THAN_300 1", - version.major, version.minor - ), - ), - // OpenGL ES 3.0+ - (3, _, true) => ( - format!("#version 3{}0 es", version.minor), - format!( - "#version 3{}0 es\n#define HIGHER_THAN_300 1", - version.minor - ), - ), - // OpenGL ES 2.0+ - (2, _, true) => ( - String::from( - "#version 100\n#define in attribute\n#define out varying", - ), - String::from("#version 100\n#define in varying"), - ), - // OpenGL 2.1 - (2, _, false) => ( - String::from( - "#version 120\n#define in attribute\n#define out varying", - ), - String::from("#version 120\n#define in varying"), - ), - // OpenGL 1.1+ - _ => panic!("Incompatible context version: {version:?}"), - }; - - log::info!("Shader directive: {}", vertex.lines().next().unwrap()); - - Version { vertex, fragment } - } -} - -pub struct Shader(<glow::Context as HasContext>::Shader); - -impl Shader { - fn compile(gl: &glow::Context, stage: u32, content: &str) -> Shader { - unsafe { - let shader = gl.create_shader(stage).expect("Cannot create shader"); - - gl.shader_source(shader, content); - gl.compile_shader(shader); - - if !gl.get_shader_compile_status(shader) { - panic!("{}", gl.get_shader_info_log(shader)); - } - - Shader(shader) - } - } - - /// Creates a vertex [`Shader`]. - pub fn vertex( - gl: &glow::Context, - version: &Version, - content: &'static str, - ) -> Self { - let content = format!("{}\n{}", version.vertex, content); - - Shader::compile(gl, glow::VERTEX_SHADER, &content) - } - - /// Creates a fragment [`Shader`]. - pub fn fragment( - gl: &glow::Context, - version: &Version, - content: &'static str, - ) -> Self { - let content = format!("{}\n{}", version.fragment, content); - - Shader::compile(gl, glow::FRAGMENT_SHADER, &content) - } -} - -pub unsafe fn create( - gl: &glow::Context, - shaders: &[Shader], - attributes: &[(u32, &str)], -) -> <glow::Context as HasContext>::Program { - let program = gl.create_program().expect("Cannot create program"); - - for shader in shaders { - gl.attach_shader(program, shader.0); - } - - for (i, name) in attributes { - gl.bind_attrib_location(program, *i, name); - } - - gl.link_program(program); - if !gl.get_program_link_status(program) { - panic!("{}", gl.get_program_info_log(program)); - } - - for shader in shaders { - gl.detach_shader(program, shader.0); - gl.delete_shader(shader.0); - } - - program -} diff --git a/glow/src/quad.rs b/glow/src/quad.rs deleted file mode 100644 index 67d9a098..00000000 --- a/glow/src/quad.rs +++ /dev/null @@ -1,74 +0,0 @@ -mod compatibility; -mod core; - -use crate::program; -use crate::Transformation; -use glow::HasContext; -use iced_graphics::layer; -use iced_native::Rectangle; - -#[cfg(feature = "tracing")] -use tracing::info_span; - -#[derive(Debug)] -pub enum Pipeline { - Core(core::Pipeline), - Compatibility(compatibility::Pipeline), -} - -impl Pipeline { - pub fn new( - gl: &glow::Context, - shader_version: &program::Version, - ) -> Pipeline { - let gl_version = gl.version(); - - // OpenGL 3.0+ and OpenGL ES 3.0+ have instancing (which is what separates `core` from `compatibility`) - if gl_version.major >= 3 { - log::info!("Mode: core"); - Pipeline::Core(core::Pipeline::new(gl, shader_version)) - } else { - log::info!("Mode: compatibility"); - Pipeline::Compatibility(compatibility::Pipeline::new( - gl, - shader_version, - )) - } - } - - pub fn draw( - &mut self, - gl: &glow::Context, - target_height: u32, - instances: &[layer::Quad], - transformation: Transformation, - scale: f32, - bounds: Rectangle<u32>, - ) { - #[cfg(feature = "tracing")] - let _ = info_span!("Glow::Quad", "DRAW").enter(); - - match self { - Pipeline::Core(pipeline) => { - pipeline.draw( - gl, - target_height, - instances, - transformation, - scale, - bounds, - ); - } - Pipeline::Compatibility(pipeline) => { - pipeline.draw( - gl, - target_height, - instances, - transformation, - scale, - bounds, - ); - } - } - } -} diff --git a/glow/src/quad/compatibility.rs b/glow/src/quad/compatibility.rs deleted file mode 100644 index e909162c..00000000 --- a/glow/src/quad/compatibility.rs +++ /dev/null @@ -1,349 +0,0 @@ -use crate::program::{self, Shader}; -use crate::Transformation; -use glow::HasContext; -use iced_graphics::layer; -use iced_native::Rectangle; - -// Only change `MAX_QUADS`, otherwise you could cause problems -// by splitting a triangle into different render passes. -const MAX_QUADS: usize = 100_000; -const MAX_VERTICES: usize = MAX_QUADS * 4; -const MAX_INDICES: usize = MAX_QUADS * 6; - -#[derive(Debug)] -pub struct Pipeline { - program: <glow::Context as HasContext>::Program, - vertex_array: <glow::Context as HasContext>::VertexArray, - vertex_buffer: <glow::Context as HasContext>::Buffer, - index_buffer: <glow::Context as HasContext>::Buffer, - transform_location: <glow::Context as HasContext>::UniformLocation, - scale_location: <glow::Context as HasContext>::UniformLocation, - screen_height_location: <glow::Context as HasContext>::UniformLocation, - current_transform: Transformation, - current_scale: f32, - current_target_height: u32, -} - -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/compatibility/quad.vert"), - ); - let fragment_shader = Shader::fragment( - gl, - shader_version, - include_str!("../shader/compatibility/quad.frag"), - ); - - program::create( - gl, - &[vertex_shader, fragment_shader], - &[ - (0, "i_Pos"), - (1, "i_Scale"), - (2, "i_Color"), - (3, "i_BorderColor"), - (4, "i_BorderRadius"), - (5, "i_BorderWidth"), - ], - ) - }; - - let transform_location = - unsafe { gl.get_uniform_location(program, "u_Transform") } - .expect("Get transform location"); - - let scale_location = - unsafe { gl.get_uniform_location(program, "u_Scale") } - .expect("Get scale location"); - - let screen_height_location = - unsafe { gl.get_uniform_location(program, "u_ScreenHeight") } - .expect("Get target height location"); - - unsafe { - gl.use_program(Some(program)); - - gl.uniform_matrix_4_f32_slice( - Some(&transform_location), - false, - Transformation::identity().as_ref(), - ); - - gl.uniform_1_f32(Some(&scale_location), 1.0); - gl.uniform_1_f32(Some(&screen_height_location), 0.0); - - gl.use_program(None); - } - - let (vertex_array, vertex_buffer, index_buffer) = - unsafe { create_buffers(gl, MAX_VERTICES) }; - - Pipeline { - program, - vertex_array, - vertex_buffer, - index_buffer, - transform_location, - scale_location, - screen_height_location, - current_transform: Transformation::identity(), - current_scale: 1.0, - current_target_height: 0, - } - } - - pub fn draw( - &mut self, - gl: &glow::Context, - target_height: u32, - instances: &[layer::Quad], - transformation: Transformation, - scale: f32, - bounds: Rectangle<u32>, - ) { - // TODO: Remove this allocation (probably by changing the shader and removing the need of two `position`) - let vertices: Vec<Vertex> = - instances.iter().flat_map(Vertex::from_quad).collect(); - - // TODO: Remove this allocation (or allocate only when needed) - let indices: Vec<i32> = (0..instances.len().min(MAX_QUADS) as i32) - .flat_map(|i| { - [i * 4, 1 + i * 4, 2 + i * 4, 2 + i * 4, 1 + i * 4, 3 + i * 4] - }) - .cycle() - .take(instances.len() * 6) - .collect(); - - unsafe { - gl.enable(glow::SCISSOR_TEST); - gl.scissor( - bounds.x as i32, - (target_height - (bounds.y + bounds.height)) as i32, - bounds.width as i32, - bounds.height as i32, - ); - - 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.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(self.index_buffer)); - } - - if transformation != self.current_transform { - unsafe { - gl.uniform_matrix_4_f32_slice( - Some(&self.transform_location), - false, - transformation.as_ref(), - ); - - self.current_transform = transformation; - } - } - - if scale != self.current_scale { - unsafe { - gl.uniform_1_f32(Some(&self.scale_location), scale); - } - - self.current_scale = scale; - } - - if target_height != self.current_target_height { - unsafe { - gl.uniform_1_f32( - Some(&self.screen_height_location), - target_height as f32, - ); - } - - self.current_target_height = target_height; - } - - let passes = vertices - .chunks(MAX_VERTICES) - .zip(indices.chunks(MAX_INDICES)); - - for (vertices, indices) in passes { - unsafe { - gl.buffer_sub_data_u8_slice( - glow::ARRAY_BUFFER, - 0, - bytemuck::cast_slice(vertices), - ); - - gl.buffer_sub_data_u8_slice( - glow::ELEMENT_ARRAY_BUFFER, - 0, - bytemuck::cast_slice(indices), - ); - - gl.draw_elements( - glow::TRIANGLES, - indices.len() as i32, - glow::UNSIGNED_INT, - 0, - ); - } - } - - unsafe { - gl.bind_vertex_array(None); - gl.use_program(None); - gl.disable(glow::SCISSOR_TEST); - } - } -} - -unsafe fn create_buffers( - gl: &glow::Context, - size: usize, -) -> ( - <glow::Context as HasContext>::VertexArray, - <glow::Context as HasContext>::Buffer, - <glow::Context as HasContext>::Buffer, -) { - let vertex_array = gl.create_vertex_array().expect("Create vertex array"); - let vertex_buffer = gl.create_buffer().expect("Create vertex buffer"); - let index_buffer = gl.create_buffer().expect("Create index buffer"); - - gl.bind_vertex_array(Some(vertex_array)); - - gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(index_buffer)); - gl.buffer_data_size( - glow::ELEMENT_ARRAY_BUFFER, - 12 * size as i32, - glow::DYNAMIC_DRAW, - ); - - gl.bind_buffer(glow::ARRAY_BUFFER, Some(vertex_buffer)); - gl.buffer_data_size( - glow::ARRAY_BUFFER, - (size * Vertex::SIZE) as i32, - glow::DYNAMIC_DRAW, - ); - - let stride = Vertex::SIZE 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, 2, glow::FLOAT, false, stride, 4 * 2); - - gl.enable_vertex_attrib_array(2); - gl.vertex_attrib_pointer_f32(2, 4, glow::FLOAT, false, stride, 4 * (2 + 2)); - - gl.enable_vertex_attrib_array(3); - gl.vertex_attrib_pointer_f32( - 3, - 4, - glow::FLOAT, - false, - stride, - 4 * (2 + 2 + 4), - ); - - gl.enable_vertex_attrib_array(4); - gl.vertex_attrib_pointer_f32( - 4, - 4, - glow::FLOAT, - false, - stride, - 4 * (2 + 2 + 4 + 4), - ); - - gl.enable_vertex_attrib_array(5); - gl.vertex_attrib_pointer_f32( - 5, - 1, - glow::FLOAT, - false, - stride, - 4 * (2 + 2 + 4 + 4 + 4), - ); - - gl.enable_vertex_attrib_array(6); - gl.vertex_attrib_pointer_f32( - 6, - 2, - glow::FLOAT, - false, - stride, - 4 * (2 + 2 + 4 + 4 + 4 + 1), - ); - - gl.bind_vertex_array(None); - gl.bind_buffer(glow::ARRAY_BUFFER, None); - gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, None); - - (vertex_array, vertex_buffer, index_buffer) -} - -/// The vertex of a colored rectangle with a border. -/// -/// This type can be directly uploaded to GPU memory. -#[derive(Debug, Clone, Copy, bytemuck::Pod, bytemuck::Zeroable)] -#[repr(C)] -pub struct Vertex { - /// The position of the [`Vertex`]. - pub position: [f32; 2], - - /// The size of the [`Vertex`]. - pub size: [f32; 2], - - /// The color of the [`Vertex`], in __linear RGB__. - pub color: [f32; 4], - - /// The border color of the [`Vertex`], in __linear RGB__. - pub border_color: [f32; 4], - - /// The border radius of the [`Vertex`]. - pub border_radius: [f32; 4], - - /// The border width of the [`Vertex`]. - pub border_width: f32, - - /// The __quad__ position of the [`Vertex`]. - pub q_position: [f32; 2], -} - -impl Vertex { - const SIZE: usize = std::mem::size_of::<Self>(); - - fn from_quad(quad: &layer::Quad) -> [Vertex; 4] { - let base = Vertex { - position: quad.position, - size: quad.size, - color: quad.color, - border_color: quad.color, - border_radius: quad.border_radius, - border_width: quad.border_width, - q_position: [0.0, 0.0], - }; - - [ - base, - Self { - q_position: [0.0, 1.0], - ..base - }, - Self { - q_position: [1.0, 0.0], - ..base - }, - Self { - q_position: [1.0, 1.0], - ..base - }, - ] - } -} diff --git a/glow/src/quad/core.rs b/glow/src/quad/core.rs deleted file mode 100644 index 89036530..00000000 --- a/glow/src/quad/core.rs +++ /dev/null @@ -1,244 +0,0 @@ -use crate::program::{self, Shader}; -use crate::Transformation; -use glow::HasContext; -use iced_graphics::layer; -use iced_native::Rectangle; - -const MAX_INSTANCES: usize = 100_000; - -#[derive(Debug)] -pub struct Pipeline { - program: <glow::Context as HasContext>::Program, - vertex_array: <glow::Context as HasContext>::VertexArray, - instances: <glow::Context as HasContext>::Buffer, - transform_location: <glow::Context as HasContext>::UniformLocation, - scale_location: <glow::Context as HasContext>::UniformLocation, - screen_height_location: <glow::Context as HasContext>::UniformLocation, - current_transform: Transformation, - current_scale: f32, - current_target_height: u32, -} - -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/core/quad.vert"), - ); - let fragment_shader = Shader::fragment( - gl, - shader_version, - include_str!("../shader/core/quad.frag"), - ); - - program::create( - gl, - &[vertex_shader, fragment_shader], - &[ - (0, "i_Pos"), - (1, "i_Scale"), - (2, "i_Color"), - (3, "i_BorderColor"), - (4, "i_BorderRadius"), - (5, "i_BorderWidth"), - ], - ) - }; - - let transform_location = - unsafe { gl.get_uniform_location(program, "u_Transform") } - .expect("Get transform location"); - - let scale_location = - unsafe { gl.get_uniform_location(program, "u_Scale") } - .expect("Get scale location"); - - let screen_height_location = - unsafe { gl.get_uniform_location(program, "u_ScreenHeight") } - .expect("Get target height location"); - - unsafe { - gl.use_program(Some(program)); - - gl.uniform_matrix_4_f32_slice( - Some(&transform_location), - false, - Transformation::identity().as_ref(), - ); - - gl.uniform_1_f32(Some(&scale_location), 1.0); - gl.uniform_1_f32(Some(&screen_height_location), 0.0); - - gl.use_program(None); - } - - let (vertex_array, instances) = - unsafe { create_instance_buffer(gl, MAX_INSTANCES) }; - - Pipeline { - program, - vertex_array, - instances, - transform_location, - scale_location, - screen_height_location, - current_transform: Transformation::identity(), - current_scale: 1.0, - current_target_height: 0, - } - } - - pub fn draw( - &mut self, - gl: &glow::Context, - target_height: u32, - instances: &[layer::Quad], - transformation: Transformation, - scale: f32, - bounds: Rectangle<u32>, - ) { - unsafe { - gl.enable(glow::SCISSOR_TEST); - gl.scissor( - bounds.x as i32, - (target_height - (bounds.y + bounds.height)) as i32, - bounds.width as i32, - bounds.height as i32, - ); - - gl.use_program(Some(self.program)); - gl.bind_vertex_array(Some(self.vertex_array)); - gl.bind_buffer(glow::ARRAY_BUFFER, Some(self.instances)); - } - - if transformation != self.current_transform { - unsafe { - gl.uniform_matrix_4_f32_slice( - Some(&self.transform_location), - false, - transformation.as_ref(), - ); - - self.current_transform = transformation; - } - } - - if scale != self.current_scale { - unsafe { - gl.uniform_1_f32(Some(&self.scale_location), scale); - } - - self.current_scale = scale; - } - - if target_height != self.current_target_height { - unsafe { - gl.uniform_1_f32( - Some(&self.screen_height_location), - target_height as f32, - ); - } - - self.current_target_height = target_height; - } - - for instances in instances.chunks(MAX_INSTANCES) { - unsafe { - gl.buffer_sub_data_u8_slice( - glow::ARRAY_BUFFER, - 0, - bytemuck::cast_slice(instances), - ); - - gl.draw_arrays_instanced( - glow::TRIANGLE_STRIP, - 0, - 4, - instances.len() as i32, - ); - } - } - - unsafe { - gl.bind_vertex_array(None); - gl.use_program(None); - gl.disable(glow::SCISSOR_TEST); - } - } -} - -unsafe fn create_instance_buffer( - gl: &glow::Context, - size: usize, -) -> ( - <glow::Context as HasContext>::VertexArray, - <glow::Context as HasContext>::Buffer, -) { - let vertex_array = gl.create_vertex_array().expect("Create vertex array"); - let buffer = gl.create_buffer().expect("Create instance buffer"); - - gl.bind_vertex_array(Some(vertex_array)); - gl.bind_buffer(glow::ARRAY_BUFFER, Some(buffer)); - gl.buffer_data_size( - glow::ARRAY_BUFFER, - (size * std::mem::size_of::<layer::Quad>()) as i32, - glow::DYNAMIC_DRAW, - ); - - let stride = std::mem::size_of::<layer::Quad>() as i32; - - gl.enable_vertex_attrib_array(0); - gl.vertex_attrib_pointer_f32(0, 2, glow::FLOAT, false, stride, 0); - gl.vertex_attrib_divisor(0, 1); - - gl.enable_vertex_attrib_array(1); - gl.vertex_attrib_pointer_f32(1, 2, glow::FLOAT, false, stride, 4 * 2); - gl.vertex_attrib_divisor(1, 1); - - gl.enable_vertex_attrib_array(2); - gl.vertex_attrib_pointer_f32(2, 4, glow::FLOAT, false, stride, 4 * (2 + 2)); - gl.vertex_attrib_divisor(2, 1); - - gl.enable_vertex_attrib_array(3); - gl.vertex_attrib_pointer_f32( - 3, - 4, - glow::FLOAT, - false, - stride, - 4 * (2 + 2 + 4), - ); - gl.vertex_attrib_divisor(3, 1); - - gl.enable_vertex_attrib_array(4); - gl.vertex_attrib_pointer_f32( - 4, - 4, - glow::FLOAT, - false, - stride, - 4 * (2 + 2 + 4 + 4), - ); - gl.vertex_attrib_divisor(4, 1); - - gl.enable_vertex_attrib_array(5); - gl.vertex_attrib_pointer_f32( - 5, - 1, - glow::FLOAT, - false, - stride, - 4 * (2 + 2 + 4 + 4 + 4), - ); - gl.vertex_attrib_divisor(5, 1); - - gl.bind_vertex_array(None); - gl.bind_buffer(glow::ARRAY_BUFFER, None); - - (vertex_array, buffer) -} diff --git a/glow/src/settings.rs b/glow/src/settings.rs deleted file mode 100644 index 6aaa0d55..00000000 --- a/glow/src/settings.rs +++ /dev/null @@ -1,61 +0,0 @@ -//! Configure a renderer. -pub use iced_graphics::Antialiasing; - -/// The settings of a [`Backend`]. -/// -/// [`Backend`]: crate::Backend -#[derive(Clone, Copy, PartialEq)] -pub struct Settings { - /// The bytes of the font that will be used by default. - /// - /// If `None` is provided, a default system font will be chosen. - pub default_font: Option<&'static [u8]>, - - /// The default size of text. - /// - /// By default, it will be set to `20.0`. - pub default_text_size: f32, - - /// If enabled, spread text workload in multiple threads when multiple cores - /// are available. - /// - /// By default, it is disabled. - pub text_multithreading: bool, - - /// The antialiasing strategy that will be used for triangle primitives. - /// - /// By default, it is `None`. - pub antialiasing: Option<Antialiasing>, -} - -impl Default for Settings { - fn default() -> Settings { - Settings { - default_font: None, - default_text_size: 20.0, - text_multithreading: false, - antialiasing: None, - } - } -} - -impl std::fmt::Debug for Settings { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("Settings") - // Instead of printing the font bytes, we simply show a `bool` indicating if using a default font or not. - .field("default_font", &self.default_font.is_some()) - .field("default_text_size", &self.default_text_size) - .field("text_multithreading", &self.text_multithreading) - .field("antialiasing", &self.antialiasing) - .finish() - } -} - -impl Settings { - /// Creates new [`Settings`] using environment configuration. - /// - /// Currently, this is equivalent to calling [`Settings::default`]. - pub fn from_env() -> Self { - Self::default() - } -} diff --git a/glow/src/shader/common/gradient.frag b/glow/src/shader/common/gradient.frag deleted file mode 100644 index 9af0cb6e..00000000 --- a/glow/src/shader/common/gradient.frag +++ /dev/null @@ -1,59 +0,0 @@ -#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 vec4 gradient_direction; -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]; - -//TODO: rewrite without branching to make ALUs happy -void main() { - vec2 start = gradient_direction.xy; - vec2 end = gradient_direction.zw; - vec2 gradient_vec = vec2(end - start); - vec2 current_vec = vec2(raw_position.xy - start); - 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 - 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 - 1].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 - 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 - gl_FragColor = mix(color_stops[i], color_stops[i+2], smoothstep( - curr_offset, - next_offset, - coord_offset - )); - } - - if (coord_offset >= max_offset) { - //current coordinate is before the last defined offset, set it to the last color - gl_FragColor = color_stops[color_stops_size - 2]; - } - } -} diff --git a/glow/src/shader/common/gradient.vert b/glow/src/shader/common/gradient.vert deleted file mode 100644 index fe505997..00000000 --- a/glow/src/shader/common/gradient.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/shader/common/image.frag b/glow/src/shader/common/image.frag deleted file mode 100644 index 5e05abdf..00000000 --- a/glow/src/shader/common/image.frag +++ /dev/null @@ -1,22 +0,0 @@ -#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 deleted file mode 100644 index 93e541f2..00000000 --- a/glow/src/shader/common/image.vert +++ /dev/null @@ -1,9 +0,0 @@ -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/solid.frag b/glow/src/shader/common/solid.frag deleted file mode 100644 index 174ffdd3..00000000 --- a/glow/src/shader/common/solid.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 - -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 deleted file mode 100644 index 59ed88e5..00000000 --- a/glow/src/shader/common/solid.vert +++ /dev/null @@ -1,11 +0,0 @@ -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/compatibility/quad.frag b/glow/src/shader/compatibility/quad.frag deleted file mode 100644 index bb9d8122..00000000 --- a/glow/src/shader/compatibility/quad.frag +++ /dev/null @@ -1,83 +0,0 @@ -#ifdef GL_ES -#ifdef GL_FRAGMENT_PRECISION_HIGH -precision highp float; -#else -precision mediump float; -#endif -#endif - -uniform float u_ScreenHeight; - -varying vec4 v_Color; -varying vec4 v_BorderColor; -varying vec2 v_Pos; -varying vec2 v_Scale; -varying vec4 v_BorderRadius; -varying float v_BorderWidth; - -float _distance(vec2 frag_coord, vec2 position, vec2 size, float radius) -{ - // TODO: Try SDF approach: https://www.shadertoy.com/view/wd3XRN - vec2 inner_size = size - vec2(radius, radius) * 2.0; - vec2 top_left = position + vec2(radius, radius); - vec2 bottom_right = top_left + inner_size; - - vec2 top_left_distance = top_left - frag_coord; - vec2 bottom_right_distance = frag_coord - bottom_right; - - vec2 distance = vec2( - max(max(top_left_distance.x, bottom_right_distance.x), 0.0), - max(max(top_left_distance.y, bottom_right_distance.y), 0.0) - ); - - return sqrt(distance.x * distance.x + distance.y * distance.y); -} - -float selectBorderRadius(vec4 radi, vec2 position, vec2 center) -{ - float rx = radi.x; - float ry = radi.y; - rx = position.x > center.x ? radi.y : radi.x; - ry = position.x > center.x ? radi.z : radi.w; - rx = position.y > center.y ? ry : rx; - return rx; -} - -void main() { - vec2 fragCoord = vec2(gl_FragCoord.x, u_ScreenHeight - gl_FragCoord.y); - - float border_radius = selectBorderRadius( - v_BorderRadius, - fragCoord, - (v_Pos + v_Scale * 0.5).xy - ); - - float internal_border = max(border_radius - v_BorderWidth, 0.0); - - float internal_distance = _distance( - fragCoord, - v_Pos + vec2(v_BorderWidth), - v_Scale - vec2(v_BorderWidth * 2.0), - internal_border - ); - - float border_mix = smoothstep( - max(internal_border - 0.5, 0.0), - internal_border + 0.5, - internal_distance - ); - - vec4 mixed_color = mix(v_Color, v_BorderColor, border_mix); - - float d = _distance( - fragCoord, - v_Pos, - v_Scale, - border_radius - ); - - float radius_alpha = - 1.0 - smoothstep(max(border_radius - 0.5, 0.0), border_radius + 0.5, d); - - gl_FragColor = vec4(mixed_color.xyz, mixed_color.w * radius_alpha); -} diff --git a/glow/src/shader/compatibility/quad.vert b/glow/src/shader/compatibility/quad.vert deleted file mode 100644 index 89931f06..00000000 --- a/glow/src/shader/compatibility/quad.vert +++ /dev/null @@ -1,46 +0,0 @@ -uniform mat4 u_Transform; -uniform float u_Scale; - -attribute vec2 i_Pos; -attribute vec2 i_Scale; -attribute vec4 i_Color; -attribute vec4 i_BorderColor; -attribute vec4 i_BorderRadius; -attribute float i_BorderWidth; -attribute vec2 q_Pos; - -varying vec4 v_Color; -varying vec4 v_BorderColor; -varying vec2 v_Pos; -varying vec2 v_Scale; -varying vec4 v_BorderRadius; -varying float v_BorderWidth; - - -void main() { - vec2 p_Pos = i_Pos * u_Scale; - vec2 p_Scale = i_Scale * u_Scale; - - vec4 i_BorderRadius = vec4( - min(i_BorderRadius.x, min(i_Scale.x, i_Scale.y) / 2.0), - min(i_BorderRadius.y, min(i_Scale.x, i_Scale.y) / 2.0), - min(i_BorderRadius.z, min(i_Scale.x, i_Scale.y) / 2.0), - min(i_BorderRadius.w, min(i_Scale.x, i_Scale.y) / 2.0) - ); - - mat4 i_Transform = mat4( - vec4(p_Scale.x + 1.0, 0.0, 0.0, 0.0), - vec4(0.0, p_Scale.y + 1.0, 0.0, 0.0), - vec4(0.0, 0.0, 1.0, 0.0), - vec4(p_Pos - vec2(0.5, 0.5), 0.0, 1.0) - ); - - v_Color = i_Color; - v_BorderColor = i_BorderColor; - v_Pos = p_Pos; - v_Scale = p_Scale; - v_BorderRadius = i_BorderRadius * u_Scale; - v_BorderWidth = i_BorderWidth * u_Scale; - - gl_Position = u_Transform * i_Transform * vec4(q_Pos, 0.0, 1.0); -} diff --git a/glow/src/shader/core/quad.frag b/glow/src/shader/core/quad.frag deleted file mode 100644 index 71147aa5..00000000 --- a/glow/src/shader/core/quad.frag +++ /dev/null @@ -1,95 +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 float u_ScreenHeight; - -in vec4 v_Color; -in vec4 v_BorderColor; -in vec2 v_Pos; -in vec2 v_Scale; -in vec4 v_BorderRadius; -in float v_BorderWidth; - -float fDistance(vec2 frag_coord, vec2 position, vec2 size, float radius) -{ - // TODO: Try SDF approach: https://www.shadertoy.com/view/wd3XRN - vec2 inner_size = size - vec2(radius, radius) * 2.0; - vec2 top_left = position + vec2(radius, radius); - vec2 bottom_right = top_left + inner_size; - - vec2 top_left_distance = top_left - frag_coord; - vec2 bottom_right_distance = frag_coord - bottom_right; - - vec2 distance = vec2( - max(max(top_left_distance.x, bottom_right_distance.x), 0.0), - max(max(top_left_distance.y, bottom_right_distance.y), 0.0) - ); - - return sqrt(distance.x * distance.x + distance.y * distance.y); -} - -float selectBorderRadius(vec4 radi, vec2 position, vec2 center) -{ - float rx = radi.x; - float ry = radi.y; - rx = position.x > center.x ? radi.y : radi.x; - ry = position.x > center.x ? radi.z : radi.w; - rx = position.y > center.y ? ry : rx; - return rx; -} - -void main() { - vec4 mixed_color; - - vec2 fragCoord = vec2(gl_FragCoord.x, u_ScreenHeight - gl_FragCoord.y); - - float border_radius = selectBorderRadius( - v_BorderRadius, - fragCoord, - (v_Pos + v_Scale * 0.5).xy - ); - - // TODO: Remove branching (?) - if(v_BorderWidth > 0.0) { - float internal_border = max(border_radius - v_BorderWidth, 0.0); - - float internal_distance = fDistance( - fragCoord, - v_Pos + vec2(v_BorderWidth), - v_Scale - vec2(v_BorderWidth * 2.0), - internal_border - ); - - float border_mix = smoothstep( - max(internal_border - 0.5, 0.0), - internal_border + 0.5, - internal_distance - ); - - mixed_color = mix(v_Color, v_BorderColor, border_mix); - } else { - mixed_color = v_Color; - } - - float d = fDistance( - fragCoord, - v_Pos, - v_Scale, - border_radius - ); - - float radius_alpha = - 1.0 - smoothstep(max(border_radius - 0.5, 0.0), border_radius + 0.5, d); - - gl_FragColor = vec4(mixed_color.xyz, mixed_color.w * radius_alpha); -} diff --git a/glow/src/shader/core/quad.vert b/glow/src/shader/core/quad.vert deleted file mode 100644 index 17c3e641..00000000 --- a/glow/src/shader/core/quad.vert +++ /dev/null @@ -1,52 +0,0 @@ -uniform mat4 u_Transform; -uniform float u_Scale; - -in vec2 i_Pos; -in vec2 i_Scale; -in vec4 i_Color; -in vec4 i_BorderColor; -in vec4 i_BorderRadius; -in float i_BorderWidth; - -out vec4 v_Color; -out vec4 v_BorderColor; -out vec2 v_Pos; -out vec2 v_Scale; -out vec4 v_BorderRadius; -out float v_BorderWidth; - -vec2 positions[4] = vec2[]( - vec2(0.0, 0.0), - vec2(0.0, 1.0), - vec2(1.0, 0.0), - vec2(1.0, 1.0) -); - -void main() { - vec2 q_Pos = positions[gl_VertexID]; - vec2 p_Pos = i_Pos * u_Scale; - vec2 p_Scale = i_Scale * u_Scale; - - vec4 i_BorderRadius = vec4( - min(i_BorderRadius.x, min(i_Scale.x, i_Scale.y) / 2.0), - min(i_BorderRadius.y, min(i_Scale.x, i_Scale.y) / 2.0), - min(i_BorderRadius.z, min(i_Scale.x, i_Scale.y) / 2.0), - min(i_BorderRadius.w, min(i_Scale.x, i_Scale.y) / 2.0) - ); - - mat4 i_Transform = mat4( - vec4(p_Scale.x + 1.0, 0.0, 0.0, 0.0), - vec4(0.0, p_Scale.y + 1.0, 0.0, 0.0), - vec4(0.0, 0.0, 1.0, 0.0), - vec4(p_Pos - vec2(0.5, 0.5), 0.0, 1.0) - ); - - v_Color = i_Color; - v_BorderColor = i_BorderColor; - v_Pos = p_Pos; - v_Scale = p_Scale; - v_BorderRadius = i_BorderRadius * u_Scale; - v_BorderWidth = i_BorderWidth * u_Scale; - - gl_Position = u_Transform * i_Transform * vec4(q_Pos, 0.0, 1.0); -} diff --git a/glow/src/text.rs b/glow/src/text.rs deleted file mode 100644 index 37ccdece..00000000 --- a/glow/src/text.rs +++ /dev/null @@ -1,257 +0,0 @@ -use crate::Transformation; - -use iced_graphics::font; - -use glow_glyph::ab_glyph; -use std::{cell::RefCell, collections::HashMap}; - -pub use iced_native::text::Hit; - -#[derive(Debug)] -pub struct Pipeline { - draw_brush: RefCell<glow_glyph::GlyphBrush>, - draw_font_map: RefCell<HashMap<String, glow_glyph::FontId>>, - measure_brush: RefCell<glyph_brush::GlyphBrush<()>>, -} - -impl Pipeline { - pub fn new( - gl: &glow::Context, - default_font: Option<&[u8]>, - multithreading: bool, - ) -> Self { - let default_font = default_font.map(|slice| slice.to_vec()); - - // TODO: Font customization - #[cfg(feature = "default_system_font")] - let default_font = { - default_font.or_else(|| { - font::Source::new() - .load(&[font::Family::SansSerif, font::Family::Serif]) - .ok() - }) - }; - - let default_font = - default_font.unwrap_or_else(|| font::FALLBACK.to_vec()); - - let font = ab_glyph::FontArc::try_from_vec(default_font) - .unwrap_or_else(|_| { - log::warn!( - "System font failed to load. Falling back to \ - embedded font..." - ); - - ab_glyph::FontArc::try_from_slice(font::FALLBACK) - .expect("Load fallback font") - }); - - let draw_brush_builder = - glow_glyph::GlyphBrushBuilder::using_font(font.clone()) - .initial_cache_size((2048, 2048)) - .draw_cache_multithread(multithreading); - - #[cfg(target_arch = "wasm32")] - let draw_brush_builder = draw_brush_builder.draw_cache_align_4x4(true); - - let draw_brush = draw_brush_builder.build(gl); - - let measure_brush = - glyph_brush::GlyphBrushBuilder::using_font(font).build(); - - Pipeline { - draw_brush: RefCell::new(draw_brush), - draw_font_map: RefCell::new(HashMap::new()), - measure_brush: RefCell::new(measure_brush), - } - } - - pub fn queue(&mut self, section: glow_glyph::Section<'_>) { - self.draw_brush.borrow_mut().queue(section); - } - - pub fn draw_queued( - &mut self, - gl: &glow::Context, - transformation: Transformation, - region: glow_glyph::Region, - ) { - self.draw_brush - .borrow_mut() - .draw_queued_with_transform_and_scissoring( - gl, - transformation.into(), - region, - ) - .expect("Draw text"); - } - - pub fn measure( - &self, - content: &str, - size: f32, - font: iced_native::Font, - bounds: iced_native::Size, - ) -> (f32, f32) { - use glow_glyph::GlyphCruncher; - - let glow_glyph::FontId(font_id) = self.find_font(font); - - let section = glow_glyph::Section { - bounds: (bounds.width, bounds.height), - text: vec![glow_glyph::Text { - text: content, - scale: size.into(), - font_id: glow_glyph::FontId(font_id), - extra: glow_glyph::Extra::default(), - }], - ..Default::default() - }; - - if let Some(bounds) = - self.measure_brush.borrow_mut().glyph_bounds(section) - { - (bounds.width().ceil(), bounds.height().ceil()) - } else { - (0.0, 0.0) - } - } - - pub fn hit_test( - &self, - content: &str, - size: f32, - font: iced_native::Font, - bounds: iced_native::Size, - point: iced_native::Point, - nearest_only: bool, - ) -> Option<Hit> { - use glow_glyph::GlyphCruncher; - - let glow_glyph::FontId(font_id) = self.find_font(font); - - let section = glow_glyph::Section { - bounds: (bounds.width, bounds.height), - text: vec![glow_glyph::Text { - text: content, - scale: size.into(), - font_id: glow_glyph::FontId(font_id), - extra: glow_glyph::Extra::default(), - }], - ..Default::default() - }; - - let mut mb = self.measure_brush.borrow_mut(); - - // The underlying type is FontArc, so clones are cheap. - use ab_glyph::{Font, ScaleFont}; - let font = mb.fonts()[font_id].clone().into_scaled(size); - - // Implements an iterator over the glyph bounding boxes. - let bounds = mb.glyphs(section).map( - |glow_glyph::SectionGlyph { - byte_index, glyph, .. - }| { - ( - *byte_index, - iced_native::Rectangle::new( - iced_native::Point::new( - glyph.position.x - font.h_side_bearing(glyph.id), - glyph.position.y - font.ascent(), - ), - iced_native::Size::new( - font.h_advance(glyph.id), - font.ascent() - font.descent(), - ), - ), - ) - }, - ); - - // Implements computation of the character index based on the byte index - // within the input string. - let char_index = |byte_index| { - let mut b_count = 0; - for (i, utf8_len) in - content.chars().map(|c| c.len_utf8()).enumerate() - { - if byte_index < (b_count + utf8_len) { - return i; - } - b_count += utf8_len; - } - - byte_index - }; - - if !nearest_only { - for (idx, bounds) in bounds.clone() { - if bounds.contains(point) { - return Some(Hit::CharOffset(char_index(idx))); - } - } - } - - let nearest = bounds - .map(|(index, bounds)| (index, bounds.center())) - .min_by(|(_, center_a), (_, center_b)| { - center_a - .distance(point) - .partial_cmp(¢er_b.distance(point)) - .unwrap_or(std::cmp::Ordering::Greater) - }); - - nearest.map(|(idx, center)| { - Hit::NearestCharOffset(char_index(idx), point - center) - }) - } - - pub fn trim_measurement_cache(&mut self) { - // TODO: We should probably use a `GlyphCalculator` for this. However, - // it uses a lifetimed `GlyphCalculatorGuard` with side-effects on drop. - // This makes stuff quite inconvenient. A manual method for trimming the - // cache would make our lives easier. - loop { - let action = self - .measure_brush - .borrow_mut() - .process_queued(|_, _| {}, |_| {}); - - match action { - Ok(_) => break, - Err(glyph_brush::BrushError::TextureTooSmall { suggested }) => { - let (width, height) = suggested; - - self.measure_brush - .borrow_mut() - .resize_texture(width, height); - } - } - } - } - - pub fn find_font(&self, font: iced_native::Font) -> glow_glyph::FontId { - match font { - iced_native::Font::Default => glow_glyph::FontId(0), - iced_native::Font::External { name, bytes } => { - if let Some(font_id) = self.draw_font_map.borrow().get(name) { - return *font_id; - } - - let font = ab_glyph::FontArc::try_from_slice(bytes) - .expect("Load font"); - - let _ = self.measure_brush.borrow_mut().add_font(font.clone()); - - let font_id = self.draw_brush.borrow_mut().add_font(font); - - let _ = self - .draw_font_map - .borrow_mut() - .insert(String::from(name), font_id); - - font_id - } - } - } -} diff --git a/glow/src/triangle.rs b/glow/src/triangle.rs deleted file mode 100644 index 42c88455..00000000 --- a/glow/src/triangle.rs +++ /dev/null @@ -1,595 +0,0 @@ -//! Draw meshes of triangles. -use crate::program; -use crate::Transformation; - -use iced_graphics::gradient::Gradient; -use iced_graphics::layer::mesh::{self, Mesh}; -use iced_graphics::triangle::{ColoredVertex2D, Vertex2D}; - -use glow::HasContext; -use std::marker::PhantomData; - -#[cfg(feature = "tracing")] -use tracing::info_span; - -const DEFAULT_VERTICES: usize = 1_000; -const DEFAULT_INDICES: usize = 1_000; - -#[derive(Debug)] -pub(crate) struct Pipeline { - indices: Buffer<u32>, - solid: solid::Program, - gradient: gradient::Program, -} - -impl Pipeline { - pub fn new(gl: &glow::Context, shader_version: &program::Version) -> Self { - let mut indices = unsafe { - Buffer::new( - gl, - glow::ELEMENT_ARRAY_BUFFER, - glow::DYNAMIC_DRAW, - DEFAULT_INDICES, - ) - }; - - let solid = solid::Program::new(gl, shader_version); - let gradient = gradient::Program::new(gl, shader_version); - - unsafe { - gl.bind_vertex_array(Some(solid.vertex_array)); - indices.bind(gl, 0); - - gl.bind_vertex_array(Some(gradient.vertex_array)); - indices.bind(gl, 0); - - gl.bind_vertex_array(None); - } - - Self { - indices, - solid, - gradient, - } - } - - pub fn draw( - &mut self, - meshes: &[Mesh<'_>], - gl: &glow::Context, - target_height: u32, - transformation: Transformation, - scale_factor: f32, - ) { - #[cfg(feature = "tracing")] - let _ = info_span!("Glow::Triangle", "DRAW").enter(); - - unsafe { - gl.enable(glow::MULTISAMPLE); - gl.enable(glow::SCISSOR_TEST); - } - - // 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.indices.bind(gl, count.indices); - } - - // We upload all the vertices and indices upfront - let mut solid_vertex_offset = 0; - let mut gradient_vertex_offset = 0; - let mut index_offset = 0; - - for mesh in meshes { - 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(indices), - ); - - 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_solid_vertex = 0; - let mut last_gradient_vertex = 0; - let mut last_index = 0; - - for mesh in meshes { - 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(); - - unsafe { - gl.scissor( - clip_bounds.x as i32, - (target_height - (clip_bounds.y + clip_bounds.height)) - as i32, - 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(), - ); - - self.solid.uniforms.transform = 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; - } - - 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_gradient_vertex += buffers.vertices.len(); - }, - } - - last_index += indices.len(); - } - - unsafe { - gl.bind_vertex_array(None); - gl.disable(glow::SCISSOR_TEST); - gl.disable(glow::MULTISAMPLE); - } - } -} - -#[derive(Debug)] -pub struct Buffer<T> { - raw: <glow::Context as HasContext>::Buffer, - target: u32, - usage: u32, - size: usize, - phantom: PhantomData<T>, -} - -impl<T> Buffer<T> { - pub unsafe fn new( - gl: &glow::Context, - target: u32, - usage: u32, - size: usize, - ) -> Self { - let raw = gl.create_buffer().expect("Create buffer"); - - let mut buffer = Buffer { - raw, - target, - usage, - size: 0, - phantom: PhantomData, - }; - - buffer.bind(gl, size); - - buffer - } - - pub unsafe fn bind(&mut self, gl: &glow::Context, size: usize) { - gl.bind_buffer(self.target, Some(self.raw)); - - if self.size < size { - gl.buffer_data_size( - self.target, - (size * std::mem::size_of::<T>()) as i32, - self.usage, - ); - - self.size = size; - } - } -} - -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/window.rs b/glow/src/window.rs deleted file mode 100644 index aac5fb9e..00000000 --- a/glow/src/window.rs +++ /dev/null @@ -1,4 +0,0 @@ -//! Display rendering results on windows. -mod compositor; - -pub use compositor::Compositor; diff --git a/glow/src/window/compositor.rs b/glow/src/window/compositor.rs deleted file mode 100644 index 20756032..00000000 --- a/glow/src/window/compositor.rs +++ /dev/null @@ -1,111 +0,0 @@ -use crate::{Backend, Color, Error, Renderer, Settings, Viewport}; - -use glow::HasContext; -use iced_graphics::{compositor, Antialiasing, Size}; - -use core::ffi::c_void; -use std::marker::PhantomData; - -/// A window graphics backend for iced powered by `glow`. -#[allow(missing_debug_implementations)] -pub struct Compositor<Theme> { - gl: glow::Context, - theme: PhantomData<Theme>, -} - -impl<Theme> iced_graphics::window::GLCompositor for Compositor<Theme> { - type Settings = Settings; - type Renderer = Renderer<Theme>; - - unsafe fn new( - settings: Self::Settings, - loader_function: impl FnMut(&str) -> *const c_void, - ) -> Result<(Self, Self::Renderer), Error> { - let gl = glow::Context::from_loader_function(loader_function); - - log::info!("{:#?}", settings); - - let version = gl.version(); - log::info!( - "OpenGL version: {:?} (Embedded: {})", - version, - version.is_embedded - ); - - let renderer = gl.get_parameter_string(glow::RENDERER); - log::info!("Renderer: {}", renderer); - - // Enable auto-conversion from/to sRGB - gl.enable(glow::FRAMEBUFFER_SRGB); - - // Enable alpha blending - gl.enable(glow::BLEND); - gl.blend_func_separate( - glow::SRC_ALPHA, - glow::ONE_MINUS_SRC_ALPHA, - glow::ONE, - glow::ONE_MINUS_SRC_ALPHA, - ); - - // Disable multisampling by default - gl.disable(glow::MULTISAMPLE); - - let renderer = Renderer::new(Backend::new(&gl, settings)); - - Ok(( - Self { - gl, - theme: PhantomData, - }, - renderer, - )) - } - - fn sample_count(settings: &Settings) -> u32 { - settings - .antialiasing - .map(Antialiasing::sample_count) - .unwrap_or(0) - } - - fn resize_viewport(&mut self, physical_size: Size<u32>) { - unsafe { - self.gl.viewport( - 0, - 0, - physical_size.width as i32, - physical_size.height as i32, - ); - } - } - - fn fetch_information(&self) -> compositor::Information { - let adapter = unsafe { self.gl.get_parameter_string(glow::RENDERER) }; - - compositor::Information { - backend: format!("{:?}", self.gl.version()), - adapter, - } - } - - fn present<T: AsRef<str>>( - &mut self, - renderer: &mut Self::Renderer, - viewport: &Viewport, - color: Color, - overlay: &[T], - ) { - let gl = &self.gl; - - let [r, g, b, a] = color.into_linear(); - - unsafe { - gl.clear_color(r, g, b, a); - gl.clear(glow::COLOR_BUFFER_BIT); - } - - renderer.with_primitives(|backend, primitive| { - backend.present(gl, primitive, viewport, overlay); - }); - } -} |