間が開きましたが、Direct2D版です。以下はコードの一部を抜粋して取り上げるので、完全なコードも併せて参照ください。ビルドにはMicrosoft Windows SDK for Windows 7 and .NET Framework 3.5 SP1: BETA、実行にはWindows 7 βが今のところ必要です。
HWND Create() { if (FAILED(D2D1CreateFactory( D2D1_FACTORY_TYPE_SINGLE_THREADED, &pD2DFactory))) { return 0; } return CreateWindow( reinterpret_cast<LPCTSTR>(static_cast<UINT_PTR>(wncClassAtom)), TEXT("Direct2D Test"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, 0, this); } |
ウィンドウを作るのと前後して、Direct2Dのファクトリを作る必要があります。
この例ではそれだけで済んでいますが、MSのサンプルでは、ほかのオブジェクトを作る操作を併せてCreateDeviceIndependentResourcesという名前の関数になっており、例えば、画像ファイルの読み込みなどが行われています。
HRESULT CreateDeviceResources() { HRESULT hr = S_OK; if (prthw == 0) { RECT rc; GetClientRect(hwnd, &rc); D2D1_SIZE_U size = D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top); hr = pD2DFactory->CreateHwndRenderTarget( D2D1::RenderTargetProperties(), D2D1::HwndRenderTargetProperties(hwnd, size), &prthw); if (FAILED(hr)) { return hr; } hr = prthw->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Black), &pscb); if (FAILED(hr)) { return hr; } } return hr; } |
CreateDeviceIndependentResourcesと違って、CreateDeviceResourcesではデバイスに依存するオブジェクトの生成を行っています。ここでのデバイスとは、レンダーターゲット、ここではウィンドウということになります。もう少し読めば、CreateDeviceIndependentResourcesとCreateDeviceResourcesに分かれている実務上の理由が見えてきます。
なお、CreateWindowの引数hInstanceは、Windows 2000以上の条件を当然満たすためNULLで構いません。
void OnPaint(HWND hwnd) { PAINTSTRUCT ps; BeginPaint(hwnd, &ps); OnRender(); EndPaint(hwnd, &ps); } |
WM_PAINTが来たときの処理です。BeginPaint/EndPaintは呼んでいますが、それだけです。実際の描画処理は行いません。
void OnRender() { HRESULT hr = CreateDeviceResources(); if (prthw && !(prthw->CheckWindowState() & D2D1_WINDOW_STATE_OCCLUDED)) { prthw->BeginDraw(); prthw->Clear(D2D1::ColorF(D2D1::ColorF::White)); Render(prthw); hr = prthw->EndDraw(); } if (hr == D2DERR_RECREATE_TARGET) { DiscardDeviceResources(); } } |
OnPaint内で呼んでいます。BeginDrawとEndDrawで挟んだ部分がGDIでのBeginPaintとEndPaintに相当し、つまりその中が実際の描画するコードです。prthwは、レンダーターゲット、およそデバイスコンテキストにあたるもので、CreateDeviceResourcesの中で作成しています。OnRenderが呼ばれる度にCreateDeviceResourcesも呼んでいますが、中でNULLチェックをしているので、毎回作り直されるわけではありません。
EndDrawの戻り値がD2DERR_RECREATE_TARGETだったときの処理、DiscardDeviceResourcesでは、CreateDeviceResourcesで作ったオブジェクトをすべて破棄しています。これらは次回のOnRender時に作り直されます。このために、CreateDeviceIndependentResourcesとCreateDeviceResourcesに分かれていると言った感じです。
void DiscardDeviceResources() { pscb.Release(); prthw.Release(); } |
pscbとprthwは_com_ptr_tなので、pscb->Release()などとしてはいけないことに注意です。
void OnSize(HWND hwnd, UINT /*state*/, int cx, int cy) { D2D1_SIZE_U size = {static_cast<UINT>(cx), static_cast<UINT>(cy)}; if (prthw != 0) { HRESULT hr = prthw->Resize(size); if (FAILED(hr)) { DiscardDeviceResources(); InvalidateRect(hwnd, 0, FALSE); } } } |
もう1ヶ所、D2D関連の処理を行っているのがWM_SIZEのときです。サイズ変更を伝え、エラーだったらオブジェクトを破棄して、InvalidateRectしています。OnRender内で作り直させるつもりでしょう。
ほか、ここで取り上げなかった細かいことをいくつか。
- WinMainの中でCoInitialize/CoUninitializeしています。
- 私はWM_DESTROYでDiscardDeviceResourcesなどを呼ぶべきではないかと最初思いましたが、
前述したとおり_com_ptr_tを使っているので、終了時は自動でReleaseされます。 - ウィンドウクラスの登録時、WNDCLASS(EX)のwc.hbrBackgroundはNULLにしています。背景の塗り潰しもD2Dで行うため不要なのです。具体的には、BeginDrawの直後prthw->Clear(D2D1::ColorF(D2D1::ColorF::White));で背景を塗り潰しています。
スポンサード リンク |
ABのサイトが遅いし何故か掲示板にアクセス出来ないのですが・・・
何がおきているんですか?
すみません。私もよく分からないですが、なんだか繋がらないことが多いですね。答えになっていなくて済みません……。