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.filters.fxaa;
29 
30 import dagon.core.ownership;
31 import dagon.graphics.postproc;
32 import dagon.graphics.framebuffer;
33 
34 /*
35  * FXAA implementation is based on demo by GeeXLab:
36  * http://www.geeks3d.com/20110405/fxaa-fast-approximate-anti-aliasing-demo-glsl-opengl-test-radeon-geforce
37  */
38  
39 class PostFilterFXAA: PostFilter
40 {
41     private static string vs = q{
42         #version 330 core
43         
44         uniform mat4 modelViewMatrix;
45         uniform mat4 projectionMatrix;
46 
47         uniform vec2 viewSize;
48         
49         layout (location = 0) in vec2 va_Vertex;
50         layout (location = 1) in vec2 va_Texcoord;
51 
52         out vec2 texCoord;
53         
54         void main()
55         {
56             texCoord = va_Texcoord;
57             gl_Position = projectionMatrix * modelViewMatrix * vec4(va_Vertex * viewSize, 0.0, 1.0);
58         }
59     };
60 
61     private static string fs = q{
62         #version 330 core
63         
64         uniform bool enabled;
65         
66         uniform sampler2D fbColor;
67         uniform vec2 viewSize;
68         
69         in vec2 texCoord;
70         out vec4 frag_color;
71 
72         const float FXAA_REDUCE_MIN = 1.0 / 128.0;
73         const float FXAA_REDUCE_MUL = 1.0 / 8.0;
74         const float FXAA_SPAN_MAX = 4.0;
75 
76         vec4 fxaa(sampler2D tex, vec2 fragCoord, vec2 resolution,
77                    vec2 v_rgbNW, vec2 v_rgbNE, 
78                    vec2 v_rgbSW, vec2 v_rgbSE, 
79                    vec2 v_rgbM)
80         {
81             vec4 color;
82             vec2 inverseVP = vec2(1.0 / resolution.x, 1.0 / resolution.y);
83             vec3 rgbNW = texture(tex, v_rgbNW).xyz;
84             vec3 rgbNE = texture(tex, v_rgbNE).xyz;
85             vec3 rgbSW = texture(tex, v_rgbSW).xyz;
86             vec3 rgbSE = texture(tex, v_rgbSE).xyz;
87             vec4 texColor = texture(tex, v_rgbM);
88             vec3 rgbM  = texColor.xyz;
89             vec3 luma = vec3(0.299, 0.587, 0.114);
90             float lumaNW = dot(rgbNW, luma);
91             float lumaNE = dot(rgbNE, luma);
92             float lumaSW = dot(rgbSW, luma);
93             float lumaSE = dot(rgbSE, luma);
94             float lumaM  = dot(rgbM,  luma);
95             float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE)));
96             float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE)));
97             
98             vec2 dir;
99             dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE));
100             dir.y =  ((lumaNW + lumaSW) - (lumaNE + lumaSE));
101             
102             float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) *
103                                   (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN);
104             
105             float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce);
106             dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX),
107                       max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX),
108                       dir * rcpDirMin)) * inverseVP;
109             
110             vec3 rgbA = 0.5 * (
111                 texture(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz +
112                 texture(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz);
113             vec3 rgbB = rgbA * 0.5 + 0.25 * (
114                 texture(tex, fragCoord * inverseVP + dir * -0.5).xyz +
115                 texture(tex, fragCoord * inverseVP + dir * 0.5).xyz);
116 
117             float lumaB = dot(rgbB, luma);
118             if ((lumaB < lumaMin) || (lumaB > lumaMax))
119                 color = vec4(rgbA, texColor.a);
120             else
121                 color = vec4(rgbB, texColor.a);
122             return color;
123         }
124 
125         void main()
126         {
127             vec2 fragCoord = gl_FragCoord.xy;
128             vec2 invScreenSize = 1.0 / viewSize;
129 
130             vec3 color;
131             if (enabled)
132             {
133                 vec2 v_rgbNW = (fragCoord + vec2(-1.0, -1.0)) * invScreenSize;
134                 vec2 v_rgbNE = (fragCoord + vec2(1.0, -1.0)) * invScreenSize;
135                 vec2 v_rgbSW = (fragCoord + vec2(-1.0, 1.0)) * invScreenSize;
136                 vec2 v_rgbSE = (fragCoord + vec2(1.0, 1.0)) * invScreenSize;
137                 vec2 v_rgbM = vec2(fragCoord * invScreenSize);
138                 color = fxaa(fbColor, fragCoord, viewSize, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM).rgb; 
139             }
140             else
141             {
142                 color = texture(fbColor, texCoord).xyz;
143             }
144         
145             frag_color = vec4(color, 1.0); 
146         }
147     };
148 
149     override string vertexShader()
150     {
151         return vs;
152     }
153 
154     override string fragmentShader()
155     {
156         return fs;
157     }
158 
159     this(Framebuffer inputBuffer, Framebuffer outputBuffer, Owner o)
160     {
161         super(inputBuffer, outputBuffer, o);
162     }
163 }