MFCでレイヤ処理
■ このスレッドは過去ログ倉庫に格納されています
0001デフォルトの名無しさん
NGNGDirectDrawや、OpenGLなどを使わないで、
C++やMFCのみでレイヤ処理のやり方を教えてください。
サンプルコードや、サンプルページを教えてください
お願い!!
0002デフォルトの名無しさん
NGNGレイヤって画像の話?
レイヤは自身でDIBを管理しなさい。
その内容を再描画の時に合成処理してDCに描きなさい。
それがもっとも簡単です。
DIBはフルカラーのみ処理するんでいいか?
まず、CDibみたいなクラスを作って、そいつがピクセルの実体を
持つ様にするだろ? で、それをリスト構造か何かで複数持てる様に
するだろ? で、再描画の時に重なっている部分の計算は、α合成で
よければ以下のように計算する。
// 1Pixelの構造体(RGBTRIPLEと一緒)
typedef strcut _PIXEL24{
unsigned char b;
unsigned char g;
unsigned char r;
}PIXEL24;
PIXEL24 AlphaBlend(PIXEL24 LowerLayer, PIXEL24 UpperLayer, int alpha)
{
PIXEL24 Result;
Result.b = (LowerLayer.b * (255 - alpha) + UpperLayer.b * alpha) / 255;
Result.g = (LowerLayer.g * (255 - alpha) + UpperLayer.g * alpha) / 255;
Result.r = (LowerLayer.r * (255 - alpha) + UpperLayer.r * alpha) / 255;
return Result;
}
もし、Pixel毎にαを持つなら、
typedef strcut _PIXEL32{
unsigned char b;
unsigned char g;
unsigned char r;
unsigned char a;//Alpha
}PIXEL32;
PIXEL32 AlphaBlend(PIXEL32 LowerLayer, PIXEL32 UpperLayer)
{
PIXEL24 Result;
Result.b = (LowerLayer.b * (255 - UpperLayer.a) + UpperLayer.b * UpperLayer.a) / 255;
Result.g = (LowerLayer.g * (255 - UpperLayer.a) + UpperLayer.g * UpperLayer.a) / 255;
Result.r = (LowerLayer.r * (255 - UpperLayer.a) + UpperLayer.r * UpperLayer.a) / 255;
return Result;
}
結果は、MemDCかなんかでバインドしたDIBに対して描画して、
それをBitBltで転送するのがいいだろうな。SetDIBitsToDeviceは
ビデオカードによってはうまく転送できないから使わない方がいいぞ。
00032
NGNG透明度を一度に簡単に処理できるぞ。また、RGBそれぞれのピクセルも
一度表をひけば、表示補正(例えばガンマとかな)をかけることも出来る。
また、α合成じゃなくてそのまま加算して飽和させれば加法混色にも
出来るし、反転させれば減法混色も出来る。まぁそこまで必要とは
思えないが、何するんだ?
0004デフォルトの名無しさん
NGNGそんなんじゃ遅くて使い物にならないだろ
LUT作ってテーブルに展開すれ
0005コスプ
NGNG0006デフォルトの名無しさん
NGNG詳細キボン
0007デフォルトの名無しさん
NGNGお察しのとおり、画像しょりです。
レイヤは6層くらいを予定しています。
何をするかというと、地図を表示して簡単なナビゲーション
みたいのを作りたいんですけど・・・・。
やっぱり、速度はいのちです。
0008デフォルトの名無しさん
NGNGLUT=Look Up Tableな
ていうか、>>2-3の方法がもろLUTのような気がするが…
>>4は目が悪いのか?
00092
NGNGそうすれば演算量は極端に減らせる気がするな。
それから、2-3はアルゴリズムの話だから、
実装する時はアセンブラ使ってね。
MMXでやれば結構速いよ。
それから、厳密な画像処理じゃなくていいんだったら、
α合成の式の/255の部分を>>8(/256ね)に置き換えて
処理しても良い。色毎に乗算が一個減るから、物すごく
効いてくるよ。
それから、CPUが物すごく速くなって、メモリが遅いこの
御時世では、LUTはなるべく使わない方が良いです。
ガンマ変換とかは、さすがに表を使わざるを得ないけど、
α合成程度の演算なら、64kbytesの表を作るより演算した方が
良いです。
それから、全部を再描画するんじゃなくて、合成した画像を
キャッシュしておいて、とりあえず再描画の指示ではそいつを
DCに転送し、レイヤ側の表示内容が変わったら、その部分の
合成画像を作り直せば結構使えると思うよ。メモリ食うけどね。
そのキャッシュ部分は、画像の表示色数に合わせればちょっとは
特するかもね。
んじゃ頑張って。
0010デフォルトの名無しさん
NGNG本当にありがとう。助かりました。
これからビシバシ地図書きます。
0011デフォルトの名無しさん
NGNG1pixごとに計算するより表引きのほうが早いでしょ?
0012デフォルトの名無しさん
NGNGDIBはを32ビットカラーにしておけば足すだけ
MMXでRGB乗算は実際にやるとパズルになって頭にくるよ<この電卓CPUめ!
00132
NGNGわかるわかる > 電卓CPU
特に、厳密な結果を導き出そうと思って、/255しようとすると、
何と難しいことか!signedだから、固定小数で逆数を掛けると
精度が足りない。unsignedの乗算もしてくれよって感じだよね。
一応、なんとかする方法を編み出したけど、MMXってタコだよね。
積和演算もヘンテコで、これをうまく使えばα合成にピッタリと
思ったけど、上記の理由でうまくいかねーんだよな。
まぁ今時SSE2を使って事なんだろうな。
00142
NGNGP6アーキテクチャに最適化してある。コメント先頭にある数字はμOP命令数。
P6のx86命令デコーダは同時に3命令をデコードできるが、デコード後のμOP
命令数が、複雑な命令(最大4μOP)は1Clockに1個しか解読できない。従って、
μOP命令数的に表現すると4-1-1の順で並んでいないと1Clockでは解読できない。
よって、この様に配置してある。また、movzxとかP5では遅くて話しにならん命令も
多用している。
それでは頑張ってね。
#インデント面倒なんで直書き。
// esi ... BGRAの順に並んだ32Bit/Pixelの画素配列(重ねる側)
// edi ... BGRAの順に並んだ32Bit/Pixelの画素配列(重ねられる側)
movzx edx, byte ptr [esi + 3] // 1 : eax = SrcのAlpha取得
mov ebx, 0x8081U // 1 : 1/255
mov ecx, 0x8081U * 0xffU // 1 : 1/255 inv
imul edx, ebx // 1 : edx = SrcTone * 0x8081(1/255)
sub ecx, edx // 1 : ecx = DstTone = (255 - a) * 0x8081 = 255 * 0x8081 - SrcTone
movzx ebx, byte ptr [esi + 0] // 1 : ebx = SrcB取得
imul ebx, edx // 1 : ebx = Fixed(SrcB * SrcTone / 255)
movzx eax, byte ptr [edi + 0] // 1 : DstB 取得
imul eax, ecx // 1 : eax = Fixed(DstB * DstTone / 255)
add eax, ebx // 1 : eax = Fixed(SrcB * SrcTone / 255 + DstB * DstTone / 255)
shr eax, 23 // 1 : eax = SrcB * SrcTone / 255 + DstB * DstTone / 255
movzx ebx, byte ptr [esi + 1] // 1 : ebx = SrcG取得
mov byte ptr [edi + 0], al // 2 : Blue格納
imul ebx, edx // 1 : ebx = Fixed(SrcG * SrcTone / 255)
movzx eax, byte ptr [edi + 1] // 1 : DstG 取得
imul eax, ecx // 1 : eax = Fixed(DstG * DstTone / 255)
add eax, ebx // 1 : eax = Fixed(SrcG * SrcTone / 255 + DstG * DstTone / 255)
shr eax, 23 // 1 : eax = SrcG * SrcTone / 255 + DstG * DstTone / 255
mov byte ptr [edi + 1], al // 2 : Green格納
movzx ebx, byte ptr [esi + 2] // 1 : ebx = SrcR取得
imul ebx, edx // 1 : ebx = Fixed(SrcR * SrcTone / 255)
movzx eax, byte ptr [edi + 2] // 1 : DstR 取得
imul eax, ecx // 1 : eax = Fixed(DstR * DstTone / 255)
add eax, ebx // 1 : eax = Fixed(SrcR * SrcTone / 255 + DstR * DstTone / 255)
shr eax, 23 // 1 : eax = SrcR * SrcTone / 255 + DstR * DstTone / 255
mov ebx, 0x8081U // 1 : 1/255
mov byte ptr [edi + 2], al // 2 : Red格納
00152
NGNG要望があれば考えるけど。
0016デフォルトの名無しさん
NGNG2さん、本当にありがとう!!いい感じに表示されています。
で、もう1個質問なんですが・・・。
地図を表示しますよね。その上にコマンドボタンを表示
したいのですが、どういう感じにすれば良いですかね?
イメージとしては、地図の上にボタンが浮いているよう
に表示したいです。(ボタンの下にも地図が描写されている)
お知恵をお願いいたしまする〜。
0017デフォルトの名無しさん
NGNG/256 を使っても精度はかなり問題ないよ。
これは超手抜きだけどコードの例。
a = [0-255]; // α値は 0-255 のいずれかの数値を取る。
if (a!=0) a+=1; // α値を 257 階調に変換する。
destR = (destR * (256-a) + srcR * a) / 256;
destG = (destG * (256-a) + srcG * a) / 256;
destB = (destB * (256-a) + srcB * a) / 256;
00182
NGNGWindowsのボタンはダメでしょう。
一番上のレイヤにボタン用のレイヤを配置して、
マウスの押下でその矩形内かどうか判別して
メッセージとばせば?
>>17
そうです。地図の表示くらいなら/256がベストだと思います。
#でもおいら画像屋なんで、誤差は許されんのです(^^;
0019デフォルトの名無しさん
NGNG0020デフォルトの名無しさん
NGNG=(a*(sR-dR)/255)+dR
ってことで前半部をテーブル化した俺って逝ってよしですか?
まともに作ると大きいから、シフトで小さくしちゃったけど
0021デフォルトの名無しさん
NGNG0022デフォルトの名無しさん
NGNG今のCPUは多少の演算量よりも下を意識した方が良いです。
・無駄なメモリアクセスを避ける
・L1キャッシュにヒットするようにする
・分岐を避ける
なのでその程度の演算に巨大なテーブルを使うことは駄目駄目です。
00232
NGNGそそ。
DOS時代からやってる人だと、表引きって常套手段だけど、
演算した方が良いんですよね〜。今時のマシンは。
乗算も速くなったし(除算はあいかわらず)。
後は少ないキャッシュをうまく使わないとね〜。
今回のα合成なんかも、処理に入る前にプリフェッチ(先読み)
しておいた方が速くなったりするからお試しアレ。
P6系ならキャッシュラインは32Bytesだから、32Bytesおきに
処理するデータの先頭データを空読みしておくのだ。
SSEや3DNow!が使えれば、prefetchという命令でキャッシュに上
げる事が出来るのでもっと効率が良いんだけどね。
#表引きするにしても、先読みは重要だよん。
■ このスレッドは過去ログ倉庫に格納されています