1 module glamour.fbo;
2
3 private {
4 import glamour.gl : GLenum, GLint, GLuint, GLsizei, glDeleteBuffers,
5 glGenFramebuffers, glBindFramebuffer, glRenderbufferStorage,
6 glFramebufferRenderbuffer, glFramebufferTexture1D,
7 glFramebufferTexture2D, glGenRenderbuffers, glGetRenderbufferParameteriv,
8 glBindRenderbuffer, glCheckFramebufferStatus, GL_FRAMEBUFFER_COMPLETE,
9 GL_FRAMEBUFFER, GL_RENDERBUFFER, GL_TEXTURE_1D, GL_TEXTURE_2D;
10 import glamour.texture : Texture1D, Texture2D;
11 import glamour.util : checkgl;
12
13 import std..string : format;
14
15 debug import std.stdio : stderr;
16 }
17
18
19 class FrameBufferException : Exception {
20 this(GLenum err) {
21 super("FrameBuffer error: 0x%x".format(err));
22 }
23 }
24
25
26 /// Represents an Opengl FBO (FrameBufferObject)
27 class FrameBuffer {
28 static const GLenum target = GL_FRAMEBUFFER;
29
30 /// The OpenGL FBO name
31 GLuint fbo;
32 /// Alias this to fbo
33 alias fbo this;
34
35 /// Creates an OpenGL FBO
36 this() {
37 checkgl!glGenFramebuffers(1, &fbo);
38 }
39
40 ~this() {
41 debug if(fbo != 0) stderr.writefln("OpenGL: FBO resource not released.");
42 }
43
44 /// Deletes the FrameBuffer
45 void remove() {
46 checkgl!glDeleteBuffers(1, &fbo);
47 fbo = 0;
48 }
49
50 /// Binds the FrameBuffer
51 void bind() {
52 checkgl!glBindFramebuffer(target, fbo);
53 }
54
55 /// Unbinds the FrameBuffer
56 void unbind() {
57 checkgl!glBindFramebuffer(target, 0);
58 }
59
60 /// Attaches a 1D-texture to the FrameBuffer
61 /// Calls validate
62 void attach(Texture1D texture, GLenum attachment_point, GLint level=0) {
63 bind();
64 checkgl!glFramebufferTexture1D(target, attachment_point, GL_TEXTURE_1D, texture, level);
65 validate();
66 }
67
68 /// Attaches a new and empty 2D texture to the FrameBuffer
69 /// Calls validate, and binds the returned texture
70 Texture1D attach_new_texture(GLenum attachment_point, GLint internal_format,
71 int width, GLenum format, GLenum type) {
72 auto texture = new Texture1D();
73 texture.set_data(cast(void*)null, internal_format, width, format, type);
74 attach(texture, attachment_point);
75
76 return texture;
77 }
78
79 /// Attaches a 2D-texture to the FrameBuffer
80 /// Calls validate
81 void attach(Texture2D texture, GLenum attachment_point, GLint level=0) {
82 bind();
83 checkgl!glFramebufferTexture2D(target, attachment_point, GL_TEXTURE_2D, texture, level);
84 validate();
85 }
86
87 /// Attaches a new and empty 2D texture to the FrameBuffer
88 /// Calls validate, and binds the returned texture
89 Texture2D attach_new_texture(GLenum attachment_point, GLint internal_format,
90 int width, int height, GLenum format, GLenum type) {
91 auto texture = new Texture2D();
92 texture.set_data(cast(void*)null, internal_format, width, height,
93 format, type, true, 0);
94 attach(texture, attachment_point);
95
96 return texture;
97 }
98
99 /// Attaches a RenderBuffer to the FrameBuffer
100 /// Calls validate
101 void attach(RenderBuffer rbuffer, GLenum attachment_point) {
102 bind();
103 checkgl!glFramebufferRenderbuffer(target, attachment_point, rbuffer.target, rbuffer);
104 validate();
105 }
106
107 /// Attaches a new renderbuffer to the FrameBuffer
108 /// Calls validate, also binds the returned RenderBuffer
109 RenderBuffer attach_new_renderbuffer(GLenum attachment_point, GLenum internal_format,
110 int width, int height) {
111 auto rb = new RenderBuffer();
112 rb.set_storage(internal_format, width, height);
113 attach(rb, attachment_point);
114 return rb;
115 }
116
117 /// Calls glCheckFramebufferStatus and throws a FrameBufferException if the return value
118 /// is not GL_FRAMEBUFFER_COMPLETE
119 static void validate() {
120 auto ret = glCheckFramebufferStatus(target);
121 if(ret != GL_FRAMEBUFFER_COMPLETE) {
122 throw new FrameBufferException(ret);
123 }
124 }
125
126 // /// Sets a framebuffer parameter, mostly used for simulating empty buffers
127 // void set_parameter(GLenum param_name, GLint param) {
128 // checkgl!glFramebufferParameteri(target, param_name, param);
129 // }
130 }
131
132 /// Represents an OpenGL RenderBuffer
133 class RenderBuffer {
134 static const GLenum target = GL_RENDERBUFFER;
135
136 /// The OpenGL RenderBuffer name
137 GLuint renderbuffer;
138 /// Alias this to renderbuffer
139 alias renderbuffer this;
140
141 /// Creates an OpenGL RenderBuffer
142 this() {
143 checkgl!glGenRenderbuffers(1, &renderbuffer);
144 }
145
146 ~this() {
147 debug if(renderbuffer != 0) stderr.writefln("OpenGL: RenderBuffer not released.");
148 }
149
150 /// Deletes the FrameBuffer
151 void remove() {
152 checkgl!glDeleteBuffers(1, &renderbuffer);
153 renderbuffer = 0;
154 }
155
156 /// Binds the RenderBuffer
157 void bind() {
158 checkgl!glBindRenderbuffer(target, renderbuffer);
159 }
160
161 /// Unbinds the RenderBuffer
162 void unbind() {
163 checkgl!glBindRenderbuffer(target, 0);
164 }
165
166 /// Allocates storage for the RenderBuffer
167 void set_storage(GLenum internal_format, GLsizei width, GLsizei height) {
168 bind();
169 checkgl!glRenderbufferStorage(target, internal_format, width, height);
170 }
171
172 /// Returns a RenderBuffer parameter
173 int get_parameter(GLenum param_name) {
174 int store;
175 checkgl!glGetRenderbufferParameteriv(target, param_name, &store);
176 return store;
177 }
178 }