• ベストアンサー

GDI+で高速な描画

GDI+を利用してお絵かきツールのようなものを作成しようと思っています。 しかしdrawImage()での画面への描画が非常に遅いようで、描いてみると線がカクカクしてしまいます。 アンチエイリアスやアルファブレンドが必要なのでGDI+を利用したいのですが、どうにか高速に描画させる方法はないでしょうか? 下記は現在のソースの一部です。 static Bitmap *offscreenBitmap //描画処理はこっちに static Graphics *offscreen; static Graphics *onscreen; //画面表示用 static RECT rect; //クライアント領域 static POINTS posPts,pts; //一つ前と現在のマウス座標 static BOOL bLButtonDown; Pen nomalPen(Color(100,0,0,0), 1); //描画用ペン switch(msg){  case WM_CREATE:   GetClientRect(hWnd,&rect);   offscreenBitmap = new Bitmap(rect.right, rect.bottom); //ビットマップ生成   offscreen = new Graphics(offscreenBitmap);   offscreen->SetCompositingMode(Gdiplus::CompositingModeSourceOver);   offscreen->SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);//アンチエイリアス有効化   offscreen->Clear(Color(255,255,255)); //初期化   onscreen = new Graphics(hWnd); //ウインドウ表示用   onscreen->SetCompositingMode(CompositingModeSourceCopy);   break;  case WM_LBTTONDOWN:   bLButtonDown = TRUE;   posPts=MAKEPOINTS(lp)   break;  case WM_MOVE:   pts=MAKEPOINTS(lp)   if(bLButtonDown){    offscreen->DrawLine(&nomalPen, posPts.x, posPts.y, pts.x, pts.y);//線描画    posPts.x=pts.x;    posPts.y=pts.y;   }   InvalidateRect(hWnd,&rect,0);//ウインドウを更新   break;  case WM_PAINT:   onscreen->DrawImage(offscreenBitmap,0,0);//画面に書き出し   break; }

質問者が選んだベストアンサー

  • ベストアンサー
回答No.3

昔の絵描きツールでは一般に 1.MouseがDown->Move->UpまではキャッシュDC(GetDC())に書き出す。 2.この間描画データ(=1ストローク=座標の配列)は別途保管 3.Mouse Upで、裏DCに1ストロークを描画しなおし。 4.アンドInvalidateRectする(もちろんストロークデータを   含む矩形のみを無効化)。 5.WM_PAINTで「裏->表」転送を実行 てな感じです。最近はPCが早いのでこうなってない場合も多いです。 どこか参考になるところがあれば幸いです。

cabin_
質問者

お礼

回答ありがとうございます。 getDC()で得られるDCってことはこの場合Onscreenってことですかね。ちらつきを抑止したいのでこれは試していませんが、無効化の領域を絞ることである程度速度が改善しました。

その他の回答 (2)

回答No.2

 こんばんは。  offscreen->DrawLine(&nomalPen, posPts.x, posPts.y, pts.x, pts.y);  の代わりに  onscreen->DrawLine(&nomalPen, posPts.x, posPts.y, pts.x, pts.y);  へ直描きした場合が一番高速でした。  バックバッファ(オフスクリーン)への書き込みが相当に重たいようです。  初めてマウスを押したポイントと、離されたポイントの矩形領域を、バックバッファにストアした方が効果的かもしれません(アンドゥ・リドゥ程度ならば此れ出来そう)。  但し、リアルタイムにエフェクターを掛けながら描写をする場合は、どうしても作業用のバックバッファが必要になりそうです。  一応CachedBitmapと言うのが速いらしいのですが、  「参考資料」  http://lamoo.s53.xrea.com/develop/gdiplus/gdiplus_blt_old.html  http://lamoo.s53.xrea.com/develop/gdiplus/gdiplus_blt.html  画面に書き出す際に  onscreen->DrawImage(offscreenBitmap,0,0);  とする代わりに、こんな感じで呼び出す  CachedBitmap offcache(offscreenBitmap, onscreen);  onscreen->DrawCachedBitmap(&offcache, 0, 0);  らしいのですが、反ってスピードが落ちました・・・。  後、new Bitmap()の第3パラメータに「PixelFormat32bppRGB」とかを指定しても駄目でしょうか(少~しだけ速くなった気がした)。

cabin_
質問者

お礼

回答ありがとうございます。 元々GDIで作っていたのですがアンチエイリアスや回転処理が欲しくなったのでGDI+に切り替えようとしてのっけから躓いてました。 URLの速度比較を見る限りGDI+は圧倒的に遅いみたいですね… GDI+のメソッド云々よりもGdiplus::Bitmapが重いんですかね。GDI::DDBにGDI+のメソッドが使えればいいのに

回答No.1

GDI+を使ったことはありませんが、下記の(1)か(2)の方法で描画速度を上げられると思います。 (1) case WM_MOVE:でのInvalidateRectをやめ、代わりにonscreenにもoffscreenと同じ線描画を行う。 (2) case WM_MOVE:でのInvalidateRectで更新する領域をposPts.x, posPts.y, pts.x, pts.yの範囲にする。 case WM_PAINT:で更新を必要とする領域を取得(PAINTSTRUCT)し、その領域のみを再描画する。

cabin_
質問者

お礼

回答ありがとうございます。 描画中のちらつきは避けたかったので1の方法は用いずに2の方法を試したところかなり速度が向上しました。 GDIの描画処理自体も相当鈍重ですが画面の更新も結構リソース食うんですね

関連するQ&A