1. 程式人生 > >DirectX入門筆記 00------ 初始化D3D

DirectX入門筆記 00------ 初始化D3D

d3dUtility.h

#include <d3dx9.h>


namespace d3d
{
	bool InitD3D(
		HINSTANCE hInstance, //Application instance
		int width, int height, //Width and height of Back buffer
		bool windowed,//Widowed(true) or full screen(false)
		D3DDEVTYPE devicetype,//HAL/REF/SM
		IDirect3DDevice9** device);//The created device

	int EnterMsgLoop(bool(*ptr_display)(float timeDelta));

	LRESULT CALLBACK WndProC(
		HWND hwnd,
		UINT msg,
		WPARAM wParam,
		LPARAM lParam);

	template<class T>void Release(T t) {
		if (t) {
			t->Release();
			t = 0;
		}
	}

	template<class T>void Delete(T t) {
		if (t) {
			delete t;
			t = 0;
		}
	}
}

Release(); 釋放COM介面並將其設定為NULL

Delete(); 刪除自由堆中的物件並將物件指標設定為NULL

d3dUtility.cpp

InitD3D分了四個步驟初始化D3D

1.建立IDirect3D9物件(此介面用於獲取系統中物理硬體裝置的資訊並建立介面IDirect3DDevice9).

//Initial D3D
	//Step 1:Create the IDirect3D9 object
	IDirect3D9* d3d9;
	D3DDISPLAYMODE DisplayMode;
	d3d9 = Direct3DCreate9(D3D_SDK_VERSION); //return NULL if fails
	//Get the desktop display mode
	if (FAILED(d3d9->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &DisplayMode)))
		return false;
	if (!d3d9) {
		::MessageBox(0, TEXT("Direct3DCreat9 - Failed"), 0, 0);
		return false;
	}

2.檢查硬體加速的支援, 指定使用IDirect3DDevice9物件進行頂點運算的型別.

	//Step 2: Check D3DCREATE_HARDWARE_VERTEXPROCESSING
	D3DCAPS9 caps;//struct
	d3d9->GetDeviceCaps(D3DADAPTER_DEFAULT,//ADPTER:Denotes primary display adapter
		DeviceType,//Specifies the device type (Usually D3DDEVTYPE_HAL)
		&caps); //Capabilities of the primary display adapter
	
	//can we use hardware vertex processing?
	int vp = 0;
	//D3DDEVCAPS_HWTRANSFORMANDLIGHT /* Device can support transformation and lighting in hardware and DRAWPRIMITIVES2EX must be also */
	if (caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) {
		//#define D3DCREATE_SOFTWARE_VERTEXPROCESSING     0x00000020L
		//#define D3DCREATE_HARDWARE_VERTEXPROCESSING     0x00000040L
		vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
	}
	else {
		vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
	}

3.填充D3DPRESENT_PARAMTETER結構體, 以此指定所要建立的IDirect3DDevice9型別物件的一些特性

	//Step3: Fill up structure D3DPRESETNT_PARAMETER
	D3DPRESENT_PARAMETERS d3dpp;
	d3dpp.BackBufferWidth = width;
	d3dpp.BackBufferHeight = height;
	d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;//pixel format
	d3dpp.BackBufferCount = 1;//Number of the back buffer
	d3dpp.Windowed = windowed;

	d3dpp.SwapEffect//Enum: Page Flipping way of the Swap Chain
		= D3DSWAPEFFECT_DISCARD;//The most effective way

	d3dpp.hDeviceWindow = hwnd;//Handle of the window that need to draw
	d3dpp.EnableAutoDepthStencil = true;//Create and maintain Z-Buffer and Stencil Buffer automatically
	d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;//depth format

	d3dpp.Flags //D3DPRESENTFLAG / 0(No Flag)
		= 0;    //D3DPRESENTFLAG_LOCKABLE_BACKBUFFER     D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL

	d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;

	d3dpp.PresentationInterval    //present rate
		= D3DPRESENT_INTERVAL_IMMEDIATE; //D3DPRESENT_INTERVAL_DEFAULT
	//MultiSample Type
	D3DMULTISAMPLE_TYPE multiType = D3DMULTISAMPLE_NONE;//Default MultiType: NONE
	if (d3d9->CheckDeviceMultiSampleType(D3DADAPTER_DEFAULT, DeviceType, 
		DisplayMode.Format, 
		windowed, D3DMULTISAMPLE_4_SAMPLES, NULL) == D3D_OK) //HResult:D3D_OK = S_OK/S_FALSE
	{
		multiType = D3DMULTISAMPLE_4_SAMPLES;
	}
	d3dpp.MultiSampleType = multiType;
	d3dpp.MultiSampleQuality = 0;

4.建立IDirect3DDevice9介面, 初始化完成

HRESULT hr = d3d9->CreateDevice(D3DADAPTER_DEFAULT, DeviceType, hwnd, vp, &d3dpp, device);
	if (FAILED(hr)) {
		//try again using a 16-bit depth buffer
		d3dpp.AutoDepthStencilFormat = D3DFMT_D16;

		hr = d3d9->CreateDevice(
			D3DADAPTER_DEFAULT,
			DeviceType,
			hwnd,
			vp,
			&d3dpp,
			device);

		if (FAILED(hr))
		{
			d3d9->Release(); // done with d3d9 object
			::MessageBox(0, TEXT("CreateDevice() - FAILED"), 0, 0);
			return false;
		}
	}
	return true;

之後實現訊息迴圈

int d3d::EnterMsgLoop(bool(*ptr_display)(float timeDelta))
{
	MSG msg;
	::ZeroMemory(&msg, sizeof(MSG));

	static float LastTime = (float)timeGetTime();

	while (msg.message != WM_QUIT) {
		if (::PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
			::TranslateMessage(&msg);
			::DispatchMessage(&msg);
		}
		else {
			float CurrTime = (float)timeGetTime();
			float TimeDelta = (CurrTime - LastTime) * 0.001f;
			
			ptr_display(TimeDelta);//call display function
			LastTime = CurrTime;
		}
	}
	return msg.wParam;
}

接收一個指向顯示函式的函式指標, 顯示函式就是實現繪製功能的那個函式.

d3dInitialize.cpp

#include "d3dUtility.h"

IDirect3DDevice9* Device = 0;

bool Setup() {

	//Nothing to set up in the sample

	return true;
}

void Cleanup() {
	
	//Nothing to clean up in the sample

}

bool Display(float TimeDelta) {
	if (Device) {
		// Instruct the device to set each pixel on the back buffer black -
		// D3DCLEAR_TARGET: 0x00000000 (black) - and to set each pixel on
		// the depth buffer to a value of 1.0 - D3DCLEAR_ZBUFFER: 1.0f.
		Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00000000, 1.f, 0);
		// Swap the back and front buffers.
		Device->Present(0, 0, 0, 0);
	}
	return true;
}

//WndProC
LRESULT CALLBACK d3d::WndProC(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch (msg) {
		case WM_DESTROY:
		::PostQuitMessage(0);
		break;
		case WM_KEYDOWN:
		if (wParam == VK_ESCAPE)
			::DestroyWindow(hwnd);
	}
	return ::DefWindowProc(hwnd, msg, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hinstance,
	HINSTANCE prevInstance,
	PSTR cmdLine,
	int showCmd)
{
	if (!d3d::InitD3D(hinstance, 890, 540, true, D3DDEVTYPE_HAL, &Device)) {
		::MessageBox(0, TEXT("InitD3D() - FAILED"), 0, 0);
		return 0;
	}

	if (!Setup()) {
		::MessageBox(0, TEXT("Setup - FAILED"), 0, 0);
		return 0;
	}

	d3d::EnterMsgLoop(Display);

	Cleanup();
	Device->Release();
	return 0;
}

初始化完成後繪製好的黑色視窗: