summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Cargo.toml1
-rw-r--r--examples/arc/src/main.rs4
-rw-r--r--examples/geometry/Cargo.toml11
-rw-r--r--examples/geometry/README.md18
-rw-r--r--examples/geometry/src/main.rs222
-rw-r--r--examples/modern_art/src/main.rs9
-rw-r--r--glow/src/triangle.rs10
-rw-r--r--graphics/src/gradient.rs75
-rw-r--r--graphics/src/gradient/linear.rs71
-rw-r--r--graphics/src/layer.rs111
-rw-r--r--graphics/src/layer/image.rs23
-rw-r--r--graphics/src/layer/mesh.rs39
-rw-r--r--graphics/src/layer/quad.rs30
-rw-r--r--graphics/src/layer/text.rs26
-rw-r--r--graphics/src/lib.rs1
-rw-r--r--graphics/src/primitive.rs5
-rw-r--r--graphics/src/shader.rs23
-rw-r--r--graphics/src/widget/canvas.rs8
-rw-r--r--graphics/src/widget/canvas/fill.rs16
-rw-r--r--graphics/src/widget/canvas/frame.rs32
-rw-r--r--graphics/src/widget/canvas/stroke.rs10
-rw-r--r--wgpu/src/buffers.rs124
-rw-r--r--wgpu/src/buffers/buffer.rs124
-rw-r--r--wgpu/src/buffers/dynamic.rs (renamed from wgpu/src/buffers/dynamic_buffers.rs)0
-rw-r--r--wgpu/src/triangle.rs22
-rw-r--r--wgpu/src/triangle/gradient.rs2
-rw-r--r--wgpu/src/triangle/solid.rs2
27 files changed, 394 insertions, 625 deletions
diff --git a/Cargo.toml b/Cargo.toml
index d8f5eccb..e4754782 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -69,7 +69,6 @@ members = [
"examples/events",
"examples/exit",
"examples/game_of_life",
- "examples/geometry",
"examples/integration_opengl",
"examples/integration_wgpu",
"examples/modern_art",
diff --git a/examples/arc/src/main.rs b/examples/arc/src/main.rs
index bc7e49c6..7b6ea0e1 100644
--- a/examples/arc/src/main.rs
+++ b/examples/arc/src/main.rs
@@ -2,7 +2,7 @@ use std::{f32::consts::PI, time::Instant};
use iced::executor;
use iced::widget::canvas::{
- self, Cache, Canvas, Cursor, Geometry, Path, Stroke, Style,
+ self, stroke, Cache, Canvas, Cursor, Geometry, Path, Stroke,
};
use iced::{
Application, Command, Element, Length, Point, Rectangle, Settings,
@@ -114,7 +114,7 @@ impl<Message> canvas::Program<Message> for Arc {
frame.stroke(
&path,
Stroke {
- style: Style::Solid(palette.text),
+ style: stroke::Style::Solid(palette.text),
width: 10.0,
..Stroke::default()
},
diff --git a/examples/geometry/Cargo.toml b/examples/geometry/Cargo.toml
deleted file mode 100644
index 22ede0e0..00000000
--- a/examples/geometry/Cargo.toml
+++ /dev/null
@@ -1,11 +0,0 @@
-[package]
-name = "geometry"
-version = "0.1.0"
-authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
-edition = "2021"
-publish = false
-
-[dependencies]
-iced = { path = "../.." }
-iced_native = { path = "../../native" }
-iced_graphics = { path = "../../graphics" }
diff --git a/examples/geometry/README.md b/examples/geometry/README.md
deleted file mode 100644
index 4d5c81cb..00000000
--- a/examples/geometry/README.md
+++ /dev/null
@@ -1,18 +0,0 @@
-## Geometry
-
-A custom widget showcasing how to draw geometry with the `Mesh2D` primitive in [`iced_wgpu`](../../wgpu).
-
-The __[`main`]__ file contains all the code of the example.
-
-<div align="center">
- <a href="https://gfycat.com/activeunfitkangaroo">
- <img src="https://thumbs.gfycat.com/ActiveUnfitKangaroo-small.gif">
- </a>
-</div>
-
-You can run it with `cargo run`:
-```
-cargo run --package geometry
-```
-
-[`main`]: src/main.rs
diff --git a/examples/geometry/src/main.rs b/examples/geometry/src/main.rs
deleted file mode 100644
index a8ce26f8..00000000
--- a/examples/geometry/src/main.rs
+++ /dev/null
@@ -1,222 +0,0 @@
-//! This example showcases a simple native custom widget that renders using
-//! arbitrary low-level geometry.
-//!
-//TODO need to update this now that vertex data doesn't contain color data
-mod rainbow {
- use iced::Color;
- // For now, to implement a custom native widget you will need to add
- // `iced_native` and `iced_wgpu` to your dependencies.
- //
- // Then, you simply need to define your widget type and implement the
- // `iced_native::Widget` trait with the `iced_wgpu::Renderer`.
- //
- // Of course, you can choose to make the implementation renderer-agnostic,
- // if you wish to, by creating your own `Renderer` trait, which could be
- // implemented by `iced_wgpu` and other renderers.
- use iced_graphics::renderer::{self, Renderer};
- use iced_graphics::{Backend, Primitive};
- use iced_graphics::shader::Shader;
-
- use iced_native::widget::{self, Widget};
- use iced_native::{
- layout, Element, Layout, Length, Point, Rectangle, Size, Vector,
- };
-
- #[derive(Default)]
- pub struct Rainbow;
-
- impl Rainbow {
- pub fn new() -> Self {
- Self
- }
- }
-
- pub fn rainbow() -> Rainbow {
- Rainbow
- }
-
- impl<Message, B, T> Widget<Message, Renderer<B, T>> for Rainbow
- where
- B: Backend,
- {
- fn width(&self) -> Length {
- Length::Fill
- }
-
- fn height(&self) -> Length {
- Length::Shrink
- }
-
- fn layout(
- &self,
- _renderer: &Renderer<B, T>,
- limits: &layout::Limits,
- ) -> layout::Node {
- let size = limits.width(Length::Fill).resolve(Size::ZERO);
-
- layout::Node::new(Size::new(size.width, size.width))
- }
-
- fn draw(
- &self,
- _tree: &widget::Tree,
- renderer: &mut Renderer<B, T>,
- _theme: &T,
- _style: &renderer::Style,
- layout: Layout<'_>,
- cursor_position: Point,
- _viewport: &Rectangle,
- ) {
- use iced_graphics::triangle::{Mesh2D, Shader, Vertex2D};
- use iced_native::Renderer as _;
-
- let b = layout.bounds();
-
- // R O Y G B I V
- // let color_r = [1.0, 0.0, 0.0, 1.0];
- // let color_o = [1.0, 0.5, 0.0, 1.0];
- // let color_y = [1.0, 1.0, 0.0, 1.0];
- // let color_g = [0.0, 1.0, 0.0, 1.0];
- // let color_gb = [0.0, 1.0, 0.5, 1.0];
- // let color_b = [0.0, 0.2, 1.0, 1.0];
- // let color_i = [0.5, 0.0, 1.0, 1.0];
- // let color_v = [0.75, 0.0, 0.5, 1.0];
-
- let posn_center = {
- if b.contains(cursor_position) {
- [cursor_position.x - b.x, cursor_position.y - b.y]
- } else {
- [b.width / 2.0, b.height / 2.0]
- }
- };
-
- let posn_tl = [0.0, 0.0];
- let posn_t = [b.width / 2.0, 0.0];
- let posn_tr = [b.width, 0.0];
- let posn_r = [b.width, b.height / 2.0];
- let posn_br = [b.width, b.height];
- let posn_b = [(b.width / 2.0), b.height];
- let posn_bl = [0.0, b.height];
- let posn_l = [0.0, b.height / 2.0];
-
- let mesh = Primitive::Mesh2D {
- size: b.size(),
- buffers: Mesh2D {
- vertices: vec![
- Vertex2D {
- position: posn_center,
- // color: [1.0, 1.0, 1.0, 1.0],
- },
- Vertex2D {
- position: posn_tl,
- // color: color_r,
- },
- Vertex2D {
- position: posn_t,
- // color: color_o,
- },
- Vertex2D {
- position: posn_tr,
- // color: color_y,
- },
- Vertex2D {
- position: posn_r,
- // color: color_g,
- },
- Vertex2D {
- position: posn_br,
- // color: color_gb,
- },
- Vertex2D {
- position: posn_b,
- // color: color_b,
- },
- Vertex2D {
- position: posn_bl,
- // color: color_i,
- },
- Vertex2D {
- position: posn_l,
- // color: color_v,
- },
- ],
- indices: vec![
- 0, 1, 2, // TL
- 0, 2, 3, // T
- 0, 3, 4, // TR
- 0, 4, 5, // R
- 0, 5, 6, // BR
- 0, 6, 7, // B
- 0, 7, 8, // BL
- 0, 8, 1, // L
- ],
- },
- shader: Shader::Solid(Color::BLACK),
- };
-
- renderer.with_translation(Vector::new(b.x, b.y), |renderer| {
- renderer.draw_primitive(mesh);
- });
- }
- }
-
- impl<'a, Message, B, T> From<Rainbow> for Element<'a, Message, Renderer<B, T>>
- where
- B: Backend,
- {
- fn from(rainbow: Rainbow) -> Self {
- Self::new(rainbow)
- }
- }
-}
-
-use iced::widget::{column, container, scrollable};
-use iced::{Alignment, Element, Length, Sandbox, Settings};
-use rainbow::rainbow;
-
-pub fn main() -> iced::Result {
- Example::run(Settings::default())
-}
-
-struct Example;
-
-impl Sandbox for Example {
- type Message = ();
-
- fn new() -> Self {
- Example
- }
-
- fn title(&self) -> String {
- String::from("Custom 2D geometry - Iced")
- }
-
- fn update(&mut self, _: ()) {}
-
- fn view(&self) -> Element<()> {
- let content = column![
- rainbow(),
- "In this example we draw a custom widget Rainbow, using \
- the Mesh2D primitive. This primitive supplies a list of \
- triangles, expressed as vertices and indices.",
- "Move your cursor over it, and see the center vertex \
- follow you!",
- "Every Vertex2D defines its own color. You could use the \
- Mesh2D primitive to render virtually any two-dimensional \
- geometry for your widget.",
- ]
- .padding(20)
- .spacing(20)
- .max_width(500)
- .align_items(Alignment::Start);
-
- let scrollable =
- scrollable(container(content).width(Length::Fill).center_x());
-
- container(scrollable)
- .width(Length::Fill)
- .height(Length::Fill)
- .center_y()
- .into()
- }
-}
diff --git a/examples/modern_art/src/main.rs b/examples/modern_art/src/main.rs
index 238c9a0f..14e117b3 100644
--- a/examples/modern_art/src/main.rs
+++ b/examples/modern_art/src/main.rs
@@ -1,14 +1,13 @@
use rand::{Rng, thread_rng};
use crate::canvas::{Cursor, Geometry};
-use iced::widget::canvas::{Cache, Fill, Frame};
+use iced::widget::canvas::{Cache, Fill, Frame, Gradient};
use iced::widget::{canvas, Canvas};
use iced::Settings;
use iced::{
executor, Application, Color, Command, Element, Length, Point, Rectangle,
Renderer, Size, Theme,
};
-use iced_graphics::gradient::Gradient;
-use iced_graphics::widget::canvas::Style;
+use iced_graphics::widget::canvas::fill;
fn main() -> iced::Result {
ModernArt::run(Settings {
@@ -121,7 +120,7 @@ fn generate_box(frame: &mut Frame, bounds: Size) -> bool {
top_left,
size,
Fill {
- style: Style::Solid(random_color()),
+ style: fill::Style::Solid(random_color()),
.. Default::default()
}
);
@@ -130,7 +129,7 @@ fn generate_box(frame: &mut Frame, bounds: Size) -> bool {
top_left,
size,
Fill {
- style: Style::Gradient(&gradient(
+ style: fill::Style::Gradient(&gradient(
top_left,
Point::new(top_left.x + size.width, top_left.y + size.height)
)),
diff --git a/glow/src/triangle.rs b/glow/src/triangle.rs
index f16f8af4..5e58f4e4 100644
--- a/glow/src/triangle.rs
+++ b/glow/src/triangle.rs
@@ -5,13 +5,13 @@ mod solid;
use crate::{program, Transformation};
use glow::HasContext;
use iced_graphics::layer::{attribute_count_of, Mesh};
-use iced_graphics::shader;
use std::marker::PhantomData;
+use iced_graphics::layer;
use crate::triangle::gradient::GradientProgram;
use crate::triangle::solid::SolidProgram;
pub use iced_graphics::triangle::{Mesh2D, Vertex2D};
-use shader::Shader;
+use layer::mesh;
#[derive(Debug)]
pub(crate) struct Pipeline {
@@ -139,11 +139,11 @@ impl Pipeline {
clip_bounds.height as i32,
);
- match mesh.shader {
- Shader::Solid(color) => {
+ match mesh.style {
+ mesh::Style::Solid(color) => {
self.programs.solid.use_program(gl, &color, &transform);
}
- Shader::Gradient(gradient) => {
+ mesh::Style::Gradient(gradient) => {
self.programs.gradient.use_program(gl, &gradient, &transform);
}
}
diff --git a/graphics/src/gradient.rs b/graphics/src/gradient.rs
index 0c394e8b..33453c67 100644
--- a/graphics/src/gradient.rs
+++ b/graphics/src/gradient.rs
@@ -1,4 +1,6 @@
//! For creating a Gradient.
+mod linear;
+
use iced_native::Color;
pub use crate::gradient::linear::Linear;
use crate::Point;
@@ -28,76 +30,3 @@ impl Gradient {
}
}
-/// Linear gradient builder & definition.
-pub mod linear {
- use crate::gradient::{ColorStop, Gradient};
- use crate::{Color, Point};
-
- /// A linear gradient that can be used in the style of [`super::Fill`] or [`super::Stroke`].
- #[derive(Debug, Clone, PartialEq)]
- pub struct Linear {
- /// The point where the linear gradient begins.
- pub start: Point,
- /// The point where the linear gradient ends.
- pub end: Point,
- /// [`ColorStop`]s along the linear gradient path.
- pub color_stops: Vec<ColorStop>,
- }
-
- /// A [`Linear`] builder.
- #[derive(Debug)]
- pub struct Builder {
- start: Point,
- end: Point,
- stops: Vec<(f32, Color)>,
- valid: bool,
- }
-
- impl Builder {
- /// Creates a new [`Builder`].
- pub fn new(start: Point, end: Point) -> Self {
- Self {
- start,
- end,
- stops: vec![],
- valid: true,
- }
- }
-
- /// Adds a new stop, defined by an offset and a color, to the gradient.
- ///
- /// `offset` must be between `0.0` and `1.0`.
- pub fn add_stop(mut self, offset: f32, color: Color) -> Self {
- if !(0.0..=1.0).contains(&offset) {
- self.valid = false;
- }
-
- self.stops.push((offset, color));
- self
- }
-
- /// Builds the linear [`Gradient`] of this [`Builder`].
- ///
- /// Returns `None` if no stops were added to the builder or
- /// if stops not between 0.0 and 1.0 were added.
- pub fn build(self) -> Option<Gradient> {
- if self.stops.is_empty() || !self.valid {
- return None;
- }
-
- let mut stops: Vec<ColorStop> = self.stops.clone().into_iter().map(|f| ColorStop {
- offset: f.0,
- color: f.1
- }).collect();
-
- stops.sort_by(|a, b| a.offset.partial_cmp(&b.offset).unwrap());
-
- Some(Gradient::Linear(Linear {
- start: self.start,
- end: self.end,
- color_stops: stops
- }))
- }
- }
-}
-
diff --git a/graphics/src/gradient/linear.rs b/graphics/src/gradient/linear.rs
new file mode 100644
index 00000000..00f94adc
--- /dev/null
+++ b/graphics/src/gradient/linear.rs
@@ -0,0 +1,71 @@
+//! Linear gradient builder & definition.
+
+use crate::gradient::{ColorStop, Gradient};
+use crate::{Color, Point};
+
+/// A linear gradient that can be used in the style of [`super::Fill`] or [`super::Stroke`].
+#[derive(Debug, Clone, PartialEq)]
+pub struct Linear {
+ /// The point where the linear gradient begins.
+ pub start: Point,
+ /// The point where the linear gradient ends.
+ pub end: Point,
+ /// [`ColorStop`]s along the linear gradient path.
+ pub color_stops: Vec<ColorStop>,
+}
+
+/// A [`Linear`] builder.
+#[derive(Debug)]
+pub struct Builder {
+ start: Point,
+ end: Point,
+ stops: Vec<(f32, Color)>,
+ valid: bool,
+}
+
+impl Builder {
+ /// Creates a new [`Builder`].
+ pub fn new(start: Point, end: Point) -> Self {
+ Self {
+ start,
+ end,
+ stops: vec![],
+ valid: true,
+ }
+ }
+
+ /// Adds a new stop, defined by an offset and a color, to the gradient.
+ ///
+ /// `offset` must be between `0.0` and `1.0`.
+ pub fn add_stop(mut self, offset: f32, color: Color) -> Self {
+ if !(0.0..=1.0).contains(&offset) {
+ self.valid = false;
+ }
+
+ self.stops.push((offset, color));
+ self
+ }
+
+ /// Builds the linear [`Gradient`] of this [`Builder`].
+ ///
+ /// Returns `None` if no stops were added to the builder or
+ /// if stops not between 0.0 and 1.0 were added.
+ pub fn build(self) -> Option<Gradient> {
+ if self.stops.is_empty() || !self.valid {
+ return None;
+ }
+
+ let mut stops: Vec<ColorStop> = self.stops.clone().into_iter().map(|f| ColorStop {
+ offset: f.0,
+ color: f.1
+ }).collect();
+
+ stops.sort_by(|a, b| a.offset.partial_cmp(&b.offset).unwrap());
+
+ Some(Gradient::Linear(Linear {
+ start: self.start,
+ end: self.end,
+ color_stops: stops
+ }))
+ }
+} \ No newline at end of file
diff --git a/graphics/src/layer.rs b/graphics/src/layer.rs
index 096c50dc..65e70cb3 100644
--- a/graphics/src/layer.rs
+++ b/graphics/src/layer.rs
@@ -1,13 +1,17 @@
//! Organize rendering primitives into a flattened list of layers.
+pub mod mesh;
+mod quad;
+mod text;
+mod image;
+
use crate::alignment;
-use crate::triangle;
use crate::{
Background, Font, Point, Primitive, Rectangle, Size, Vector, Viewport,
};
-
-use iced_native::image;
-use iced_native::svg;
-use crate::shader::Shader;
+pub use crate::layer::image::Image;
+pub use crate::layer::mesh::Mesh;
+pub use crate::layer::quad::Quad;
+pub use crate::layer::text::Text;
/// A group of primitives that should be clipped together.
#[derive(Debug)]
@@ -163,7 +167,7 @@ impl<'a> Layer<'a> {
Primitive::Mesh2D {
buffers,
size,
- shader,
+ style,
} => {
let layer = &mut layers[current_layer];
@@ -179,7 +183,7 @@ impl<'a> Layer<'a> {
origin: Point::new(translation.x, translation.y),
buffers,
clip_bounds,
- shader,
+ style,
}
);
}
@@ -242,99 +246,6 @@ impl<'a> Layer<'a> {
}
}
-/// A colored rectangle with a border.
-///
-/// This type can be directly uploaded to GPU memory.
-#[derive(Debug, Clone, Copy)]
-#[repr(C)]
-pub struct Quad {
- /// The position of the [`Quad`].
- pub position: [f32; 2],
-
- /// The size of the [`Quad`].
- pub size: [f32; 2],
-
- /// The color of the [`Quad`], in __linear RGB__.
- pub color: [f32; 4],
-
- /// The border color of the [`Quad`], in __linear RGB__.
- pub border_color: [f32; 4],
-
- /// The border radius of the [`Quad`].
- pub border_radius: f32,
-
- /// The border width of the [`Quad`].
- pub border_width: f32,
-}
-
-/// A mesh of triangles.
-#[derive(Debug, Clone, Copy)]
-pub struct Mesh<'a> {
- /// The origin of the vertices of the [`Mesh`].
- pub origin: Point,
-
- /// The vertex and index buffers of the [`Mesh`].
- pub buffers: &'a triangle::Mesh2D,
-
- /// The clipping bounds of the [`Mesh`].
- pub clip_bounds: Rectangle<f32>,
-
- /// The shader of the [`Mesh`].
- pub shader: &'a Shader,
-}
-
-/// A paragraph of text.
-#[derive(Debug, Clone, Copy)]
-pub struct Text<'a> {
- /// The content of the [`Text`].
- pub content: &'a str,
-
- /// The layout bounds of the [`Text`].
- pub bounds: Rectangle,
-
- /// The color of the [`Text`], in __linear RGB_.
- pub color: [f32; 4],
-
- /// The size of the [`Text`].
- pub size: f32,
-
- /// The font of the [`Text`].
- pub font: Font,
-
- /// The horizontal alignment of the [`Text`].
- pub horizontal_alignment: alignment::Horizontal,
-
- /// The vertical alignment of the [`Text`].
- pub vertical_alignment: alignment::Vertical,
-}
-
-/// 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 bounds of the image.
- bounds: Rectangle,
- },
- /// A vector image.
- Vector {
- /// The handle of a vector image.
- handle: svg::Handle,
-
- /// The bounds of the image.
- bounds: Rectangle,
- },
-}
-
-#[allow(unsafe_code)]
-unsafe impl bytemuck::Zeroable for Quad {}
-
-#[allow(unsafe_code)]
-unsafe impl bytemuck::Pod for Quad {}
-
/// Returns the number of total vertices & total indices of all [`Mesh`]es.
pub fn attribute_count_of<'a>(meshes: &'a [Mesh<'a>]) -> (usize, usize) {
meshes
diff --git a/graphics/src/layer/image.rs b/graphics/src/layer/image.rs
new file mode 100644
index 00000000..387b60ed
--- /dev/null
+++ b/graphics/src/layer/image.rs
@@ -0,0 +1,23 @@
+use iced_native::{image, svg};
+use crate::Rectangle;
+
+/// 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 bounds of the image.
+ bounds: Rectangle,
+ },
+ /// A vector image.
+ Vector {
+ /// The handle of a vector image.
+ handle: svg::Handle,
+
+ /// The bounds of the image.
+ bounds: Rectangle,
+ },
+} \ No newline at end of file
diff --git a/graphics/src/layer/mesh.rs b/graphics/src/layer/mesh.rs
new file mode 100644
index 00000000..a025675a
--- /dev/null
+++ b/graphics/src/layer/mesh.rs
@@ -0,0 +1,39 @@
+//! A collection of triangle primitives.
+
+use crate::{Color, Point, Rectangle, triangle};
+use crate::gradient::Gradient;
+
+/// A mesh of triangles.
+#[derive(Debug, Clone, Copy)]
+pub struct Mesh<'a> {
+ /// The origin of the vertices of the [`Mesh`].
+ pub origin: Point,
+
+ /// The vertex and index buffers of the [`Mesh`].
+ pub buffers: &'a triangle::Mesh2D,
+
+ /// The clipping bounds of the [`Mesh`].
+ pub clip_bounds: Rectangle<f32>,
+
+ /// The shader of the [`Mesh`].
+ pub style: &'a Style,
+}
+
+#[derive(Debug, Clone)]
+/// Supported shaders for primitives.
+pub enum Style {
+ /// Fill a primitive with a solid color.
+ Solid(Color),
+ /// Fill a primitive with an interpolated color.
+ Gradient(Gradient)
+}
+
+impl <'a> Into<Style> for Gradient {
+ fn into(self) -> Style {
+ match self {
+ Gradient::Linear(linear) => {
+ Style::Gradient(Gradient::Linear(linear))
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/graphics/src/layer/quad.rs b/graphics/src/layer/quad.rs
new file mode 100644
index 00000000..4380fb6c
--- /dev/null
+++ b/graphics/src/layer/quad.rs
@@ -0,0 +1,30 @@
+/// A colored rectangle with a border.
+///
+/// This type can be directly uploaded to GPU memory.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct Quad {
+ /// The position of the [`Quad`].
+ pub position: [f32; 2],
+
+ /// The size of the [`Quad`].
+ pub size: [f32; 2],
+
+ /// The color of the [`Quad`], in __linear RGB__.
+ pub color: [f32; 4],
+
+ /// The border color of the [`Quad`], in __linear RGB__.
+ pub border_color: [f32; 4],
+
+ /// The border radius of the [`Quad`].
+ pub border_radius: f32,
+
+ /// The border width of the [`Quad`].
+ pub border_width: f32,
+}
+
+#[allow(unsafe_code)]
+unsafe impl bytemuck::Zeroable for Quad {}
+
+#[allow(unsafe_code)]
+unsafe impl bytemuck::Pod for Quad {} \ No newline at end of file
diff --git a/graphics/src/layer/text.rs b/graphics/src/layer/text.rs
new file mode 100644
index 00000000..b6dd4b7f
--- /dev/null
+++ b/graphics/src/layer/text.rs
@@ -0,0 +1,26 @@
+use crate::{alignment, Font, Rectangle};
+
+/// A paragraph of text.
+#[derive(Debug, Clone, Copy)]
+pub struct Text<'a> {
+ /// The content of the [`Text`].
+ pub content: &'a str,
+
+ /// The layout bounds of the [`Text`].
+ pub bounds: Rectangle,
+
+ /// The color of the [`Text`], in __linear RGB_.
+ pub color: [f32; 4],
+
+ /// The size of the [`Text`].
+ pub size: f32,
+
+ /// The font of the [`Text`].
+ pub font: Font,
+
+ /// The horizontal alignment of the [`Text`].
+ pub horizontal_alignment: alignment::Horizontal,
+
+ /// The vertical alignment of the [`Text`].
+ pub vertical_alignment: alignment::Vertical,
+} \ No newline at end of file
diff --git a/graphics/src/lib.rs b/graphics/src/lib.rs
index ce9b1b07..0d29416c 100644
--- a/graphics/src/lib.rs
+++ b/graphics/src/lib.rs
@@ -35,7 +35,6 @@ pub mod renderer;
pub mod triangle;
pub mod widget;
pub mod window;
-pub mod shader;
pub mod gradient;
pub use antialiasing::Antialiasing;
diff --git a/graphics/src/primitive.rs b/graphics/src/primitive.rs
index 4f79a74c..10c86ad2 100644
--- a/graphics/src/primitive.rs
+++ b/graphics/src/primitive.rs
@@ -2,10 +2,11 @@ use iced_native::image;
use iced_native::svg;
use iced_native::{Background, Color, Font, Rectangle, Size, Vector};
-use crate::{alignment, shader};
+use crate::{alignment, layer};
use crate::triangle;
use std::sync::Arc;
+use layer::mesh;
/// A rendering primitive.
#[derive(Debug, Clone)]
@@ -90,7 +91,7 @@ pub enum Primitive {
size: Size,
/// The shader of the mesh
- shader: shader::Shader,
+ style: mesh::Style,
},
/// A cached primitive.
///
diff --git a/graphics/src/shader.rs b/graphics/src/shader.rs
deleted file mode 100644
index 69679e9b..00000000
--- a/graphics/src/shader.rs
+++ /dev/null
@@ -1,23 +0,0 @@
-//! Supported shaders;
-
-use crate::Color;
-use crate::gradient::Gradient;
-
-#[derive(Debug, Clone)]
-/// Supported shaders for primitives.
-pub enum Shader {
- /// Fill a primitive with a solid color.
- Solid(Color),
- /// Fill a primitive with an interpolated color.
- Gradient(Gradient)
-}
-
-impl <'a> Into<Shader> for Gradient {
- fn into(self) -> Shader {
- match self {
- Gradient::Linear(linear) => {
- Shader::Gradient(Gradient::Linear(linear))
- }
- }
- }
-} \ No newline at end of file
diff --git a/graphics/src/widget/canvas.rs b/graphics/src/widget/canvas.rs
index f6929e97..6ed3a12f 100644
--- a/graphics/src/widget/canvas.rs
+++ b/graphics/src/widget/canvas.rs
@@ -9,17 +9,17 @@ pub mod path;
mod cache;
mod cursor;
-mod fill;
mod frame;
mod geometry;
mod program;
-mod stroke;
mod text;
+pub mod fill;
+pub mod stroke;
pub use cache::Cache;
pub use cursor::Cursor;
pub use event::Event;
-pub use fill::{Fill, FillRule, Style};
+pub use fill::{Fill, FillRule};
pub use frame::Frame;
pub use geometry::Geometry;
pub use path::Path;
@@ -37,6 +37,8 @@ use iced_native::{
Clipboard, Element, Length, Point, Rectangle, Shell, Size, Vector, Widget,
};
+pub use crate::gradient::Gradient;
+
use std::marker::PhantomData;
/// A widget capable of drawing 2D graphics.
diff --git a/graphics/src/widget/canvas/fill.rs b/graphics/src/widget/canvas/fill.rs
index 6f10505c..55cb3966 100644
--- a/graphics/src/widget/canvas/fill.rs
+++ b/graphics/src/widget/canvas/fill.rs
@@ -1,6 +1,8 @@
-use iced_native::Color;
+//! Fill [crate::widget::canvas::Geometry] with a certain style.
+
use crate::gradient::Gradient;
-use crate::shader::Shader;
+use crate::layer::mesh;
+use iced_native::Color;
/// The style used to fill geometry.
#[derive(Debug, Clone)]
@@ -21,7 +23,7 @@ pub struct Fill<'a> {
pub rule: FillRule,
}
-impl <'a> Default for Fill<'a> {
+impl<'a> Default for Fill<'a> {
fn default() -> Fill<'a> {
Fill {
style: Style::Solid(Color::BLACK),
@@ -48,11 +50,11 @@ pub enum Style<'a> {
Gradient(&'a Gradient),
}
-impl <'a> Into<Shader> for Style<'a> {
- fn into(self) -> Shader {
+impl<'a> Into<mesh::Style> for Style<'a> {
+ fn into(self) -> mesh::Style {
match self {
- Style::Solid(color) => Shader::Solid(color),
- Style::Gradient(gradient) => gradient.clone().into()
+ Style::Solid(color) => mesh::Style::Solid(color),
+ Style::Gradient(gradient) => gradient.clone().into(),
}
}
}
diff --git a/graphics/src/widget/canvas/frame.rs b/graphics/src/widget/canvas/frame.rs
index 30239b2a..6517d62a 100644
--- a/graphics/src/widget/canvas/frame.rs
+++ b/graphics/src/widget/canvas/frame.rs
@@ -6,7 +6,7 @@ use crate::triangle;
use crate::widget::canvas::{path, Fill, Geometry, Path, Stroke, Text};
use crate::Primitive;
-use crate::shader::Shader;
+use crate::layer::mesh;
use crate::triangle::Vertex2D;
use lyon::tessellation;
use lyon::tessellation::geometry_builder::Positions;
@@ -17,7 +17,10 @@ use lyon::tessellation::geometry_builder::Positions;
#[allow(missing_debug_implementations)]
pub struct Frame {
size: Size,
- buffers: Vec<(tessellation::VertexBuffers<lyon::math::Point, u32>, Shader)>,
+ buffers: Vec<(
+ tessellation::VertexBuffers<lyon::math::Point, u32>,
+ mesh::Style,
+ )>,
primitives: Vec<Primitive>,
transforms: Transforms,
fill_tessellator: tessellation::FillTessellator,
@@ -109,7 +112,8 @@ impl Frame {
&options,
&mut buffers,
)
- }.expect("Tessellate path.");
+ }
+ .expect("Tessellate path.");
self.buffers.push((buf, style.into()))
}
@@ -126,7 +130,8 @@ impl Frame {
let mut buf = tessellation::VertexBuffers::new();
- let mut buffers = tessellation::BuffersBuilder::new(&mut buf, Positions);
+ let mut buffers =
+ tessellation::BuffersBuilder::new(&mut buf, Positions);
let top_left =
self.transforms.current.raw.transform_point(
@@ -159,7 +164,8 @@ impl Frame {
let mut buf = tessellation::VertexBuffers::new();
- let mut buffers = tessellation::BuffersBuilder::new(&mut buf, Positions);
+ let mut buffers =
+ tessellation::BuffersBuilder::new(&mut buf, Positions);
let mut options = tessellation::StrokeOptions::default();
options.line_width = stroke.width;
@@ -187,7 +193,8 @@ impl Frame {
&options,
&mut buffers,
)
- }.expect("Stroke path");
+ }
+ .expect("Stroke path");
self.buffers.push((buf, stroke.style.into()))
}
@@ -331,7 +338,7 @@ impl Frame {
}
fn into_primitives(mut self) -> Vec<Primitive> {
- for (buffer, shader) in self.buffers {
+ for (buffer, style) in self.buffers {
if !buffer.indices.is_empty() {
self.primitives.push(Primitive::Mesh2D {
buffers: triangle::Mesh2D {
@@ -339,7 +346,7 @@ impl Frame {
indices: buffer.indices,
},
size: self.size,
- shader,
+ style,
})
}
}
@@ -350,5 +357,10 @@ impl Frame {
/// Converts from [`lyon::math::Point`] to [`Vertex2D`]. Used for generating primitives.
fn vertices_from(points: Vec<lyon::math::Point>) -> Vec<Vertex2D> {
- points.iter().map(|p| Vertex2D { position: [p.x, p.y]}).collect()
-} \ No newline at end of file
+ points
+ .iter()
+ .map(|p| Vertex2D {
+ position: [p.x, p.y],
+ })
+ .collect()
+}
diff --git a/graphics/src/widget/canvas/stroke.rs b/graphics/src/widget/canvas/stroke.rs
index 7ce5ff1d..a19937ea 100644
--- a/graphics/src/widget/canvas/stroke.rs
+++ b/graphics/src/widget/canvas/stroke.rs
@@ -1,6 +1,8 @@
+//! Create lines from a [crate::widget::canvas::Path] and render with various attributes/styles.
+
use iced_native::Color;
use crate::gradient::Gradient;
-use crate::shader::Shader;
+use crate::layer::mesh;
/// The style of a stroke.
#[derive(Debug, Clone)]
@@ -66,10 +68,10 @@ pub enum Style<'a> {
Gradient(&'a Gradient),
}
-impl <'a> Into<Shader> for Style<'a> {
- fn into(self) -> Shader {
+impl <'a> Into<mesh::Style> for Style<'a> {
+ fn into(self) -> mesh::Style {
match self {
- Style::Solid(color) => Shader::Solid(color),
+ Style::Solid(color) => mesh::Style::Solid(color),
Style::Gradient(gradient) => gradient.clone().into()
}
}
diff --git a/wgpu/src/buffers.rs b/wgpu/src/buffers.rs
index f94d175d..fd6ca244 100644
--- a/wgpu/src/buffers.rs
+++ b/wgpu/src/buffers.rs
@@ -1,3 +1,123 @@
//! Utilities for buffer operations.
-pub mod buffer;
-pub mod dynamic_buffers; \ No newline at end of file
+pub mod dynamic;
+
+use bytemuck::{Pod, Zeroable};
+use std::marker::PhantomData;
+use std::mem;
+
+//128 triangles/indices
+const DEFAULT_STATIC_BUFFER_COUNT: wgpu::BufferAddress = 128;
+
+/// A generic buffer struct useful for items which have no alignment requirements
+/// (e.g. Vertex, Index buffers) and are set once and never changed until destroyed.
+#[derive(Debug)]
+pub(crate) struct StaticBuffer<T> {
+ //stored sequentially per mesh iteration; refers to the offset index in the GPU buffer
+ offsets: Vec<wgpu::BufferAddress>,
+ label: &'static str,
+ usages: wgpu::BufferUsages,
+ gpu: wgpu::Buffer,
+ //the static size of the buffer
+ size: wgpu::BufferAddress,
+ _data: PhantomData<T>,
+}
+
+impl<T: Pod + Zeroable> StaticBuffer<T> {
+ /// Initialize a new static buffer.
+ pub fn new(
+ device: &wgpu::Device,
+ label: &'static str,
+ usages: wgpu::BufferUsages,
+ ) -> Self {
+ let size = (mem::size_of::<T>() as u64) * DEFAULT_STATIC_BUFFER_COUNT;
+
+ Self {
+ offsets: Vec::new(),
+ label,
+ usages,
+ gpu: Self::gpu_buffer(device, label, size, usages),
+ size,
+ _data: Default::default(),
+ }
+ }
+
+ fn gpu_buffer(
+ device: &wgpu::Device,
+ label: &'static str,
+ size: wgpu::BufferAddress,
+ usage: wgpu::BufferUsages,
+ ) -> wgpu::Buffer {
+ device.create_buffer(&wgpu::BufferDescriptor {
+ label: Some(label),
+ size,
+ usage,
+ mapped_at_creation: false,
+ })
+ }
+
+ /// Returns whether or not the buffer needs to be recreated. This can happen whenever mesh data
+ /// changes & a redraw is requested.
+ pub fn recreate_if_needed(
+ &mut self,
+ device: &wgpu::Device,
+ new_count: usize,
+ ) -> bool {
+ let size =
+ wgpu::BufferAddress::from((mem::size_of::<T>() * new_count) as u64);
+
+ if self.size <= size {
+ self.offsets.clear();
+ self.size = size;
+ self.gpu = Self::gpu_buffer(device, self.label, size, self.usages);
+ true
+ } else {
+ false
+ }
+ }
+
+ /// Writes the current vertex data to the gpu buffer if it is currently writable with a memcpy &
+ /// stores its offset.
+ ///
+ /// This will return either the offset of the written bytes, or `None` if the GPU buffer is not
+ /// currently writable.
+ pub fn write(
+ &mut self,
+ device: &wgpu::Device,
+ staging_belt: &mut wgpu::util::StagingBelt,
+ encoder: &mut wgpu::CommandEncoder,
+ offset: u64,
+ content: &[T],
+ ) -> u64 {
+ let bytes = bytemuck::cast_slice(content);
+ let bytes_size = bytes.len() as u64;
+
+ if let Some(buffer_size) = wgpu::BufferSize::new(bytes_size as u64) {
+ let mut buffer = staging_belt.write_buffer(
+ encoder,
+ &self.gpu,
+ offset,
+ buffer_size,
+ device,
+ );
+
+ buffer.copy_from_slice(bytes);
+
+ self.offsets.push(offset);
+ }
+
+ bytes_size
+ }
+
+ fn offset_at(&self, index: usize) -> &wgpu::BufferAddress {
+ self.offsets
+ .get(index)
+ .expect("Offset at index does not exist.")
+ }
+
+ /// Returns the slice calculated from the offset stored at the given index.
+ /// e.g. to calculate the slice for the 2nd mesh in the layer, this would be the offset at index
+ /// 1 that we stored earlier when writing.
+ pub fn slice_from_index(&self, index: usize) -> wgpu::BufferSlice<'_> {
+ self.gpu.slice(self.offset_at(index)..)
+ }
+} \ No newline at end of file
diff --git a/wgpu/src/buffers/buffer.rs b/wgpu/src/buffers/buffer.rs
deleted file mode 100644
index a44120d3..00000000
--- a/wgpu/src/buffers/buffer.rs
+++ /dev/null
@@ -1,124 +0,0 @@
-//! Utilities for static buffer operations.
-use bytemuck::{Pod, Zeroable};
-use std::marker::PhantomData;
-use std::mem;
-
-//128 triangles/indices
-const DEFAULT_STATIC_BUFFER_COUNT: wgpu::BufferAddress = 128;
-
-/// A generic buffer struct useful for items which have no alignment requirements
-/// (e.g. Vertex, Index buffers) and are set once and never changed until destroyed.
-#[derive(Debug)]
-pub(crate) struct StaticBuffer<T> {
- //stored sequentially per mesh iteration; refers to the offset index in the GPU buffer
- offsets: Vec<wgpu::BufferAddress>,
- label: &'static str,
- usages: wgpu::BufferUsages,
- gpu: wgpu::Buffer,
- //the static size of the buffer
- size: wgpu::BufferAddress,
- _data: PhantomData<T>,
-}
-
-impl<T: Pod + Zeroable> StaticBuffer<T> {
- /// Initialize a new static buffer.
- pub fn new(
- device: &wgpu::Device,
- label: &'static str,
- usages: wgpu::BufferUsages,
- ) -> Self {
- let size = (mem::size_of::<T>() as u64) * DEFAULT_STATIC_BUFFER_COUNT;
-
- Self {
- offsets: Vec::new(),
- label,
- usages,
- gpu: Self::gpu_buffer(device, label, size, usages),
- size,
- _data: Default::default(),
- }
- }
-
- fn gpu_buffer(
- device: &wgpu::Device,
- label: &'static str,
- size: wgpu::BufferAddress,
- usage: wgpu::BufferUsages,
- ) -> wgpu::Buffer {
- device.create_buffer(&wgpu::BufferDescriptor {
- label: Some(label),
- size,
- usage,
- mapped_at_creation: false,
- })
- }
-
- /// Returns whether or not the buffer needs to be recreated. This can happen whenever mesh data
- /// changes & a redraw is requested.
- pub fn recreate_if_needed(
- &mut self,
- device: &wgpu::Device,
- new_count: usize,
- ) -> bool {
- let size =
- wgpu::BufferAddress::from((mem::size_of::<T>() * new_count) as u64);
-
- if self.size <= size {
- self.offsets.clear();
- self.size = size;
- self.gpu = Self::gpu_buffer(device, self.label, size, self.usages);
- true
- } else {
- false
- }
- }
-
- /// Writes the current vertex data to the gpu buffer if it is currently writable with a memcpy &
- /// stores its offset.
- ///
- /// This will return either the offset of the written bytes, or `None` if the GPU buffer is not
- /// currently writable.
- pub fn write(
- &mut self,
- device: &wgpu::Device,
- staging_belt: &mut wgpu::util::StagingBelt,
- encoder: &mut wgpu::CommandEncoder,
- offset: u64,
- content: &[T],
- ) -> u64 {
- let bytes = bytemuck::cast_slice(content);
- let bytes_size = bytes.len() as u64;
-
- if let Some(buffer_size) = wgpu::BufferSize::new(bytes_size as u64) {
- //offset has to be divisible by 8 for alignment reasons
- let actual_offset = if offset % 8 != 0 { offset + 4 } else { offset };
-
- let mut buffer = staging_belt.write_buffer(
- encoder,
- &self.gpu,
- actual_offset,
- buffer_size,
- device,
- );
-
- buffer.copy_from_slice(bytes);
-
- self.offsets.push(actual_offset);
- }
-
- bytes_size
- }
-
- fn offset_at(&self, index: usize) -> &wgpu::BufferAddress {
- self.offsets
- .get(index)
- .expect("Offset at index does not exist.")
- }
-
- /// Returns the slice calculated from the offset stored at the given index.
- /// e.g. to calculate the slice for the 2nd mesh in the layer, this would be the offset at index
- /// 1 that we stored earlier when writing.
- pub fn slice_from_index(&self, index: usize) -> wgpu::BufferSlice<'_> {
- self.gpu.slice(self.offset_at(index)..)
- }
-}
diff --git a/wgpu/src/buffers/dynamic_buffers.rs b/wgpu/src/buffers/dynamic.rs
index 75cc202c..75cc202c 100644
--- a/wgpu/src/buffers/dynamic_buffers.rs
+++ b/wgpu/src/buffers/dynamic.rs
diff --git a/wgpu/src/triangle.rs b/wgpu/src/triangle.rs
index df5e3132..c22f118c 100644
--- a/wgpu/src/triangle.rs
+++ b/wgpu/src/triangle.rs
@@ -4,13 +4,13 @@ use core::fmt;
use std::fmt::Formatter;
use iced_graphics::layer::{attribute_count_of, Mesh};
-use iced_graphics::shader::Shader;
-use iced_graphics::Size;
+use iced_graphics::{layer, Size};
-use crate::buffers::buffer::StaticBuffer;
+use crate::buffers::StaticBuffer;
use crate::triangle::gradient::GradientPipeline;
use crate::triangle::solid::SolidPipeline;
pub use iced_graphics::triangle::{Mesh2D, Vertex2D};
+use layer::mesh;
mod gradient;
mod msaa;
@@ -107,7 +107,9 @@ impl Pipeline {
//We are not currently using the return value of these functions as we have no system in
//place to calculate mesh diff, or to know whether or not that would be more performant for
//the majority of use cases. Therefore we will write GPU data every frame (for now).
- let _ = self.vertex_buffer.recreate_if_needed(device, total_vertices);
+ let _ = self
+ .vertex_buffer
+ .recreate_if_needed(device, total_vertices);
let _ = self.index_buffer.recreate_if_needed(device, total_indices);
//prepare dynamic buffers & data store for writing
@@ -144,11 +146,11 @@ impl Pipeline {
self.index_strides.push(mesh.buffers.indices.len() as u32);
//push uniform data to CPU buffers
- match mesh.shader {
- Shader::Solid(color) => {
+ match mesh.style {
+ mesh::Style::Solid(color) => {
self.pipelines.solid.push(transform, color);
}
- Shader::Gradient(gradient) => {
+ mesh::Style::Gradient(gradient) => {
self.pipelines.gradient.push(transform, gradient);
}
}
@@ -204,15 +206,15 @@ impl Pipeline {
clip_bounds.height,
);
- match mesh.shader {
- Shader::Solid(_) => {
+ match mesh.style {
+ mesh::Style::Solid(_) => {
self.pipelines.solid.configure_render_pass(
&mut render_pass,
num_solids,
);
num_solids += 1;
}
- Shader::Gradient(_) => {
+ mesh::Style::Gradient(_) => {
self.pipelines.gradient.configure_render_pass(
&mut render_pass,
num_gradients,
diff --git a/wgpu/src/triangle/gradient.rs b/wgpu/src/triangle/gradient.rs
index 15b6b7e0..e8c6d7db 100644
--- a/wgpu/src/triangle/gradient.rs
+++ b/wgpu/src/triangle/gradient.rs
@@ -1,4 +1,4 @@
-use crate::buffers::dynamic_buffers::DynamicBuffer;
+use crate::buffers::dynamic::DynamicBuffer;
use crate::settings;
use crate::triangle::{
default_fragment_target, default_multisample_state,
diff --git a/wgpu/src/triangle/solid.rs b/wgpu/src/triangle/solid.rs
index e7e9098a..d2b4d13b 100644
--- a/wgpu/src/triangle/solid.rs
+++ b/wgpu/src/triangle/solid.rs
@@ -1,4 +1,4 @@
-use crate::buffers::dynamic_buffers::DynamicBuffer;
+use crate::buffers::dynamic::DynamicBuffer;
use crate::triangle::{
default_fragment_target, default_multisample_state,
default_triangle_primitive_state, vertex_buffer_layout,