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