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
28pub struct FramebufferBind<'a> {
30 framebuffer: &'a Framebuffer,
31}
32
33impl Framebuffer {
34 pub fn new(glcore: Rc<GLCore>) -> Self {
36 let mut name: u32 = 0;
37 glcore.glGenFramebuffers(1, &mut name as *mut _);
38 Self {
39 glcore,
40 name,
41 draw_targets: BTreeMap::new(),
42 }
43 }
44
45 pub fn bind<'a>(&'a self) -> FramebufferBind<'a> {
47 FramebufferBind::new(self)
48 }
49}
50
51impl<'a> FramebufferBind<'a> {
52 fn new(framebuffer: &'a Framebuffer) -> Self {
54 framebuffer.glcore.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer.name);
55 Self {
56 framebuffer,
57 }
58 }
59
60 pub fn setup(&self, program: &Shader) {
62 let draw_targets = &self.framebuffer.draw_targets;
63 assert!(!draw_targets.is_empty());
64 let glcore = self.framebuffer.glcore.clone();
65 let mut draw_buffers: Vec<u32> = Vec::with_capacity(draw_targets.len());
66 let mut max_width: u32 = 0;
67 let mut max_height: u32 = 0;
68 for (target_name, target) in draw_targets.iter() {
69 let location = glcore.glGetFragDataLocation(program.get_name(), target_name.as_ptr() as *const i8);
70 if location >= 0 {
71 let location = location as u32;
72 let (target, texture) = target;
73 let attachment = GL_COLOR_ATTACHMENT0 + location;
74 max_width = max(max_width, texture.get_width());
75 max_height = max(max_height, texture.get_height());
76 match texture.get_dim() {
77 TextureDimension::Tex1d => glcore.glFramebufferTexture1D(GL_DRAW_FRAMEBUFFER, attachment, target.texture_target as u32, texture.get_name(), 0),
78 TextureDimension::Tex2d => glcore.glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, attachment, target.texture_target as u32, texture.get_name(), 0),
79 TextureDimension::Tex3d => glcore.glFramebufferTexture3D(GL_DRAW_FRAMEBUFFER, attachment, target.texture_target as u32, texture.get_name(), 0, target.layer_of_3d),
80 TextureDimension::TexCube => glcore.glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, attachment, target.texture_target as u32, texture.get_name(), 0),
81 }
82 draw_buffers.push(attachment);
83 } else {
84 eprintln!("Location of shader output `{target_name}` couldn't be found.");
85 }
86 }
87 glcore.glDrawBuffers(draw_buffers.len() as i32, draw_buffers.as_ptr());
88 glcore.glViewport(0, 0, max_width as i32, max_height as i32);
89 }
90
91 pub fn unbind(self) {}
93}
94
95impl Drop for FramebufferBind<'_> {
96 fn drop(&mut self) {
97 self.framebuffer.glcore.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
98 }
99}
100
101impl Drop for Framebuffer {
102 fn drop(&mut self) {
103 self.glcore.glDeleteFramebuffers(1, &self.name as *const _);
104 }
105}
106
107impl Debug for Framebuffer {
108 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
109 f.debug_struct("Framebuffer")
110 .field("name", &self.name)
111 .finish()
112 }
113}