Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /* COMPATIBILITY
- - HLSL compilers
- - Cg compilers
- */
- /*
- CRT shader
- Copyright (C) 2010, 2011 cgwg, Themaister and DOLLS
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the Free
- Software Foundation; either version 2 of the License, or (at your option)
- any later version.
- (cgwg gave their consent to have the original version of this shader
- distributed under the GPL in this message:
- http://board.byuu.org/viewtopic.php?p=26075#p26075
- "Feel free to distribute my shaders under the GPL. After all, the
- barrel distortion code was taken from the Curvature shader, which is
- under the GPL."
- )
- */
- struct tex_coords
- {
- float2 texCoord : TEXCOORD0;
- float mod_factor : TEXCOORD1;
- float2 one : TEXCOORD2;
- };
- struct input
- {
- float2 video_size;
- float2 texture_size;
- float2 output_size;
- float frame_count;
- float frame_direction;
- float frame_rotation;
- };
- /* Default Vertex shader */
- void main_vertex
- (
- float4 position : POSITION,
- out float4 oPosition : POSITION,
- uniform float4x4 modelViewProj,
- float4 color : COLOR,
- out float4 oColor : COLOR,
- float2 tex : TEXCOORD,
- uniform input IN,
- out tex_coords coords
- )
- {
- oPosition = mul(modelViewProj, position);
- oColor = color;
- coords.texCoord = tex + float2(0.0, 0.0);
- coords.mod_factor = tex.x * IN.output_size.x * IN.texture_size.x / IN.video_size.x;
- coords.one = 1.0 / IN.texture_size;
- }
- // Comment the next line to disable interpolation in linear gamma (and gain speed).
- #define LINEAR_PROCESSING
- // Compensate for 16-235 level range as per Rec. 601.
- // #define REF_LEVELS
- // Enable screen curvature.
- #define CURVATURE
- // Controls the intensity of the barrel distortion used to emulate the
- // curvature of a CRT. 0.0 is perfectly flat, 1.0 is annoyingly
- // distorted, higher values are increasingly ridiculous.
- #define distortion 0.1
- // Simulate a CRT gamma of 2.4.
- #define inputGamma 2.4
- // Compensate for the standard sRGB gamma of 2.2.
- #define outputGamma 2.2
- // Macros.
- #define FIX(c) max(abs(c), 1e-5);
- #define PI 3.141592653589
- #ifdef REF_LEVELS
- # define LEVELS(c) max((c - 16.0 / 255.0) * 255.0 / (235.0 - 16.0), 0.0)
- #else
- # define LEVELS(c) c
- #endif
- #ifdef LINEAR_PROCESSING
- # define TEX2D(c) pow(LEVELS(tex2D(s_p, (c))), float4(inputGamma, inputGamma, inputGamma, inputGamma))
- #else
- # define TEX2D(c) LEVELS(tex2D(s_p, (c)))
- #endif
- // Apply radial distortion to the given coordinate.
- float2 radialDistortion(float2 coord, input ruby) {
- coord *= ruby.texture_size.x / ruby.video_size.x;
- float2 cc = coord - 0.5;
- float dist = dot(cc, cc) * distortion;
- return (coord + cc * (1.0 + dist) * dist) * ruby.video_size.x / ruby.texture_size.x;
- }
- // Calculate the influence of a scanline on the current pixel.
- //
- // 'distance' is the distance in texture coordinates from the current
- // pixel to the scanline in question.
- // 'color' is the colour of the scanline at the horizontal location of
- // the current pixel.
- float4 scanlineWeights(float distance, float4 color)
- {
- // The "width" of the scanline beam is set as 2*(1 + x^4) for
- // each RGB channel.
- float4 wid = 2.0 + 2.0 * pow(color, float4(4.0, 4.0, 4.0, 4.0));
- // The "weights" lines basically specify the formula that gives
- // you the profile of the beam, i.e. the intensity as
- // a function of distance from the vertical center of the
- // scanline. In this case, it is gaussian if width=2, and
- // becomes nongaussian for larger widths. Ideally this should
- // be normalized so that the integral across the beam is
- // independent of its width. That is, for a narrower beam
- // "weights" should have a higher peak at the center of the
- // scanline than for a wider beam.
- float4 weights = float4(distance / 0.3, distance / 0.3, distance / 0.3, distance / 0.3);
- return 1.7 * exp(-pow(weights * rsqrt(0.5 * wid), wid)) / (0.6 + 0.2 * wid);
- }
- float4 main_fragment(in tex_coords co, uniform input IN, uniform sampler2D s_p : TEXUNIT0) : COLOR
- {
- // Here's a helpful diagram to keep in mind while trying to
- // understand the code:
- //
- // | | | | |
- // -------------------------------
- // | | | | |
- // | 01 | 11 | 21 | 31 | <-- current scanline
- // | | @ | | |
- // -------------------------------
- // | | | | |
- // | 02 | 12 | 22 | 32 | <-- next scanline
- // | | | | |
- // -------------------------------
- // | | | | |
- //
- // Each character-cell represents a pixel on the output
- // surface, "@" represents the current pixel (always somewhere
- // in the bottom half of the current scan-line, or the top-half
- // of the next scanline). The grid of lines represents the
- // edges of the texels of the underlying texture.
- // Texture coordinates of the texel containing the active pixel.
- #ifdef CURVATURE
- float2 xy = radialDistortion(co.texCoord, IN);
- #else
- float2 xy = co.texCoord;
- #endif
- // Of all the pixels that are mapped onto the texel we are
- // currently rendering, which pixel are we currently rendering?
- float2 ratio_scale = xy * IN.texture_size - float2(0.5, 0.5);
- float2 uv_ratio = frac(ratio_scale);
- // Snap to the center of the underlying texel.
- xy = (floor(ratio_scale) + float2(0.5, 0.5)) / IN.texture_size;
- // Calculate Lanczos scaling coefficients describing the effect
- // of various neighbour texels in a scanline on the current
- // pixel.
- float4 coeffs = PI * float4(1.0 + uv_ratio.x, uv_ratio.x, 1.0 - uv_ratio.x, 2.0 - uv_ratio.x);
- // Prevent division by zero.
- coeffs = FIX(coeffs);
- // Lanczos2 kernel.
- coeffs = 2.0 * sin(coeffs) * sin(coeffs / 2.0) / (coeffs * coeffs);
- // Normalize.
- coeffs /= dot(coeffs, float4(1.0, 1.0, 1.0, 1.0));
- // Calculate the effective colour of the current and next
- // scanlines at the horizontal location of the current pixel,
- // using the Lanczos coefficients above.
- float4 col = clamp(mul(coeffs, float4x4(
- TEX2D(xy + float2(-co.one.x, 0.0)),
- TEX2D(xy),
- TEX2D(xy + float2(co.one.x, 0.0)),
- TEX2D(xy + float2(2.0 * co.one.x, 0.0)))),
- 0.0, 1.0);
- float4 col2 = clamp(mul(coeffs, float4x4(
- TEX2D(xy + float2(-co.one.x, co.one.y)),
- TEX2D(xy + float2(0.0, co.one.y)),
- TEX2D(xy + co.one),
- TEX2D(xy + float2(2.0 * co.one.x, co.one.y)))),
- 0.0, 1.0);
- #ifndef LINEAR_PROCESSING
- col = pow(col , float4(inputGamma, inputGamma, inputGamma, inputGamma));
- col2 = pow(col2, float4(inputGamma, inputGamma, inputGamma, inputGamma));
- #endif
- // Calculate the influence of the current and next scanlines on
- // the current pixel.
- float4 weights = scanlineWeights(uv_ratio.y, col);
- float4 weights2 = scanlineWeights(1.0 - uv_ratio.y, col2);
- float3 mul_res = (col * weights + col2 * weights2).rgb;
- // dot-mask emulation:
- // Output pixels are alternately tinted green and magenta.
- float3 dotMaskWeights = lerp(
- float3(1.0, 0.7, 1.0),
- float3(0.7, 1.0, 0.7),
- floor(fmod(co.mod_factor, 2.0))
- );
- mul_res *= dotMaskWeights;
- // Convert the image gamma for display on our output device.
- mul_res = pow(mul_res, float3(1.0 / outputGamma, 1.0 / outputGamma, 1.0 / outputGamma));
- return float4(mul_res, 1.0);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement