suzy 0.2.0

GUI framework based on observer pattern
Documentation
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use std::rc::Rc;

use super::context::bindings::types::*;
use super::context::bindings::{
    BLEND_COLOR, CLAMP_TO_EDGE, COLOR_ATTACHMENT0, FRAMEBUFFER,
    FRAMEBUFFER_BINDING, FRAMEBUFFER_COMPLETE, NEAREST, RGBA, TEXTURE_2D,
    TEXTURE_MAG_FILTER, TEXTURE_MIN_FILTER, TEXTURE_WRAP_S, TEXTURE_WRAP_T,
    UNSIGNED_BYTE,
};
use super::context::OpenGlBindings;
use super::texture::TextureData;

gl_object! { FramebufferData, GenFramebuffers, DeleteFramebuffers, 1 }

pub struct Mask {
    tex: TextureData,
    fbo: FramebufferData,
    old_fbo: GLint,
    old_blend_color: [f32; 4],
    pub width: f32,
    pub height: f32,
}

impl Mask {
    pub fn new() -> Self {
        Self {
            tex: TextureData::new(),
            fbo: FramebufferData::new(),
            old_fbo: 0,
            old_blend_color: [0.0; 4],
            width: 0.0,
            height: 0.0,
        }
    }

    pub fn tex_id(&self) -> GLuint {
        self.tex.ids[0]
    }

    pub fn bind_fbo(&mut self, gl: &OpenGlBindings) {
        let color = 1.0 / f32::from(super::drawparams::MASK_LEVELS);
        unsafe {
            gl.GetIntegerv(FRAMEBUFFER_BINDING, &mut self.old_fbo as *mut _);
            gl.GetFloatv(BLEND_COLOR, self.old_blend_color.as_mut_ptr());
            gl.BindFramebuffer(FRAMEBUFFER, self.fbo.ids[0]);
            gl.BlendColor(color, color, color, color);
        }
    }

    pub fn restore_fbo(&mut self, gl: &OpenGlBindings) {
        assert_eq!(self.old_fbo, 0);
        let [r, g, b, a] = self.old_blend_color;
        unsafe {
            gl.BindFramebuffer(FRAMEBUFFER, self.old_fbo as _);
            gl.BlendColor(r, g, b, a);
        }
        self.old_fbo = 0;
    }

    pub fn mask_size(
        &mut self,
        gl: &Rc<OpenGlBindings>,
        width: u32,
        height: u32,
    ) {
        self.tex.check_ready(gl);
        self.fbo.check_ready(gl);
        unsafe {
            gl.BindTexture(TEXTURE_2D, self.tex.ids[0]);
            gl.TexImage2D(
                TEXTURE_2D,
                0,
                RGBA as _,
                width as GLsizei,
                height as GLsizei,
                0,
                RGBA,
                UNSIGNED_BYTE,
                std::ptr::null(),
            );
            gl.TexParameteri(TEXTURE_2D, TEXTURE_MIN_FILTER, NEAREST as _);
            gl.TexParameteri(TEXTURE_2D, TEXTURE_MAG_FILTER, NEAREST as _);
            gl.TexParameteri(TEXTURE_2D, TEXTURE_WRAP_S, CLAMP_TO_EDGE as _);
            gl.TexParameteri(TEXTURE_2D, TEXTURE_WRAP_T, CLAMP_TO_EDGE as _);

            let mut old_fbo: GLint = 0;
            gl.GetIntegerv(FRAMEBUFFER_BINDING, &mut old_fbo as *mut _);
            gl.BindFramebuffer(FRAMEBUFFER, self.fbo.ids[0]);
            gl.FramebufferTexture2D(
                FRAMEBUFFER,
                COLOR_ATTACHMENT0,
                TEXTURE_2D,
                self.tex.ids[0],
                0,
            );
            assert_eq!(
                gl.CheckFramebufferStatus(FRAMEBUFFER),
                FRAMEBUFFER_COMPLETE,
            );
            gl.BindFramebuffer(FRAMEBUFFER, old_fbo as _);
        }
        self.width = width as f32;
        self.height = height as f32;
    }
}