1 /*
2 Copyright (c) 2019-2022 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.view;
39 import dagon.render.framebuffer;
40 import dagon.render.gbuffer;
41 import dagon.postproc.filterpass;
42 import dagon.postproc.blurpass;
43 import dagon.postproc.presentpass;
44 import dagon.postproc.shaders.dof;
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         this.writeBuffer = writeBuffer;
65         this.readBuffer = readBuffer;
66     }
67 
68     void swap()
69     {
70         auto w = writeBuffer;
71         writeBuffer = readBuffer;
72         readBuffer = w;
73     }
74 
75     override GLuint colorTexture()
76     {
77         return readBuffer.colorTexture();
78     }
79 
80     override GLuint depthTexture()
81     {
82         return readBuffer.depthTexture();
83     }
84 
85     override void bind()
86     {
87         writeBuffer.bind();
88     }
89 
90     override void unbind()
91     {
92         writeBuffer.unbind();
93     }
94 
95     override void resize(uint width, uint height)
96     {
97 
98     }
99 
100     override void blitColorBuffer()
101     {
102 
103     }
104 
105     override void blitDepthBuffer()
106     {
107 
108     }
109 }
110 
111 class PostProcRenderer: Renderer
112 {
113     public:
114 
115     Framebuffer inputBuffer;
116     Framebuffer outputBuffer;
117 
118     protected:
119 
120     DoubleBuffer ldrDoubleBuffer;
121 
122     Framebuffer ldrBuffer1;
123     Framebuffer ldrBuffer2;
124 
125     Framebuffer hdrBuffer1;
126     Framebuffer hdrBuffer2;
127     Framebuffer hdrBuffer3;
128     Framebuffer hdrBuffer4;
129 
130     RenderView viewHalf;
131     BlurPass passBlur;
132 
133     DepthOfFieldShader dofShader;
134     BrightPassShader brightPassShader;
135     GlowShader glowShader;
136     MotionBlurShader motionBlurShader;
137     TonemapShader tonemapShader;
138     FXAAShader fxaaShader;
139     LensDistortionShader lensDistortionShader;
140     LUTShader lutShader;
141 
142     FilterPass passDoF;
143     FilterPass passMotionBlur;
144     FilterPass passBrightPass;
145     FilterPass passGlow;
146     FilterPass passTonemap;
147     FilterPass passFXAA;
148     FilterPass passLensDistortion;
149     FilterPass passLUT;
150     PresentPass passPresent;
151 
152     bool _dofEnabled = false;
153     bool _motionBlurEnabled = false;
154     bool _glowEnabled = false;
155 
156     public:
157 
158     float glowViewScale = 0.33f;
159 
160     float glowThreshold = 0.8f;
161     float glowIntensity = 0.2f;
162     int glowRadius = 5;
163     Tonemapper tonemapper = Tonemapper.ACES;
164     float exposure = 1.0f;
165 
166     uint motionBlurSamples = 16;
167     uint motionBlurFramerate = 24;
168     float motionBlurRandomness = 0.2f;
169     float motionBlurMinDistance = 0.01f;
170     float motionBlurMaxDistance = 1.0f;
171     float radialBlurAmount = 0.0f;
172     
173     float lensDistortionScale = 1.0f;
174     float lensDistortionDispersion = 0.1f;
175     
176     bool autofocus = true;
177     float focalDepth = 1.5;
178     float focalLength = 5.0;
179     float fStop = 2.0;
180     
181     bool dofManual = false;
182     float dofNearStart = 1.0;
183     float dofNearDistance = 2.0;
184     float dofFarStart = 1.0;
185     float dofFarDistance = 3.0;
186 
187     Texture colorLookupTable;
188 
189     this(EventManager eventManager, Framebuffer inputBuffer, GBuffer gbuffer, Owner owner)
190     {
191         super(eventManager, owner);
192 
193         this.inputBuffer = inputBuffer;
194 
195         viewHalf = New!RenderView(0, 0, cast(uint)(view.width * glowViewScale), cast(uint)(view.height * glowViewScale), this);
196 
197         ldrBuffer1 = New!Framebuffer(view.width, view.height, FrameBufferFormat.RGBA8, true, this);
198         ldrBuffer2 = New!Framebuffer(view.width, view.height, FrameBufferFormat.RGBA8, true, this);
199         ldrDoubleBuffer = New!DoubleBuffer(ldrBuffer1, ldrBuffer2, this);
200 
201         hdrBuffer1 = New!Framebuffer(viewHalf.width, viewHalf.height, FrameBufferFormat.RGBA16F, true, this);
202         hdrBuffer2 = New!Framebuffer(viewHalf.width, viewHalf.height, FrameBufferFormat.RGBA16F, true, this);
203 
204         hdrBuffer3 = New!Framebuffer(view.width, view.height, FrameBufferFormat.RGBA16F, true, this);
205         hdrBuffer4 = New!Framebuffer(view.width, view.height, FrameBufferFormat.RGBA16F, true, this);
206 
207         dofShader = New!DepthOfFieldShader(this);
208         dofShader.gbuffer = gbuffer;
209         passDoF = New!FilterPass(pipeline, dofShader);
210         passDoF.view = view;
211         passDoF.inputBuffer = inputBuffer;
212         passDoF.outputBuffer = hdrBuffer3;
213 
214         motionBlurShader = New!MotionBlurShader(this);
215         motionBlurShader.gbuffer = gbuffer;
216         passMotionBlur = New!FilterPass(pipeline, motionBlurShader);
217         passMotionBlur.view = view;
218         passMotionBlur.inputBuffer = passDoF.outputBuffer;
219         passMotionBlur.outputBuffer = hdrBuffer4;
220 
221         brightPassShader = New!BrightPassShader(this);
222         brightPassShader.luminanceThreshold = glowThreshold;
223         passBrightPass = New!FilterPass(pipeline, brightPassShader);
224         passBrightPass.view = viewHalf;
225         passBrightPass.inputBuffer = passMotionBlur.outputBuffer;
226         passBrightPass.outputBuffer = hdrBuffer1;
227 
228         passBlur = New!BlurPass(pipeline);
229         passBlur.view = viewHalf;
230         passBlur.inputBuffer = passBrightPass.outputBuffer;
231         passBlur.outputBuffer = hdrBuffer1;
232         passBlur.outputBuffer2 = hdrBuffer2;
233         passBlur.radius = glowRadius;
234 
235         glowShader = New!GlowShader(this);
236         glowShader.blurredBuffer = passBlur.outputBuffer;
237         glowShader.intensity = glowIntensity;
238         passGlow = New!FilterPass(pipeline, glowShader);
239         passGlow.view = view;
240         passGlow.inputBuffer = passMotionBlur.outputBuffer;
241         passGlow.outputBuffer = hdrBuffer3;
242 
243         tonemapShader = New!TonemapShader(this);
244         passTonemap = New!FilterPass(pipeline, tonemapShader);
245         passTonemap.view = view;
246         passTonemap.inputBuffer = passGlow.outputBuffer;
247         passTonemap.outputBuffer = ldrDoubleBuffer;
248 
249         fxaaShader = New!FXAAShader(this);
250         passFXAA = New!FilterPass(pipeline, fxaaShader);
251         passFXAA.view = view;
252         passFXAA.inputBuffer = ldrDoubleBuffer;
253         passFXAA.outputBuffer = ldrDoubleBuffer;
254 
255         lensDistortionShader = New!LensDistortionShader(this);
256         passLensDistortion = New!FilterPass(pipeline, lensDistortionShader);
257         passLensDistortion.view = view;
258         passLensDistortion.inputBuffer = ldrDoubleBuffer;
259         passLensDistortion.outputBuffer = ldrDoubleBuffer;
260 
261         lutShader = New!LUTShader(this);
262         passLUT = New!FilterPass(pipeline, lutShader);
263         passLUT.view = view;
264         passLUT.inputBuffer = ldrDoubleBuffer;
265         passLUT.outputBuffer = ldrDoubleBuffer;
266 
267         outputBuffer = ldrDoubleBuffer;
268     }
269 
270     void depthOfFieldEnabled(bool mode) @property
271     {
272         _dofEnabled = mode;
273         passDoF.active = mode;
274     }
275     bool depthOfFieldEnabled() @property
276     {
277         return _dofEnabled;
278     }
279 
280     void motionBlurEnabled(bool mode) @property
281     {
282         _motionBlurEnabled = mode;
283         passMotionBlur.active = mode;
284     }
285     bool motionBlurEnabled() @property
286     {
287         return _motionBlurEnabled;
288     }
289 
290     void glowEnabled(bool mode) @property
291     {
292         _glowEnabled = mode;
293         passBrightPass.active = mode;
294         passBlur.active = mode;
295         passGlow.active = mode;
296     }
297     bool glowEnabled() @property
298     {
299         return _glowEnabled;
300     }
301 
302     void fxaaEnabled(bool mode) @property
303     {
304         passFXAA.active = mode;
305     }
306     bool fxaaEnabled() @property
307     {
308         return passFXAA.active;
309     }
310 
311     void lensDistortionEnabled(bool mode) @property
312     {
313         passLensDistortion.active = mode;
314     }
315     bool lensDistortionEnabled() @property
316     {
317         return passLensDistortion.active;
318     }
319 
320     void lutEnabled(bool mode) @property
321     {
322         passLUT.active = mode;
323     }
324     bool lutEnabled() @property
325     {
326         return passLUT.active;
327     }
328 
329     override void update(Time t)
330     {
331         super.update(t);
332 
333         brightPassShader.luminanceThreshold = glowThreshold;
334         glowShader.intensity = glowIntensity;
335         passBlur.radius = glowRadius;
336         
337         tonemapShader.tonemapper = tonemapper;
338         tonemapShader.exposure = exposure;
339         
340         dofShader.autofocus = autofocus;
341         dofShader.focalDepth = focalDepth;
342         dofShader.focalLength = focalLength;
343         dofShader.fStop = fStop;
344         dofShader.manual = dofManual;
345         dofShader.nearStart = dofNearStart;
346         dofShader.nearDistance = dofNearDistance;
347         dofShader.farStart = dofFarStart;
348         dofShader.farDistance = dofFarDistance;
349         
350         motionBlurShader.samples = motionBlurSamples;
351         motionBlurShader.currentFramerate = 60.0f; //1.0 / t.delta;
352         motionBlurShader.shutterFramerate = motionBlurFramerate;
353         motionBlurShader.offsetRandomCoefficient = motionBlurRandomness;
354         motionBlurShader.minDistance = motionBlurMinDistance;
355         motionBlurShader.maxDistance = motionBlurMaxDistance;
356         motionBlurShader.radialBlur = radialBlurAmount;
357         
358         lensDistortionShader.scale = lensDistortionScale;
359         lensDistortionShader.dispersion = lensDistortionDispersion;
360         
361         lutShader.colorLookupTable = colorLookupTable;
362         if (lutShader.colorLookupTable)
363         {
364             lutShader.colorLookupTable.useMipmapFiltering = false;
365         }
366     }
367 
368     override void render()
369     {
370         if (outputBuffer)
371             outputBuffer.bind();
372         
373         if (!_dofEnabled)
374         {
375             passMotionBlur.inputBuffer = inputBuffer;
376         }
377         else
378         {
379             passMotionBlur.inputBuffer = passDoF.outputBuffer;
380         }
381         
382         if (!_motionBlurEnabled)
383         {
384             if (_dofEnabled)
385             {
386                 passBrightPass.inputBuffer = passDoF.outputBuffer;
387                 passGlow.inputBuffer = passDoF.outputBuffer;
388             }
389             else
390             {
391                 passBrightPass.inputBuffer = inputBuffer;
392                 passGlow.inputBuffer = inputBuffer;
393             }
394         }
395         else
396         {
397             passBrightPass.inputBuffer = passMotionBlur.outputBuffer;
398             passGlow.inputBuffer = passMotionBlur.outputBuffer;
399         }
400             
401         if (!_glowEnabled)
402         {
403             if (_motionBlurEnabled)
404                 passTonemap.inputBuffer = passMotionBlur.outputBuffer;
405             else if (_dofEnabled)
406                 passTonemap.inputBuffer = passDoF.outputBuffer;
407             else
408                 passTonemap.inputBuffer = inputBuffer;
409         }
410         else
411         {
412             passTonemap.inputBuffer = passGlow.outputBuffer;
413         }
414         
415         foreach(pass; pipeline.passes.data)
416         {
417             if (pass.active)
418             {
419                 pass.render();
420                 ldrDoubleBuffer.swap();
421             }
422         }
423 
424         if (outputBuffer)
425             outputBuffer.unbind();
426     }
427 
428     override void setViewport(uint x, uint y, uint w, uint h)
429     {
430         super.setViewport(x, y, w, h);
431 
432         viewHalf.resize(cast(uint)(view.width * glowViewScale), cast(uint)(view.height * glowViewScale));
433 
434         ldrBuffer1.resize(view.width, view.height);
435         ldrBuffer2.resize(view.width, view.height);
436 
437         hdrBuffer1.resize(viewHalf.width, viewHalf.height);
438         hdrBuffer2.resize(viewHalf.width, viewHalf.height);
439         hdrBuffer3.resize(view.width, view.height);
440         hdrBuffer4.resize(view.width, view.height);
441     }
442 }