Readjusted namespaces, removed Geometry example as it's no longer relevant.
This commit is contained in:
parent
6e7b3ced0b
commit
30432cbade
27 changed files with 394 additions and 625 deletions
|
|
@ -69,7 +69,6 @@ members = [
|
||||||
"examples/events",
|
"examples/events",
|
||||||
"examples/exit",
|
"examples/exit",
|
||||||
"examples/game_of_life",
|
"examples/game_of_life",
|
||||||
"examples/geometry",
|
|
||||||
"examples/integration_opengl",
|
"examples/integration_opengl",
|
||||||
"examples/integration_wgpu",
|
"examples/integration_wgpu",
|
||||||
"examples/modern_art",
|
"examples/modern_art",
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use std::{f32::consts::PI, time::Instant};
|
||||||
|
|
||||||
use iced::executor;
|
use iced::executor;
|
||||||
use iced::widget::canvas::{
|
use iced::widget::canvas::{
|
||||||
self, Cache, Canvas, Cursor, Geometry, Path, Stroke, Style,
|
self, stroke, Cache, Canvas, Cursor, Geometry, Path, Stroke,
|
||||||
};
|
};
|
||||||
use iced::{
|
use iced::{
|
||||||
Application, Command, Element, Length, Point, Rectangle, Settings,
|
Application, Command, Element, Length, Point, Rectangle, Settings,
|
||||||
|
|
@ -114,7 +114,7 @@ impl<Message> canvas::Program<Message> for Arc {
|
||||||
frame.stroke(
|
frame.stroke(
|
||||||
&path,
|
&path,
|
||||||
Stroke {
|
Stroke {
|
||||||
style: Style::Solid(palette.text),
|
style: stroke::Style::Solid(palette.text),
|
||||||
width: 10.0,
|
width: 10.0,
|
||||||
..Stroke::default()
|
..Stroke::default()
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -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" }
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,14 +1,13 @@
|
||||||
use rand::{Rng, thread_rng};
|
use rand::{Rng, thread_rng};
|
||||||
use crate::canvas::{Cursor, Geometry};
|
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::widget::{canvas, Canvas};
|
||||||
use iced::Settings;
|
use iced::Settings;
|
||||||
use iced::{
|
use iced::{
|
||||||
executor, Application, Color, Command, Element, Length, Point, Rectangle,
|
executor, Application, Color, Command, Element, Length, Point, Rectangle,
|
||||||
Renderer, Size, Theme,
|
Renderer, Size, Theme,
|
||||||
};
|
};
|
||||||
use iced_graphics::gradient::Gradient;
|
use iced_graphics::widget::canvas::fill;
|
||||||
use iced_graphics::widget::canvas::Style;
|
|
||||||
|
|
||||||
fn main() -> iced::Result {
|
fn main() -> iced::Result {
|
||||||
ModernArt::run(Settings {
|
ModernArt::run(Settings {
|
||||||
|
|
@ -121,7 +120,7 @@ fn generate_box(frame: &mut Frame, bounds: Size) -> bool {
|
||||||
top_left,
|
top_left,
|
||||||
size,
|
size,
|
||||||
Fill {
|
Fill {
|
||||||
style: Style::Solid(random_color()),
|
style: fill::Style::Solid(random_color()),
|
||||||
.. Default::default()
|
.. Default::default()
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
@ -130,7 +129,7 @@ fn generate_box(frame: &mut Frame, bounds: Size) -> bool {
|
||||||
top_left,
|
top_left,
|
||||||
size,
|
size,
|
||||||
Fill {
|
Fill {
|
||||||
style: Style::Gradient(&gradient(
|
style: fill::Style::Gradient(&gradient(
|
||||||
top_left,
|
top_left,
|
||||||
Point::new(top_left.x + size.width, top_left.y + size.height)
|
Point::new(top_left.x + size.width, top_left.y + size.height)
|
||||||
)),
|
)),
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,13 @@ mod solid;
|
||||||
use crate::{program, Transformation};
|
use crate::{program, Transformation};
|
||||||
use glow::HasContext;
|
use glow::HasContext;
|
||||||
use iced_graphics::layer::{attribute_count_of, Mesh};
|
use iced_graphics::layer::{attribute_count_of, Mesh};
|
||||||
use iced_graphics::shader;
|
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
use iced_graphics::layer;
|
||||||
|
|
||||||
use crate::triangle::gradient::GradientProgram;
|
use crate::triangle::gradient::GradientProgram;
|
||||||
use crate::triangle::solid::SolidProgram;
|
use crate::triangle::solid::SolidProgram;
|
||||||
pub use iced_graphics::triangle::{Mesh2D, Vertex2D};
|
pub use iced_graphics::triangle::{Mesh2D, Vertex2D};
|
||||||
use shader::Shader;
|
use layer::mesh;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct Pipeline {
|
pub(crate) struct Pipeline {
|
||||||
|
|
@ -139,11 +139,11 @@ impl Pipeline {
|
||||||
clip_bounds.height as i32,
|
clip_bounds.height as i32,
|
||||||
);
|
);
|
||||||
|
|
||||||
match mesh.shader {
|
match mesh.style {
|
||||||
Shader::Solid(color) => {
|
mesh::Style::Solid(color) => {
|
||||||
self.programs.solid.use_program(gl, &color, &transform);
|
self.programs.solid.use_program(gl, &color, &transform);
|
||||||
}
|
}
|
||||||
Shader::Gradient(gradient) => {
|
mesh::Style::Gradient(gradient) => {
|
||||||
self.programs.gradient.use_program(gl, &gradient, &transform);
|
self.programs.gradient.use_program(gl, &gradient, &transform);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
//! For creating a Gradient.
|
//! For creating a Gradient.
|
||||||
|
mod linear;
|
||||||
|
|
||||||
use iced_native::Color;
|
use iced_native::Color;
|
||||||
pub use crate::gradient::linear::Linear;
|
pub use crate::gradient::linear::Linear;
|
||||||
use crate::Point;
|
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
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
||||||
71
graphics/src/gradient/linear.rs
Normal file
71
graphics/src/gradient/linear.rs
Normal file
|
|
@ -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
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,13 +1,17 @@
|
||||||
//! Organize rendering primitives into a flattened list of layers.
|
//! Organize rendering primitives into a flattened list of layers.
|
||||||
|
pub mod mesh;
|
||||||
|
mod quad;
|
||||||
|
mod text;
|
||||||
|
mod image;
|
||||||
|
|
||||||
use crate::alignment;
|
use crate::alignment;
|
||||||
use crate::triangle;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Background, Font, Point, Primitive, Rectangle, Size, Vector, Viewport,
|
Background, Font, Point, Primitive, Rectangle, Size, Vector, Viewport,
|
||||||
};
|
};
|
||||||
|
pub use crate::layer::image::Image;
|
||||||
use iced_native::image;
|
pub use crate::layer::mesh::Mesh;
|
||||||
use iced_native::svg;
|
pub use crate::layer::quad::Quad;
|
||||||
use crate::shader::Shader;
|
pub use crate::layer::text::Text;
|
||||||
|
|
||||||
/// A group of primitives that should be clipped together.
|
/// A group of primitives that should be clipped together.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
@ -163,7 +167,7 @@ impl<'a> Layer<'a> {
|
||||||
Primitive::Mesh2D {
|
Primitive::Mesh2D {
|
||||||
buffers,
|
buffers,
|
||||||
size,
|
size,
|
||||||
shader,
|
style,
|
||||||
} => {
|
} => {
|
||||||
let layer = &mut layers[current_layer];
|
let layer = &mut layers[current_layer];
|
||||||
|
|
||||||
|
|
@ -179,7 +183,7 @@ impl<'a> Layer<'a> {
|
||||||
origin: Point::new(translation.x, translation.y),
|
origin: Point::new(translation.x, translation.y),
|
||||||
buffers,
|
buffers,
|
||||||
clip_bounds,
|
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.
|
/// Returns the number of total vertices & total indices of all [`Mesh`]es.
|
||||||
pub fn attribute_count_of<'a>(meshes: &'a [Mesh<'a>]) -> (usize, usize) {
|
pub fn attribute_count_of<'a>(meshes: &'a [Mesh<'a>]) -> (usize, usize) {
|
||||||
meshes
|
meshes
|
||||||
|
|
|
||||||
23
graphics/src/layer/image.rs
Normal file
23
graphics/src/layer/image.rs
Normal file
|
|
@ -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,
|
||||||
|
},
|
||||||
|
}
|
||||||
39
graphics/src/layer/mesh.rs
Normal file
39
graphics/src/layer/mesh.rs
Normal file
|
|
@ -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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
30
graphics/src/layer/quad.rs
Normal file
30
graphics/src/layer/quad.rs
Normal file
|
|
@ -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 {}
|
||||||
26
graphics/src/layer/text.rs
Normal file
26
graphics/src/layer/text.rs
Normal file
|
|
@ -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,
|
||||||
|
}
|
||||||
|
|
@ -35,7 +35,6 @@ pub mod renderer;
|
||||||
pub mod triangle;
|
pub mod triangle;
|
||||||
pub mod widget;
|
pub mod widget;
|
||||||
pub mod window;
|
pub mod window;
|
||||||
pub mod shader;
|
|
||||||
pub mod gradient;
|
pub mod gradient;
|
||||||
|
|
||||||
pub use antialiasing::Antialiasing;
|
pub use antialiasing::Antialiasing;
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,11 @@ use iced_native::image;
|
||||||
use iced_native::svg;
|
use iced_native::svg;
|
||||||
use iced_native::{Background, Color, Font, Rectangle, Size, Vector};
|
use iced_native::{Background, Color, Font, Rectangle, Size, Vector};
|
||||||
|
|
||||||
use crate::{alignment, shader};
|
use crate::{alignment, layer};
|
||||||
use crate::triangle;
|
use crate::triangle;
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use layer::mesh;
|
||||||
|
|
||||||
/// A rendering primitive.
|
/// A rendering primitive.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
@ -90,7 +91,7 @@ pub enum Primitive {
|
||||||
size: Size,
|
size: Size,
|
||||||
|
|
||||||
/// The shader of the mesh
|
/// The shader of the mesh
|
||||||
shader: shader::Shader,
|
style: mesh::Style,
|
||||||
},
|
},
|
||||||
/// A cached primitive.
|
/// A cached primitive.
|
||||||
///
|
///
|
||||||
|
|
|
||||||
|
|
@ -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))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -9,17 +9,17 @@ pub mod path;
|
||||||
|
|
||||||
mod cache;
|
mod cache;
|
||||||
mod cursor;
|
mod cursor;
|
||||||
mod fill;
|
|
||||||
mod frame;
|
mod frame;
|
||||||
mod geometry;
|
mod geometry;
|
||||||
mod program;
|
mod program;
|
||||||
mod stroke;
|
|
||||||
mod text;
|
mod text;
|
||||||
|
pub mod fill;
|
||||||
|
pub mod stroke;
|
||||||
|
|
||||||
pub use cache::Cache;
|
pub use cache::Cache;
|
||||||
pub use cursor::Cursor;
|
pub use cursor::Cursor;
|
||||||
pub use event::Event;
|
pub use event::Event;
|
||||||
pub use fill::{Fill, FillRule, Style};
|
pub use fill::{Fill, FillRule};
|
||||||
pub use frame::Frame;
|
pub use frame::Frame;
|
||||||
pub use geometry::Geometry;
|
pub use geometry::Geometry;
|
||||||
pub use path::Path;
|
pub use path::Path;
|
||||||
|
|
@ -37,6 +37,8 @@ use iced_native::{
|
||||||
Clipboard, Element, Length, Point, Rectangle, Shell, Size, Vector, Widget,
|
Clipboard, Element, Length, Point, Rectangle, Shell, Size, Vector, Widget,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub use crate::gradient::Gradient;
|
||||||
|
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
/// A widget capable of drawing 2D graphics.
|
/// A widget capable of drawing 2D graphics.
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
use iced_native::Color;
|
//! Fill [crate::widget::canvas::Geometry] with a certain style.
|
||||||
|
|
||||||
use crate::gradient::Gradient;
|
use crate::gradient::Gradient;
|
||||||
use crate::shader::Shader;
|
use crate::layer::mesh;
|
||||||
|
use iced_native::Color;
|
||||||
|
|
||||||
/// The style used to fill geometry.
|
/// The style used to fill geometry.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
@ -21,7 +23,7 @@ pub struct Fill<'a> {
|
||||||
pub rule: FillRule,
|
pub rule: FillRule,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <'a> Default for Fill<'a> {
|
impl<'a> Default for Fill<'a> {
|
||||||
fn default() -> Fill<'a> {
|
fn default() -> Fill<'a> {
|
||||||
Fill {
|
Fill {
|
||||||
style: Style::Solid(Color::BLACK),
|
style: Style::Solid(Color::BLACK),
|
||||||
|
|
@ -48,11 +50,11 @@ pub enum Style<'a> {
|
||||||
Gradient(&'a Gradient),
|
Gradient(&'a Gradient),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <'a> Into<Shader> for Style<'a> {
|
impl<'a> Into<mesh::Style> for Style<'a> {
|
||||||
fn into(self) -> Shader {
|
fn into(self) -> mesh::Style {
|
||||||
match self {
|
match self {
|
||||||
Style::Solid(color) => Shader::Solid(color),
|
Style::Solid(color) => mesh::Style::Solid(color),
|
||||||
Style::Gradient(gradient) => gradient.clone().into()
|
Style::Gradient(gradient) => gradient.clone().into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ use crate::triangle;
|
||||||
use crate::widget::canvas::{path, Fill, Geometry, Path, Stroke, Text};
|
use crate::widget::canvas::{path, Fill, Geometry, Path, Stroke, Text};
|
||||||
use crate::Primitive;
|
use crate::Primitive;
|
||||||
|
|
||||||
use crate::shader::Shader;
|
use crate::layer::mesh;
|
||||||
use crate::triangle::Vertex2D;
|
use crate::triangle::Vertex2D;
|
||||||
use lyon::tessellation;
|
use lyon::tessellation;
|
||||||
use lyon::tessellation::geometry_builder::Positions;
|
use lyon::tessellation::geometry_builder::Positions;
|
||||||
|
|
@ -17,7 +17,10 @@ use lyon::tessellation::geometry_builder::Positions;
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
pub struct Frame {
|
pub struct Frame {
|
||||||
size: Size,
|
size: Size,
|
||||||
buffers: Vec<(tessellation::VertexBuffers<lyon::math::Point, u32>, Shader)>,
|
buffers: Vec<(
|
||||||
|
tessellation::VertexBuffers<lyon::math::Point, u32>,
|
||||||
|
mesh::Style,
|
||||||
|
)>,
|
||||||
primitives: Vec<Primitive>,
|
primitives: Vec<Primitive>,
|
||||||
transforms: Transforms,
|
transforms: Transforms,
|
||||||
fill_tessellator: tessellation::FillTessellator,
|
fill_tessellator: tessellation::FillTessellator,
|
||||||
|
|
@ -109,7 +112,8 @@ impl Frame {
|
||||||
&options,
|
&options,
|
||||||
&mut buffers,
|
&mut buffers,
|
||||||
)
|
)
|
||||||
}.expect("Tessellate path.");
|
}
|
||||||
|
.expect("Tessellate path.");
|
||||||
|
|
||||||
self.buffers.push((buf, style.into()))
|
self.buffers.push((buf, style.into()))
|
||||||
}
|
}
|
||||||
|
|
@ -126,7 +130,8 @@ impl Frame {
|
||||||
|
|
||||||
let mut buf = tessellation::VertexBuffers::new();
|
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 =
|
let top_left =
|
||||||
self.transforms.current.raw.transform_point(
|
self.transforms.current.raw.transform_point(
|
||||||
|
|
@ -159,7 +164,8 @@ impl Frame {
|
||||||
|
|
||||||
let mut buf = tessellation::VertexBuffers::new();
|
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();
|
let mut options = tessellation::StrokeOptions::default();
|
||||||
options.line_width = stroke.width;
|
options.line_width = stroke.width;
|
||||||
|
|
@ -187,7 +193,8 @@ impl Frame {
|
||||||
&options,
|
&options,
|
||||||
&mut buffers,
|
&mut buffers,
|
||||||
)
|
)
|
||||||
}.expect("Stroke path");
|
}
|
||||||
|
.expect("Stroke path");
|
||||||
|
|
||||||
self.buffers.push((buf, stroke.style.into()))
|
self.buffers.push((buf, stroke.style.into()))
|
||||||
}
|
}
|
||||||
|
|
@ -331,7 +338,7 @@ impl Frame {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn into_primitives(mut self) -> Vec<Primitive> {
|
fn into_primitives(mut self) -> Vec<Primitive> {
|
||||||
for (buffer, shader) in self.buffers {
|
for (buffer, style) in self.buffers {
|
||||||
if !buffer.indices.is_empty() {
|
if !buffer.indices.is_empty() {
|
||||||
self.primitives.push(Primitive::Mesh2D {
|
self.primitives.push(Primitive::Mesh2D {
|
||||||
buffers: triangle::Mesh2D {
|
buffers: triangle::Mesh2D {
|
||||||
|
|
@ -339,7 +346,7 @@ impl Frame {
|
||||||
indices: buffer.indices,
|
indices: buffer.indices,
|
||||||
},
|
},
|
||||||
size: self.size,
|
size: self.size,
|
||||||
shader,
|
style,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -350,5 +357,10 @@ impl Frame {
|
||||||
|
|
||||||
/// Converts from [`lyon::math::Point`] to [`Vertex2D`]. Used for generating primitives.
|
/// Converts from [`lyon::math::Point`] to [`Vertex2D`]. Used for generating primitives.
|
||||||
fn vertices_from(points: Vec<lyon::math::Point>) -> Vec<Vertex2D> {
|
fn vertices_from(points: Vec<lyon::math::Point>) -> Vec<Vertex2D> {
|
||||||
points.iter().map(|p| Vertex2D { position: [p.x, p.y]}).collect()
|
points
|
||||||
}
|
.iter()
|
||||||
|
.map(|p| Vertex2D {
|
||||||
|
position: [p.x, p.y],
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
|
//! Create lines from a [crate::widget::canvas::Path] and render with various attributes/styles.
|
||||||
|
|
||||||
use iced_native::Color;
|
use iced_native::Color;
|
||||||
use crate::gradient::Gradient;
|
use crate::gradient::Gradient;
|
||||||
use crate::shader::Shader;
|
use crate::layer::mesh;
|
||||||
|
|
||||||
/// The style of a stroke.
|
/// The style of a stroke.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
@ -66,10 +68,10 @@ pub enum Style<'a> {
|
||||||
Gradient(&'a Gradient),
|
Gradient(&'a Gradient),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <'a> Into<Shader> for Style<'a> {
|
impl <'a> Into<mesh::Style> for Style<'a> {
|
||||||
fn into(self) -> Shader {
|
fn into(self) -> mesh::Style {
|
||||||
match self {
|
match self {
|
||||||
Style::Solid(color) => Shader::Solid(color),
|
Style::Solid(color) => mesh::Style::Solid(color),
|
||||||
Style::Gradient(gradient) => gradient.clone().into()
|
Style::Gradient(gradient) => gradient.clone().into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,123 @@
|
||||||
//! Utilities for buffer operations.
|
//! Utilities for buffer operations.
|
||||||
pub mod buffer;
|
pub mod dynamic;
|
||||||
pub mod dynamic_buffers;
|
|
||||||
|
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)..)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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)..)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -4,13 +4,13 @@ use core::fmt;
|
||||||
use std::fmt::Formatter;
|
use std::fmt::Formatter;
|
||||||
|
|
||||||
use iced_graphics::layer::{attribute_count_of, Mesh};
|
use iced_graphics::layer::{attribute_count_of, Mesh};
|
||||||
use iced_graphics::shader::Shader;
|
use iced_graphics::{layer, Size};
|
||||||
use iced_graphics::Size;
|
|
||||||
|
|
||||||
use crate::buffers::buffer::StaticBuffer;
|
use crate::buffers::StaticBuffer;
|
||||||
use crate::triangle::gradient::GradientPipeline;
|
use crate::triangle::gradient::GradientPipeline;
|
||||||
use crate::triangle::solid::SolidPipeline;
|
use crate::triangle::solid::SolidPipeline;
|
||||||
pub use iced_graphics::triangle::{Mesh2D, Vertex2D};
|
pub use iced_graphics::triangle::{Mesh2D, Vertex2D};
|
||||||
|
use layer::mesh;
|
||||||
|
|
||||||
mod gradient;
|
mod gradient;
|
||||||
mod msaa;
|
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
|
//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
|
//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).
|
//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);
|
let _ = self.index_buffer.recreate_if_needed(device, total_indices);
|
||||||
|
|
||||||
//prepare dynamic buffers & data store for writing
|
//prepare dynamic buffers & data store for writing
|
||||||
|
|
@ -144,11 +146,11 @@ impl Pipeline {
|
||||||
self.index_strides.push(mesh.buffers.indices.len() as u32);
|
self.index_strides.push(mesh.buffers.indices.len() as u32);
|
||||||
|
|
||||||
//push uniform data to CPU buffers
|
//push uniform data to CPU buffers
|
||||||
match mesh.shader {
|
match mesh.style {
|
||||||
Shader::Solid(color) => {
|
mesh::Style::Solid(color) => {
|
||||||
self.pipelines.solid.push(transform, color);
|
self.pipelines.solid.push(transform, color);
|
||||||
}
|
}
|
||||||
Shader::Gradient(gradient) => {
|
mesh::Style::Gradient(gradient) => {
|
||||||
self.pipelines.gradient.push(transform, gradient);
|
self.pipelines.gradient.push(transform, gradient);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -204,15 +206,15 @@ impl Pipeline {
|
||||||
clip_bounds.height,
|
clip_bounds.height,
|
||||||
);
|
);
|
||||||
|
|
||||||
match mesh.shader {
|
match mesh.style {
|
||||||
Shader::Solid(_) => {
|
mesh::Style::Solid(_) => {
|
||||||
self.pipelines.solid.configure_render_pass(
|
self.pipelines.solid.configure_render_pass(
|
||||||
&mut render_pass,
|
&mut render_pass,
|
||||||
num_solids,
|
num_solids,
|
||||||
);
|
);
|
||||||
num_solids += 1;
|
num_solids += 1;
|
||||||
}
|
}
|
||||||
Shader::Gradient(_) => {
|
mesh::Style::Gradient(_) => {
|
||||||
self.pipelines.gradient.configure_render_pass(
|
self.pipelines.gradient.configure_render_pass(
|
||||||
&mut render_pass,
|
&mut render_pass,
|
||||||
num_gradients,
|
num_gradients,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::buffers::dynamic_buffers::DynamicBuffer;
|
use crate::buffers::dynamic::DynamicBuffer;
|
||||||
use crate::settings;
|
use crate::settings;
|
||||||
use crate::triangle::{
|
use crate::triangle::{
|
||||||
default_fragment_target, default_multisample_state,
|
default_fragment_target, default_multisample_state,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::buffers::dynamic_buffers::DynamicBuffer;
|
use crate::buffers::dynamic::DynamicBuffer;
|
||||||
use crate::triangle::{
|
use crate::triangle::{
|
||||||
default_fragment_target, default_multisample_state,
|
default_fragment_target, default_multisample_state,
|
||||||
default_triangle_primitive_state, vertex_buffer_layout,
|
default_triangle_primitive_state, vertex_buffer_layout,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue