diff options
author | 3gg <3gg@shellblade.net> | 2023-01-03 08:49:54 -0800 |
---|---|---|
committer | 3gg <3gg@shellblade.net> | 2023-01-03 08:49:54 -0800 |
commit | 1e3fcf5b38d67fb54102786be74af42be5c6792f (patch) | |
tree | 88bff4e24121c50d0e3c62f5ddb4eff6a3dfa238 /gfx/src/render/framebuffer.c |
Initial commit.
Diffstat (limited to 'gfx/src/render/framebuffer.c')
-rw-r--r-- | gfx/src/render/framebuffer.c | 150 |
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 | |||
10 | static 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 | |||
38 | static 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 | |||
66 | bool 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 | |||
98 | bool 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 | |||
113 | bool 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 | |||
128 | void gfx_del_framebuffer(FrameBuffer* framebuffer) { | ||
129 | assert(framebuffer); | ||
130 | if (framebuffer->id) { | ||
131 | glDeleteFramebuffers(1, &framebuffer->id); | ||
132 | framebuffer->id = 0; | ||
133 | } | ||
134 | } | ||
135 | |||
136 | void gfx_activate_framebuffer(const FrameBuffer* framebuffer) { | ||
137 | assert(framebuffer); | ||
138 | glBindFramebuffer(GL_FRAMEBUFFER, framebuffer->id); | ||
139 | } | ||
140 | |||
141 | void gfx_deactivate_framebuffer(const FrameBuffer* framebuffer) { | ||
142 | assert(framebuffer); | ||
143 | glBindFramebuffer(GL_FRAMEBUFFER, 0); | ||
144 | } | ||
145 | |||
146 | void 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 | } | ||