Brenta Engine 1.2
Loading...
Searching...
No Matches
framebuffer.cpp
1// SPDX-License-Identifier: MIT
2// Author: Giovanni Santini
3// Mail: giovanni.santini@proton.me
4// Github: @San7o
5
6#include <brenta/renderer/opengl/framebuffer.hpp>
7#include <brenta/renderer/opengl/gl.hpp>
8#include <brenta/logger.hpp>
9#include <brenta/window.hpp>
10
11#include <stdexcept>
12
13using namespace brenta;
14
15int FrameBuffer::tot_memory = 0;
16
17FrameBuffer::FrameBuffer(int width, int height, GLenum color_format)
18{
19 // Save the current state
20 GLint old_fbo, old_tex, old_rbo;
21 glGetIntegerv(GL_FRAMEBUFFER_BINDING, &old_fbo);
22 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_tex);
23 glGetIntegerv(GL_RENDERBUFFER_BINDING, &old_rbo);
24
25 this->width = width;
26 this->height = height;
27 this->color_format = color_format;
28
29 glGenFramebuffers(1, &this->id);
30 if (this->id == 0)
31 {
32 ERROR("framebuffer: error generating framebuffer");
33 throw std::runtime_error("framebuffer: error generating framebuffer");
34 }
35 glBindFramebuffer(GL_FRAMEBUFFER, this->id);
36 check_error();
37
38 glGenTextures(1, &this->texture_id);
39 if (this->texture_id == 0)
40 {
41 ERROR("framebuffer: error generating texture");
42 exit(1);
43 }
44 glBindTexture(GL_TEXTURE_2D, this->texture_id);
45 check_error();
46
47 glTexImage2D(GL_TEXTURE_2D, 0, this->color_format, width, height, 0, GL_RGB,
48 this->channel_type, NULL);
49 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
50 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
51 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
52 this->texture_id, 0);
53
54 glGenRenderbuffers(1, &this->render_buffer_id);
55 glBindRenderbuffer(GL_RENDERBUFFER, this->render_buffer_id);
56 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
57 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
58 GL_RENDERBUFFER, this->render_buffer_id);
59 check_error();
60
61 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
62 {
63 ERROR("framebuffer: not complete");
64 exit(1);
65 }
66
67 // Restore old state
68 glBindFramebuffer(GL_FRAMEBUFFER, old_fbo);
69 glBindTexture(GL_TEXTURE_2D, old_tex);
70 glBindRenderbuffer(GL_RENDERBUFFER, old_rbo);
71
72 // Update memory for profiling
73 int channels = Gl::get_num_channels(this->color_format);
74 int bytes_per_channel = Gl::get_bytes_per_channel(this->channel_type);
75 this->memory = channels * bytes_per_channel * width * height;
76 FrameBuffer::tot_memory += this->memory;
77
78 EVENT(Logger::Event::Lifetime, "framebuffer: initialized");
79 return;
80}
81
82FrameBuffer::~FrameBuffer()
83{
84 this->destroy();
85 return;
86}
87
88void FrameBuffer::bind() const
89{
90 glBindFramebuffer(GL_FRAMEBUFFER, this->id);
91 check_error();
92 return;
93}
94
95void FrameBuffer::unbind() const
96{
97 glBindFramebuffer(GL_FRAMEBUFFER, 0);
98 check_error();
99 return;
100}
101
102void FrameBuffer::destroy()
103{
104 if (this->id == 0) return;
105
106 glDeleteFramebuffers(1, &this->id);
107 glDeleteTextures(1, &this->texture_id);
108
109 // Update memory for profiling
110 FrameBuffer::tot_memory -= this->memory;
111 this->id = 0;
112 this->memory = 0;
113
114 EVENT(Logger::Event::Lifetime, "framebuffer: destroyed");
115 return;
116}
117
118void FrameBuffer::rescale(int width, int height)
119{
120 if (this->width == width && this->height == height)
121 return;
122 FrameBuffer::tot_memory -= this->memory;
123
124 glBindFramebuffer(GL_FRAMEBUFFER, this->id);
125
126 this->width = width;
127 this->height = height;
128 glBindTexture(GL_TEXTURE_2D, this->texture_id);
129 check_error();
130
131 glTexImage2D(GL_TEXTURE_2D, 0, this->color_format, width, height, 0,
132 this->color_format, this->channel_type, NULL);
133 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
134 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
135 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
136 this->texture_id, 0);
137 glBindTexture(GL_TEXTURE_2D, 0);
138 check_error();
139
140 glBindRenderbuffer(GL_RENDERBUFFER, this->render_buffer_id);
141 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
142 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
143 GL_RENDERBUFFER, this->render_buffer_id);
144 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
145 {
146 ERROR("framebuffer: not complete");
147 return;
148 }
149
150 // Update memory for profiling
151 int channels = Gl::get_num_channels(this->color_format);
152 int bytes_per_channel = Gl::get_bytes_per_channel(channel_type);
153 this->memory = channels * bytes_per_channel * width * height;
154 FrameBuffer::tot_memory += this->memory;
155
156 return;
157}
158
159void FrameBuffer::set_color_format(GLenum color_format)
160{
161 this->color_format = color_format;
162 return;
163}