電子書籍の厳選無料作品が豊富!

MFCのMDIで、DirectXおよびWinAPIを仕様して領域に描画を行うものを作っています。

環境ですが、
VS2008
DirectX9.0
です。

子ウィンドウは4分割しており、(0,0)と(1,0)が描画領域で、(0,1)(1,1)はフォームです。
そこで、以前は各子ウィンドウごとに、デバイスを取得し、描画をおこなっていたのですが、ファイルを5個以上作成すると、WinAPIで描画されるものが表示されなくなりました。
それは、デバイスコンテキストは、5個以上もてないことが発覚したためとわかったので、デバイスは親で持つことにし、共通化することになりました。

しかし、それでは、親ウィンドウで取得しているため、描画のウィンドウサイズなどが異なるため、意図した領域にかけておりません。
そこで、各領域に再設定を行いたいのですが、どうすればよいのでしょうか?

対策として、下記のように考えたのですが、検討違いでしょうか?

・デバイスの画面の設定をResetなどをつかって、リセットし、描画領域の再設定を行う。(Resetだと、再度デバイスの取得を行うと思っているのですが、これだとファイルごとにもっているのと変わらないような気がします。)

・CreateOffscreenPlainSurface等でオフスクリーン サーフェイスを作成し、描画する。(描画の座標情報等の微調整がいるような気がします。)

・単純に再設定できるから再設定を行う。

アドバイスを御願い致します。

A 回答 (2件)

 こんばんは。


 以前の方で御礼頂きました。相当難航している様で・・・。
 一番手っ取り早いのは、#No1さんが説明されている通り、GetDC()/ReleaseDC()でもって、サーフェースからMDIウィンドウに描写してしまう事です。

 pDev->BeginScene();
 //処理
 pDev->EndScene();

 を使用すると、MDIドキュメントごとぶっ潰されてしまいます・・・。どうやら、MDIでDirect3Dを使用するのはそう容易では無いみたいです。
 で、調べまわしていたのですが、漸くサイトを発見できました。

 「SetViewportメソッドで分割」(但し事例がSDI、実験失敗)
 http://www.shader.jp/xoops/html/masafumi/directx …

 「Presentメソッドの第3パラメータにウィンドウハンドルを渡す」(此方で実験成功)
 http://monsho.hp.infoseek.co.jp/dx/dx77.html

 非常に強引ですが・・・、前回の続編的に書けば、

/////////////////////////////////////////////////////////////////////////////
// CMyMDIView クラスの描画

void CMyMDIView::OnDraw(CDC* pDC)
{
CMyMDIDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: この場所にネイティブ データ用の描画コードを追加します。

//スプライトの作成
LPD3DXSPRITE pSprite = NULL;
::D3DXCreateSprite(DirectX::g_pDEVPlan, &pSprite);

//シーン開始
DirectX::g_pDEVPlan->BeginScene();
DirectX::g_pDEVPlan->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(255, 0, 0), 1.0f, 0);

//スプライトにテクスチャを貼って描写
pSprite->Begin(D3DXSPRITE_ALPHABLEND);
pSprite->Draw(pDoc->GetTexture(), NULL, NULL, NULL, D3DCOLOR_ARGB(255, 255, 255, 255));
pSprite->End();

//シーン終了
DirectX::g_pDEVPlan->EndScene();

//第3パラメータにMDIビューのハンドルを入れる
DirectX::g_pDEVPlan->Present(NULL, NULL, this->GetSafeHwnd(), NULL);

//スプライトの開放(本来は何処か別の場所に作成して常駐させて置く)
DirectX::ReleaseCOM(pSprite);
}
    • good
    • 0

>それは、デバイスコンテキストは、5個以上もてないことが発覚したためと


>わかったので、デバイスは親で持つことにし、共通化することになりました。

DCを親で持つ必要はありません。

GetDCは、子ウィンドウごとで構いません。

但し「描画が終ったらReleaseDCですぐに解放する」と言う処理が必要です。

つまり、描画ルーチンは
  HDC hDC; /* ここだけにしかスコープを持たないauto変数にする。publicにしない */
  if ((hDC = GetDC(hWnd) != NULL) { /* 座標系はhWndで指定したウィンドゥの座標系になる */
    描画処理; /* ファイル1つに対する描画はすべてここで行う */
    if (ReleaseDC(hWnd,hDC) != 1) {
      alert("DCの解放に失敗!");
    }
  }
と言う事になります。

描画が終ったのにReleaseDCしないままだと「6回目のGetDCで失敗する」と言う事になります。

GetDCとReleaseDCがペアになっている限り、GetDCは何万回繰り返しても大丈夫です。

>しかし、それでは、親ウィンドウで取得しているため、描画のウィンドウサイズなどが異なるため、意図した領域にかけておりません。

親ウィンドゥでGetDCすると、座標系は親ウィンドゥになるので、座標(0,0)は「親ウィンドゥのクライアント描画領域の原点」になります。

なので「子ウィンドウの特定の座標が、親ウィンドゥのクライアント座標のどこに相当するかを求める必要」があります。

つまり「子のクライアント座標を親のクライアント座標に変換する必要」があるのです。

「子ウィンドゥのクライアント座標を、親ウィンドゥのクライアント座標に変換する」には、ClientToScreenとScreenToClientを使います(双方のウィンドウが同じスクリーンにある事が条件)

子ウィンドゥのクライアント座標系から、親ウィンドゥのクライアント座標系に変換するには
  POINT Po;
  Po.x = 子ウィンドゥのX座標;
  Po.y = 子ウィンドゥのY座標;
  ClientToScreen(Child_hWnd,&Po); /* 子の座標をスクリーン座標に */
  ScreenToClient(Parent_hWnd,&Po); /* スクリーン座標を親の座標に */
で行います。これでPOINT構造体のx、yに、子の座標から親の座標に変換した座標が入ります。

>対策として、下記のように考えたのですが、検討違いでしょうか?

見当違い(「検討違い」ではなく「見当違い」が正しい)

「描画の直前にGetDCし、GetDCしたらすぐに描画を行い、描画が終ったらすぐにReleaseDCする」と言うのが正しい処理。

GetDCしたデバイスコンテキストのハンドルは、保持したままにしない事。

もし、ユーザーが「画面のプロパティを変更」したりすると、保持したままのデバイスコンテキストは、無効なハンドルになってしまうでしょう。

つまり、質問者さんのように「親ウィンドゥのデバイスコンテキストのハンドルをGetDCしたまま、ずっと保持して使い回す」と、ユーザーが「画面のプロパティを変更」した瞬間、それ以降、何も描画されなくなる可能性があります(画面のプロパティの変更を検知したらReleaseDCしてGetDCし直しても良いが、それだったら、描画処理の直前にGetDCして、描画終了してからReleaseDCすれば良い筈)
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!