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.lens;
29 
30 import derelict.opengl;
31 import dagon.core.ownership;
32 import dagon.graphics.postproc;
33 import dagon.graphics.framebuffer;
34 import dagon.graphics.rc;
35 
36 /*
37  * Implementation is based on a code by Jaume Sanchez:
38  * https://github.com/spite/Wagner
39  */
40 
41 class PostFilterLensDistortion: PostFilter
42 {
43     private string vs = "
44         #version 330 core
45         
46         uniform mat4 modelViewMatrix;
47         uniform mat4 projectionMatrix;
48 
49         uniform vec2 viewSize;
50         
51         layout (location = 0) in vec2 va_Vertex;
52         layout (location = 1) in vec2 va_Texcoord;
53 
54         out vec2 texCoord;
55         
56         void main()
57         {
58             texCoord = va_Texcoord;
59             gl_Position = projectionMatrix * modelViewMatrix * vec4(va_Vertex * viewSize, 0.0, 1.0);
60         }
61     ";
62 
63     private string fs = "
64         #version 330 core
65         
66         uniform sampler2D fbColor;
67         uniform vec2 viewSize;
68         
69         in vec2 texCoord;
70         out vec4 frag_color;
71 
72         vec2 barrelDistortion(vec2 coord, float amt)
73         {
74             vec2 cc = coord - 0.5;
75             float dist = dot(cc, cc);
76             return coord + cc * dist * amt;
77         }
78 
79         float sat(float t)
80         {
81             return clamp(t, 0.0, 1.0);
82         }
83 
84         float linterp(float t)
85         {
86             return sat(1.0 - abs(2.0 * t - 1.0));
87         }
88 
89         float remap(float t, float a, float b)
90         {
91             return sat((t - a) / (b - a));
92         }
93 
94         vec4 spectrumOffset(float t)
95         {
96             vec4 ret;
97             float lo = step(t, 0.5);
98             float hi = 1.0 - lo;
99             float w = linterp(remap(t, 1.0/6.0, 5.0/6.0));
100             ret = vec4(lo, 1.0, hi, 1.0) * vec4(1.0 - w, w, 1.0 - w, 1.0);
101             return pow(ret, vec4(1.0 / 2.2));
102         }
103 
104         uniform float scale;
105         uniform float dispersion;
106 
107         const int num_iter = 12;
108         const float reci_num_iter_f = 1.0 / float(num_iter);
109 
110         void main()
111         {	
112             vec2 uv = texCoord * scale + (1.0 - scale) * 0.5;
113 
114             vec4 sumcol = vec4(0.0);
115             vec4 sumw = vec4(0.0);	
116             for (int i = 0; i < num_iter; ++i)
117             {
118                 float t = float(i) * reci_num_iter_f;
119                 vec4 w = spectrumOffset(t);
120                 sumw += w;
121                 sumcol += w * texture(fbColor, barrelDistortion(uv, 0.6 * dispersion * t));
122             }
123                 
124             frag_color = sumcol / sumw;
125             frag_color.a = 1.0;
126         }
127     ";
128 
129     override string vertexShader()
130     {
131         return vs;
132     }
133 
134     override string fragmentShader()
135     {
136         return fs;
137     }
138 
139     GLint scaleLoc;
140     GLint dispersionLoc;
141 
142     float scale = 0.84;
143     float dispersion = 0.5;
144 
145     this(Framebuffer inputBuffer, Framebuffer outputBuffer, Owner o)
146     {
147         super(inputBuffer, outputBuffer, o);
148 
149         scaleLoc = glGetUniformLocation(shaderProgram, "scale");
150         dispersionLoc = glGetUniformLocation(shaderProgram, "dispersion");
151     }
152     
153     override void bind(RenderingContext* rc)
154     {
155         super.bind(rc);
156 
157         glUniform1f(scaleLoc, scale);
158         glUniform1f(dispersionLoc, dispersion);
159     }
160 }