1 /* 2 Copyright (c) 2019-2020 Timur Gafarov 3 4 Boost Software License - Version 1.0 - August 17th, 2003 5 Permission is hereby granted, free of charge, to any person or organization 6 obtaining a copy of the software and accompanying documentation covered by 7 this license (the "Software") to use, reproduce, display, distribute, 8 execute, and transmit the Software, and to prepare derivative works of the 9 Software, and to permit third-parties to whom the Software is furnished to 10 do so, all subject to the following: 11 12 The copyright notices in the Software and this entire statement, including 13 the above license grant, this restriction and the following disclaimer, 14 must be included in all copies of the Software, in whole or in part, and 15 all derivative works of the Software, unless such copies or derivative 16 works are solely in the form of machine-executable object code generated by 17 a source language processor. 18 19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 22 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 23 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 24 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 DEALINGS IN THE SOFTWARE. 26 */ 27 28 module dagon.render.framebuffer; 29 30 import std.stdio; 31 import dlib.core.memory; 32 import dlib.core.ownership; 33 import dlib.image.color; 34 35 import dagon.core.bindings; 36 37 enum FrameBufferFormat 38 { 39 R8, 40 RGBA8, 41 RGBA16F 42 } 43 44 class Framebuffer: Owner 45 { 46 uint width; 47 uint height; 48 FrameBufferFormat colorFormat; 49 bool hasDepthBuffer; 50 GLuint _colorTexture = 0; 51 GLuint _depthTexture = 0; 52 GLuint framebuffer; 53 54 this(Owner owner) 55 { 56 super(owner); 57 } 58 59 this(uint w, uint h, FrameBufferFormat format, bool depth, Owner owner) 60 { 61 super(owner); 62 init(w, h, format, depth); 63 } 64 65 void init(uint w, uint h, FrameBufferFormat format, bool depth) 66 { 67 width = w; 68 height = h; 69 colorFormat = format; 70 hasDepthBuffer = depth; 71 createFramebuffer(); 72 } 73 74 ~this() 75 { 76 releaseFramebuffer(); 77 } 78 79 protected void createFramebuffer() 80 { 81 releaseFramebuffer(); 82 83 GLint intFormat; 84 GLenum textureFormat; 85 GLenum pixelType; 86 87 switch (colorFormat) 88 { 89 case FrameBufferFormat.R8: intFormat = GL_R8; textureFormat = GL_RED; pixelType = GL_UNSIGNED_BYTE; break; 90 case FrameBufferFormat.RGBA8: intFormat = GL_RGBA8; textureFormat = GL_RGBA; pixelType = GL_UNSIGNED_BYTE; break; 91 case FrameBufferFormat.RGBA16F: intFormat = GL_RGBA16F; textureFormat = GL_RGBA; pixelType = GL_FLOAT; break; 92 default: break; 93 } 94 95 glActiveTexture(GL_TEXTURE0); 96 97 glGenTextures(1, &_colorTexture); 98 glBindTexture(GL_TEXTURE_2D, _colorTexture); 99 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 100 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 101 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 102 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 103 glTexImage2D(GL_TEXTURE_2D, 0, intFormat, width, height, 0, textureFormat, pixelType, null); 104 glBindTexture(GL_TEXTURE_2D, 0); 105 106 if (hasDepthBuffer) 107 { 108 glGenTextures(1, &_depthTexture); 109 glBindTexture(GL_TEXTURE_2D, _depthTexture); 110 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 111 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 112 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 113 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 114 glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, width, height, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, null); 115 glBindTexture(GL_TEXTURE_2D, 0); 116 } 117 118 glGenFramebuffers(1, &framebuffer); 119 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); 120 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _colorTexture, 0); 121 if (hasDepthBuffer) 122 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, _depthTexture, 0); 123 124 GLenum[1] drawBuffers = [GL_COLOR_ATTACHMENT0]; 125 glDrawBuffers(drawBuffers.length, drawBuffers.ptr); 126 127 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); 128 if (status != GL_FRAMEBUFFER_COMPLETE) 129 writeln(status); 130 131 glBindFramebuffer(GL_FRAMEBUFFER, 0); 132 } 133 134 void releaseFramebuffer() 135 { 136 if (glIsFramebuffer(framebuffer)) 137 glDeleteFramebuffers(1, &framebuffer); 138 139 if (glIsTexture(_colorTexture)) 140 glDeleteTextures(1, &_colorTexture); 141 142 if (glIsTexture(_depthTexture)) 143 glDeleteTextures(1, &_depthTexture); 144 } 145 146 GLuint colorTexture() 147 { 148 return _colorTexture; 149 } 150 151 GLuint depthTexture() 152 { 153 return _depthTexture; 154 } 155 156 void bind() 157 { 158 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer); 159 } 160 161 void unbind() 162 { 163 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); 164 } 165 166 void resize(uint w, uint h) 167 { 168 width = w; 169 height = h; 170 createFramebuffer(); 171 } 172 173 void blitColorBuffer() 174 { 175 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer); 176 glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST); 177 glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); 178 } 179 180 void blitDepthBuffer() 181 { 182 if (hasDepthBuffer) 183 { 184 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer); 185 glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST); 186 glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); 187 } 188 } 189 }