Loading...
Searching...
No Matches
Framebuffer.cpp
Go to the documentation of this file.
1//
2// Created by denzel on 31/05/2025.
3//
4#include "Framebuffer.h"
5
6#include <iostream>
7#include <GL/glew.h>
8
9namespace hellfire {
12 }
13
16 }
17
19 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_id_);
20
21 uint32_t texture;
22 glGenTextures(1, &texture);
23 glBindTexture(GL_TEXTURE_2D, texture);
24
25 // Allocate texture storage
26 glTexImage2D(GL_TEXTURE_2D, 0, settings.internal_format,
27 settings.width, settings.height, 0,
28 settings.format, settings.type, nullptr);
29
30 // Set texture parameters
31 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, settings.min_filter);
32 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, settings.mag_filter);
33 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, settings.wrap_s);
34 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, settings.wrap_t);
35
36 // Attach to framebuffer
37 const uint32_t attachment_point = GL_COLOR_ATTACHMENT0 + color_attachments_.size();
38 glFramebufferTexture2D(GL_FRAMEBUFFER, attachment_point, GL_TEXTURE_2D, texture, 0);
39
40 color_attachments_.push_back(texture);
41 color_settings_.push_back(settings);
42
43 // Update draw buffers
44 std::vector<GLenum> draw_buffers;
45 for (size_t i = 0; i < color_attachments_.size(); i++) {
46 draw_buffers.push_back(GL_COLOR_ATTACHMENT0 + i);
47 }
48 glDrawBuffers(draw_buffers.size(), draw_buffers.data());
49
50 glBindTexture(GL_TEXTURE_2D, 0);
51 glBindFramebuffer(GL_FRAMEBUFFER, 0);
52 }
53
54 void Framebuffer::attach_texture_by_id(const uint32_t texture_id, GLenum attachment = GL_COLOR_ATTACHMENT0, GLenum target = GL_FRAMEBUFFER) {
55 // Attach to framebuffer
56 glFramebufferTexture2D(target, attachment,
57 GL_TEXTURE_2D, texture_id, 0);
58 }
59
61 if (depth_attachment_ != 0) {
62 std::cerr << "Depth attachment already exists!" << std::endl;
63 return;
64 }
65
66 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_id_);
67
68 glGenTextures(1, &depth_attachment_);
69 glBindTexture(GL_TEXTURE_2D, depth_attachment_);
70
71 // Override format settings for depth texture
72 const GLenum internal_format = settings.internal_format == GL_RGBA8
73 ? GL_DEPTH_COMPONENT32F
74 : settings.internal_format;
75 constexpr GLenum format = GL_DEPTH_COMPONENT;
76 const GLenum type = settings.type == GL_UNSIGNED_BYTE ? GL_FLOAT : settings.type;
77
78 // Allocate texture storage
79 glTexImage2D(GL_TEXTURE_2D, 0, internal_format,
80 settings.width, settings.height, 0,
81 format, type, nullptr);
82
83 // Set texture parameters
84 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, settings.min_filter);
85 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, settings.mag_filter);
86 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, settings.wrap_s);
87 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, settings.wrap_t);
88
89 // Attach to framebuffer
90 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_attachment_, 0);
91
92 // Unbind texture & framebuffer
93 glBindTexture(GL_TEXTURE_2D, 0);
94 glBindFramebuffer(GL_FRAMEBUFFER, 0);
95
96 depth_settings_ = settings;
97 has_depth_ = true;
98 }
99
101 if (stencil_attachment_ != 0) {
102 std::cerr << "Stencil attachment already exists!" << std::endl;
103 return;
104 }
105
106 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_id_);
107
108 glGenTextures(1, &stencil_attachment_);
109 glBindTexture(GL_TEXTURE_2D, stencil_attachment_);
110
111 // Override format settings for stencil texture
112 constexpr GLenum internal_format = GL_STENCIL_INDEX8;
113 constexpr GLenum format = GL_STENCIL_INDEX;
114 constexpr GLenum type = GL_UNSIGNED_BYTE;
115
116 glTexImage2D(GL_TEXTURE_2D, 0, internal_format,
117 settings.width, settings.height, 0,
118 format, type, nullptr);
119
120 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
121 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
122 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, settings.wrap_s);
123 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, settings.wrap_t);
124
125 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, stencil_attachment_, 0);
126
127 glBindTexture(GL_TEXTURE_2D, 0);
128 glBindFramebuffer(GL_FRAMEBUFFER, 0);
129
130 stencil_settings_ = settings; // Store the settings
131 has_stencil_ = true;
132 }
133
134
135 void Framebuffer::bind() const {
136 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_id_);
137
138 // Set viewport based on first color attachment if it exists
139 if (!color_settings_.empty()) {
140 glViewport(0, 0, color_settings_[0].width, color_settings_[0].height);
141 }
142 }
143
145 glBindFramebuffer(GL_FRAMEBUFFER, 0);
146 }
147
148 void Framebuffer::resize(const uint32_t width, const uint32_t height) {
149 // Store current settings
150 bool had_depth = depth_attachment_ != 0;
151 bool had_stencil = stencil_attachment_ != 0;
152
153 std::vector<FrameBufferAttachmentSettings> old_color_settings = color_settings_;
154 FrameBufferAttachmentSettings old_depth_settings = depth_settings_;
155 FrameBufferAttachmentSettings old_stencil_settings = stencil_settings_;
156
157 // Cleanup old resources
158 cleanup();
159
160 // Recreate framebuffer
162
163 // Recreate attachments with new size
164 for (auto &settings: old_color_settings) {
165 settings.width = width;
166 settings.height = height;
167 attach_color_texture(settings);
168 }
169
170 if (had_depth) {
171 old_depth_settings.width = width;
172 old_depth_settings.height = height;
173 attach_depth_texture(old_depth_settings);
174 }
175
176 if (had_stencil) {
177 old_stencil_settings.width = width;
178 old_stencil_settings.height = height;
179 attach_stencil_texture(old_stencil_settings);
180 }
181
182 if (!is_complete()) {
183 std::cerr << "Framebuffer incomplete after resize!" << std::endl;
184 }
185 }
186
187 uint32_t Framebuffer::read_pixel_from_texture(const uint32_t texture_id, const int x, const int y) {
188 std::cout << "FBO ID: " << framebuffer_id_<< ", is valid: " << (glIsFramebuffer(framebuffer_id_) ? "yes" : "no") << std::endl;
189 std::cout << "Texture ID: " << texture_id << ", is valid: " << (glIsTexture(texture_id) ? "yes" : "no") << std::endl;
190
191 // Bind the framebuffer
192 bind();
193 // Attach the texture to the framebuffer
194 attach_texture_by_id(texture_id, GL_COLOR_ATTACHMENT0, GL_READ_FRAMEBUFFER);
195
196 // Set the read buffer to where the texture is attached
197 glReadBuffer(GL_COLOR_ATTACHMENT0);
198
199 // Read the pixel data at x, y position
200 uint32_t pixel_data = 0;
201 glReadPixels(x, y, 1, 1, GL_RED_INTEGER, GL_UNSIGNED_INT, &pixel_data);
202
203 // Unbind the fbo
204 unbind();
205 return pixel_data;
206 }
207
208
209 bool Framebuffer::is_complete() const {
210 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_id_);
211 const GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
212 glBindFramebuffer(GL_FRAMEBUFFER, 0);
213
214 if (status != GL_FRAMEBUFFER_COMPLETE) {
215 std::cerr << "Framebuffer not complete! Status: ";
216 switch (status) {
217 case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
218 std::cerr << "INCOMPLETE_ATTACHMENT" << std::endl;
219 break;
220 case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
221 std::cerr << "INCOMPLETE_MISSING_ATTACHMENT" << std::endl;
222 break;
223 case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
224 std::cerr << "INCOMPLETE_DRAW_BUFFER" << std::endl;
225 break;
226 case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
227 std::cerr << "INCOMPLETE_READ_BUFFER" << std::endl;
228 break;
229 case GL_FRAMEBUFFER_UNSUPPORTED:
230 std::cerr << "UNSUPPORTED" << std::endl;
231 break;
232 default:
233 std::cerr << "UNKNOWN (" << status << ")" << std::endl;
234 break;
235 }
236 return false;
237 }
238
239 return true;
240 }
241
242 uint32_t Framebuffer::get_width() const {
243 return !color_settings_.empty() ? color_settings_[0].width : 0;
244 }
245
246 uint32_t Framebuffer::get_height() const {
247 return !color_settings_.empty() ? color_settings_[0].height : 0;
248 }
249
251 glGenFramebuffers(1, &framebuffer_id_);
252 }
253
255 if (!color_attachments_.empty()) {
256 glDeleteTextures(static_cast<GLsizei>(color_attachments_.size()), color_attachments_.data());
257 color_attachments_.clear();
258 color_settings_.clear();
259 }
260 if (depth_attachment_) {
261 glDeleteTextures(1, &depth_attachment_);
263 }
265 glDeleteTextures(1, &stencil_attachment_);
267 }
268 if (framebuffer_id_) {
269 glDeleteFramebuffers(1, &framebuffer_id_);
270 framebuffer_id_ = 0;
271 }
272 }
273}
uint32_t get_width() const
uint32_t get_height() const
void attach_depth_texture(const FrameBufferAttachmentSettings &settings={})
void attach_color_texture(const FrameBufferAttachmentSettings &settings={})
void attach_stencil_texture(const FrameBufferAttachmentSettings &settings={})
uint32_t stencil_attachment_
Definition Framebuffer.h:86