Ruby 上でも高速な 2D 描画が売りの Ruby/SDL ですが、SDL::Surface の API (kmc.gr.jp) を眺めていると、アルファブレンディングはサポートされているものの、加算・乗算などの画像合成は用意されていないことに気が付きました。まぁ昨今の華美な加算・乗算合成エフェクトは食傷気味でもありますが、アルファブレンディングの表現力には物足りなさというか古臭さを感じてしまいます。昔読んだコラムには、アルファブレンディングは重いよって書いてあったしね。いまはどうなんだろう。
API がなければスクリプト書けばいいじゃない。ということでちょっと実験してみました。こんなときこそ Ruby の身軽さです。SDI::Surface からピクセルデータを取得する pixels メソッドと、ピクセルデータから SDL::Surface のインスタンスを生成する new_from メソッドがあるから、自分で計算すればなんとかなるかなぁと甘い考えをしていたわけです。元画像には Ruby/SDL の sample フォルダに入ってた ruby っぽい画像 (icon.bmp) にちょい手を加えたのと、コマンドプロンプトを切り抜いた画像を使いました。

書いてみたソースはこんな感じ。ピクセルごとにゴリゴリ計算。スマートな方法をご存知の方、教えてください。
#Multiple blending for Ruby/SDL
def multi(dest, src)
result = Array.new()
(0...dest.pixels.size-1).each do |i|
result << ((dest.pixels[i]*src.pixels[i]) >> 8)
end
return result.pack("c*")
end
img1 = SDL::Surface.loadBMP("icon.bmp")
img2 = SDL::Surface.loadBMP("icon2.bmp")
image = SDL::Surface.new_from(multi(img1, img2), 32, 32, 32, 128, 0, 0, 0, 0)
image.setColorKey(SDL::SRCCOLORKEY, 1)
$image = image.displayFormat
SDL.blitSurface($image, 0, 0, 32, 32, screen, x, y)
いろいろと紆余曲折がありまして、途中かなりの泥沼にはまったのですが、まぁなんとか Photoshop の乗算合成と全く同じ合成効果が得られました!

落とし穴については、後日書くことにします。上述の処理は、同じサイズの同じ色深度の BMP ファイルで動作します。色深度の穴は深くて冷たかった。
こうなると加算だろうが減算だろうがどんとこい。下は加算合成の例。

がしかし、リアルタイムで合成するのはツライのかな? まー今日のところは結果 ok。
※ new_from メソッドの (R|G|B|A)mask って何を渡せばよいのでしょう? 0x000000ff とか投げてみたけど、よくわかんない。結局 0 に落ち着いた。
おぉ、ついに phonondrive さんも SDL の世界に!実は私も C++ で SDL | GL | AL なソレだったりします。
なにやら ttp://rainer.blog7.fc2.com の 2006/09 あたりに開発ログがあったりしますですよ (最近はあまり開発関連のエントリを書いていませんが、ひそひそと作ってます)。
それと 2/11 (次の日曜日) に新宿あたりで SDL-OFF なるものが開催されるようで...。私も一度 phonondrive さんをお目にかかりたいと思っているので、もしご都合が良ければ是非とも参加のほうをご検討ください。
→ ttp://zinnia.dyndns.org/~hiki/SandBox/?2007年新春(関東)
(無理を承知で書いています。急な話ですいません^^;)
お誘い頂きありがとうございます。しかし当方、一昨日インストールしたばかりの者ですが・・・。
先日曲を聴いたときに blog もチラ見させて頂いてました。レンダー作ってて凄いなぁと思ったんですが、SDL も触ってらしたですね。Lua×OpenGL だと勝手に思い込んでました。
もし 「この速さなら言える」 ってな具合にテンションが急上昇したら、刺激を貰いに行くかも、程度に考えていてください。
アルファブレンドはソフトウェアサーフェスを使っているなら普通に数倍遅くなるだけだと思いますが、ハードウェアサーフェスを使う場合はハードウェアによる高速化がなくなるため理屈としては相当遅くなるはずです。SDLのvideoは内部ではDirectDrawを使うのでこうなります。ここはSDL1.3で変更されますがまだまだ先の話です。凝った合成を高速に使いたければ今はOpenGLを併用するのが良いと思います。
あとget_pixel/put_pixelを使ったほうがプログラムはわかりやすくなると思います。ただこうするとさらに遅くなるでしょう。
コメントありがとうございます。SW と HW でもかなり変わってくるんですね。パフォーマンスが出ないようでしたら OpenGL も考えます。
get/put(set)_pixel と名の付くものはやはり遅いのですね。