Windows(というよりGDI?)でダブルバッファリングってどうするのだろ?
ダブルバッファで画面描画する
僕が今までやった事あるのはバッファを2面持って、カメラデバイスから受け取った画像をタイミングをずらしてV-RAMに直接転送するみたいな作りだったんだけど……と、半日悩んでダブルバッファリングに対応してきました……Windowsは難しいなぁ(´・ω・`)
つまりこういう事かな?表示しているバッファに対して直接描画せずに、一枚噛ませて一時描画用のバッファに対してBitmapを転送、その後表示用のバッファに転送みたいな。
上記の事を考慮した結果、このようなサンプルコードになりました。
////////////////////////////////////////////////////////////////////////////// // CSample::Render // Called when an effect should render itself to the screen. ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CSample::Render(TimedLevel *pLevels, HDC hdc, RECT *prc) { // draw using the current preset switch (m_nPreset) { case PRESET_BARS: { HDC hBackDC = NULL; HBITMAP hBackBitmap = NULL; // ダブルバッファ用の領域確保 hBackDC = CreateCompatibleDC(hdc); hBackBitmap = CreateCompatibleBitmap(hdc, prc->right, prc->bottom); HBITMAP hOldBitmap = (HBITMAP)::SelectObject(hBackDC, hBackBitmap); // DLLのリソースから「IDB_BITMAP1」を読み出す HINSTANCE hInstance = ::GetModuleHandle("sample"); HBITMAP hBitmap = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP1)); // BMPの大きさを把握 BITMAP bm = {0}; ::GetObject(hBitmap, sizeof(BITMAP), (LPVOID)&bm); // BMPを表示領域全体に合わせて転送(まだ表示はしない) HDC hMdc = ::CreateCompatibleDC(hBackDC); ::SelectObject(hMdc, hBitmap); ::StretchBlt(hBackDC, 0, 0, prc->right - prc->left, prc->bottom - prc->top, hMdc, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY ); // 一気に転送するお(^ω^) ::BitBlt(hdc, 0, 0, prc->right - prc->left, prc->bottom - prc->top, hBackDC, 0, 0, SRCCOPY); // 後始末 if(hMdc) ::DeleteObject(hMdc); if(hBitmap) ::DeleteObject(hBitmap); if(hBackBitmap) ::DeleteObject(hBackBitmap); if(hBackDC) { ::SelectObject(hBackDC, hOldBitmap); ::DeleteDC(hBackDC); } } break; } return S_OK; }
このコードを実行してみました。
はい、静止画では非常に分かりにくいですが美しく表示されております。
ただ、Renderは数十〜数百ミリ秒間隔で呼ばれているので、上記のサンプルコードのように毎回リソースの読み込みをするのはパフォーマンスに大きく影響します。
ここではサンプルコードの範囲内に収めたいのでこのようにしておりますが、実際にコードを書く際には気をつけてください。
追記
とっちゃんさんに「AddFontMemResourceEx()を使えばいいよん」と、ヒントを頂く事が出来たので、早速リソースにフォントを埋め込んで文字列を表示させてみたいと思います。でも、ちょっと大変そうなのでエントリを分けます。今日はAddFontMemResourceEx()を使える様にするところまでヽ(^o^)/
適当なパラメータを突っ込んでAddFontMemResourceEx()を呼ぶと「識別子が見当たりません」とビルドエラーが出ちゃいます。AddFontMemResourceEx()はWindows2000以降対応のWIN32APIなので、Visualizer Plug-In Wizerdから生成されたままのプロジェクトだと使用する事が出来ません。
StdAfx.h を開いて下記の定義を変更します。
#define STRICT #ifndef _WIN32_WINNT //#define _WIN32_WINNT 0x0400 #define _WIN32_WINNT 0x0500 #endif
以上で、「Windows Media Player用の視覚エフェクト(Visualizer)を作ってみるテスト」を終わらせて頂きます。