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 Renderer: MaybeSend + MaybeSync;
23
24 fn initialize(
29 &self,
30 device: &wgpu::Device,
31 queue: &wgpu::Queue,
32 format: wgpu::TextureFormat,
33 ) -> Self::Renderer;
34
35 fn prepare(
37 &self,
38 renderer: &mut Self::Renderer,
39 device: &wgpu::Device,
40 queue: &wgpu::Queue,
41 bounds: &Rectangle,
42 viewport: &Viewport,
43 );
44
45 fn draw(
59 &self,
60 _renderer: &Self::Renderer,
61 _render_pass: &mut wgpu::RenderPass<'_>,
62 ) -> bool {
63 false
64 }
65
66 fn render(
72 &self,
73 _renderer: &Self::Renderer,
74 _encoder: &mut wgpu::CommandEncoder,
75 _target: &wgpu::TextureView,
76 _clip_bounds: &Rectangle<u32>,
77 ) {
78 }
79}
80
81pub(crate) trait Stored:
82 Debug + MaybeSend + MaybeSync + 'static
83{
84 fn prepare(
85 &self,
86 storage: &mut Storage,
87 device: &wgpu::Device,
88 queue: &wgpu::Queue,
89 format: wgpu::TextureFormat,
90 bounds: &Rectangle,
91 viewport: &Viewport,
92 );
93
94 fn draw(
95 &self,
96 storage: &Storage,
97 render_pass: &mut wgpu::RenderPass<'_>,
98 ) -> bool;
99
100 fn render(
101 &self,
102 storage: &Storage,
103 encoder: &mut wgpu::CommandEncoder,
104 target: &wgpu::TextureView,
105 clip_bounds: &Rectangle<u32>,
106 );
107}
108
109#[derive(Debug)]
110struct BlackBox<P: Primitive> {
111 primitive: P,
112}
113
114impl<P: Primitive> Stored for BlackBox<P> {
115 fn prepare(
116 &self,
117 storage: &mut Storage,
118 device: &wgpu::Device,
119 queue: &wgpu::Queue,
120 format: wgpu::TextureFormat,
121 bounds: &Rectangle,
122 viewport: &Viewport,
123 ) {
124 if !storage.has::<P>() {
125 storage.store::<P, _>(
126 self.primitive.initialize(device, queue, format),
127 );
128 }
129
130 let renderer = storage
131 .get_mut::<P>()
132 .expect("renderer should be initialized")
133 .downcast_mut::<P::Renderer>()
134 .expect("renderer should have the proper type");
135
136 self.primitive
137 .prepare(renderer, device, queue, bounds, viewport);
138 }
139
140 fn draw(
141 &self,
142 storage: &Storage,
143 render_pass: &mut wgpu::RenderPass<'_>,
144 ) -> bool {
145 let renderer = storage
146 .get::<P>()
147 .expect("renderer should be initialized")
148 .downcast_ref::<P::Renderer>()
149 .expect("renderer should have the proper type");
150
151 self.primitive.draw(renderer, render_pass)
152 }
153
154 fn render(
155 &self,
156 storage: &Storage,
157 encoder: &mut wgpu::CommandEncoder,
158 target: &wgpu::TextureView,
159 clip_bounds: &Rectangle<u32>,
160 ) {
161 let renderer = storage
162 .get::<P>()
163 .expect("renderer should be initialized")
164 .downcast_ref::<P::Renderer>()
165 .expect("renderer should have the proper type");
166
167 self.primitive
168 .render(renderer, encoder, target, clip_bounds);
169 }
170}
171
172#[derive(Debug)]
173pub struct Instance {
175 pub(crate) bounds: Rectangle,
177
178 pub(crate) primitive: Box<dyn Stored>,
180}
181
182impl Instance {
183 pub fn new(bounds: Rectangle, primitive: impl Primitive) -> Self {
185 Instance {
186 bounds,
187 primitive: Box::new(BlackBox { primitive }),
188 }
189 }
190}
191
192pub trait Renderer: core::Renderer {
194 fn draw_primitive(&mut self, bounds: Rectangle, primitive: impl Primitive);
196}
197
198#[derive(Default)]
200pub struct Storage {
201 pipelines: FxHashMap<TypeId, Box<dyn AnyConcurrent>>,
202}
203
204impl Storage {
205 pub fn has<T: 'static>(&self) -> bool {
207 self.pipelines.contains_key(&TypeId::of::<T>())
208 }
209
210 pub fn store<T: 'static, D: Any + MaybeSend + MaybeSync>(
212 &mut self,
213 data: D,
214 ) {
215 let _ = self.pipelines.insert(TypeId::of::<T>(), Box::new(data));
216 }
217
218 pub fn get<T: 'static>(&self) -> Option<&dyn Any> {
220 self.pipelines
221 .get(&TypeId::of::<T>())
222 .map(|pipeline| pipeline.as_ref() as &dyn Any)
223 }
224
225 pub fn get_mut<T: 'static>(&mut self) -> Option<&mut dyn Any> {
227 self.pipelines
228 .get_mut(&TypeId::of::<T>())
229 .map(|pipeline| pipeline.as_mut() as &mut dyn Any)
230 }
231}
232
233trait AnyConcurrent: Any + MaybeSend + MaybeSync {}
234
235impl<T> AnyConcurrent for T where T: Any + MaybeSend + MaybeSync {}