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