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
extern crate gl;

use crate::{GlBind, GlObject, GlTarget, GlEnum};
use crate::texture::GlTexture;

#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum FramebufferAttachment {
    ColorAttachment(u32),
    DepthAttachment,
    StencilAttachment
}

impl Default for FramebufferAttachment {
    fn default() -> Self {
        FramebufferAttachment::ColorAttachment(0)
    }
}

impl GlEnum for FramebufferAttachment {
    fn to_enum(&self) -> u32 {
        match self {
            Self::ColorAttachment(c) => { return gl::COLOR_ATTACHMENT0 + c; },
            Self::DepthAttachment => { return gl::DEPTH_ATTACHMENT },
            Self::StencilAttachment => { return gl::STENCIL_ATTACHMENT }
        }
    }
}

#[derive(Default, Debug, Eq, PartialEq)]
pub struct Framebuffer(u32);

/******************************
 * Framebuffer
 ******************************/
impl Framebuffer {
    pub fn new() -> Result<Self, String> {
        let mut handle: u32 = 0;
        unsafe {
            gl::GenFramebuffers(1, &mut handle);
        }
        Ok(Framebuffer(handle))
    }

    pub fn attach_texture<T: GlTexture>(&self, attachment: FramebufferAttachment, texture: &T) {
        unsafe {
            gl::FramebufferTexture2D(
                Self::target(),
                attachment.to_enum(), 
                T::target(), texture.get_id(), 0
            );
        }
    }

    pub fn bind_read(&self) {
        unsafe { gl::BindFramebuffer(gl::READ_FRAMEBUFFER, self.0) };
    }

    pub fn bind_draw(&self) {
        unsafe { gl::BindFramebuffer(gl::DRAW_FRAMEBUFFER, self.0) };
    }
}

impl GlTarget for Framebuffer {
    fn target() -> u32 { gl::FRAMEBUFFER }
    fn binding() -> u32 { gl::FRAMEBUFFER_BINDING }
}

impl GlObject for Framebuffer {
    fn get_id(&self) -> u32 {
        self.0
    }
}

impl GlBind for Framebuffer {
    fn bind(&self) {
        unsafe { gl::BindFramebuffer(Self::target(), self.0) };
    }

    fn unbind(&self) {
        unsafe { gl::BindFramebuffer(Self::target(), 0) };
    }
}

impl Drop for Framebuffer {
    fn drop(&mut self) {
        unsafe { gl::DeleteFramebuffers(1, &self.0) };
    }
}