BREW の高速アルファブレンド

スレに書き込めない(ずっと規制されてる)のでここで返信。


誰か↓の内容を教えてあげて下さい...。

453 :デフォルトの名無しさん  :2008/04/30(水) 16:04:48
    すいません、初歩な質問をさせてください。

    BREWで半透明描画をするには、どうしたらいいでしょうか?
    αチャンネルがサポートされていますでしょうか?
    (使ってる画像がpngです)

    えろい人教えてください。m(_ _)m

454 :デフォルトの名無しさん [sage] :2008/04/30(水) 16:49:07
    >>453
    透過は普通な方法では不可。
    どうしてもやりたければDIB使って自力で描画。
    でもとても遅いので使うべきじゃない。


455 :デフォルトの名無しさん [sage] :2008/04/30(水) 17:17:35
    BREW3.1しか使ったことないんだけど、4.0でも半透明って実装されてないの?

456 :453 :2008/04/30(水) 17:30:15
    >>454
    ご返答ありがとうございます。
    半透明=マスコットカプセルってことになりそうですかね。

    >>455
    リファレンス見てみたが、なかったっぽい。調べ方変かも…

457 :デフォルトの名無しさん [sage] :2008/04/30(水) 21:22:14
    >>453
    メッシュで我慢しとけ

458 :デフォルトの名無しさん [sage] :2008/04/30(水) 23:17:24
    なんか質問が来そうだから先に回り込んでおくぜ?

    Q.メッシュてなんですか?
    A.スレチですがお答えします
    以下のように配色することでドット単位で透過する方法です
    ■通常色
    □透過色
    ■□■□■□
    □■□■□■
    ■□■□■□
    大概はドッターさんにメッシュでよろで通じるはずです
    通じないなら調教してあげてください

459 :デフォルトの名無しさん [sage] :2008/05/01(木) 02:58:12
    98の頃みたいだな・・・

460 :デフォルトの名無しさん [sage] :2008/05/01(木) 13:36:05
    >>456
    半透明?輝度を落とすってこと?
    それならなんかAPIがあった様な気がする(BREW4.0だったけど……)
    網掛けは綺麗じゃないんで使わなかったなぁ。


461 :デフォルトの名無しさん [sage] :2008/05/01(木) 14:07:59
    >>460
    半透明がどんなものか理解してないなら黙ってろw


462 :デフォルトの名無しさん [sage] :2008/05/01(木) 15:39:42
    >>461
    透過している状態だと思ったけど?

    アプリ描画領域いっぱいのwidgetを用意して、
    Zオーダーで最前面に来るように設定して、
    50%透過でもしてやればいけると思ったんだけどなぁ。

463 :453 :2008/05/01(木) 15:44:05
    亀レスすいません。皆様ご返答ありがとうございました。
    これで胸を張って、上司に「そんなこと無理ですよ、メッシュのドットを用意してくれ!」と言えますかねw(危険…


464 :デフォルトの名無しさん [sage] :2008/05/01(木) 19:23:52
    しっかし、そんなにDIBの半透過処理って重いかな?
    確かに通常の転送と比較すればずいぶん重いけど、画面全体に処理をかけるということでもなければ十分な速度って認識なんだけどなあ。

465 :デフォルトの名無しさん [sage] :2008/05/01(木) 23:30:53
    >>462
    メッシュしか知らないジジイなんだから気にすんな

466 :デフォルトの名無しさん [sage] :2008/05/01(木) 23:49:30
    確かにwidget使えばどうにでもなりそうだな

467 :デフォルトの名無しさん [sage] :2008/05/02(金) 02:22:24
    >>463
    本当にメッシュ用意させたら
    次から仕事無いかもw

468 :デフォルトの名無しさん [sage] :2008/05/02(金) 08:46:35
    50%の透過でよければ、DIBでいけるんじゃ?
    処理領域の広さや再描画間隔にもよるだろうけど・・・
    BREW2.1時代からやってるけど、そんなに重くはならないよ

469 :デフォルトの名無しさん [sage] :2008/05/02(金) 08:49:33
    α=0.5固定なら軽いよな

470 :デフォルトの名無しさん [sage] :2008/05/02(金) 09:23:38
    リアルタイム処理が必要でないなら、DIBで1ドットずつごりごり処理すればいいし
    50%ならマスクとシフト演算で済むから結構早いよな

471 :デフォルトの名無しさん [sage] :2008/05/02(金) 21:06:40
    >>470
    シフト演算を使ったコードはどう書けば良いのでしょうか?
    サンプルコード等ありませんか?

472 :デフォルトの名無しさん [sage] :2008/05/02(金) 23:35:56
    流石にそれくらい自力でできないと、プログラマとしてまずいと思うぞ・・・

473 :デフォルトの名無しさん [sage] :2008/05/02(金) 23:48:11
    ここまで使えない奴がBREWに来るようになったか・・・

474 :デフォルトの名無しさん [sage] :2008/05/03(土) 00:56:37
    やっと検証システムに価値がでてきそうだな

475 :デフォルトの名無しさん [sage] :2008/05/03(土) 02:19:44
    結局、463は上司になんて言ったんだろう……

BREW で実際にアルファブレンド使いまくってゲームを作っていた自分からすると >>464 さんと同じ意見で、テーブルさえ使えばそんなに重いとは思っていません。
id:melpon:20060419 みたいな感じで実際のコードを書きました。


で、アルファ値が 50% なら RGB 全てに対して同時に演算することが出来るので、テーブルを使うよりもさらに高速な転送が可能です。
ということで RGB565 で半分にするコード。

word& s = *(word*)&pal[src[x]];
word& d = *(word*)&dst[x];
d = (s & d) + (((s ^ d) & 0xf7de) >> 1);

参照にしてるので遅くなりそうですが、きっとそこは最適化されるはず。


あと更に高速化したい場合ですが、転送ループの中ではアルファ値が変更しないので、テーブルの持ち方を少々変更することで少しだけ速くなります。

byte** m_pTable;

m_pTable = new byte*[32];
for (int a = 0; a < 32; a++)
{
    m_pTable[a] = new byte[32 * 32];
    for (int s = 0; s < 32; s++)
        for (int d = 0; d < 32; d++)
            m_pTable[a][(s << 5) | d] = (s * a + d * (31 - a)) >> 5;
}

こんな風にテーブルを作っておいて、

    byte* tbl = m_pTable[alpha];
    dst = (word*)((byte*)dst + dx * sizeof(word) + dy * dp);
    src = (byte*)((byte*)src + sx * sizeof(byte) + sy * sp);

    for (int y = 0; y < h; y++)
    {
        for (int x = 0; x < w; x++)
        {
            if (src[x] != key)
            {
                word& s = *(word*)&pal[src[x]];
                word& d = *(word*)&dst[x];
                d = (tbl[((s >>  6) & 0x03e0) | ((d >> 11)         )] << 11) | // R
                    (tbl[((s >>  1) & 0x03e0) | ((d >>  6) & 0x001f)] <<  6) | // G
                    (tbl[((s <<  5) & 0x03e0) | ((d      ) & 0x001f)] <<  0);  // B
            }
        }
        dst = (word*)((byte*)dst + dp);
        src = (byte*)((byte*)src + sp);
    }

こうやって転送します。
アルファ値で OR 演算をする必要が無くなるので、少しだけ高速化が期待できます。
ただ、こうすると汎用性が低くなる(例えばアルファ矩形転送では遅くなる)ので、別のテーブルを作る羽目になってメモリに負担が掛かるかもしれません。
今の機種なら問題ないと思いますが。


あと、例えばバイナリの容量が少々大きくなってもいいというのであれば、テンプレートを使う方法があります。
こうすると、特殊な値の場合のみ転送方法を変更することができます。
本当は 15.5 が中央の値なのでちょっとばかし誤差が出るのですが、とりあえず 15 を 50% として扱うことにします。

template<int TAlpha>
struct Blt
{
    static void ColorKeyAlpha(
        word* dst,      // 転送先画像
        int dx,         // 転送先 X 座標
        int dy,         // 転送先 Y 座標
        int dp,         // 転送先 pitch
        byte* src,      // 転送元画像(8bit index)
        int sx,         // 転送元 X 座標
        int sy,         // 転送元 Y 座標
        int sp,         // 転送元 pitch
        int w,          // 転送元 width
        int h,          // 転送元 height
        word* pal,      // パレット
        uint32 key)     // 透過インデックス
    {
        byte* tbl = m_pTable[TAlpha];
        dst = (word*)((byte*)dst + dx * sizeof(word) + dy * dp);
        src = (byte*)((byte*)src + sx * sizeof(byte) + sy * sp);

        for (int y = 0; y < h; y++)
        {
            for (int x = 0; x < w; x++)
            {
                if (src[x] != key)
                {
                    word& s = *(word*)&pal[src[x]];
                    word& d = *(word*)&dst[x];
                    d = (tbl[((s >>  6) & 0x03e0) | ((d >> 11)         )] << 11) | // R
                        (tbl[((s >>  1) & 0x03e0) | ((d >>  6) & 0x001f)] <<  6) | // G
                        (tbl[((s <<  5) & 0x03e0) | ((d      ) & 0x001f)] <<  0);  // B
                }
            }
            dst = (word*)((byte*)dst + dp);
            src = (byte*)((byte*)src + sp);
        }
    }
};

// アルファ値 15 専用ルーチン
template<>
struct Blt<15>
{
    static void ColorKeyAlpha(
        word* dst,      // 転送先画像
        int dx,         // 転送先 X 座標
        int dy,         // 転送先 Y 座標
        int dp,         // 転送先 pitch
        byte* src,      // 転送元画像(8bit index)
        int sx,         // 転送元 X 座標
        int sy,         // 転送元 Y 座標
        int sp,         // 転送元 pitch
        int w,          // 転送元 width
        int h,          // 転送元 height
        word* pal,      // パレット
        uint32 key)     // 透過インデックス
    {
        dst = (word*)((byte*)dst + dx * sizeof(word) + dy * dp);
        src = (byte*)((byte*)src + sx * sizeof(byte) + sy * sp);

        for (int y = 0; y < h; y++)
        {
            for (int x = 0; x < w; x++)
            {
                if (src[x] != key)
                {
                    word& s = *(word*)&pal[src[x]];
                    word& d = *(word*)&dst[x];
                    d = (s & d) + (((s ^ d) & 0xf7de) >> 1);
                }
            }
            dst = (word*)((byte*)dst + dp);
            src = (byte*)((byte*)src + sp);
        }
    }
};

あとはこれを実体化すればいいと。

void ColorKeyAlpha(
    word* dst,      // 転送先画像
    int dx,         // 転送先 X 座標
    int dy,         // 転送先 Y 座標
    int dp,         // 転送先 pitch
    byte* src,      // 転送元画像(8bit index)
    int sx,         // 転送元 X 座標
    int sy,         // 転送元 Y 座標
    int sp,         // 転送元 pitch
    int w,          // 転送元 width
    int h,          // 転送元 height
    word* pal,      // パレット
    uint32 key,     // 透過インデックス
    int alpha)      // アルファ値(0〜31)
{
    switch (alpha)
    {
        case 0: Blt<0>::ColorKeyAlpha(dst, dx, dy, dp, src, sx, sy, sp, w, h, pal, key); break;
        ...
        case 15: Blt<15>::ColorKeyAlpha(dst, dx, dy, dp, src, sx, sy, sp, w, h, pal, key); break;
        ...
        case 31: Blt<31>::ColorKeyAlpha(dst, dx, dy, dp, src, sx, sy, sp, w, h, pal, key); break;
    }
}

こんな感じになります。
あとは更に最適化出来そうな値があれば、それぞれを特殊化して高速化すればいいかと。