一天搞定DXUT三步曲之一:DXUT框架

 

   当初学GL的时候, 一直想写那个HDR的SHADER程序,苦于没有框架,再加上GL的例子太少,最后果断踏上了DX这条不归路.花了一天时间(准确的说是第一天的上午和第二天的下午)把DXUT的框架学习了,感觉很不错.算是正式踏上了DX这条大道.后面的无数的SHADER等着去实现,心里难免有点小激动!!!好了费话不多说了,跟着来吧,把这三个例子实现了,你就可以随意使用DXUT框架了.呵呵!!!

 

 

我的DX-SDK版本为:Microsoft DirectX SDK (June 2010)

这时的下载地址为:http://download.microsoft.com/download/A/E/7/AE743F1F-632B-4809-87A9-AA1BB3458E31/DXSDK_Jun10.exe
不知道以后会失效不!

 

版本一定要对,不然生成的DXUT框架代码不一样,会死人的!!!

 

开发环境为VS2008,D3D9

 

第一步:打开DirectX Sample Browser(June 2010)

第二步:找到EmptyProject项目(可以通过搜索empty快速定位):

这里我们需要最下面一个,那个才是DX9的框架

第三步:点击Install Project,选好目录,生成之.

最后,我们来分析下它生成的代码吧.

打开2008的项目文件

 

//--------------------------------------------------------------------------------------
// File: chap1_dx9.cpp
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//--------------------------------------------------------------------------------------
#include "DXUT.h"
#include "resource.h"


//--------------------------------------------------------------------------------------
// Rejects any D3D9 devices that aren't acceptable to the app by returning false
//--------------------------------------------------------------------------------------
bool CALLBACK IsD3D9DeviceAcceptable( D3DCAPS9* pCaps, D3DFORMAT AdapterFormat, D3DFORMAT BackBufferFormat,
                                      bool bWindowed, void* pUserContext )
{
    // Typically want to skip back buffer formats that don't support alpha blending
    IDirect3D9* pD3D = DXUTGetD3D9Object();
    if( FAILED( pD3D->CheckDeviceFormat( pCaps->AdapterOrdinal, pCaps->DeviceType,
                                         AdapterFormat, D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING,
                                         D3DRTYPE_TEXTURE, BackBufferFormat ) ) )
        return false;

    return true;
}
/*知识点8.2:选择最好的设备设置
---------------------------------------------
来自<<DXUT框架剖析(4)>>
---------------------------------------------
在回调函数IsD3D9DeviceAcceptable()被每种设置的组合调用之后,框架把这些可以接受的组合分级,并从中选出最优的使用。较高级别的组合
包括:

(1)D3DDEVTYPE_HAL,为了得到硬件加速。

(2)如果该应用程序运行在全屏模式下,该框架会选择桌面格式所对应的适配器格式,这样从窗口到全屏模式的转换就快多了。例外的是,
 如果桌面显示模式不足32位,该框架会选择D3DFMT_X8R8G8B8。

(3)适配器格式所对应的后台缓冲区格式。

IDirect3D9::CheckDeviceFormat Method
Determines whether a surface format is available as a specified resource type and can be used as a texture, depth-stencil 
buffer, or render target, or any combination of the three, on a device representing this adapter.

Syntax
HRESULT CheckDeviceFormat(
  [in]  UINT Adapter,
  [in]  D3DDEVTYPE DeviceType,
  [in]  D3DFORMAT AdapterFormat,
  [in]  DWORD Usage,
  [in]  D3DRESOURCETYPE RType,
  [in]  D3DFORMAT CheckFormat
);

Parameters
Adapter [in] 
UINT 
Ordinal number denoting the display adapter to query. D3DADAPTER_DEFAULT is always the primary display adapter. 
This method returns D3DERR_INVALIDCALL when this value equals or exceeds the number of display adapters in the system. 

DeviceType [in] 
D3DDEVTYPE 
Member of the D3DDEVTYPE enumerated type, identifying the device type.

AdapterFormat [in] 
D3DFORMAT 
Member of the D3DFORMAT enumerated type, identifying the format of the display mode into which the adapter will be placed.

Usage [in] 
DWORD 
Requested usage options for the surface. Usage options are any combination of D3DUSAGE and D3DUSAGE_QUERY constants 
(only a subset of the D3DUSAGE constants are valid for CheckDeviceFormat; see the table on the D3DUSAGE page).

RType [in] 
D3DRESOURCETYPE 
Resource type requested for use with the queried format. Member of D3DRESOURCETYPE. 

CheckFormat [in] 
D3DFORMAT 
Format of the surfaces which may be used, as defined by Usage. Member of D3DFORMAT.

Return Value
HRESULT 

If the format is compatible with the specified device for the requested usage, this method returns D3D_OK.

D3DERR_INVALIDCALL is returned if Adapter equals or exceeds the number of display adapters in the system, or if DeviceType is 
unsupported.

D3DERR_NOTAVAILABLE is returned if the format is not acceptable to the device for this usage.

Remarks
Here are some examples using CheckDeviceFormat to check for hardware support of:

An off-screen plain surface format - Specify Usage = 0 and RType = D3DRTYPE_SURFACE. 
A depth-stencil format - The following snippet tests for the passed in depth-stencil format: 
BOOL IsDepthFormatExisting( D3DFORMAT DepthFormat, D3DFORMAT AdapterFormat ) 
{
    HRESULT hr = pD3D->CheckDeviceFormat( D3DADAPTER_DEFAULT,
                                          D3DDEVTYPE_HAL,
                                          AdapterFormat,
                                          D3DUSAGE_DEPTHSTENCIL,
                                          D3DRTYPE_SURFACE,
                                          DepthFormat);
    
    return SUCCEEDED( hr );
}

See Selecting a Device (Direct3D 9) for more detail on the enumeration process.

Can this texture be rendered in a particular format - Given the current display mode, this example shows how to verify that 
the texture format is compatible with the specific back-buffer format: 
BOOL IsTextureFormatOk( D3DFORMAT TextureFormat, D3DFORMAT AdapterFormat ) 
{
    HRESULT hr = pD3D->CheckDeviceFormat( D3DADAPTER_DEFAULT,
                                          D3DDEVTYPE_HAL,
                                          AdapterFormat,
                                          0,
                                          D3DRTYPE_TEXTURE,
                                          TextureFormat);
    
    return SUCCEEDED( hr );
}

Alpha blending in a pixel shader - Set Usage to D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING. Expect this to fail for all 
floating-point render targets. 
Autogeneration of mipmaps - Set Usage to D3DUSAGE_AUTOGENMIPMAP. If the mipmap automatic generation fails, the application will
get a non-mipmapped texture. Calling this method is considered a hint, so this method can return D3DOK_NOAUTOGEN 
(a valid success code) if the only thing that fails is the mipmap generation. For more information about mipmap generation, 
see Automatic Generation of Mipmaps (Direct3D 9). 

When migrating code from Direct3D 9 to Direct3D 10, the Direct3D 10 equivalent to CheckDeviceFormat is CheckFormatSupport.




*/


//--------------------------------------------------------------------------------------
// Before a device is created, modify the device settings as needed
//--------------------------------------------------------------------------------------
bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, void* pUserContext )
{
    return true;
}


//--------------------------------------------------------------------------------------
// Create any D3D9 resources that will live through a device reset (D3DPOOL_MANAGED)
// and aren't tied to the back buffer size
//--------------------------------------------------------------------------------------
HRESULT CALLBACK OnD3D9CreateDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc,
                                     void* pUserContext )
{
    return S_OK;
}


//--------------------------------------------------------------------------------------
// Create any D3D9 resources that won't live through a device reset (D3DPOOL_DEFAULT) 
// or that are tied to the back buffer size 
//--------------------------------------------------------------------------------------
HRESULT CALLBACK OnD3D9ResetDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc,
                                    void* pUserContext )
{
    return S_OK;
}


//--------------------------------------------------------------------------------------
// Handle updates to the scene.  This is called regardless of which D3D API is used
//--------------------------------------------------------------------------------------
void CALLBACK OnFrameMove( double fTime, float fElapsedTime, void* pUserContext )
{
}


//--------------------------------------------------------------------------------------
// Render the scene using the D3D9 device
//--------------------------------------------------------------------------------------
void CALLBACK OnD3D9FrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext )
{
    HRESULT hr;

    // Clear the render target and the zbuffer 
    V( pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB( 0, 45, 50, 170 ), 1.0f, 0 ) );

    // Render the scene
    if( SUCCEEDED( pd3dDevice->BeginScene() ) )
    {
        V( pd3dDevice->EndScene() );
    }
}


//--------------------------------------------------------------------------------------
// Handle messages to the application 
//--------------------------------------------------------------------------------------
LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
                          bool* pbNoFurtherProcessing, void* pUserContext )
{
    return 0;
}


//--------------------------------------------------------------------------------------
// Release D3D9 resources created in the OnD3D9ResetDevice callback 
//--------------------------------------------------------------------------------------
void CALLBACK OnD3D9LostDevice( void* pUserContext )
{
}


//--------------------------------------------------------------------------------------
// Release D3D9 resources created in the OnD3D9CreateDevice callback 
//--------------------------------------------------------------------------------------
void CALLBACK OnD3D9DestroyDevice( void* pUserContext )
{
}


//--------------------------------------------------------------------------------------
// Initialize everything and go into a render loop
//--------------------------------------------------------------------------------------
INT WINAPI wWinMain( HINSTANCE, HINSTANCE, LPWSTR, int )
{
    // Enable run-time memory check for debug builds.
#if defined(DEBUG) | defined(_DEBUG)
    _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
#endif

    // Set the callback functions
    DXUTSetCallbackD3D9DeviceAcceptable( IsD3D9DeviceAcceptable );
/*知识点8.1:选择最好的设备设置
---------------------------------------------
来自<<DXUT框架剖析(4)>>
---------------------------------------------
在应用程序中,可以使用DXUTSetCallbackD3D9DeviceAcceptable设置回调函数IsDeviceAcceptable()帮助DXUT框架为应用程序选择最好的设备,
该函数的声明如下:
Sets the Direct3D 9 device acceptable callback function.
VOID DXUTSetCallbackD3D9DeviceAcceptable(
         LPDXUTCALLBACKISD3D9DEVICEACCEPTABLE pCallback,
         void* pUserContext
)
 

Parameters
pCallback
[in] Pointer to a LPDXUTCALLBACKISD3D9DEVICEACCEPTABLE callback function. If the callback function is supplied, it will be 
called after the Direct3D 9 device. 
pUserContext
[in] Pointer to a user-defined value which is passed to the callback function. Typically used by an application to pass a 
pointer to a data structure that provides context information for the callback function. The default value is NULL. 
Return Value
No return value.
----------------------------------------
Application-defined callback function, called by DXUT to build an enumerated list of all possible Direct3D 9 devices. 
DXUT then selects the best device for creation among this list. This callback function allows the application to prevent
unwanted devices from being added to the list.

bool LPDXUTCALLBACKISD3D9DEVICEACCEPTABLE(
         D3DCAPS9* pCaps,
         D3DFORMAT AdapterFormat,
         D3DFORMAT BackBufferFormat,
         bool bWindowed,
         void* pUserContext
)
 

Parameters
pCaps
[in] Pointer to the D3DCAPS9 capabilities of the Direct3D 9 device 
AdapterFormat
[in] Format of the Direct3D 9 adapter 
BackBufferFormat
[in] Format of the Direct3D 9 backbuffer 
bWindowed
[in] Indicates windowed mode. TRUE if the application runs windowed; FALSE if the application runs full-screen. 
pUserContext
[in] Pointer to a user-defined value which is passed to the callback function. Typically used by an application to pass a 
pointer to a data structure that provides context information for the callback function. The default value is NULL 
Return Value
Program the application to return TRUE if the device settings are acceptable. If not, the application should return FALSE.

Remarks
This function's parameters describe a set of unique valid device settings that could be used to create a device. The 
application can examine and reject this set if desired.

All possible unique valid combinations of the following device settings are sent to this callback function:

pCaps

AdapterFormat

BackBufferFormat

bWindowed

After the application rejects the unwanted device settings combinations, DXUT picks the best of the remaining combinations and
uses that best combination to create the device. Before creating the device, DXUT calls LPDXUTCALLBACKMODIFYDEVICESETTINGS to 
allow the application to change any of the device creation settings.

应用程序可以使用这个回调函数拒绝任何硬件不支持或不想要的组合。例如,应用程序可以使用下列代码拒绝16位后台缓冲区格式以及所有至少
不支持像素渲染2.0版本的设备:

bool CALLBACK IsD3D9DeviceAcceptable(D3DCAPS9* pCaps, D3DFORMAT AdapterFormat, D3DFORMAT BackBufferFormat,
bool bWindowed, void* pUserContext)
{	
	if(pCaps->PixelShaderVersion < D3DPS_VERSION(2, 0))		
		return false;
	if(BackBufferFormat == D3DFMT_X1R5G5B5 || BackBufferFormat == D3DFMT_R5G6B5)		
		return false;
	return true;
}
*/    
	DXUTSetCallbackDeviceChanging( ModifyDeviceSettings );
/*知识点9:修改可用的设备
---------------------------------------------
来自<<DXUT框架剖析(5)>>
---------------------------------------------
应用程序可以通过DXUTSetCallbackDeviceChanging()设置回调函数来修改Direct3D设备的创建设置:

Sets a callback function that allow the application to change the device settings before the device is created.
VOID DXUTSetCallbackDeviceChanging(
         LPDXUTCALLBACKMODIFYDEVICESETTINGS pCallbackModifyDeviceSettings,
         void* pUserContext
)
 

Parameters
pCallbackModifyDeviceSettings
[in] Pointer to a LPDXUTCALLBACKMODIFYDEVICESETTINGS callback function. If the callback function is supplied, it will be called
before the Direct3D device is created. If NULL, DXUT will not notify the application about device changes. 
pUserContext
[in] Pointer to a user-defined value which is passed to the callback function. Typically used by an application to pass a 
pointer to a data structure that provides context information for the callback function. The default value is NULL 
Return Value
No return value.

Remarks
Before a device is created by DXUT, the LPDXUTCALLBACKMODIFYDEVICESETTINGS callback will be called to allow the application to
examine or change the device settings before the device is created. This allows an application to modify the device creation 
settings as it sees fit.

This callback also allows applications to reject changing the device altogether. Returning false from inside this callback will
notify DXUT to keep using the current device instead of changing to the new device.

-------------------------------------
Application-defined callback function, called by DXUT to allow changes in device settings before the device is created.

bool LPDXUTCALLBACKMODIFYDEVICESETTINGS(
         DXUTDeviceSettings * pDeviceSettings,
         void* pUserContext
)
 

Parameters
pDeviceSettings
[in] Pointer to a DXUTDeviceSettings structure that contains the settings for the new device. 
pUserContext
[in] Pointer to a user-defined value which is passed to the callback function. Typically used by an application to pass a 
pointer to a data structure that provides context information for the callback function. The default value is NULL 
Return Value
Program the application to return true to continue creating the device. If not, the application should return false to continue
using the current device if one exists.

Remarks
Before a device is created by DXUT, the LPDXUTCALLBACKMODIFYDEVICESETTINGS callback will be called to allow the application to
examine or change the device settings before the device is created. This allows an application to modify the device creation 
settings as it sees fit.

This callback also allows applications to reject changing the device altogether. Returning false from inside this callback will
notify DXUT to keep using the current device instead of changing to the new device.

Anything in pDeviceSettings can be changed by the application. DXUT will not prevent the failure of device creation caused by
changes to device settings.

---------------------------------------------
DXUTDeviceSettings
A union of settings describing how to create the Direct3D 9 or Direct3D 10 device.
typedef struct DXUTDeviceSettings {
    DXUTDeviceVersion ver;
    union {
        DXUTD3D9DeviceSettings d3d9;
        DXUTD3D10DeviceSettings d3d10;
    };
} DXUTDeviceSettings, *LPDXUTDeviceSettings;

Members
ver 
Indicates whether the settings structure is for a Direct3D 9 or Direct3D 10 device. 
d3d9 
Device settings for Direct3D 9 device. Only valid if ver is DXUT_D3D9_DEVICE. 
d3d10 
Device settings for Direct3D 10 device. Only valid if ver is DXUT_D3D10_DEVICE. 
Remarks
The DXUTDeviceSettings can only describe a single device because the DXUTD3D9DeviceSettings and DXUTD3D10DeviceSettings member
variables are unioned together. The DXUTDeviceVersion indicates which of these structures is valid.
--------------------------------------
DXUTD3D9DeviceSettings

Describes the settings used to create a Direct3D 9 device.

typedef struct DXUTD3D9DeviceSettings {
    UINT AdapterOrdinal;
    D3DDEVTYPE DeviceType;
    D3DFORMAT AdapterFormat;
    DWORD BehaviorFlags;
    D3DPRESENT_PARAMETERS pp;
} DXUTD3D9DeviceSettings, *LPDXUTD3D9DeviceSettings;
 

Members
AdapterOrdinal
Ordinal number that denotes the display adapter. 
DeviceType
Enumerated type of the device. 
AdapterFormat
Adapter surface format. 
BehaviorFlags
Behavior flags. This member can be a combination of one or more of the D3DCREATE values. 
pp
Presentation parameters structure. 

DXUT fills this structure with valid values, and then passes the structure to the callback function where the application can
modify it. Be sure to validate any changes your application makes in this callback function. Here is an example that changes
the depth-stencil format.
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;
}

回调函数ModifyDeviceSettings()返回一个布尔值,如果应用程序返回TRUE,DXUT框架继续像在正常情况下那样进行设备创建。如果返回FALSE,
框架不能改变设备,如果已有一个设备,则继续使用当前设备。如果框架提出的请求是改变到一个应用程序不能使用的设备,应用程序可以拒绝
该请求。例如,在一个多显示器配置中,默认情况下在显示器之间拖动窗口将使框架改变设备。但如果应用程序不能使用其他设备,它就必须拒
绝这种改变并继续使用当前设备。

再举一例:降级到软件顶点处理

Be careful if your hardware supports pixel processing (transforms and lighting) but does not support vertex processing. 
One common mistake is to reject devices based on the vertex shader version in the (LPDXUTCALLBACKISD3D9DEVICEACCEPTABLE or 
LPDXUTCALLBACKISD3D10DEVICEACCEPTABLE) callback functions. The correct solution is to implement the checking in the 
ModifyDeviceSettings callback function as shown here.

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; 
}




*/
    DXUTSetCallbackD3D9DeviceCreated( OnD3D9CreateDevice );
    DXUTSetCallbackD3D9DeviceReset( OnD3D9ResetDevice );

/*知识点1:第一阶段:启动
---------------------------------------------
来自<<DXUT框架剖析(1)>> 1
---------------------------------------------



DXUT框架依次执行IsD3D9DeviceAcceptable()、ModifyDeviceSettings()、OnD3D9CreateDevice()、OnD3D9ResetDevice()这4个函数。

在创建某个Direct3D渲染设备之前,如果需要对渲染设备的特征进行检查,查看设备是否支持需要的功能,可将检查代码写在函数
IsD3D9DeviceAcceptable()中。

在某个渲染设备创建之前,如果需要修改该渲染设备的设置,可将代码写在函数ModifyDeviceSettings()中。DXUT框架接下来就根据
设置(或者是默认设置)创建最适合当前硬件的Direct3D渲染设备。例如,当硬件不支持某些功能时,可以通过使用参考设备进行模拟,
设置使用参考设备代码通常写在该函数中。

DXUT框架创建了Direct3D设备之后,接下来会调用OnD3D9CreateDevice()回调函数,可在OnD3D9CreateDevice()回调函数中创建所有
内存池类型为D3DPOOL_MANAGED或D3DPOOL_SYSTEMMEM的资源。以类型D3DPOOL_MANAGED创建的设备由Direct3D系统代替管理(位于显存
或系统内存中),以类型D3DPOOL_SYSTEMMEM创建的设备位于系统内存中,在程序退出之前,这些资源常驻内存,不会出现设备丢失的
现象。也就是说,以这两种内存类型创建的资源不需要程序员进行管理。

DXUT框架在调用OnD3D9CreateDevice()回调函数之后,将调用OnD3D9ResetDevice()回调函数。我们可在函数OnD3D9ResetDevice()中创
建所有内存池类型为D3DPOOL_DEFAULT的资源,这一类资源将尽可能存放在显存中,这样可以提高程序的运行速度。但是,这类资源在
程序运行时会出现设备丢失的现象(lost device:monitor resolution change,user locked and unlocked the OS,etc),因此需要程
序员自己管理。在设备丢失时释放它的内存,当设备恢复时重新为它分配内存。此外,观察变换矩阵和投影变换矩阵以及在整个程序运
行期间保持不变的渲染状态通常也在该回调函数中设置。

如果性能不是很重要,使用D3DPOOL_MANAGED内存类型资源永远是一种安全的选择。

*/

/*知识点2:Memory Pools

---------------------------------------------
来自龙书P41
---------------------------------------------
1.3.4 Memory Pools
Surfaces and other Direct3D resources can be placed in a variety of
memory pools. The memory pool is specified by one of the members of
the D3DPOOL enumerated type. The memory pools available are:
 D3DPOOL_DEFAULT—The default memory pool instructs
Direct3D to place the resource in the memory that is best suited
for the resource type and its usage. This may be video memory,
AGP memory, or system memory. Note that resources in the
default pool must be destroyed (released) prior to an IDirect-
3DDevice9::Reset call, and must be reinitialized after the reset
call.
 D3DPOOL_MANAGED—Resources placed in the manage pool are
managed by Direct3D (that is, they are moved to video or AGP
memory as needed by the device automatically). In addition, a
back-up copy of the resource is maintained in system memory.
When resources are accessed and changed by the application, they
work with the system copy. Then, Direct3D automatically updates
them to video memory as needed.
 D3DPOOL_SYSTEMMEM—Specifies that the resource be placed in
system memory
 D3DPOOL_SCRATCH—Specifies that the resource be placed in system
memory. The difference between this pool and D3DPOOL_
SYSTEMMEM is that these resources must not follow the graphics
device’s restrictions. Consequently, the device cannot access
resources in this pool. But the resources can be copied to and from
each other.
*/    


	DXUTSetCallbackMsgProc( MsgProc );
	DXUTSetCallbackFrameMove( OnFrameMove );
	DXUTSetCallbackD3D9FrameRender( OnD3D9FrameRender );
    DXUTSetCallbackD3D9DeviceLost( OnD3D9LostDevice );
    DXUTSetCallbackD3D9DeviceDestroyed( OnD3D9DestroyDevice );
/*知识点3:第二阶段:运行

---------------------------------------------
来自<<DXUT框架剖析(1)>>
---------------------------------------------
DXUT框架调用回调函数MsgProc()处理各类消息,并在空闲时间反复调用OnFrameMove()和OnFrameRender()两个函数进行场景渲染。

在每一帧中,程序为实现对场景的刷新,为用户输入的响应而编写的代码通常写在函数OnFrameMove()中,例如设置世界变换矩阵实现
物体的运动,它相当于“update”的性质,真正进行渲染的代码写在函数OnFrameRender()中。

需要说明的是,在应用程序运行期间,当Direct3D设备变为丢失状态时,DXUT框架会调用OnD3D9LostDevice()函数,释放所有在回调
函数OnD3D9ResetDevice()中创建的设备资源。也就是说,这时释放的资源都是D3DPOOL_DEFAULT类型的。当Direct3D设备从丢失状态
恢复时,DXUT框架会调用回调函数OnD3D9ResetDevice()重新创建所有类型为D3DPOOL_DEFAULT的资源。也就是说,在程序运行时,如
果出现设备丢失现象,OnD3D9LostDevice()和OnD3D9ResetDevice()这一对函数就需要分别调用一次。
*/    

/*知识点4:第三阶段:退出


---------------------------------------------
来自<<DXUT框架剖析(1)>>
---------------------------------------------
在退出程序时,DXUT框架会依次调用OnD3D9LostDevice()和OnD3D9DestroyDevice()回调函数,在函数OnD3D9LostDevice()中释放由函数
OnD3D9ResetDevice()创建的资源,在函数OnD3D9DestroyDevice()中释放由函数OnD3D9CreateDevice()创建的资源。

*/   

/*知识点11:处理事件

---------------------------------------------
来自<<DXUT框架剖析(6,7)>>
---------------------------------------------
框架使用回调函数机制来使应用程序对事件做出反应。应用程序只需对框架注册和设置相应的函数指针,则当事件发生时,框架就会调用相应的
函数。框架不需要注册所有的回调函数,所以应用程序只须对所需要的回调函数进行注册即可。通过为回调函数设置参数pUserContext,回调函
数可以从应用程序接受内容,比如将该参数设置为一个指向类对象的指针。

DXUT框架可以处理以下事件类型:
(1)设备事件 

当应用程序使用Direct3D设备渲染图形时,该设备有可能处于丢失状态。这种情况的发生有多种原因,例如按下Alt + Tab键离开一个全屏模式
的应用程序,或者按下Ctrl + Alt + Del键,或者启动了另一个全屏3D应用程序。发生这种情况时,当调用一些函数(如Present)时,Direct3D
API通过返回D3DERR_DEVICELOST通知应用程序设备丢失。

当设备丢失时,应用程序负责释放所有不能在设备丢失时存在的Direct3D资源对象,如在D3DPOOL_DEFAULT内存池中创建的对象。如果没有释放这
些对象,那么该设备从丢失状态返回时就不能被重新设置。当设备丢失时,应用程序必须等待。当设备返回时,应用程序必须调用函数 
IDirect3DDevice9::Reset(),并重新创建所有不能在Reset()函数中存在的对象。

通过DXUT框架,这个过程可以通过在应用程序中使用回调函数来简化,这些回调函数处理各种设备事件:设备改变、创建、重新设置、丢失或
销毁。当设备丢失时,框架会有提示;当它从丢失状态返回时,框架会适当调用相应的回调函数,重新设置该设备,即框架使用应用程序的回调
函数在适当的时间释放和重新创建设备对象。应用程序需要做的是注册并实现相关回调函数,各回调函数的类型、注册、调用时机等细节见下表:


注册函数  
应用程序回调函数  
框架调用时机  
创建资源  
释放资源  

DXUTSetCallbackDeviceChanging 
LPDXUTCALLBACKMODIFYDEVICESETTINGS 
在创建Direct3D设备之前调用,应用程序可以返回FALSE,拒绝改变该设备。 
x
x

DXUTSetCallbackD3D9DeviceCreated  
LPDXUTCALLBACKD3D9DEVICECREATED  
当应用程序初始化和重新创建设备时,在Direct3D设备创建之后立即调用。 
创建D3DPOOL_MANAGED资源,因为这些资源无论什么时候被销毁都需要重新加载,但这些资源被重新设置时不需要重新加载。在这里创建的资源
需要在LPDXUTCALLBACK-DEVICEDESTROYED中释放。 
x 

DXUTSetCallbackD3D9DeviceReset
LPDXUTCALLBACKD3D9DEVICERESET 
当Direct3D设备丢失又被重新设置后立即调用。 
创建D3DPOOL_DEFAULT资源,因为这些资源无论什么时候丢失或重新设置时都需要重新加载,在这里创建的资源需要在
LPDXUTCALLBACK-DEVICELOST中释放。 
x 

DXUTSetCallbackD3D9DeviceLost 
LPDXUTCALLBACKD3D9DEVICELOST 
当Direct3D设备变为丢失状态且在Reset调用之前,立即调用。 
x 
释放在回调函数LPDXUTCALLBACK-D3D9DEVICERESET中创建的资源,这些资源通常包括所有的D3DPOOL_DEFAULT资源。 

DXUTSetCallbackD3D9DeviceDestroyed  
LPDXUTCALLBACKD3D9DEVICEDESTROYED  
当应用程序终止或重新创建设备时,Direct3D设备被销毁后,立即调用。 
x 
释放在回调函数LPDXUTCALLBACKD3D9DEVICECREATED中创建的资源,这些资源通常包括所有的D3DPOOL_MANAGED资源。 


当设备在窗口和全屏模式间切换时常常需要重新设置,但有时它必须通过Direct3D重新创建。

调用这些回调函数是可选的,但如果应用程序没有使用函数DXUTSetCallbackD3D9DeviceDestroyed()和 DXUTSetCallbackD3D9DeviceCreated()
注册销毁回调函数和创建回调函数,则改变设备或在硬件抽象层设备和参考设备间切换都不能进行。

类似地,如果没有用函数DXUTSetCallbackD3D9DeviceLost()和 DXUTSetCallbackD3D9DeviceReset()注册丢失回调函数和重置回调函数,
则当设备丢失或重置设备时,框架无法通知应用程序。这样一来,所有不在D3DPOOL_MANAGED内存中的设备对象都不能重新设置。

(2)帧事件 

框架也提供了帧事件,它在渲染过程中的每一帧被调用,应用程序应该注册并实现这些回调函数,如下表所示:

应用程序回调函数  
注册回调函数  
框架调用时机  
场景渲染  
LPDXUTCALLBACKFRAMEMOVE
DXUTSetCallbackFrameMove 
在每一帧开始时调用一次 
这个回调函数是应用程序处理场景更新的最好位置,但它不应包括实际的渲染调用,渲染调用应放在帧渲染回调函数中。

LPDXUTCALLBACKD3D9FRAMERENDER
DXUTSetCallbackD3D9FrameRender 
在每一帧结束或窗口需要重画时调用 
所有对场景的渲染调用都应在此回调函数中完成,在这个回调函数返回后,框架将调用Present()来显示交换链中下一缓冲区的内容。 
DXUTSetCallbackFrameMove 

Sets the frame update callback function.


VOID DXUTSetCallbackFrameMove(
         LPDXUTCALLBACKFRAMEMOVE pCallbackFrameMove,
         void* pUserContext
)
 

Parameters
pCallbackFrameMove
[in] Pointer to a LPDXUTCALLBACKFRAMEMOVE callback function. If the callback function is supplied, it will be called at the
beginning of every frame to facilitate updates to the scene. If NULL, DXUT will not notify the application about new frames. 
pUserContext
[in] Pointer to a user-defined value which is passed to the callback function. Typically used by an application to pass a 
pointer to a data structure that provides context information for the callback function. The default value is NULL 
Return Value
No return value.

Remarks
The LPDXUTCALLBACKFRAMEMOVE callback function is the appropriate location for the application to handle updates to the scene. 
However, LPDXUTCALLBACKFRAMEMOVE is not intended to contain actual rendering calls, which should instead be placed in the 
LPDXUTCALLBACKD3D9FRAMERENDER or LPDXUTCALLBACKD3D10FRAMERENDER callback function. These callbacks is called when rendering 
with either Direct3D 9 or Direct3D 10 respectively.

The LPDXUTCALLBACKFRAMEMOVE callback function will be called once per frame, while the render callback function will be called
whenever the scene needs to be rendered, which might be more than once per frame on rare occasion if a WM_PAINT message occurs.

-------------------------------------------------------------------------------------------------------------------------
LPDXUTCALLBACKFRAMEMOVE 

Application-defined callback function that allows for updating the scene. This function is called by DXUT once each frame, before the application renders the scene.

  
VOID LPDXUTCALLBACKFRAMEMOVE(
         DOUBLE fTime,
         FLOAT fElapsedTime,
         void* pUserContext
)
 

Parameters
fTime
[in] Time elapsed since the application started, in seconds. 
fElapsedTime
[in] Time elapsed since the last frame, in seconds. 
pUserContext
[in] Pointer to a user-defined value which is passed to the callback function. Typically used by an application to pass a 
pointer to a data structure that provides context information for the callback function. The default value is NULL 
Return Value
No return value.

Remarks
The LPDXUTCALLBACKFRAMEMOVE callback function is the appropriate location for the application to handle updates to the scene.
However, LPDXUTCALLBACKFRAMEMOVE is not intended to contain actual rendering calls, which should instead be placed in the
LPDXUTCALLBACKD3D9FRAMERENDER or LPDXUTCALLBACKD3D10FRAMERENDER callback function. These callbacks is called when rendering 
with either Direct3D 9 or Direct3D 10 respectively.

The LPDXUTCALLBACKFRAMEMOVE callback function will be called once per frame, while the render callback function will be called
whenever the scene needs to be rendered, which might be more than once per frame on rare occasion if a WM_PAINT message occurs.
----------------------------------------------------------------------------------------------------
DXUTSetCallbackD3D9FrameRender 

Sets the Direct3D 9 frame render callback function.

 
VOID DXUTSetCallbackD3D9FrameRender(
         LPDXUTCALLBACKD3D9FRAMERENDER pCallback,
         void* pUserContext
)
 

Parameters
pCallback
[in] Pointer to a LPDXUTCALLBACKD3D9FRAMERENDER callback function. If the callback function is supplied, it will be called once
per frame for the application to render the current scene using the Direct3D 9 device. If NULL, DXUT will not prompt the 
application to render the scene. 
pUserContext
[in] Pointer to a user-defined value which is passed to the callback function. Typically used by an application to pass a 
pointer to a data structure that provides context information for the callback function. The default value is NULL 
Return Value
No return value.

Remarks
This function only needs to be called if the application supports rendering with Direct3D 9 device.

The LPDXUTCALLBACKD3D9FRAMERENDER callback function is the appropriate location for the application to render the current scene
using the Direct3D 9 device. The LPDXUTCALLBACKFRAMEMOVE callback function will be called once per frame, while 
LPDXUTCALLBACKD3D9FRAMERENDER will be called when the scene needs to be rendered, which might be more than once per frame.

---------------------------------------------------------------------------------
LPDXUTCALLBACKD3D9FRAMERENDER 

Application-defined callback function that allows for rendering the scene using a Direct3D 9 device. This function is called by DXUT at the end of every frame, and whenever the application needs to paint the scene.
 
VOID LPDXUTCALLBACKD3D9FRAMERENDER(
         IDirect3DDevice9 * pd3dDevice,
         DOUBLE fTime,
         FLOAT fElapsedTime,
         void* pUserContext
)
 

Parameters
pd3dDevice
[in] Pointer to the Direct3D 9 device used for rendering. 
fTime
[in] Time elapsed since the application started, in seconds. 
fElapsedTime
[in] Time elapsed since the last frame, in seconds. 
pUserContext
[in] Pointer to a user-defined value which is passed to the callback function. Typically used by an application to pass a 
pointer to a data structure that provides context information for the callback function. The default value is NULL 
Return Value
No return value.

Remarks
The LPDXUTCALLBACKD3D9FRAMERENDER callback function is the appropriate location for the application to render the current
scene using the Direct3D 9 device. The LPDXUTCALLBACKFRAMEMOVE callback function will be called once per frame, while
LPDXUTCALLBACKD3D9FRAMERENDER will be called when the scene needs to be rendered, which might be more than once per frame.

DXUT will call this function after the LPDXUTCALLBACKFRAMEMOVE callback function.

-------------------------------------------------------------------------

在函数 LPDXUTCALLBACKFRAMEMOVE 中,通常进行数据变换,比如设置坐标变换矩阵。在函数 LPDXUTCALLBACKD3D9FRAMERENDER 中,
主要进行图形的渲染.

(3)消息事件 

框架通过下表中的回调函数和相应的注册函数来传递窗口消息、键盘事件和鼠标事件,编写应用程序对这些事件做出适当反应。

应用程序回调函数					注册回调函数							描述  
LPDXUTCALLBACKMSGPROC			DXUTSetCallbackMsgProc			处理来自DXUT消息泵的窗口消息 
LPDXUTCALLBACKKEYBOARD			DXUTSetCallbackKeyboard			处理来自DXUT消息泵的键盘事件 
LPDXUTCALLBACKMOUSE				DXUTSetCallbackMouse			处理来自DXUT消息泵的鼠标事件 


DXUTSetCallbackKeyboard 

Sets the keyboard event callback function.

VOID DXUTSetCallbackKeyboard(
         LPDXUTCALLBACKKEYBOARD pCallbackKeyboard,
         void* pUserContext
)
 

Parameters
pCallbackKeyboard
[in] Pointer to a LPDXUTCALLBACKKEYBOARD keyboard event callback function. If supplied, the callback function will be called
for keyboard events. If NULL, DXUT will not notify the application about keyboard events. 
pUserContext
[in] Pointer to a user-defined value which is passed to the callback function. Typically used by an application to pass a 
pointer to a data structure that provides context information for the callback function. The default value is NULL 
Return Value
No return value.

Remarks
The pCallbackKeyboard keyboard event callback function will be called when any keyboard event occurs.

This callback mechanism is provided to simplify handling keyboard messages through the windows message pump, but does not 
preclude the application from handling those messages directly through the LPDXUTCALLBACKMSGPROC callback.

------------------------------------------------------------------
LPDXUTCALLBACKKEYBOARD 

Application-defined keyboard event callback function, called by DXUT.

VOID LPDXUTCALLBACKKEYBOARD(
         UINT nChar,
         bool bKeyDown,
         bool bAltDown,
         void* pUserContext
)
 

Parameters
nChar
[in] A virtual-key code for the key. See Virtual-Key Codes for a listing. 
bKeyDown
[in] TRUE if key is down. FALSE if the key is up 
bAltDown
[in] TRUE if the ALT key is also down. 
pUserContext
[in] Pointer to a user-defined value which is passed to the callback function. Typically used by an application to pass a
pointer to a data structure that provides context information for the callback function. The default value is NULL 
Return Value
No return value.

Remarks
The pCallbackKeyboard keyboard event callback function will be called when any keyboard event occurs.

This callback mechanism is provided to simplify handling keyboard messages through the windows message pump, but does not
preclude the application from handling those messages directly through the LPDXUTCALLBACKMSGPROC callback.

---------------------------------------------------------------------------------------------------------

DXUTSetCallbackMouse 
Sets the mouse event callback function.

VOID DXUTSetCallbackMouse(
         LPDXUTCALLBACKMOUSE pCallbackMouse,
         BOOL bIncludeMouseMove,
         void* pUserContext
)
 

Parameters
pCallbackMouse
[in] Pointer to an LPDXUTCALLBACKMOUSE mouse event callback function. If supplied, the callback function will be called for
mouse events. If NULL, DXUT will not notify the application about mouse events. 
bIncludeMouseMove
[in] If TRUE, the mouse movement events are passed to the pCallbackMouse callback function. Default value is FALSE. 
pUserContext
[in] Pointer to a user-defined value which is passed to the callback function. Typically used by an application to pass a 
pointer to a data structure that provides context information for the callback function. The default value is NULL 
Return Value
No return value.

Remarks
The pCallbackMouse mouse event callback function will be called when any mouse events occurs

This callback mechanism is provided to simplify handling mouse messages through the Windows message pump, but does not
preclude the application from handling those messages directly in the LPDXUTCALLBACKMSGPROC callback function.
------------------------------------------------------------------------------
LPDXUTCALLBACKMOUSE 

Application-defined mouse event callback function, called by DXUT when it receives mouse events.

VOID LPDXUTCALLBACKMOUSE(
         bool bLeftButtonDown,
         bool bRightButtonDown,
         bool bMiddleButtonDown,
         bool bSideButton1Down,
         bool bSideButton2Down,
         INT nMouseWheelDelta,
         INT xPos,
         INT yPos,
         void* pUserContext
)
 

Parameters
bLeftButtonDown
[in] The left mouse button is down. 
bRightButtonDown
[in] The right mouse button is down. 
bMiddleButtonDown
[in] The middle mouse button is down. 
bSideButton1Down
[in] Windows 2000/Windows XP: The first side button is down. 
bSideButton2Down
[in] Windows 2000/Windows XP: The second side button is down. 
nMouseWheelDelta
[in] The distance and direction the mouse wheel has rolled, expressed in multiples or divisions of WHEEL_DELTA, which is 120.
A positive value indicates that the wheel was rotated forward, away from the user; a negative value indicates that the wheel 
was rotated backward, toward the user. 
xPos
[in] x-coordinate of the pointer, relative to the upper-left corner of the client area. 
yPos
[in] y-coordinate of the pointer, relative to the upper-left corner of the client area. 
pUserContext
[in] Pointer to a user-defined value which is passed to the callback function. Typically used by an application to pass a 
pointer to a data structure that provides context information for the callback function. The default value is NULL 
Return Value
No return value.

Remarks
The pCallbackMouse mouse event callback function will be called when any mouse events occurs

This callback mechanism is provided to simplify handling mouse messages through the Windows message pump, but does not preclude
the application from handling those messages directly in the LPDXUTCALLBACKMSGPROC callback function



*/    


    // TODO: Perform any application-level initialization here

    // Initialize DXUT and create the desired Win32 window and Direct3D device for the application
    DXUTInit( true, true ); // Parse the command line and show msgboxes
/*知识点5:初始化DXUT 

---------------------------------------------
来自<<DXUT框架剖析(3)>>
---------------------------------------------
使用DXUT框架之前,首先需要初始化DXUT,初始化DXUT可以通过函数DXUTInit()完成:
HRESULT DXUTInit(    
	BOOL   bParseCommandLine  ,    
	BOOL   bShowMsgBoxOnError  ,    
	WCHAR *   strExtraCommandLineParams  ,    
	bool   bThreadSafeDXUT  
) ;
Parameters

bParseCommandLine 

[in] If TRUE, DXUT checks for command-line arguments. The application performs the following actions based upon the 
entered command-line arguments. 


Command-line	Action 
Argument   
-forceapi:#		Forces the application to use the specified Direct3D API version. Fails if the application doesn't support this 
				API or if no device is found.  

-adapter:#		Forces the application to use this adapter ordinal. Fails if the adapter ordinal does not exist. 

-output:#		Applies to Direct3D 10 only. Forces the application to use a particular output on the adapter. Fails if the 
				output does not exist.  

-windowed		Forces the application to start in windowed mode.  

-fullscreen		Forces the application to start in full-screen mode.  

-forcehal		Forces the application to use a HAL device type. Fails if a HAL device does not exist.  

-forceref		Forces the application to use a reference device type. Fails if a reference device does not exist.  

-forcehwvp		Applies to Direct3D 9 only. Forces the application to use hardware vertex processing. Fails if the device 
				does not support this mode.  

-forcepurehwvp  Applies to Direct3D 9 only. Forces the application to use pure hardware vertex processing. Fails if the device
				does not support this mode.  

-forceswvp		Applies to Direct3D 9 only. Forces the application to use software vertex processing.  

-forcevsync:#	If # is 0, then vertical sync is disabled. Otherwise, it is enabled. 

-width:#		Forces the application to use the window width #. For full-screen mode, DXUT picks the closest possible 
				supported mode.  

-height:#		Forces the application to use the window height #. For full-screen mode, DXUT picks the closest possible 
				supported mode.  

-startx:#		For windowed mode, forces the application to use the x-coordinate of the window position to the value of #. 

-starty:#		For windowed mode, forces the application to use the y-coordinate of the window position to the value of #. 

-constantframetime  Forces the application to into a mode where DXUT reports that a constant amount of time has passed between
					each frame, where # is the time/frame in seconds. This is useful for such scenarios as rendering an movie 
					that can not render in real time  

-quitafterframe:#	Forces the application to quit after frame #.  

-noerrormsgboxes	Prevents the display of message boxes generated by DXUT, allowing the application to be run without user 
					interaction.  

-nostats		Prevents the display of device and frame statistics by always returning blank strings for DXUTGetDeviceStats
				and DXUTGetFrameStats.  

-automation		This is a simple hint to other components that automation is active. The DXUT GUI uses this to enable UI 
				navigation with keyboard by default.  



Return Values
If the function succeeds, the return value is S_OK. If the function fails, the return value can be one of the error codes in 
DXUTERR.

Remarks
If this function has not been called before DXUTCreateWindow or DXUTSetWindow, DXUT will automatically call this function using
the default parameter values.

通常在WinMain()函数中调用DXUTInit()函数进行DXUT初始化工作,如果程序员没有调用DXUTInit()函数,则DXUT框架会自动使用默认参数调用
该函数。

如果第一个参数 bParseCommandLine 设置为TRUE,则DXUT框架就会使用命令行参数,例如通过下面的命令运行上面的chap1_dx9_2008.exe:

chap1_dx9_2008.exe -windowed -width:1024 -height:768

DXUT框架会尽量使用上面命令行中设置的窗口宽度和高度。

注意:在VS2008中,可以通过 项目->属性->配置属性->调试->命令参数 向程序传入参数

在这里我们只需填入:-windowed -width:1024 -height:768

*/   

	DXUTCreateWindow( L"chap1_dx9" );
/*知识点6:创建一个窗口 
---------------------------------------------
来自<<DXUT框架剖析(3)>>
---------------------------------------------
在应用程序中使用Windows API函数创建窗口是一个比较复杂的过程,如果操作有误,就会导致bug。尽管这对于一个Direct3D程序员来说可能
并不起眼,但在每个应用程序中却都是必须的。而DXUT框架通过函数DXUTCreateWindow()简化了这个过程,该函数的声明如下:

Creates the window for the application.

HRESULT DXUTCreateWindow(
         CONST const WCHAR * strWindowTitle,
         HINSTANCE hInstance,
         HICON hIcon,
         HMENU hMenu,
         INT x,
         INT y
)

Parameters
strWindowTitle 
[in] Title bar caption for the window. The default value is L"Direct3D Window". 
hInstance 
[in] Handle of the application's instance, or NULL to retrieve the handle of the current module. The default value is NULL. 
hIcon 
[in] Handle to the application's icon, or NULL to use the first icon embedded in the application's executable. The default 
value is NULL. 
hMenu 
[in] Handle to the application's menu resource, or NULL to indicate no menu. The default value is NULL. 
x 
[in] Horizontal coordinate of the window's upper left corner, in screen coordinates. Using a value of CW_USEDEFAULT allows 
Windows to choose an appropriate location. The default value is CW_USEDEFAULT. 
y 
[in] Vertical coordinate of the window's upper left corner, in screen coordinates. Using a value of CW_USEDEFAULT allows 
Windows to choose an appropriate location. The default value is CW_USEDEFAULT. 
Return Values
If the function succeeds, the return value is S_OK. If the function fails, the return value can be one of the error codes in 
DXUTERR.

Remarks
This function creates a new window for the application; alternately, the application can handle window creation and pass the 
desired window handle to DXUT by using the DXUTSetWindow function. If neither DXUTCreateWindow nor DXUTSetWindow has been 
called before calling a device creation method, DXUT will call DXUTCreateWindow using the default parameter values. 
The window width and height are set later using the device settings.

All parameters are optional.

If both x and y are CW_USEDEFAULT and a windowed non-primary Direct3D device is created, the window will automatically be moved
to the adapter's monitor to ensure maximum performance.

DXUT框架创建的窗口的句柄可以通过DXUTGetHWND()函数来获取。

如果应用程序要对上面创建的窗口消息做出反应,那么需要使用DXUTSetCallbackMsgProc()来设置一个窗口消息处理函数

Sets the window message callback function.

 VOID DXUTSetCallbackMsgProc(    LPDXUTCALLBACKMSGPROC   pCallbackMsgProc  ,    void*   pUserContext  ) ;
 -----------------------------------------------
 Application-defined function that processes messages from DXUT message pump.

LRESULT LPDXUTCALLBACKMSGPROC(
         HWND hWnd,
         UINT uMsg,
         WPARAM wParam,
         LPARAM lParam,
         bool * pbNoFurtherProcessing,
         void* pUserContext
)
 
Parameters
hWnd
[in] Handle to the window. 
uMsg
[in] Specifies the message. See WindowProc for details. 
wParam
[in] Specifies additional message information. The contents of this parameter depend on the value of the uMsg parameter. 
lParam
[in] Specifies additional message information. The contents of this parameter depend on the value of the uMsg parameter. 
pbNoFurtherProcessing
[out] If TRUE, prevents DXUT from further handling the message. 
pUserContext
[in] Pointer to a user-defined value which is passed to the callback function. Typically used by an application to pass a 
pointer to a data structure that provides context information for the callback function. The default value is NULL 
Return Value
Returns zero if the function has processed window messages successfully; otherwise, returns a nonzero value.

Remarks
This function and its parameters are similar to to the Windows WindowProc function.

With the use of the pbNoFurtherProcessing parameter, the application can control DXUT's level of involvement in processing 
window messages. If the application sets pbNoFurtherProcessing to TRUE in the call to LPDXUTCALLBACKMSGPROC, DXUT will not 
process the message and will immediately return with the value returned by LPDXUTCALLBACKMSGPROC. If the application sets 
pbNoFurtherProcessing to FALSE, DXUT will handle window management events.

在这个回调函数中,因为所有的重要消息都被该框架处理了,所以应用程序可以无需对任何消息做出响应。如果想禁用DXUT框架的消息处理,
应用程序可以将 pbNoFurtherProcessing 设为TRUE。但是,使用这个设置时要格外小心,因为它有可能使框架不能正确运行。

如果想要应用程序创建自己的窗口并同DXUT框架一起使用,那么可以创建一个窗口,然后使用函数DXUTSetWindow()为DXUT框架设置自己创建的
窗口,该函数声明如下:

Sets a previously created window for use by DXUT.

HRESULT DXUTSetWindow(
         HWND hWndFocus,
         HWND hWndDeviceFullScreen,
         HWND hWndDeviceWindowed,
         BOOL bHandleMessages
)
 
Parameters
hWndFocus 
[in] Handle of the Direct3D focus window. Must not be NULL. 
hWndDeviceFullScreen 
[in] Handle of the Direct3D device window when in full-screen mode. Must not be NULL. 
hWndDeviceWindowed 
[in] Handle of the Direct3D device window when in windowed mode. Must not be NULL. 
bHandleMessages 
[in] If TRUE, DXUT will handle and respond to messages for the window. If FALSE, DXUT will not handle messages for the window,
giving the application full responsibility for responding to messages. The default value is TRUE. 
Return Values
If the function succeeds, the return value is S_OK. If the function fails, the return value can be one of the error codes in
DXUTERR.

Remarks
This function relies on an existing window object created by the application. Alternately, the application can call 
DXUTCreateWindow to have DXUT create a window. If neither DXUTCreateWindow nor DXUTSetWindow has been called before calling 
a device creation method, DXUT will automatically call DXUTCreateWindow using the default parameter values.

The same Window handle may be used for more than one parameter.

这个函数使用了3个窗口句柄参数,但它们通常都设置为同一个窗口句柄。

如果框架创建了窗口,窗口消息将被自动处理,而要让DXUT框架使用自己创建的窗口,除了为DXUT框架设置窗口之外,还需要向DXUT框架通知
窗口接收到的消息(仅当DXUTSetWindow函数中bHandleMessages为false时需要),才能使DXUT框架正常运行。应用程序可通过函数
DXUTStaticWndProc()将窗口消息从窗口回调函数WindowProc 的内部传递给框架,函数DXUTStaticWndProc()的声明如下:
Processes messages sent to a window.

LRESULT_CALLBACK DXUTStaticWndProc(
         HWND hWnd,
         UINT uMsg,
         WPARAM wParam,
         LPARAM lParam
)
 

Parameters
hWnd
[in] Handle to the window. 
uMsg
[in] Specifies the message. 
wParam
[in] Specifies additional message information. The contents of this parameter depend on the value of the uMsg parameter. 
lParam
[in] Specifies additional message information. The contents of this parameter depend on the value of the uMsg parameter. 
Return Value
If the function has processed window messages successfully, returns zero; otherwise, returns a nonzero value.

Remarks
This method does not normally need to be called. It is useful only when the application use DXUTSetWindow with bHandleMessages
set to FALSE but still wants DXUT to assist with handling Windows messages. If this is the case, this function can be called 
from inside the application's window procedure, or it can be used directly as the window procedure.

*/
	DXUTCreateDevice( true, 640, 480 );
/*知识点7:创建一个设备

---------------------------------------------
来自<<DXUT框架剖析(4)>>
---------------------------------------------
通常可以用标准的Direct3D方法CreateDevice()创建一个Direct3D设备,这个方法需要一个有效的显示适配器、设备类型(硬件抽象层设备或参
考设备)、窗口句柄、运行标志(软件/硬件顶点运算模式和其他驱动标志)和提交参数。更重要的是,结构体 D3DPRESENT_PARAMETERS有许多
成员指定了后台缓冲区的设置、多重采样设置、交换效果、窗口模式、深度缓冲区设置、刷新频率、提交间隔和提交标志等。

为所有的参数选择合适的设置是比较繁琐的,DXUT框架使用函数DXUTCreateDevice()简化了Direct3D设备的创建,该函数的声明如下:
HRESULT DXUTCreateDevice(
         bool bWindowed,
         INT nSuggestedWidth,
         INT nSuggestedHeight
)
 

Parameters
bWindowed
[in] If TRUE, the application will start in windowed mode; if FALSE, the application will start in full-screen mode. 
The default value is TRUE. 
nSuggestedWidth
[in] The requested initial width of the application's back buffer. The actual width may be adjusted to fit device and 
operating system constraints. The default value is 0. 
nSuggestedHeight
[in] The requested initial height of the application's back buffer. The actual height may be adjusted to fit device and 
operating system constraints. The default value is 0. If both nSuggestedWidth and nSuggestedHeight are zero, the dimension
of the client area of the window is used. 
Return Value
If the function succeeds, the return value is S_OK. If the function fails, the return value can be one of the error codes
in DXUTERR.

Remarks
This function creates a new Direct3D 9 or Direct3D 10 device for the application. DXUT will pick the best device for the 
application based upon what is available on the system and which Direct3D API version(s) the application supports. The API 
version(s) that the application supports is determined by which device callbacks are set. This logic can be overridden by 
calling DXUTSetD3DVersionSupport. If both Direct3D 9 and Direct3D 10 are available on the system and both are supported by
the application, then DXUT will favor Direct3D 10.

Alternately, the application can use the DXUTCreateDeviceFromSettings or handle device creation and pass the desired device to
DXUT by using the DXUTSetD3D9Device or DXUTSetD3D10Device function. If neither DXUTCreateDevice, DXUTCreateDeviceFromSettings,
nor DXUTSetD3D9Device or DXUTSetD3D10Device have been called before calling DXUTMainLoop, DXUT will automatically call 
DXUTCreateDevice using the default parameter values.

The application can call this method after a device has already been created to change the current device.

If a device is successfully found, the LPDXUTCALLBACKMODIFYDEVICESETTINGS callback will be called to allow the application to
examine or change the device settings before the device is created. This allows an application to modify the device creation
settings as it sees fit.

通过这个简单的调用,DXUT框架创建了一个使用默认设置的Direct3D设备,它可以在大多数情况下使用,默认的设备创建设置如下表所示:

Direct3D创建标志										描述					DXUTCreateDevice的默认值  
函数CheckDeviceFormat()的参数AdapterFormat				适配器表面格式			当前桌面显示模式,如果桌面显示模式不足32位,
																				则使用D3DFMT_X8R8G8B8 

IDirect3D9::CreateDevice()的参数Adapter					显示适配器编号			D3DADAPTER_DEFAULT 

D3DPRESENT_PARAMETERS.BackBufferCount					后台缓冲区数目			2,表示有两个后台缓冲区,可实现3倍缓冲。 

D3DPRESENT_PARAMETERS.BackBufferFormat					后台缓冲区格式			桌面显示模式,如果桌面显示模式不足32位,
																				则使用D3DFMT_X8R8G8B8 

D3DPRESENT_PARAMETERS.AutoDepthStencilFormat			设备将自动创建的深度	如果后台缓冲区格式小于等于16位,
														模板表面的深度格式		则使用D3DFMT_D16,否则使用D3DFMT_D32。

IDirect3D9::CreateDevice()函数的参数DeviceType			设备类型				若D3DDEVTYPE_HAL可行,则使用之,否则使用
																				D3DDEVTYPE_REF,若二者均不可行,则创建失败。

D3DPRESENT_PARAMETERS.MultiSampleQuality				多重采样数量			MultiSampleQuality = 0表示禁用多重采样 

D3DPRESENT_PARAMETERS.Flags								提交参数标志			D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL 

D3DPRESENT_PARAMETERS.PresentationInterval				提交间隔				窗口模式下为D3DPRESENT_INTERVAL_IMMEDIATE,
																				全屏模式下为D3DPRESENT_INTERVAL_DEFAULT。 

D3DPRESENT_PARAMETERS.FullScreen_RefreshRateInHz		显示适配器刷新频率		0,表示当前桌面设置的刷新频率。 

D3DPRESENT_PARAMETERS.BackBufferWidth和BackBufferHeight 显示器分辨率			在窗口模式下为640 x 480,全屏模式下为桌面分辨率。 

D3DPRESENT_PARAMETERS.SwapEffect						交换效果				D3DSWAPEFFECT_DISCARD 
IDirect3D9::CreateDevice()的参数BehaviorFlags			顶点运算标志			如果硬件支持,就使用
																				D3DCREATE_HARDWARE_VERTEXPROCESSING,
																				否则使用D3DCREATE_SOFTWARE_VERTEXPROCESSING。 

D3DPRESENT_PARAMETERS.Windowed							窗口模式或全屏模式		TRUE,表示窗口模式 
IDirect3D9::CreateDevice()的参数hFocusWindow			创建窗口的句柄			DXUTSetWindow函数的参数hWndFocus 
D3DPRESENT_PARAMETERS.hDeviceWindow						设备窗口的句柄			DXUTSetWindow的参数hWndDeviceFullScreen或
																				hWndDeviceWindowed 

D3DPRESENT_PARAMETERS.EnableAutoDepthStencil			深度模板缓冲区创建标志	TRUE,表示自动创建深度模板缓冲区 

让我们对比下在DX中如何创建设备
HRESULT IDirect3D9::CreateDevice(
UINT Adapter,
D3DDEVTYPE DeviceType,
HWND hFocusWindow,
DWORD BehaviorFlags,
D3DPRESENT_PARAMETERS *pPresentationParameters,
IDirect3DDevice9** ppReturnedDeviceInterface
);
我们可以发现它们是一一对应的
*/ 
    DXUTSetHotkeyHandling( true, true, true );  // handle the default hotkeys
    DXUTSetCursorSettings( true, true ); // Show the cursor and clip it when in full screen

   

    // Start the render loop
    DXUTMainLoop();
/*知识点10:进入消息循环 

---------------------------------------------
来自<<DXUT框架剖析(6)>>
---------------------------------------------
在窗口和设备创建好之后,应用程序需要使用消息循环处理窗口消息、更新和渲染场景、处理设备事件。应用程序可以实现自己的消息循环,
也可以使用DXUT消息循环,注册相应的回调函数,可以让DXUT处理设备、帧消息事件。

为使用DXUT框架的消息循环,可以调用DXUTMainLoop()函数:

Starts the main execution loop of DXUT.

HRESULT DXUTMainLoop(
         HACCEL hAccel
)
 

Parameters
hAccel
[in] Handle to an accelerator table to use in translating keyboard messages from the Windows message queue, or NULL if not 
using an accelerator table. The default value is NULL. 
Return Value
If the function succeeds, the return value is S_OK. If the function fails, the return value can be one of the error codes 
in DXUTERR.

Remarks
This function starts the message loop that will run for the lifetime of the application. During execution, DXUTMainLoop 
calls the registered callback functions to ask the application to update and render the frame, as well as handle any device 
or input events.

Custom Main Loop
For some advanced applications a custom main loop may be a better design. It is possible to use DXUT with a custom main loop.
An example of how to do this is shown below.

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();//知识点12    
	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();
}
This example calls DXUTRender3DEnvironment to have DXUT update and render the scene and handle device events. While it is
possible for the application to completely replicate this functionality, it is not recommended.
-------------------------------------------
DXUTRender3DEnvironment
Renders the 3D environment.
VOID DXUTRender3DEnvironment()
 

Return Value
No return value.

Remarks
This method does not normally need to be called. It is useful only when the application does not use DXUTMainLoop but still
wants DXUT to assist with rendering.

This method checks whether the device is lost. If so, the method attempts to reset the device and then calls the 
LPDXUTCALLBACKFRAMEMOVE and LPDXUTCALLBACKD3D10FRAMERENDER callback functions.

If the application window is minimized or the application is paused, CPU time is yielded to other processes.

*/

    // TODO: Perform any application-level cleanup here
/*知识点12:允许改变DXUT行为和获取内部变量的函数

---------------------------------------------
来自<<DXUT框架剖析(9,10,11,12)>>
---------------------------------------------
管理窗口的DXUT函数

DXUTGetHINSTANCE			获取应用程序实例的句柄 
DXUTGetHWND					获取当前设备窗口的句柄 
DXUTGetHWNDFocus			获取当前获得焦点的窗口的句柄 
DXUTGetHWNDDeviceFullScreen 获取全屏模式设备窗口的句柄 
DXUTGetHWNDDeviceWindowed	获取窗口模式设备窗口的句柄 
DXUTGetWindowClientRect		获取应用程序设备窗口的客户区矩形 
DXUTGetWindowTitle			获取指向应用程序窗口标题的指针 
DXUTIsWindowed				检查应用程序是否处在窗口模式下 

管理设备的DXUT函数

DXUTSetCursorSettings		为全屏模式下光标的用法设置选项 
DXUTSetMultimonSettings		为框架如何在多显示器配置中工作设置选项 
DXUTToggleFullscreen		使应用程序在窗口模式和全屏模式间切换 
DXUTToggleREF				使应用程序在硬件抽象层和参考设备间切换 

管理DXUT框架的函数
DXUTResetFrameworkState		将框架状态重置为初始默认状态,之前设置的框架状态改变将失效。 
DXUTShutdown				触发程序终止和清空框架 
DXUTGetExitCode				获取框架的退出代码 

检索Direct3D变量的函数
DXUTGetD3DObject					获取一个指向IDirect3D9对象的指针 
DXUTGetD3D9Device					获取一个指向代表当前设备的IDirect3DDevice9接口指针 
DXUTGetDeviceSettings				获取用来创建当前设备的结构体DXUTDeviceSettings 
DXUTGetPresentParameters			获取当前设备的提交(presentation)参数 
DXUTGetD3D9BackBufferSurfaceDesc	获取一个指向当前设备后台缓冲区表面的D3DSURFACE_DESC结构体的指针 
DXUTGetD3D9DeviceCaps				获取一个指向当前设备的D3DCAPS9结构体的指针 

DXUT统计函数 

DXUTGetFPS				获取当前每秒提交的帧数 
DXUTGetFrameStats		获取一个指向字符串的指针,该字符串包括每秒帧数、分辨率、后台缓冲区格式、深度缓冲区格式。 
DXUTGetDeviceStats		获取一个指向字符串的指针,该字符串包括当前设备类型、顶点运算行为和设备名。 

DXUT时间函数 

DXUTGetTime					获取当前时间(秒) 
DXUTGetElapsedTime			获取从上一帧到当前帧所经过的时间 
DXUTSetConstantFrameTime	启用或禁用固定帧时间 

DXUT计时器函数

DXUTSetTimer				添加一个新的计时器 
DXUTKillTimer				卸载一个已有的计时器 

DXUT暂停函数

DXUTPause					将框架的内部计数器和(或)渲染过程设为暂停状态 
DXUTRenderingPaused			检查当前设备的渲染状态是否处在暂停状态 
DXUTIsTimePaused			检查当前设备的计时器是否处在暂停状态 

DXUT用户输入函数

DXUTIsKeyDown 检查当该函数调用时,键盘上指定的某个键是否按下。 
DXUTIsMouseButtonDown 检查当该函数调用时,指定的鼠标键是否按下。 


*/    
    return DXUTGetExitCode();
/*知识点13:DXUTGetExitCode

---------------------------------------------
来自<<DXUT框架剖析(10)>>
---------------------------------------------
 
Gets the DXUT exit code.


INT DXUTGetExitCode()
 

Return Value
Returns a DXUT exit code, which will be one of the possible values shown in the following table. 

Value		Description  
0		Successful execution.  
1		An undetermined error occurred.  
2		Direct3D could not be initialized.  
3		No Direct3D device could be found with the specified device settings.  
4		The required media could not be found.  
5		The Direct3D device has a non-zero reference count, meaning that some objects were not released.  
6		An error occurred when attempting to create a Direct3D device.  
7		An error occurred when attempting to reset a Direct3D device.  
8		An error occurred in the device creation callback function.  
9		An error occurred in the device reset callback function.  
10		The last device used upon exit was a reference (REF) device type.  
11		The device was removed.  

Remarks
The return value of this function is typically used in the application as the return code of the application's WinMain
function. Command-line tests can then be performed on applications using this return code.

The following is an example of command-line usage that uses DXUT exit code:

start /wait BasicHLSL.exe
echo %errorlevel%

*/


}



 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
DXUT框架剖析 DXUT框架剖析(14) 摘要: 控件是用户接口的重要组成部分,为了便于用户操作,为程序界面添加各种控件是非常好的方法。DXUT框架为在Direct3D程序中添加各种控件提供了支持。为了便于加载控件和处理各控件的消息,通常先在窗口中加载对话框,然后在对话框中添加响应的控件,由对话框来管理控件。为了统一管理各个对话框,还需要定义对话框资源管理器类CDXUTDialogResourceManager的一个对象,在程序开始时,调用各个对话框的Init函数和对话框资源管理对象进行初始化 DXUT框架剖析(13) 摘要: DXUT框架对文本绘制进行了封装,提供了类CDXUTHelper来简化文本显示,使用该接口大体分为3个步骤:初始化ID3DXSprite和ID3DXFont对象,显示文本,释放ID3DXSprite和ID3DXFont对象。 DXUT框架剖析(12) 摘要: DXUT暂停函数: DXUTPause:将框架的内部计数器和(或)渲染过程设为暂停状态。 DXUTRenderingPaused:检查当前设备的渲染状态是否处在暂停状态。 DXUTIsTimePaused:检查当前设备的计时器是否处在暂停状态。 DXUT框架剖析(11) 摘要: DXUT统计函数: DXUTGetFPS: 获取当前每秒提交的帧数。 DXUTGetFrameStats:获取一个指向字符串的指针,该字符串包括每秒帧数、分辨率、后台缓冲区格式、深度缓冲区格式。 DXUTGetDeviceStats:获取一个指向字符串的指针,该字符串包括当前设备类型、顶点运算行为和设备名。 DXUT框架剖析(10) 摘要: 管理DXUT框架的函数: DXUTResetFrameworkState: 将框架状态重置为初始默认状态,之前设置的框架状态改变将失效。 DXUTShutdown: 触发程序终止和清空框架DXUTGetExitCode: 获取框架的退出代码。 DXUT框架剖析(9) 摘要: 下面列出允许改变DXUT行为和获取内部变量的函数,这些函数在使用DXUT框架的Direct3D程序中是非常实用的。 DXUT框架剖析(8) 摘要: Direct3D API的设计使程序能比较容易地处理各种错误,尽管大多数Direct3D API函数返回HTRSULT值,但只有一部分函数返回设备错误,如D3DERR_DEVICELOST或 D3DERR_DRIVERINTERNALERROR。但是通常的Direct3D应用程序使用多种API函数,当传递的参数不合要求时,将返回 D3DERR_INVALIDCALL。 当开发Direct3D应用程序时,应该检查所有的API调用是否成功,如果出现一个没有预测到的失败调用,应用程序应立即给出通知或记录该错误。使用这种方法,开发人员能很快发现哪些API函数的调用是不正确的。一个正确调用Direct3D API函数的应用程序应能安全地忽略大多数Direct3D API函数的失败调用,除了一些关键性的API函数,如Present()或TestCooperativeLevel(),这些函数返回的错误应用程序不能忽略。 DXUT框架剖析(7) 摘要: 框架也提供了帧事件,它在渲染过程中的每一帧被调用,应用程序应该注册并实现这些回调函数。 DXUT框架剖析(6) 摘要: 在窗口和设备创建好之后,应用程序需要使用消息循环处理窗口消息、更新和渲染场景、处理设备事件。应用程序可以实现自己的消息循环,也可以使用DXUT消息循环,注册相应的回调函数,可以让DXUT处理设备、帧消息事件。 为使用DXUT框架的消息循环,可以调用DXUTMainLoop()函数. DXUT框架剖析(5) 摘要: 应用程序可以通过DXUTSetCallbackDeviceChanging()设置回调函数来修改Direct3D设备的创建设置。 回调函数ModifyDeviceSettings()返回一个布尔值,如果应用程序返回 TRUE,DXUT框架继续像在正常情况下那样进行设备创建。如果返回FALSE,框架不能改变设备,如果已有一个设备,则继续使用当前设备。如果框架提出的请求是改变到一个应用程序不能使用的设备,应用程序可以拒绝该请求。例如,在一个多显示器配置中,默认情况下在显示器之间拖动窗口将使框架改变设备。但如果应用程序不能使用其他设备,它就必须拒绝这种改变并继续使用当前设备。 DXUT框架剖析(4) 摘要: 通常可以用标准的Direct3D方法Creat
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值