1#version 130
2
3/*
4   Hyllian's CRT Shader
5
6   Copyright (C) 2011-2015 Hyllian - sergiogdb@gmail.com
7
8   Permission is hereby granted, free of charge, to any person obtaining a copy
9   of this software and associated documentation files (the "Software"), to deal
10   in the Software without restriction, including without limitation the rights
11   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12   copies of the Software, and to permit persons to whom the Software is
13   furnished to do so, subject to the following conditions:
14
15   The above copyright notice and this permission notice shall be included in
16   all copies or substantial portions of the Software.
17
18   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24   THE SOFTWARE.
25
26*/
27
28#pragma parameter PHOSPHOR "CRT - Phosphor ON/OFF" 0.0 0.0 1.0 1.0
29#pragma parameter VSCANLINES "CRT - Scanlines Direction" 0.0 0.0 1.0 1.0
30#pragma parameter InputGamma "CRT - Input gamma" 2.2 0.0 5.0 0.1
31#pragma parameter OutputGamma "CRT - Output Gamma" 2.2 0.0 5.0 0.1
32#pragma parameter SHARPNESS "CRT - Sharpness Hack" 2.0 1.0 5.0 1.0
33#pragma parameter COLOR_BOOST "CRT - Color Boost" 1.3 1.0 2.0 0.05
34#pragma parameter RED_BOOST "CRT - Red Boost" 1.0 1.0 2.0 0.01
35#pragma parameter GREEN_BOOST "CRT - Green Boost" 1.0 1.0 2.0 0.01
36#pragma parameter BLUE_BOOST "CRT - Blue Boost" 1.0 1.0 2.0 0.01
37#pragma parameter SCANLINES_STRENGTH "CRT - Scanline Strength" 1.0 0.0 1.0 0.02
38#pragma parameter BEAM_MIN_WIDTH "CRT - Min Beam Width" 0.60 0.0 1.0 0.02
39#pragma parameter BEAM_MAX_WIDTH "CRT - Max Beam Width" 0.80 0.0 1.0 0.02
40#pragma parameter CRT_ANTI_RINGING "CRT - Anti-Ringing" 0.8 0.0 1.0 0.1
41
42#define GAMMA_IN(color)     pow(color, vec3(InputGamma, InputGamma, InputGamma))
43#define GAMMA_OUT(color)    pow(color, vec3(1.0 / OutputGamma, 1.0 / OutputGamma, 1.0 / OutputGamma))
44
45// Horizontal cubic filter.
46
47// Some known filters use these values:
48
49//    B = 0.0, C = 0.0  =>  Hermite cubic filter.
50//    B = 1.0, C = 0.0  =>  Cubic B-Spline filter.
51//    B = 0.0, C = 0.5  =>  Catmull-Rom Spline filter. This is the default used in this shader.
52//    B = C = 1.0/3.0   =>  Mitchell-Netravali cubic filter.
53//    B = 0.3782, C = 0.3109  =>  Robidoux filter.
54//    B = 0.2620, C = 0.3690  =>  Robidoux Sharp filter.
55//    B = 0.36, C = 0.28  =>  My best config for ringing elimination in pixel art (Hyllian).
56
57// For more info, see: http://www.imagemagick.org/Usage/img_diagrams/cubic_survey.gif
58
59#if defined(VERTEX)
60
61#if __VERSION__ >= 130
62#define COMPAT_VARYING out
63#define COMPAT_ATTRIBUTE in
64#define COMPAT_TEXTURE texture
65#else
66#define COMPAT_VARYING varying
67#define COMPAT_ATTRIBUTE attribute
68#define COMPAT_TEXTURE texture2D
69#endif
70
71#ifdef GL_ES
72#define COMPAT_PRECISION mediump
73#else
74#define COMPAT_PRECISION
75#endif
76
77COMPAT_ATTRIBUTE vec4 VertexCoord;
78COMPAT_ATTRIBUTE vec4 COLOR;
79COMPAT_ATTRIBUTE vec4 TexCoord;
80COMPAT_VARYING vec4 COL0;
81COMPAT_VARYING vec4 TEX0;
82
83vec4 _oPosition1;
84uniform mat4 MVPMatrix;
85uniform COMPAT_PRECISION int FrameDirection;
86uniform COMPAT_PRECISION int FrameCount;
87uniform COMPAT_PRECISION vec2 OutputSize;
88uniform COMPAT_PRECISION vec2 TextureSize;
89uniform COMPAT_PRECISION vec2 InputSize;
90
91// compatibility #defines
92#define vTexCoord TEX0.xy
93#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
94#define OutSize vec4(OutputSize, 1.0 / OutputSize)
95
96#ifdef PARAMETER_UNIFORM
97uniform COMPAT_PRECISION float PHOSPHOR;
98uniform COMPAT_PRECISION float VSCANLINES;
99uniform COMPAT_PRECISION float InputGamma;
100uniform COMPAT_PRECISION float OutputGamma;
101uniform COMPAT_PRECISION float SHARPNESS;
102uniform COMPAT_PRECISION float COLOR_BOOST;
103uniform COMPAT_PRECISION float RED_BOOST;
104uniform COMPAT_PRECISION float GREEN_BOOST;
105uniform COMPAT_PRECISION float BLUE_BOOST;
106uniform COMPAT_PRECISION float SCANLINES_STRENGTH;
107uniform COMPAT_PRECISION float BEAM_MIN_WIDTH;
108uniform COMPAT_PRECISION float BEAM_MAX_WIDTH;
109uniform COMPAT_PRECISION float CRT_ANTI_RINGING;
110#else
111#define PHOSPHOR 0.0
112#define VSCANLINES 0.0
113#define InputGamma 2.2
114#define OutputGamma 2.2
115#define SHARPNESS 2.0
116#define COLOR_BOOST 1.3
117#define RED_BOOST 1.0
118#define GREEN_BOOST 1.0
119#define BLUE_BOOST 1.0
120#define SCANLINES_STRENGTH 1.0
121#define BEAM_MIN_WIDTH 0.60
122#define BEAM_MAX_WIDTH 0.80
123#define CRT_ANTI_RINGING 0.8
124#endif
125
126void main()
127{
128    gl_Position = MVPMatrix * VertexCoord;
129    TEX0.xy = TexCoord.xy;
130}
131
132#elif defined(FRAGMENT)
133
134#ifdef GL_ES
135#ifdef GL_FRAGMENT_PRECISION_HIGH
136precision highp float;
137#else
138precision mediump float;
139#endif
140#define COMPAT_PRECISION mediump
141#else
142#define COMPAT_PRECISION
143#endif
144
145#if __VERSION__ >= 130
146#define COMPAT_VARYING in
147#define COMPAT_TEXTURE texture
148out COMPAT_PRECISION vec4 FragColor;
149#else
150#define COMPAT_VARYING varying
151#define FragColor gl_FragColor
152#define COMPAT_TEXTURE texture2D
153#endif
154
155uniform COMPAT_PRECISION int FrameDirection;
156uniform COMPAT_PRECISION int FrameCount;
157uniform COMPAT_PRECISION vec2 OutputSize;
158uniform COMPAT_PRECISION vec2 TextureSize;
159uniform COMPAT_PRECISION vec2 InputSize;
160uniform sampler2D Texture;
161COMPAT_VARYING vec4 TEX0;
162
163// compatibility #defines
164#define Source Texture
165#define vTexCoord TEX0.xy
166
167#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
168#define OutSize vec4(OutputSize, 1.0 / OutputSize)
169
170#ifdef PARAMETER_UNIFORM
171uniform COMPAT_PRECISION float PHOSPHOR;
172uniform COMPAT_PRECISION float VSCANLINES;
173uniform COMPAT_PRECISION float InputGamma;
174uniform COMPAT_PRECISION float OutputGamma;
175uniform COMPAT_PRECISION float SHARPNESS;
176uniform COMPAT_PRECISION float COLOR_BOOST;
177uniform COMPAT_PRECISION float RED_BOOST;
178uniform COMPAT_PRECISION float GREEN_BOOST;
179uniform COMPAT_PRECISION float BLUE_BOOST;
180uniform COMPAT_PRECISION float SCANLINES_STRENGTH;
181uniform COMPAT_PRECISION float BEAM_MIN_WIDTH;
182uniform COMPAT_PRECISION float BEAM_MAX_WIDTH;
183uniform COMPAT_PRECISION float CRT_ANTI_RINGING;
184#else
185#define PHOSPHOR 0.0
186#define VSCANLINES 0.0
187#define InputGamma 2.2
188#define OutputGamma 2.2
189#define SHARPNESS 2.0
190#define COLOR_BOOST 1.3
191#define RED_BOOST 1.0
192#define GREEN_BOOST 1.0
193#define BLUE_BOOST 1.0
194#define SCANLINES_STRENGTH 1.0
195#define BEAM_MIN_WIDTH 0.60
196#define BEAM_MAX_WIDTH 0.80
197#define CRT_ANTI_RINGING 0.8
198#endif
199
200// Change these params to configure the horizontal filter.
201float  B =  0.0;
202float  C =  0.5;
203
204mat4 invX = mat4(
205	(-B - 6.0*C)/6.0, (3.0*B + 12.0*C)/6.0, (-3.0*B - 6.0*C)/6.0, B/6.0,
206	(12.0 - 9.0*B - 6.0*C)/6.0, (-18.0 + 12.0*B + 6.0*C)/6.0, 0.0, (6.0 - 2.0*B)/6.0,
207   -(12.0 - 9.0*B - 6.0*C)/6.0, (18.0 - 15.0*B - 12.0*C)/6.0, (3.0*B + 6.0*C)/6.0, B/6.0,
208	(B + 6.0*C)/6.0, -C, 0.0, 0.0
209);
210
211void main()
212{
213    vec3 color;
214
215    vec2 TexSize = vec2(SHARPNESS*SourceSize.x, SourceSize.y);
216
217    vec2 dx = mix(vec2(1.0/TexSize.x, 0.0), vec2(0.0, 1.0/TexSize.y), VSCANLINES);
218    vec2 dy = mix(vec2(0.0, 1.0/TexSize.y), vec2(1.0/TexSize.x, 0.0), VSCANLINES);
219
220    vec2 pix_coord = vTexCoord*TexSize + vec2(-0.5, 0.5);
221
222    vec2 tc = mix((floor(pix_coord) + vec2(0.5, 0.5))/TexSize, (floor(pix_coord) + vec2(1.0, -0.5))/TexSize, VSCANLINES);
223
224    vec2 fp = mix(fract(pix_coord), fract(pix_coord.yx), VSCANLINES);
225
226    vec3 c00 = GAMMA_IN(COMPAT_TEXTURE(Source, tc     - dx - dy).xyz);
227    vec3 c01 = GAMMA_IN(COMPAT_TEXTURE(Source, tc          - dy).xyz);
228    vec3 c02 = GAMMA_IN(COMPAT_TEXTURE(Source, tc     + dx - dy).xyz);
229    vec3 c03 = GAMMA_IN(COMPAT_TEXTURE(Source, tc + 2.0*dx - dy).xyz);
230    vec3 c10 = GAMMA_IN(COMPAT_TEXTURE(Source, tc     - dx     ).xyz);
231    vec3 c11 = GAMMA_IN(COMPAT_TEXTURE(Source, tc              ).xyz);
232    vec3 c12 = GAMMA_IN(COMPAT_TEXTURE(Source, tc     + dx     ).xyz);
233    vec3 c13 = GAMMA_IN(COMPAT_TEXTURE(Source, tc + 2.0*dx     ).xyz);
234
235    // Get min/max samples
236    vec3 min_sample = min(min(c01, c11), min(c02, c12));
237    vec3 max_sample = max(max(c01, c11), max(c02, c12));
238
239    mat4x3 color_matrix0 = mat4x3(c00, c01, c02, c03);
240    mat4x3 color_matrix1 = mat4x3(c10, c11, c12, c13);
241
242    vec4 invX_Px    = vec4(fp.x*fp.x*fp.x, fp.x*fp.x, fp.x, 1.0) * invX;
243    vec3 color0     = color_matrix0 * invX_Px;
244    vec3 color1     = color_matrix1 * invX_Px;
245
246    // Anti-ringing
247    vec3 aux    = color0;
248    color0      = clamp(color0, min_sample, max_sample);
249    color0      = mix(aux, color0, CRT_ANTI_RINGING);
250    aux         = color1;
251    color1      = clamp(color1, min_sample, max_sample);
252    color1      = mix(aux, color1, CRT_ANTI_RINGING);
253
254    float pos0 = fp.y;
255    float pos1 = 1 - fp.y;
256
257    vec3 lum0 = mix(vec3(BEAM_MIN_WIDTH), vec3(BEAM_MAX_WIDTH), color0);
258    vec3 lum1 = mix(vec3(BEAM_MIN_WIDTH), vec3(BEAM_MAX_WIDTH), color1);
259
260    vec3 d0 = clamp(pos0/(lum0 + 0.0000001), 0.0, 1.0);
261    vec3 d1 = clamp(pos1/(lum1 + 0.0000001), 0.0, 1.0);
262
263    d0 = exp(-10.0*SCANLINES_STRENGTH*d0*d0);
264    d1 = exp(-10.0*SCANLINES_STRENGTH*d1*d1);
265
266    color = clamp(color0*d0 + color1*d1, 0.0, 1.0);
267
268    color *= COLOR_BOOST*vec3(RED_BOOST, GREEN_BOOST, BLUE_BOOST);
269
270    float mod_factor = mix(vTexCoord.x * OutputSize.x, vTexCoord.y * OutputSize.y, VSCANLINES);
271
272    vec3 dotMaskWeights = mix(
273        vec3(1.0, 0.7, 1.0),
274        vec3(0.7, 1.0, 0.7),
275        floor(mod(mod_factor, 2.0))
276    );
277
278    color.rgb *= mix(vec3(1.0), dotMaskWeights, PHOSPHOR);
279
280    color  = GAMMA_OUT(color);
281
282FragColor = vec4(color, 1.0);
283}
284#endif
285