globject_rs/
glframebuffer.rs1
2use crate::prelude::*;
3use std::{
4 cmp::max,
5 collections::BTreeMap,
6 fmt::{self, Debug, Formatter},
7 rc::Rc,
8};
9
10pub struct FramebufferTarget {
12 pub texture_target: TextureTarget,
14
15 pub layer_of_3d: i32,
17}
18
19pub struct Framebuffer {
21 pub glcore: Rc<GLCore>,
22 name: u32,
23
24 pub draw_targets: BTreeMap<String, (FramebufferTarget, Rc<dyn GenericTexture>)>,
26}
27
28#[derive(Debug, Clone)]
30pub enum FramebufferError {
31 NoDefaultFramebuffer,
32 IncompleteAttachment,
33 IncompleteMissingAttachment,
34 IncompleteDrawBuffer,
35 IncompleteReadBuffer,
36 Unsupported,
37 IncompleteMultisample,
38 IncompleteLayerTarget,
39 UnknownError(GLenum),
40 GLCoreError(GLCoreError),
41}
42
43impl From<GLCoreError> for FramebufferError {
44 fn from(val: GLCoreError) -> Self {
45 Self::GLCoreError(val)
46 }
47}
48
49pub struct FramebufferBind<'a> {
51 framebuffer: &'a Framebuffer,
52}
53
54impl Framebuffer {
55 pub fn new(glcore: Rc<GLCore>) -> Result<Self, FramebufferError> {
57 let mut name: u32 = 0;
58 glcore.glGenFramebuffers(1, &mut name as *mut _)?;
59 Ok(Self {
60 glcore,
61 name,
62 draw_targets: BTreeMap::new(),
63 })
64 }
65
66 pub fn bind<'a>(&'a self) -> Result<FramebufferBind<'a>, FramebufferError> {
68 FramebufferBind::new(self)
69 }
70
71 pub fn default_bind(glcore: &GLCore) -> Result<(), FramebufferError> {
73 glcore.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0)?;
74 Ok(())
75 }
76}
77
78impl<'a> FramebufferBind<'a> {
79 fn new(framebuffer: &'a Framebuffer) -> Result<Self, FramebufferError> {
81 framebuffer.glcore.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer.name)?;
82 Ok(Self {
83 framebuffer,
84 })
85 }
86
87 pub fn setup(&self, program: &Shader) -> Result<(), FramebufferError> {
89 let draw_targets = &self.framebuffer.draw_targets;
90 assert!(!draw_targets.is_empty());
91 let glcore = self.framebuffer.glcore.clone();
92 let mut draw_buffers: Vec<u32> = Vec::with_capacity(draw_targets.len());
93 let mut max_width: u32 = 0;
94 let mut max_height: u32 = 0;
95 for (target_name, target) in draw_targets.iter() {
96 let location = glcore.glGetFragDataLocation(program.get_name(), target_name.as_ptr() as *const i8)?;
97 if location >= 0 {
98 let location = location as u32;
99 let (target, texture) = target;
100 let attachment = GL_COLOR_ATTACHMENT0 + location;
101 max_width = max(max_width, texture.get_width());
102 max_height = max(max_height, texture.get_height());
103 match texture.get_dim() {
104 TextureDimension::Tex1d => glcore.glFramebufferTexture1D(GL_DRAW_FRAMEBUFFER, attachment, target.texture_target as u32, texture.get_name(), 0)?,
105 TextureDimension::Tex2d => glcore.glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, attachment, target.texture_target as u32, texture.get_name(), 0)?,
106 TextureDimension::Tex3d => glcore.glFramebufferTexture3D(GL_DRAW_FRAMEBUFFER, attachment, target.texture_target as u32, texture.get_name(), 0, target.layer_of_3d)?,
107 TextureDimension::TexCube => glcore.glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, attachment, target.texture_target as u32, texture.get_name(), 0)?,
108 }
109 draw_buffers.push(attachment);
110 } else {
111 eprintln!("Location of shader output `{target_name}` couldn't be found.");
112 }
113 }
114 glcore.glDrawBuffers(draw_buffers.len() as i32, draw_buffers.as_ptr())?;
115 match glcore.glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) ?{
116 GL_FRAMEBUFFER_COMPLETE => {},
117 GL_FRAMEBUFFER_UNDEFINED => return Err(FramebufferError::NoDefaultFramebuffer),
118 GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT => return Err(FramebufferError::IncompleteAttachment),
119 GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT => return Err(FramebufferError::IncompleteMissingAttachment),
120 GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER => return Err(FramebufferError::IncompleteDrawBuffer),
121 GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER => return Err(FramebufferError::IncompleteReadBuffer),
122 GL_FRAMEBUFFER_UNSUPPORTED => return Err(FramebufferError::Unsupported),
123 GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE => return Err(FramebufferError::IncompleteMultisample),
124 GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS => return Err(FramebufferError::IncompleteLayerTarget),
125 other => return Err(FramebufferError::UnknownError(other)),
126 }
127 glcore.glViewport(0, 0, max_width as i32, max_height as i32)?;
128 Ok(())
129 }
130
131 pub fn unbind(self) {}
133}
134
135impl Drop for FramebufferBind<'_> {
136 fn drop(&mut self) {
137 self.framebuffer.glcore.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0).unwrap();
138 }
139}
140
141impl Drop for Framebuffer {
142 fn drop(&mut self) {
143 self.glcore.glDeleteFramebuffers(1, &self.name as *const _).unwrap();
144 }
145}
146
147impl Debug for Framebuffer {
148 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
149 f.debug_struct("Framebuffer")
150 .field("name", &self.name)
151 .finish()
152 }
153}