D3D的初始化

要开始D3D编程,首先是要初始化D3D环境,SDK文档的tutorial将整个过程分为几部

  1. 创建一个窗体
  2. 初始化D3D

    • 获取IDirect3D9的指针
    • 检查设备的性能、对API的支持能力
    • 初始化D3DPRESENT_PARAMETERS
    • 使用D3DPRESENT_PARAMETER的参数创建IDirectDDevice9
  3. 处理消息
  4. 渲染&显示场景
  5. 关闭D3D,退出程序


  1. 创建窗体
    之前说过,D3D程序是在一个windows窗体的客户区进行绘制,D3D相当于画笔的话,这个窗体就是画布,所以在初始化D3D之前首先要有一个窗体,根据简单的Windows API编程回顾的内容,创建一个简单窗体并不难。

    • 定义窗口类

      WNDCLASS wclass;
    • 注册窗口类

      RegisterClass(&wclass);
    • 创建窗口

      CreateWindow(...);
  2. 初始化D3D
    一旦创建好了窗体,就可以在这个基础上进一步去初始化D3D,创建D3D设备,以在窗体这个画布上进行绘图,初始化D3D的过程可以分为四部。

    • 获取IDirect3D9的指针,游戏开发中最常用的就是COM配合DirectX技术,这儿IDirect3D9就是一个表示D3D9的COM接口,因此不能直接使用C++的new操作符

      LPDIRECT3D9 g_pD3D9;    //IDirect3D9 *g_pD3D9;
      g_pD3D9 = Direct3DCreate9(D3D_SDK_VERSION);
    • 检查设备性能,对API的支持程度(如硬件TnL,这个是比较老的固定功能流水线中所采用的一些东西,现代的可编程流水线已经见不着了)

      //以硬件TnL为例
      D3DCAPS9 d3dcap;
      int hwTnL = 0;
      g_pD3D9->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &d3dcaps);
      if(caps.Devcaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
          hwTnL = D3DCREATE_HARDWARE_VERTEXPROCESSING;
      else
          hwTnL = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
    • 建立一个D3DPRESENT_PARAMETERS

      D3DPRESENT_PARAMETERS d3dpp;
      //按需设置d3dpp的各类属性
    • 建立D3D设备

      g_pD3D9->CreateDevice(D3DADAPTER,
                            D3DDEVTYPE,
                            HWND, BEHAVIOR_FLAGS
                            D3DPRESENT_PARAMETERS*,
                            IDirect3DDevice9 **);

      至此,D3D的初始化就完成了

  3. 处理消息
    就如简单的Windows API编程回顾中所述,游戏程序多数不是事件驱动的,因而可以使用PeekMessage处理消息

    MSG msg;
    while(PeekMessage(&msg, 0, 0, 0, 0))
    {
        if(msg.message == WM_QUIT)
            break;
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    //Game Codes
  4. 渲染&显示场景

    • 清除后台缓存,将后台缓存置为所设定的颜色,将深度或模板缓存设置为需要的值

      //IDirect3DDevice9::Clear
      g_pD3DDEV9->Clear(DWORD Count, const D3DRECT *pRects,
                        DWORD flags, D3DCOLOR Color, float Z, DWORD Stencil);
    • 向后台缓存绘制场景

      g_pD3DDEV9->BeginScene();
      //Render Codes
      g_pD3DDEV9->EndScene();
    • 提交下一帧后台缓存,仅仅是提交,还没有显示

      //IDirect3DDevice9::Present
      g_pD3DDEV9->Present(0,0,0,0);
  5. 关闭D3D,退出程序
    退出程序不困难,但之前要先关闭D3D。之前说了g_pD3D9和g_pD3DDEV9是两个COM接口指针,而COM不可以使用C++的new/delete操作符来创建和销毁,所以需要手动的来释放一下

    g_pD3D9->Release();
    g_pD3D9 = NULL;
    g_pD3DDEV9->Release();
    g_pD3DDEV9 = NULL;

至此,整个D3D程序流程就结束了

全部代码如下

#include <windows.h>
#include <d3d9.h>
#include <strsafe.h>

#pragma comment(lib, "d3d9.lib")


LPDIRECT3D9			g_pD3D9;
LPDIRECT3DDEVICE9	g_pD3D9dev;

HWND hMain;

bool initWinApp(HINSTANCE hInstance, int iCmdShow);
LRESULT CALLBACK MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);

HRESULT D3DInit(HWND hWnd);
void D3DRender();
void D3DCleanup();


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR cmd, int iCmdShow)
{
	if( !initWinApp(hInstance, iCmdShow) )
	{
		::MessageBox(0, TEXT("initWinApp Failed!"), TEXT("ERROR"), MB_OK);
		return 0;
	}

	if( SUCCEEDED(D3DInit(hMain)) )
	{
		::ShowWindow(hMain, iCmdShow);
		::UpdateWindow(hMain);

		MSG msg;
		while( PeekMessage(&msg, 0, 0, 0, 0 ) )
		{
			if( msg.message == WM_QUIT )
				break;
			msg.message = WM_PAINT;
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}

	D3DCleanup();
	UnregisterClass(L"D3DInit", hInstance);
	return 0;


}

bool initWinApp(HINSTANCE hInstance, int iCmdshow)
{
	WNDCLASS wc;
	wc.style		= CS_HREDRAW | CS_VREDRAW; 
	wc.lpfnWndProc	= MsgProc;
	wc.cbClsExtra	= 0;
	wc.cbWndExtra	= 0;
	wc.hInstance	= hInstance;
	wc.hIcon		= ::LoadIcon(0, IDI_APPLICATION);
	wc.hCursor		= ::LoadCursor(0, IDC_ARROW);
	wc.hbrBackground= static_cast<HBRUSH>(::GetStockObject(WHITE_BRUSH));
	wc.lpszMenuName	= 0;
	wc.lpszClassName= TEXT("D3DInit");

	if( !RegisterClass(&wc) )
	{
		::MessageBox(0, TEXT("RegisterClass Failed!"), TEXT("ERROR"), MB_OK);
		return false;
	}

	if( (hMain = CreateWindow(TEXT("D3DInit"), TEXT("D3DInit"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
		CW_USEDEFAULT, 800, 600, NULL, NULL, hInstance, NULL)) == NULL)
	{
		::MessageBox(0, TEXT("CreateWindow Failed!"), TEXT("ERROR"), MB_OK);
		return false;
	}

	return true;
}

HRESULT D3DInit(HWND hWnd)
{
	//acquire pointer to IDirect3D9
	if( (g_pD3D9 = Direct3DCreate9(D3D_SDK_VERSION)) == NULL )
	{
		::MessageBox(0, TEXT("Direct3DCreate Failed!"), TEXT("ERROR"), MB_OK);
		return E_FAIL;
	}

	//Check Device Capabilities, here we check the hardware TnL support
	D3DCAPS9 caps;
	g_pD3D9->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps);
	int hardwareTnL = 0;
	if( caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT )
		hardwareTnL = D3DCREATE_HARDWARE_VERTEXPROCESSING;
	else
		hardwareTnL = D3DCREATE_SOFTWARE_VERTEXPROCESSING;

	//setup D3DPRESENT_PARAMETERS which defines the behavior of the D3D app 
	D3DPRESENT_PARAMETERS d3dpp;
	d3dpp.BackBufferWidth			= 800;
	d3dpp.BackBufferHeight			= 600;
	d3dpp.BackBufferCount			= 2;
	d3dpp.BackBufferFormat			= D3DFMT_A8R8G8B8;
	d3dpp.MultiSampleType			= D3DMULTISAMPLE_NONE;
	d3dpp.MultiSampleQuality		= 0;
	d3dpp.SwapEffect				= D3DSWAPEFFECT_DISCARD;
	d3dpp.hDeviceWindow				= hMain;
	d3dpp.Windowed					= 1;
	d3dpp.EnableAutoDepthStencil	= TRUE;
	d3dpp.AutoDepthStencilFormat	= D3DFMT_D24S8;
	d3dpp.Flags						= 0;
	d3dpp.FullScreen_RefreshRateInHz= D3DPRESENT_RATE_DEFAULT;
	d3dpp.PresentationInterval		= D3DPRESENT_INTERVAL_IMMEDIATE;

	//Create D3D device
	if( FAILED(g_pD3D9->CreateDevice(D3DADAPTER_DEFAULT,
									D3DDEVTYPE_HAL,
									hWnd,
									hardwareTnL,
									&d3dpp,
									&g_pD3D9dev)) )
	{
		MessageBox(0, TEXT("CreateDevice Failed"), TEXT("ERROR"), MB_OK);
		return E_FAIL;
	}

	return S_OK;
}

LRESULT CALLBACK MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch( msg )
	{
	case WM_DESTROY:
		::PostQuitMessage(0);
		return 0;
	case WM_PAINT:
		D3DRender();
		ValidateRect(hWnd, NULL);
		return 0;
	}
	return DefWindowProc(hWnd, msg, wParam, lParam);
}

void D3DRender()
{
	//Set BackBuffer
	g_pD3D9dev->Clear(0, NULL, D3DCLEAR_TARGET,D3DCOLOR_XRGB( 0, 255, 0 ), 1.0f, 0 );

	//Render in this section
	if( SUCCEEDED(g_pD3D9dev->BeginScene()) )
	{
		g_pD3D9dev->EndScene();
	}

	//Present BackBuffer
	g_pD3D9dev->Present(NULL, NULL, NULL, NULL);
}

void D3DCleanup()
{
	if( g_pD3D9dev != NULL )
	{
		g_pD3D9dev->Release();
	}
	if( g_pD3D9 != NULL )
	{
		g_pD3D9->Release();
	}
}

你可能感兴趣的:(初始化)