1 /*
2 Copyright (c) 2019-2020 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.dof;
46 import dagon.postproc.shaders.brightpass;
47 import dagon.postproc.shaders.glow;
48 import dagon.postproc.shaders.motionblur;
49 import dagon.postproc.shaders.tonemap;
50 import dagon.postproc.shaders.fxaa;
51 import dagon.postproc.shaders.lut;
52 import dagon.postproc.shaders.lensdistortion;
53 import dagon.game.renderer;
54 
55 import dagon.core.bindings;
56 
57 class DoubleBuffer: Framebuffer
58 {
59     Framebuffer writeBuffer;
60     Framebuffer readBuffer;
61 
62     this(Framebuffer writeBuffer, Framebuffer readBuffer, Owner owner)
63     {
64         super(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     DepthOfFieldShader dofShader;
135     BrightPassShader brightPassShader;
136     GlowShader glowShader;
137     MotionBlurShader motionBlurShader;
138     TonemapShader tonemapShader;
139     FXAAShader fxaaShader;
140     LensDistortionShader lensDistortionShader;
141     LUTShader lutShader;
142 
143     FilterPass passDoF;
144     FilterPass passMotionBlur;
145     FilterPass passBrightPass;
146     FilterPass passGlow;
147     FilterPass passTonemap;
148     FilterPass passFXAA;
149     FilterPass passLensDistortion;
150     FilterPass passLUT;
151     PresentPass passPresent;
152 
153     bool _dofEnabled = false;
154     bool _motionBlurEnabled = false;
155     bool _glowEnabled = false;
156 
157     public:
158 
159     float glowViewScale = 0.33f;
160 
161     float glowThreshold = 0.8f;
162     float glowIntensity = 0.2f;
163     int glowRadius = 5;
164     Tonemapper tonemapper = Tonemapper.ACES;
165     float exposure = 1.0f;
166 
167     uint motionBlurSamples = 16;
168     uint motionBlurFramerate = 24;
169     float motionBlurRandomness = 0.2f;
170     float motionBlurMinDistance = 0.01f;
171     float motionBlurMaxDistance = 1.0f;
172     
173     bool autofocus = true;
174     float focalDepth = 1.5;
175     float focalLength = 5.0;
176     float fStop = 2.0;
177 
178     Texture colorLookupTable;
179 
180     this(EventManager eventManager, Framebuffer inputBuffer, GBuffer gbuffer, Owner owner)
181     {
182         super(eventManager, owner);
183 
184         this.inputBuffer = inputBuffer;
185 
186         viewHalf = New!RenderView(0, 0, cast(uint)(view.width * glowViewScale), cast(uint)(view.height * glowViewScale), this);
187 
188         ldrBuffer1 = New!Framebuffer(view.width, view.height, FrameBufferFormat.RGBA8, true, this);
189         ldrBuffer2 = New!Framebuffer(view.width, view.height, FrameBufferFormat.RGBA8, true, this);
190         ldrDoubleBuffer = New!DoubleBuffer(ldrBuffer1, ldrBuffer2, this);
191 
192         hdrBuffer1 = New!Framebuffer(viewHalf.width, viewHalf.height, FrameBufferFormat.RGBA16F, true, this);
193         hdrBuffer2 = New!Framebuffer(viewHalf.width, viewHalf.height, FrameBufferFormat.RGBA16F, true, this);
194 
195         hdrBuffer3 = New!Framebuffer(view.width, view.height, FrameBufferFormat.RGBA16F, true, this);
196         hdrBuffer4 = New!Framebuffer(view.width, view.height, FrameBufferFormat.RGBA16F, true, this);
197 
198         dofShader = New!DepthOfFieldShader(this);
199         dofShader.gbuffer = gbuffer;
200         passDoF = New!FilterPass(pipeline, dofShader);
201         passDoF.view = view;
202         passDoF.inputBuffer = inputBuffer;
203         passDoF.outputBuffer = hdrBuffer3;
204 
205         motionBlurShader = New!MotionBlurShader(this);
206         motionBlurShader.gbuffer = gbuffer;
207         passMotionBlur = New!FilterPass(pipeline, motionBlurShader);
208         passMotionBlur.view = view;
209         passMotionBlur.inputBuffer = passDoF.outputBuffer;
210         passMotionBlur.outputBuffer = hdrBuffer4;
211 
212         brightPassShader = New!BrightPassShader(this);
213         brightPassShader.luminanceThreshold = glowThreshold;
214         passBrightPass = New!FilterPass(pipeline, brightPassShader);
215         passBrightPass.view = viewHalf;
216         passBrightPass.inputBuffer = passMotionBlur.outputBuffer;
217         passBrightPass.outputBuffer = hdrBuffer1;
218 
219         passBlur = New!BlurPass(pipeline);
220         passBlur.view = viewHalf;
221         passBlur.inputBuffer = passBrightPass.outputBuffer;
222         passBlur.outputBuffer = hdrBuffer1;
223         passBlur.outputBuffer2 = hdrBuffer2;
224         passBlur.radius = glowRadius;
225 
226         glowShader = New!GlowShader(this);
227         glowShader.blurredBuffer = passBlur.outputBuffer;
228         glowShader.intensity = glowIntensity;
229         passGlow = New!FilterPass(pipeline, glowShader);
230         passGlow.view = view;
231         passGlow.inputBuffer = passMotionBlur.outputBuffer;
232         passGlow.outputBuffer = hdrBuffer3;
233 
234         tonemapShader = New!TonemapShader(this);
235         passTonemap = New!FilterPass(pipeline, tonemapShader);
236         passTonemap.view = view;
237         passTonemap.inputBuffer = passGlow.outputBuffer;
238         passTonemap.outputBuffer = ldrDoubleBuffer;
239 
240         fxaaShader = New!FXAAShader(this);
241         passFXAA = New!FilterPass(pipeline, fxaaShader);
242         passFXAA.view = view;
243         passFXAA.inputBuffer = ldrDoubleBuffer;
244         passFXAA.outputBuffer = ldrDoubleBuffer;
245 
246         lensDistortionShader = New!LensDistortionShader(this);
247         passLensDistortion = New!FilterPass(pipeline, lensDistortionShader);
248         passLensDistortion.view = view;
249         passLensDistortion.inputBuffer = ldrDoubleBuffer;
250         passLensDistortion.outputBuffer = ldrDoubleBuffer;
251 
252         lutShader = New!LUTShader(this);
253         passLUT = New!FilterPass(pipeline, lutShader);
254         passLUT.view = view;
255         passLUT.inputBuffer = ldrDoubleBuffer;
256         passLUT.outputBuffer = ldrDoubleBuffer;
257 
258         outputBuffer = ldrDoubleBuffer;
259     }
260 
261     void depthOfFieldEnabled(bool mode) @property
262     {
263         _dofEnabled = mode;
264         passDoF.active = mode;
265     }
266     bool depthOfFieldEnabled() @property
267     {
268         return _dofEnabled;
269     }
270 
271     void motionBlurEnabled(bool mode) @property
272     {
273         _motionBlurEnabled = mode;
274         passMotionBlur.active = mode;
275     }
276     bool motionBlurEnabled() @property
277     {
278         return _motionBlurEnabled;
279     }
280 
281     void glowEnabled(bool mode) @property
282     {
283         _glowEnabled = mode;
284         passBrightPass.active = mode;
285         passBlur.active = mode;
286         passGlow.active = mode;
287     }
288     bool glowEnabled() @property
289     {
290         return _glowEnabled;
291     }
292 
293     void fxaaEnabled(bool mode) @property
294     {
295         passFXAA.active = mode;
296     }
297     bool fxaaEnabled() @property
298     {
299         return passFXAA.active;
300     }
301 
302     void lensDistortionEnabled(bool mode) @property
303     {
304         passLensDistortion.active = mode;
305     }
306     bool lensDistortionEnabled() @property
307     {
308         return passLensDistortion.active;
309     }
310 
311     void lutEnabled(bool mode) @property
312     {
313         passLUT.active = mode;
314     }
315     bool lutEnabled() @property
316     {
317         return passLUT.active;
318     }
319 
320     override void update(Time t)
321     {
322         super.update(t);
323 
324         brightPassShader.luminanceThreshold = glowThreshold;
325         glowShader.intensity = glowIntensity;
326         passBlur.radius = glowRadius;
327         tonemapShader.tonemapper = tonemapper;
328         tonemapShader.exposure = exposure;
329         dofShader.autofocus = autofocus;
330         dofShader.focalDepth = focalDepth;
331         dofShader.focalLength = focalLength;
332         dofShader.fStop = fStop;
333         motionBlurShader.samples = motionBlurSamples;
334         motionBlurShader.currentFramerate = 60.0f; //1.0 / t.delta;
335         motionBlurShader.shutterFramerate = motionBlurFramerate;
336         motionBlurShader.offsetRandomCoefficient = motionBlurRandomness;
337         motionBlurShader.minDistance = motionBlurMinDistance;
338         motionBlurShader.maxDistance = motionBlurMaxDistance;
339         lutShader.colorLookupTable = colorLookupTable;
340         if (lutShader.colorLookupTable)
341         {
342             lutShader.colorLookupTable.useMipmapFiltering = false;
343         }
344     }
345 
346     override void render()
347     {
348         if (outputBuffer)
349             outputBuffer.bind();
350         
351         if (!_dofEnabled)
352         {
353             passMotionBlur.inputBuffer = inputBuffer;
354         }
355         else
356         {
357             passMotionBlur.inputBuffer = passDoF.outputBuffer;
358         }
359         
360         if (!_motionBlurEnabled)
361         {
362             if (_dofEnabled)
363             {
364                 passBrightPass.inputBuffer = passDoF.outputBuffer;
365                 passGlow.inputBuffer = passDoF.outputBuffer;
366             }
367             else
368             {
369                 passBrightPass.inputBuffer = inputBuffer;
370                 passGlow.inputBuffer = inputBuffer;
371             }
372         }
373         else
374         {
375             passBrightPass.inputBuffer = passMotionBlur.outputBuffer;
376             passGlow.inputBuffer = passMotionBlur.outputBuffer;
377         }
378             
379         if (!_glowEnabled)
380         {
381             if (_motionBlurEnabled)
382                 passTonemap.inputBuffer = passMotionBlur.outputBuffer;
383             else if (_dofEnabled)
384                 passTonemap.inputBuffer = passDoF.outputBuffer;
385             else
386                 passTonemap.inputBuffer = inputBuffer;
387         }
388         else
389         {
390             passTonemap.inputBuffer = passGlow.outputBuffer;
391         }
392         
393         foreach(pass; pipeline.passes.data)
394         {
395             if (pass.active)
396             {
397                 pass.render();
398                 ldrDoubleBuffer.swap();
399             }
400         }
401 
402         if (outputBuffer)
403             outputBuffer.unbind();
404     }
405 
406     override void setViewport(uint x, uint y, uint w, uint h)
407     {
408         super.setViewport(x, y, w, h);
409 
410         viewHalf.resize(cast(uint)(view.width * glowViewScale), cast(uint)(view.height * glowViewScale));
411 
412         ldrBuffer1.resize(view.width, view.height);
413         ldrBuffer2.resize(view.width, view.height);
414 
415         hdrBuffer1.resize(viewHalf.width, viewHalf.height);
416         hdrBuffer2.resize(viewHalf.width, viewHalf.height);
417         hdrBuffer3.resize(view.width, view.height);
418         hdrBuffer4.resize(view.width, view.height);
419     }
420 }