1 /* 2 Copyright (c) 2017-2018 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.graphics.framebuffer; 29 30 import std.math; 31 32 import dlib.math.vector; 33 import dlib.image.color; 34 import derelict.opengl; 35 import dagon.core.ownership; 36 37 class Framebuffer: Owner 38 { 39 uint width; 40 uint height; 41 GLuint fbo; 42 GLuint depthTexture = 0; 43 GLuint colorTexture = 0; 44 GLuint velocityTexture = 0; 45 GLuint lumaTexture = 0; 46 GLuint positionTexture = 0; 47 GLuint normalTexture = 0; 48 49 Vector2f[4] vertices; 50 Vector2f[4] texcoords; 51 uint[3][2] indices; 52 53 GLuint vao = 0; 54 GLuint vbo = 0; 55 GLuint tbo = 0; 56 GLuint eao = 0; 57 58 bool isFloating = false; 59 60 bool isHDRSceneBuffer = false; 61 62 this(uint w, uint h, bool floating, bool isHDRSceneBuffer, Owner o) 63 { 64 super(o); 65 66 width = w; 67 height = h; 68 69 this.isHDRSceneBuffer = isHDRSceneBuffer; 70 71 glActiveTexture(GL_TEXTURE0); 72 73 glGenTextures(1, &depthTexture); 74 glBindTexture(GL_TEXTURE_2D, depthTexture); 75 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 76 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 77 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 78 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 79 glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, width, height, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, null); 80 glBindTexture(GL_TEXTURE_2D, 0); 81 82 isFloating = floating; 83 84 glGenTextures(1, &colorTexture); 85 glBindTexture(GL_TEXTURE_2D, colorTexture); 86 if (!floating) 87 { 88 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, null); 89 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 90 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 91 } 92 else 93 { 94 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width, height, 0, GL_RGBA, GL_FLOAT, null); 95 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 96 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 97 } 98 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 99 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 100 glBindTexture(GL_TEXTURE_2D, 0); 101 102 if (isHDRSceneBuffer) 103 { 104 glGenTextures(1, &velocityTexture); 105 glBindTexture(GL_TEXTURE_2D, velocityTexture); 106 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width, height, 0, GL_RGBA, GL_FLOAT, null); 107 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 108 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 109 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 110 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 111 glBindTexture(GL_TEXTURE_2D, 0); 112 113 glGenTextures(1, &lumaTexture); 114 glBindTexture(GL_TEXTURE_2D, lumaTexture); 115 glTexImage2D(GL_TEXTURE_2D, 0, GL_R16F, width, height, 0, GL_RED, GL_FLOAT, null); 116 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 117 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 118 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 119 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 120 glBindTexture(GL_TEXTURE_2D, 0); 121 122 glGenTextures(1, &positionTexture); 123 glBindTexture(GL_TEXTURE_2D, positionTexture); 124 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, width, height, 0, GL_RGB, GL_FLOAT, null); 125 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 126 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 127 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 128 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 129 glBindTexture(GL_TEXTURE_2D, 0); 130 131 glGenTextures(1, &normalTexture); 132 glBindTexture(GL_TEXTURE_2D, normalTexture); 133 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, width, height, 0, GL_RGB, GL_FLOAT, null); 134 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 135 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 136 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 137 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 138 glBindTexture(GL_TEXTURE_2D, 0); 139 } 140 141 glGenFramebuffers(1, &fbo); 142 glBindFramebuffer(GL_FRAMEBUFFER, fbo); 143 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture, 0); 144 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, depthTexture, 0); 145 146 if (isHDRSceneBuffer) 147 { 148 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, velocityTexture, 0); 149 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, lumaTexture, 0); 150 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, positionTexture, 0); 151 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT4, GL_TEXTURE_2D, normalTexture, 0); 152 153 GLenum[5] bufs = [GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3, GL_COLOR_ATTACHMENT4]; 154 glDrawBuffers(5, bufs.ptr); 155 } 156 else 157 { 158 glDrawBuffer(GL_COLOR_ATTACHMENT0); 159 } 160 161 import std.stdio; 162 163 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); 164 if (status != GL_FRAMEBUFFER_COMPLETE) 165 writeln(status); 166 167 glBindFramebuffer(GL_FRAMEBUFFER, 0); 168 169 vertices[0] = Vector2f(0, 0); 170 vertices[1] = Vector2f(0, 1); 171 vertices[2] = Vector2f(1, 0); 172 vertices[3] = Vector2f(1, 1); 173 174 texcoords[0] = Vector2f(0, 1); 175 texcoords[1] = Vector2f(0, 0); 176 texcoords[2] = Vector2f(1, 1); 177 texcoords[3] = Vector2f(1, 0); 178 179 indices[0][0] = 0; 180 indices[0][1] = 1; 181 indices[0][2] = 2; 182 183 indices[1][0] = 2; 184 indices[1][1] = 1; 185 indices[1][2] = 3; 186 187 glGenBuffers(1, &vbo); 188 glBindBuffer(GL_ARRAY_BUFFER, vbo); 189 glBufferData(GL_ARRAY_BUFFER, vertices.length * float.sizeof * 2, vertices.ptr, GL_STATIC_DRAW); 190 191 glGenBuffers(1, &tbo); 192 glBindBuffer(GL_ARRAY_BUFFER, tbo); 193 glBufferData(GL_ARRAY_BUFFER, texcoords.length * float.sizeof * 2, texcoords.ptr, GL_STATIC_DRAW); 194 195 glGenBuffers(1, &eao); 196 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eao); 197 glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.length * uint.sizeof * 3, indices.ptr, GL_STATIC_DRAW); 198 199 glGenVertexArrays(1, &vao); 200 glBindVertexArray(vao); 201 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eao); 202 203 glEnableVertexAttribArray(0); 204 glBindBuffer(GL_ARRAY_BUFFER, vbo); 205 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, null); 206 207 glEnableVertexAttribArray(1); 208 glBindBuffer(GL_ARRAY_BUFFER, tbo); 209 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, null); 210 211 glBindVertexArray(0); 212 213 maxMipmap = cast(int)log2(fmax(width, height)); 214 } 215 216 int maxMipmap; 217 218 ~this() 219 { 220 glBindFramebuffer(GL_FRAMEBUFFER, 0); 221 glDeleteFramebuffers(1, &fbo); 222 if (glIsTexture(depthTexture)) 223 glDeleteTextures(1, &depthTexture); 224 if (glIsTexture(colorTexture)) 225 glDeleteTextures(1, &colorTexture); 226 if (glIsTexture(velocityTexture)) 227 glDeleteTextures(1, &velocityTexture); 228 if (glIsTexture(lumaTexture)) 229 glDeleteTextures(1, &lumaTexture); 230 if (glIsTexture(positionTexture)) 231 glDeleteTextures(1, &positionTexture); 232 if (glIsTexture(normalTexture)) 233 glDeleteTextures(1, &normalTexture); 234 235 glDeleteVertexArrays(1, &vao); 236 glDeleteBuffers(1, &vbo); 237 glDeleteBuffers(1, &tbo); 238 glDeleteBuffers(1, &eao); 239 } 240 241 void genLuminanceMipmaps() 242 { 243 glBindTexture(GL_TEXTURE_2D, lumaTexture); 244 glGenerateMipmap(GL_TEXTURE_2D); 245 glBindTexture(GL_TEXTURE_2D, 0); 246 } 247 248 float averageLuminance() 249 { 250 glBindTexture(GL_TEXTURE_2D, lumaTexture); 251 float luma = 0.0f; 252 if (!isHDRSceneBuffer) 253 return 0.0f; 254 else 255 glGetTexImage(GL_TEXTURE_2D, maxMipmap, GL_RED, GL_FLOAT, &luma); 256 glBindTexture(GL_TEXTURE_2D, 0); 257 return luma; 258 } 259 260 void bind() 261 { 262 glBindFramebuffer(GL_FRAMEBUFFER, fbo); 263 } 264 265 void unbind() 266 { 267 glBindFramebuffer(GL_FRAMEBUFFER, 0); 268 } 269 270 void render() 271 { 272 glDepthMask(0); 273 glDisable(GL_DEPTH_TEST); 274 glBindVertexArray(vao); 275 glDrawElements(GL_TRIANGLES, cast(uint)indices.length * 3, GL_UNSIGNED_INT, cast(void*)0); 276 glBindVertexArray(0); 277 glEnable(GL_DEPTH_TEST); 278 glDepthMask(1); 279 } 280 281 void clearBuffers() 282 { 283 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 284 if (isHDRSceneBuffer) 285 { 286 Color4f zero = Color4f(0, 0, 0, 0); 287 glClearBufferfv(GL_COLOR, 1, zero.arrayof.ptr); 288 glClearBufferfv(GL_COLOR, 2, zero.arrayof.ptr); 289 glClearBufferfv(GL_COLOR, 3, zero.arrayof.ptr); 290 glClearBufferfv(GL_COLOR, 4, zero.arrayof.ptr); 291 } 292 } 293 }