spitfire_draw/
canvas.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
use crate::{
    context::DrawContext,
    sprite::SpriteTexture,
    utils::{TextureRef, Vertex},
};
use spitfire_glow::{
    graphics::{Graphics, Surface},
    renderer::{GlowTextureFiltering, GlowTextureFormat},
};
use std::borrow::Cow;

pub struct Canvas {
    surface: Surface,
}

impl Canvas {
    pub fn simple(
        width: u32,
        height: u32,
        format: GlowTextureFormat,
        graphics: &Graphics<Vertex>,
    ) -> Result<Self, String> {
        Ok(Self {
            surface: graphics.surface(vec![graphics
                .texture(width, height, 1, format, None)?
                .into()])?,
        })
    }

    pub fn from_surface(surface: Surface) -> Self {
        Self { surface }
    }

    pub fn from_screen(
        texture_formats: Vec<GlowTextureFormat>,
        graphics: &Graphics<Vertex>,
    ) -> Result<Self, String> {
        let width = graphics.main_camera.screen_size.x as _;
        let height = graphics.main_camera.screen_size.y as _;
        Ok(Self {
            surface: graphics.surface(
                texture_formats
                    .into_iter()
                    .filter_map(|format| {
                        graphics
                            .texture(width, height, 1, format, None)
                            .ok()
                            .map(|texture| texture.into())
                    })
                    .collect(),
            )?,
        })
    }

    pub fn color(mut self, color: [f32; 4]) -> Self {
        self.surface.set_color(color);
        self
    }

    pub fn match_to_screen(&mut self, graphics: &Graphics<Vertex>) -> Result<(), String> {
        let width = graphics.main_camera.screen_size.x as _;
        let height = graphics.main_camera.screen_size.y as _;
        if self.surface.width() != width || self.surface.height() != height {
            self.surface = graphics.surface(
                self.surface
                    .attachments()
                    .iter()
                    .filter_map(|attachment| {
                        graphics
                            .texture(width, height, 1, attachment.texture.format(), None)
                            .ok()
                            .map(|texture| texture.into())
                    })
                    .collect(),
            )?;
        }
        Ok(())
    }

    pub fn activate(
        &self,
        context: &mut DrawContext,
        graphics: &mut Graphics<Vertex>,
        clear: bool,
    ) {
        context.end_frame();
        let _ = graphics.draw();
        let _ = graphics.push_surface(self.surface.clone());
        let _ = graphics.prepare_frame(clear);
        context.begin_frame(graphics);
    }

    pub fn deactivate(context: &mut DrawContext, graphics: &mut Graphics<Vertex>) {
        context.end_frame();
        let _ = graphics.draw();
        let _ = graphics.pop_surface();
        let _ = graphics.prepare_frame(false);
        context.begin_frame(graphics);
    }

    pub fn with<R>(
        &self,
        context: &mut DrawContext,
        graphics: &mut Graphics<Vertex>,
        clear: bool,
        mut f: impl FnMut(&mut DrawContext, &mut Graphics<Vertex>) -> R,
    ) -> R {
        self.activate(context, graphics, clear);
        let result = f(context, graphics);
        Self::deactivate(context, graphics);
        result
    }

    pub fn surface(&self) -> &Surface {
        &self.surface
    }

    pub fn surface_mut(&mut self) -> &mut Surface {
        &mut self.surface
    }

    pub fn sprite_texture(
        &self,
        index: usize,
        sampler: Cow<'static, str>,
        filtering: GlowTextureFiltering,
    ) -> Option<SpriteTexture> {
        Some(SpriteTexture {
            sampler,
            texture: TextureRef::object(self.surface.attachments().get(index)?.texture.clone()),
            filtering,
        })
    }
}