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(
48 &self,
49 _pipeline: &Self::Pipeline,
50 _render_pass: &mut wgpu::RenderPass<'_>,
51 ) -> bool {
52 false
53 }
54
55 fn render(
61 &self,
62 _pipeline: &Self::Pipeline,
63 _encoder: &mut wgpu::CommandEncoder,
64 _target: &wgpu::TextureView,
65 _clip_bounds: &Rectangle<u32>,
66 ) {
67 }
68}
69
70pub trait Pipeline: Any + MaybeSend + MaybeSync {
72 fn new(
77 device: &wgpu::Device,
78 queue: &wgpu::Queue,
79 format: wgpu::TextureFormat,
80 ) -> Self
81 where
82 Self: Sized;
83
84 fn trim(&mut self) {}
88}
89
90pub(crate) trait Stored:
91 Debug + MaybeSend + MaybeSync + 'static
92{
93 fn prepare(
94 &self,
95 storage: &mut Storage,
96 device: &wgpu::Device,
97 queue: &wgpu::Queue,
98 format: wgpu::TextureFormat,
99 bounds: &Rectangle,
100 viewport: &Viewport,
101 );
102
103 fn draw(
104 &self,
105 storage: &Storage,
106 render_pass: &mut wgpu::RenderPass<'_>,
107 ) -> bool;
108
109 fn render(
110 &self,
111 storage: &Storage,
112 encoder: &mut wgpu::CommandEncoder,
113 target: &wgpu::TextureView,
114 clip_bounds: &Rectangle<u32>,
115 );
116}
117
118#[derive(Debug)]
119struct BlackBox<P: Primitive> {
120 primitive: P,
121}
122
123impl<P: Primitive> Stored for BlackBox<P> {
124 fn prepare(
125 &self,
126 storage: &mut Storage,
127 device: &wgpu::Device,
128 queue: &wgpu::Queue,
129 format: wgpu::TextureFormat,
130 bounds: &Rectangle,
131 viewport: &Viewport,
132 ) {
133 if !storage.has::<P>() {
134 storage.store::<P, _>(P::Pipeline::new(device, queue, format));
135 }
136
137 let renderer = storage
138 .get_mut::<P>()
139 .expect("renderer should be initialized")
140 .downcast_mut::<P::Pipeline>()
141 .expect("renderer should have the proper type");
142
143 self.primitive
144 .prepare(renderer, device, queue, bounds, viewport);
145 }
146
147 fn draw(
148 &self,
149 storage: &Storage,
150 render_pass: &mut wgpu::RenderPass<'_>,
151 ) -> bool {
152 let renderer = storage
153 .get::<P>()
154 .expect("renderer should be initialized")
155 .downcast_ref::<P::Pipeline>()
156 .expect("renderer should have the proper type");
157
158 self.primitive.draw(renderer, render_pass)
159 }
160
161 fn render(
162 &self,
163 storage: &Storage,
164 encoder: &mut wgpu::CommandEncoder,
165 target: &wgpu::TextureView,
166 clip_bounds: &Rectangle<u32>,
167 ) {
168 let renderer = storage
169 .get::<P>()
170 .expect("renderer should be initialized")
171 .downcast_ref::<P::Pipeline>()
172 .expect("renderer should have the proper type");
173
174 self.primitive
175 .render(renderer, encoder, target, clip_bounds);
176 }
177}
178
179#[derive(Debug)]
180pub struct Instance {
182 pub(crate) bounds: Rectangle,
184
185 pub(crate) primitive: Box<dyn Stored>,
187}
188
189impl Instance {
190 pub fn new(bounds: Rectangle, primitive: impl Primitive) -> Self {
192 Instance {
193 bounds,
194 primitive: Box::new(BlackBox { primitive }),
195 }
196 }
197}
198
199pub trait Renderer: core::Renderer {
201 fn draw_primitive(&mut self, bounds: Rectangle, primitive: impl Primitive);
203}
204
205#[derive(Default)]
207pub struct Storage {
208 pipelines: FxHashMap<TypeId, Box<dyn Pipeline>>,
209}
210
211impl Storage {
212 pub fn has<T: 'static>(&self) -> bool {
214 self.pipelines.contains_key(&TypeId::of::<T>())
215 }
216
217 pub fn store<T: 'static, P: Pipeline>(&mut self, pipeline: P) {
219 let _ = self.pipelines.insert(TypeId::of::<T>(), Box::new(pipeline));
220 }
221
222 pub fn get<T: 'static>(&self) -> Option<&dyn Any> {
224 self.pipelines
225 .get(&TypeId::of::<T>())
226 .map(|pipeline| pipeline.as_ref() as &dyn Any)
227 }
228
229 pub fn get_mut<T: 'static>(&mut self) -> Option<&mut dyn Any> {
231 self.pipelines
232 .get_mut(&TypeId::of::<T>())
233 .map(|pipeline| pipeline.as_mut() as &mut dyn Any)
234 }
235
236 pub fn trim(&mut self) {
238 for pipeline in self.pipelines.values_mut() {
239 pipeline.trim();
240 }
241 }
242}