summaryrefslogtreecommitdiff
path: root/crates/renderer/src/overlay/drawing.rs
blob: 93bf85b50397a6cb58af3a0937f610b640b49bf5 (plain)
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
use teleia::*;

use glow::HasContext;

use crate::{input, overlay};

pub const SCALE: usize = 4;
pub const WIDTH: usize = 1920 / SCALE;
pub const HEIGHT: usize = 1080 / SCALE;
pub struct Overlay {
    pub tex: texture::Texture,
    pub pixels: [u8; WIDTH * HEIGHT],
    pub last_point: Option<(i32, i32)>,
    pub shader_white: shader::Shader,
    pub shader_background: shader::Shader,
}
impl Overlay {
    pub fn new(ctx: &context::Context) -> Self {
        let shader_background = shader::Shader::new(
            ctx,
            include_str!("../assets/shaders/background/vert.glsl"),
            include_str!("../assets/shaders/background/frag.glsl"),
        );
        shader_background.set_i32(ctx, "background", 1);
        Self {
            tex: texture::Texture::new_empty(ctx),
            pixels: [0; WIDTH * HEIGHT],
            last_point: None,
            shader_white: shader::Shader::new(
                ctx,
                include_str!("../assets/shaders/white/vert.glsl"),
                include_str!("../assets/shaders/white/frag.glsl"),
            ),
            shader_background,
        }
    }
    pub fn coord(&self, x: usize, y: usize) -> Option<usize> {
        if x >= WIDTH || y >= HEIGHT {
            None
        } else {
            Some(x + y * WIDTH)
        }
    }
    pub fn set(&mut self, val: u8, x: i32, y: i32) {
        self.coord(x as usize, y as usize).map(|idx| self.pixels[idx] = val);
    }
    pub fn point(&mut self, val: u8, x: i32, y: i32) {
        self.set(val, x, y - 1);
        self.set(val, x - 1, y);
        self.set(val, x, y);
        self.set(val, x + 1, y);
        self.set(val, x, y + 1);
    }
    pub fn line(&mut self, val: u8, (mut x0, mut y0): (i32, i32), (x1, y1): (i32, i32)) {
        let dx = (x1 - x0).abs();
        let sx = if x0 < x1 { 1 } else { -1 };
        let dy = -((y1 - y0).abs());
        let sy = if y0 < y1 { 1 } else { -1 };
        let mut error = dx + dy;
        loop {
            self.point(val, x0, y0);
            let e2 = 2 * error;
            if e2 >= dy {
                if x0 == x1 { break; }
                error += dy;
                x0 += sx;
            }
            if e2 <= dx {
                if y0 == y1 { break; }
                error += dx;
                y0 += sy;
            }
        }
    }
    pub fn upload(&self, ctx: &context::Context) {
        unsafe {
            let err = ctx.gl.get_error();
            self.tex.bind(ctx);
            ctx.gl.tex_image_2d(
                glow::TEXTURE_2D,
                0,
                glow::R8 as i32,
                WIDTH as i32,
                HEIGHT as i32,
                0,
                glow::RED,
                glow::UNSIGNED_BYTE,
                Some(&self.pixels),
            );
            ctx.gl.generate_mipmap(glow::TEXTURE_2D);
        }
    }
}
impl overlay::Overlay for Overlay {
    fn update(&mut self, ctx: &context::Context, st: &mut state::State, ost: &mut overlay::State) -> Erm<()> {
        match ost.input.get_command() {
            input::Command::Drawing => {
                let (sx, sy) = ost.input.get_mouse();
                let x = sx / (SCALE as i32);
                let y = sy / (SCALE as i32);
                if let Some(last) = self.last_point {
                    self.line(1, last, (x, y));
                } else {
                    self.point(1, x, y);
                }
                self.last_point = Some((x, y));
            },
            input::Command::EraseAll => {
                self.pixels.fill(0);
                self.last_point = None;
            },
            input::Command::None => {
                self.last_point = None;
            },
        }
        self.upload(ctx);
        Ok(())
    }
    fn render(&mut self, ctx: &context::Context, st: &mut state::State, ost: &mut overlay::State) -> Erm<()> {
        st.bind_2d(ctx, &self.shader_background);
        self.tex.bind(ctx);
        ost.backgrounds.drawing.bind_index(ctx, 1);
        self.shader_background.set_position_2d(
            ctx, st,
            &glam::Vec2::new(0.0, 0.0),
            &glam::Vec2::new(1920.0, 1080.0)
        );
        st.mesh_square.render(ctx);
        Ok(())
    }
}