#define COLOR_LOW 0.7 #define COLOR_HIGH 1.0 #define VERTICAL_BORDER_DEPTH 0.6 #define SCANLINE_DEPTH 0.3 #define CURVENESS 0.3 STATIC vec4 scale(sampler2D image, vec2 position, vec2 input_resolution, vec2 output_resolution) { /* Curve and pixel ratio */ float y_curve = cos(position.x - 0.5) * CURVENESS + (1.0 - CURVENESS); float y_multiplier = 8.0 / 7.0 / y_curve; position.y *= y_multiplier; position.y -= (y_multiplier - 1.0) / 2.0; if (position.y < 0.0) return vec4(0,0,0,0); if (position.y > 1.0) return vec4(0,0,0,0); float x_curve = cos(position.y - 0.5) * CURVENESS + (1.0 - CURVENESS); float x_multiplier = 1.0 / x_curve; position.x *= x_multiplier; position.x -= (x_multiplier - 1.0) / 2.0; if (position.x < 0.0) return vec4(0.0, 0.0, 0.0, 0.0); if (position.x > 1.0) return vec4(0.0, 0.0, 0.0, 0.0); /* Setting up common vars */ vec2 pos = fract(position * input_resolution); vec2 sub_pos = fract(position * input_resolution * 6.0); vec4 center = texture(image, position); vec4 left = texture(image, position - vec2(1.0 / input_resolution.x, 0.0)); vec4 right = texture(image, position + vec2(1.0 / input_resolution.x, 0.0)); /* Vertical blurring */ if (pos.y < 1.0 / 6.0) { center = mix(center, texture(image, position + vec2(0.0, -1.0 / input_resolution.y)), 0.5 - sub_pos.y / 2.0); left = mix(left, texture(image, position + vec2(-1.0 / input_resolution.x, -1.0 / input_resolution.y)), 0.5 - sub_pos.y / 2.0); right = mix(right, texture(image, position + vec2( 1.0 / input_resolution.x, -1.0 / input_resolution.y)), 0.5 - sub_pos.y / 2.0); } else if (pos.y > 5.0 / 6.0) { center = mix(center, texture(image, position + vec2(0.0, 1.0 / input_resolution.y)), sub_pos.y / 2.0); left = mix(left, texture(image, position + vec2(-1.0 / input_resolution.x, 1.0 / input_resolution.y)), sub_pos.y / 2.0); right = mix(right, texture(image, position + vec2( 1.0 / input_resolution.x, 1.0 / input_resolution.y)), sub_pos.y / 2.0); } /* Scanlines */ float scanline_multiplier; if (pos.y < 0.5) { scanline_multiplier = (pos.y * 2.0) * SCANLINE_DEPTH + (1.0 - SCANLINE_DEPTH); } else { scanline_multiplier = ((1.0 - pos.y) * 2.0) * SCANLINE_DEPTH + (1.0 - SCANLINE_DEPTH); } center *= scanline_multiplier; left *= scanline_multiplier; right *= scanline_multiplier; /* Vertical seperator for shadow masks */ bool odd = bool(int((position * input_resolution).x) >= 1); if (odd) { pos.y += 0.5; pos.y = fract(pos.y); } if (pos.y < 1.0 / 3.0) { float gradient_position = pos.y * 3.0; center *= gradient_position * VERTICAL_BORDER_DEPTH + (1.0 - VERTICAL_BORDER_DEPTH); left *= gradient_position * VERTICAL_BORDER_DEPTH + (1.0 - VERTICAL_BORDER_DEPTH); right *= gradient_position * VERTICAL_BORDER_DEPTH + (1.0 - VERTICAL_BORDER_DEPTH); } else if (pos.y > 2.0 / 3.0) { float gradient_position = (1.0 - pos.y) * 3.0; center *= gradient_position * VERTICAL_BORDER_DEPTH + (1.0 - VERTICAL_BORDER_DEPTH); left *= gradient_position * VERTICAL_BORDER_DEPTH + (1.0 - VERTICAL_BORDER_DEPTH); right *= gradient_position * VERTICAL_BORDER_DEPTH + (1.0 - VERTICAL_BORDER_DEPTH); } /* Blur the edges of the separators of adjacent columns */ if (pos.x < 1.0 / 6.0 || pos.x > 5.0 / 6.0) { pos.y += 0.5; pos.y = fract(pos.y); if (pos.y < 1.0 / 3.0) { float gradient_position = pos.y * 3.0; if (pos.x < 0.5) { gradient_position = 1.0 - (1.0 - gradient_position) * (1.0 - (pos.x) * 6.0); } else { gradient_position = 1.0 - (1.0 - gradient_position) * (1.0 - (1.0 - pos.x) * 6.0); } center *= gradient_position * VERTICAL_BORDER_DEPTH + (1.0 - VERTICAL_BORDER_DEPTH); left *= gradient_position * VERTICAL_BORDER_DEPTH + (1.0 - VERTICAL_BORDER_DEPTH); right *= gradient_position * VERTICAL_BORDER_DEPTH + (1.0 - VERTICAL_BORDER_DEPTH); } else if (pos.y > 2.0 / 3.0) { float gradient_position = (1.0 - pos.y) * 3.0; if (pos.x < 0.5) { gradient_position = 1.0 - (1.0 - gradient_position) * (1.0 - (pos.x) * 6.0); } else { gradient_position = 1.0 - (1.0 - gradient_position) * (1.0 - (1.0 - pos.x) * 6.0); } center *= gradient_position * VERTICAL_BORDER_DEPTH + (1.0 - VERTICAL_BORDER_DEPTH); left *= gradient_position * VERTICAL_BORDER_DEPTH + (1.0 - VERTICAL_BORDER_DEPTH); right *= gradient_position * VERTICAL_BORDER_DEPTH + (1.0 - VERTICAL_BORDER_DEPTH); } } /* Subpixel blurring, like LCD filter*/ vec4 midleft = mix(left, center, 0.5); vec4 midright = mix(right, center, 0.5); vec4 ret; if (pos.x < 1.0 / 6.0) { ret = mix(vec4(COLOR_HIGH * center.r, COLOR_LOW * center.g, COLOR_HIGH * left.b, 1.0), vec4(COLOR_HIGH * center.r, COLOR_LOW * center.g, COLOR_LOW * left.b, 1.0), sub_pos.x); } else if (pos.x < 2.0 / 6.0) { ret = mix(vec4(COLOR_HIGH * center.r, COLOR_LOW * center.g, COLOR_LOW * left.b, 1.0), vec4(COLOR_HIGH * center.r, COLOR_HIGH * center.g, COLOR_LOW * midleft.b, 1.0), sub_pos.x); } else if (pos.x < 3.0 / 6.0) { ret = mix(vec4(COLOR_HIGH * center.r , COLOR_HIGH * center.g, COLOR_LOW * midleft.b, 1.0), vec4(COLOR_LOW * midright.r, COLOR_HIGH * center.g, COLOR_LOW * center.b, 1.0), sub_pos.x); } else if (pos.x < 4.0 / 6.0) { ret = mix(vec4(COLOR_LOW * midright.r, COLOR_HIGH * center.g , COLOR_LOW * center.b, 1.0), vec4(COLOR_LOW * right.r , COLOR_HIGH * center.g, COLOR_HIGH * center.b, 1.0), sub_pos.x); } else if (pos.x < 5.0 / 6.0) { ret = mix(vec4(COLOR_LOW * right.r, COLOR_HIGH * center.g , COLOR_HIGH * center.b, 1.0), vec4(COLOR_LOW * right.r, COLOR_LOW * midright.g, COLOR_HIGH * center.b, 1.0), sub_pos.x); } else { ret = mix(vec4(COLOR_LOW * right.r, COLOR_LOW * midright.g, COLOR_HIGH * center.b, 1.0), vec4(COLOR_HIGH * right.r, COLOR_LOW * right.g , COLOR_HIGH * center.b, 1.0), sub_pos.x); } /* Anti alias the curve */ vec2 pixel_position = position * output_resolution; if (pixel_position.x < 1.0) { ret *= pixel_position.x; } else if (pixel_position.x > output_resolution.x - 1.0) { ret *= output_resolution.x - pixel_position.x; } if (pixel_position.y < 1.0) { ret *= pixel_position.y; } else if (pixel_position.y > output_resolution.y - 1.0) { ret *= output_resolution.y - pixel_position.y; } // Gamma correction ret = pow(ret, vec4(0.72)); return ret; }