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