spitfire_draw/
canvas.rs

1use crate::{
2    context::DrawContext,
3    sprite::SpriteTexture,
4    utils::{TextureRef, Vertex},
5};
6use spitfire_glow::{
7    graphics::{Graphics, Surface},
8    renderer::{GlowTextureFiltering, GlowTextureFormat},
9};
10use std::borrow::Cow;
11
12pub struct Canvas {
13    surface: Surface,
14}
15
16impl Canvas {
17    pub fn simple(
18        width: u32,
19        height: u32,
20        format: GlowTextureFormat,
21        graphics: &Graphics<Vertex>,
22    ) -> Result<Self, String> {
23        Ok(Self {
24            surface: graphics.surface(vec![graphics
25                .texture(width, height, 1, format, None)?
26                .into()])?,
27        })
28    }
29
30    pub fn from_surface(surface: Surface) -> Self {
31        Self { surface }
32    }
33
34    pub fn from_screen(
35        texture_formats: Vec<GlowTextureFormat>,
36        graphics: &Graphics<Vertex>,
37    ) -> Result<Self, String> {
38        let width = graphics.main_camera.screen_size.x as _;
39        let height = graphics.main_camera.screen_size.y as _;
40        Ok(Self {
41            surface: graphics.surface(
42                texture_formats
43                    .into_iter()
44                    .filter_map(|format| {
45                        graphics
46                            .texture(width, height, 1, format, None)
47                            .ok()
48                            .map(|texture| texture.into())
49                    })
50                    .collect(),
51            )?,
52        })
53    }
54
55    pub fn color(mut self, color: [f32; 4]) -> Self {
56        self.surface.set_color(color);
57        self
58    }
59
60    pub fn match_to_screen(&mut self, graphics: &Graphics<Vertex>) -> Result<(), String> {
61        let width = graphics.main_camera.screen_size.x as _;
62        let height = graphics.main_camera.screen_size.y as _;
63        if self.surface.width() != width || self.surface.height() != height {
64            self.surface = graphics.surface(
65                self.surface
66                    .attachments()
67                    .iter()
68                    .filter_map(|attachment| {
69                        graphics
70                            .texture(width, height, 1, attachment.texture.format(), None)
71                            .ok()
72                            .map(|texture| texture.into())
73                    })
74                    .collect(),
75            )?;
76        }
77        Ok(())
78    }
79
80    pub fn activate(
81        &self,
82        context: &mut DrawContext,
83        graphics: &mut Graphics<Vertex>,
84        clear: bool,
85    ) {
86        context.end_frame();
87        let _ = graphics.draw();
88        let _ = graphics.push_surface(self.surface.clone());
89        let _ = graphics.prepare_frame(clear);
90        context.begin_frame(graphics);
91    }
92
93    pub fn deactivate(context: &mut DrawContext, graphics: &mut Graphics<Vertex>) {
94        context.end_frame();
95        let _ = graphics.draw();
96        let _ = graphics.pop_surface();
97        let _ = graphics.prepare_frame(false);
98        context.begin_frame(graphics);
99    }
100
101    pub fn with<R>(
102        &self,
103        context: &mut DrawContext,
104        graphics: &mut Graphics<Vertex>,
105        clear: bool,
106        mut f: impl FnMut(&mut DrawContext, &mut Graphics<Vertex>) -> R,
107    ) -> R {
108        self.activate(context, graphics, clear);
109        let result = f(context, graphics);
110        Self::deactivate(context, graphics);
111        result
112    }
113
114    pub fn surface(&self) -> &Surface {
115        &self.surface
116    }
117
118    pub fn surface_mut(&mut self) -> &mut Surface {
119        &mut self.surface
120    }
121
122    pub fn sprite_texture(
123        &self,
124        index: usize,
125        sampler: Cow<'static, str>,
126        filtering: GlowTextureFiltering,
127    ) -> Option<SpriteTexture> {
128        Some(SpriteTexture {
129            sampler,
130            texture: TextureRef::object(self.surface.attachments().get(index)?.texture.clone()),
131            filtering,
132        })
133    }
134}