bicubic_scale.effect 3.7 KB

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