notan_app/
graphics.rs

1use hashbrown::HashMap;
2pub use notan_graphics::prelude::*;
3pub use notan_graphics::*;
4use std::any::{Any, TypeId};
5use std::cell::{Ref, RefCell, RefMut};
6
7/// Graphic interface to interact with the GPU
8/// It's a wrapper for the Device interface and
9/// the graphics extensions
10pub struct Graphics {
11    /// Graphic raw implementation
12    pub device: Device,
13
14    pub extensions: ExtContainer,
15}
16
17impl Graphics {
18    pub fn new(backend: Box<dyn DeviceBackend>) -> Result<Self, String> {
19        let device = Device::new(backend)?;
20        let plugins = ExtContainer::default();
21
22        Ok(Self {
23            device,
24            extensions: plugins,
25        })
26    }
27
28    /// Adds a new graphic extensions
29    #[inline]
30    pub fn add_extension<R, T>(&mut self, extension: T)
31    where
32        R: GfxRenderer,
33        T: GfxExtension<R> + 'static,
34    {
35        self.extensions.add(extension);
36    }
37
38    /// Remove a graphic extensions
39    #[inline]
40    pub fn remove_extension<R, T>(&mut self)
41    where
42        R: GfxRenderer,
43        T: GfxExtension<R> + 'static,
44    {
45        self.extensions.remove::<R, T>();
46    }
47
48    /// Returns the extension as mutable reference
49    #[inline]
50    pub fn extension_mut<R, T>(&self) -> Option<RefMut<'_, T>>
51    where
52        R: GfxRenderer,
53        T: GfxExtension<R> + 'static,
54    {
55        self.extensions.get_mut()
56    }
57
58    /// Returns the extension as reference
59    #[inline]
60    pub fn extension<R, T>(&self) -> Option<Ref<'_, T>>
61    where
62        R: GfxRenderer,
63        T: GfxExtension<R> + 'static,
64    {
65        self.extensions.get()
66    }
67
68    /// Creates a Pipeline builder
69    #[inline]
70    pub fn create_pipeline(&mut self) -> PipelineBuilder<'_, '_> {
71        self.device.create_pipeline()
72    }
73
74    /// Creates a texture builder
75    #[inline]
76    pub fn create_texture(&mut self) -> TextureBuilder<'_, '_> {
77        self.device.create_texture()
78    }
79
80    /// Creates a render texture builder
81    #[inline]
82    pub fn create_render_texture(&mut self, width: u32, height: u32) -> RenderTextureBuilder<'_> {
83        self.device.create_render_texture(width, height)
84    }
85
86    /// Creates a vertex buffer builder
87    #[inline]
88    pub fn create_vertex_buffer(&mut self) -> VertexBufferBuilder<'_> {
89        self.device.create_vertex_buffer()
90    }
91
92    /// Creates a index buffer builder
93    #[inline]
94    pub fn create_index_buffer(&mut self) -> IndexBufferBuilder<'_> {
95        self.device.create_index_buffer()
96    }
97
98    /// Creates a uniform buffer builder
99    #[inline]
100    pub fn create_uniform_buffer(&mut self, slot: u32, name: &str) -> UniformBufferBuilder<'_> {
101        self.device.create_uniform_buffer(slot, name)
102    }
103
104    /// Update the texture data
105    #[inline]
106    pub fn update_texture<'a>(&'a mut self, texture: &'a mut Texture) -> TextureUpdater<'a> {
107        self.device.update_texture(texture)
108    }
109
110    /// Read pixels from a texture
111    #[inline]
112    pub fn read_pixels<'a>(&'a mut self, texture: &'a Texture) -> TextureReader<'a> {
113        self.device.read_pixels(texture)
114    }
115
116    /// Render to the screen
117    #[inline]
118    pub fn render<G: GfxRenderer>(&mut self, renderer: &G) {
119        if let Err(err) = renderer.render(&mut self.device, &mut self.extensions, None) {
120            log::error!("{err}");
121            panic!("{}", err);
122        }
123    }
124
125    /// Render to a custom target
126    #[inline]
127    pub fn render_to<G: GfxRenderer>(&mut self, target: &RenderTexture, renderer: &G) {
128        if let Err(err) = renderer.render(&mut self.device, &mut self.extensions, Some(target)) {
129            log::error!("{err}");
130            panic!("{}", err);
131        }
132    }
133
134    /// Upload the buffer data to the GPU
135    #[inline]
136    pub fn set_buffer_data<T: BufferData>(&mut self, buffer: &Buffer, data: T) {
137        self.device.set_buffer_data(buffer, data);
138    }
139
140    /// Creates a render pass
141    #[inline]
142    pub fn create_renderer(&self) -> Renderer {
143        self.device.create_renderer()
144    }
145
146    /// Returns the Graphics API limits
147    #[inline]
148    pub fn limits(&self) -> Limits {
149        self.device.limits()
150    }
151
152    /// Returns the drawable size
153    #[inline]
154    pub fn size(&self) -> (u32, u32) {
155        self.device.size()
156    }
157
158    /// Sets the drawable size
159    #[inline]
160    pub fn set_size(&mut self, width: u32, height: u32) {
161        self.device.set_size(width, height);
162    }
163
164    /// Returns the screen dpi
165    #[inline]
166    pub fn dpi(&self) -> f64 {
167        self.device.dpi()
168    }
169
170    /// Sets the screens dpi
171    #[inline]
172    pub fn set_dpi(&mut self, scale_factor: f64) {
173        self.device.set_dpi(scale_factor);
174    }
175
176    /// Return the GPU stats
177    #[inline]
178    pub fn stats(&self) -> GpuStats {
179        self.device.stats()
180    }
181}
182
183impl std::ops::Deref for Graphics {
184    type Target = Device;
185
186    fn deref(&self) -> &Self::Target {
187        &self.device
188    }
189}
190
191impl std::ops::DerefMut for Graphics {
192    fn deref_mut(&mut self) -> &mut Self::Target {
193        &mut self.device
194    }
195}
196
197/// Graphic extensions container
198#[derive(Default)]
199pub struct ExtContainer {
200    map: HashMap<TypeId, Box<dyn Any>>,
201}
202
203impl ExtContainer {
204    /// Adds a graphics extension
205    #[inline]
206    pub fn add<R, T>(&mut self, value: T)
207    where
208        R: GfxRenderer,
209        T: GfxExtension<R> + 'static,
210    {
211        self.map
212            .insert(TypeId::of::<T>(), Box::new(RefCell::new(value)));
213    }
214
215    /// Returns the extension as mutable reference
216    #[inline]
217    pub fn get_mut<R, T>(&self) -> Option<RefMut<'_, T>>
218    where
219        R: GfxRenderer,
220        T: GfxExtension<R> + 'static,
221    {
222        self.map
223            .get(&TypeId::of::<T>())?
224            .downcast_ref::<RefCell<T>>()
225            .map(|value| value.borrow_mut())
226    }
227
228    /// Returns the extension
229    #[inline]
230    pub fn get<R, T>(&self) -> Option<Ref<'_, T>>
231    where
232        R: GfxRenderer,
233        T: GfxExtension<R> + 'static,
234    {
235        self.map
236            .get(&TypeId::of::<T>())?
237            .downcast_ref::<RefCell<T>>()
238            .map(|value| value.borrow())
239    }
240
241    /// Remove the extension
242    #[inline]
243    pub fn remove<R, T>(&mut self)
244    where
245        R: GfxRenderer,
246        T: GfxExtension<R> + 'static,
247    {
248        self.map.remove(&TypeId::of::<T>());
249    }
250}
251
252/// Represents an object that contains render commands
253pub trait GfxRenderer {
254    /// Send the commands to the gpu to be rendered
255    fn render(
256        &self,
257        device: &mut Device,
258        extensions: &mut ExtContainer,
259        target: Option<&RenderTexture>,
260    ) -> Result<(), String>;
261}
262
263pub trait GfxExtension<T: ?Sized> {}
264
265impl GfxRenderer for Renderer {
266    fn render(
267        &self,
268        device: &mut Device,
269        _extensions: &mut ExtContainer,
270        target: Option<&RenderTexture>,
271    ) -> Result<(), String> {
272        match target {
273            None => device.render(self.commands()),
274            Some(rt) => device.render_to(rt, self.commands()),
275        }
276
277        Ok(())
278    }
279}