DirectXでBitmapを表示

Windows

VC++(Win32)とDirectXを使ってBitmapを表示するプログラム。
画像をパタパタ切り替えるプログラムが必要だったので雛形として作ってみた。

今回、DirectXを使ったのは、Windows環境で画像をパタパタ切り替えるときに、VSYNCを使えばチラつきがないと思ったから。
そこまで行くのは先が長そうですが・・・。

環境

  • WindowsXP Pro SP3
  • Visual C++ 2008 SP1
  • DirectX SDK (June 2008)

スナップショット

プロジェクトの設定

文字コード設定は、
・「プロジェクト」→「プロパティ」→「構成プロパティ」→「全般」→「文字セット」
・「マルチバイト文字セットに設定する」、又は「設定なし」に設定する。

その他

  • 24bit Bitmap(1024×768など)を準備する。
  • Picture Controlのサイズは適当に決めているので、表示すると画像の縦横比が滅茶苦茶(T_T)
  • 表示Windowのサイズはヘッダファイルで固定。
  • 「pragma」で指定している「ddraw.lib」のPathは適宜変更する。
  • 画面4分割で4枚を表示。
  • 画像のルーレットなどをやりたいので余計なコードが入っている。
  • win32で作っているのでrc、cpp、hファイルがあればコンパイラのバージョンアップや移行も簡単。
  • http://homepage1.nifty.com/MADIA/vc/vc_bbs/200605/200605_06050028.html

ソース

//
// Windows and DirectX 2D
//
// 2008.12.16 naonao
//

// バージョン
char g_SystemVersion[128] = "DirectX 2D Sample ver.0.0.7 (o^-')b";

// セキュア関数「_s」の警告を抑制
#pragma warning(disable : 4996)

// #pragma警告を抑制
/#pragma warning(disable : 4995)

// Libリンク
#pragma comment(lib, "comctl32.lib")
#pragma comment(lib, "vfw32.lib")
#pragma comment(lib, "C:\\Program Files\\Microsoft DirectX SDK (June 2008)\\Lib\\x86\\ddraw.lib")

#include <windows.h>
#include <shlobj.h> // 選択ダイアログ
#include <stdio.h>
#include <process.h>
#include <dshow.h>
#include <vfw.h>
#include "resource.h"
#include "dx2d.h"

//
// メイン
//
int PASCAL WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
	g_hInst = hInstance;

	DialogBox( hInstance, MAKEINTRESOURCE( IDD_DIALOG ), NULL, ( DLGPROC )Dlgproc );
	return 0;
}

//
// アプリケーションダイアログ
//
LRESULT CALLBACK Dlgproc( HWND hwnd, UINT mes, WPARAM wParam, LPARAM lParam )
{
	int i, r;

	switch ( mes )
	{
		case WM_INITDIALOG:
				InitDialog( hwnd );
				break;
		case WM_TIMER:
				break;
		case WM_COMMAND:
			switch ( LOWORD( wParam ) )
			{
				case IDC_TEXTDRAW:
					TextDraw("テキスト描画(/ω・\)");
					return TRUE;
				case IDC_DXWINDOW:
					On_WindowShowDirectX( hwnd );
					return TRUE;
				case IDC_DXBITMAP1:
					On_DrawBitmap( hwnd, 0, IDC_SMALLFIG0 );
					return TRUE;
				case IDC_DXBITMAP2:
					On_DrawBitmap( hwnd, 1, IDC_SMALLFIG1 );
					return TRUE;
				case IDC_DXBITMAP3:
					On_DrawBitmap( hwnd, 2, IDC_SMALLFIG2 );
					return TRUE;
				case IDC_DXBITMAP4:
					On_DrawBitmap( hwnd, 3, IDC_SMALLFIG3 );
					return TRUE;
				case IDC_EXIT:
					r = MsgExit("終了しますか?");
					if ( r == IDNO )
					{
						break;
					}
					PostQuitMessage( 0 );
					return TRUE;
			}
			break;
		case WM_PAINT :
			// 確認用の小さい画像の再描画
			if ( g_hDirectX != NULL )
			{
				for ( i=0; i < VIEWBITMAP_MAX; i++ )
				{
					BitBlt( g_hdcViewSmall[i], 0, 0, g_sx, g_sy, g_hdcMemSmall[i], 0, 0, SRCCOPY );
				}
			}
			break;
		// 右上の【X】ボタン
		case WM_CLOSE:
			r = MsgExit("終了しますか?");
			if ( r == IDNO )
			{
				break;
			}
			PostQuitMessage( 0 );
			return TRUE;
		// 終了処理
		case WM_DESTROY:
			ReleaseResource();
			// COM終了処理(ファイル選択ダイアログ用)
			CoUninitialize();
			EndDialog( hwnd, FALSE );
			PostQuitMessage( 0 );
			return TRUE;
	}
	return FALSE;
}

//
// DirectX用Windownのメッセージ処理
//
LRESULT CALLBACK DXproc( HWND hwnd, UINT mes, WPARAM wParam, LPARAM lParam )
{
	switch ( mes )
	{
		case WM_COMMAND:
			break;
		case WM_DESTROY :
			break;
		case WM_MOVING :
			break;
		case WM_PAINT :
			if ( g_hDirectX != NULL )
			{
				BitBlt( g_hdcViewDX, 0, 0, DX_XSIZE, DX_YSIZE, g_hdcMemDX, 0, 0, SRCCOPY );
				g_dxwin.length = sizeof( WINDOWPLACEMENT );
				GetWindowPlacement( g_hDirectX, &g_dxwin );
			}
//			else
//			{
//				BitBlt( g_hdcViewDX, 0, 0, DX_XSIZE, DX_YSIZE, g_hdcMemDX, 0, 0, BLACKNESS );
//			}
			break;
		case WM_LBUTTONDOWN :
			MsgDebug("右クリック");
			break;
		case WM_RBUTTONDOWN :
			MsgDebug("左クリック");
			break;
	}

	return DefWindowProc( hwnd, mes, wParam, lParam );
}

//
// ダイアログ作成時の初期化
//
void InitDialog( HWND hwnd )
{
	int ret;

	// 親ダイアログHandle
	g_hParent = hwnd;

	// タイトルバーのバージョン番号表示
	SetWindowText( hwnd, (LPCSTR)g_SystemVersion );

	// COM初期化(ファイル選択ダイアログ用)
	CoInitialize( NULL );

	// DirectX初期化
	DirectDrawCreate( NULL, &g_pdx, NULL );

	// 表示用DCの初期化
	InitViewDC( hwnd );

	// DirectX用Bufferの確保
	ret = GetImageBuffer( &g_dxbuf );
	if ( ret == FALSE )
	{
		return;
	}

	// 確認用の小さい画像の設定
	g_SmallFigRect.length = sizeof( WINDOWPLACEMENT );
	// 他3個も同じなので省略
	GetWindowPlacement( GetDlgItem( hwnd, IDC_SMALLFIG0 ), &g_SmallFigRect );
	g_sx = g_SmallFigRect.rcNormalPosition.right  - g_SmallFigRect.rcNormalPosition.left;
	g_sy = g_SmallFigRect.rcNormalPosition.bottom - g_SmallFigRect.rcNormalPosition.top;
//	RECT rc;
//	GetWindowRect( hwnd, &rc );
//	sx = rc.right - rc.left;
//	sy = rc.bottom - rc.top;
//	hdcview = GetDC( hwnd );

	// 変数の初期化
	g_hbmpDX    = NULL;
	g_hdcViewDX = NULL;
	g_hdcMemDX  = NULL;
	g_hDirectX  = NULL;
	g_dxposx    = 0;
	g_dxposy    = 0;

	// ボタンの無効化
	HWND bt1 = GetDlgItem( hwnd, IDC_DXBITMAP1 );
	HWND bt2 = GetDlgItem( hwnd, IDC_DXBITMAP2 );
	HWND bt3 = GetDlgItem( hwnd, IDC_DXBITMAP3 );
	HWND bt4 = GetDlgItem( hwnd, IDC_DXBITMAP4 );
	HWND bt5 = GetDlgItem( hwnd, IDC_TEXTDRAW );
	EnableWindow( bt1, FALSE );
	EnableWindow( bt2, FALSE );
	EnableWindow( bt3, FALSE );
	EnableWindow( bt4, FALSE );
	EnableWindow( bt5, FALSE );
}

//
// 配列確保
//
int GetImageBuffer( unsigned char **buf )
{
	*buf = ( unsigned  char * )malloc( IMG_BUFSIZE );
	if ( *buf == NULL )
	{
		MsgDebug("Can not allocate memory. [GetImageBuffer]");
		return FALSE;
	}
	memset( *buf, 0, IMG_BUFSIZE );

	return TRUE;
}

//
// 表示用DCの初期化
//
void InitViewDC( HWND hwnd )
{
	int  i;
	HWND hwnds[ VIEWBITMAP_MAX ];
	HDC  hdc;

	// 表示用
	hdc = GetDC( g_hDirectX );
	for ( i=0; i < VIEWBITMAP_MAX; i++ )
	{
		g_hdcFigMem[i]  = CreateCompatibleDC( hdc );
		g_hbmpFigMem[i] = CreateCompatibleBitmap( hdc, DX_XSIZE, DX_YSIZE );
		SelectObject( g_hdcFigMem[i], g_hbmpFigMem[i] );
		g_hdibFig[i] = DrawDibOpen();
		DrawDibRealize( g_hdibFig[i], g_hdcFigMem[i], TRUE );
		BitBlt( g_hdcFigMem[i], 0, 0, DX_XSIZE, DX_YSIZE, g_hdcFigMem[i], 0, 0, BLACKNESS );
	}
	ReleaseDC( g_hDirectX, hdc );

	// 確認用の小さい画像(再描画用)
	// 特定のコントロールIDを列挙する方法が分かれば・・;;
	hwnds[0] = GetDlgItem( hwnd, IDC_SMALLFIG0 );
	hwnds[1] = GetDlgItem( hwnd, IDC_SMALLFIG1 );
	hwnds[2] = GetDlgItem( hwnd, IDC_SMALLFIG2 );
	hwnds[3] = GetDlgItem( hwnd, IDC_SMALLFIG3 );
	for ( i=0; i < VIEWBITMAP_MAX; i++ )
	{
		g_hdcViewSmall[i] = GetDC( hwnds[i] );
		g_hdcMemSmall[i]  = CreateCompatibleDC( g_hdcViewSmall[i] );
		g_hbmpSmall[i]    = CreateCompatibleBitmap( g_hdcViewSmall[i], DX_XSIZE, DX_YSIZE );
		SelectObject( g_hdcMemSmall[i], g_hbmpSmall[i] );
		g_DrawDIBSmall[i] = DrawDibOpen();
		DrawDibRealize( g_DrawDIBSmall[i], g_hdcMemSmall[i], TRUE );
	}
}

//
// Bitmapファイルの読み込み
//
char *FileSelectBitmap( void )
{
	static char  p[1 + FILENAME_MAX] = "\0";
	OPENFILENAME ofn;

	memset( &ofn, 0, sizeof( OPENFILENAME ) );

	ofn.lStructSize = sizeof( OPENFILENAME );
	ofn.hwndOwner   = g_hParent;
	ofn.lpstrFilter = TEXT( "Bitmap(*.bmp)\0*.bmp\0All Files(*.*)\0*.*\0\0" );
	ofn.lpstrTitle  = "Bitmapファイルの選択";
	ofn.lpstrDefExt = "bmp";
	ofn.Flags       = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
	ofn.lpstrFile   = p;
	ofn.nMaxFile    = sizeof( p );

	if ( GetOpenFileName( &ofn ) == FALSE )
	{
		return NULL;
	}
	else
	{
		return p;
	}
}

//
// Bitmap読み込み・表示
//
void On_DrawBitmap( HWND hwnd, int no, int idc )
{
	int              i, x, y, r;
	char             *fname;
	LPVOID           pbit;
	LPBITMAPINFO     pbmi;
	BITMAPFILEHEADER bmfh;
	BITMAPINFOHEADER bmih, *lpbmih;

	if ( g_hDirectX == NULL )
	{
		return;
	}

	fname = FileSelectBitmap();
	if ( fname == NULL )
	{
		OutputDebugString("FileSelectBitmap can not excute.");
		return;
	}
	OutputDebugString(fname);

	r = BitmapLoad( fname, &pbmi, &pbit, &bmfh, &bmih );
	if ( r == FALSE )
	{
		MsgDebug("BitmapLoad can not excute.");
		return;
	}

	lpbmih = &bmih;
	i      = 0;

	// ****************** 大きい画像
	if      ( no == 0 ) { x = 0;            y = 0; }
	else if ( no == 1 ) { x = DX_XSIZE / 2; y = 0; }
	else if ( no == 2 ) { x = 0;            y = DX_YSIZE / 2; }
	else if ( no == 3 ) { x = DX_XSIZE / 2; y = DX_YSIZE / 2; }

	// 描画
	r = DrawDibDraw (
//		g_hdibFig[i], g_hdcViewDX,
		g_DrawDIBDX, g_hdcViewDX,
		x, y,                       // 転送先の先頭座標
		DX_XSIZE / 2, DX_YSIZE / 2, // 転送先の幅と高さ
		lpbmih,
		pbit,               // 転送元画像データ
		0, 0,               // 転送元の先頭画素
		pbmi->bmiHeader.biWidth, pbmi->bmiHeader.biHeight, // 転送画素の行と列数
		DDF_BACKGROUNDPAL
	);
	if ( r == FALSE )
	{
		MsgDebug("DrawDibDraw can not excute.");
	}

/*
	r = BitBlt( g_hdcViewDX, 0, 0, DX_XSIZE, DX_YSIZE, g_hdcViewDX, 0, 0, SRCCOPY );
//	r = BitBlt( g_hdcFigMem[i], 0, 0, DX_XSIZE, DX_YSIZE, g_hdcFigMem[i], 0, 0, SRCCOPY );
	if ( r == FALSE )
	{
		MsgDebug("BitBlt can not excute.");
	}
*/
	// ****************** 小さい画像
	r = DrawDibDraw (
		g_DrawDIBSmall[no], g_hdcMemSmall[no],
		0, 0,       // 送信先長方形の左上角の座標
		g_sx, g_sy, // 送信先長方形の幅・高さ
		lpbmih,
		pbit,   // 転送元画像データ
		0, 0,   // 転送元の先頭画素
		pbmi->bmiHeader.biWidth, pbmi->bmiHeader.biHeight, // 転送画素の行と列数
		DDF_BACKGROUNDPAL
	);
	if ( r == FALSE )
	{
		MsgDebug("DrawDibDraw can not excute. [small]");
	}

//	r = BitBlt( hdcview, 0, 0, sx, sy,	g_hdcViewDX, 0, 0, BLACKNESS );
//	r = BitBlt( hdcview, 0, 0, sx, sy,	g_hdcFigMem[no], 0, 0, BLACKNESS );
//	r = BitBlt( hdcview, 0, 0, sx, sy,	g_hdcFigMem[no], 0, 0, SRCCOPY );
	r = BitBlt( g_hdcViewSmall[no], 0, 0, g_sx, g_sy,	g_hdcMemSmall[no], 0, 0, SRCCOPY );
	if ( r == FALSE )
	{
		MsgDebug("BitBlt can not excute. [small]");
	}

	// メモリ解放
	HeapFree( GetProcessHeap(), 0, pbit );
	HeapFree( GetProcessHeap(), 0, pbmi );
}

//
// Bitmap読み込み
//
int BitmapLoad( char *fname, LPBITMAPINFO *pbmi, LPVOID *pbit, BITMAPFILEHEADER *bmfh, BITMAPINFOHEADER *bmih )
{
	unsigned long    n;
	LPVOID           lpbit;
	LPBITMAPINFO     lpbmi;
	HANDLE           fh;

	fh = CreateFile( fname, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
	if ( fh == INVALID_HANDLE_VALUE )
	{
		OutputDebugString("Error: CreateFile bitmap file");
		return FALSE;
	}

	ReadFile( fh, bmfh, sizeof( BITMAPFILEHEADER ), &n, NULL );
	if ( bmfh->bfType != *(LPWORD)"BM" )
	{
		OutputDebugString("Not Bitmap file");
		CloseHandle( fh );
		return FALSE;
	}

	ReadFile( fh, bmih, sizeof( BITMAPINFOHEADER ), &n, NULL );
	if ( fh == FALSE )
	{
		OutputDebugString("Error: ReadFile bitmap file");
		return FALSE;
	}

	// 24bit Bitmap以外
	if ( bmih->biBitCount < 24)
	{
		OutputDebugString("Not 24bit Bitmap file");
		CloseHandle( fh );
		return FALSE;
	}

	lpbmi = ( LPBITMAPINFO )HeapAlloc( GetProcessHeap(), 0, sizeof( BITMAPINFOHEADER ) );
	lpbit = ( LPVOID )HeapAlloc( GetProcessHeap(), 0, bmfh->bfSize - bmfh->bfOffBits );

	ReadFile( fh, lpbit, bmfh->bfSize - bmfh->bfOffBits, &n, NULL);
	
	*pbmi = lpbmi;
	*pbit = lpbit;

	CloseHandle( fh );

	return TRUE;
}

//
// DirectX用のサブWinwdow表示
//
void On_WindowShowDirectX( HWND hwnd )
{
	WNDCLASSEX wc;

	// 1個だけ作成するために必要
	if ( g_hDirectX != NULL )
	{
		goto ADJ;
	}

	// DirectX用Winwdowの作成
	g_dxclass.cbSize        = sizeof( wc );
	g_dxclass.style         = CS_HREDRAW | CS_VREDRAW;
	g_dxclass.lpfnWndProc   = DXproc;
	g_dxclass.cbClsExtra    = 0;
	g_dxclass.cbWndExtra    = 0;
//	g_dxclass.hInstance     = (HINSTANCE )GetWindowLong( g_hParent, GWL_HINSTANCE );
	g_dxclass.hInstance     = g_hInst;
	g_dxclass.hIcon         = LoadIcon( NULL, IDI_APPLICATION );
	g_dxclass.hCursor       = LoadCursor( NULL, IDC_ARROW );
	g_dxclass.hbrBackground = (HBRUSH)GetStockObject( WHITE_BRUSH );
	g_dxclass.lpszMenuName  = NULL;
	g_dxclass.lpszClassName = "DirectX_VIEW";
	g_dxclass.hIconSm       = LoadIcon( NULL, IDI_APPLICATION );

	RegisterClassEx( &g_dxclass );

	g_hDirectX = CreateWindow (
		"DirectX_VIEW",
		"",
		WS_VISIBLE,
		g_dxposx, g_dxposy,
		DX_XSIZE, DX_YSIZE,
		hwnd,
		(HMENU)NULL,
		g_hInst,
		NULL
	);

	// DirectX用Winwdowを表示
	ShowWindow( g_hDirectX, SW_SHOW ); 
	UpdateWindow( g_hDirectX );

	g_hdcViewDX = GetDC( g_hDirectX );
	g_hbmpDX    = CreateCompatibleBitmap( g_hdcViewDX, DX_XSIZE, DX_YSIZE );
	g_hdcMemDX  = CreateCompatibleDC( g_hdcViewDX );

	SelectObject( g_hdcMemDX, g_hbmpDX );

	g_DrawDIBDX = DrawDibOpen();

	DrawDibRealize( g_DrawDIBDX, g_hdcMemDX, TRUE );

	// ボタンの有効化
	HWND bt1 = GetDlgItem( hwnd, IDC_DXBITMAP1 );
	HWND bt2 = GetDlgItem( hwnd, IDC_DXBITMAP2 );
	HWND bt3 = GetDlgItem( hwnd, IDC_DXBITMAP3 );
	HWND bt4 = GetDlgItem( hwnd, IDC_DXBITMAP4 );
	HWND bt5 = GetDlgItem( hwnd, IDC_TEXTDRAW );
	EnableWindow( bt1, TRUE );
	EnableWindow( bt2, TRUE );
	EnableWindow( bt3, TRUE );
	EnableWindow( bt4, TRUE );
	EnableWindow( bt5, TRUE );

	return;

// 表示位置の調整
ADJ:
	g_dxwin.length = sizeof( WINDOWPLACEMENT );

	g_dxwin.rcNormalPosition.left   = 0;
	g_dxwin.rcNormalPosition.top    = 0;
	g_dxwin.rcNormalPosition.right  = DX_XSIZE;
	g_dxwin.rcNormalPosition.bottom = DX_YSIZE;

	SetWindowPlacement( g_hDirectX, &g_dxwin );
	GetWindowPlacement( g_hDirectX, &g_dxwin );

	g_dxposx = g_dxwin.rcNormalPosition.left;
	g_dxposy = g_dxwin.rcNormalPosition.top;

	return;
}

//
// テキストの描画
//
void TextDraw( char *buf )
{
	int   x, y, len;
	RECT  rc;
	HFONT hf;

	x = ( DX_XSIZE - VIEW_XSIZE ) / 2;
	y = ( DX_YSIZE - VIEW_YSIZE ) / 2;

/*
	// 四角形
	rc.left   = x - 10; 
	rc.top    = y - 30;
	rc.right  = x + VIEW_XSIZE + 10; 
	rc.bottom = y + VIEW_YSIZE + 10; 
	DrawEdge( g_hdcViewDX, &rc, EDGE_BUMP, BF_RECT );
*/

	// テキスト
	hf = CreateFont (
		60, 30, 0, 0, 700,
		FALSE, FALSE, FALSE,
		SHIFTJIS_CHARSET,
		OUT_OUTLINE_PRECIS,
		CLIP_DEFAULT_PRECIS,
		ANTIALIASED_QUALITY,
		DEFAULT_PITCH | FF_DONTCARE,
		NULL
	);
	SelectObject( g_hdcViewDX, hf );

	rc.left   = x;
	rc.top    = 10;
	rc.right  = DX_XSIZE; 
	rc.bottom = y; 

	len = ( int )strlen( buf );

	SetTextColor( g_hdcViewDX, RGB( 255, 0, 0 ) );
	SetBkColor( g_hdcViewDX, RGB( 255, 255, 255 ) );
	DrawText( g_hdcViewDX, buf, len, &rc, DT_SINGLELINE );

	DeleteObject( hf );
}

//
// リソース解放
//
void ReleaseResource( void )
{
	int i;

	if ( g_hdcViewDX != NULL )
	{
		DeleteDC( g_hdcMemDX );
		DrawDibClose( g_DrawDIBDX );
		DeleteObject( g_hdcMemDX );
		ReleaseDC( g_hDirectX, g_hdcViewDX );
	}

	for ( i=0; i < VIEWBITMAP_MAX; i++ )
	{
		DrawDibClose( g_hdibFig[i] );
		DeleteObject( g_hbmpFigMem[ i] );
		DeleteDC( g_hdcFigMem[i] );

		DrawDibClose( g_DrawDIBSmall[i] );
		DeleteObject( g_hbmpSmall[i] );
		DeleteDC( g_hdcMemSmall[i] );
		ReleaseDC( g_hSmall[i], g_hdcViewSmall[i] );
	}
	
	g_pdx->Release();

	free( g_dxbuf );
}

Comments