README.md edited online with Bitbucket
[gdash.git] / shaders / GDash-TV.shader
blobc0587af14b4909050782d3f10c14eb4c364dbde5
1 <?xml version="1.0" encoding="UTF-8"?>
2 <!--
3 GDash-TV shader
4 -->
5 <shader language="GLSL">
6 <vertex><![CDATA[
7 #version 120
9 uniform vec2 rubyTextureSize;
11 varying vec2 c00;
12 varying vec2 c10;
13 varying vec2 c01;
15 void main(void)
17 vec2 tex = gl_MultiTexCoord0.xy;
18 vec2 onetexelx = vec2(1.0 / rubyTextureSize.x, 0.0);
19 vec2 onetexely = vec2(0.0, 1.0 / rubyTextureSize.y);
21 c00 = tex;
22 c10 = tex - onetexelx;
23 c01 = tex - onetexely;
25 gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
27 ]]></vertex>
28 <fragment filter="linear"><![CDATA[
29 #version 120
31 uniform float randomSeed;
33 uniform float CHROMA_TO_LUMA_STRENGTH;
34 uniform float LUMA_TO_CHROMA_STRENGTH;
35 uniform float SCANLINE_SHADE_LUMA;
36 uniform float PHOSPHOR_SHADE;
37 uniform float RANDOM_SCANLINE_DISPLACE;
38 uniform float RANDOM_Y;
39 uniform float RANDOM_UV;
40 uniform float LUMA_X_BLUR;
41 uniform float CHROMA_X_BLUR;
42 uniform float CHROMA_Y_BLUR;
43 uniform float RADIAL_DISTORTION;
45 uniform sampler2D rubyTexture;
46 uniform vec2 rubyTextureSize;
48 varying vec2 c00;
49 varying vec2 c10;
50 varying vec2 c01;
52 float rand(vec2 seed) {
53 return fract(sin(dot(vec2(seed.x + randomSeed, seed.y + randomSeed), vec2(12.9898, 78.233))) * 43758.5453);
56 vec2 rand_x() {
57 return vec2(fract(sin(dot(vec2(randomSeed, gl_FragCoord.y), vec2(12.9898, 78.233))) * 43758.5453), 0.0);
60 vec2 radialDistortion(vec2 coord) {
61 vec2 cc = coord - vec2(0.5);
62 float dist = dot(cc, cc) * RADIAL_DISTORTION * 0.5;
63 return (coord + cc * (1.0 + dist) * dist);
66 vec4 texture_x_linear(vec2 pos) {
67 pos = radialDistortion(pos);
68 return texture2D(rubyTexture, vec2(pos.x, (floor(pos.y * rubyTextureSize.y) + 0.5) / rubyTextureSize.y));
71 vec4 texture(vec2 pos) {
72 pos = radialDistortion(pos);
73 return texture2D(rubyTexture, pos);
76 void main(void) {
77 mat3 rgb2yuv = mat3(0.299, -0.14713, 0.615,
78 0.587, -0.28886, -0.51499,
79 0.114, 0.436 , -0.10001);
80 mat3 yuv2rgb = mat3(1.0, 1.0, 1.0,
81 0.0, -0.39465, 2.03211,
82 1.13983, -0.58060, 0.0);
84 bool even = mod(c00.y * rubyTextureSize.y, 2.0) < 1.0;
85 vec3 phosphor = vec3(1.0, PHOSPHOR_SHADE, PHOSPHOR_SHADE);
87 /* to yuv */
88 vec2 dist = rand_x() / rubyTextureSize.x * RANDOM_SCANLINE_DISPLACE;
89 vec3 yuvm1 = rgb2yuv * texture_x_linear(c10 + dist).rgb;
90 vec3 yuv_0 = rgb2yuv * texture_x_linear(c00 + dist).rgb;
91 vec3 yuvym1 = rgb2yuv * texture(c01 + dist).rgb;
93 vec3 yuv = vec3(
94 /* luma: set as blurred from original */
95 /* y */ mix(yuv_0.x, yuvm1.x, LUMA_X_BLUR * 0.5),
96 /* chroma: set as blurred from original */
97 /* u */ mix(yuv_0.y, yuvym1.y, CHROMA_Y_BLUR),
98 /* v */ mix(yuv_0.z, yuvym1.z, CHROMA_Y_BLUR)
101 /* edge detect for crosstalk. */
102 /* also chroma x blur from the edge detect vector - otherwise it's not really visible. */
103 vec3 d = yuvm1 - yuv_0;
104 yuv += vec3(
105 /* chroma crosstalk to luma */
106 /* y */ CHROMA_TO_LUMA_STRENGTH * (even ? (d.y + d.z) : (d.z - d.y)),
107 /* luma crosstalk to chroma */
108 /* u */ -LUMA_TO_CHROMA_STRENGTH * d.x + CHROMA_X_BLUR * d.y,
109 /* v */ LUMA_TO_CHROMA_STRENGTH * d.x + CHROMA_X_BLUR * d.z
112 /* random noise. the positions are used to feed the random gen. */
113 yuv += vec3(
114 (rand(c00) - 0.5) * RANDOM_Y,
115 (rand(c01) - 0.5) * RANDOM_UV,
116 (rand(c10) - 0.5) * RANDOM_UV
119 /* darken every second row */
120 if (mod(gl_FragCoord.y, 2.0) < 1.0)
121 yuv.x *= SCANLINE_SHADE_LUMA;
123 /* phosphor stuff */
124 float pix = mod(gl_FragCoord.x, 3.0);
125 if (pix < 1.0)
126 phosphor = phosphor.yzx;
127 else if (pix < 2.0)
128 phosphor = phosphor.zxy;
130 /* back to rgb and add phosphor. and here is the result */
131 gl_FragColor.rgb = yuv2rgb * yuv * phosphor;
133 ]]></fragment>
134 </shader>