Re-organize custom module as pipeline module
... and move `Shader` widget to `iced_widget` crate
This commit is contained in:
parent
2dda9132cd
commit
9489e29e66
14 changed files with 246 additions and 197 deletions
|
|
@ -3,15 +3,20 @@ mod cubes;
|
||||||
mod pipeline;
|
mod pipeline;
|
||||||
mod primitive;
|
mod primitive;
|
||||||
|
|
||||||
|
use crate::camera::Camera;
|
||||||
use crate::cubes::Cubes;
|
use crate::cubes::Cubes;
|
||||||
|
use crate::pipeline::Pipeline;
|
||||||
|
|
||||||
|
use iced::executor;
|
||||||
|
use iced::time::Instant;
|
||||||
use iced::widget::{
|
use iced::widget::{
|
||||||
checkbox, column, container, row, slider, text, vertical_space, Shader,
|
checkbox, column, container, row, slider, text, vertical_space, Shader,
|
||||||
};
|
};
|
||||||
|
use iced::window;
|
||||||
use iced::{
|
use iced::{
|
||||||
executor, window, Alignment, Application, Color, Command, Element, Length,
|
Alignment, Application, Color, Command, Element, Length, Renderer,
|
||||||
Renderer, Subscription, Theme,
|
Subscription, Theme,
|
||||||
};
|
};
|
||||||
use std::time::Instant;
|
|
||||||
|
|
||||||
fn main() -> iced::Result {
|
fn main() -> iced::Result {
|
||||||
IcedCubes::run(iced::Settings::default())
|
IcedCubes::run(iced::Settings::default())
|
||||||
|
|
|
||||||
|
|
@ -4,17 +4,18 @@ pub mod vertex;
|
||||||
mod buffer;
|
mod buffer;
|
||||||
mod uniforms;
|
mod uniforms;
|
||||||
|
|
||||||
use crate::camera::Camera;
|
pub use buffer::Buffer;
|
||||||
use crate::pipeline::Pipeline;
|
pub use cube::Cube;
|
||||||
use crate::primitive::cube::Cube;
|
pub use uniforms::Uniforms;
|
||||||
|
pub use vertex::Vertex;
|
||||||
|
|
||||||
|
use crate::Camera;
|
||||||
|
use crate::Pipeline;
|
||||||
|
|
||||||
use iced::advanced::graphics::Transformation;
|
use iced::advanced::graphics::Transformation;
|
||||||
use iced::widget::shader;
|
use iced::widget::shader;
|
||||||
use iced::{Color, Rectangle, Size};
|
use iced::{Color, Rectangle, Size};
|
||||||
|
|
||||||
pub use crate::primitive::vertex::Vertex;
|
|
||||||
pub use buffer::Buffer;
|
|
||||||
pub use uniforms::Uniforms;
|
|
||||||
|
|
||||||
/// A collection of `Cube`s that can be rendered.
|
/// A collection of `Cube`s that can be rendered.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Primitive {
|
pub struct Primitive {
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,15 @@
|
||||||
#![forbid(rust_2018_idioms)]
|
#![forbid(rust_2018_idioms)]
|
||||||
#![deny(unsafe_code, unused_results, rustdoc::broken_intra_doc_links)]
|
#![deny(unsafe_code, unused_results, rustdoc::broken_intra_doc_links)]
|
||||||
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||||
|
#[cfg(feature = "wgpu")]
|
||||||
|
pub use iced_wgpu as wgpu;
|
||||||
|
|
||||||
pub mod compositor;
|
pub mod compositor;
|
||||||
|
|
||||||
#[cfg(feature = "geometry")]
|
#[cfg(feature = "geometry")]
|
||||||
pub mod geometry;
|
pub mod geometry;
|
||||||
|
|
||||||
mod settings;
|
mod settings;
|
||||||
pub mod widget;
|
|
||||||
|
|
||||||
pub use iced_graphics as graphics;
|
pub use iced_graphics as graphics;
|
||||||
pub use iced_graphics::core;
|
pub use iced_graphics::core;
|
||||||
|
|
@ -60,26 +62,6 @@ impl<T> Renderer<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw_custom<P: widget::shader::Primitive>(
|
|
||||||
&mut self,
|
|
||||||
bounds: Rectangle,
|
|
||||||
primitive: P,
|
|
||||||
) {
|
|
||||||
match self {
|
|
||||||
Renderer::TinySkia(_) => {
|
|
||||||
log::warn!(
|
|
||||||
"Custom shader primitive is unavailable with tiny-skia."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
#[cfg(feature = "wgpu")]
|
|
||||||
Renderer::Wgpu(renderer) => {
|
|
||||||
renderer.draw_primitive(iced_wgpu::Primitive::Custom(
|
|
||||||
iced_wgpu::primitive::Custom::shader(bounds, primitive),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> core::Renderer for Renderer<T> {
|
impl<T> core::Renderer for Renderer<T> {
|
||||||
|
|
@ -292,3 +274,23 @@ impl<T> crate::graphics::geometry::Renderer for Renderer<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "wgpu")]
|
||||||
|
impl<T> iced_wgpu::primitive::pipeline::Renderer for Renderer<T> {
|
||||||
|
fn draw_pipeline_primitive(
|
||||||
|
&mut self,
|
||||||
|
bounds: Rectangle,
|
||||||
|
primitive: impl wgpu::primitive::pipeline::Primitive,
|
||||||
|
) {
|
||||||
|
match self {
|
||||||
|
Self::TinySkia(_renderer) => {
|
||||||
|
log::warn!(
|
||||||
|
"Custom shader primitive is unavailable with tiny-skia."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Self::Wgpu(renderer) => {
|
||||||
|
renderer.draw_pipeline_primitive(bounds, primitive);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
#[cfg(feature = "wgpu")]
|
|
||||||
pub mod shader;
|
|
||||||
|
|
@ -2,8 +2,11 @@ use crate::core::{Color, Size};
|
||||||
use crate::graphics::backend;
|
use crate::graphics::backend;
|
||||||
use crate::graphics::color;
|
use crate::graphics::color;
|
||||||
use crate::graphics::{Transformation, Viewport};
|
use crate::graphics::{Transformation, Viewport};
|
||||||
|
use crate::primitive::pipeline;
|
||||||
use crate::primitive::{self, Primitive};
|
use crate::primitive::{self, Primitive};
|
||||||
use crate::{custom, quad, text, triangle};
|
use crate::quad;
|
||||||
|
use crate::text;
|
||||||
|
use crate::triangle;
|
||||||
use crate::{Layer, Settings};
|
use crate::{Layer, Settings};
|
||||||
|
|
||||||
#[cfg(feature = "tracing")]
|
#[cfg(feature = "tracing")]
|
||||||
|
|
@ -23,7 +26,7 @@ pub struct Backend {
|
||||||
quad_pipeline: quad::Pipeline,
|
quad_pipeline: quad::Pipeline,
|
||||||
text_pipeline: text::Pipeline,
|
text_pipeline: text::Pipeline,
|
||||||
triangle_pipeline: triangle::Pipeline,
|
triangle_pipeline: triangle::Pipeline,
|
||||||
pipeline_storage: custom::Storage,
|
pipeline_storage: pipeline::Storage,
|
||||||
|
|
||||||
#[cfg(any(feature = "image", feature = "svg"))]
|
#[cfg(any(feature = "image", feature = "svg"))]
|
||||||
image_pipeline: image::Pipeline,
|
image_pipeline: image::Pipeline,
|
||||||
|
|
@ -49,7 +52,7 @@ impl Backend {
|
||||||
quad_pipeline,
|
quad_pipeline,
|
||||||
text_pipeline,
|
text_pipeline,
|
||||||
triangle_pipeline,
|
triangle_pipeline,
|
||||||
pipeline_storage: custom::Storage::default(),
|
pipeline_storage: pipeline::Storage::default(),
|
||||||
|
|
||||||
#[cfg(any(feature = "image", feature = "svg"))]
|
#[cfg(any(feature = "image", feature = "svg"))]
|
||||||
image_pipeline,
|
image_pipeline,
|
||||||
|
|
@ -183,9 +186,9 @@ impl Backend {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if !layer.shaders.is_empty() {
|
if !layer.pipelines.is_empty() {
|
||||||
for shader in &layer.shaders {
|
for pipeline in &layer.pipelines {
|
||||||
shader.primitive.prepare(
|
pipeline.primitive.prepare(
|
||||||
format,
|
format,
|
||||||
device,
|
device,
|
||||||
queue,
|
queue,
|
||||||
|
|
@ -323,19 +326,17 @@ impl Backend {
|
||||||
// kill render pass to let custom shaders get mut access to encoder
|
// kill render pass to let custom shaders get mut access to encoder
|
||||||
let _ = ManuallyDrop::into_inner(render_pass);
|
let _ = ManuallyDrop::into_inner(render_pass);
|
||||||
|
|
||||||
if !layer.shaders.is_empty() {
|
if !layer.pipelines.is_empty() {
|
||||||
for shader in &layer.shaders {
|
for pipeline in &layer.pipelines {
|
||||||
//This extra check is needed since each custom pipeline must set it's own
|
let bounds = (pipeline.bounds * scale_factor).snap();
|
||||||
//scissor rect, which will panic if bounds.w/h < 1
|
|
||||||
let bounds = shader.bounds * scale_factor;
|
|
||||||
|
|
||||||
if bounds.width < 1.0 || bounds.height < 1.0 {
|
if bounds.width < 1 || bounds.height < 1 {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
shader.primitive.render(
|
pipeline.primitive.render(
|
||||||
&self.pipeline_storage,
|
&self.pipeline_storage,
|
||||||
bounds.snap(),
|
bounds,
|
||||||
target,
|
target,
|
||||||
target_size,
|
target_size,
|
||||||
encoder,
|
encoder,
|
||||||
|
|
|
||||||
|
|
@ -1,67 +1,8 @@
|
||||||
//! Draw custom primitives.
|
//! Draw custom primitives.
|
||||||
use crate::core::{Rectangle, Size};
|
use crate::core::{Rectangle, Size};
|
||||||
use crate::graphics::Transformation;
|
use crate::graphics::Transformation;
|
||||||
|
use crate::primitive;
|
||||||
|
|
||||||
use std::any::{Any, TypeId};
|
use std::any::{Any, TypeId};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
/// Stores custom, user-provided pipelines.
|
|
||||||
#[derive(Default, Debug)]
|
|
||||||
pub struct Storage {
|
|
||||||
pipelines: HashMap<TypeId, Box<dyn Any>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Storage {
|
|
||||||
/// Returns `true` if `Storage` contains a pipeline with type `T`.
|
|
||||||
pub fn has<T: 'static>(&self) -> bool {
|
|
||||||
self.pipelines.get(&TypeId::of::<T>()).is_some()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Inserts the pipeline `T` in to [`Storage`].
|
|
||||||
pub fn store<T: 'static>(&mut self, pipeline: T) {
|
|
||||||
let _ = self.pipelines.insert(TypeId::of::<T>(), Box::new(pipeline));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a reference to pipeline with type `T` if it exists in [`Storage`].
|
|
||||||
pub fn get<T: 'static>(&self) -> Option<&T> {
|
|
||||||
self.pipelines.get(&TypeId::of::<T>()).map(|pipeline| {
|
|
||||||
pipeline
|
|
||||||
.downcast_ref::<T>()
|
|
||||||
.expect("Pipeline with this type does not exist in Storage.")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a mutable reference to pipeline `T` if it exists in [`Storage`].
|
|
||||||
pub fn get_mut<T: 'static>(&mut self) -> Option<&mut T> {
|
|
||||||
self.pipelines.get_mut(&TypeId::of::<T>()).map(|pipeline| {
|
|
||||||
pipeline
|
|
||||||
.downcast_mut::<T>()
|
|
||||||
.expect("Pipeline with this type does not exist in Storage.")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A set of methods which allows a [`Primitive`] to be rendered.
|
|
||||||
pub trait Primitive: Debug + Send + Sync + 'static {
|
|
||||||
/// Processes the [`Primitive`], allowing for GPU buffer allocation.
|
|
||||||
fn prepare(
|
|
||||||
&self,
|
|
||||||
format: wgpu::TextureFormat,
|
|
||||||
device: &wgpu::Device,
|
|
||||||
queue: &wgpu::Queue,
|
|
||||||
target_size: Size<u32>,
|
|
||||||
scale_factor: f32,
|
|
||||||
transform: Transformation,
|
|
||||||
storage: &mut Storage,
|
|
||||||
);
|
|
||||||
|
|
||||||
/// Renders the [`Primitive`].
|
|
||||||
fn render(
|
|
||||||
&self,
|
|
||||||
storage: &Storage,
|
|
||||||
bounds: Rectangle<u32>,
|
|
||||||
target: &wgpu::TextureView,
|
|
||||||
target_size: Size<u32>,
|
|
||||||
encoder: &mut wgpu::CommandEncoder,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -35,8 +35,8 @@ pub struct Layer<'a> {
|
||||||
/// The images of the [`Layer`].
|
/// The images of the [`Layer`].
|
||||||
pub images: Vec<Image>,
|
pub images: Vec<Image>,
|
||||||
|
|
||||||
/// The custom shader primitives of this [`Layer`].
|
/// The custom pipelines of this [`Layer`].
|
||||||
pub shaders: Vec<primitive::Shader>,
|
pub pipelines: Vec<primitive::Pipeline>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Layer<'a> {
|
impl<'a> Layer<'a> {
|
||||||
|
|
@ -48,7 +48,7 @@ impl<'a> Layer<'a> {
|
||||||
meshes: Vec::new(),
|
meshes: Vec::new(),
|
||||||
text: Vec::new(),
|
text: Vec::new(),
|
||||||
images: Vec::new(),
|
images: Vec::new(),
|
||||||
shaders: Vec::new(),
|
pipelines: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -312,16 +312,21 @@ impl<'a> Layer<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
primitive::Custom::Shader(shader) => {
|
primitive::Custom::Pipeline(pipeline) => {
|
||||||
let layer = &mut layers[current_layer];
|
let layer = &mut layers[current_layer];
|
||||||
|
|
||||||
let bounds = Rectangle::new(
|
let bounds = Rectangle::new(
|
||||||
Point::new(translation.x, translation.y),
|
Point::new(translation.x, translation.y),
|
||||||
shader.bounds.size(),
|
pipeline.bounds.size(),
|
||||||
);
|
);
|
||||||
|
|
||||||
if layer.bounds.intersection(&bounds).is_some() {
|
if let Some(clip_bounds) =
|
||||||
layer.shaders.push(shader.clone());
|
layer.bounds.intersection(&bounds)
|
||||||
|
{
|
||||||
|
layer.pipelines.push(primitive::Pipeline {
|
||||||
|
bounds: clip_bounds,
|
||||||
|
primitive: pipeline.primitive.clone(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,6 @@
|
||||||
rustdoc::broken_intra_doc_links
|
rustdoc::broken_intra_doc_links
|
||||||
)]
|
)]
|
||||||
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||||
pub mod custom;
|
|
||||||
pub mod layer;
|
pub mod layer;
|
||||||
pub mod primitive;
|
pub mod primitive;
|
||||||
pub mod settings;
|
pub mod settings;
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
//! Draw using different graphical primitives.
|
//! Draw using different graphical primitives.
|
||||||
|
pub mod pipeline;
|
||||||
|
|
||||||
|
pub use pipeline::Pipeline;
|
||||||
|
|
||||||
use crate::core::Rectangle;
|
use crate::core::Rectangle;
|
||||||
use crate::custom;
|
|
||||||
use crate::graphics::{Damage, Mesh};
|
use crate::graphics::{Damage, Mesh};
|
||||||
use std::any::Any;
|
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
/// The graphical primitives supported by `iced_wgpu`.
|
/// The graphical primitives supported by `iced_wgpu`.
|
||||||
pub type Primitive = crate::graphics::Primitive<Custom>;
|
pub type Primitive = crate::graphics::Primitive<Custom>;
|
||||||
|
|
@ -14,44 +16,15 @@ pub type Primitive = crate::graphics::Primitive<Custom>;
|
||||||
pub enum Custom {
|
pub enum Custom {
|
||||||
/// A mesh primitive.
|
/// A mesh primitive.
|
||||||
Mesh(Mesh),
|
Mesh(Mesh),
|
||||||
/// A custom shader primitive
|
/// A custom pipeline primitive.
|
||||||
Shader(Shader),
|
Pipeline(Pipeline),
|
||||||
}
|
|
||||||
|
|
||||||
impl Custom {
|
|
||||||
/// Create a custom [`Shader`] primitive.
|
|
||||||
pub fn shader<P: custom::Primitive>(
|
|
||||||
bounds: Rectangle,
|
|
||||||
primitive: P,
|
|
||||||
) -> Self {
|
|
||||||
Self::Shader(Shader {
|
|
||||||
bounds,
|
|
||||||
primitive: Arc::new(primitive),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Damage for Custom {
|
impl Damage for Custom {
|
||||||
fn bounds(&self) -> Rectangle {
|
fn bounds(&self) -> Rectangle {
|
||||||
match self {
|
match self {
|
||||||
Self::Mesh(mesh) => mesh.bounds(),
|
Self::Mesh(mesh) => mesh.bounds(),
|
||||||
Self::Shader(shader) => shader.bounds,
|
Self::Pipeline(pipeline) => pipeline.bounds,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
/// A custom primitive which can be used to render primitives associated with a custom pipeline.
|
|
||||||
pub struct Shader {
|
|
||||||
/// The bounds of the [`Shader`].
|
|
||||||
pub bounds: Rectangle,
|
|
||||||
|
|
||||||
/// The [`custom::Primitive`] to render.
|
|
||||||
pub primitive: Arc<dyn custom::Primitive>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq for Shader {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
self.primitive.type_id() == other.primitive.type_id()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
117
wgpu/src/primitive/pipeline.rs
Normal file
117
wgpu/src/primitive/pipeline.rs
Normal file
|
|
@ -0,0 +1,117 @@
|
||||||
|
//! Draw primitives using custom pipelines.
|
||||||
|
use crate::core::{Rectangle, Size};
|
||||||
|
use crate::graphics::Transformation;
|
||||||
|
|
||||||
|
use std::any::{Any, TypeId};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
/// A custom primitive which can be used to render primitives associated with a custom pipeline.
|
||||||
|
pub struct Pipeline {
|
||||||
|
/// The bounds of the [`Shader`].
|
||||||
|
pub bounds: Rectangle,
|
||||||
|
|
||||||
|
/// The [`custom::Primitive`] to render.
|
||||||
|
pub primitive: Arc<dyn Primitive>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Pipeline {
|
||||||
|
/// Creates a new [`Pipeline`] with the given [`Primitive`].
|
||||||
|
pub fn new(bounds: Rectangle, primitive: impl Primitive) -> Self {
|
||||||
|
Pipeline {
|
||||||
|
bounds,
|
||||||
|
primitive: Arc::new(primitive),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for Pipeline {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.primitive.type_id() == other.primitive.type_id()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A set of methods which allows a [`Primitive`] to be rendered.
|
||||||
|
pub trait Primitive: Debug + Send + Sync + 'static {
|
||||||
|
/// Processes the [`Primitive`], allowing for GPU buffer allocation.
|
||||||
|
fn prepare(
|
||||||
|
&self,
|
||||||
|
format: wgpu::TextureFormat,
|
||||||
|
device: &wgpu::Device,
|
||||||
|
queue: &wgpu::Queue,
|
||||||
|
target_size: Size<u32>,
|
||||||
|
scale_factor: f32,
|
||||||
|
transform: Transformation,
|
||||||
|
storage: &mut Storage,
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Renders the [`Primitive`].
|
||||||
|
fn render(
|
||||||
|
&self,
|
||||||
|
storage: &Storage,
|
||||||
|
bounds: Rectangle<u32>,
|
||||||
|
target: &wgpu::TextureView,
|
||||||
|
target_size: Size<u32>,
|
||||||
|
encoder: &mut wgpu::CommandEncoder,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A renderer than can draw custom pipeline primitives.
|
||||||
|
pub trait Renderer: crate::core::Renderer {
|
||||||
|
/// Draws a custom pipeline primitive.
|
||||||
|
fn draw_pipeline_primitive(
|
||||||
|
&mut self,
|
||||||
|
bounds: Rectangle,
|
||||||
|
primitive: impl Primitive,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Theme> Renderer for crate::Renderer<Theme> {
|
||||||
|
fn draw_pipeline_primitive(
|
||||||
|
&mut self,
|
||||||
|
bounds: Rectangle,
|
||||||
|
primitive: impl Primitive,
|
||||||
|
) {
|
||||||
|
self.draw_primitive(super::Primitive::Custom(super::Custom::Pipeline(
|
||||||
|
Pipeline::new(bounds, primitive),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Stores custom, user-provided pipelines.
|
||||||
|
#[derive(Default, Debug)]
|
||||||
|
pub struct Storage {
|
||||||
|
pipelines: HashMap<TypeId, Box<dyn Any>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Storage {
|
||||||
|
/// Returns `true` if `Storage` contains a pipeline with type `T`.
|
||||||
|
pub fn has<T: 'static>(&self) -> bool {
|
||||||
|
self.pipelines.get(&TypeId::of::<T>()).is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Inserts the pipeline `T` in to [`Storage`].
|
||||||
|
pub fn store<T: 'static>(&mut self, pipeline: T) {
|
||||||
|
let _ = self.pipelines.insert(TypeId::of::<T>(), Box::new(pipeline));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a reference to pipeline with type `T` if it exists in [`Storage`].
|
||||||
|
pub fn get<T: 'static>(&self) -> Option<&T> {
|
||||||
|
self.pipelines.get(&TypeId::of::<T>()).map(|pipeline| {
|
||||||
|
pipeline
|
||||||
|
.downcast_ref::<T>()
|
||||||
|
.expect("Pipeline with this type does not exist in Storage.")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a mutable reference to pipeline `T` if it exists in [`Storage`].
|
||||||
|
pub fn get_mut<T: 'static>(&mut self) -> Option<&mut T> {
|
||||||
|
self.pipelines.get_mut(&TypeId::of::<T>()).map(|pipeline| {
|
||||||
|
pipeline
|
||||||
|
.downcast_mut::<T>()
|
||||||
|
.expect("Pipeline with this type does not exist in Storage.")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -98,7 +98,11 @@ pub use tooltip::Tooltip;
|
||||||
pub use vertical_slider::VerticalSlider;
|
pub use vertical_slider::VerticalSlider;
|
||||||
|
|
||||||
#[cfg(feature = "wgpu")]
|
#[cfg(feature = "wgpu")]
|
||||||
pub use renderer::widget::shader::{self, Shader, Transformation};
|
pub mod shader;
|
||||||
|
|
||||||
|
#[cfg(feature = "wgpu")]
|
||||||
|
#[doc(no_inline)]
|
||||||
|
pub use shader::Shader;
|
||||||
|
|
||||||
#[cfg(feature = "svg")]
|
#[cfg(feature = "svg")]
|
||||||
pub mod svg;
|
pub mod svg;
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,24 @@
|
||||||
//! A custom shader widget for wgpu applications.
|
//! A custom shader widget for wgpu applications.
|
||||||
use crate::core::event::Status;
|
|
||||||
use crate::core::layout::{Limits, Node};
|
|
||||||
use crate::core::mouse::{Cursor, Interaction};
|
|
||||||
use crate::core::renderer::Style;
|
|
||||||
use crate::core::widget::tree::{State, Tag};
|
|
||||||
use crate::core::widget::{tree, Tree};
|
|
||||||
use crate::core::{
|
|
||||||
self, layout, mouse, widget, window, Clipboard, Element, Layout, Length,
|
|
||||||
Rectangle, Shell, Size, Widget,
|
|
||||||
};
|
|
||||||
use std::marker::PhantomData;
|
|
||||||
|
|
||||||
mod event;
|
mod event;
|
||||||
mod program;
|
mod program;
|
||||||
|
|
||||||
pub use event::Event;
|
pub use event::Event;
|
||||||
pub use iced_graphics::Transformation;
|
|
||||||
pub use iced_wgpu::custom::Primitive;
|
|
||||||
pub use iced_wgpu::custom::Storage;
|
|
||||||
pub use program::Program;
|
pub use program::Program;
|
||||||
|
|
||||||
|
use crate::core;
|
||||||
|
use crate::core::layout::{self, Layout};
|
||||||
|
use crate::core::mouse;
|
||||||
|
use crate::core::renderer;
|
||||||
|
use crate::core::widget::tree::{self, Tree};
|
||||||
|
use crate::core::widget::{self, Widget};
|
||||||
|
use crate::core::window;
|
||||||
|
use crate::core::{Clipboard, Element, Length, Rectangle, Shell, Size};
|
||||||
|
use crate::renderer::wgpu::primitive::pipeline;
|
||||||
|
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
pub use pipeline::{Primitive, Storage};
|
||||||
|
|
||||||
/// A widget which can render custom shaders with Iced's `wgpu` backend.
|
/// A widget which can render custom shaders with Iced's `wgpu` backend.
|
||||||
///
|
///
|
||||||
/// Must be initialized with a [`Program`], which describes the internal widget state & how
|
/// Must be initialized with a [`Program`], which describes the internal widget state & how
|
||||||
|
|
@ -56,17 +55,17 @@ impl<Message, P: Program<Message>> Shader<Message, P> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P, Message, Theme> Widget<Message, crate::Renderer<Theme>>
|
impl<P, Message, Renderer> Widget<Message, Renderer> for Shader<Message, P>
|
||||||
for Shader<Message, P>
|
|
||||||
where
|
where
|
||||||
P: Program<Message>,
|
P: Program<Message>,
|
||||||
|
Renderer: pipeline::Renderer,
|
||||||
{
|
{
|
||||||
fn tag(&self) -> Tag {
|
fn tag(&self) -> tree::Tag {
|
||||||
struct Tag<T>(T);
|
struct Tag<T>(T);
|
||||||
tree::Tag::of::<Tag<P::State>>()
|
tree::Tag::of::<Tag<P::State>>()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn state(&self) -> State {
|
fn state(&self) -> tree::State {
|
||||||
tree::State::new(P::State::default())
|
tree::State::new(P::State::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -81,9 +80,9 @@ where
|
||||||
fn layout(
|
fn layout(
|
||||||
&self,
|
&self,
|
||||||
_tree: &mut Tree,
|
_tree: &mut Tree,
|
||||||
_renderer: &crate::Renderer<Theme>,
|
_renderer: &Renderer,
|
||||||
limits: &Limits,
|
limits: &layout::Limits,
|
||||||
) -> Node {
|
) -> layout::Node {
|
||||||
let limits = limits.width(self.width).height(self.height);
|
let limits = limits.width(self.width).height(self.height);
|
||||||
let size = limits.resolve(Size::ZERO);
|
let size = limits.resolve(Size::ZERO);
|
||||||
|
|
||||||
|
|
@ -95,12 +94,12 @@ where
|
||||||
tree: &mut Tree,
|
tree: &mut Tree,
|
||||||
event: crate::core::Event,
|
event: crate::core::Event,
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
cursor: Cursor,
|
cursor: mouse::Cursor,
|
||||||
_renderer: &crate::Renderer<Theme>,
|
_renderer: &Renderer,
|
||||||
_clipboard: &mut dyn Clipboard,
|
_clipboard: &mut dyn Clipboard,
|
||||||
shell: &mut Shell<'_, Message>,
|
shell: &mut Shell<'_, Message>,
|
||||||
_viewport: &Rectangle,
|
_viewport: &Rectangle,
|
||||||
) -> Status {
|
) -> event::Status {
|
||||||
let bounds = layout.bounds();
|
let bounds = layout.bounds();
|
||||||
|
|
||||||
let custom_shader_event = match event {
|
let custom_shader_event = match event {
|
||||||
|
|
@ -140,9 +139,9 @@ where
|
||||||
&self,
|
&self,
|
||||||
tree: &Tree,
|
tree: &Tree,
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
cursor: Cursor,
|
cursor: mouse::Cursor,
|
||||||
_viewport: &Rectangle,
|
_viewport: &Rectangle,
|
||||||
_renderer: &crate::Renderer<Theme>,
|
_renderer: &Renderer,
|
||||||
) -> mouse::Interaction {
|
) -> mouse::Interaction {
|
||||||
let bounds = layout.bounds();
|
let bounds = layout.bounds();
|
||||||
let state = tree.state.downcast_ref::<P::State>();
|
let state = tree.state.downcast_ref::<P::State>();
|
||||||
|
|
@ -153,9 +152,9 @@ where
|
||||||
fn draw(
|
fn draw(
|
||||||
&self,
|
&self,
|
||||||
tree: &widget::Tree,
|
tree: &widget::Tree,
|
||||||
renderer: &mut crate::Renderer<Theme>,
|
renderer: &mut Renderer,
|
||||||
_theme: &Theme,
|
_theme: &Renderer::Theme,
|
||||||
_style: &Style,
|
_style: &renderer::Style,
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
cursor_position: mouse::Cursor,
|
cursor_position: mouse::Cursor,
|
||||||
_viewport: &Rectangle,
|
_viewport: &Rectangle,
|
||||||
|
|
@ -163,20 +162,21 @@ where
|
||||||
let bounds = layout.bounds();
|
let bounds = layout.bounds();
|
||||||
let state = tree.state.downcast_ref::<P::State>();
|
let state = tree.state.downcast_ref::<P::State>();
|
||||||
|
|
||||||
renderer.draw_custom(
|
renderer.draw_pipeline_primitive(
|
||||||
bounds,
|
bounds,
|
||||||
self.program.draw(state, cursor_position, bounds),
|
self.program.draw(state, cursor_position, bounds),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, M, P, Theme> From<Shader<M, P>>
|
impl<'a, Message, Renderer, P> From<Shader<Message, P>>
|
||||||
for Element<'a, M, crate::Renderer<Theme>>
|
for Element<'a, Message, Renderer>
|
||||||
where
|
where
|
||||||
M: 'a,
|
Message: 'a,
|
||||||
P: Program<M> + 'a,
|
Renderer: pipeline::Renderer,
|
||||||
|
P: Program<Message> + 'a,
|
||||||
{
|
{
|
||||||
fn from(custom: Shader<M, P>) -> Element<'a, M, crate::Renderer<Theme>> {
|
fn from(custom: Shader<Message, P>) -> Element<'a, Message, Renderer> {
|
||||||
Element::new(custom)
|
Element::new(custom)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -193,16 +193,16 @@ where
|
||||||
state: &mut Self::State,
|
state: &mut Self::State,
|
||||||
event: Event,
|
event: Event,
|
||||||
bounds: Rectangle,
|
bounds: Rectangle,
|
||||||
cursor: Cursor,
|
cursor: mouse::Cursor,
|
||||||
shell: &mut Shell<'_, Message>,
|
shell: &mut Shell<'_, Message>,
|
||||||
) -> (Status, Option<Message>) {
|
) -> (event::Status, Option<Message>) {
|
||||||
T::update(self, state, event, bounds, cursor, shell)
|
T::update(self, state, event, bounds, cursor, shell)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw(
|
fn draw(
|
||||||
&self,
|
&self,
|
||||||
state: &Self::State,
|
state: &Self::State,
|
||||||
cursor: Cursor,
|
cursor: mouse::Cursor,
|
||||||
bounds: Rectangle,
|
bounds: Rectangle,
|
||||||
) -> Self::Primitive {
|
) -> Self::Primitive {
|
||||||
T::draw(self, state, cursor, bounds)
|
T::draw(self, state, cursor, bounds)
|
||||||
|
|
@ -212,8 +212,8 @@ where
|
||||||
&self,
|
&self,
|
||||||
state: &Self::State,
|
state: &Self::State,
|
||||||
bounds: Rectangle,
|
bounds: Rectangle,
|
||||||
cursor: Cursor,
|
cursor: mouse::Cursor,
|
||||||
) -> Interaction {
|
) -> mouse::Interaction {
|
||||||
T::mouse_interaction(self, state, bounds, cursor)
|
T::mouse_interaction(self, state, bounds, cursor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
use crate::core::keyboard;
|
use crate::core::keyboard;
|
||||||
use crate::core::mouse;
|
use crate::core::mouse;
|
||||||
use crate::core::touch;
|
use crate::core::touch;
|
||||||
|
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
pub use crate::core::event::Status;
|
pub use crate::core::event::Status;
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
use crate::core::{event, mouse, Rectangle, Shell};
|
use crate::core::event;
|
||||||
use crate::widget;
|
use crate::core::mouse;
|
||||||
use widget::shader;
|
use crate::core::{Rectangle, Shell};
|
||||||
|
use crate::renderer::wgpu::primitive::pipeline;
|
||||||
|
use crate::shader;
|
||||||
|
|
||||||
/// The state and logic of a [`Shader`] widget.
|
/// The state and logic of a [`Shader`] widget.
|
||||||
///
|
///
|
||||||
|
|
@ -13,7 +15,7 @@ pub trait Program<Message> {
|
||||||
type State: Default + 'static;
|
type State: Default + 'static;
|
||||||
|
|
||||||
/// The type of primitive this [`Program`] can draw.
|
/// The type of primitive this [`Program`] can draw.
|
||||||
type Primitive: shader::Primitive + 'static;
|
type Primitive: pipeline::Primitive + 'static;
|
||||||
|
|
||||||
/// Update the internal [`State`] of the [`Program`]. This can be used to reflect state changes
|
/// Update the internal [`State`] of the [`Program`]. This can be used to reflect state changes
|
||||||
/// based on mouse & other events. You can use the [`Shell`] to publish messages, request a
|
/// based on mouse & other events. You can use the [`Shell`] to publish messages, request a
|
||||||
Loading…
Add table
Add a link
Reference in a new issue