SWIGを試してみたことはありますが、1から 書いたことがなかったので。
お題は数学関数に。うまいこと完成したら、ruby-opengl と一緒に使えるかも しれません。
以下のメモに出てくる
RVec4
は「4次元ベクトルを表すクラス」として 読んでみてください。クラスの追加
rb_cRVec4 = rb_define_class( "RVec4", rb_cObject );
rb_cObject は
include/ruby/ruby.h
で宣言されている組み込みの変数。メモリ確保関数の指定
rb_define_alloc_func( rb_cRVec4, RVec4_allocate );
RVec4.new
と書くと、allocate→initializeの順にメソッド が走るようです。このallocateのときに呼ばれる関数は上記のように指 定できるようになっています。確保した領域の Ruby オブジェクト(T_DATA)化
RVec4* v = malloc( sizeof(RVec4) ); ... VALUE obj = Data_Wrap_Struct( rb_cRVec4, 0, RVec4_free, v );
C++ でいうPlacement new みたいなものかな? obj の型は TYPE(obj) == T_DATA だった。 この領域を解放する関数は Data_Wrap_Struct の第3引数で指定する。
インスタンスメソッドの追加
rb_define_method( rb_cRVec4, "getLength", RVec4_getLength, -1 );
これで RVec4 クラスのインスタンスに getLength メソッドが追加される。実装は
VALUE RVec4_getLength( int argc, VALUE* argv, VALUE self );
という関数で行う。
クラスメソッド*1の追加
rb_define_singleton_method( rb_cRVec4, "dot", RVec4_dot, -1 );
これで
result = RVec4.dot(v1, v2)
という感じで利用できることになる。Ruby の VALUE から C の構造体へのキャスト
VALUE RVec4_getLength( int argc, VALUE* argv, VALUE self ) { RVec4* v = NULL; ... Data_Get_Struct( self, RVec4, v ); ...
float/doubleのT_FLOAT化
VALUE obj = rb_float_new( flt );
Ruby のメソッドを使う
obj の to_s メソッドを使いたいときは:
VALUE str = rb_funcall( obj, rb_intern("to_s"), 0 );
…となる。 rb_funcall の第3/第4引数にはそれぞれ argc, argv を渡すことができる。
特に rb_funcall がおもしろいですね。Ruby の機能がそのまま C から利用できるというわけですから。
*1 正確には「クラス(を表すオジェクト)に対する特異メソッド」と呼ぶらしい。