1 /* 2 ******************************************************************************************* 3 * Dgame (a D game framework) - Copyright (c) Randy Schütt 4 * 5 * This software is provided 'as-is', without any express or implied warranty. 6 * In no event will the authors be held liable for any damages arising from 7 * the use of this software. 8 * 9 * Permission is granted to anyone to use this software for any purpose, 10 * including commercial applications, and to alter it and redistribute it 11 * freely, subject to the following restrictions: 12 * 13 * 1. The origin of this software must not be misrepresented; you must not claim 14 * that you wrote the original software. If you use this software in a product, 15 * an acknowledgment in the product documentation would be appreciated but is 16 * not required. 17 * 18 * 2. Altered source versions must be plainly marked as such, and must not be 19 * misrepresented as being the original software. 20 * 21 * 3. This notice may not be removed or altered from any source distribution. 22 ******************************************************************************************* 23 */ 24 module Dgame.System.FrameBufferObject; 25 26 private { 27 import derelict.opengl3.gl; 28 29 import Dgame.Internal.Log; 30 import Dgame.Graphics.Drawable; 31 import Dgame.Graphics.Texture; 32 } 33 34 /** 35 * A FrameBufferObject is usefull if you want to blit Drawables on a Texture. 36 * You create an FBO, set an Image/Texture to it and draw what you want. 37 * After drawing it is on your Texture. 38 * 39 * Author: rschuett 40 */ 41 class FrameBufferObject { 42 private: 43 GLuint _fboId; 44 GLuint _depthBuffer; 45 46 Texture _tex; 47 48 public: 49 final: 50 /** 51 * CTor with a Texture and the boolean flag if you want a depthBuffer 52 */ 53 this(Texture tex, bool depthBuffer = false) in { 54 assert(tex !is null && tex.isValid()); 55 } body { 56 glGenFramebuffers(1, &this._fboId); 57 if (!this._fboId) 58 Log.error("Failed to create the frame buffer object."); 59 60 glBindFramebuffer(GL_FRAMEBUFFER, this._fboId); 61 62 if (depthBuffer) { 63 glGenRenderbuffers(1, &this._depthBuffer); 64 if (!this._depthBuffer) 65 Log.error("Failed to create the attached depth buffer."); 66 67 glBindRenderbuffer(GL_RENDERBUFFER, this._depthBuffer); 68 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, tex.width, tex.height); 69 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, this._depthBuffer); 70 } 71 72 this.setTexture(tex); 73 } 74 75 ~this() { 76 if (this._depthBuffer != 0) 77 glDeleteRenderbuffers(1, &this._depthBuffer); 78 glDeleteFramebuffers(1, &this._fboId); 79 } 80 81 /** 82 * Set a new Texture to the FBO which is now the new render target. 83 */ 84 void setTexture(Texture tex) in { 85 assert(tex !is null && tex.isValid()); 86 } body { 87 this.bind(); 88 scope(exit) this.unbind(); 89 90 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex.Id, 0); 91 92 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { 93 glBindFramebuffer(GL_FRAMEBUFFER, 0); 94 Log.error("Failed to link the target texture to the frame buffer."); 95 } 96 97 this._tex = tex; 98 } 99 100 /** 101 * Clears the content of the FBO. 102 */ 103 void clear() const { 104 this.bind(); 105 scope(exit) this.unbind(); 106 107 glClear(GL_COLOR_BUFFER_BIT); 108 } 109 110 /** 111 * Draw a Drawable on the current render target 112 */ 113 void draw(Drawable draw) in { 114 assert(draw !is null); 115 assert(this._tex !is null && this._tex.isValid()); 116 } body { 117 this.bind(); 118 scope(exit) this.unbind(); 119 120 glPushAttrib(GL_VIEWPORT_BIT | GL_CURRENT_BIT | GL_ENABLE_BIT); 121 glPushMatrix(); 122 123 glDisable(GL_TEXTURE_2D); 124 125 scope(exit) { 126 glPopAttrib(); 127 glPopMatrix(); 128 } 129 130 glMatrixMode(GL_MODELVIEW); 131 glLoadIdentity(); 132 133 glMatrixMode(GL_PROJECTION); 134 glLoadIdentity(); 135 136 glViewport(0, 0, this._tex.width, this._tex.height); 137 glOrtho(0, this._tex.width, this._tex.height, 0, 1, -1); 138 139 draw.render(); 140 } 141 142 /** 143 * Bind the current FBO. This is mostly done automatically. 144 */ 145 void bind() const { 146 glBindFramebuffer(GL_FRAMEBUFFER, this._fboId); 147 } 148 149 /** 150 * Unbind the current FBO. This is mostly done automatically. 151 */ 152 void unbind() const { 153 glBindFramebuffer(GL_FRAMEBUFFER, 0); 154 } 155 }