DXRuby拡張

DXRubyそのものをコンパイルしようとするとDirectXSDKが必要になるが、テクスチャをいじる処理をCで書くだけならDXRubyの外部I/Fを使えば不要になる。
DXRubyではテクスチャイメージへのポインタを返す関数を公開しているから、DXRubyのlibをリンクさえすれば、DirectXSDK無しでも高速画像処理ライブラリを作ることができる。
RGSS互換ライブラリでflashとcolorが死ぬほど遅かったので、このインターフェースを使ってCで書いてみた。
こんな感じ。

#include "ruby.h"
#include "dxruby.h"

VALUE Image_flash( VALUE self, VALUE a, VALUE r, VALUE g, VALUE b )
{
    void *handle;
    char *address;
    int pitch, width, height;
    int x, y;
    unsigned int color;

    color = (NUM2INT(a) << 24) + (NUM2INT(r) << 16) + (NUM2INT(g) << 8) + NUM2INT(b);

    handle = DXRuby_lock( self, &address, &pitch, &width, &height );

    for( y = 0; y < height; y++ )
    {
        for( x = 0; x < width; x++)
        {
            char *addr = address + x * 4 + y * pitch;
            if( *addr != 0 )
            {
                *((unsigned int*)addr) = color;
            }
        }
    }
    DXRuby_unlock( handle );
    return self;
}

VALUE Image_blend( VALUE self, VALUE a, VALUE r, VALUE g, VALUE b )
{
    void *handle;
    char *address;
    int pitch, width, height;
    int x, y;
    unsigned int color;

    color = (NUM2INT(a) << 24) + (NUM2INT(r) << 16) + (NUM2INT(g) << 8) + NUM2INT(b);

    handle = DXRuby_lock( self, &address, &pitch, &width, &height );

    for( y = 0; y < height; y++ )
    {
        for( x = 0; x < width; x++)
        {
            char *addr = address + x * 4 + y * pitch;
            if( *addr != 0 )
            {
                int c, rr, rg, rb;
                c = (int)*(addr + 1) + (NUM2INT(r) * 256 / NUM2INT(a));
                if( c > 255 )
                {
                    rr = 255;
                }
                else
                {
                    rr = c;
                }
                c = (int)*(addr + 2) + (NUM2INT(g) * 256 / NUM2INT(a));
                if( c > 255 )
                {
                    rg = 255;
                }
                else
                {
                    rg = c;
                }
                c = (int)*(addr + 3) + (NUM2INT(b) * 256 / NUM2INT(a));
                if( c > 255 )
                {
                    rb = 255;
                }
                else
                {
                    rb = c;
                }

                *((unsigned int*)addr) = (*addr << 24) + (rr << 16) + (rg << 8) + rb;
            }
        }
    }
    DXRuby_unlock( handle );
    return self;
}

void Init_dxrubyrgss_c()
{
    VALUE cImage;

    cImage = rb_eval_string( "DXRuby::Image" );

    /* Imageクラスにメソッド登録*/
    rb_define_method(cImage, "flash", Image_flash, 4);
    rb_define_method(cImage, "blend", Image_blend, 4);
}

これでImageクラスにflashとblendという2つのメソッドが追加され、自分自身の画像を書き換える動作をする。
手早く作るためにいい加減な仕様になっているが、とにかく拡張ライブラリをコンパイルできる環境さえあれば誰でも高速画像処理ができる、という話。
なんだか色の計算まわりがバグりまくってるようだけどキニシナイ。