summaryrefslogtreecommitdiff
path: root/gfx/src/render/framebuffer.c
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2023-01-03 08:49:54 -0800
committer3gg <3gg@shellblade.net>2023-01-03 08:49:54 -0800
commit1e3fcf5b38d67fb54102786be74af42be5c6792f (patch)
tree88bff4e24121c50d0e3c62f5ddb4eff6a3dfa238 /gfx/src/render/framebuffer.c
Initial commit.
Diffstat (limited to 'gfx/src/render/framebuffer.c')
-rw-r--r--gfx/src/render/framebuffer.c150
1 files changed, 150 insertions, 0 deletions
diff --git a/gfx/src/render/framebuffer.c b/gfx/src/render/framebuffer.c
new file mode 100644
index 0000000..323ef56
--- /dev/null
+++ b/gfx/src/render/framebuffer.c
@@ -0,0 +1,150 @@
1#include "framebuffer.h"
2
3#include "renderbuffer.h"
4#include "texture.h"
5
6#include <gfx/error.h>
7
8#include <assert.h>
9
10static void framebuffer_attach_colour(FrameBuffer* framebuffer,
11 const FrameBufferAttachment* attachment) {
12 assert(framebuffer);
13 assert(attachment);
14
15 switch (attachment->type) {
16 case FrameBufferNoAttachment:
17 break;
18 case FrameBufferTexture:
19 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
20 attachment->texture.texture->id,
21 attachment->texture.mip_level);
22 break;
23 case FrameBufferCubemapTexture:
24 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
25 to_GL_cubemap_face(attachment->cubemap.face),
26 attachment->cubemap.texture->id,
27 attachment->cubemap.mip_level);
28 break;
29 case FrameBufferRenderBuffer:
30 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
31 GL_RENDERBUFFER, attachment->renderbuffer->id);
32 break;
33 }
34
35 ASSERT_GL;
36}
37
38static void framebuffer_attach_depth(FrameBuffer* framebuffer,
39 const FrameBufferAttachment* attachment) {
40 assert(framebuffer);
41 assert(attachment);
42
43 switch (attachment->type) {
44 case FrameBufferNoAttachment:
45 break;
46 case FrameBufferTexture:
47 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
48 GL_DEPTH_COMPONENT, attachment->texture.texture->id,
49 attachment->texture.mip_level);
50 break;
51 // TODO: Could distinguish between colour and depth attachment types to make
52 // this a compile-time error.
53 case FrameBufferCubemapTexture:
54 gfx_set_error(
55 "Cannot use a cubemap texture as a depth framebuffer attachment");
56 break;
57 case FrameBufferRenderBuffer:
58 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
59 GL_RENDERBUFFER, attachment->renderbuffer->id);
60 break;
61 }
62
63 ASSERT_GL;
64}
65
66bool gfx_init_framebuffer(FrameBuffer* framebuffer,
67 const FrameBufferDesc* desc) {
68 assert(framebuffer);
69 assert(desc);
70
71 glGenFramebuffers(1, &framebuffer->id);
72 if (!framebuffer->id) {
73 gfx_set_error("glGenFramebuffers() failed");
74 return false;
75 }
76
77 // Allow incomplete framebuffers for flexibility.
78 // Attach buffers and check the framebuffer status only if buffers are given
79 // up front.
80 if (desc->colour.type != FrameBufferNoAttachment ||
81 desc->depth.type != FrameBufferNoAttachment) {
82 // TODO: Could use the "named" API to avoid having to bind the framebuffer.
83 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer->id);
84 framebuffer_attach_colour(framebuffer, &desc->colour);
85 framebuffer_attach_depth(framebuffer, &desc->depth);
86 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
87 gfx_set_error("glCheckFramebufferStatus() failed");
88 gfx_del_framebuffer(framebuffer);
89 return false;
90 }
91 glBindFramebuffer(GL_FRAMEBUFFER, 0);
92 }
93
94 ASSERT_GL;
95 return true;
96}
97
98bool gfx_framebuffer_attach_colour(FrameBuffer* framebuffer,
99 const FrameBufferAttachment* attachment) {
100 assert(framebuffer);
101 assert(attachment);
102
103 // TODO: Could use the "named" API to avoid having to bind the framebuffer.
104 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer->id);
105 framebuffer_attach_colour(framebuffer, attachment);
106 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
107 gfx_set_error("glCheckFramebufferStatus() failed");
108 return false;
109 }
110 return true;
111}
112
113bool gfx_framebuffer_attach_depth(FrameBuffer* framebuffer,
114 const FrameBufferAttachment* attachment) {
115 assert(framebuffer);
116 assert(attachment);
117
118 // TODO: Could use the "named" API to avoid having to bind the framebuffer.
119 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer->id);
120 framebuffer_attach_depth(framebuffer, attachment);
121 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
122 gfx_set_error("glCheckFramebufferStatus() failed");
123 return false;
124 }
125 return true;
126}
127
128void gfx_del_framebuffer(FrameBuffer* framebuffer) {
129 assert(framebuffer);
130 if (framebuffer->id) {
131 glDeleteFramebuffers(1, &framebuffer->id);
132 framebuffer->id = 0;
133 }
134}
135
136void gfx_activate_framebuffer(const FrameBuffer* framebuffer) {
137 assert(framebuffer);
138 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer->id);
139}
140
141void gfx_deactivate_framebuffer(const FrameBuffer* framebuffer) {
142 assert(framebuffer);
143 glBindFramebuffer(GL_FRAMEBUFFER, 0);
144}
145
146void gfx_framebuffer_set_viewport(FrameBuffer* framebuffer, int x, int y,
147 int width, int height) {
148 assert(framebuffer);
149 glViewport(x, y, width, height);
150}