1 module ws.gl.gbuffer; 2 3 import 4 std.string, 5 ws.gl.gl; 6 7 8 string error(GLuint i){ 9 string[GLuint] ERRORS = [ 10 GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: "invalid attachment(s)", 11 // GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: "invalid dimensions", 12 GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: "no attachments", 13 GL_FRAMEBUFFER_UNSUPPORTED: "this framebuffer configuration is not supported" 14 ]; 15 return ERRORS[i]; 16 } 17 18 19 20 class GBuffer { 21 22 private { 23 GLuint fbo; 24 GLuint[NUM] textures; 25 GLuint depth; 26 GLuint result; 27 } 28 29 this(int w, int h){ 30 31 // Create the FBO 32 glGenFramebuffers(1, &fbo); 33 glBindFramebuffer(GL_FRAMEBUFFER, fbo); 34 35 // Create the gbuffer textures 36 glGenTextures(textures.length, textures.ptr); 37 for(uint i = 0; i < textures.length; i++){ 38 glBindTexture(GL_TEXTURE_2D, textures[i]); 39 if(i == LIGHT) 40 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, null); 41 else 42 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, w, h, 0, GL_RGB, GL_FLOAT, null); 43 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 44 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 45 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, textures[i], 0); 46 } 47 // depth & stencil 48 glGenTextures(1, &depth); 49 glBindTexture(GL_TEXTURE_2D, depth); 50 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 51 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 52 glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH32F_STENCIL8, w, h, 0, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, null); 53 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, depth, 0); 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 if(fbo) 63 glDeleteFramebuffers(1, &fbo); 64 if(textures[0]) 65 glDeleteTextures(textures.length, textures.ptr); 66 if(depth) 67 glDeleteRenderbuffers(1, &depth); 68 } 69 70 71 void startFrame(){ 72 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); 73 glDrawBuffer(GL_COLOR_ATTACHMENT0+LIGHT); 74 glClearColor(0.1,0.1,0.1,1); 75 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 76 } 77 78 void bindGeom(){ 79 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); 80 GLenum[] buffers; 81 for(int i=0; i<NUM; i++) 82 buffers ~= GL_COLOR_ATTACHMENT0 + i; 83 glDrawBuffers(cast(uint)buffers.length, buffers.ptr); 84 } 85 86 void bindStencil(){ 87 glDrawBuffer(GL_NONE); 88 } 89 90 void bindTextures(){ 91 for(int i=0 ; i < LIGHT; i++){ 92 glActiveTexture(GL_TEXTURE0 + i); 93 glBindTexture(GL_TEXTURE_2D, textures[i]); 94 } 95 } 96 97 void bindDepth(int where){ 98 glActiveTexture(GL_TEXTURE0 + where); 99 glBindTexture(GL_TEXTURE_2D, depth); 100 } 101 102 void bindLight(){ 103 glBindFramebuffer(GL_FRAMEBUFFER, fbo); 104 glDrawBuffer(GL_COLOR_ATTACHMENT0+LIGHT); 105 bindTextures; 106 } 107 108 void bindRead(int which){ 109 glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); 110 glReadBuffer(GL_COLOR_ATTACHMENT0+which); 111 } 112 113 enum: int { DIFFUSE, TEXCOORD, NORMAL, LIGHT, NUM }; 114 115 }