Shaderを使って点線

昔、Window.draw_exを使って線を引くコードを書いた。
http://d.hatena.ne.jp/mirichi/20100622/p1
今だとWindow.draw_lineがあるからこのような細工はしなくていいが、Shaderを組み合わせればもっと高度な線が引けるのではないかと思って試してみた。

まあ、点線が引きたければそのようにImageを作るのが手っ取り早いのだが、斜めの点線を引くのは自前でブレゼンハムアルゴリズムを書かないといけなくなるから、こういう手を利用したほうがラクではある。
なんにせよ微妙だ。座標計算間違ってるかも。

require 'dxruby'

module Window
hlsl = <<EOS
  texture tex0;
  float width;

  sampler Samp0 = sampler_state
  {
   Texture =<tex0>;
   AddressU = WRAP;
   AddressV = WRAP;
  };

  float4 PS(float2 input : TEXCOORD0) : COLOR0
  {
    float4 output;

    output = tex2D( Samp0, float2(input.x * width, input.y) );
    return output;
  }

  technique
  {
   pass P0
   {
    PixelShader = compile ps_2_0 PS();
   }
  }
EOS

  core = Shader::Core.new(hlsl, :width=>:float)
  @shader = Shader.new(core)

  def self.draw_line_ex(x1, y1, x2, y2, image, z = 0)
    sx = Math.sqrt(((x1 - x2)**2) + ((y1 - y2)**2))
    angle = Math.atan2(y2 - y1, x2 - x1) / Math::PI * 180
    @shader.width = sx.quo(image.width)
    Window.draw_ex((x2 + x1) / 2.0, (y2 + y1) / 2.0, image,
                  :scalex=>sx.quo(image.width), :scaley=>1,
                  :centerx=>0, :centery=>0.5,
                  :angle=>angle, :z=>z, :shader=>@shader)
  end
end

Window.width, Window.height = 220,200
image1 = Image.new(8, 1)
image1.line(4, 0, 7, 0, C_WHITE)

image2 = Image.new(9, 1)
image2[2, 0] = C_WHITE
image2.line(5, 0, 9, 0, C_WHITE)

image3 = Image.new(3, 1)
image3[1,0] = C_WHITE

Window.loop do
  Window.draw_line_ex(20, 40, 120, 40, image1)
  Window.draw_line_ex(20, 60, 120, 60, image2)
  Window.draw_line_ex(20, 80, 120, 80, image3)
end