ダブルバッファについて

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
神崎

ダブルバッファについて

#1

投稿記事 by 神崎 » 8年前

環境: win7 Visual Studio Community 2015

スレッド1
約60FPSで無効領域をつくって画面を更新させています。
方向キーの入力時にbitmapの座標を更新

mainスレッド
描画処理

困っていることは、画面のちらつきです。他のアプリにも影響がでています。
どの辺を変更したらよろしいでしょうか?

コード:

 
#include "windows.h"
#include "resource.h"
#include "stdio.h"

// プロトタイプ宣言
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
//global variable
HINSTANCE   ghInst;
HANDLE hThread; // スレッドのハンドル
HWND hWnd;	// ウインドウハンドル

// リソース50x50のビットマップ
struct bitmap {
	int width = 50;// サイズ
	int height = 50;// サイズ
	int x = 10; // 座標
	int y = 10; // 座標
};
bitmap kaeru;

//スレッド 疑似60FPS
DWORD WINAPI ThreadFunc(LPVOID arg)
{
	while (1) {
		Sleep(16);
		InvalidateRect(hWnd, NULL, TRUE);
		
		if (GetAsyncKeyState(VK_UP))
		{
			kaeru.y -= 1;
		}
		else if (GetAsyncKeyState(VK_DOWN))
		{
			kaeru.y += 1;
		}
		else if (GetAsyncKeyState(VK_LEFT))
		{
			kaeru.x -= 1;
		}
		else if (GetAsyncKeyState(VK_RIGHT))
		{
			kaeru.x += 1;
		}
	}
	return 0;
}


// エントリポイント
int WINAPI WinMain(
	HINSTANCE hInstance,// 現在のインスタンスのハンドル
	HINSTANCE hPrevInstance,// 以前のインスタンスのハンドル
	LPSTR lpCmdLine,// コマンドライン
	int nCmdShow)// 表示状態
{
	WNDCLASSEX wcex;//ウィンドウクラスの構造体
	HWND hWnd;	// ウインドウハンドル
	MSG msg;	// メッセージ構造体
	ghInst = hInstance;

	// ウィンドウクラスの構造体
	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(NULL, IDI_APPLICATION);
	wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
	wcex.lpszMenuName = NULL;
	wcex.lpszClassName = "TestApp";
	wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

	// ウィンドウの登録
	RegisterClassEx(&wcex);

	// ウィンドウを作成
	hWnd = CreateWindowEx(
		WS_EX_TOOLWINDOW,      // 拡張ウィンドウスタイル
		wcex.lpszClassName,  // 登録されているクラス名
		TEXT("Testウィンドウ名"), // ウィンドウ名
		WS_OVERLAPPEDWINDOW,        // ウィンドウスタイル
		CW_USEDEFAULT,                // ウィンドウの横方向の位置
		CW_USEDEFAULT,                // ウィンドウの縦方向の位置
		480,           // ウィンドウの幅
		360,          // ウィンドウの高さ
		NULL,      // 親ウィンドウまたはオーナーウィンドウのハンドル
		NULL,          // メニューハンドルまたは子ウィンドウ ID
		hInstance,  // アプリケーションインスタンスのハンドル
		NULL        // ウィンドウ作成データ
		);

	// ウィンドウを表示する
	ShowWindow(hWnd, nCmdShow);
	UpdateWindow(hWnd);

	DWORD dwThreadId;

	//スレッド起動
	hThread = CreateThread(
		NULL, //セキュリティ属性
		0, //スタックサイズ
		ThreadFunc, //スレッド関数
		NULL, //スレッド関数に渡す引数
		0, //作成オプション(0またはCREATE_SUSPENDED)
		&dwThreadId);//スレッドID


		// メッセージループ
	while (GetMessage(&msg, NULL, 0, 0)) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	// 戻り値を返します。
	return msg.wParam;
}


// ウインドウプロシージャ
LRESULT CALLBACK WndProc(HWND hWnd, UINT message,
	WPARAM wParam, LPARAM lParam)
{
	static HDC	hdc, hMdc;
	PAINTSTRUCT ps;
	static HBITMAP hbmp;

	// メッセージの種類に応じて処理を分岐します。
	switch (message)
	{
	case WM_DESTROY:
		// ウインドウが破棄されたときの処理
		//スレッドのハンドルを閉じる
		CloseHandle(hThread);
		PostQuitMessage(0);
		return 0;

	case WM_PAINT:

		hdc = BeginPaint(hWnd, &ps);
		//リソースからBMPを読み込む
		hbmp = LoadBitmap(ghInst, MAKEINTRESOURCE(IDB_BITMAP1));// リソース50x50のビットマップ
		hMdc = CreateCompatibleDC(hdc);
		SelectObject(hMdc, hbmp);

		BitBlt(hdc, kaeru.x, kaeru.y, kaeru.height, kaeru.width, hMdc, 0, 0, SRCCOPY);

		DeleteDC(hMdc);
		DeleteObject(hbmp);
		EndPaint(hWnd, &ps);

		break;
	}
	return DefWindowProc(hWnd, message, wParam, lParam);
}
 

だんごさん
記事: 273
登録日時: 12年前

Re: ダブルバッファについて

#2

投稿記事 by だんごさん » 8年前

スレッドから呼び出されたInvalidateRectのhWndには何も値が入っていません。
そのため、「NULL を指定すると、システムはすべてのウィンドウを無効化し、再描画し、さらにこの関数から制御が返る前に、 と の各メッセージをウィンドウプロシージャへ送信します。(InvalidateRect)」
とあるように、すべての領域を再描画させるため画面がちらつきます。

まず60FPSを出すためにスレッドは使わずにPeekMessageを使います。
ウィンドウメッセージを処理する部分を以下のようにします。

コード:

while(1) {
	if (PeekMessage(&msg,NULL,0,0,PM_NOREMOVE)) {
		if (!GetMessage(&msg,NULL,0,0))
			return msg.wParam;
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	} else {
		hoge(); /* 独自の処理 */
	}
}
そして、hogeの部分に60FPSで処理させる内容と60FPSに保つための処理を書きます。

次に、画面のちらつきとは関係ないかもしれませんが、128行目で宣言されているhbmpはstaticなのに144行目LoadBitmapで都度読み込みを行っているのは意味のない処理だと思います。
staticにするのであれば読み込みは最初の一回にし、DeleteObjectはウィンドウが消される時に呼び出してはいかがでしょう。
 Dango San

閉鎖

“C言語何でも質問掲示板” へ戻る