DXUT Programming Guide

214 views
Skip to first unread message

earlyfly

unread,
Feb 16, 2008, 9:51:00 PM2/16/08
to earlyfly
The DirectX Utility Library (DXUT) is a framework used by most of the
Direct3D tutorials and samples and is built on top of the Direct3D 9
and Direct3D 10 API. Its goal is to make Direct3D samples, prototypes,
and tools as well as professional games more robust and easier to
build. It simplifies the Windows and Direct3D APIs for typical usage.

DXUT is a layer designed to help programmers spend less time coding
and debugging mundane aspects such as creating a window, creating a
device, processing Windows messages, and handling device events.

Features and Limitations
DXUT provides help with many tasks such as:

Creating a window
Choosing a Direct3D device
Creating a Direct3D device
Handling device events
Handling window events
Toggling between windowed and full-screen
DXUT works with both Direct3D 9 and Direct3D 10. An application built
on top of DXUT can make easy use of one or both of these APIs. If DXUT
detects a Direct3D 10 device on the system and the application
supports both Direct3D 9 and Direct3D 10, then it will default to
Direct3D 10. If the application only supports Direct3D 10 and the no
Direct3D 10 device can be found then DXUT will return an error.

DXUT also include a set of textured GUI controls, including an IME-
enabled edit box, extra classes such as simple camera types, and a
high-resolution timer class. DXUT is designed to be modular, so the
application can use all of the DXUT features or just the parts
desired. The remainder of this programming guide covers each of these
steps in detail and looks at the choices the application has available
to control or replace each step.

For ease of use, DXUT supports only a single window attached to a
single device. Advanced applications that need to use multiple devices
simultaneously or that need to display multiple Direct3D windows are
not supported by DXUT. Most typical applications should be able to use
DXUT.

Example Main Function using DXUT
Here is an example main function of an application using DXUT:

INT WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, INT )
{
// Set Direct3D 9 callbacks
DXUTSetCallbackD3D9DeviceAcceptable( IsD3D9DeviceAcceptable );
DXUTSetCallbackD3D9DeviceCreated( OnD3D9CreateDevice );
DXUTSetCallbackD3D9DeviceReset( OnD3D9ResetDevice );
DXUTSetCallbackD3D9FrameRender( OnD3D9FrameRender );
DXUTSetCallbackD3D9DeviceLost( OnD3D9LostDevice );
DXUTSetCallbackD3D9DeviceDestroyed( OnD3D9DestroyDevice );

// Set Direct3D 10 callbacks
DXUTSetCallbackD3D10DeviceAcceptable( IsD3D10DeviceAcceptable );
DXUTSetCallbackD3D10DeviceCreated( OnD3D10CreateDevice );
DXUTSetCallbackD3D10SwapChainResized( OnD3D10ResizedSwapChain );
DXUTSetCallbackD3D10FrameRender( OnD3D10FrameRender );

DXUTSetCallbackD3D10SwapChainReleasing( OnD3D10ReleasingSwapChain );
DXUTSetCallbackD3D10DeviceDestroyed( OnD3D10DestroyDevice );

// Set the generic callback functions
DXUTSetCallbackDeviceChanging( ModifyDeviceSettings );
DXUTSetCallbackMsgProc( MsgProc );
DXUTSetCallbackFrameMove( OnFrameMove );

// TODO: Perform any application-level initialization here

// Initialize DXUT and create the desired Win32 window and
Direct3D device for the application
DXUTInit( true, true );
DXUTCreateWindow( L"TestApp" );
DXUTCreateDevice( true, 640, 480 );

// Start the render loop
DXUTMainLoop();

// TODO: Perform any application-level cleanup here

return DXUTGetExitCode();
}

earlyfly

unread,
Feb 16, 2008, 9:51:00 PM2/16/08
to earlyfly

earlyfly

unread,
Feb 16, 2008, 10:04:45 PM2/16/08
to earlyfly
Getting Started with DXUT
Starting a New Project
To start a new Visual Studio development project using DXUT:

Launch the DirectX Sample Browser from:
(SDK root)\Samples\SampleBrowser\

Select an existing Direct3D 9 or Direct3D 10 sample as a starting
point.
Click on the Install Project link next to that project. SampleBrowser
will copy the sample to a new directory location. You may rename the
project, in which case the sample browser will change the appropriate
files and source code to give the project the new name.
Initialize DXUT
Initialize DXUT by calling the DXUTInit function.

Copy Code
HRESULT WINAPI DXUTInit(
bool bParseCommandLine = true,
bool bShowMsgBoxOnError = true,
WCHAR* strExtraCommandLineParams = NULL,
bool bThreadSafeDXUT = false );
You will typically make this call near the beginning of your
application's WinMain function. However, DXUT will call it
automatically using the default parameters if your application does
not.

The function takes four parameters.

The first parameter (bParseCommandLine) determines if DXUT will
respond to command-line arguments. See DXUTInit for a listing of the
command-line arguments supported. For example, running the BasicHLSL
Sample with these command-line arguments will cause the sample to
attempt to open a 400 x 300 window.
Copy Code
BasicHLSL.exe -windowed -width:400 -height:300
The second parameter (bShowMsgBoxOnError) enables the display of a
message box when DXUT detects an error. Set it to FALSE to run
automated testing or if your application does not allow dialog boxes.
The third parameter (strExtraCommandLineParams) instructs DXUT to
append this string to the command line for if the application wants to
programmatically control the command line switches.
The last parameter (bThreadSafeDXUT) controls if DXUT enters a
critical section when retrieving or modify internal DXUT state. Most
applications can leave this set to false

earlyfly

unread,
Feb 16, 2008, 10:09:47 PM2/16/08
to earlyfly
Create a Window
Every Direct3D application communicates to the desktop through a
window. The window is responsible for behaving nicely with other
running applications by responding to focus changes, mode switches,
and responding to other window events caused by user-input key
combinations and windows messages. This functionality is accomplished
with an event handler.

DXUT supports windows created by either DXUT or an application.


Windows Created by DXUT
DXUT makes window creation easy with DXUTCreateWindow.


HRESULT DXUTCreateWindow(
const WCHAR *strWindowTitle = L"Direct3D Window",
HINSTANCE hInstance = NULL,
HICON hIcon = NULL,
HMENU hMenu = NULL,
INT x = CW_USEDEFAULT,
INT y = CW_USEDEFAULT
);
All of the input parameters are optional.

strWindowTitle is the window title that appears on the task bar; it is
typically the project title.
hInstance is the handle to the application's instance; it is typically
NULL for most applications.
hIcon is the handle to the application's icon. This is typically set
to NULL, so that the first icon embedded in the application's
executable is used.
hMenu is the menu handle. Most games, however, do not use a standard
menu but instead create a custom in-game interface.
(x,y) describe the position of the window (in windowed mode only);
they are ignored for an application running in full-screen mode.
The handle to the window can be retrieved by calling DXUTGetHWND.

Windows Created by Application
The application can choose not to use DXUT to create a window, but
instead create a window using standard Windows API calls. How to
create a window is beyond the scope of this programming guide.

Once the window is created, call DXUTSetWindow to initialize DXUT with
the HWND.

Copy Code
HRESULT DXUTSetWindow(
HWND hWndFocus,
HWND hWndDeviceFullScreen,
HWND hWndDeviceWindowed,
BOOL bHandleMessages = TRUE
);
This function takes three handles to windows, which are typically the
same unless the windowed application is in a different window than the
full-screen application. The focus-window informs Direct3D when the
application needs to switch from the topmost window to the background
from an ALT+TAB key combination, mouse click, or other user input. As
a minimum for initializing DXUT, an application should always set the
focus-window handle.

Handling Window Events
Once DXUT has been initialized with a window, the application needs to
notify DXUT about how to handle windows messages. There are two ways
to accomplish this.

Handling Events with DXUT
The simplest way to handle events is to call DXUTCreateWindow with a
single argument.

Copy Code
DXUTCreateWindow( L"My New Game" );
DXUT will create a window and automatically handle the important
window messages.

If the application wants to also handle window events in addition to
DXUT, it can call DXUTSetCallbackMsgProc which sets a callback
function which is called before the window message is processed
(LPDXUTCALLBACKMSGPROC).

Copy Code
LRESULT CALLBACK MsgProc(
HWND hWnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam,
bool* pbNoFurtherProcessing,
void* pUserContext )
{
return 0;
}
You may choose to not implement this callback in which case all of the
important messages will be handled by DXUT. You may also choose handle
this callback, and upon some messages set *pbNoFurtherProcessing to
TRUE to prevent DXUT from also handling that message. Be cautious when
setting this as it may prevent DXUT from behaving correctly.

Handling Events in Application
For an application created window, the application is expected to
handle window messages. However, an application can pass window
messages to DXUT by calling DXUTStaticWndProc from the window's
WindowProc callback function.

earlyfly

unread,
Mar 6, 2008, 10:49:06 AM3/6/08
to earlyfly
Getting Started with DXUT(DXUT 进阶)
开始一个工程基于DXUT:
新建立一个window应用程序------>>>>>然后把DXUT.cpp,DXUT.h,DXUTenum.cpp,DXUTenum.h等等包
含在
建立的项目中,然后新建一个main.cpp就可以使用DXUT了。DXUT主要是对Directx的一次封装。方便一些工具,游戏
模拟软件的快速开发。注意,要把库链接上(dxerr.lib dxguid.lib d3dx9d.lib d3d9.lib
d3dx10d.lib winmm.lib comctl32.lib)
还有就是项目属性---->>>链接器--->>输入---------->>>延迟加载的DLL设置为d3dx10d_34.dll,否则会
链接运行不起。

初始化 DXUT
通过调用 DXUTInit函数来初始化
HRESULT WINAPI DXUTInit(
bool bParseCommandLine = true,
bool bShowMsgBoxOnError = true,
WCHAR* strExtraCommandLineParams = NULL,
bool bThreadSafeDXUT = false );
你可以在WinMain函数开始时就初始化,如果不调用此函数也不所谓,DXUT将自动为你设置一个默认的参数。

bParaseCommandLine参数就是表示是否分析命令行参数。如BasicHLSL Sample例子可以通过
BasicHLSL.exe -windowed -width:400 -height:300来为应用程序进行初始化

bShowMsgBoxOnError参数很显然表示是否显示错误提示对话框,当DXUT检测到错误是否弹出

strExtraCommandLineParams参数是为命令行附上的额外参数,如果为NULL就附加

bThreadSafeDXUT参数就是当重新获得一个状态,或者修改状态DXUT将进入一段临界区域。大多应用程序都设置为false,因为都没有多
线程。

创建一个窗口

每一个D3D应用程序都是通过桌面上的一个窗体来与用户交流。

你可以通过DXUT来创建一个窗体,也可以自己调用window API来创建一个窗体。

通过DXUT来创建窗体(By Windows)
DXUT是创建窗体非常容易,只需要调用(DXUTCreateWindow)

HRESULT DXUTCreateWindow(
const WCHAR *strWindowTitle = L"Direct3D Window",
HINSTANCE hInstance = NULL,
HICON hIcon = NULL,
HMENU hMenu = NULL,
INT x = CW_USEDEFAULT,
INT y = CW_USEDEFAULT
);

所有的输入参数都是可选的.
.strWindowTitle 是窗口的标题栏显示的文字,还有window任务栏显示的文字
.hInstance是应用程序的实例句柄。大多数应用程序都是NULL
.hIcon 是应用程序的图标,如果为NULL将使用系统默认的
.hMenu是菜单句柄。大多数游戏都不使用系统的菜单,都是自己定义用户界面
.(x,y)指定窗口的位置(只有窗口模式有用);全屏模式的话这两个参数被忽略

如果通过DXUTCreateWindow后,可以通过 DXUTGetHWND来获得窗口的句柄HWND

一旦窗口创建完毕后,就可以通过DXUTSetWindow来初始化窗口
HRESULT DXUTSetWindow(
HWND hWndFocus,
HWND hWndDeviceFullScreen,
HWND hWndDeviceWindowed,
BOOL bHandleMessages = TRUE
);
这个函数有三个窗口句柄,如果你在全屏和窗口模式不使用一个窗口的话其实他们都是一个窗口句柄。

处理窗口事件
当我们把窗口创建好后我们还需要为窗口写消息回调函数,这样当消息发生才有地方处理。

当通过DXUTCreateWindow创建窗口,注意是DXUTCreateWindow哈,呵呵...
这个函数创建的后,一些重要的窗口消息都自动处理了。
如果处理除了DXUT处理以外的窗口事件,可以调用DXUTSetCallbackMsgProc来设置一个回调函数,他将会
调用在DXUT默认的回调处理函数(LPDXUTCALLBACKMSGPROC)之前调用
LRESULT CALLBACK MsgProc(
HWND hWnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam,
bool* pbNoFurtherProcessing,
void* pUserContext )
{
return 0;
}
创建一个D3D设备
一旦你已经 初始化DXUT 和 创建一个窗体后,下一步就是创建一个渲染设备。你可能直接用Direct3D 9或10 API调用,或者可以
直接使用DXUT来简化设备的创建过程。

为你应用程序创建一个渲染设备
如果你创建设备直接用Directx API,你可以调用如下函数:

Direct3D 9 用 IDirect3D9::CreateDevice
Direct3D 10 用 D3D10CreateDevice
这两个函数都需要很多参数,比如:一个适配器,设备类型,一个应用程序句柄,软/硬件顶点处理,还有其他驱动信息,渲染参数
渲染参数又包含很多选项要指定:如后绘面缓存,交换方式,深度缓存等等。

使用DXUT来创建,可以简化这一步骤,当然只是把一些我们不关心的参数给了默认设置即可。

通过DXUT来创建一个渲染设备:
你一个简单调用DXUTCreateDevice来创建一个设备
HRESULT WINAPI DXUTCreateDevice(
bool bWindowed = true,
int nSuggestedWidth = 0,
int nSuggestedHeight = 0 );
其他参数都是默认设置了,这些默认值是什么你如果想知道可以跟踪一下源代码,或者参看MSDN

通过 IsDeviceAcceptable 回调函数来自定义渲染设备的参数

为了帮助DXUT选择最好的设备参数设置,我们要么通过 DXUTSetCallbackD3D9DeviceAcceptable或者
DXUTSetCallbackD3D10DeviceAcceptable来
指定回调函数,这个毁掉函数将过滤掉你的机器不适合的设置。不支持就返回一个false,例如下面
bool CALLBACK IsD3D9DeviceAcceptable(
D3DCAPS9* pCaps,
D3DFORMAT AdapterFormat,
D3DFORMAT BackBufferFormat,
bool bWindowed )
{
if( BackBufferFormat == D3DFMT_X1R5G5B5 || BackBufferFormat ==
D3DFMT_R5G6B5 )
return false;
if( pCaps->PixelShaderVersion < D3DPS_VERSION(2,0) )
return false;

return true;
}

不支持16位后绘缓存格式和像素着色器模式2

通过ModifyDeviceSetting回调函数来改变一个渲染设备的设置

在选择了最好的设置以后,我们需要修改设备时候,可以通过ModifyDeviceSettings回调函数。这个回调函数
带上一个DXUTDeviceSetting结构体。这个结构体是DXUTD3D10DeviceSettings和
DXUTD3D9DeviceSettings的一个联合体
它包含任何创建设备的信息。DXUTDeviceSettings结构体里有一个ver属性,它表示设备是9还是10,开始时候
结构体被填充了默认的值,然后我们只需要在回调函数里调用IDirect3D9或10的方法来改变具体的参数,例如下面:
bool CALLBACK ModifyDeviceSettings(
DXUTDeviceSettings* pDeviceSettings,
void* pUserContext )
{
if( pDeviceSettings->ver == DXUT_D3D9_DEVICE )
{
IDirect3D9* pD3D = DXUTGetD3DObject();
if( SUCCEEDED( pD3D->CheckDeviceFormat(
pDeviceSettings->d3d9.AdapterOrdinal,
pDeviceSettings->d3d9.DeviceType,
pDeviceSettings->d3d9.AdapterFormat,
D3DUSAGE_DEPTHSTENCIL,
D3DRTYPE_SURFACE, D3DFMT_D24S8 ) ) )
{
if( SUCCEEDED( pD3D->CheckDepthStencilMatch(
pDeviceSettings->d3d9.AdapterOrdinal,
pDeviceSettings->d3d9.DeviceType,
pDeviceSettings->d3d9.AdapterFormat,
pDeviceSettings->d3d9.pp.BackBufferFormat,
D3DFMT_D24S8 ) ) )
{
pDeviceSettings->d3d9.pp.AutoDepthStencilFormat =
D3DFMT_D24S8;
}
}
}

return true;
}
也可以使用 DXUT 里的 CD3D9Enumeration来检查格式是否支持
bool CALLBACK ModifyDeviceSettings(
DXUTDeviceSettings* pDeviceSettings,
void* pUserContext )
{
if( pDeviceSettings->ver == DXUT_D3D9_DEVICE )
{
CD3D9Enumeration *pEnum = DXUTGetD3D9Enumeration();
CD3D9EnumDeviceSettingsCombo *pCombo;

pCombo = pEnum->GetDeviceSettingsCombo( pDeviceSettings );

if( pCombo->depthStencilFormatList.Contains( D3DFMT_D24S8 ) )
pDeviceSettings->d3d9.pp.AutoDepthStencilFormat =
D3DFMT_D24S8;
}

return true;
}

对硬件的顶点着色器版本的检查,看他是否支持指定版本。也是通过ModifyDeviceSetting进行验证
bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings*
pDeviceSettings,
void* pUserContext )
{
if( pDeviceSettings->ver == DXUT_D3D9_DEVICE )
{
D3DCAPS9 caps;
DXUTGetD3D9DeviceCaps( pDeviceSettings, &caps );

// If device doesn't support HW T&L or doesn't support 1.1
vertex
// shaders in HW, then switch to SWVP.
if( (pCaps->DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0 ||
pCaps->VertexShaderVersion < D3DVS_VERSION(1,1) )
{
pDeviceSettings->d3d9.BehaviorFlags =
D3DCREATE_SOFTWARE_VERTEXPROCESSING;
}

else
{
pDeviceSettings->d3d9.BehaviorFlags =
D3DCREATE_HARDWARE_VERTEXPROCESSING;
}
}

return true;
}

创建主循环
当你 初始化DXUT--->>>创建一个窗口------>>>创建一个设备 后,下一步就是执行主循环(也可以叫做 渲染循环 和 消息循
环 )。
这个主循环 响应设备事件 窗口消息,然后更新场景 渲染场景。

普通的主循环:
在DXUT里面提供了最容易的方法来创建主循环。通过调用 DXUTMainLoop来实现就可以了。
当这个函数调用过后,当应用程序关闭才返回。应用程序会注册设备事件毁掉,和消息响应。

自定义的主循环:
自定义一个主循环是写应用程序比较好的选择。下面是自定义的一个消息循环
INT WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, INT )
{
DXUTSetCallbackD3D9DeviceAcceptable( IsDeviceAcceptable );
DXUTSetCallbackD3D9DeviceCreated( OnCreateDevice );
DXUTSetCallbackD3D9DeviceReset( OnResetDevice );
DXUTSetCallbackD3D9FrameRender( OnFrameRender );
DXUTSetCallbackD3D9DeviceLost( OnLostDevice );
DXUTSetCallbackD3D9DeviceDestroyed( OnDestroyDevice );
DXUTSetCallbackMsgProc( MsgProc );
DXUTSetCallbackKeyboard( KeyboardProc );
DXUTSetCallbackFrameMove( OnFrameMove );
DXUTSetCallbackDeviceChanging( ModifyDeviceSettings );

DXUTInit( true, true );
DXUTCreateWindow( L"Example" );
DXUTCreateDevice( true, 640, 480 );

// Custom main loop
HWND hWnd = DXUTGetHWND();
BOOL bGotMsg;
MSG msg;
msg.message = WM_NULL;
PeekMessage( &msg, NULL, 0U, 0U, PM_NOREMOVE );

while( WM_QUIT != msg.message )
{
// Use PeekMessage() so we can use idle time to render the
scene
bGotMsg = ( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) !=
0 );

if( bGotMsg )
{
// Translate and dispatch the message
if( 0 == TranslateAccelerator( hWnd, NULL, &msg ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
}
else
{
// Render a frame during idle time (no messages are
waiting)
DXUTRender3DEnvironment();
}
}

return DXUTGetExitCode();
}
这个例子调用 DXUTRender3DEnvironment 函数来实现 场景的更新渲染和设备事件的处理。当然你也可以完全不用
这个函数,自己处理但不推荐。

处理事件:
一旦你 初始了DXUT----->>>>>创建了窗口------>>>创建了渲染设备------->>>创建了主循环。下一步就是处理消息
DXUT 使用一个回调函数机制来响应事件。应用程序需要注册一系列的对调函数指针给DXUT,然后当事件发生DXUT将调用这些函数。
DXUT不需要你一定设置这些回调函数,只有你需要时你才设置。

可以通过DXUTSetCallback***函数来设置一个函数,这个函数有两个参数,第一个指定对调函数的指针,
第二个是void *pUserContext,可以允许回调函数接受一个应用程序的指针,比如一个类指针。

在DXUT里有三种类型的事件:
.Device 事件
.Frame 事件
.Window 事件

渲染设备事件
当应用程序通过Direct3D 9设备来渲染,可能设备会丢失(当按下windows键从全屏模式到窗口模式).或者按下ALT+TAB离开全屏模
式,
或者CTRL+ALT+DEL.
当设备丢失后,应用程序将释放所有的Direct3D对象(如果对象被创建是在(D3DPOOL_DEFAULT)内存里,如果这些对象被释放,他们不

被reset(复原)). 可以调用IDirect3DDevice9::Reset里重新创建所有的对象。
记得以前回了处理这个设备丢失,是通过查看应用程序是否有效来通知设备来 reset.

但在DXUT里,这一过程只需要简单的调用一个回调函数在应用程序里,可以处理各种与设备相关的事件。
例如:changing,created,reset,lost,destroyed.我们要做的就是注册回调函数,实现回调函数。

详细函数信息查看MSDN或者例子代码去找。

这些回调函数不是一定要注册,但是最好注册实现掉。

帧事件:
DXUT也提供了帧事件对调,通过DXUTSetCallbackFrameMove和DXUTSetCallbackD3D9FrameRender
注册
前面注册的回调函数是在帧开始的时候调用,后面注册的函数是在帧结束时候调用。

消息事件:
DXUT传递windows消息,键盘事件,鼠标事件通过下面对调函数来设置。然后写这些回调函数来处理这些事件。
DXUTSetCallbackMsgProc 设置window消息处理函数
DXUTSetCallbackKeyboard 设置键盘消息处理函数
DXUTSetCallbackMouse 设置鼠标消息处理回调函数
Reply all
Reply to author
Forward
0 new messages