1 /*
2 Copyright (c) 2018-2019 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.gbuffer;
29 
30 import std.stdio;
31 import std.math;
32 
33 import dlib.core.memory;
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.rc;
40 import dagon.graphics.shaders.geometrypass;
41 import dagon.graphics.terrain;
42 import dagon.resource.scene;
43 
44 class GBuffer: Owner
45 {
46     uint width;
47     uint height;
48 
49     GeometryPassShader geometryPassShader;
50 
51     GLuint fbo;
52     GLuint depthTexture = 0;
53     GLuint colorTexture = 0;
54     GLuint rmsTexture = 0;
55     GLuint positionTexture = 0;
56     GLuint normalTexture = 0;
57     GLuint velocityTexture = 0;
58     GLuint emissionTexture = 0;
59 
60     this(uint w, uint h, Owner o)
61     {
62         super(o);
63 
64         width = w;
65         height = h;
66 
67         geometryPassShader = New!GeometryPassShader(this);
68 
69         glActiveTexture(GL_TEXTURE0);
70 
71         glGenTextures(1, &depthTexture);
72         glBindTexture(GL_TEXTURE_2D, depthTexture);
73         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
74         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
75         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
76         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
77         glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, width, height, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, null);
78         glBindTexture(GL_TEXTURE_2D, 0);
79 
80         glGenTextures(1, &colorTexture);
81         glBindTexture(GL_TEXTURE_2D, colorTexture);
82         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
83         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
84         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
85         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
86         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, null);
87         glBindTexture(GL_TEXTURE_2D, 0);
88 
89         glGenTextures(1, &rmsTexture);
90         glBindTexture(GL_TEXTURE_2D, rmsTexture);
91         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, null);
92         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
93         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
94         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
95         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
96         glBindTexture(GL_TEXTURE_2D, 0);
97 
98         glGenTextures(1, &positionTexture);
99         glBindTexture(GL_TEXTURE_2D, positionTexture);
100         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, width, height, 0, GL_RGBA, GL_FLOAT, null);
101         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
102         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
103         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
104         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
105         glBindTexture(GL_TEXTURE_2D, 0);
106 
107         glGenTextures(1, &normalTexture);
108         glBindTexture(GL_TEXTURE_2D, normalTexture);
109         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, width, height, 0, GL_RGB, GL_FLOAT, null);
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         glBindTexture(GL_TEXTURE_2D, 0);
115 
116         glGenTextures(1, &velocityTexture);
117         glBindTexture(GL_TEXTURE_2D, velocityTexture);
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_NEAREST);
120         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
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, &emissionTexture);
126         glBindTexture(GL_TEXTURE_2D, emissionTexture);
127         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, width, height, 0, GL_RGB, GL_FLOAT, null);
128         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
129         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
130         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
131         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
132         glBindTexture(GL_TEXTURE_2D, 0);
133 
134         glGenFramebuffers(1, &fbo);
135         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
136         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture, 0);
137         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, rmsTexture, 0);
138         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, positionTexture, 0);
139         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, normalTexture, 0);
140         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT4, GL_TEXTURE_2D, velocityTexture, 0);
141         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT5, GL_TEXTURE_2D, emissionTexture, 0);
142         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, depthTexture, 0);
143 
144         GLenum[6] bufs = [GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3, GL_COLOR_ATTACHMENT4, GL_COLOR_ATTACHMENT5];
145         glDrawBuffers(6, bufs.ptr);
146 
147         GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
148         if (status != GL_FRAMEBUFFER_COMPLETE)
149             writeln(status);
150 
151         glBindFramebuffer(GL_FRAMEBUFFER, 0);
152     }
153 
154     ~this()
155     {
156         glBindFramebuffer(GL_FRAMEBUFFER, 0);
157         glDeleteFramebuffers(1, &fbo);
158 
159         if (glIsTexture(depthTexture))
160             glDeleteTextures(1, &depthTexture);
161         if (glIsTexture(colorTexture))
162             glDeleteTextures(1, &colorTexture);
163         if (glIsTexture(velocityTexture))
164             glDeleteTextures(1, &velocityTexture);
165         if (glIsTexture(rmsTexture))
166             glDeleteTextures(1, &rmsTexture);
167         if (glIsTexture(positionTexture))
168             glDeleteTextures(1, &positionTexture);
169         if (glIsTexture(normalTexture))
170             glDeleteTextures(1, &normalTexture);
171         if (glIsTexture(emissionTexture))
172             glDeleteTextures(1, &emissionTexture);
173     }
174 
175     void bind()
176     {
177         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
178     }
179 
180     void unbind()
181     {
182         glBindFramebuffer(GL_FRAMEBUFFER, 0);
183     }
184     
185     void clear()
186     {
187         bind();
188 
189         glViewport(0, 0, width, height);
190         glScissor(0, 0, width, height);
191         glClear(GL_DEPTH_BUFFER_BIT);
192         Color4f zero = Color4f(0, 0, 0, 0);
193         glClearBufferfv(GL_COLOR, 0, zero.arrayof.ptr);
194         glClearBufferfv(GL_COLOR, 1, zero.arrayof.ptr);
195         glClearBufferfv(GL_COLOR, 2, zero.arrayof.ptr);
196         glClearBufferfv(GL_COLOR, 3, zero.arrayof.ptr);
197         glClearBufferfv(GL_COLOR, 4, zero.arrayof.ptr);
198         glClearBufferfv(GL_COLOR, 5, zero.arrayof.ptr);
199         
200         unbind();
201     }
202 
203     void renderStatic(Scene scene, RenderingContext* rc)
204     {
205         bind();
206 
207         glEnable(GL_DEPTH_TEST);
208 
209         auto rcLocal = *rc;
210 
211         rcLocal.overrideShader = geometryPassShader;
212         rcLocal.rebindShaderProgram = false;
213         geometryPassShader.bindProgram();
214         scene.renderer.renderStaticOpaqueEntities3D(scene, &rcLocal);
215         //renderOpaqueEntities3D(scene, &rcLocal);
216         geometryPassShader.unbindProgram();
217 
218         unbind();
219     }
220     
221     void renderDynamic(Scene scene, RenderingContext* rc)
222     {
223         bind();
224 
225         glEnable(GL_DEPTH_TEST);
226 
227         auto rcLocal = *rc;
228 
229         rcLocal.overrideShader = geometryPassShader;
230         rcLocal.rebindShaderProgram = false;
231         geometryPassShader.bindProgram();
232         scene.renderer.renderDynamicOpaqueEntities3D(scene, &rcLocal);
233         //renderOpaqueEntities3D(scene, &rcLocal);
234         geometryPassShader.unbindProgram();
235 
236         unbind();
237     }
238     
239     void renderTerrains(Scene scene, RenderingContext* rc)
240     {
241         bind();
242         
243         glEnable(GL_DEPTH_TEST);
244         foreach(e; scene.entities3Dflat)
245         {
246             if (entityIsTerrain(e))
247                 e.render(rc);
248         }
249         
250         unbind();
251     }
252 }