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 }