インデックスバッファ


番号による頂点の指定

これまでの図形は、単純な2次元的な三角形だけを表示してきました
しかし、実用的なプログラムになれば、当然複雑な図形を描くでしょう

角が4つ以上ある図形の場合、D3DPT_TRIANGLESTRIP プリミティブなどを使えば
頂点バッファによる処理でも十分対応することができますが
立方体などを複数の三角形の接合体と考えた場合、処理に無駄が発生します

立方体の一つの面は四角形であり、四角形は2つの三角形で構成されます
この時、三角形は3つの頂点で構成されるため、四角形は6つの頂点が必要になります
しかし、理屈上の四角形の頂点は4つであり、6つの頂点のうち2つは同じ値になります

このような無駄をなくすための機能がインデックスバッファです
インデックスバッファとは、頂点に対して連続した正数インデックスを割り当てます
そうすれば、複数の三角形が共有する一点を一つの数値として表すことができるため
三角形ごとに、同じ頂点を複数用意する無駄を省くことができるようになります

インデックスバッファは、頂点バッファの様に割り当てたメモリに対し
頂点バッファに対応したインデックスを表す数値配列を保存します
これらはレンタリング時に関連付けられ、指定したインデックスの範囲で描画されます

頂点バッファの各頂点にインデックスを与えるには、インデックスバッファを表す
IDirect3DIndexBuffer8 インターフェイスを作成します
作成には IDirect3DDevice8::CreateIndexBuffer() を使います
HRESULT CreateIndexBuffer(
	UINT Length , DWORD Usage,
	D3DFORMAT Format , D3DPOOL Pool,
	IDirect3DIndexBuffer8** ppIndexBuffer
);
Length には、インデックスバッファのサイズをバイト単位で指定します
Usage には、リソースの制御方法を表す定数を指定します
これには CreateVertexBuffer() メソッドの Usage 引数と同じものを指定できます

Format には、D3DFORMAT 列挙型のメンバで、バッファのフォーマットを指定します
ただし、設定できる有効な値は D3DFMT_INDEX16 か D3DFMT_INDEX32 のいずれかです
よほど膨大な情報量を扱わない限り D3DFMT_INDEX16 で十分だと考えられます

Pool には、D3DPOOL 列挙型のメンバで、有効なメモリを指定します
ppIndexBuffer には、作成したインデックスバッファを受けるポインタのポインタを指定します
メソッドが成功すれば D3D_OK、失敗すれば以下のエラー値のいずれかが返ります

定数解説
D3DERR_INVALIDCALL メソッドの呼び出しが無効である
D3DERR_OUTOFVIDEOMEMORY 十分なディスプレイメモリが存在しない
D3DXERR_INVALIDDATA データが無効である
E_OUTOFMEMORY 十分なメモリを割り当てることができない

インデックスバッファは、頂点バッファと同様の方法で値を設定できます
すなわち IDirect3DIndexBuffer8::Lock() メソッドで
インデックスバッファの特定の範囲をロックし、メモリポインタを取得できます
HRESULT Lock(
	UINT OffsetToLock , UINT SizeToLock ,
	BYTE** ppbData , DWORD Flags
);
OffsetToLock はロックするインデックスデータのオフセットを
SizeToLock には、ロックするデータの範囲をそれぞれバイト単位で指定します
SizeToLock を 0 にすれば、データの最後までがロックの対象となります

ppbData には、ロックしたバッファへのポインタのポインタを指定します
Flags にはロックの方法を表すフラグを指定します
このフラグは頂点バッファの Lock() メソッドで指定するフラグと同じものです
メソッドは成功すれば D3D_OK を、そうでなければ D3DERR_INVALIDCALL を返します

データの入出力が終われば IDirect3DIndexBuffer8::Unlock() を呼び出し
頂点バッファの時と同様に、アンロックする必要があります

HRESULT Unlock();

成功すれば D3D_OK を、そうでなければ D3DERR_INVALIDCALL を返します
これで、インデックスバッファの準備は終わりました
後は、頂点バッファをレンタリング時にセットし、その後にインデックスバッファを設定します

インデックスバッファをデバイスに設定するには
IDirect3DDevice8::SetIndices() メソッドを用いて行います
HRESULT SetIndices(
	IDirect3DIndexBuffer8* pIndexData ,
	UINT BaseVertexIndex
);
pIndexData には、インデックスバッファを指定します
BaseVertexIndex は頂点インデックスのオフセット値を指定します
この値は、頂点データを参照する前にすべてのインデックスに追加されます
成功すれば D3D_OK を、そうでなければ D3DERR_INVALIDCALL を返します

これが終われば IDirect3DDevice8::DrawIndexedPrimitive() を使って
頂点バッファとインデックスバッファに基き、プリミティブをレンタリングします
HRESULT DrawIndexedPrimitive(
	D3DPRIMITIVETYPE Type ,
	UINT MinIndex , UINT NumVertices ,
	UINT StartIndex , UINT PrimitiveCount
);
Type には、描画するプリミティブを指定します
MinIndex は使用するインデックスの最小値を
NumVerticex はこのレンタリングで使用される頂点の数を指定します

StartIndex には、インデックスの中で頂点の読み取りを開始する位置を
PrimitiveCount には、レンタリングするプリミティブの数を指定します
成功すれば D3D_OK を、そうでなければ D3DERR_INVALIDCALL を返します
#include <windows.h>
#include <d3d8.h>
#include <d3dx8.h>

#define TITLE TEXT("Kitty on your lap")
#define D3DFVF D3DFVF_XYZRHW | D3DFVF_DIFFUSE

IDirect3D8 * pDirect3D;
IDirect3DDevice8 * pD3Device;
D3DPRESENT_PARAMETERS d3dpp;

typedef struct {
	float x , y , z , w;
	DWORD color;
} D3DVERTEX;

LRESULT CALLBACK WndProc(HWND hWnd , UINT msg , WPARAM wp , LPARAM lp) {
	static D3DVERTEX pt[] = {
		{10 , 10 , 0 , 1 , 0xFFFF0000} ,
		{200 , 10 , 0 , 1 , 0xFFFF00FF} ,
		{10 , 200 , 0 , 1 , 0xFFFF00FF} ,
		{200 , 200 , 0 , 1 , 0xFF0000FF}
	};
	static WORD index[] = { 0 , 1 , 2 , 3 , 2 , 1};
	BYTE *bBuf;
	static IDirect3DVertexBuffer8 *d3dvb;
	static IDirect3DIndexBuffer8 *d3dib;

	switch(msg){
		case WM_DESTROY:
			PostQuitMessage(0);
			break;
		case WM_CREATE:
			pDirect3D->CreateDevice(
				D3DADAPTER_DEFAULT , D3DDEVTYPE_HAL , hWnd ,
				D3DCREATE_SOFTWARE_VERTEXPROCESSING , &d3dpp , &pD3Device
			);

			pD3Device->CreateVertexBuffer(
				sizeof (D3DVERTEX) * 4 , 0 , D3DFVF , D3DPOOL_MANAGED , &d3dvb);
			d3dvb->Lock(0 , 0 , &bBuf , 0);
			memcpy(bBuf , pt , sizeof (D3DVERTEX) * 4);
			d3dvb->Unlock();

			pD3Device->CreateIndexBuffer(sizeof (WORD) * 6 ,
				D3DUSAGE_WRITEONLY , D3DFMT_INDEX16 , D3DPOOL_MANAGED , &d3dib);
			d3dib->Lock(0 , 0 , &bBuf , 0);
			memcpy(bBuf , index , sizeof (WORD) * 6);
			d3dib->Unlock();

			return 0;
		case WM_PAINT:
			pD3Device->Clear(0 , NULL , D3DCLEAR_TARGET ,
				D3DCOLOR_XRGB(0xFF , 0xFF , 0xFF) , 1.0 , 0);
			pD3Device->BeginScene();
			pD3Device->SetVertexShader(D3DFVF);
			pD3Device->SetStreamSource(0 , d3dvb , sizeof (D3DVERTEX));
			pD3Device->SetIndices(d3dib , 0);
			pD3Device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST , 0 , 4 , 0 , 2);
			pD3Device->EndScene();

			pD3Device->Present(NULL , NULL , NULL , NULL);
			ValidateRect(hWnd , NULL);
			break;
		case WM_SIZE:
			if(pD3Device && (wp == SIZE_RESTORED || wp == SIZE_MAXIMIZED)) {
				d3dpp.BackBufferWidth = LOWORD(lp);
				d3dpp.BackBufferHeight = HIWORD(lp);
				pD3Device->Reset(&d3dpp);

				InvalidateRect(hWnd,NULL,TRUE);
			}
			return 0;
	}
	return DefWindowProc(hWnd , msg , wp , lp);
}

int WINAPI WinMain(HINSTANCE hInstance , HINSTANCE hPrevInstance ,
				   LPSTR lpCmdLine,int nCmdShow) {
	MSG msg;
	HWND hWnd;
	WNDCLASS winc;
	D3DDISPLAYMODE dmode;

	pDirect3D = Direct3DCreate8(D3D_SDK_VERSION);
	pDirect3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT , &dmode);

	ZeroMemory(&d3dpp , sizeof (d3dpp));
	d3dpp.Windowed = TRUE;
	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
	d3dpp.BackBufferFormat = dmode.Format;
	d3dpp.BackBufferCount = 1;

	winc.style			= CS_CLASSDC;
	winc.lpfnWndProc	= WndProc;
	winc.cbClsExtra		= winc.cbWndExtra		= 0;
	winc.hInstance		= hInstance;
	winc.hIcon			= LoadIcon(NULL , IDI_APPLICATION);
	winc.hCursor		= LoadCursor(NULL,IDC_ARROW);
	winc.hbrBackground	= (HBRUSH)GetStockObject(WHITE_BRUSH);
	winc.lpszMenuName	= NULL;
	winc.lpszClassName	= TEXT("KITTY");

	if(!RegisterClass(&winc)) return 0;

	hWnd = CreateWindow(TEXT("KITTY") , TITLE ,
		WS_OVERLAPPEDWINDOW | WS_VISIBLE , 
		CW_USEDEFAULT , CW_USEDEFAULT , CW_USEDEFAULT , CW_USEDEFAULT ,
		(HWND)NULL,(HMENU)NULL , hInstance , (LPSTR)NULL);

	while (GetMessage(&msg , NULL , 0 , 0 )) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	pDirect3D->Release();
	pD3Device->Release();
	return msg.wParam;
}


このプログラムを実行すると、上の図のような四角形が描画されます
この四角形は、2つの三角形で成り立っていて、紫色のラインでそれを確認できます

頂点は、長方形の各頂点を表す4つの点から成り立っています
これらに 0 〜 3 までの4つのインデックスを割り当て、これを利用して描画しています
こうすれば、一つの頂点を複数の図形で共有することができます


ユーザメモリポインタを使う

最適な方法ではありませんが、バッファを用いることができないような場合
上のようなインデックスを使った処理を、アプリケーションが占有するメモリで行えます
つまり、バッファを用いずにアプリケーションが割り当てたメモリのポインタを直接使います

ユーザメモリポインタを使って頂点のインデックス処理を行うには
IDirect3DDevice8::DrawIndexedPrimitiveUP() メソッドを使います
HRESULT DrawIndexedPrimitiveUP(
	D3DPRIMITIVETYPE PrimitiveType ,
	UINT MinIndex , UINT NumVertices ,
	UINT PrimitiveCount ,
	CONST void* pIndexData , D3DFORMAT IndexDataFormat ,
	CONST void* pVertexStreamZeroData , UINT VertexStreamZeroStride
);
PrimitiveType にはプリミティブを指定します
MinIndex には、使用するインデックスの最小値を
NumVerticex はこのレンタリングで使用される頂点の数を指定します

PrimitiveCount は描画するプリミティブの数を
pIndexData は、インデックスデータが格納されている数値配列へのポインタを指定します
IndexDataFormat は、データのフォーマットを示す D3DFORMAT 列挙型メンバを指定します
これも、D3DFMT_INDEX16 か D3DFMT_INDEX32 のいずれかでなければなりません

pVertexStreamZeroData には頂点データの配列へのポインタを
VertexStreamZeroStride は、頂点でータ一つ分のサイズをバイト単位で指定します
成功すれば D3D_OK を、そうでなければ D3DERR_INVALIDCALL を返します

このメソッドを使えば、バッファを確保しなくても直接レンタリングすることができます
ただし、同時に扱うことができる頂点バッファは一つまでとなります
#include <windows.h>
#include <d3d8.h>
#include <d3dx8.h>

#define TITLE TEXT("Kitty on your lap")
#define D3DFVF D3DFVF_XYZRHW | D3DFVF_DIFFUSE

IDirect3D8 * pDirect3D;
IDirect3DDevice8 * pD3Device;
D3DPRESENT_PARAMETERS d3dpp;

typedef struct {
	float x , y , z , w;
	DWORD color;
} D3DVERTEX;

LRESULT CALLBACK WndProc(HWND hWnd , UINT msg , WPARAM wp , LPARAM lp) {
	static D3DVERTEX pt[] = {
		{10 , 10 , 0 , 1 , 0xFFFF0000} ,
		{200 , 10 , 0 , 1 , 0xFFFF00FF} ,
		{10 , 200 , 0 , 1 , 0xFFFF00FF} ,
		{200 , 200 , 0 , 1 , 0xFF0000FF}
	};
	static WORD index[] = { 0 , 1 , 2 , 3 , 2 , 1};

	switch(msg){
		case WM_DESTROY:
			PostQuitMessage(0);
			break;
		case WM_CREATE:
			pDirect3D->CreateDevice(
				D3DADAPTER_DEFAULT , D3DDEVTYPE_HAL , hWnd ,
				D3DCREATE_SOFTWARE_VERTEXPROCESSING , &d3dpp , &pD3Device
			);
			return 0;
		case WM_PAINT:
			pD3Device->Clear(0 , NULL , D3DCLEAR_TARGET ,
				D3DCOLOR_XRGB(0xFF , 0xFF , 0xFF) , 1.0 , 0);
			pD3Device->BeginScene();
			pD3Device->SetVertexShader(D3DFVF);
			pD3Device->DrawIndexedPrimitiveUP(
				D3DPT_TRIANGLELIST , 0 , 4 , 2 , index ,
				D3DFMT_INDEX16 , pt , sizeof (D3DVERTEX));
			pD3Device->EndScene();

			pD3Device->Present(NULL , NULL , NULL , NULL);
			ValidateRect(hWnd , NULL);
			break;
		case WM_SIZE:
			if(pD3Device && (wp == SIZE_RESTORED || wp == SIZE_MAXIMIZED)) {
				d3dpp.BackBufferWidth = LOWORD(lp);
				d3dpp.BackBufferHeight = HIWORD(lp);
				pD3Device->Reset(&d3dpp);

				InvalidateRect(hWnd,NULL,TRUE);
			}
			return 0;
	}
	return DefWindowProc(hWnd , msg , wp , lp);
}

int WINAPI WinMain(HINSTANCE hInstance , HINSTANCE hPrevInstance ,
				   LPSTR lpCmdLine,int nCmdShow) {
	MSG msg;
	HWND hWnd;
	WNDCLASS winc;
	D3DDISPLAYMODE dmode;

	pDirect3D = Direct3DCreate8(D3D_SDK_VERSION);
	pDirect3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT , &dmode);

	ZeroMemory(&d3dpp , sizeof (d3dpp));
	d3dpp.Windowed = TRUE;
	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
	d3dpp.BackBufferFormat = dmode.Format;
	d3dpp.BackBufferCount = 1;

	winc.style			= CS_CLASSDC;
	winc.lpfnWndProc	= WndProc;
	winc.cbClsExtra		= winc.cbWndExtra		= 0;
	winc.hInstance		= hInstance;
	winc.hIcon			= LoadIcon(NULL , IDI_APPLICATION);
	winc.hCursor		= LoadCursor(NULL,IDC_ARROW);
	winc.hbrBackground	= (HBRUSH)GetStockObject(WHITE_BRUSH);
	winc.lpszMenuName	= NULL;
	winc.lpszClassName	= TEXT("KITTY");

	if(!RegisterClass(&winc)) return 0;

	hWnd = CreateWindow(TEXT("KITTY") , TITLE ,
		WS_OVERLAPPEDWINDOW | WS_VISIBLE , 
		CW_USEDEFAULT , CW_USEDEFAULT , CW_USEDEFAULT , CW_USEDEFAULT ,
		(HWND)NULL,(HMENU)NULL , hInstance , (LPSTR)NULL);

	while (GetMessage(&msg , NULL , 0 , 0 )) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	pDirect3D->Release();
	pD3Device->Release();
	return msg.wParam;
}
このプログラムの結果は、先ほどのものとまったく同じものですが
バッファを確保せずに、直接メモリポインタを渡してレンタリングしていることがわかります


IDirect3DDevice8::CreateIndexBuffer()

HRESULT CreateIndexBuffer(
	UINT Length , DWORD Usage,
	D3DFORMAT Format , D3DPOOL Pool,
	IDirect3DIndexBuffer8** ppIndexBuffer
);
インデックスバッファを作成します

Length - インデックスバッファのサイズをバイト単位で指定します
Usage - リソースの制御方法を表す定数を指定します
Format - D3DFMT_INDEX16、または D3DFMT_INDEX32 のいずれかを指定します
Pool - D3DPOOL 列挙型のメンバで、有効なメモリを指定します
ppIndexBuffer - インデックスバッファを受けるポインタのポインタを指定します

戻り値 - 成功すれば D3D_OK、失敗すればエラー値

Usage には以下の定数の組み合わせを指定することができます

定数解説
D3DUSAGE_DONOTCLIP 頂点バッファの内容が決してクリッピングを要求しないことを示す
このフラグが設定されたバッファを使ってレンダリングする場合は
D3DRS_CLIPPING レンダリング ステートが FALSE に設定されていなければならない
D3DUSAGE_DYNAMIC 頂点またはインデックス バッファが動的なメモリの使用を必要とすることを示す
これを使用すると、ドライバが配置場所を決定できるので、ドライバにとって有効である
一般的に、静的な頂点バッファはビデオ メモリに配置され
動的な頂点バッファは AGP メモリに配置される
静的な使用方法だけを分離できないことに注意すること
D3DUSAGE_DYNAMIC を指定しないと、頂点バッファは静的に作成される
D3DUSAGE_DYNAMIC は、D3DLOCK_DISCARD
および D3DLOCK_NOOVERWRITE ロッキング フラグによって厳密に強制される
この結果、D3DLOCK_DISCARD および D3DLOCK_NOOVERWRITE は
D3DUSAGE_DYNAMIC を指定して作成された頂点
およびインデックス バッファでのみ有効である
これらは、静的な頂点バッファでは有効なフラグではない

D3DUSAGE_DYNAMIC は、管理下の頂点
およびインデックス バッファでは指定できないことに注意すること
D3DUSAGE_RTPATCHES 高次プリミティブの描画に頂点バッファを使用するとき設定する
D3DUSAGE_NPATCHES N パッチの描画に頂点バッファを使用するとき設定する
D3DUSAGE_POINTS ポイント スプライトまたはインデックス付きポイント リストの描画に
頂点バッファを使用するとき設定する
D3DUSAGE_SOFTWAREPROCESSING ソフトウェア頂点処理で使用する頂点バッファであることを示す
D3DUSAGE_WRITEONLY 頂点バッファへの書き込み操作しか実行しないことをシステムに知らせる
このフラグを使用することにより、ドライバは最適なメモリ領域を選択して
効率的に書き込み操作やレンダリングを実行する
この能力を使用して作成された頂点バッファからの読み出しは失敗する

このメソッドが返すエラー値は、以下のものが考えられます
定数解説
D3DERR_INVALIDCALL メソッドの呼び出しが無効である
D3DERR_OUTOFVIDEOMEMORY 十分なディスプレイメモリが存在しない
D3DXERR_INVALIDDATA データが無効である
E_OUTOFMEMORY 十分なメモリを割り当てることができない

IDirect3DIndexBuffer8::Lock()

HRESULT Lock(
	UINT OffsetToLock , UINT SizeToLock ,
	BYTE** ppbData , DWORD Flags
);
指定したデータ範囲をロックして、バッファへのポインタを取得します

OffsetToLock - ロックするデータのオフセットをバイト単位で指定します
SizeToLock - ロックするデータの範囲をバイト単位で指定します
ppbData - ロックしたバッファへのポインタのポインタを指定します
Flags - ロックの方法を表すフラグを指定します

戻り値 - 成功すれば D3D_OK、失敗すれば D3DERR_INVALIDCALL

Flags には以下の定数を組み合わせて指定することができます

定数解説
D3DLOCK_DISCARD アプリケーションは、書き込み専用処理でインデックス バッファ全体を上書きする
これにより、Direct3D は新しいメモリ領域へのポインタを返すことができるので
ダイナミック メモリ アクセス (DMA) と
古い領域からのレンダリングが機能停止することはない
D3DLOCK_NOOVERWRITE フレームの開始以降、またはこのフラグが指定されていない最後のロック以降に
描画処理の呼び出しの中で参照された頂点は、ロック中に変更されないことを示す
頂点バッファにのみデータを追加する場合は、このフラグにより処理を最適化できる
D3DLOCK_NOSYSLOCK ビデオ メモリ ロックのデフォルトの動作は
システムのクリティカル セクションを確保することで
ロック中にディスプレイ モードの変更が行われないことを保証する
このフラグは、システムワイドなクリティカル セクションがロックの間保持されないようにする
ロック処理は若干負荷が高くなるが、マウス カーソルの移動など
システムでほかの処理を実行することが可能になる
このフラグは、ソフトウェア レンダリングのバックバッファのロックのように
ロックが長時間に及び、システムの応答性に
悪影響を与えてしまうようなロックに対して有効である
D3DLOCK_READONLY アプリケーションはバッファに書き込みを行わない
これにより、いくらかの最適化が実現する
D3DLOCK_READONLY は D3DLOCK_DISCARD と共に指定することはできない
また、D3DUSAGE_WRITEONLY で作成された頂点バッファに指定することもできない

IDirect3DIndexBuffer8::Unlock()


HRESULT Unlock();

ロックしたインデックスバッファデータをアンロックします

戻り値 - 成功すれば D3D_OK、失敗すればエラー値

IDirect3DDevice8::SetIndices()

HRESULT SetIndices(
	IDirect3DIndexBuffer8* pIndexData ,
	UINT BaseVertexIndex
);
デバイスにインデックスデータを設定します

pIndexData - インデックスバッファを指定します
BaseVertexIndex - 頂点インデックスのオフセット値を指定します

戻り値 - 成功すれば D3D_OK、失敗すれば D3DERR_INVALIDCALL

IDirect3DDevice8::DrawIndexedPrimitive()

HRESULT DrawIndexedPrimitive(
	D3DPRIMITIVETYPE Type ,
	UINT MinIndex , UINT NumVertices ,
	UINT StartIndex , UINT PrimitiveCount
);
インデックスに基いてレンタリングを行います

Type - 描画するプリミティブを指定します
MinIndex - 使用するインデックスの最小値を指定します
NumVerticex - レンタリングで使用される頂点の数を指定します
StartIndex - インデックスの中で頂点の読み取りを開始する位置を指定します
PrimitiveCount - レンタリングするプリミティブの数を指定します

戻り値 -成功すれば D3D_OK、失敗すれば D3DERR_INVALIDCALL

IDirect3DDevice8::DrawIndexedPrimitiveUP()

HRESULT DrawIndexedPrimitiveUP(
	D3DPRIMITIVETYPE PrimitiveType ,
	UINT MinIndex , UINT NumVertices ,
	UINT PrimitiveCount ,
	CONST void* pIndexData , D3DFORMAT IndexDataFormat ,
	CONST void* pVertexStreamZeroData , UINT VertexStreamZeroStride
);
ユーザメモリポインタから、指定されているプリミティブをレンタリングします

PrimitiveType - プリミティブを指定します
MinIndex - 使用するインデックスの最小値を指定します
NumVerticex - このレンタリングで使用される頂点の数を指定します
PrimitiveCount - 描画するプリミティブの数を指定します
pIndexData - インデックスデータの数値配列へのポインタを指定します
IndexDataFormat - D3DFORMAT 列挙型メンバを指定します
pVertexStreamZeroData - 頂点データの配列へのポインタを指定します
VertexStreamZeroStride - 頂点でータ一つ分のサイズをバイト単位で指定します

戻り値 - 成功すれば D3D_OK、失敗すれば D3DERR_INVALIDCALL



前のページへ戻る次のページへ