1 /*
2 Copyright (c) 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.game.postprocrenderer;
29 
30 import dlib.core.memory;
31 import dlib.core.ownership;
32 
33 import dagon.core.event;
34 import dagon.core.time;
35 import dagon.graphics.texture;
36 import dagon.resource.scene;
37 import dagon.render.pass;
38 import dagon.render.deferred;
39 import dagon.render.view;
40 import dagon.render.framebuffer;
41 import dagon.render.gbuffer;
42 import dagon.postproc.filterpass;
43 import dagon.postproc.blurpass;
44 import dagon.postproc.presentpass;
45 import dagon.postproc.shaders.brightpass;
46 import dagon.postproc.shaders.glow;
47 import dagon.postproc.shaders.motionblur;
48 import dagon.postproc.shaders.tonemap;
49 import dagon.postproc.shaders.fxaa;
50 import dagon.postproc.shaders.lut;
51 import dagon.postproc.shaders.lensdistortion;
52 import dagon.game.renderer;
53 
54 import dagon.core.bindings;
55 
56 class DoubleBuffer: Framebuffer
57 {
58     Framebuffer writeBuffer;
59     Framebuffer readBuffer;
60 
61     this(Framebuffer writeBuffer, Framebuffer readBuffer, Owner owner)
62     {
63         super(owner);
64         //super(writeBuffer.width, writeBuffer.height, true, owner);
65         this.writeBuffer = writeBuffer;
66         this.readBuffer = readBuffer;
67     }
68 
69     void swap()
70     {
71         auto w = writeBuffer;
72         writeBuffer = readBuffer;
73         readBuffer = w;
74     }
75 
76     override GLuint colorTexture()
77     {
78         return readBuffer.colorTexture();
79     }
80 
81     override GLuint depthTexture()
82     {
83         return readBuffer.depthTexture();
84     }
85 
86     override void bind()
87     {
88         writeBuffer.bind();
89     }
90 
91     override void unbind()
92     {
93         writeBuffer.unbind();
94     }
95 
96     override void resize(uint width, uint height)
97     {
98 
99     }
100 
101     override void blitColorBuffer()
102     {
103 
104     }
105 
106     override void blitDepthBuffer()
107     {
108 
109     }
110 }
111 
112 class PostProcRenderer: Renderer
113 {
114     public:
115 
116     Framebuffer inputBuffer;
117     Framebuffer outputBuffer;
118 
119     protected:
120 
121     DoubleBuffer ldrDoubleBuffer;
122 
123     Framebuffer ldrBuffer1;
124     Framebuffer ldrBuffer2;
125 
126     Framebuffer hdrBuffer1;
127     Framebuffer hdrBuffer2;
128     Framebuffer hdrBuffer3;
129     Framebuffer hdrBuffer4;
130 
131     RenderView viewHalf;
132     BlurPass passBlur;
133 
134     BrightPassShader brightPassShader;
135     GlowShader glowShader;
136     MotionBlurShader motionBlurShader;
137     TonemapShader tonemapShader;
138     FXAAShader fxaaShader;
139     LensDistortionShader lensDistortionShader;
140     LUTShader lutShader;
141 
142     FilterPass passMotionBlur;
143     FilterPass passBrightPass;
144     FilterPass passGlow;
145     FilterPass passTonemap;
146     FilterPass passFXAA;
147     FilterPass passLensDistortion;
148     FilterPass passLUT;
149     PresentPass passPresent;
150 
151     bool _motionBlurEnabled = false;
152     bool _glowEnabled = false;
153 
154     public:
155 
156     float glowViewScale = 0.33f;
157 
158     float glowThreshold = 0.8f;
159     float glowIntensity = 0.2f;
160     int glowRadius = 5;
161     Tonemapper tonemapper = Tonemapper.ACES;
162     float exposure = 1.0f;
163 
164     uint motionBlurSamples = 16;
165     uint motionBlurFramerate = 24;
166 
167     Texture colorLookupTable;
168 
169     this(EventManager eventManager, Framebuffer inputBuffer, GBuffer gbuffer, Owner owner)
170     {
171         super(eventManager, owner);
172 
173         this.inputBuffer = inputBuffer;
174 
175         viewHalf = New!RenderView(0, 0, cast(uint)(view.width * glowViewScale), cast(uint)(view.height * glowViewScale), this);
176 
177         ldrBuffer1 = New!Framebuffer(view.width, view.height, FrameBufferFormat.RGBA8, true, this);
178         ldrBuffer2 = New!Framebuffer(view.width, view.height, FrameBufferFormat.RGBA8, true, this);
179         ldrDoubleBuffer = New!DoubleBuffer(ldrBuffer1, ldrBuffer2, this);
180 
181         hdrBuffer1 = New!Framebuffer(viewHalf.width, viewHalf.height, FrameBufferFormat.RGBA16F, true, this);
182         hdrBuffer2 = New!Framebuffer(viewHalf.width, viewHalf.height, FrameBufferFormat.RGBA16F, true, this);
183 
184         hdrBuffer3 = New!Framebuffer(view.width, view.height, FrameBufferFormat.RGBA16F, true, this);
185         hdrBuffer4 = New!Framebuffer(view.width, view.height, FrameBufferFormat.RGBA16F, true, this);
186 
187         motionBlurShader = New!MotionBlurShader(this);
188         motionBlurShader.gbuffer = gbuffer;
189         passMotionBlur = New!FilterPass(pipeline, motionBlurShader);
190         passMotionBlur.view = view;
191         passMotionBlur.inputBuffer = inputBuffer;
192         passMotionBlur.outputBuffer = hdrBuffer4;
193 
194         brightPassShader = New!BrightPassShader(this);
195         brightPassShader.luminanceThreshold = glowThreshold;
196         passBrightPass = New!FilterPass(pipeline, brightPassShader);
197         passBrightPass.view = viewHalf;
198         passBrightPass.inputBuffer = passMotionBlur.outputBuffer;
199         passBrightPass.outputBuffer = hdrBuffer1;
200 
201         passBlur = New!BlurPass(pipeline);
202         passBlur.view = viewHalf;
203         passBlur.inputBuffer = passBrightPass.outputBuffer;
204         passBlur.outputBuffer = hdrBuffer1;
205         passBlur.outputBuffer2 = hdrBuffer2;
206         passBlur.radius = glowRadius;
207 
208         glowShader = New!GlowShader(this);
209         glowShader.blurredBuffer = passBlur.outputBuffer;
210         glowShader.intensity = glowIntensity;
211         passGlow = New!FilterPass(pipeline, glowShader);
212         passGlow.view = view;
213         passGlow.inputBuffer = passMotionBlur.outputBuffer;
214         passGlow.outputBuffer = hdrBuffer3;
215 
216         tonemapShader = New!TonemapShader(this);
217         passTonemap = New!FilterPass(pipeline, tonemapShader);
218         passTonemap.view = view;
219         passTonemap.inputBuffer = passGlow.outputBuffer;
220         passTonemap.outputBuffer = ldrDoubleBuffer;
221 
222         fxaaShader = New!FXAAShader(this);
223         passFXAA = New!FilterPass(pipeline, fxaaShader);
224         passFXAA.view = view;
225         passFXAA.inputBuffer = ldrDoubleBuffer;
226         passFXAA.outputBuffer = ldrDoubleBuffer;
227 
228         lensDistortionShader = New!LensDistortionShader(this);
229         passLensDistortion = New!FilterPass(pipeline, lensDistortionShader);
230         passLensDistortion.view = view;
231         passLensDistortion.inputBuffer = ldrDoubleBuffer;
232         passLensDistortion.outputBuffer = ldrDoubleBuffer;
233 
234         lutShader = New!LUTShader(this);
235         passLUT = New!FilterPass(pipeline, lutShader);
236         passLUT.view = view;
237         passLUT.inputBuffer = ldrDoubleBuffer;
238         passLUT.outputBuffer = ldrDoubleBuffer;
239 
240         outputBuffer = ldrDoubleBuffer;
241     }
242 
243     void motionBlurEnabled(bool mode) @property
244     {
245         _motionBlurEnabled = mode;
246         passMotionBlur.active = mode;
247     }
248     bool motionBlurEnabled() @property
249     {
250         return _motionBlurEnabled;
251     }
252 
253     void glowEnabled(bool mode) @property
254     {
255         _glowEnabled = mode;
256         passBrightPass.active = mode;
257         passBlur.active = mode;
258         passGlow.active = mode;
259     }
260     bool glowEnabled() @property
261     {
262         return _glowEnabled;
263     }
264 
265     void fxaaEnabled(bool mode) @property
266     {
267         passFXAA.active = mode;
268     }
269     bool fxaaEnabled() @property
270     {
271         return passFXAA.active;
272     }
273 
274     void lensDistortionEnabled(bool mode) @property
275     {
276         passLensDistortion.active = mode;
277     }
278     bool lensDistortionEnabled() @property
279     {
280         return passLensDistortion.active;
281     }
282 
283     void lutEnabled(bool mode) @property
284     {
285         passLUT.active = mode;
286     }
287     bool lutEnabled() @property
288     {
289         return passLUT.active;
290     }
291 
292     override void update(Time t)
293     {
294         super.update(t);
295 
296         brightPassShader.luminanceThreshold = glowThreshold;
297         glowShader.intensity = glowIntensity;
298         passBlur.radius = glowRadius;
299         tonemapShader.tonemapper = tonemapper;
300         tonemapShader.exposure = exposure;
301         motionBlurShader.samples = motionBlurSamples;
302         motionBlurShader.currentFramerate = 1.0 / t.delta;
303         motionBlurShader.shutterFramerate = motionBlurFramerate;
304         lutShader.colorLookupTable = colorLookupTable;
305         if (lutShader.colorLookupTable)
306         {
307             lutShader.colorLookupTable.useMipmapFiltering = false;
308         }
309     }
310 
311     override void render()
312     {
313         if (outputBuffer)
314             outputBuffer.bind();
315             
316         if (!_motionBlurEnabled)
317         {
318             passBrightPass.inputBuffer = inputBuffer;
319             passGlow.inputBuffer = inputBuffer;
320         }
321         else
322         {
323             passBrightPass.inputBuffer = passMotionBlur.outputBuffer;
324             passGlow.inputBuffer = passMotionBlur.outputBuffer;
325         }
326             
327         if (!_glowEnabled)
328         {
329             if (_motionBlurEnabled)
330                 passTonemap.inputBuffer = passMotionBlur.outputBuffer;
331             else
332                 passTonemap.inputBuffer = inputBuffer;
333         }
334         else
335         {
336             passTonemap.inputBuffer = passGlow.outputBuffer;
337         }
338         
339         foreach(pass; pipeline.passes.data)
340         {
341             if (pass.active)
342             {
343                 pass.render();
344                 ldrDoubleBuffer.swap();
345             }
346         }
347 
348         if (outputBuffer)
349             outputBuffer.unbind();
350     }
351 
352     override void setViewport(uint x, uint y, uint w, uint h)
353     {
354         super.setViewport(x, y, w, h);
355 
356         viewHalf.resize(cast(uint)(view.width * glowViewScale), cast(uint)(view.height * glowViewScale));
357 
358         ldrBuffer1.resize(view.width, view.height);
359         ldrBuffer2.resize(view.width, view.height);
360 
361         hdrBuffer1.resize(viewHalf.width, viewHalf.height);
362         hdrBuffer2.resize(viewHalf.width, viewHalf.height);
363         hdrBuffer3.resize(view.width, view.height);
364         hdrBuffer4.resize(view.width, view.height);
365     }
366 }