創建窗口
Direct3D是基于Microsoft Windows的圖形開發接口,它的使用必須建立在Windows窗口的基礎上,這就需要創建一個窗口,而創建窗口首先需要注冊一個窗口類。示例程序中注冊窗口類并根據窗口類創建窗口的代碼如下:
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_CLASSDC;
wc.lpfnWndProc = WinProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = inst;
wc.hIcon = NULL;
wc.hCursor = NULL;
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = CLASS_NAME;
wc.hIconSm = NULL;
if(! RegisterClassEx(&wc))
return -1;
HWND hwnd = CreateWindow(CLASS_NAME, "Direct3D App", WS_OVERLAPPEDWINDOW, 200, 100, 600, 500,
NULL, NULL, wc.hInstance, NULL);
if(hwnd == NULL)
return -1;
初始化Direct3D
創建了可供繪制圖形的窗口后,在使用Direct3D渲染圖形前,還需要進行與Direct3D相關的初始化操作,主要包括創建Direct3D對象并獲取其接口指針,通過Direct3D對象創建Direct3D設備對象。
bool init_d3d(HWND hwnd)
{
g_d3d = Direct3DCreate9(D3D_SDK_VERSION);
if(g_d3d == NULL)
return false;
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
if(FAILED(g_d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp, &g_device)))
{
return false;
}
return true;
}
Direct3D設備(Direct3D Device)定義了Direct3D的所有繪圖操作,絕大多數Direct3D操作都是通過Direct3D設備接口進行的。比較而言,Direct3D對象更像是DirectX顯示信息的說明,而Direct3D設備對象則是3D功能的具體實現。
要創建Direct3D設備,可調用IDirect3D9::CreateDevice()函數。
Creates a device to represent the display adapter.
HRESULT CreateDevice(
UINT Adapter,
D3DDEVTYPE DeviceType,
HWND hFocusWindow,
DWORD BehaviorFlags,
D3DPRESENT_PARAMETERS * pPresentationParameters,
IDirect3DDevice9 ** ppReturnedDeviceInterface
);
Parameters
- Adapter
- [in] Ordinal number that denotes the display
adapter. D3DADAPTER_DEFAULT is always the primary display adapter.
- DeviceType
- [in] Member of the D3DDEVTYPE enumerated type that
denotes the desired device type. If the desired device type is not
available, the method will fail.
- hFocusWindow
- [in] The focus window alerts Direct3D when an
application switches from foreground mode to background mode. See Remarks.
- For full-screen mode, the window specified
must be a top-level window.
- For windowed mode, this parameter may be NULL
only if the hDeviceWindow member of pPresentationParameters is
set to a valid, non-NULL value.
- BehaviorFlags
- [in] Combination of one or more options that
control device creation. For more information, see D3DCREATE.
- pPresentationParameters
Pointer to a D3DPRESENT_PARAMETERS structure,
describing the presentation parameters for the device to be created. If
BehaviorFlags specifies D3DCREATE_ADAPTERGROUP_DEVICE,
pPresentationParameters is an array. Regardless of the number of heads that
exist, only one depth/stencil surface is automatically created.
- [in, out] For Windows 2000 and Windows XP, the
full-screen device display refresh rate is set in the following order:
- User-specified nonzero ForcedRefreshRate
registry key, if supported by the device.
- Application-specified nonzero refresh rate
value in the presentation parameter.
- Refresh rate of the latest desktop mode, if
supported by the device.
- 75 hertz if supported by the device.
- 60 hertz if supported by the device.
- Device default.
An unsupported refresh rate will default to the
closest supported refresh rate below it. For example, if the application
specifies 63 hertz, 60 hertz will be used. There are no supported refresh
rates below 57 hertz.
pPresentationParameters is both an input and an
output parameter. Calling this method may change several members including:
- If BackBufferCount, BackBufferWidth, and
BackBufferHeight are 0 before the method is called, they will be changed
when the method returns.
- If BackBufferFormat equals D3DFMT_UNKNOWN
before the method is called, it will be changed when the method returns.
- ppReturnedDeviceInterface
- [out, retval] Address of a pointer to the returned
IDirect3DDevice9 interface, which represents the created device.
Return Values
If the method succeeds, the return value is D3D_OK. If
the method fails, the return value can be one of the following:
D3DERR_DEVICELOST, D3DERR_INVALIDCALL, D3DERR_NOTAVAILABLE,
D3DERR_OUTOFVIDEOMEMORY.
Remarks
This method returns a fully working device interface,
set to the required display mode (or windowed), and allocated with the
appropriate back buffers. To begin rendering, the application needs only to
create and set a depth buffer (assuming EnableAutoDepthStencil is FALSE in
D3DPRESENT_PARAMETERS).
When you create a Direct3D device, you supply two
different window parameters: a focus window (hFocusWindow) and a device window
(the hDeviceWindow in D3DPRESENT_PARAMETERS). The purpose of each window
is:
- The focus window alerts Direct3D when an
application switches from foreground mode to background mode (via Alt-Tab, a
mouse click, or some other method). A single focus window is shared by each
device created by an application.
- The device window determines the location and size
of the back buffer on screen. This is used by Direct3D when the back buffer
contents are copied to the front buffer during IDirect3DDevice9::Present.
This method should not be run during the handling of
WM_CREATE. An application should never pass a window handle to Direct3D while
handling WM_CREATE. Any call to create, release, or reset the device must be
done using the same thread as the window procedure of the focus window.
Note that D3DCREATE_HARDWARE_VERTEXPROCESSING,
D3DCREATE_MIXED_VERTEXPROCESSING, and D3DCREATE_SOFTWARE_VERTEXPROCESSING are
mutually exclusive flags, and at least one of these vertex processing flags must
be specified when calling this method.
Back buffers created as part of the device are only
lockable if D3DPRESENTFLAG_LOCKABLE_BACKBUFFER is specified in the presentation
parameters. (Multisampled back buffers and depth surfaces are never lockable.)
The methods IDirect3DDevice9::Reset, IUnknown, and
IDirect3DDevice9::TestCooperativeLevel must be called from the same thread that
used this method to create a device.
D3DFMT_UNKNOWN can be specified for the windowed mode
back buffer format when calling IDirect3D9::CreateDevice,
IDirect3DDevice9::Reset, and IDirect3DDevice9::CreateAdditionalSwapChain.
This means the application does not have to query the current desktop format
before calling IDirect3D9::CreateDevice for windowed mode. For
full-screen mode, the back buffer format must be specified.
If you attempt to create a device on a 0x0 sized
window, IDirect3D9::CreateDevice will fail.
消息循環
在Direct3D中,渲染圖形通常是在消息循環中進行的:
MSG msg;
ZeroMemory(&msg, sizeof(msg));
while(msg.message != WM_QUIT)
{
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
render();
}
}
這段代碼的主要部分由PeekMessage()、TranslateMessage()和DispatchMessage()構成,它們是Windows程序標準的消息循環處理代碼。當應用程序消息隊列中出現一條消息時,PeekMessage()返回布爾值TRUE,執行TranslateMessage()進行消息轉換,然后由DispatchMessage()把消息傳遞給窗口過程函數。
特別需要注意的是,在消息循環中使用的是PeekMessage()函數,而不是GetMessage()函數。函數PeekMessage()和GetMessage()的功能大體相同,作用都是從消息隊列中取一條消息出來,唯一不同的是,每當GetMessage()發現消息隊列中沒有消息時,過門不入,而PeekMessage()發現消息隊列中沒有消息時,會取回系統控制權,讓程序在此停留一段時間,應用程序就是在這時候處理render()函數。也就是說,渲染函數render()都是在程序運行時的空閑時間調用的。
注意理解PeekMessage()和GetMessage()運行機制的區別,這對理解Direct3D程序中如何實現動畫是很關鍵的。