Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/dosbox-staging/dosbox-staging.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatryk Obara <dreamer.tan@gmail.com>2020-03-20 23:25:29 +0300
committerPatryk Obara <dreamer.tan@gmail.com>2020-03-20 23:25:32 +0300
commit94ff5dea559e81a8f8b859b928341e3e28fcfb94 (patch)
treeb34c43c468208aa45585faa4c2bece068e0b0925
parent694e6f6cb11106b5b0bb3da11039613d9bf1882e (diff)
WIP shaderspo/glshaders
Imported-from: https://www.vogons.org/viewtopic.php?p=835314#p835314
-rw-r--r--contrib/glshaders/crt-easy.glsl138
-rw-r--r--contrib/glshaders/crt-lottes.glsl234
-rw-r--r--contrib/glshaders/scanline.glsl48
3 files changed, 420 insertions, 0 deletions
diff --git a/contrib/glshaders/crt-easy.glsl b/contrib/glshaders/crt-easy.glsl
new file mode 100644
index 000000000..0c9712c76
--- /dev/null
+++ b/contrib/glshaders/crt-easy.glsl
@@ -0,0 +1,138 @@
+#version 330 core
+
+varying vec2 v_texCoord;
+uniform vec2 rubyTextureSize;
+uniform vec2 rubyInputSize;
+uniform vec2 rubyOutputSize;
+
+#if defined(VERTEX)
+
+attribute vec4 a_position;
+
+void main()
+
+{
+ gl_Position = a_position;
+ v_texCoord = vec2(a_position.x+1.0,1.0-a_position.y)/2.0*rubyInputSize/rubyTextureSize;
+}
+
+#elif defined(FRAGMENT)
+
+uniform sampler2D rubyTexture;
+
+#define BRIGHT_BOOST 1.25
+#define DILATION 1.0
+#define GAMMA_INPUT 2.0
+#define GAMMA_OUTPUT 1.8
+#define MASK_SIZE 1.0
+#define MASK_STAGGER 0.0
+#define MASK_STRENGTH 0.425
+#define MASK_DOT_HEIGHT 1.0
+#define MASK_DOT_WIDTH 1.0
+#define SCANLINE_BEAM_WIDTH_MAX 1.5
+#define SCANLINE_BEAM_WIDTH_MIN 1.5
+#define SCANLINE_BRIGHT_MAX 0.65
+#define SCANLINE_BRIGHT_MIN 0.35
+#define SCANLINE_CUTOFF 400.0
+#define SCANLINE_STRENGTH 1.0
+#define SHARPNESS_H 0.55
+#define SHARPNESS_V 0.55
+#define FIX(c) max(abs(c), 1e-5)
+#define PI 3.141592653589
+#define TEX2D(c) dilate(texture(tex, c))
+
+// Set to 0 to use linear filter and gain speed
+
+#define ENABLE_LANCZOS 1
+
+vec4 dilate(vec4 col)
+{
+ vec4 x = mix(vec4(1.0), col, DILATION);
+ return col * x;
+}
+
+float curve_distance(float x, float sharp)
+{
+/*
+ apply half-circle s-curve to distance for sharper (more pixelated) interpolation
+ single line formula for Graph Toy:
+ 0.5 - sqrt(0.25 - (x - step(0.5, x)) * (x - step(0.5, x))) * sign(0.5 - x)
+*/
+
+ float x_step = step(0.5, x);
+ float curve = 0.5 - sqrt(0.25 - (x - x_step) * (x - x_step)) * sign(0.5 - x);
+ return mix(x, curve, sharp);
+}
+
+
+mat4 get_color_matrix(sampler2D tex, vec2 co, vec2 dx)
+{
+ return mat4(TEX2D(co - dx), TEX2D(co), TEX2D(co + dx), TEX2D(co + 2.0 * dx));
+}
+
+vec3 filter_lanczos(vec4 coeffs, mat4 color_matrix)
+{
+ vec4 col = color_matrix * coeffs;
+ vec4 sample_min = min(color_matrix[1], color_matrix[2]);
+ vec4 sample_max = max(color_matrix[1], color_matrix[2]);
+ col = clamp(col, sample_min, sample_max);
+ return col.rgb;
+}
+
+out vec4 color;
+
+void main()
+{
+ vec2 dx = vec2(1.0 / rubyTextureSize.x, 0.0);
+ vec2 dy = vec2(0.0, 1.0 / rubyTextureSize.y);
+ vec2 pix_co = v_texCoord * rubyTextureSize - vec2(0.5, 0.5);
+ vec2 tex_co = (floor(pix_co) + vec2(0.5, 0.5)) / rubyTextureSize;
+ vec2 dist = fract(pix_co);
+
+ float curve_x;
+ vec3 col, col2;
+
+#if ENABLE_LANCZOS
+
+ curve_x = curve_distance(dist.x, SHARPNESS_H * SHARPNESS_H);
+ vec4 coeffs = PI * vec4(1.0 + curve_x, curve_x, 1.0 - curve_x, 2.0 - curve_x);
+ coeffs = FIX(coeffs);
+ coeffs = 2.0 * sin(coeffs) * sin(coeffs / 2.0) / (coeffs * coeffs);
+ coeffs /= dot(coeffs, vec4(1.0));
+ col = filter_lanczos(coeffs, get_color_matrix(rubyTexture, tex_co, dx));
+ col2 = filter_lanczos(coeffs, get_color_matrix(rubyTexture, tex_co + dy, dx));
+
+#else
+
+ curve_x = curve_distance(dist.x, SHARPNESS_H);
+ col = mix(TEX2D(tex_co).rgb, TEX2D(tex_co + dx).rgb, curve_x);
+ col2 = mix(TEX2D(tex_co + dy).rgb, TEX2D(tex_co + dx + dy).rgb, curve_x);
+
+#endif
+
+ col = mix(col, col2, curve_distance(dist.y, SHARPNESS_V));
+ col = pow(col, vec3(GAMMA_INPUT / (DILATION + 1.0)));
+ float luma = dot(vec3(0.2126, 0.7152, 0.0722), col);
+ float bright = (max(col.r, max(col.g, col.b)) + luma) / 2.0;
+ float scan_bright = clamp(bright, SCANLINE_BRIGHT_MIN, SCANLINE_BRIGHT_MAX);
+ float scan_beam = clamp(bright * SCANLINE_BEAM_WIDTH_MAX, SCANLINE_BEAM_WIDTH_MIN, SCANLINE_BEAM_WIDTH_MAX);
+ float scan_weight = 1.0 - pow(cos(v_texCoord.y * 2.0 * PI * rubyTextureSize.y) * 0.5 + 0.5, scan_beam) * SCANLINE_STRENGTH;
+ float mask = 1.0 - MASK_STRENGTH;
+ vec2 mod_fac = floor(v_texCoord * rubyOutputSize * rubyTextureSize / (rubyInputSize * vec2(MASK_SIZE, MASK_DOT_HEIGHT * MASK_SIZE)));
+ int dot_no = int(mod((mod_fac.x + mod(mod_fac.y, 2.0) * MASK_STAGGER) / MASK_DOT_WIDTH, 3.0));
+ vec3 mask_weight;
+
+ if (dot_no == 0) mask_weight = vec3(1.0, mask, mask);
+ else if (dot_no == 1) mask_weight = vec3(mask, 1.0, mask);
+ else mask_weight = vec3(mask, mask, 1.0);
+
+ if (rubyInputSize.y >= SCANLINE_CUTOFF) scan_weight = 1.0;
+ col2 = col.rgb;
+ col *= vec3(scan_weight);
+ col = mix(col, col2, scan_bright);
+ col *= mask_weight;
+ col = pow(col, vec3(1.0 / GAMMA_OUTPUT));
+ color = vec4(col * BRIGHT_BOOST, 1.0);
+}
+
+#endif
diff --git a/contrib/glshaders/crt-lottes.glsl b/contrib/glshaders/crt-lottes.glsl
new file mode 100644
index 000000000..00f74c51b
--- /dev/null
+++ b/contrib/glshaders/crt-lottes.glsl
@@ -0,0 +1,234 @@
+#version 330 core
+
+varying vec2 v_texCoord;
+uniform vec2 rubyTextureSize;
+uniform vec2 rubyInputSize;
+uniform vec2 rubyOutputSize;
+
+#if defined(VERTEX)
+
+attribute vec4 a_position;
+
+void main()
+{
+ gl_Position = a_position;
+ v_texCoord = vec2(a_position.x+1.0,1.0-a_position.y)/2.0*rubyInputSize/rubyTextureSize;
+}
+
+#elif defined(FRAGMENT)
+
+uniform sampler2D rubyTexture;
+
+const float hardScan = -8.0;
+const float hardPix = -3.0;
+const float warpX = 0.0075;
+const float warpY = 0.0075;
+const float maskDark = 0.5;
+const float maskLight = 1.5;
+const float scaleInLinearGamma = 1;
+const float shadowMask = 1;
+const float brightBoost = 1.4;
+
+#define Blackmask 1
+
+out vec4 color;
+
+//------------------------------------------------------------------------
+
+// sRGB to Linear.
+// Assuing using sRGB typed textures this should not be needed.
+float ToLinear1(float c)
+{
+ if (scaleInLinearGamma == 0)
+ {
+ return c;
+ }
+ return (c <= 0.04045) ? c / 12.92 : pow((c + 0.055) / 1.055, 2.4);
+}
+
+vec3 ToLinear(vec3 c)
+{
+ if (scaleInLinearGamma == 0)
+ {
+
+ return c;
+ }
+ return vec3(ToLinear1(c.r), ToLinear1(c.g), ToLinear1(c.b));
+}
+
+// Linear to sRGB.
+// Assuing using sRGB typed textures this should not be needed.
+float ToSrgb1(float c)
+{
+ if (scaleInLinearGamma == 0)
+ {
+ return c;
+ }
+ return(c < 0.0031308 ? c *12.92 : 1.055 * pow(c, 0.41666) - 0.055);
+}
+
+vec3 ToSrgb(vec3 c)
+{
+ if (scaleInLinearGamma == 0)
+ {
+ return c;
+ }
+ return vec3(ToSrgb1(c.r), ToSrgb1(c.g), ToSrgb1(c.b));
+}
+
+// Nearest emulated sample given floating point position and texel offset.
+// Also zero's off screen.
+vec3 Fetch(vec2 pos,vec2 off)
+{
+ pos = (floor(pos * rubyTextureSize.xy + off) + vec2(0.5, 0.5)) / rubyTextureSize.xy;
+ return ToLinear(brightBoost * texture(rubyTexture, pos.xy).rgb);
+}
+
+// Distance in emulated pixels to nearest texel.
+vec2 Dist(vec2 pos)
+{
+ pos = pos * rubyTextureSize.xy;
+ return -((pos - floor(pos)) - vec2(0.5));
+}
+
+// 1D Gaussian.
+float Gaus(float pos, float scale)
+{
+ return exp2(scale * pos * pos);
+}
+
+// 3-tap Gaussian filter along horz line.
+vec3 Horz3(vec2 pos, float off)
+{
+ vec3 b = Fetch(pos, vec2(-1.0, off));
+ vec3 c = Fetch(pos, vec2(0.0, off));
+ vec3 d = Fetch(pos, vec2(1.0, off));
+ float dst = Dist(pos).x;
+ // Convert distance to weight.
+ float scale = hardPix;
+ float wb = Gaus(dst - 1.0, scale);
+ float wc = Gaus(dst + 0.0, scale);
+ float wd = Gaus(dst + 1.0, scale);
+ // Return filtered sample.
+ return (b * wb + c * wc + d * wd) / (wb + wc + wd);
+}
+
+// 5-tap Gaussian filter along horz line.
+vec3 Horz5(vec2 pos, float off)
+{
+ vec3 a = Fetch(pos, vec2(-2.0, off));
+ vec3 b = Fetch(pos, vec2(-1.0, off));
+ vec3 c = Fetch(pos, vec2(0.0, off));
+ vec3 d = Fetch(pos, vec2(1.0, off));
+ vec3 e = Fetch(pos, vec2(2.0, off));
+ float dst = Dist(pos).x;
+ // Convert distance to weight.
+ float scale = hardPix;
+ float wa = Gaus(dst - 2.0, scale);
+ float wb = Gaus(dst - 1.0, scale);
+ float wc = Gaus(dst + 0.0, scale);
+ float wd = Gaus(dst + 1.0, scale);
+ float we = Gaus(dst + 2.0, scale);
+ // Return filtered sample.
+ return (a * wa + b * wb + c * wc + d * wd + e * we) / (wa + wb + wc + wd + we);
+}
+
+// Return scanline weight.
+float Scan(vec2 pos, float off)
+{
+ float dst = Dist(pos).y;
+ return Gaus(dst + off, hardScan);
+}
+
+// Allow nearest three lines to effect pixel.
+vec3 Tri(vec2 pos)
+{
+ vec3 a = Horz3(pos, -1.0);
+ vec3 b = Horz5(pos, 0.0);
+ vec3 c = Horz3(pos, 1.0);
+ float wa = Scan(pos, -1.0);
+ float wb = Scan(pos, 0.0);
+ float wc = Scan(pos, 1.0);
+ return a * wa + b * wb + c * wc;
+}
+
+// Distortion of scanlines, and end of screen alpha.
+vec2 Warp(vec2 pos)
+{
+ pos = pos * 2.0 -1.0;
+ pos *= vec2(1.0 + (pos.y * pos.y) * warpX, 1.0 + (pos.x * pos.x) * warpY);
+ return pos * 0.5 + 0.5;
+}
+
+// Shadow mask.
+vec3 Mask(vec2 pos)
+{
+ pos.x += pos.y * 3.0;
+ vec3 mask = vec3(maskDark, maskDark, maskDark);
+ pos.x = fract(pos.x / 6.0);
+ if (pos.x < 0.333)
+ {
+ mask.r = maskLight;
+ }
+ else if (pos.x < 0.666)
+ {
+ mask.g = maskLight;
+ }
+ else
+ {
+ mask.b = maskLight;
+ }
+ return mask;
+}
+
+uniform vec2 resolution;
+uniform vec2 mouse;
+uniform float time;
+
+float box(vec2 _st, vec2 _size, float _smoothEdges) {
+ _size = vec2(.1) - _size*.2;
+ vec2 aa = vec2(_smoothEdges * 0.1);
+ vec2 uv = smoothstep(_size, _size+aa, _st);
+ uv *= smoothstep(_size, _size+aa, vec2(1.0)-_st);
+ return uv.x * uv.y;
+}
+
+vec3 drawRectangle(in vec2 st) {
+ // Each result will return 1.0 (white) or 0.0 (
+ vec3 color = vec3(0.0);
+ vec2 borders = step(vec2(0.0),st);
+ float pct = borders.x * borders.y;
+
+ // top-right
+ vec2 tr = step(vec2(0.1),1.0-st);
+ pct *= tr.x * tr.y;
+
+ // The multiplication of left*bottom will be similar to the logical AND.
+ color = vec3(pct);
+ return color;
+}
+
+void main()
+{
+ vec2 pos = Warp(v_texCoord.xy * (rubyTextureSize.xy / rubyInputSize.xy)) * (rubyInputSize.xy / rubyTextureSize.xy);
+
+
+#ifdef Blackmask
+ vec3 outColor = vec3(1.0);
+ outColor *= Tri(pos);
+ outColor *= drawRectangle(pos);
+ outColor *= vec3(box(pos, vec2(0.5), 0.01));
+#else
+ vec3 outColor = Tri(pos);
+#endif
+
+
+ if (shadowMask != 0)
+ {
+ outColor.rgb *= Mask(floor(v_texCoord.xy * (rubyTextureSize.xy / rubyInputSize.xy) * rubyOutputSize.xy) + vec2(0.5, 0.5));
+ }
+
+ color = vec4(ToSrgb(outColor.rgb), 1.0);
+}
+
+#endif
diff --git a/contrib/glshaders/scanline.glsl b/contrib/glshaders/scanline.glsl
new file mode 100644
index 000000000..b9f5bbc24
--- /dev/null
+++ b/contrib/glshaders/scanline.glsl
@@ -0,0 +1,48 @@
+#version 330 core
+
+varying vec2 v_texCoord;
+uniform vec2 rubyTextureSize;
+uniform vec2 rubyInputSize;
+uniform vec2 rubyOutputSize;
+
+#if defined(VERTEX)
+
+attribute vec4 a_position;
+
+out sine_coord
+{
+ vec2 omega;
+} coords;
+
+
+void main()
+{
+ gl_Position = a_position;
+ v_texCoord = vec2(a_position.x+1.0,1.0-a_position.y)/2.0*rubyInputSize/rubyTextureSize;
+ coords.omega = vec2(3.1415 * rubyOutputSize.x * rubyTextureSize.x / rubyInputSize.x, 2.0 * 3.1415 * rubyTextureSize.y);
+}
+
+#elif defined(FRAGMENT)
+
+const float SCANLINE_BASE_BRIGHTNESS = 0.95;
+const float SCANLINE_SINE_COMP_A = 0.05;
+const float SCANLINE_SINE_COMP_B = 0.15;
+
+uniform sampler2D rubyTexture;
+
+in sine_coord
+{
+ vec2 omega;
+} coords;
+
+out vec4 color;
+
+void main()
+{
+ vec2 sine_comp = vec2(SCANLINE_SINE_COMP_A, SCANLINE_SINE_COMP_B);
+ vec3 res = texture(rubyTexture, v_texCoord).xyz;
+ vec3 scanline = res * (SCANLINE_BASE_BRIGHTNESS + dot(sine_comp * sin(v_texCoord * coords.omega), vec2(1.0, 1.0)));
+ color = vec4(scanline.x, scanline.y, scanline.z, 1.0);
+}
+
+#endif