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 }