1 module ws.gl.framebuffer; 2 3 import 4 std.string, 5 std.conv, 6 ws.gl.texture, 7 ws.gl.gl; 8 9 10 string error(GLuint i){ 11 string[GLuint] ERRORS = [ 12 GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: "invalid attachment(s)", 13 // GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: "invalid dimensions", 14 GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: "no attachments", 15 GL_FRAMEBUFFER_UNSUPPORTED: "this framebuffer configuration is not supported" 16 ]; 17 //return ERRORS[i]; 18 return to!string(i); 19 } 20 21 22 23 class FrameBuffer { 24 25 GLuint fbo; 26 Texture depth; 27 Texture[] textures; 28 uint width, height; 29 30 this(int w, int h, int count, GLuint format=GL_RGBA32F, GLuint type=GL_FLOAT, GLuint colors=GL_RGB){ 31 width = w; 32 height = h; 33 glGenFramebuffers(1, &fbo); 34 glBindFramebuffer(GL_FRAMEBUFFER, fbo); 35 for(uint i = 0; i < count; i++){ 36 uint tex; 37 glGenTextures(1, &tex); 38 glBindTexture(GL_TEXTURE_2D, tex); 39 glTexImage2D(GL_TEXTURE_2D, 0, format, w, h, 0, colors, type, null); 40 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 41 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 42 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, tex, 0); 43 textures ~= new Texture(tex); 44 } 45 uint tex; 46 glGenTextures(1, &tex); 47 glBindTexture(GL_TEXTURE_2D, tex); 48 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 49 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 50 glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH32F_STENCIL8, w, h, 0, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, null); 51 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, tex, 0); 52 depth = new Texture(tex); 53 54 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); 55 if(status != GL_FRAMEBUFFER_COMPLETE) 56 throw new Exception("FB error: %s".format(error(status))); 57 58 glBindFramebuffer(GL_FRAMEBUFFER, 0); 59 } 60 61 void destroy(){ 62 glDeleteFramebuffers(1, &fbo); 63 foreach(t; textures) 64 t.destroy; 65 //glDeleteTextures(cast(int)textures.length, textures.ptr); 66 depth.destroy; 67 } 68 69 void draw(GLuint[] targets){ 70 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); 71 GLuint[] drawBuffers; 72 foreach(i, n; targets) 73 drawBuffers ~= GL_COLOR_ATTACHMENT0+n; 74 glDrawBuffers(cast(int)drawBuffers.length, drawBuffers.ptr); 75 } 76 77 void clear(){ 78 float[3] clear = [0, 0, 0]; 79 float one = 1; 80 foreach(i; 0..textures.length) 81 glClearBufferfv(GL_COLOR, cast(int)i, clear.ptr); 82 glClearBufferfv(GL_DEPTH, 0, &one); 83 } 84 85 void read(GLuint target){ 86 glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); 87 glReadBuffer(GL_COLOR_ATTACHMENT0+target); 88 } 89 90 /+++ 91 Bind textures for reading 92 tex: [shader offset: framebuffer index, ...] 93 / 94 void read(uint[uint] tex){ 95 foreach(i, n; tex){ 96 glActiveTexture(GL_TEXTURE0+i); 97 glBindTexture(GL_TEXTURE_2D, textures[n]); 98 } 99 } 100 +/ 101 102 void blit(int which, int x, int y, int w){ 103 float aspect = width/cast(float)height; 104 int h = cast(int)(w/aspect); 105 read(which); 106 glBlitFramebuffer(0,0,width,height,x,y,x+w,y+h,GL_COLOR_BUFFER_BIT,GL_LINEAR); 107 } 108 109 }