summaryrefslogtreecommitdiffstats
path: root/graphics/src/primitive.rs
diff options
context:
space:
mode:
Diffstat (limited to 'graphics/src/primitive.rs')
-rw-r--r--graphics/src/primitive.rs220
1 files changed, 184 insertions, 36 deletions
diff --git a/graphics/src/primitive.rs b/graphics/src/primitive.rs
index cef422a2..d4446c87 100644
--- a/graphics/src/primitive.rs
+++ b/graphics/src/primitive.rs
@@ -1,24 +1,17 @@
-use iced_native::image;
-use iced_native::svg;
-use iced_native::{Background, Color, Font, Rectangle, Size, Vector};
-
-use crate::alignment;
-use crate::gradient::Gradient;
-use crate::triangle;
+//! Draw using different graphical primitives.
+use crate::core::alignment;
+use crate::core::image;
+use crate::core::svg;
+use crate::core::text;
+use crate::core::{Background, Color, Font, Gradient, Rectangle, Size, Vector};
+use bytemuck::{Pod, Zeroable};
use std::sync::Arc;
/// A rendering primitive.
-#[derive(Debug, Clone, Default)]
+#[derive(Debug, Clone, PartialEq)]
+#[non_exhaustive]
pub enum Primitive {
- /// An empty primitive
- #[default]
- None,
- /// A group of primitives
- Group {
- /// The primitives of the group
- primitives: Vec<Primitive>,
- },
/// A text primitive
Text {
/// The contents of the text
@@ -27,14 +20,18 @@ pub enum Primitive {
bounds: Rectangle,
/// The color of the text
color: Color,
- /// The size of the text
+ /// The size of the text in logical pixels
size: f32,
+ /// The line height of the text
+ line_height: text::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: text::Shaping,
},
/// A quad primitive
Quad {
@@ -67,27 +64,12 @@ pub enum Primitive {
/// The bounds of the viewport
bounds: Rectangle,
},
- /// A clip primitive
- Clip {
- /// The bounds of the clip
- bounds: Rectangle,
- /// The content of the clip
- content: Box<Primitive>,
- },
- /// A primitive that applies a translation
- Translate {
- /// The translation vector
- translation: Vector,
-
- /// The primitive to translate
- content: Box<Primitive>,
- },
/// A low-level primitive to render a mesh of triangles with a solid color.
///
/// It can be used to render many kinds of geometry freely.
SolidMesh {
/// The vertices and indices of the mesh.
- buffers: triangle::Mesh2D<triangle::ColoredVertex2D>,
+ buffers: Mesh2D<ColoredVertex2D>,
/// The size of the drawable region of the mesh.
///
@@ -99,7 +81,7 @@ pub enum Primitive {
/// It can be used to render many kinds of geometry freely.
GradientMesh {
/// The vertices and indices of the mesh.
- buffers: triangle::Mesh2D<triangle::Vertex2D>,
+ buffers: Mesh2D<Vertex2D>,
/// The size of the drawable region of the mesh.
///
@@ -109,12 +91,178 @@ pub enum Primitive {
/// The [`Gradient`] to apply to the mesh.
gradient: Gradient,
},
+ /// A [`tiny_skia`] path filled with some paint.
+ #[cfg(feature = "tiny-skia")]
+ Fill {
+ /// The path to fill.
+ path: tiny_skia::Path,
+ /// The paint to use.
+ paint: tiny_skia::Paint<'static>,
+ /// The fill rule to follow.
+ rule: tiny_skia::FillRule,
+ /// The transform to apply to the path.
+ transform: tiny_skia::Transform,
+ },
+ /// A [`tiny_skia`] path stroked with some paint.
+ #[cfg(feature = "tiny-skia")]
+ Stroke {
+ /// The path to stroke.
+ path: tiny_skia::Path,
+ /// The paint to use.
+ paint: tiny_skia::Paint<'static>,
+ /// The stroke settings.
+ stroke: tiny_skia::Stroke,
+ /// The transform to apply to the path.
+ transform: tiny_skia::Transform,
+ },
+ /// A group of primitives
+ Group {
+ /// The primitives of the group
+ primitives: Vec<Primitive>,
+ },
+ /// A clip primitive
+ Clip {
+ /// The bounds of the clip
+ bounds: Rectangle,
+ /// The content of the clip
+ content: Box<Primitive>,
+ },
+ /// A primitive that applies a translation
+ Translate {
+ /// The translation vector
+ translation: Vector,
+
+ /// The primitive to translate
+ content: Box<Primitive>,
+ },
/// A cached primitive.
///
/// This can be useful if you are implementing a widget where primitive
/// generation is expensive.
- Cached {
+ Cache {
/// The cached primitive
- cache: Arc<Primitive>,
+ content: Arc<Primitive>,
},
}
+
+impl Primitive {
+ /// Creates a [`Primitive::Group`].
+ pub fn group(primitives: Vec<Self>) -> Self {
+ Self::Group { primitives }
+ }
+
+ /// Creates a [`Primitive::Clip`].
+ pub fn clip(self, bounds: Rectangle) -> Self {
+ Self::Clip {
+ bounds,
+ content: Box::new(self),
+ }
+ }
+
+ /// Creates a [`Primitive::Translate`].
+ pub fn translate(self, translation: Vector) -> Self {
+ Self::Translate {
+ translation,
+ content: Box::new(self),
+ }
+ }
+
+ /// Returns the bounds of the [`Primitive`].
+ pub fn bounds(&self) -> Rectangle {
+ match self {
+ Self::Text {
+ bounds,
+ horizontal_alignment,
+ vertical_alignment,
+ ..
+ } => {
+ let mut bounds = *bounds;
+
+ bounds.x = match horizontal_alignment {
+ alignment::Horizontal::Left => bounds.x,
+ alignment::Horizontal::Center => {
+ bounds.x - bounds.width / 2.0
+ }
+ alignment::Horizontal::Right => bounds.x - bounds.width,
+ };
+
+ bounds.y = match vertical_alignment {
+ alignment::Vertical::Top => bounds.y,
+ alignment::Vertical::Center => {
+ bounds.y - bounds.height / 2.0
+ }
+ alignment::Vertical::Bottom => bounds.y - bounds.height,
+ };
+
+ bounds.expand(1.5)
+ }
+ Self::Quad { bounds, .. }
+ | Self::Image { bounds, .. }
+ | Self::Svg { bounds, .. } => bounds.expand(1.0),
+ Self::Clip { bounds, .. } => bounds.expand(1.0),
+ Self::SolidMesh { size, .. } | Self::GradientMesh { size, .. } => {
+ Rectangle::with_size(*size)
+ }
+ #[cfg(feature = "tiny-skia")]
+ Self::Fill { path, .. } | Self::Stroke { path, .. } => {
+ let bounds = path.bounds();
+
+ Rectangle {
+ x: bounds.x(),
+ y: bounds.y(),
+ width: bounds.width(),
+ height: bounds.height(),
+ }
+ .expand(1.0)
+ }
+ Self::Group { primitives } => primitives
+ .iter()
+ .map(Self::bounds)
+ .fold(Rectangle::with_size(Size::ZERO), |a, b| {
+ Rectangle::union(&a, &b)
+ }),
+ Self::Translate {
+ translation,
+ content,
+ } => content.bounds() + *translation,
+ Self::Cache { content } => content.bounds(),
+ }
+ }
+}
+
+/// A set of [`Vertex2D`] and indices representing a list of triangles.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct Mesh2D<T> {
+ /// The vertices of the mesh
+ pub vertices: Vec<T>,
+
+ /// The list of vertex indices that defines the triangles of the mesh.
+ ///
+ /// Therefore, this list should always have a length that is a multiple of 3.
+ pub indices: Vec<u32>,
+}
+
+/// A two-dimensional vertex.
+#[derive(Copy, Clone, Debug, PartialEq, Zeroable, Pod)]
+#[repr(C)]
+pub struct Vertex2D {
+ /// The vertex position in 2D space.
+ pub position: [f32; 2],
+}
+
+/// A two-dimensional vertex with a color.
+#[derive(Copy, Clone, Debug, PartialEq, Zeroable, Pod)]
+#[repr(C)]
+pub struct ColoredVertex2D {
+ /// The vertex position in 2D space.
+ pub position: [f32; 2],
+
+ /// The color of the vertex in __linear__ RGBA.
+ pub color: [f32; 4],
+}
+
+impl From<()> for Primitive {
+ fn from(_: ()) -> Self {
+ Self::Group { primitives: vec![] }
+ }
+}