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