ViewPort機能を考える

DirectXにはViewPortという機能がある。
ようするにクリッピング範囲の指定だ。


現在、DXRubyにはViewPortを指定する機能が無い。
Imageクラスの拡張が超高速に動くのなら、それこそImageオブジェクトを適当な範囲で作って、そこに描画するようにすればViewPortのようなものになる。
が、おそらくかなり低速になるから、そういう使い方をしてはいけない。
もしSurfaceクラスを作ったら、Imageクラスと違ってデータは保持されないことが前提となるから、使い方は単純にViewPortの代わりということになる。
そのためだけにSurfaceクラスを作るのもちょっとなんだかなー、という感じだ。


RGSSではSpriteにViewPortがくっついているようだ。
スクリーン座標のうち、自分が描画される範囲を自分で持っている、ということだ。
DirectXを使っているなら、おそらく実装はSpriteの描画時に毎回DirectXのSetViewPortでViewPortを指定しているのだろう。
DXRubyではスプライトオブジェクトは無いから、似たようなやりかたをしようと思うとImageオブジェクトにViewPortを持たせることになる。
しかし範囲の中と外に同じ絵を描画したい場合、同じイメージを2個生成しないといけないのはスマートではないし、絵が描画範囲を持つのはどうも何か違うような気がする。
Window.drawの引数にViewPortを追加する、という手もある。
構造体も大きくなるし、描画時に毎回ViewPortを指定するのもあまり嬉しくない。
何より描画ごとに設定するほどのものでもないのに、引数が増えるのがよろしくない。


Window.setViewPortメソッドを作って、実行後のWindow.draw系のViewPortがそれに切り替わる、という手がある。
だがDXRubyでは描画時にzを指定することができて、これが描画順となって、ソートされてから描画される。
だからWindow.drawの間にsetViewPortメソッドを使っても、実際の描画順はバラバラになる可能性がある。
setViewPortの概念とWindow.drawの概念が食い違うと、使う側が非常にやりにくくなる。
Window.drawがz値でソートされるなら、同様にViewPortもz値を持つ、というのも考えられる。
通常ViewPortを指定するなら、ある程度のz範囲ごとに設定されると想像できる。
それを考えるとViewPortをz値に関連付ける、というのは理にかなっている。
DXRuby的イメージでいくとこれが一番よさそうだ。


例えば、z範囲100〜200まではViewPortいくつ、という指定方法の案。
ViewPortを切り替えようと思ったら、zを指定しないといけなくなるから面倒だ。
俺ならzを省略してもViewPortを切り替えて使ったりしたい。
そうするとさっきのsetViewPortメソッドのようなものになるが、このsetViewPortをz値と関連付ける方法を考える。
Window.setViewPort(範囲, z = 0)という感じか。
全てのWindow.draw系でzを省略している場合はそこから後のWindow.drawが、zを指定している場合はそのz以降の指定のWindow.drawのViewPortが切り替わる。
この場合の実装としては、スプライト構造体に現在ImageとFontが混ざっているように、ViewPort切り替えオブジェクトを挟んでしまえばよさそうだ。
描画するものがViewPort切り替えオブジェクトだった場合、DirectXのSetViewPortを呼んで切り替えるだけの動作をする。


とりあえず仕様はできたが、使いやすさや問題点などはしばらく寝かせて考える必要はあるだろう。
俺としてはマップ描画時の高速クリッピング手段が欲しい。
Surfaceクラスを作るほどでもないが、Imageで代用するわけにもいかないなら、そういった機能を追加するしかない。
黒い絵や枠を重ねて消すというのはどうにもしょぼい。
幸い簡単にできそうな感じでよかった。