//! Draw custom primitives. use crate::core::{self, Rectangle}; use crate::graphics::Viewport; use rustc_hash::FxHashMap; use std::any::{Any, TypeId}; use std::fmt::Debug; /// A batch of primitives. pub type Batch = Vec; /// 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, device: &wgpu::Device, queue: &wgpu::Queue, format: wgpu::TextureFormat, storage: &mut Storage, bounds: &Rectangle, viewport: &Viewport, ); /// Renders the [`Primitive`]. fn render( &self, encoder: &mut wgpu::CommandEncoder, storage: &Storage, target: &wgpu::TextureView, clip_bounds: &Rectangle, ); } #[derive(Debug)] /// An instance of a specific [`Primitive`]. pub struct Instance { /// The bounds of the [`Instance`]. pub bounds: Rectangle, /// The [`Primitive`] to render. pub primitive: Box, } impl Instance { /// Creates a new [`Instance`] with the given [`Primitive`]. pub fn new(bounds: Rectangle, primitive: impl Primitive) -> Self { Instance { bounds, primitive: Box::new(primitive), } } } /// A renderer than can draw custom primitives. pub trait Renderer: core::Renderer { /// Draws a custom primitive. fn draw_primitive(&mut self, bounds: Rectangle, primitive: impl Primitive); } /// Stores custom, user-provided types. #[derive(Default, Debug)] pub struct Storage { pipelines: FxHashMap>, } impl Storage { /// Returns `true` if `Storage` contains a type `T`. pub fn has(&self) -> bool { self.pipelines.contains_key(&TypeId::of::()) } /// Inserts the data `T` in to [`Storage`]. pub fn store(&mut self, data: T) { let _ = self.pipelines.insert(TypeId::of::(), Box::new(data)); } /// Returns a reference to the data with type `T` if it exists in [`Storage`]. pub fn get(&self) -> Option<&T> { self.pipelines.get(&TypeId::of::()).map(|pipeline| { pipeline .downcast_ref::() .expect("Value with this type does not exist in Storage.") }) } /// Returns a mutable reference to the data with type `T` if it exists in [`Storage`]. pub fn get_mut(&mut self) -> Option<&mut T> { self.pipelines.get_mut(&TypeId::of::()).map(|pipeline| { pipeline .downcast_mut::() .expect("Value with this type does not exist in Storage.") }) } }