1use crate::core::{self, Rectangle};
3use crate::graphics::Viewport;
4use crate::graphics::futures::{MaybeSend, MaybeSync};
5
6use rustc_hash::FxHashMap;
7use std::any::{Any, TypeId};
8use std::fmt::Debug;
9
10pub type Batch = Vec<Instance>;
12
13pub trait Primitive: Debug + MaybeSend + MaybeSync + 'static {
15 type Pipeline: Pipeline + MaybeSend + MaybeSync;
23
24 fn prepare(
26 &self,
27 pipeline: &mut Self::Pipeline,
28 device: &wgpu::Device,
29 queue: &wgpu::Queue,
30 bounds: &Rectangle,
31 viewport: &Viewport,
32 );
33
34 fn draw(&self, _pipeline: &Self::Pipeline, _render_pass: &mut wgpu::RenderPass<'_>) -> bool {
48 false
49 }
50
51 fn render(
57 &self,
58 _pipeline: &Self::Pipeline,
59 _encoder: &mut wgpu::CommandEncoder,
60 _target: &wgpu::TextureView,
61 _clip_bounds: &Rectangle<u32>,
62 ) {
63 }
64}
65
66pub trait Pipeline: Any + MaybeSend + MaybeSync {
68 fn new(device: &wgpu::Device, queue: &wgpu::Queue, format: wgpu::TextureFormat) -> Self
73 where
74 Self: Sized;
75
76 fn trim(&mut self) {}
80}
81
82pub(crate) trait Stored: Debug + MaybeSend + MaybeSync + 'static {
83 fn prepare(
84 &self,
85 storage: &mut Storage,
86 device: &wgpu::Device,
87 queue: &wgpu::Queue,
88 format: wgpu::TextureFormat,
89 bounds: &Rectangle,
90 viewport: &Viewport,
91 );
92
93 fn draw(&self, storage: &Storage, render_pass: &mut wgpu::RenderPass<'_>) -> bool;
94
95 fn render(
96 &self,
97 storage: &Storage,
98 encoder: &mut wgpu::CommandEncoder,
99 target: &wgpu::TextureView,
100 clip_bounds: &Rectangle<u32>,
101 );
102}
103
104#[derive(Debug)]
105struct BlackBox<P: Primitive> {
106 primitive: P,
107}
108
109impl<P: Primitive> Stored for BlackBox<P> {
110 fn prepare(
111 &self,
112 storage: &mut Storage,
113 device: &wgpu::Device,
114 queue: &wgpu::Queue,
115 format: wgpu::TextureFormat,
116 bounds: &Rectangle,
117 viewport: &Viewport,
118 ) {
119 if !storage.has::<P>() {
120 storage.store::<P, _>(P::Pipeline::new(device, queue, format));
121 }
122
123 let renderer = storage
124 .get_mut::<P>()
125 .expect("renderer should be initialized")
126 .downcast_mut::<P::Pipeline>()
127 .expect("renderer should have the proper type");
128
129 self.primitive
130 .prepare(renderer, device, queue, bounds, viewport);
131 }
132
133 fn draw(&self, storage: &Storage, render_pass: &mut wgpu::RenderPass<'_>) -> bool {
134 let renderer = storage
135 .get::<P>()
136 .expect("renderer should be initialized")
137 .downcast_ref::<P::Pipeline>()
138 .expect("renderer should have the proper type");
139
140 self.primitive.draw(renderer, render_pass)
141 }
142
143 fn render(
144 &self,
145 storage: &Storage,
146 encoder: &mut wgpu::CommandEncoder,
147 target: &wgpu::TextureView,
148 clip_bounds: &Rectangle<u32>,
149 ) {
150 let renderer = storage
151 .get::<P>()
152 .expect("renderer should be initialized")
153 .downcast_ref::<P::Pipeline>()
154 .expect("renderer should have the proper type");
155
156 self.primitive
157 .render(renderer, encoder, target, clip_bounds);
158 }
159}
160
161#[derive(Debug)]
162pub struct Instance {
164 pub(crate) bounds: Rectangle,
166
167 pub(crate) primitive: Box<dyn Stored>,
169}
170
171impl Instance {
172 pub fn new(bounds: Rectangle, primitive: impl Primitive) -> Self {
174 Instance {
175 bounds,
176 primitive: Box::new(BlackBox { primitive }),
177 }
178 }
179}
180
181pub trait Renderer: core::Renderer {
183 fn draw_primitive(&mut self, bounds: Rectangle, primitive: impl Primitive);
185}
186
187#[derive(Default)]
189pub struct Storage {
190 pipelines: FxHashMap<TypeId, Box<dyn Pipeline>>,
191}
192
193impl Storage {
194 pub fn has<T: 'static>(&self) -> bool {
196 self.pipelines.contains_key(&TypeId::of::<T>())
197 }
198
199 pub fn store<T: 'static, P: Pipeline>(&mut self, pipeline: P) {
201 let _ = self.pipelines.insert(TypeId::of::<T>(), Box::new(pipeline));
202 }
203
204 pub fn get<T: 'static>(&self) -> Option<&dyn Any> {
206 self.pipelines
207 .get(&TypeId::of::<T>())
208 .map(|pipeline| pipeline.as_ref() as &dyn Any)
209 }
210
211 pub fn get_mut<T: 'static>(&mut self) -> Option<&mut dyn Any> {
213 self.pipelines
214 .get_mut(&TypeId::of::<T>())
215 .map(|pipeline| pipeline.as_mut() as &mut dyn Any)
216 }
217
218 pub fn trim(&mut self) {
220 for pipeline in self.pipelines.values_mut() {
221 pipeline.trim();
222 }
223 }
224}