sdl2rのそのままじゃないところ

一応、sdl2rはSDL2そのままの形でRubyから使えるというのが売りなのだが、そもそもがC用のライブラリであるだけに、どうしてもそのままでは困ったちゃんな部分があって、Ruby向けに修正しているところがいくつかある。そのへんを書いておこうと思う。

オブジェクト管理

SDL2はC用のライブラリなので、オブジェクトの寿命の管理や解放処理はユーザが自分で書くのが前提になっている。オブジェクトの大半はOSやGPUのリソースを食うわけだから、慎重に厳密に管理してやらないといけないのだが、最近GCを装備した言語が急激に増えているのを考えると、そういうのがいかに難しい話なのかがわかるというものだろう。RubyGCを持つ言語であるからして、その恩恵を受けるべきである。
ということで、SDLオブジェクトはすべてRubyのオブジェクトでラップしてあり、GC回収時に解放されていなかったら自動的に解放するようにしてある。SDLオブジェクト生成時に失敗したらGCを動かしてからもう一度チャレンジする。これでオブジェクト管理まわりのバグでコケたりリークしたりして悩むことは無くなる。
もちろん無駄に参照を保持しっぱなしでリソース不足になればコケるが、それは論外である。

Rendererの話

前にごちゃごちゃ書いた件だが、結局SDL::WindowオブジェクトにSDL_Rendererを持たせて、SDL::RendererからはSDL::Windowオブジェクトへの参照だけ持つことにした。Proxyパターンである。といえば聞こえはいいが、まあ、動くし簡単に実装できるんだからそれでよい。

SDL::Surface::Pixels

SDL_RendererやSDL_Textureは構造体だが、それの中身はユーザが見るべきではないようだ。通常、このようなライブラリではそのような内部仕様は隠蔽するべきだと思うのだが、SDL_Surfaceだけは事情が異なっていて、画像データへのアクセスはsurface->pixelsで持つvoidポインタを経由してアクセスする。ポインタが指す先のデータはピクセルフォーマットによりさまざまなので、データのサイズもまちまちだしアドレス算出式もまちまちとなる。過去の互換性をひきずっているのかもしれないがイマイチである。
Rubyから画像データへアクセスする際に、アドレス算出やらデータサイズごとの読み書き処理やらを書くのはさすがにありえないと思うので、この部分は拡張ライブラリで隠蔽することにした。どうせみんな同じコード書くことになるし。
具体的にはSDL::Surface#pixelsメソッドを呼ぶとSDL::Surface::Pixelsオブジェクトが返ってくる。Pixelsは画像データへのアクセスを抽象化するもので、Pixels#[x,y]でSDL::Colorを返すし、Pixels#[x,y]=cでSDL::Colorの色をセットすることができる。ピクセルフォーマットは内部でよしなに処理する。8bppの場合はパレットを使うことになるが、取得する時はパレットから色を取ってSDL::Colorを作るし、色をセットする時は一番近い色をパレットから探してセットするという動作をする。
ちょっと残念だがいたしかたあるまい。

各種クラスのインスタンスメソッドについて

destroyed?しか無い。これはSDL2には当然無いもので、保持するSDLオブジェクトが解放済みかどうかを返す。WindowやRendererを最初に考えていたのでdestroyed?という名前になったが、Surfaceを解放するのはSDL_FreeSurfaceだしJoystickはSDL_JoystickCloseなので全部destroyed?なのはおかしいのだが、とりあえず統一性を持たせるためにdestroyed?を全部に作ることにした。そのうちいい名前があったら変えるかもしれない。
SDLの機能はトップレベルのものとSDLオブジェクトに対するものに分かれるが、リファレンスがそういう構成じゃないことと、SDL2の使い勝手を継承するために、インスタンスメソッドでの操作は現時点では考えていない。あと、そのようにするとどうしてもSDL2のリファレンスと(名前的に)食い違いが発生して、独自にマニュアルを作らなければならなくなるのも問題である。マニュアル作るのめんどい。
無論、Rubyで勝手に定義するのは自由なので、使いやすいようにラップして公開してくれる人がいればそれは無条件で歓迎する。