BitBltを使って画像を表示して、タイマーを使用して約100ms後に再度画像を表示しています。
時々画面更新の時、処理がしきれないのか、数ラインが一瞬白くなったりします。
これを無くす方法はないのでしょうか?
簡単な流れとしまして
BitBlt で画像を表示
InvalidateRect で更新領域の設定
UpdateWindow で画面表示の様な感じです。
アドバイス御願いします。
処理がしきれないのではなくちらつきが発生しているんだと思います。
InvalidateRect、UpdateWindowで画面更新したときWM_PAINTで
BitBltをウィンドウDCに対して複数回描画していないでしょうか?
もししているようでしたら、バックバッファ(裏画面)用にメモリDCを作成し、そこに全ての描画をして画面更新の時はバックバッファを転送してあげればよいです。
アドバスありがとうございます。
バックバッファを利用するとの事ですが、DirectDrawを使用するのでしょうか?
DirectDrawを調査した所、フルスクリーンモードでは、プライマリサーフェイスと
バックバッファをフリップしてちらつきのない描画をしていると書いてありました。
今回は、フルスクリーンでは、使用しないのでフリップは出来ないと思うのですが、そのへんについて、実際どうすれば良いか、もう少し詳しく教えて頂けると
助かります。
えーとDirectDrawは使いません。
基本的に考え方は同じなんですけどね。
WindowsAPIだけで描画する場合は初期化時(WM_CREATE)に、
1.ビットマップハンドルを作成。
2.メモリDC作成。
3.2で作成したメモリDCにビットマップハンドルを関連づける。
としてバックバッファ用のメモリDCを作成し、全てここに描画します。
(例)
初期化で、
hBackBitmap = CreateCompatibleBitmap(hdc, 640, 480);
hBackMemDC = CreateCompatibleDC(hdc);
SelectObject(hBackMemDC, hBackBitmap);
実際の描画は、
BitBlt(hBackMemDC, 0, 0, 幅、高さ、描画するメモリDC, ...);
BitBlt(hBackMemDC, 0, 0, 幅、高さ、描画するメモリDC2, ...);
BitBlt(hBackMemDC, 0, 0, 幅、高さ、描画するメモリDC3, ...);
.
.
.
と、全てバックバッファに描画してWM_PAINTでは、
BeginPaint( hWnd, &ps );
BitBlt(ps.hdc, 0, 0, 640, 480, hBackMemDC, 0, 0, SRCCOPY );
EndPaint( hWnd, &ps );
このような感じになります。
ちなみにDirectDrawでウィンドウの場合フリップではなくセカンダリ(バックバッファ)>プライマリにBltします。
また何か分らなかったら質問して下さい。
それでは。
SELNAさんのアドバイスを受けて、試してみましたが、うまく動作しないのです。
352×288ピクセルに青を連続でちらつきが無く表示しないのですが、
青い画面がでません。。。
下に、ソースを記載しますので、どこが悪いか見て頂けませんでしょうか?
よろしくおねがいします。
**********************
#include "stdafx.h"
HINSTANCE hInst; // 現在のインスタンス
HWND hWnd; // Main Window Handle
HDC hdcMem; // Memory DC
LPBYTE lpBMP; // BITMAP表示用 Bit値
DWORD tm=0; // Wait用変数
HDC hBackMemDC;
HBITMAP hBackBitmap;
ATOM MyRegisterClass( HINSTANCE hInstance );
BOOL InitInstance( HINSTANCE, int );
LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM );
LRESULT CALLBACK About( HWND, UINT, WPARAM, LPARAM );
static BitMapConfig(void); //BITMAP表示用の定義
static MainLoop(void); //MainLoop
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow )
{
MSG msg;
MyRegisterClass( hInstance );
if( !InitInstance( hInstance, nCmdShow ) )
{
return FALSE;
}
BitMapConfig(); //BITMAP表示用の定義
while (1) { // MainLoop
if (PeekMessage (&msg,NULL,0,0,PM_NOREMOVE))
{
if (!GetMessage (&msg,NULL,0,0)) // Message処理
{
return msg.wParam ;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
MainLoop();
}
}
return msg.wParam;
}
//////////////////////////
// BITMAP表示用の定義 //
//////////////////////////
BitMapConfig(void)
{
LPBITMAPINFO lpDIB;
HDC hdc; // DC
HBITMAP hBMP; // DIB Handle
lpDIB=(LPBITMAPINFO)GlobalAlloc(GPTR,352*288*3);// DIBヘッダ用メモリ確保
lpDIB->bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
lpDIB->bmiHeader.biWidth=352;
lpDIB->bmiHeader.biHeight=288;
lpDIB->bmiHeader.biPlanes=1;
lpDIB->bmiHeader.biBitCount=24;
lpDIB->bmiHeader.biCompression=BI_RGB;
lpDIB->bmiHeader.biSizeImage=0;
lpDIB->bmiHeader.biXPelsPerMeter=0;
lpDIB->bmiHeader.biYPelsPerMeter=0;
lpDIB->bmiHeader.biClrUsed=0;
lpDIB->bmiHeader.biClrImportant=0;
hdc=GetDC(hWnd); // WindowのDC(Deviceコンテキスト)を取得
// DIB とウインドウのDC からDIBSection を作成
hBMP=CreateDIBSection(hdc,lpDIB,DIB_RGB_COLORS,(void **)&lpBMP,NULL,0);
hdcMem=CreateCompatibleDC(hdc); // Memory DC を作成
SelectObject(hdcMem,hBMP); /* メモリDC にビットマップを選択 */
hBackBitmap = CreateCompatibleBitmap(hdc, 352, 288);
hBackMemDC = CreateCompatibleDC(hdc);
SelectObject(hBackMemDC, hBackBitmap);
ReleaseDC(hWnd,hdc);
return 0;
}
////////////////
// Main-Loop //
////////////////
MainLoop(void)
{
int Yline;
int Xline;
int i=1;
RECT rt;
if (GetTickCount()>tm+500)
{
tm=GetTickCount();
}
else
{
return 0;
}
for (Yline=1;Yline<=288;Yline++)
{
for (Xline=1;Xline<=352;Xline++)
{
lpBMP[(i-1)*3+0]=255;
lpBMP[(i-1)*3+1]=0;
lpBMP[(i-1)*3+2]=0;
i++;
}
}
BitBlt(hBackMemDC,0,0,352,288,hdcMem, 0, 0, SRCCOPY);
InvalidateRect(hWnd,&rt,TRUE);
UpdateWindow (hWnd); // 再描画
return 0;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
static int x,y;
HDC hdc;
switch( message )
{
case WM_CREATE:
return 0;
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
return 0;
case WM_PAINT:
hdc = BeginPaint (hWnd, &ps);
BeginPaint( hWnd, &ps );
BitBlt(ps.hdc, 0, 0, 352, 288, hBackMemDC, 0, 0, SRCCOPY );
EndPaint( hWnd, &ps );
break;
case WM_DESTROY:
PostQuitMessage( 0 );
break;
default:
return DefWindowProc( hWnd, message, wParam, lParam );
}
return 0;
}
ATOM MyRegisterClass( HINSTANCE hInstance )
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = (WNDPROC)WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, IDI_WINLOGO);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_BTNFACE+5);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = "Test";
wcex.hIconSm = LoadIcon(wcex.hInstance, NULL);
return RegisterClassEx( &wcex );
}
BOOL InitInstance( HINSTANCE hInstance, int nCmdShow )
{
hInst = hInstance; // グローバル変数にインスタンス ハンドルを保存します
hWnd = CreateWindow("Test", "TITLE", WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU, // 左のWS_*でWindowSize変更禁止
CW_USEDEFAULT, 0, 1000, 800, NULL, NULL, hInstance, NULL);
if( !hWnd )
{
return FALSE;
}
ShowWindow( hWnd, nCmdShow );
UpdateWindow( hWnd );
return TRUE;
}
ざっと見た感じ、どうやら
>InvalidateRect(hWnd,&rt,TRUE);
この部分に問題がありますね。
RECT構造体で宣言した、
>RECT rt;
の部分で矩形領域の設定がされていません。
画面全体ならInvalidateRectの第2に引数はNULLでいいと思います。
後ちょっと気になったのが、
>hdc = BeginPaint (hWnd, &ps);
>BeginPaint( hWnd, &ps );
>BitBlt(ps.hdc, 0, 0, 352, 288, hBackMemDC, 0, 0, SRCCOPY );
>EndPaint( hWnd, &ps );
BeginPaintが2回も(笑)
BeginPaintの戻り値とps.hdcは同じです。
それでは。
アドバイスのとおり修正し、描画されました。
ありがとうございました。
でも、画面更新の時に、ちらつきが時々見られてしまいます。。。
すみません。重大なところを見落としていました。
>InvalidateRect(hWnd,&rt,TRUE);
第3引数はTRUEだと更新領域の背景が削除されるのでFALSEにしてください。
元々原因はここでした。
後、関係ないですがアプリケーション終了時にメモリが解放されていません。
>HDC hdcMem; // Memory DC
>HBITMAP hBMP; // DIB Handle
>HDC hBackMemDC;
>HBITMAP hBackBitmap;
これを、WM_DESTROYなどで
DeleteDC(hdcMem);
DeleteDC(hBackMemDC);
DeleteObject(hBMP);
DeleteObject(hBackBitmap);
の順番で解放してあげて下さい。
以下のサイトはお薦めですので参考になさって下さい。
http://black.sakura.ne.jp/~third/
それでは。
無事解決できました。
SELNAさん。本当にありがとうございました。
ツイート | ![]() |