Branch data Line data Source code
1 : : #pragma once
2 : :
3 : : /*
4 : : MIT License
5 : :
6 : : Copyright (c) 2014-2024 Stephane Cuillerdier (aka aiekick)
7 : :
8 : : Permission is hereby granted, free of charge, to any person obtaining a copy
9 : : of this software and associated documentation files (the "Software"), to deal
10 : : in the Software without restriction, including without limitation the rights
11 : : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 : : copies of the Software, and to permit persons to whom the Software is
13 : : furnished to do so, subject to the following conditions:
14 : :
15 : : The above copyright notice and this permission notice shall be included in all
16 : : copies or substantial portions of the Software.
17 : :
18 : : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 : : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 : : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 : : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 : : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 : : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 : : SOFTWARE.
25 : : */
26 : :
27 : : // ezGL is part of the ezLibs project : https://github.com/aiekick/ezLibs.git
28 : :
29 : :
30 : : #include "ezGL.hpp"
31 : : #include <array>
32 : : #include <vector>
33 : : #include <memory>
34 : :
35 : : namespace ez {
36 : : namespace gl {
37 : :
38 : : class FBO;
39 : : typedef std::shared_ptr<FBO> FBOPtr;
40 : : typedef std::weak_ptr<FBO> FBOWeak;
41 : :
42 : : class FBO {
43 : : private:
44 : : FBOWeak m_This;
45 : : GLuint m_FBOId = 0U;
46 : : GLsizei m_SizeX = 0;
47 : : GLsizei m_SizeY = 0;
48 : : GLuint m_CountBuffers = 0U;
49 : : bool m_UseMipMapping = false;
50 : : std::vector<TexturePtr> m_Textures;
51 : : GLenum* m_ColorDrawBuffers = nullptr;
52 : :
53 : : public:
54 : 0 : static FBOPtr create(const GLsizei& vSX, const GLsizei& vSY, const GLuint vCountBuffers, const bool vUseMipMapping) {
55 : 0 : auto res = std::make_shared<FBO>();
56 : 0 : res->m_This = res;
57 : 0 : if (!res->init(vSX, vSY, vCountBuffers, vUseMipMapping)) {
58 : 0 : res.reset();
59 : 0 : }
60 : 0 : return res;
61 : 0 : }
62 : :
63 : : public:
64 : : FBO() = default;
65 : 0 : virtual ~FBO() { unit(); }
66 : :
67 : 0 : bool init(const GLsizei& vSX, const GLsizei& vSY, const GLuint vCountBuffers, const bool vUseMipMapping) {
68 : 0 : bool res = false;
69 : 0 : m_SizeX = vSX;
70 : 0 : m_SizeY = vSY;
71 : 0 : m_CountBuffers = vCountBuffers;
72 : 0 : m_UseMipMapping = vUseMipMapping;
73 : 0 : if (m_CountBuffers > 0U) {
74 : 0 : glGenFramebuffers(1, &m_FBOId);
75 : 0 : CheckGLErrors;
76 : 0 : glBindFramebuffer(GL_FRAMEBUFFER, m_FBOId);
77 : 0 : CheckGLErrors;
78 : 0 : m_Textures.resize(m_CountBuffers);
79 : 0 : m_ColorDrawBuffers = new GLenum[m_CountBuffers];
80 : 0 : for (GLuint idx = 0U; idx < vCountBuffers; ++idx) {
81 : 0 : m_Textures[idx] = Texture::createEmpty(vSX, vSY, "clamp", "nearest", vUseMipMapping);
82 : 0 : if (m_Textures[idx] != nullptr) {
83 : 0 : m_ColorDrawBuffers[idx] = GL_COLOR_ATTACHMENT0 + (GLenum)idx;
84 : 0 : glFramebufferTexture2D(GL_FRAMEBUFFER, m_ColorDrawBuffers[idx], GL_TEXTURE_2D, m_Textures[idx]->getTexId(), 0);
85 : 0 : CheckGLErrors;
86 : 0 : }
87 : 0 : }
88 : 0 : glFinish();
89 : 0 : res = check();
90 : 0 : glBindFramebuffer(GL_FRAMEBUFFER, 0);
91 : 0 : CheckGLErrors;
92 : 0 : }
93 : 0 : return res;
94 : 0 : }
95 : :
96 : 0 : bool bind() {
97 : 0 : #ifdef PROFILER_SCOPED
98 : 0 : PROFILER_SCOPED("FBO", "bind");
99 : 0 : #endif
100 : 0 : if (m_FBOId > 0) {
101 : 0 : glBindFramebuffer(GL_FRAMEBUFFER, m_FBOId);
102 : 0 : CheckGLErrors;
103 : 0 : return true;
104 : 0 : }
105 : 0 : return false;
106 : 0 : }
107 : :
108 : 0 : void clearBuffer(const std::array<float, 4U>& vColor) {
109 : 0 : #ifdef PROFILER_SCOPED
110 : 0 : PROFILER_SCOPED("FBO", "clearBuffer");
111 : 0 : #endif
112 : 0 : if (bind()) {
113 : 0 : {
114 : 0 : #ifdef PROFILER_SCOPED
115 : 0 : PROFILER_SCOPED("FBO", "clearColor");
116 : 0 : #endif
117 : 0 : glClearColor(vColor[0], vColor[1], vColor[2], vColor[3]);
118 : 0 : glClear(GL_COLOR_BUFFER_BIT);
119 : 0 : }
120 : 0 : unbind();
121 : 0 : }
122 : 0 : }
123 : :
124 : 0 : void updateMipMaping() {
125 : 0 : if (m_UseMipMapping) {
126 : 0 : #ifdef PROFILER_SCOPED
127 : 0 : PROFILER_SCOPED("FBO", "updateMipMaping %u", m_FBOId);
128 : 0 : #endif
129 : 0 : for (auto& tex_ptr : m_Textures) {
130 : 0 : if (tex_ptr != nullptr) {
131 : 0 : tex_ptr->updateMipMaping();
132 : 0 : }
133 : 0 : }
134 : 0 : }
135 : 0 : }
136 : :
137 : 0 : void selectBuffers() {
138 : 0 : #ifdef PROFILER_SCOPED
139 : 0 : PROFILER_SCOPED("FBO", "glDrawBuffers");
140 : 0 : #endif
141 : 0 : glDrawBuffers(m_CountBuffers, m_ColorDrawBuffers);
142 : 0 : CheckGLErrors;
143 : 0 : }
144 : :
145 : 0 : void unbind() {
146 : 0 : #ifdef PROFILER_SCOPED
147 : 0 : PROFILER_SCOPED("FBO", "unbind");
148 : 0 : #endif
149 : 0 : glBindFramebuffer(GL_FRAMEBUFFER, 0);
150 : 0 : CheckGLErrors;
151 : 0 : glBindTexture(GL_TEXTURE_2D, 0);
152 : 0 : CheckGLErrors;
153 : 0 : }
154 : :
155 : 0 : GLuint getBuffersCount() const { return m_CountBuffers; }
156 : :
157 : 0 : GLuint getTextureId(const size_t& vBufferIdx = 0U) const {
158 : 0 : if (m_Textures.size() > vBufferIdx) {
159 : 0 : return m_Textures[vBufferIdx]->getTexId();
160 : 0 : }
161 : 0 : return 0U;
162 : 0 : }
163 : :
164 : 0 : bool resize(const GLsizei& vNewSx, const GLsizei& vNewSy) {
165 : 0 : bool res = false;
166 : 0 : if (m_FBOId > 0) {
167 : 0 : m_SizeX = vNewSx;
168 : 0 : m_SizeY = vNewSy;
169 : 0 : glBindFramebuffer(GL_FRAMEBUFFER, m_FBOId);
170 : 0 : CheckGLErrors;
171 : 0 : for (GLuint idx = 0U; idx < m_CountBuffers; ++idx) {
172 : 0 : if (m_Textures[idx] != nullptr) {
173 : 0 : // m_Textures[idx] = Texture::createEmpty(vNewSx, vNewSy, m_UseMipMapping);
174 : 0 : if (m_Textures[idx]->resize(vNewSx, vNewSy)) {
175 : 0 : if (m_Textures[idx] != nullptr) {
176 : 0 : m_ColorDrawBuffers[idx] = GL_COLOR_ATTACHMENT0 + (GLenum)idx;
177 : 0 : glFramebufferTexture2D(GL_FRAMEBUFFER, m_ColorDrawBuffers[idx], GL_TEXTURE_2D, m_Textures[idx]->getTexId(), 0);
178 : 0 : CheckGLErrors;
179 : 0 : }
180 : 0 : }
181 : 0 : }
182 : 0 : }
183 : 0 : glFinish();
184 : 0 : res = check();
185 : 0 : glBindFramebuffer(GL_FRAMEBUFFER, 0);
186 : 0 : CheckGLErrors;
187 : 0 : }
188 : 0 : return res;
189 : 0 : }
190 : :
191 : 0 : bool check() {
192 : 0 : if (GL_TRUE == glIsFramebuffer(m_FBOId)) {
193 : 0 : CheckGLErrors;
194 : 0 : if (glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE) {
195 : 0 : CheckGLErrors;
196 : 0 : return true;
197 : 0 : }
198 : 0 : }
199 : 0 : return false;
200 : 0 : }
201 : :
202 : 0 : void unit() {
203 : 0 : glDeleteFramebuffers(1, &m_FBOId);
204 : 0 : CheckGLErrors;
205 : 0 : }
206 : :
207 : 0 : void blitOnScreen(const GLint vX, const GLint vY, const GLint vW, const GLint vH, const GLint vAttachementID, GLbitfield vMask, GLenum vFilter) {
208 : 0 : glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
209 : 0 : CheckGLErrors;
210 : 0 :
211 : 0 : glBindFramebuffer(GL_READ_FRAMEBUFFER, m_FBOId);
212 : 0 : CheckGLErrors;
213 : 0 :
214 : 0 : glReadBuffer(GL_COLOR_ATTACHMENT0 + vAttachementID);
215 : 0 : CheckGLErrors;
216 : 0 :
217 : 0 : glDrawBuffer(GL_BACK);
218 : 0 : CheckGLErrors;
219 : 0 :
220 : 0 : glBlitFramebuffer(0, 0, m_SizeX, m_SizeY, vX, vY, vX + vW, vY + vH, vMask, vFilter);
221 : 0 : CheckGLErrors;
222 : 0 : }
223 : : };
224 : :
225 : : /*
226 : : * add front and back FBO
227 : : * and switch between front and back after rendering
228 : : */
229 : :
230 : : class FBOPipeLine;
231 : : typedef std::shared_ptr<FBOPipeLine> FBOPipeLinePtr;
232 : : typedef std::weak_ptr<FBOPipeLine> FBOPipeLineWeak;
233 : : class FBOPipeLine {
234 : : private:
235 : : FBOPipeLineWeak m_This;
236 : : FBOPtr m_FrontFBOPtr = nullptr;
237 : : FBOPtr m_BackFBOPtr = nullptr;
238 : : bool m_MultiPass = false;
239 : :
240 : : public:
241 : 0 : static FBOPipeLinePtr create(const GLsizei& vSX, const GLsizei& vSY, const GLuint vCountBuffers, const bool vUseMipMapping, const bool vMultiPass) {
242 : 0 : auto res = std::make_shared<FBOPipeLine>();
243 : 0 : res->m_This = res;
244 : 0 : if (!res->init(vSX, vSY, vCountBuffers, vUseMipMapping, vMultiPass)) {
245 : 0 : res.reset();
246 : 0 : }
247 : 0 : return res;
248 : 0 : }
249 : :
250 : : public:
251 : : FBOPipeLine() = default;
252 : 0 : virtual ~FBOPipeLine() { unit(); }
253 : 0 : bool init(const GLsizei& vSX, const GLsizei& vSY, const GLuint vCountBuffers, const bool vUseMipMapping, const bool vMultiPass) {
254 : 0 : bool res = true;
255 : 0 : m_MultiPass = vMultiPass;
256 : 0 : m_FrontFBOPtr = FBO::create(vSX, vSY, vCountBuffers, vUseMipMapping);
257 : 0 : if (m_FrontFBOPtr != nullptr) {
258 : 0 : if (m_MultiPass) {
259 : 0 : m_BackFBOPtr = FBO::create(vSX, vSY, vCountBuffers, vUseMipMapping);
260 : 0 : if (m_BackFBOPtr != nullptr) {
261 : 0 : res = true;
262 : 0 : }
263 : 0 : } else {
264 : 0 : res = true;
265 : 0 : }
266 : 0 : }
267 : 0 : return res;
268 : 0 : }
269 : 0 : bool resize(const GLsizei& vNewSx, const GLsizei& vNewSy) {
270 : 0 : bool res = false;
271 : 0 : assert(m_FrontFBOPtr != nullptr);
272 : 0 : res = m_FrontFBOPtr->resize(vNewSx, vNewSy);
273 : 0 : if (m_MultiPass) {
274 : 0 : assert(m_BackFBOPtr != nullptr);
275 : 0 : res &= m_BackFBOPtr->resize(vNewSx, vNewSy);
276 : 0 : }
277 : 0 : return res;
278 : 0 : }
279 : 0 : void unit() {
280 : 0 : m_FrontFBOPtr.reset();
281 : 0 : m_BackFBOPtr.reset();
282 : 0 : }
283 : 0 : bool bind() {
284 : 0 : assert(m_FrontFBOPtr != nullptr);
285 : 0 : return m_FrontFBOPtr->bind();
286 : 0 : }
287 : 0 : void clearBuffer(const std::array<float, 4U>& vColor) {
288 : 0 : assert(m_FrontFBOPtr != nullptr);
289 : 0 : m_FrontFBOPtr->clearBuffer(vColor);
290 : 0 : if (m_MultiPass) {
291 : 0 : assert(m_BackFBOPtr != nullptr);
292 : 0 : m_BackFBOPtr->clearBuffer(vColor);
293 : 0 : }
294 : 0 : }
295 : 0 : void updateMipMaping() {
296 : 0 : assert(m_FrontFBOPtr != nullptr);
297 : 0 : m_FrontFBOPtr->updateMipMaping();
298 : 0 : }
299 : 0 : void selectBuffers() {
300 : 0 : assert(m_FrontFBOPtr != nullptr);
301 : 0 : m_FrontFBOPtr->selectBuffers();
302 : 0 : }
303 : 0 : void unbind() {
304 : 0 : assert(m_FrontFBOPtr != nullptr);
305 : 0 : m_FrontFBOPtr->unbind();
306 : 0 : if (m_MultiPass) {
307 : 0 : swapFBOs();
308 : 0 : }
309 : 0 : }
310 : 0 : GLuint getFrontTextureId(const size_t& vBufferIdx = 0U) const {
311 : 0 : assert(m_FrontFBOPtr != nullptr);
312 : 0 : return m_FrontFBOPtr->getTextureId(vBufferIdx);
313 : 0 : }
314 : 0 : GLuint getBackTextureId(const size_t& vBufferIdx = 0U) const {
315 : 0 : assert(m_MultiPass);
316 : 0 : assert(m_BackFBOPtr != nullptr);
317 : 0 : return m_BackFBOPtr->getTextureId(vBufferIdx);
318 : 0 : }
319 : 0 : FBOWeak getFrontFBO() const { return m_FrontFBOPtr; }
320 : 0 : FBOWeak getBackFBO() const {
321 : 0 : assert(m_MultiPass);
322 : 0 : return m_BackFBOPtr;
323 : 0 : }
324 : 0 : void swapFBOs() {
325 : 0 : assert(m_MultiPass);
326 : 0 : FBOPtr tmp = m_BackFBOPtr;
327 : 0 : m_BackFBOPtr = m_FrontFBOPtr;
328 : 0 : m_FrontFBOPtr = tmp;
329 : 0 : }
330 : : };
331 : :
332 : : } // namespace gl
333 : : } // namespace ez
|