線形補間

昔やった拡大縮小のメソッドを、線形補間に対応させてみた。
実験的に。
昔の記事はこれ。
http://d.hatena.ne.jp/mirichi/20090708/p3

#! ruby -Ks
require 'dxruby'

class Image
  def strechRect(x1, y1, w1, h1, image, x2, y2, w2, h2)
    if image.width < x2 + w2 or image.height < y2 + h2 or
       self.width < x1 + w1 or self.height < x1 + h1 or
       x1 < 0 or y1 < 0 or w1 < 0 or h1 < 0 or
       x2 < 0 or y2 < 0 or w2 < 0 or h2 < 0
        raise "座標がはみ出してるようです"
    end

    dx = w2.quo(w1)
    dy = h2.quo(h1)
    x = x2
    y = y2
    for i in y1...(y1 + h1)
      ty1 = y % 1.0
      ty2 = 1.0 - ty1
      for j in x1...(x1 + w1)
        s1 = image[x, y]
        s2 = image[x+1, y]
        s3 = image[x, y+1]
        s4 = image[x+1, y+1]
        tx1 = x % 1.0
        tx2 = 1.0 - tx1
        s1.map! { |c| tx2 * ty2 * c }
        s2.map! { |c| tx1 * ty2 * c }
        s3.map! { |c| tx2 * ty1 * c }
        s4.map! { |c| tx1 * ty1 * c }

        self[j, i] = [s1[0]+s2[0]+s3[0]+s4[0], s1[1]+s2[1]+s3[1]+s4[1], s1[2]+s2[2]+s3[2]+s4[2], s1[3]+s2[3]+s3[3]+s4[3]]
        x = x + dx
      end
      x = x2
      y = y + dy
    end
    return self
  end
end


image0 = Image.new(100,100).circleFill(49,49,49, [255,0,255,0]). # もとねた
                          circleFill(49,49,30, [255,128,128,0])
image1 = Image.new(50,50)                                      # 縮小先
image2 = Image.new(200,200)                                    # 拡大先

image1.strechRect(0, 0, 50, 50, image0, 0, 0, 100, 100)   # 縮小
image2.strechRect(0, 0, 200, 200, image0, 10, 10, 50, 50) # 拡大

Window.loop do
  break if Input.keyPush?(K_ESCAPE)

  Window.draw(0,0,image0)
  Window.draw(0,100,image1)
  Window.draw(0,150,image2)
end


真面目にRubyでやると死ぬほど遅い。
Cでやってもそれなりに遅いだろう。
アルゴリズムとしては、ピクセルの中心を(0.0, 0.0)として、右と下と右下の点の色を、端数のぶんだけ合成する。
透明色の計算をきちんとしてないから、色のついてるところに色を置くと輪郭がおかしくなる。
アルファブレンドの処理を追加する必要がある。
また、このやりかただけでは縮小に対応ができない。
縮小のほうは元画像の座標が飛ぶから、間の色を全部足して距離で割る必要がある。
線形補間をリアルタイムにやるならソフトウェアでやるべきではない。RGSSも単純拡縮しかしていない。


このアルゴリズムでは左上(0.0, 0.0)から始まるから、右下のピクセルを描画するときに元画像の範囲からはみ出した色を合成する。
画像の中心を拡大縮小の中心におくと、左上のピクセルも左上にはみ出した色を合成する。
DirectXはこのへん真面目にそのままやっているため、拡大したときに指定テクスチャ範囲外の色を拾ってしまう。
昨日の記事のコメントのtotobook氏の指摘はその問題のことで、DirectXの固定機能パイプラインを使う限り、なんらかの細工で対策するしか手が無い。
とりあえず拡大縮小アルゴリズムについてもDirectXについてもぜんぜん知識が足りてないから、勉強しつつ対策を考えていこうと思う。