Shader再び

DXRuby1.1で一度作ったが、とても使いにくかったので再設計。
シェーダのアルゴリズムとパラメータ名・型を保持するImmutableのShaderクラスと、Shaderオブジェクトとパラメータを保持するShaderSetクラスに分けてみた。
これでShaderSetを描画プリミティブごとに持つことができるようになる。Window.drawShaderに渡すのはShaderSetオブジェクトのほう。
ためしにトランジションのコードを昔の記事から引っ張り出してきて動かしてみた。ルール画像は吉里吉里トランジションライブラリから拝借。

ただ、HLSLの都合でパラメータの設定がわかりにくいことになるから、そのへんはサポートクラスを用意して扱いやすくする必要があるだろう。
そのへんはまた後日。
あと、クラスの名前は仮。実装もまだ手抜き。設計もとりあえず作ってみた実験的なもので、変わる可能性はおおいにあることを付け加えておく。

#!ruby -Ks
require 'dxruby'

map = [[0, 0, 0, 0, 0, 0, 0, 0, 29, 11, 11, 30, 34, 66, 67, 67],
       [0, 0, 0, 24, 25, 26, 0, 0, 29, 11, 11, 39, 40, 6, 34, 34],
       [0, 0, 24, 17, 31, 35, 0, 0, 12, 20, 11, 11, 11, 39, 40, 40],
       [0, 24, 17, 34, 7, 44, 0, 28, 28, 29, 11, 11, 11, 11, 11, 11],
       [0, 33, 31, 34, 35, 0, 28, 3, 37, 38, 11, 11, 11, 18, 19, 19],
       [0, 42, 43, 43, 44, 28, 3, 38, 11, 11, 11, 18, 19, 13, 28, 28],
       [0, 0, 0, 0, 3, 37, 38, 11, 11, 18, 19, 13, 28, 28, 28, 0],
       [0, 0, 0, 3, 38, 11, 11, 11, 18, 13, 28, 28, 51, 52, 52, 52],
       [0, 0, 3, 38, 11, 11, 18, 19, 13, 51, 52, 52, 86, 58, 61, 76],
       [28, 0, 29, 11, 11, 18, 13, 28, 51, 86, 58, 58, 61, 61, 58, 62],
       [0, 28, 29, 11, 18, 13, 28, 0, 60, 58, 61, 61, 61, 61, 76, 71],
       [0, 28, 29, 11, 27, 28, 28, 51, 86, 61, 61, 58, 76, 70, 71, 0],
       [0, 0, 29, 11, 36, 4, 28, 60, 58, 61, 58, 76, 71, 0, 1, 2],
       [0, 28, 29, 11, 11, 36, 4, 69, 70, 70, 70, 71, 0, 1, 2, 0],
       [0, 0, 12, 20, 11, 11, 27, 0, 1, 0, 1, 1, 1, 2, 2, 0],
       [0, 0, 28, 12, 20, 11, 27, 0, 0, 0, 2, 2, 0, 2, 2, 0],
       [0, 0, 0, 2, 29, 11, 27, 1, 2, 2, 2, 0, 0, 2, 2, 2],
       [0, 0, 0, 2, 29, 11, 27, 1, 0, 1, 1, 2, 2, 0, 0, 2],
       [0, 0, 0, 0, 29, 11, 27, 1, 0, 2, 2, 2, 1, 1, 2, 2],
       [0, 45, 47, 2, 29, 11, 36, 4, 1, 2, 2, 0, 0, 2, 2, 0],
       [45, 82, 56, 0, 29, 11, 11, 36, 4, 1, 2, 2, 2, 2, 0, 0],
       [54, 0, 56, 0, 12, 20, 11, 11, 36, 37, 4, 0, 2, 2, 2, 2],
       [54, 55, 81, 46, 47, 12, 20, 11, 11, 11, 36, 4, 1, 1, 1, 2],
       [54, 55, 0, 0, 56, 0, 12, 19, 20, 11, 11, 36, 37, 4, 1, 1],
       [54, 0, 55, 55, 56, 0, 0, 0, 12, 20, 11, 11, 11, 36, 37, 37],
       [63, 73, 55, 55, 56, 0, 0, 2, 2, 29, 11, 11, 11, 11, 11, 11],
       [0, 54, 0, 55, 81, 47, 0, 2, 3, 38, 11, 11, 11, 11, 11, 11],
       [0, 54, 0, 0, 55, 56, 2, 0, 29, 11, 11, 11, 21, 22, 22, 22],
       [0, 63, 64, 64, 64, 65, 0, 0, 29, 11, 11, 21, 15, 48, 49, 49],
       [0, 0, 0, 0, 0, 0, 0, 0, 29, 11, 11, 30, 34, 57, 34, 34],
      ]

hlsl = <<EOS
float g_min;
float g_max;
texture tex0;
texture tex1;
sampler Samp0 = sampler_state
{
 Texture =<tex0>;
};
sampler Samp1 = sampler_state
{
 Texture =<tex1>;
};

struct PixelIn
{
  float2 UV : TEXCOORD0;
};
struct PixelOut
{
  float4 Color : COLOR0;
};

PixelOut PS(PixelIn input)
{
  PixelOut output;
  output.Color = tex2D( Samp0, input.UV );
  output.Color.a = smoothstep(g_min, g_max, tex2D( Samp1, input.UV ).r );

  return output;
}

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

shader = Shader.new(hlsl,
  "TShader", # 2つ目のパラメータはtechniqe名
  {          # 3つ目のパラメータはシェーダに渡すパラメータ名と型のHash
    :g_min => :float,
    :g_max => :float,
    :tex1 => :texture,
  }
)

shaderset = ShaderSet.new(shader) # ShaderSetがShaderオブジェクトとパラメータの値を持つ

rt = RenderTarget.new(640, 480)
transition = Image.load("右渦巻き.png")

image = Image.loadToArray("image/maptile.png", 9, 10)

min = 0.0
max = 0.1
Window.loop do
  min += 0.01
  max += 0.01

  rt.drawTile(150, 16, map, image, 0, 0, 12, 14)
  rt.update

  # ShaderSetオブジェクトには特異メソッドでSetter/Getterが定義される
  shaderset.tex1 = transition
  shaderset.g_min = min
  shaderset.g_max = max

  # drawShaderに渡すのはShaderSetオブジェクト
  Window.drawShader(0, 0, rt, shaderset)
end