この記事では、これがどのように可能かを説明します。
まず、Windows Mobileを搭載したほとんどのデバイスには、65,000色の画面があります。 つまり、画面上の各ピクセルに対して、2バイトがメモリに割り当てられます。 次に、このようなデバイスには32ビットプロセッサが搭載されています。 このようなプロセッサでは、2バイトの数値で数学演算を実行する速度は、4バイトの数値で作業する速度とはわずかに異なります。 これが最適化計算の1つです。 グラフィックライブラリは、一度に2ピクセルを処理します。
16ビットピクセルの仕組みを見てみましょう。 上位5ビットは赤用に、次に6ビットは緑用に、残りの5ビットは青用に予約されています。
P = [RRRR RGGG GGGB BBBB] 15 8 7 0
同時に、色自体は、式に従ってシフトとマスクを使用して取得できます。
int R = (P >> 11) & 0x1f; int G = (P >> 5) & 0x3f; int B = P & 0x1f;
ピクセルは、逆変換によって取得されます。
unsigned short P = (R << 11) + (G << 5) + B;
透明度のあるピクセルを別のピクセルの上に描画しようとすると、色の混合が発生します。 両方のピクセルは、赤、青、緑の3つのコンポーネントに分かれています。 次に、コンポーネントが混合し、赤が赤と混合し、青が青と混合し、緑が緑と混合します。 そして、取得した値から新しいピクセルがコンパイルされます。
一般に、色の混合は次のようになります。
C = C1*α + C2*(1 - α)
C1は、最初のピクセルの赤、緑、または青の値です。
C2は、2番目のピクセルの同じ色の値です。
Cは結果の色です。
α-透明度係数、0〜1の値を取ります。
特にハンドヘルドコンピュータでは、αの実際の値を保存して操作するのは非常に高価なので、整数の範囲に制限されます。 通常、値0〜255が使用されますが、5ビットカラーには5ビットαで十分です。
まず、50%の透明度で色の混合が行われる方法に注意してください。
C = C1/2 + C2/2
2による除算は、シフトに置き換えることができます。
C = (C1 >> 1) + (C2 >> 1)
次に、2つのピクセルを1対1で混合したときに何が起こるかを見てみましょう。
P = (R1 >> 1 + R2 >> 1) << 11 + (G1 >> 1 + G2 >> 1) << 5 + (B1 >> 1 + B2 >> 1)
取得する括弧を展開します。
P = (P1 & 0xf7de) >> 1 + (P2 & 0xf7de) >> 1
0xf7deのマスクは、各色成分の1シフトが正しいことを確認するために表示されます。 比較する:
[RRRR RGGG GGGB BBBB] = P [0RRR RRGG GGGG BBBB] = P >> 1 // [RRRR RGGG GGGB BBBB] = P [1111 0111 1101 1110] = 0xf7de [RRRR 0GGG GG0B BBB0] = P & 0xf7de // [0RRR R0GG GGG0 BBBB] = P & 0xf7de >> 1
この方法と同様に、ピクセル1から3、1から7を混合するために同じ操作を行うことができます。しかし、これらの点で、この方法は完全に無効です。 したがって、まず乗算の余地を作る必要があります。 mビットの符号なし数値にnビットを掛けると、m + nビット以下を占める数値が得られることに注意してください。 つまり、各色の前に5ビットを解放する必要があります。そのためには、ピクセルの色を偶数と奇数に分けて、それらを既に操作することができます。 そこで、ピクセルごとに2つの乗算を使用して、次のブレンド手順に進みました。
#define Shift(p) ((p)>>5) #define OddCol(p) ((p) & 0x07E0F81F) #define EvenCol(p) ((p) & 0xF81F07E0) // 2 register unsigned int p1 = *dst; register unsigned int p2 = *(src++); // 4 , 2 *(dst++) = OddCol( Shift(OddCol(p1)*a + OddCol(p2)*(32 - a)) ) | EvenCol( Shift(EvenCol(p1))*a + Shift(EvenCol(p2))*(32 - a) );
もう1つの乗算を取り除く方法は? 括弧を開いて用語を並べ替えてみましょう。
C = (C1*α + C2*(32 - α)) >> 5 = (C1 - C2)*α >> 5 + C2
ただし、括弧内に負の数が表示される場合があり、負の数の算術演算はオーバーフローに基づいています。 したがって、この形式の式を計算の並列化に適用することはできません。 したがって、可能な最大値を追加して負の値を取り除きます。
C = (C1 - C2 + 32 - 32)*α >> 5 + C2 = (C1 - C2 + 32)*α >> 5 + C2 - α
この式と偶数色と奇数色のトリックを使用すると、ピクセルごとに1つの乗算のみを使用するピクセル混合手順を取得できます。
#define OddCol(p) ((p) & 0x07E0F81F) #define EvenCol(p) ((p) & 0xF81F07E0) register unsigned int p1 = *dst; register unsigned int p2 = *(src++); register unsigned int oddA = (a<<22) | (a<<11) | (a); register unsigned int evenA = (a<<27) | (a<<16) | (a<<6); register unsigned int oddP2 = OddCol(p2); register unsigned int evenP2 = EvenCol(p2); // 2 2 oddCol = (((OddCol(p1) - oddP2 + 0x08010020) * a) >> 5) + oddP2 - oddA; evenCol = ((( (EvenCol(p1)>>5) - (evenP2>>5) + 0x08010040) * a) + evenP2 - evenA ); *(dst++) = OddCol(oddCol) | EvenCol(evenCol);