Dirext3DX UtilityLibrary を使う 1 初期化

DirectX7になってUtilityLibraryというものができました。6.0や6.1にもついていたのだろうか。見てないのでわからないが。

で、これはDirect3Dの初期化などが簡単にできるようになってます。えー!?なめとんのか。
じゃあ、今までやってきたのはなんだったの?

ではまずプロジェクトを作って初期化が終わるまでを作ろうかと思いましたが同じことを何度やっても徒労なので一挙にアプリのベースを作ってみましょう。
フルスクリーンとウィンドウを切り替えられるコードです。
わかりやすくするためにF9キーで切り替えるようにしてみました。

プロジェクトは空のプロジェクト。ソースを作成して、必要な処理を書きます。これは通常のWinMainがあるソースです。以下のとおり。以下のコードを貼り付けるだけで動くはず。

ついでにリンクが必要なのは d3dxd.lib 
プロジェクト>設定>リンクで追加してください。 外部参照が解決されないエラーは、たいてこれの設定を忘れている場合です。
(注)リリースをビルドする場合は d3dxd.lib ではなくて d3dx.lib をリンクするのを忘れずに。
ついでに


あたらしいプロジェクトを作成した場合はddraw.lib dxguid.lib の設定も忘れずに。
動作確認のために例の回転する3角形を表示しましょうかねー。

「外部参照が解決されていない」エラーが出る人はDirextX7への移行を読み直すように。
 

/*----------------------------------------------------------
フルスクリーン、ウィンドウ切り替えプログラム
--------------------------------------------------------------*/
#define STRICT
 
#define D3D_OVERLOADS
#include <d3dx.h>
 
#define RELEASE(x) if(x){x->Release();x=NULL;}
/*-------------------------------------------
外部変数
--------------------------------------------*/
HINSTANCE hInstApp;
HWND hwndApp;
char szAppName[] = "Direct3D IM test";
char szDevice[128], szDDDeviceName[128] = "default";
 
LPD3DXCONTEXT pD3DXC;
LPDIRECT3DDEVICE7 m_pD3DDev = NULL;
LPDIRECTDRAW7 m_pDD = NULL;
 
int WinType=0; // アプリのタイプ0=ウインドウ 1=フルスクリーン
 
// FPS計測用変数(デバッグ時のみ)
#if _DEBUG
int m_FPS = 0;
int m_FPSCount = 0;
DWORD m_FPSTimer = 0;
#endif
 
// アプリケーションの動作フラグ
bool m_bActive = false;
DWORD m_fUpdateFrame = 0; // 垂直同期を待ってフレームを更新
 
 
LRESULT CALLBACK MainWndProc(HWND hWnd,UINT msg,UINT wParam,LONG lParam);
 
// プロトタイプ宣言
 
BOOL FreeD3D(); // 取得したオブジェクトの開放
BOOL InitD3D(int type); // D3Dの初期化
 
/*-------------------------------------------
アプリケーション初期化
--------------------------------------------*/
int InitApp(HINSTANCE hInst,int nCmdShow)
{
WNDCLASS wndclass;
hInstApp=hInst;
/*ウィンドウクラスの登録*/
wndclass.hCursor =LoadCursor(NULL,IDC_ARROW);
wndclass.hIcon =NULL;
wndclass.lpszMenuName =NULL;//MAKEINTRESOURCE(IDR_MENU1);//NULL;-----(1)
wndclass.lpszClassName ="Main Window";
wndclass.hbrBackground =(HBRUSH)GetStockObject(BLACK_BRUSH);
wndclass.hInstance =hInst;
wndclass.style =CS_BYTEALIGNCLIENT|CS_VREDRAW|CS_HREDRAW;
wndclass.lpfnWndProc =(WNDPROC)MainWndProc;
wndclass.cbClsExtra =0;
wndclass.cbWndExtra =0;
if(!RegisterClass(&wndclass))
 return FALSE;
/*メインウィンドウ*/
hwndApp = CreateWindowEx(0,"Main Window",szAppName,
WS_OVERLAPPEDWINDOW,//WS_POPUP,
0,0,640,480,
(HWND)NULL,(HMENU)NULL,
hInst,(LPSTR)NULL);
ShowWindow(hwndApp,nCmdShow);
UpdateWindow(hwndApp);
return TRUE;
}
/*-------------------------------------------
終了の処理
--------------------------------------------*/
int EndApp(void)
{
 return TRUE;
}
/*-------------------------------------------
ウィンドウ処理
--------------------------------------------*/
LRESULT CALLBACK MainWndProc(HWND hWnd,UINT msg,UINT wParam,LONG lParam)
{
switch(msg){
case WM_KEYDOWN:
 switch(wParam){
 case VK_ESCAPE:
 case VK_F12:
  DestroyWindow(hWnd);
  break;
 case VK_F9: //--------------------------(2)
  if(WinType==0){
   FreeD3D();
   WinType=1;
   InitD3D(WinType);
  } else {
   FreeD3D();
   WinType=0;
   InitD3D(WinType);
  }
  break;
 default:
  break;
 }
break;
case WM_DESTROY:
 PostQuitMessage(0);
 break;
 
// ウィンドウサイズの変更
 
case WM_SIZE:
 if(pD3DXC && LOWORD(lParam)>0 && HIWORD(lParam)>0)
 {
  HRESULT hr;
  hr=pD3DXC->Resize(LOWORD(lParam),HIWORD(lParam));
  if(hr!=DD_OK){
   // エラー
  }
 }
break;
 
default:
 return DefWindowProc(hWnd,msg,wParam,lParam);
}
 return 0L;
}
 
/*-------------------------------------------
スクリーンモードが変化したときの処理
--------------------------------------------*/
bool RestoreSurface()
{
HRESULT hr;
 
// ディスプレイの協調レベルを調査
hr = m_pDD->TestCooperativeLevel();
 
// アプリケーションは排他モードに設定されているが,実際には排他モードを持っていない場合
if (hr == DDERR_NOEXCLUSIVEMODE)
{
 // 排他モードを取り戻せるまで(最大6秒)ループする.
 int count=0;
 do
 {
  Sleep(500); // 0.5秒待つ
  count += 500;
  hr = m_pDD->TestCooperativeLevel();
 } while (DDERR_NOEXCLUSIVEMODE == hr && (count <6000));
} // 協調レベルに問題ない場合
if (SUCCEEDED(hr)) { // すべてのサーフェイスをリストアする
 hr=m_pDD->RestoreAllSurfaces();
 if (SUCCEEDED(hr)){
  // ここで,サーフェイスの内容を復元する.
  // if (InitSurface()) // ←例(アプリケーションで定義した関数)
  return true; // 正常に終了
 }
}
 
// エラー発生(協調レベルに問題あり)
// InterpretError(hr);
return false;
}
 
 
/*--------------------------------------------
アイドル時の処理
--------------------------------------------*/
bool AppIdle(void)
{
/*---------------------------------
ここに描画の処理を入れます.
----------------------------------*/
 
HRESULT hr;
 
// 描画する面とZバッファをクリア
pD3DXC->Clear(D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER);
 
// 描画を開始する
hr = m_pD3DDev->BeginScene();
if (SUCCEEDED(hr))
{
// 三角形の頂点座標
static D3DVECTOR v[3] = { D3DVECTOR(0.0f, 1.0f, 0.0f), D3DVECTOR(1.0f, 0.0f, 0.0f), D3DVECTOR(-1.0f, 0.0f, 0.0f) };
 
// 描画する三角形のデータ
static D3DLVERTEX vTriangle[3] = { D3DLVERTEX(D3DVECTOR(0.0f, 0.0f, 0.0f), RGB_MAKE( 0xff, 0x00, 0x00 ), 0, 0.0f, 0.0f),
D3DLVERTEX(D3DVECTOR(0.0f, 0.0f, 0.0f), RGB_MAKE( 0x00, 0xff, 0x00 ), 0, 0.0f, 0.0f),
D3DLVERTEX(D3DVECTOR(0.0f, 0.0f, 0.0f), RGB_MAKE( 0x00, 0x00, 0xff ), 0, 0.0f, 0.0f) };
 
// 頂点を回転させる
static float m_fAngle = 0.0f; // 回転角
float fSin = (float) sin(m_fAngle);
float fCos = (float) cos(m_fAngle);
for (int i = 0; i <3; i +=1) {
 vTriangle[i].x=v[i].x * fCos - v[i].z * fSin;
 vTriangle[i].y=v[i].y;
 vTriangle[i].z=v[i].x * fSin + v[i].z * fCos + 2.5f;
} m_fAngle +=2.0f*3.141592654f / 90.0f; // 回転角を更新 // 三角形を描画する
m_pD3DDev->DrawPrimitive( D3DPT_TRIANGLELIST, D3DFVF_LVERTEX, vTriangle, 3, D3DDP_WAIT );
 
// 描画終了
m_pD3DDev->EndScene();
}
 
// FPS描画(デバッグ時のみ)
#if _DEBUG
++m_FPSCount;
if (m_FPSCount>=20)
{
 DWORD t = GetTickCount();
 m_FPS = (1000 * m_FPSCount) / (t - m_FPSTimer);
 m_FPSTimer = t;
 m_FPSCount = 0;
}
char data[32];
wsprintf(data, "FPS = %hu", m_FPS);
pD3DXC->DrawDebugText(0.0f, 0.0f, D3DRGB(0xff,0xff,0xff), data);
#endif
 
// フレーム更新
hr = pD3DXC->UpdateFrame(m_fUpdateFrame);
if (hr == DDERR_SURFACELOST || hr == DDERR_SURFACEBUSY)
{
 // サーフェイスが失われている場合の処理
 return RestoreSurface();
}
 
return SUCCEEDED(hr);
}
 
//D3Dの初期化フルスクリーン、ウィンドウ両用
BOOL InitD3D(int type)
{
HRESULT hr;
//ウィンドウ
if(type==0){
 hr=D3DXCreateContextEx(D3DX_DEFAULT, // D3DX Device またはハードウェアレベル
 0, // ウィンドウ
 hwndApp,
 NULL,
 D3DX_DEFAULT, // ビット深度(色)
 D3DX_DEFAULT, // ビット深度(アルファチャンネル)
 D3DX_DEFAULT, // ビット深度(深度バッファ)
 D3DX_DEFAULT, // ビット深度(ステンシルバッファ)
 D3DX_DEFAULT, // (バックバッファ数)
 640,//D3DX_DEFAULT, // (幅)
 480,//D3DX_DEFAULT, // (高さ)
 D3DX_DEFAULT, // (リフレッシュレート)
 &pD3DXC);

 if(hr!=DD_OK){
  return FALSE;
 }
} else {
 
 // フルスクリーン
 // if(type==1){
 hr=D3DXCreateContextEx(D3DX_DEFAULT, // D3DX Device またはハードウェアレベル
 D3DX_CONTEXT_FULLSCREEN, // フルスクリーン
 hwndApp,
 hwndApp,
 D3DX_DEFAULT, // ビット深度(色)
 D3DX_DEFAULT, // ビット深度(アルファチャンネル)
 D3DX_DEFAULT, // ビット深度(深度バッファ)
 D3DX_DEFAULT, // ビット深度(ステンシルバッファ)
 D3DX_DEFAULT, // (バックバッファ数)
 D3DX_DEFAULT, // (幅)
 D3DX_DEFAULT, // (高さ)
 D3DX_DEFAULT, // (リフレッシュレート)
 &pD3DXC);

 if(hr!=DD_OK){
  return FALSE;
 }
}
 
// 初期化したDirectDraw,Direct3Dオブジェクトを取得
m_pD3DDev = pD3DXC->GetD3DDevice();
if (m_pD3DDev == NULL)
 return FALSE;
m_pDD = pD3DXC->GetDD();
if (m_pDD == NULL)
 return FALSE;
// ディザリング有効
hr = m_pD3DDev->SetRenderState(D3DRENDERSTATE_DITHERENABLE, TRUE);
// ポリゴンを表裏とも描画する
hr = m_pD3DDev->SetRenderState( D3DRENDERSTATE_CULLMODE, D3DCULL_NONE );
// ライティング無効
hr = m_pD3DDev->SetRenderState( D3DRENDERSTATE_LIGHTING, FALSE );
// 描画面をクリアするときの色を設定
hr = pD3DXC->SetClearColor(D3DRGBA(0.3f,0.3f,0.3f,0));
return TRUE;
}
 
//D3Dの開放・・これをしないといけません
BOOL FreeD3D()
{
 // 取得したオブジェクトの開放
 RELEASE(m_pDD);
 RELEASE(m_pD3DDev);
 RELEASE(pD3DXC);
 return TRUE;
}
 
/*--------------------------------------------
メイン
---------------------------------------------*/
int APIENTRY WinMain(HINSTANCE hInst,
HINSTANCE hPrevInst,
LPSTR lpCmdLine,
int nCmdShow )
{
 MSG msg;
 if(!InitApp(hInst,nCmdShow))
  return FALSE;
 
 HRESULT hr=D3DXInitialize(); // UtilityLibraryの初期化
 if(hr!=DD_OK){
  return FALSE;
}
 
InitD3D(WinType);
m_bActive=true;
 
while(TRUE){
if(PeekMessage(&msg,0,0,0,PM_REMOVE)){
 if(msg.message == WM_QUIT)
  break;
  TranslateMessage(&msg);
  DispatchMessage(&msg);
 }
 
else if(m_bActive)
{
 // アイドル処理(画面描画)
 if (!AppIdle())
  // エラーがある場合,アプリケーションを終了する
  PostQuitMessage(0);
}
 
}
 
FreeD3D(); // 取得したオブジェクトの開放
 
EndApp();
return msg.wParam;
}
 

(2)F9でフルスクリーンとウィンドウを切り替える部分。オブジェクトを破棄して作成しなおしという荒業。これが正当な方法かどうかは不明、でもちゃんと動くので(うちのマシンでは)。動かない人はメールくれ。

うーん、何かが足りない。そうだ、メニューがないじゃん!!という方にはメニューを作ってもらいましょう。

以下製作中

MENUをつける場合は(1)の部分をメニューのID(コメントになっている)に変更します。

Win32アプリの空アプリケーションを作るとワークスペースにはクラスビューとファイルビューしかありません。メニューはリソースなので、リソースの挿入でメニューを作成します。

挿入>リソース>新規作成>メニュー を選択します。メニューには何か文字列を入れないと作成されません。テスト用になにか入れてみましょう。最初にあるのはFILEなので、File とか、ファイルとか、AAAとかでもかまいませんが。

メニューの場所をダブルクリックしてメニューアイテムプロパティダイアログを出します。ポップアップのチェックをはずしてIDにたとえば ID_MENU1 などと入力します。

メニューはできましたがハンドルの作り方は後回しなので各自調べてください。では解散。

2001-1-5

メニューの作り方は超メジャーな「猫でもわかるプログラミング」のこのページ を参照すれば
作れるので、やってみよう。

と思ったが、D3Dユーティリティライブラリには必要なものが全部そろったプロジェクトが用意されている。
それを使うと面倒な初期化などを簡単に済ますことが出来るので、次のページではそれを使用してみることにしよう。では、次へ。