BREW での画像転送(3)

例えば、単純な画像転送であれば、次のようにします。

// dst_type dst の型
// dst      転送先
// dx       転送先 X オフセット
// dy       転送先 Y オフセット
// dp       転送先ピッチ
// src_type src の型
// src      転送元
// sx       転送元 X オフセット
// sy       転送元 Y オフセット
// sp       転送元ピッチ
// w        転送する幅
// h        転送する高さ
#define NormalBltDefile( dst_type , dst , dx , dy , dp ,
                            src_type , src , sx , sy , sp , w , h ) \
    dst = (word*)((byte*)dst + dx * sizeof( dst_type ) + dy * dp ); \
    src = (word*)((byte*)src + sx * sizeof( src_type ) + sy * sp ); \
    for( int y = 0 ; y < h ; y++ ){                                 \
        for( int x = 0 ; x < w ; x++ ){                             \
            ... ここに転送 functor を書く                           \
        }                                                           \
        dst = (dst_type*)((byte*)dst + dp);                         \
        src = (src_type*)((byte*)src + sp);                         \
    }

で、肝心の転送方法ですが、いつもは functor でエフェクトをかけながら転送をしていたわけなんですけど、クラスの functor を使用するわけにはいかないので、これも #define で代用します。

// そのまま転送する functor
#define copy_functor( dst , dn , src , sn , dummy ) \
{                                                   \
    dst = src                                       \
}

// カラーキーを考慮して転送する functor
#define colorkey_functor( dst , dn , src , sn , key )   \
{                                                       \
    if( key != src ){                                   \
        dst = src;                                      \
    }                                                   \
}

// パレット+カラーキーの functor
#define palette8_colorkey_functor( dst , dn , src , sn , palette , key )    \
{                                                                           \
    if( key != src ){                                                       \
        dst = palette[ src ];                                               \
    }                                                                       \
}

dst は転送先画像、dn は dst のインデックス、src は転送元画像、sn は src のインデックスで、これらの引数は様々な転送ルーチンを書く上で必要になりそうなので、これらを全ての functor に付けて、それ以降の引数は functor によって変化しても構わないことにします。
もう一度通常の転送ルーチンを今度は functor を付けて書くと、次のようになります。

// dst_type dst の型
// dst      転送先
// dx       転送先 X オフセット
// dy       転送先 Y オフセット
// dp       転送先ピッチ
// src_type src の型
// src      転送元
// sx       転送元 X オフセット
// sy       転送元 Y オフセット
// sp       転送元ピッチ
// w        転送する幅
// h        転送する高さ
// functor      転送方法
// arguments    functor の引数
#define NormalBltDefile( dst_type , dst , dx , dy , dp ,
                            src_type , src , sx , sy , sp , w , h ,
                            functor , arguments )                   \
    dst = (word*)((byte*)dst + dx * sizeof( dst_type ) + dy * dp ); \
    src = (word*)((byte*)src + sx * sizeof( src_type ) + sy * sp ); \
    for( int y = 0 ; y < h ; y++ ){                                 \
        for( int x = 0 ; x < w ; x++ ){                             \
            functor( dst[ i ] , i , src[ i ] , i , arguments );     \
        }                                                           \
        dst = (dst_type*)((byte*)dst + dp);                         \
        src = (src_type*)((byte*)src + sp);                         \
    }

で、これらを呼び出す関数を書きます。
複数の引数を一つにまとめているところがミソです。

#define arg1(_1)                _1
#define arg2(_1,_2)             arg1(_1),##_2
#define arg3(_1,_2,_3)          arg2(_1,_2),##_3
#define arg4(_1,_2,_3,_4)       arg3(_1,_2,_3),##_4
#define arg5(_1,_2,_3,_4,_5)    arg4(_1,_2,_3,_4),##_5

// RGB565 → RGB565 , コピー転送
void RGB565_RGB565_Copy(
    word* dst_ ,
    int dx_ ,
    int dy_ ,
    int dp_ ,
    word* src_ ,
    int sx_ ,
    int sy_ ,
    int sp_ ,
    int w_ ,
    int h_
){
    int dummy_ = 0;
    NormalBltDefine( word , dst_ , dx_ , dy_ , dp_ ,
                        word , src_ , sx_ , sy_ , sp_ , w_ , h_ ,
                        copy_functor , arg1( dummy_ ) );
}

// RGB565 → RGB565 , カラーキー転送
void RGB565_RGB565_ColorKey(
    word* dst_ ,
    int dx_ ,
    int dy_ ,
    int dp_ ,
    word* src_ ,
    int sx_ ,
    int sy_ ,
    int sp_ ,
    int w_ ,
    int h_ ,
    uint32 key_     // 透過色
){
    NormalBltDefine( word , dst_ , dx_ , dy_ , dp_ ,
                        word , src_ , sx_ , sy_ , sp_ , w_ , h_ ,
                        colorkey_functor , arg1( key_ ) );
}

// 8bit Palette → RGB565 , カラーキー転送
void RGB565_RGB565PLT8_ColorKey(
    word* dst_ ,
    int dx_ ,
    int dy_ ,
    int dp_ ,
    byte* src_ ,
    int sx_ ,
    int sy_ ,
    int sp_ ,
    int w_ ,
    int h_ ,
    word* pal_ ,    // パレット
    uint32 key_     // 透過色
){
    NormalBltDefine( word , dst_ , dx_ , dy_ , dp_ ,
                        byte , src_ , sx_ , sy_ , sp_ , w_ , h_ ,
                        palette8_colorkey_functor , arg2( pal_ , key_ ) );
}

こうすることによって、通常転送のルーチンは一ヶ所にまとめられています。
今は大してこの define による恩恵はないですが、数が増えてくると、転送ルーチン×functor だけ必要だったものが、転送ルーチン+functor になるので、めちゃめちゃ楽です。


あと、これで完成だと思ったんですが、コンパイルするとエラーが出ました。
どうやら、arguments が functor の define より後に展開されてしまって、可変長にした意味が無くなってしまっているようです。
なので、次のようにしてみました。

#define execute( f )    f

execute( functor( dst[ i ] , i , src[ i ] , i , arguments ) );

define の細かい展開の方法は知らないんですが、これならいけるみたいです。


あとは 4bit パレットの転送とかになるとかなりごちゃごちゃしてくるんですが、とりあえずこれにて完成!ということで。