Advertisement
Guest User

crt-cgwg-curved

a guest
Aug 4th, 2013
303
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 7.42 KB | None | 0 0
  1. /* COMPATIBILITY
  2.    - HLSL compilers
  3.    - Cg   compilers
  4. */
  5.  
  6. /*
  7.     CRT shader
  8.  
  9.     Copyright (C) 2010, 2011 cgwg, Themaister and DOLLS
  10.  
  11.     This program is free software; you can redistribute it and/or modify it
  12.     under the terms of the GNU General Public License as published by the Free
  13.     Software Foundation; either version 2 of the License, or (at your option)
  14.     any later version.
  15.  
  16.     (cgwg gave their consent to have the original version of this shader
  17.     distributed under the GPL in this message:
  18.  
  19.         http://board.byuu.org/viewtopic.php?p=26075#p26075
  20.  
  21.         "Feel free to distribute my shaders under the GPL. After all, the
  22.         barrel distortion code was taken from the Curvature shader, which is
  23.         under the GPL."
  24.     )
  25. */
  26.  
  27.  
  28. struct tex_coords
  29. {
  30.    float2 texCoord  : TEXCOORD0;
  31.    float mod_factor : TEXCOORD1;
  32.    float2 one       : TEXCOORD2;
  33. };
  34.  
  35. struct input
  36. {
  37.   float2 video_size;
  38.   float2 texture_size;
  39.   float2 output_size;
  40.   float  frame_count;
  41.   float  frame_direction;
  42.   float frame_rotation;
  43. };
  44.  
  45. /* Default Vertex shader */
  46. void main_vertex
  47. (
  48.    float4 position : POSITION,
  49.    out float4 oPosition : POSITION,
  50.    uniform float4x4 modelViewProj,
  51.  
  52.    float4 color : COLOR,
  53.    out float4 oColor : COLOR,
  54.  
  55.    float2 tex : TEXCOORD,
  56.  
  57.    uniform input IN,
  58.    out tex_coords coords
  59.  )
  60. {
  61.    oPosition = mul(modelViewProj, position);
  62.    oColor = color;
  63.  
  64.    coords.texCoord = tex + float2(0.0, 0.0);
  65.    coords.mod_factor = tex.x * IN.output_size.x * IN.texture_size.x / IN.video_size.x;
  66.    coords.one = 1.0 / IN.texture_size;
  67. }
  68.  
  69.  
  70. // Comment the next line to disable interpolation in linear gamma (and gain speed).
  71. #define LINEAR_PROCESSING
  72.  
  73. // Compensate for 16-235 level range as per Rec. 601.
  74. // #define REF_LEVELS
  75.        
  76. // Enable screen curvature.
  77. #define CURVATURE
  78.        
  79. // Controls the intensity of the barrel distortion used to emulate the
  80. // curvature of a CRT. 0.0 is perfectly flat, 1.0 is annoyingly
  81. // distorted, higher values are increasingly ridiculous.
  82. #define distortion 0.1
  83.  
  84. // Simulate a CRT gamma of 2.4.
  85. #define inputGamma  2.4
  86.  
  87. // Compensate for the standard sRGB gamma of 2.2.
  88. #define outputGamma 2.2
  89.  
  90. // Macros.
  91. #define FIX(c) max(abs(c), 1e-5);
  92. #define PI 3.141592653589
  93.  
  94. #ifdef REF_LEVELS
  95. #       define LEVELS(c) max((c - 16.0 / 255.0) * 255.0 / (235.0 - 16.0), 0.0)
  96. #else
  97. #       define LEVELS(c) c
  98. #endif
  99.  
  100. #ifdef LINEAR_PROCESSING
  101. #       define TEX2D(c) pow(LEVELS(tex2D(s_p, (c))), float4(inputGamma, inputGamma, inputGamma, inputGamma))
  102. #else
  103. #       define TEX2D(c) LEVELS(tex2D(s_p, (c)))
  104. #endif
  105.  
  106. // Apply radial distortion to the given coordinate.
  107. float2 radialDistortion(float2 coord, input ruby) {
  108.     coord *= ruby.texture_size.x / ruby.video_size.x;
  109.     float2 cc = coord - 0.5;
  110.     float dist = dot(cc, cc) * distortion;             
  111.     return (coord + cc * (1.0 + dist) * dist) * ruby.video_size.x / ruby.texture_size.x;
  112. }
  113.  
  114. // Calculate the influence of a scanline on the current pixel.
  115. //
  116. // 'distance' is the distance in texture coordinates from the current
  117. // pixel to the scanline in question.
  118. // 'color' is the colour of the scanline at the horizontal location of
  119. // the current pixel.
  120. float4 scanlineWeights(float distance, float4 color)
  121. {
  122.     // The "width" of the scanline beam is set as 2*(1 + x^4) for
  123.     // each RGB channel.
  124.     float4 wid = 2.0 + 2.0 * pow(color, float4(4.0, 4.0, 4.0, 4.0));
  125.  
  126.     // The "weights" lines basically specify the formula that gives
  127.     // you the profile of the beam, i.e. the intensity as
  128.     // a function of distance from the vertical center of the
  129.     // scanline. In this case, it is gaussian if width=2, and
  130.     // becomes nongaussian for larger widths. Ideally this should
  131.     // be normalized so that the integral across the beam is
  132.     // independent of its width. That is, for a narrower beam
  133.     // "weights" should have a higher peak at the center of the
  134.     // scanline than for a wider beam.
  135.     float4 weights = float4(distance / 0.3, distance / 0.3, distance / 0.3, distance / 0.3);
  136.     return 1.7 * exp(-pow(weights * rsqrt(0.5 * wid), wid)) / (0.6 + 0.2 * wid);
  137. }
  138.  
  139.  
  140. float4 main_fragment(in tex_coords co, uniform input IN, uniform sampler2D s_p : TEXUNIT0) : COLOR
  141. {
  142.     // Here's a helpful diagram to keep in mind while trying to
  143.     // understand the code:
  144.     //
  145.     //  |      |      |      |      |
  146.     // -------------------------------
  147.     //  |      |      |      |      |
  148.     //  |  01  |  11  |  21  |  31  | <-- current scanline
  149.     //  |      | @    |      |      |
  150.     // -------------------------------
  151.     //  |      |      |      |      |
  152.     //  |  02  |  12  |  22  |  32  | <-- next scanline
  153.     //  |      |      |      |      |
  154.     // -------------------------------
  155.     //  |      |      |      |      |
  156.     //
  157.     // Each character-cell represents a pixel on the output
  158.     // surface, "@" represents the current pixel (always somewhere
  159.     // in the bottom half of the current scan-line, or the top-half
  160.     // of the next scanline). The grid of lines represents the
  161.     // edges of the texels of the underlying texture.
  162.  
  163.     // Texture coordinates of the texel containing the active pixel.
  164. #ifdef CURVATURE
  165.     float2 xy = radialDistortion(co.texCoord, IN);
  166. #else
  167.     float2 xy = co.texCoord;
  168. #endif
  169.  
  170.     // Of all the pixels that are mapped onto the texel we are
  171.     // currently rendering, which pixel are we currently rendering?
  172.     float2 ratio_scale = xy * IN.texture_size - float2(0.5, 0.5);
  173.     float2 uv_ratio = frac(ratio_scale);
  174.  
  175.     // Snap to the center of the underlying texel.
  176.     xy = (floor(ratio_scale) + float2(0.5, 0.5)) / IN.texture_size;
  177.  
  178.     // Calculate Lanczos scaling coefficients describing the effect
  179.     // of various neighbour texels in a scanline on the current
  180.     // pixel.
  181.     float4 coeffs = PI * float4(1.0 + uv_ratio.x, uv_ratio.x, 1.0 - uv_ratio.x, 2.0 - uv_ratio.x);
  182.  
  183.     // Prevent division by zero.
  184.     coeffs = FIX(coeffs);
  185.  
  186.     // Lanczos2 kernel.
  187.     coeffs = 2.0 * sin(coeffs) * sin(coeffs / 2.0) / (coeffs * coeffs);
  188.  
  189.     // Normalize.
  190.     coeffs /= dot(coeffs, float4(1.0, 1.0, 1.0, 1.0));
  191.  
  192.     // Calculate the effective colour of the current and next
  193.     // scanlines at the horizontal location of the current pixel,
  194.     // using the Lanczos coefficients above.
  195.     float4 col  = clamp(mul(coeffs, float4x4(
  196.                     TEX2D(xy + float2(-co.one.x, 0.0)),
  197.                     TEX2D(xy),
  198.                     TEX2D(xy + float2(co.one.x, 0.0)),
  199.                     TEX2D(xy + float2(2.0 * co.one.x, 0.0)))),
  200.             0.0, 1.0);
  201.     float4 col2 = clamp(mul(coeffs, float4x4(
  202.                     TEX2D(xy + float2(-co.one.x, co.one.y)),
  203.                     TEX2D(xy + float2(0.0, co.one.y)),
  204.                     TEX2D(xy + co.one),
  205.                     TEX2D(xy + float2(2.0 * co.one.x, co.one.y)))),
  206.             0.0, 1.0);
  207.  
  208. #ifndef LINEAR_PROCESSING
  209.     col  = pow(col , float4(inputGamma, inputGamma, inputGamma, inputGamma));
  210.     col2 = pow(col2, float4(inputGamma, inputGamma, inputGamma, inputGamma));
  211. #endif
  212.  
  213.     // Calculate the influence of the current and next scanlines on
  214.     // the current pixel.
  215.     float4 weights  = scanlineWeights(uv_ratio.y, col);
  216.     float4 weights2 = scanlineWeights(1.0 - uv_ratio.y, col2);
  217.     float3 mul_res  = (col * weights + col2 * weights2).rgb;
  218.  
  219.     // dot-mask emulation:
  220.     // Output pixels are alternately tinted green and magenta.
  221.     float3 dotMaskWeights = lerp(
  222.             float3(1.0, 0.7, 1.0),
  223.             float3(0.7, 1.0, 0.7),
  224.             floor(fmod(co.mod_factor, 2.0))
  225.             );
  226.  
  227.     mul_res *= dotMaskWeights;
  228.  
  229.     // Convert the image gamma for display on our output device.
  230.     mul_res = pow(mul_res, float3(1.0 / outputGamma, 1.0 / outputGamma, 1.0 / outputGamma));
  231.  
  232.     return float4(mul_res, 1.0);
  233. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement