forked from randyrossi/bmc64
-
Notifications
You must be signed in to change notification settings - Fork 0
/
crt_pi_rgb.c
executable file
·260 lines (260 loc) · 9.01 KB
/
crt_pi_rgb.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
const char *rgb_shader =
"/*\n"
" crt-pi - A Raspberry Pi friendly CRT shader.\n"
"\n"
" Copyright (C) 2015-2016 davej\n"
"\n"
" This program is free software; you can redistribute it and/or modify it\n"
" under the terms of the GNU General Public License as published by the Free\n"
" Software Foundation; either version 2 of the License, or (at your option)\n"
" any later version.\n"
"\n"
"\n"
"Notes:\n"
"\n"
"This shader is designed to work well on Raspberry Pi GPUs (i.e. 1080P @ 60Hz on a game with a 4:3 aspect ratio). It pushes the Pi's GPU hard and enabling some features will slow it down so that it is no longer able to match 1080P @ 60Hz. You will need to overclock your Pi to the fastest setting in raspi-config to get the best results from this shader: 'Pi2' for Pi2 and 'Turbo' for original Pi and Pi Zero. Note: Pi2s are slower at running the shader than other Pis, this seems to be down to Pi2s lower maximum memory speed. Pi2s don't quite manage 1080P @ 60Hz - they drop about 1 in 1000 frames. You probably won't notice this, but if you do, try enabling FAKE_GAMMA.\n"
"\n"
"SCANLINES enables scanlines. You'll almost certainly want to use it with MULTISAMPLE to reduce moire effects. SCANLINE_WEIGHT defines how wide scanlines are (it is an inverse value so a higher number = thinner lines). SCANLINE_GAP_BRIGHTNESS defines how dark the gaps between the scan lines are. Darker gaps between scan lines make moire effects more likely.\n"
"\n"
"GAMMA enables gamma correction using the values in INPUT_GAMMA and OUTPUT_GAMMA. FAKE_GAMMA causes it to ignore the values in INPUT_GAMMA and OUTPUT_GAMMA and approximate gamma correction in a way which is faster than true gamma whilst still looking better than having none. You must have GAMMA defined to enable FAKE_GAMMA.\n"
"\n"
"CURVATURE distorts the screen by CURVATURE_X and CURVATURE_Y. Curvature slows things down a lot.\n"
"\n"
"By default the shader uses linear blending horizontally. If you find this too blury, enable SHARPER.\n"
"\n"
"BLOOM_FACTOR controls the increase in width for bright scanlines.\n"
"\n"
"MASK_TYPE defines what, if any, shadow mask to use. MASK_BRIGHTNESS defines how much the mask type darkens the screen.\n"
"\n"
"*/\n"
"\n"
"#pragma parameter CURVATURE_X \"Screen curvature - horizontal\" 0.10 0.0 1.0 0.01\n"
"#pragma parameter CURVATURE_Y \"Screen curvature - vertical\" 0.15 0.0 1.0 0.01\n"
"#pragma parameter MASK_BRIGHTNESS \"Mask brightness\" 0.70 0.0 1.0 0.01\n"
"#pragma parameter SCANLINE_WEIGHT \"Scanline weight\" 6.0 0.0 15.0 0.1\n"
"#pragma parameter SCANLINE_GAP_BRIGHTNESS \"Scanline gap brightness\" 0.12 0.0 1.0 0.01\n"
"#pragma parameter BLOOM_FACTOR \"Bloom factor\" 1.5 0.0 5.0 0.01\n"
"#pragma parameter INPUT_GAMMA \"Input gamma\" 2.4 0.0 5.0 0.01\n"
"#pragma parameter OUTPUT_GAMMA \"Output gamma\" 2.2 0.0 5.0 0.01\n"
"\n"
"// Haven't put these as parameters as it would slow the code down.\n"
"//#define SCANLINES\n"
"//#define MULTISAMPLE\n"
"//#define GAMMA\n"
"//#define FAKE_GAMMA\n"
"//#define CURVATURE\n"
"//#define SHARPER\n"
"// MASK_TYPE: 0 = none, 1 = green/magenta, 2 = trinitron(ish)\n"
"//#define MASK_TYPE 1\n"
"\n"
"\n"
"#ifdef GL_ES\n"
"#define COMPAT_PRECISION mediump\n"
"precision mediump float;\n"
"#else\n"
"#define COMPAT_PRECISION\n"
"#endif\n"
"\n"
"#ifdef PARAMETER_UNIFORM\n"
"uniform COMPAT_PRECISION float CURVATURE_X;\n"
"uniform COMPAT_PRECISION float CURVATURE_Y;\n"
"uniform COMPAT_PRECISION float MASK_BRIGHTNESS;\n"
"uniform COMPAT_PRECISION float SCANLINE_WEIGHT;\n"
"uniform COMPAT_PRECISION float SCANLINE_GAP_BRIGHTNESS;\n"
"uniform COMPAT_PRECISION float BLOOM_FACTOR;\n"
"uniform COMPAT_PRECISION float INPUT_GAMMA;\n"
"uniform COMPAT_PRECISION float OUTPUT_GAMMA;\n"
"#else\n"
"//#define CURVATURE_X 0.10\n"
"//#define CURVATURE_Y 0.25\n"
"//#define MASK_BRIGHTNESS 0.70\n"
"//#define SCANLINE_WEIGHT 6.0\n"
"//#define SCANLINE_GAP_BRIGHTNESS 0.12\n"
"//#define BLOOM_FACTOR 1.5\n"
"//#define INPUT_GAMMA 2.4\n"
"//#define OUTPUT_GAMMA 2.2\n"
"#endif\n"
"\n"
"/* COMPATIBILITY\n"
" - GLSL compilers\n"
"*/\n"
"\n"
"uniform vec2 TextureSize;\n"
"uniform vec2 TexelSize;\n"
"#if defined(CURVATURE)\n"
"varying vec2 screenScale;\n"
"#endif\n"
"varying vec2 TEX0;\n"
"varying float filterWidth;\n"
"\n"
"#if defined(VERTEX)\n"
"uniform mat4 MVPMatrix;\n"
"attribute vec4 VertexCoord;\n"
"attribute vec2 TexCoord;\n"
"uniform vec2 InputSize;\n"
"uniform vec2 OutputSize;\n"
"\n"
"void main()\n"
"{\n"
"#if defined(CURVATURE)\n"
" screenScale = TextureSize / InputSize;\n"
"#endif\n"
" filterWidth = (InputSize.y / OutputSize.y) / 3.0;\n"
" TEX0 = TexCoord;\n"
" gl_Position = MVPMatrix * VertexCoord;\n"
"}\n"
"#elif defined(FRAGMENT)\n"
"\n"
"uniform sampler2D Texture;\n"
"\n"
"#if defined(CURVATURE)\n"
"vec2 Distort(vec2 coord)\n"
"{\n"
" vec2 CURVATURE_DISTORTION = vec2(CURVATURE_X, CURVATURE_Y);\n"
" // Barrel distortion shrinks the display area a bit, this will allow us to counteract that.\n"
" vec2 barrelScale = 1.0 - (0.23 * CURVATURE_DISTORTION);\n"
" coord *= screenScale;\n"
" coord -= vec2(0.5);\n"
" float rsq = coord.x * coord.x + coord.y * coord.y;\n"
" coord += coord * (CURVATURE_DISTORTION * rsq);\n"
" coord *= barrelScale;\n"
" if (abs(coord.x) >= 0.5 || abs(coord.y) >= 0.5)\n"
" coord = vec2(-1.0); // If out of bounds, return an invalid value.\n"
" else\n"
" {\n"
" coord += vec2(0.5);\n"
" coord /= screenScale;\n"
" }\n"
"\n"
" return coord;\n"
"}\n"
"#endif\n"
"\n"
"float CalcScanLineWeight(float dist)\n"
"{\n"
" return max(1.0-dist*dist*SCANLINE_WEIGHT, SCANLINE_GAP_BRIGHTNESS);\n"
"}\n"
"\n"
"float CalcScanLine(float dy)\n"
"{\n"
" float scanLineWeight = CalcScanLineWeight(dy);\n"
"#if defined(MULTISAMPLE)\n"
" scanLineWeight += CalcScanLineWeight(dy-filterWidth);\n"
" scanLineWeight += CalcScanLineWeight(dy+filterWidth);\n"
" scanLineWeight *= 0.3333333;\n"
"#endif\n"
" return scanLineWeight;\n"
"}\n"
"\n"
"// Bi-linear interpolation\n"
"vec4 texture2DBL(in sampler2D t, in vec2 uv, in vec2 textureSize, in vec2 texelSize)\n"
"{\n"
" vec2 f = fract( uv * textureSize );\n"
" uv += ( .5 - f ) * texelSize; // move uv to texel centre\n"
" vec4 tl = texture2D(t, uv);\n"
" vec4 tr = texture2D(t, uv + vec2(texelSize.x, 0.0));\n"
" vec4 bl = texture2D(t, uv + vec2(0.0, texelSize.y));\n"
" vec4 br = texture2D(t, uv + vec2(texelSize.x, texelSize.y));\n"
" vec4 tA = mix( tl, tr, f.x );\n"
" vec4 tB = mix( bl, br, f.x );\n"
" return mix( tA, tB, f.y );\n"
"}\n"
"\n"
"void main()\n"
"{\n"
"#if defined(CURVATURE)\n"
" vec2 texcoord = Distort(TEX0);\n"
" if (texcoord.x < 0.0)\n"
" gl_FragColor = vec4(0.0);\n"
" else\n"
"#else\n"
" vec2 texcoord = TEX0;\n"
"#endif\n"
" {\n"
"\n"
"#if defined(BILINEAR_INTERPOLATION)\n"
" vec2 adj = vec2(0, .5);\n"
" vec2 texcoordInPixels = texcoord * TextureSize + adj;\n"
"#else\n"
" vec2 texcoordInPixels = texcoord * TextureSize;\n"
"#endif\n"
"\n"
"#if defined(SHARPER)\n"
" vec2 tempCoord = floor(texcoordInPixels) + 0.5;\n"
" vec2 coord = tempCoord / TextureSize;\n"
" vec2 deltas = texcoordInPixels - tempCoord;\n"
" float scanLineWeight = CalcScanLine(deltas.y);\n"
" vec2 signs = sign(deltas);\n"
" deltas.x *= 2.0;\n"
" deltas = deltas * deltas;\n"
" deltas.y = deltas.y * deltas.y;\n"
" deltas.x *= 0.5;\n"
" deltas.y *= 8.0;\n"
" deltas /= TextureSize;\n"
" deltas *= signs;\n"
" vec2 tc = coord + deltas;\n"
"#else\n"
" float tempY = floor(texcoordInPixels.y) + 0.5;\n"
" float yCoord = tempY / TextureSize.y;\n"
" float dy = texcoordInPixels.y - tempY;\n"
" float scanLineWeight = CalcScanLine(dy);\n"
" float signY = sign(dy);\n"
" dy = dy * dy;\n"
" dy = dy * dy;\n"
" dy *= 8.0;\n"
" dy /= TextureSize.y;\n"
" dy *= signY;\n"
" vec2 tc = vec2(texcoord.x, yCoord + dy);\n"
"#endif\n"
"\n"
"#if defined(BILINEAR_INTERPOLATION)\n"
" vec3 colour = texture2DBL(Texture, texcoord, TextureSize, TexelSize).rgb;\n"
"#else\n"
" vec3 colour = texture2D(Texture, tc).rgb;\n"
"#endif\n"
"\n"
"#if defined(SCANLINES)\n"
"#if defined(GAMMA)\n"
"#if defined(FAKE_GAMMA)\n"
" colour = colour * colour;\n"
"#else\n"
" colour = pow(colour, vec3(INPUT_GAMMA));\n"
"#endif\n"
"#endif\n"
" scanLineWeight *= BLOOM_FACTOR;\n"
" colour *= scanLineWeight;\n"
"\n"
"#if defined(GAMMA)\n"
"#if defined(FAKE_GAMMA)\n"
" colour = sqrt(colour);\n"
"#else\n"
" colour = pow(colour, vec3(1.0/OUTPUT_GAMMA));\n"
"#endif\n"
"#endif\n"
"#endif\n"
"#if MASK_TYPE == 0\n"
" gl_FragColor = vec4(colour, 1.0);\n"
"#else\n"
"#if MASK_TYPE == 1\n"
" float whichMask = fract(gl_FragCoord.x * 0.5);\n"
" vec3 mask;\n"
" if (whichMask < 0.5)\n"
" mask = vec3(MASK_BRIGHTNESS, 1.0, MASK_BRIGHTNESS);\n"
" else\n"
" mask = vec3(1.0, MASK_BRIGHTNESS, 1.0);\n"
"#elif MASK_TYPE == 2\n"
" float whichMask = fract(gl_FragCoord.x * 0.3333333);\n"
" vec3 mask = vec3(MASK_BRIGHTNESS, MASK_BRIGHTNESS, MASK_BRIGHTNESS);\n"
" if (whichMask < 0.3333333)\n"
" mask.x = 1.0;\n"
" else if (whichMask < 0.6666666)\n"
" mask.y = 1.0;\n"
" else\n"
" mask.z = 1.0;\n"
"#endif\n"
"\n"
" gl_FragColor = vec4(colour * mask, 1.0);\n"
"#endif\n"
" }\n"
"}\n"
"#endif\n";