bicubic_scale.effect 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. /*
  2. * bicubic sharper (better for downscaling)
  3. * note - this shader is adapted from the GPL bsnes shader, very good stuff
  4. * there.
  5. */
  6. uniform float4x4 ViewProj;
  7. uniform texture2d image;
  8. uniform float4x4 color_matrix;
  9. uniform float3 color_range_min = {0.0, 0.0, 0.0};
  10. uniform float3 color_range_max = {1.0, 1.0, 1.0};
  11. uniform float2 base_dimension_i;
  12. uniform float undistort_factor = 1.0;
  13. sampler_state textureSampler {
  14. Filter = Linear;
  15. AddressU = Clamp;
  16. AddressV = Clamp;
  17. };
  18. struct VertData {
  19. float4 pos : POSITION;
  20. float2 uv : TEXCOORD0;
  21. };
  22. VertData VSDefault(VertData v_in)
  23. {
  24. VertData vert_out;
  25. vert_out.pos = mul(float4(v_in.pos.xyz, 1.0), ViewProj);
  26. vert_out.uv = v_in.uv;
  27. return vert_out;
  28. }
  29. float weight(float x)
  30. {
  31. float ax = abs(x);
  32. /* Sharper version. May look better in some cases. */
  33. const float B = 0.0;
  34. const float C = 0.75;
  35. if (ax < 1.0)
  36. return (pow(x, 2.0) *
  37. ((12.0 - 9.0 * B - 6.0 * C) * ax +
  38. (-18.0 + 12.0 * B + 6.0 * C)) +
  39. (6.0 - 2.0 * B))
  40. / 6.0;
  41. else if ((ax >= 1.0) && (ax < 2.0))
  42. return (pow(x, 2.0) *
  43. ((-B - 6.0 * C) * ax + (6.0 * B + 30.0 * C)) +
  44. (-12.0 * B - 48.0 * C) * ax +
  45. (8.0 * B + 24.0 * C))
  46. / 6.0;
  47. else
  48. return 0.0;
  49. }
  50. float4 weight4(float x)
  51. {
  52. return float4(
  53. weight(x - 2.0),
  54. weight(x - 1.0),
  55. weight(x),
  56. weight(x + 1.0));
  57. }
  58. float AspectUndistortX(float x, float a)
  59. {
  60. // The higher the power, the longer the linear part will be.
  61. return (1.0 - a) * (x * x * x * x * x) + a * x;
  62. }
  63. float AspectUndistortU(float u)
  64. {
  65. // Normalize texture coord to -1.0 to 1.0 range, and back.
  66. return AspectUndistortX((u - 0.5) * 2.0, undistort_factor) * 0.5 + 0.5;
  67. }
  68. float2 pixel_coord(float xpos, float ypos)
  69. {
  70. return float2(AspectUndistortU(xpos), ypos);
  71. }
  72. float4 pixel(float xpos, float ypos, bool undistort)
  73. {
  74. if (undistort)
  75. return image.Sample(textureSampler, pixel_coord(xpos, ypos));
  76. else
  77. return image.Sample(textureSampler, float2(xpos, ypos));
  78. }
  79. float4 get_line(float ypos, float4 xpos, float4 linetaps, bool undistort)
  80. {
  81. return
  82. pixel(xpos.r, ypos, undistort) * linetaps.r +
  83. pixel(xpos.g, ypos, undistort) * linetaps.g +
  84. pixel(xpos.b, ypos, undistort) * linetaps.b +
  85. pixel(xpos.a, ypos, undistort) * linetaps.a;
  86. }
  87. float4 DrawBicubic(VertData v_in, bool undistort)
  88. {
  89. float2 stepxy = base_dimension_i;
  90. float2 pos = v_in.uv + stepxy * 0.5;
  91. float2 f = frac(pos / stepxy);
  92. float4 rowtaps = weight4(1.0 - f.x);
  93. float4 coltaps = weight4(1.0 - f.y);
  94. /* make sure all taps added together is exactly 1.0, otherwise some
  95. * (very small) distortion can occur */
  96. rowtaps /= rowtaps.r + rowtaps.g + rowtaps.b + rowtaps.a;
  97. coltaps /= coltaps.r + coltaps.g + coltaps.b + coltaps.a;
  98. float2 xystart = (-1.5 - f) * stepxy + pos;
  99. float4 xpos = float4(
  100. xystart.x,
  101. xystart.x + stepxy.x,
  102. xystart.x + stepxy.x * 2.0,
  103. xystart.x + stepxy.x * 3.0
  104. );
  105. return
  106. get_line(xystart.y , xpos, rowtaps, undistort) * coltaps.r +
  107. get_line(xystart.y + stepxy.y , xpos, rowtaps, undistort) * coltaps.g +
  108. get_line(xystart.y + stepxy.y * 2.0, xpos, rowtaps, undistort) * coltaps.b +
  109. get_line(xystart.y + stepxy.y * 3.0, xpos, rowtaps, undistort) * coltaps.a;
  110. }
  111. float4 PSDrawBicubicRGBA(VertData v_in, bool undistort) : TARGET
  112. {
  113. return DrawBicubic(v_in, undistort);
  114. }
  115. float4 PSDrawBicubicMatrix(VertData v_in) : TARGET
  116. {
  117. float4 rgba = DrawBicubic(v_in, false);
  118. float4 yuv;
  119. yuv.xyz = clamp(rgba.xyz, color_range_min, color_range_max);
  120. return saturate(mul(float4(yuv.xyz, 1.0), color_matrix));
  121. }
  122. technique Draw
  123. {
  124. pass
  125. {
  126. vertex_shader = VSDefault(v_in);
  127. pixel_shader = PSDrawBicubicRGBA(v_in, false);
  128. }
  129. }
  130. technique DrawUndistort
  131. {
  132. pass
  133. {
  134. vertex_shader = VSDefault(v_in);
  135. pixel_shader = PSDrawBicubicRGBA(v_in, true);
  136. }
  137. }
  138. technique DrawMatrix
  139. {
  140. pass
  141. {
  142. vertex_shader = VSDefault(v_in);
  143. pixel_shader = PSDrawBicubicMatrix(v_in);
  144. }
  145. }