summaryrefslogtreecommitdiffstats
path: root/graphics
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón Jiménez <hector@hecrj.dev>2024-04-03 21:07:54 +0200
committerLibravatar Héctor Ramón Jiménez <hector@hecrj.dev>2024-04-03 21:07:54 +0200
commitb05e61f5c8ae61c9f3c7cc08cded53901ebbccfd (patch)
tree3d35a011d94d4936f09b5a9be4031358a09c60da /graphics
parent99a904112ca111f2ab0e60e30b6c369741b1653b (diff)
downloadiced-b05e61f5c8ae61c9f3c7cc08cded53901ebbccfd.tar.gz
iced-b05e61f5c8ae61c9f3c7cc08cded53901ebbccfd.tar.bz2
iced-b05e61f5c8ae61c9f3c7cc08cded53901ebbccfd.zip
Redesign `iced_wgpu` layering architecture
Diffstat (limited to 'graphics')
-rw-r--r--graphics/src/cached.rs8
-rw-r--r--graphics/src/geometry/cache.rs10
-rw-r--r--graphics/src/image.rs154
-rw-r--r--graphics/src/layer.rs47
-rw-r--r--graphics/src/lib.rs6
-rw-r--r--graphics/src/mesh.rs90
-rw-r--r--graphics/src/renderer.rs4
-rw-r--r--graphics/src/text.rs57
8 files changed, 290 insertions, 86 deletions
diff --git a/graphics/src/cached.rs b/graphics/src/cached.rs
index b52f9d9d..1ba82f9f 100644
--- a/graphics/src/cached.rs
+++ b/graphics/src/cached.rs
@@ -5,7 +5,7 @@ use std::sync::Arc;
/// A piece of data that can be cached.
pub trait Cached: Sized {
/// The type of cache produced.
- type Cache;
+ type Cache: Clone;
/// Loads the [`Cache`] into a proper instance.
///
@@ -15,7 +15,7 @@ pub trait Cached: Sized {
/// Caches this value, producing its corresponding [`Cache`].
///
/// [`Cache`]: Self::Cache
- fn cache(self) -> Self::Cache;
+ fn cache(self, previous: Option<Self::Cache>) -> Self::Cache;
}
impl<T> Cached for Primitive<T> {
@@ -27,7 +27,7 @@ impl<T> Cached for Primitive<T> {
}
}
- fn cache(self) -> Arc<Self> {
+ fn cache(self, _previous: Option<Arc<Self>>) -> Arc<Self> {
Arc::new(self)
}
}
@@ -38,5 +38,5 @@ impl Cached for () {
fn load(_cache: &Self::Cache) -> Self {}
- fn cache(self) -> Self::Cache {}
+ fn cache(self, _previous: Option<Self::Cache>) -> Self::Cache {}
}
diff --git a/graphics/src/geometry/cache.rs b/graphics/src/geometry/cache.rs
index 37d433c2..ebbafd14 100644
--- a/graphics/src/geometry/cache.rs
+++ b/graphics/src/geometry/cache.rs
@@ -49,7 +49,7 @@ where
) -> Renderer::Geometry {
use std::ops::Deref;
- if let State::Filled {
+ let previous = if let State::Filled {
bounds: cached_bounds,
geometry,
} = self.state.borrow().deref()
@@ -57,12 +57,16 @@ where
if *cached_bounds == bounds {
return Cached::load(geometry);
}
- }
+
+ Some(geometry.clone())
+ } else {
+ None
+ };
let mut frame = Frame::new(renderer, bounds);
draw_fn(&mut frame);
- let geometry = frame.into_geometry().cache();
+ let geometry = frame.into_geometry().cache(previous);
let result = Cached::load(&geometry);
*self.state.borrow_mut() = State::Filled { bounds, geometry };
diff --git a/graphics/src/image.rs b/graphics/src/image.rs
index d89caace..e8626717 100644
--- a/graphics/src/image.rs
+++ b/graphics/src/image.rs
@@ -1,14 +1,94 @@
//! Load and operate on images.
-use crate::core::image::{Data, Handle};
+#[cfg(feature = "image")]
+pub use ::image as image_rs;
-use bitflags::bitflags;
+use crate::core::image;
+use crate::core::svg;
+use crate::core::{Color, Rectangle};
-pub use ::image as image_rs;
+/// A raster or vector image.
+#[derive(Debug, Clone)]
+pub enum Image {
+ /// A raster image.
+ Raster {
+ /// The handle of a raster image.
+ handle: image::Handle,
+
+ /// The filter method of a raster image.
+ filter_method: image::FilterMethod,
+
+ /// The bounds of the image.
+ bounds: Rectangle,
+ },
+ /// A vector image.
+ Vector {
+ /// The handle of a vector image.
+ handle: svg::Handle,
+
+ /// The [`Color`] filter
+ color: Option<Color>,
+ /// The bounds of the image.
+ bounds: Rectangle,
+ },
+}
+
+#[cfg(feature = "image")]
/// Tries to load an image by its [`Handle`].
-pub fn load(handle: &Handle) -> image_rs::ImageResult<image_rs::DynamicImage> {
+pub fn load(
+ handle: &image::Handle,
+) -> ::image::ImageResult<::image::DynamicImage> {
+ use bitflags::bitflags;
+
+ bitflags! {
+ struct Operation: u8 {
+ const FLIP_HORIZONTALLY = 0b001;
+ const ROTATE_180 = 0b010;
+ const FLIP_DIAGONALLY = 0b100;
+ }
+ }
+
+ impl Operation {
+ // Meaning of the returned value is described e.g. at:
+ // https://magnushoff.com/articles/jpeg-orientation/
+ fn from_exif<R>(reader: &mut R) -> Result<Self, exif::Error>
+ where
+ R: std::io::BufRead + std::io::Seek,
+ {
+ let exif = exif::Reader::new().read_from_container(reader)?;
+
+ Ok(exif
+ .get_field(exif::Tag::Orientation, exif::In::PRIMARY)
+ .and_then(|field| field.value.get_uint(0))
+ .and_then(|value| u8::try_from(value).ok())
+ .and_then(|value| Self::from_bits(value.saturating_sub(1)))
+ .unwrap_or_else(Self::empty))
+ }
+
+ fn perform(
+ self,
+ mut image: ::image::DynamicImage,
+ ) -> ::image::DynamicImage {
+ use ::image::imageops;
+
+ if self.contains(Self::FLIP_DIAGONALLY) {
+ imageops::flip_vertical_in_place(&mut image);
+ }
+
+ if self.contains(Self::ROTATE_180) {
+ imageops::rotate180_in_place(&mut image);
+ }
+
+ if self.contains(Self::FLIP_HORIZONTALLY) {
+ imageops::flip_horizontal_in_place(&mut image);
+ }
+
+ image
+ }
+ }
+
match handle.data() {
- Data::Path(path) => {
+ image::Data::Path(path) => {
let image = ::image::open(path)?;
let operation = std::fs::File::open(path)
@@ -19,7 +99,7 @@ pub fn load(handle: &Handle) -> image_rs::ImageResult<image_rs::DynamicImage> {
Ok(operation.perform(image))
}
- Data::Bytes(bytes) => {
+ image::Data::Bytes(bytes) => {
let image = ::image::load_from_memory(bytes)?;
let operation =
Operation::from_exif(&mut std::io::Cursor::new(bytes))
@@ -28,68 +108,22 @@ pub fn load(handle: &Handle) -> image_rs::ImageResult<image_rs::DynamicImage> {
Ok(operation.perform(image))
}
- Data::Rgba {
+ image::Data::Rgba {
width,
height,
pixels,
} => {
- if let Some(image) = image_rs::ImageBuffer::from_vec(
- *width,
- *height,
- pixels.to_vec(),
- ) {
- Ok(image_rs::DynamicImage::ImageRgba8(image))
+ if let Some(image) =
+ ::image::ImageBuffer::from_vec(*width, *height, pixels.to_vec())
+ {
+ Ok(::image::DynamicImage::ImageRgba8(image))
} else {
- Err(image_rs::error::ImageError::Limits(
- image_rs::error::LimitError::from_kind(
- image_rs::error::LimitErrorKind::DimensionError,
+ Err(::image::error::ImageError::Limits(
+ ::image::error::LimitError::from_kind(
+ ::image::error::LimitErrorKind::DimensionError,
),
))
}
}
}
}
-
-bitflags! {
- struct Operation: u8 {
- const FLIP_HORIZONTALLY = 0b001;
- const ROTATE_180 = 0b010;
- const FLIP_DIAGONALLY = 0b100;
- }
-}
-
-impl Operation {
- // Meaning of the returned value is described e.g. at:
- // https://magnushoff.com/articles/jpeg-orientation/
- fn from_exif<R>(reader: &mut R) -> Result<Self, exif::Error>
- where
- R: std::io::BufRead + std::io::Seek,
- {
- let exif = exif::Reader::new().read_from_container(reader)?;
-
- Ok(exif
- .get_field(exif::Tag::Orientation, exif::In::PRIMARY)
- .and_then(|field| field.value.get_uint(0))
- .and_then(|value| u8::try_from(value).ok())
- .and_then(|value| Self::from_bits(value.saturating_sub(1)))
- .unwrap_or_else(Self::empty))
- }
-
- fn perform(self, mut image: image::DynamicImage) -> image::DynamicImage {
- use image::imageops;
-
- if self.contains(Self::FLIP_DIAGONALLY) {
- imageops::flip_vertical_in_place(&mut image);
- }
-
- if self.contains(Self::ROTATE_180) {
- imageops::rotate180_in_place(&mut image);
- }
-
- if self.contains(Self::FLIP_HORIZONTALLY) {
- imageops::flip_horizontal_in_place(&mut image);
- }
-
- image
- }
-}
diff --git a/graphics/src/layer.rs b/graphics/src/layer.rs
new file mode 100644
index 00000000..5b8aacab
--- /dev/null
+++ b/graphics/src/layer.rs
@@ -0,0 +1,47 @@
+pub trait Layer {
+ type Cache;
+
+ fn new() -> Self;
+
+ fn clear(&mut self);
+}
+
+pub struct Recorder<T: Layer> {
+ layers: Vec<T>,
+ caches: Vec<T::Cache>,
+ stack: Vec<Kind>,
+ current: usize,
+}
+
+enum Kind {
+ Fresh(usize),
+ Cache(usize),
+}
+
+impl<T: Layer> Recorder<T> {
+ pub fn new() -> Self {
+ Self {
+ layers: vec![Layer::new()],
+ caches: Vec::new(),
+ stack: Vec::new(),
+ current: 0,
+ }
+ }
+
+ pub fn fill_quad(&mut self) {}
+
+ pub fn push_cache(&mut self, cache: T::Cache) {
+ self.caches.push(cache);
+ }
+
+ pub fn clear(&mut self) {
+ self.caches.clear();
+ self.stack.clear();
+
+ for mut layer in self.layers {
+ layer.clear();
+ }
+
+ self.current = 0;
+ }
+}
diff --git a/graphics/src/lib.rs b/graphics/src/lib.rs
index d7f2f439..5857aea5 100644
--- a/graphics/src/lib.rs
+++ b/graphics/src/lib.rs
@@ -28,6 +28,7 @@ pub mod compositor;
pub mod damage;
pub mod error;
pub mod gradient;
+pub mod image;
pub mod mesh;
pub mod renderer;
pub mod text;
@@ -35,9 +36,6 @@ pub mod text;
#[cfg(feature = "geometry")]
pub mod geometry;
-#[cfg(feature = "image")]
-pub mod image;
-
pub use antialiasing::Antialiasing;
pub use backend::Backend;
pub use cached::Cached;
@@ -45,10 +43,12 @@ pub use compositor::Compositor;
pub use damage::Damage;
pub use error::Error;
pub use gradient::Gradient;
+pub use image::Image;
pub use mesh::Mesh;
pub use primitive::Primitive;
pub use renderer::Renderer;
pub use settings::Settings;
+pub use text::Text;
pub use viewport::Viewport;
pub use iced_core as core;
diff --git a/graphics/src/mesh.rs b/graphics/src/mesh.rs
index 20692b07..d3e7ffaf 100644
--- a/graphics/src/mesh.rs
+++ b/graphics/src/mesh.rs
@@ -1,8 +1,7 @@
//! Draw triangles!
use crate::color;
-use crate::core::{Rectangle, Size};
+use crate::core::{Rectangle, Size, Transformation};
use crate::gradient;
-use crate::Damage;
use bytemuck::{Pod, Zeroable};
@@ -14,9 +13,10 @@ pub enum Mesh {
/// The vertices and indices of the mesh.
buffers: Indexed<SolidVertex2D>,
- /// The size of the drawable region of the mesh.
- ///
- /// Any geometry that falls out of this region will be clipped.
+ /// The [`Transformation`] for the vertices of the [`Mesh`].
+ transformation: Transformation,
+
+ /// The [`Size`] of the [`Mesh`].
size: Size,
},
/// A mesh with a gradient.
@@ -24,19 +24,44 @@ pub enum Mesh {
/// The vertices and indices of the mesh.
buffers: Indexed<GradientVertex2D>,
- /// The size of the drawable region of the mesh.
- ///
- /// Any geometry that falls out of this region will be clipped.
+ /// The [`Transformation`] for the vertices of the [`Mesh`].
+ transformation: Transformation,
+
+ /// The [`Size`] of the [`Mesh`].
size: Size,
},
}
-impl Damage for Mesh {
- fn bounds(&self) -> Rectangle {
+impl Mesh {
+ /// Returns the indices of the [`Mesh`].
+ pub fn indices(&self) -> &[u32] {
+ match self {
+ Self::Solid { buffers, .. } => &buffers.indices,
+ Self::Gradient { buffers, .. } => &buffers.indices,
+ }
+ }
+
+ /// Returns the [`Transformation`] of the [`Mesh`].
+ pub fn transformation(&self) -> Transformation {
+ match self {
+ Self::Solid { transformation, .. }
+ | Self::Gradient { transformation, .. } => *transformation,
+ }
+ }
+
+ /// Returns the clip bounds of the [`Mesh`].
+ pub fn clip_bounds(&self) -> Rectangle {
match self {
- Self::Solid { size, .. } | Self::Gradient { size, .. } => {
- Rectangle::with_size(*size)
+ Self::Solid {
+ size,
+ transformation,
+ ..
}
+ | Self::Gradient {
+ size,
+ transformation,
+ ..
+ } => Rectangle::with_size(*size) * *transformation,
}
}
}
@@ -75,6 +100,47 @@ pub struct GradientVertex2D {
pub gradient: gradient::Packed,
}
+/// The result of counting the attributes of a set of meshes.
+#[derive(Debug, Clone, Copy, Default)]
+pub struct AttributeCount {
+ /// The total amount of solid vertices.
+ pub solid_vertices: usize,
+
+ /// The total amount of solid meshes.
+ pub solids: usize,
+
+ /// The total amount of gradient vertices.
+ pub gradient_vertices: usize,
+
+ /// The total amount of gradient meshes.
+ pub gradients: usize,
+
+ /// The total amount of indices.
+ pub indices: usize,
+}
+
+/// Returns the number of total vertices & total indices of all [`Mesh`]es.
+pub fn attribute_count_of(meshes: &[Mesh]) -> AttributeCount {
+ meshes
+ .iter()
+ .fold(AttributeCount::default(), |mut count, mesh| {
+ match mesh {
+ Mesh::Solid { buffers, .. } => {
+ count.solids += 1;
+ count.solid_vertices += buffers.vertices.len();
+ count.indices += buffers.indices.len();
+ }
+ Mesh::Gradient { buffers, .. } => {
+ count.gradients += 1;
+ count.gradient_vertices += buffers.vertices.len();
+ count.indices += buffers.indices.len();
+ }
+ }
+
+ count
+ })
+}
+
/// A renderer capable of drawing a [`Mesh`].
pub trait Renderer {
/// Draws the given [`Mesh`].
diff --git a/graphics/src/renderer.rs b/graphics/src/renderer.rs
index fb1a0d73..d4f91dab 100644
--- a/graphics/src/renderer.rs
+++ b/graphics/src/renderer.rs
@@ -62,7 +62,7 @@ impl<B: Backend> Renderer<B> {
}
impl<B: Backend> iced_core::Renderer for Renderer<B> {
- fn start_layer(&mut self) {
+ fn start_layer(&mut self, _bounds: Rectangle) {
self.stack.push(std::mem::take(&mut self.primitives));
}
@@ -75,7 +75,7 @@ impl<B: Backend> iced_core::Renderer for Renderer<B> {
self.primitives.push(Primitive::group(layer).clip(bounds));
}
- fn start_transformation(&mut self) {
+ fn start_transformation(&mut self, _transformation: Transformation) {
self.stack.push(std::mem::take(&mut self.primitives));
}
diff --git a/graphics/src/text.rs b/graphics/src/text.rs
index 0310ead7..c9c821c0 100644
--- a/graphics/src/text.rs
+++ b/graphics/src/text.rs
@@ -9,14 +9,67 @@ pub use paragraph::Paragraph;
pub use cosmic_text;
+use crate::core::alignment;
use crate::core::font::{self, Font};
-use crate::core::text::Shaping;
-use crate::core::{Color, Point, Rectangle, Size};
+use crate::core::text::{LineHeight, Shaping};
+use crate::core::{Color, Pixels, Point, Rectangle, Size, Transformation};
use once_cell::sync::OnceCell;
use std::borrow::Cow;
use std::sync::{Arc, RwLock, Weak};
+/// A text primitive.
+#[derive(Debug, Clone)]
+pub enum Text {
+ /// A paragraph.
+ #[allow(missing_docs)]
+ Paragraph {
+ paragraph: paragraph::Weak,
+ position: Point,
+ color: Color,
+ clip_bounds: Rectangle,
+ transformation: Transformation,
+ },
+ /// An editor.
+ #[allow(missing_docs)]
+ Editor {
+ editor: editor::Weak,
+ position: Point,
+ color: Color,
+ clip_bounds: Rectangle,
+ transformation: Transformation,
+ },
+ /// Some cached text.
+ Cached {
+ /// The contents of the text.
+ content: String,
+ /// The bounds of the text.
+ bounds: Rectangle,
+ /// The color of the text.
+ color: Color,
+ /// The size of the text in logical pixels.
+ size: Pixels,
+ /// The line height of the text.
+ line_height: LineHeight,
+ /// The font of the text.
+ font: Font,
+ /// The horizontal alignment of the text.
+ horizontal_alignment: alignment::Horizontal,
+ /// The vertical alignment of the text.
+ vertical_alignment: alignment::Vertical,
+ /// The shaping strategy of the text.
+ shaping: Shaping,
+ /// The clip bounds of the text.
+ clip_bounds: Rectangle,
+ },
+ /// Some raw text.
+ #[allow(missing_docs)]
+ Raw {
+ raw: Raw,
+ transformation: Transformation,
+ },
+}
+
/// The regular variant of the [Fira Sans] font.
///
/// It is loaded as part of the default fonts in Wasm builds.