天行健 君子当自强而不息

DXUT源码分析 ---- 类CDXUTMeshFrame

类CDXUTMeshFrame封装了CDXUTMesh,与CDXUTMesh不同的是,类CDXUTMeshFrame可以包含框架层次结构,适用于更复杂的网格模型,框架层次正是骨骼动画所必须的。

首先来看看它的定义:

//-----------------------------------------------------------------------------
// Name: class CDXUTMeshFrame
// Desc: Class for loading and rendering file-based meshes
//-----------------------------------------------------------------------------
class CDXUTMeshFrame
{
public:
    WCHAR            m_strName[
512];     // 框架名称
    D3DXMATRIX        m_mat;               // 框架变换矩阵(相对于网格模型的原点)
    CDXUTMesh*        m_pMesh;           // 指向CDXUTMesh对象

    CDXUTMeshFrame
* m_pNext;         // 指向下一个框架对象
    CDXUTMeshFrame* m_pChild;         // 指向子框架对象

public:
    
// Matrix access
    void        SetMatrix( D3DXMATRIX* pmat ) { m_mat = *pmat; }
    D3DXMATRIX
* GetMatrix()                   { return &m_mat; }

    CDXUTMesh
*         FindMesh( LPCWSTR strMeshName );
    CDXUTMeshFrame
*  FindFrame( LPCWSTR strFrameName );

    
bool EnumMeshes( bool (*EnumMeshCB)(CDXUTMesh*void*), void* pContext );

    HRESULT Destroy();
    HRESULT RestoreDeviceObjects(LPDIRECT3DDEVICE9 pd3dDevice);
    HRESULT InvalidateDeviceObjects();

    HRESULT Render( LPDIRECT3DDEVICE9 pd3dDevice, 
                    
bool bDrawOpaqueSubsets = true,
                    
bool bDrawAlphaSubsets = true,
                    D3DXMATRIX
* pmatWorldMatrix = NULL);

    CDXUTMeshFrame( LPCWSTR strName 
= L"CDXUTMeshFile_Frame" );
    
virtual ~CDXUTMeshFrame();
};

 

构造函数和析构函数只是负责初始化数据和释放分配的资源:

CDXUTMeshFrame::CDXUTMeshFrame( LPCWSTR strName )
{
StringCchCopy(m_strName, 512, strName);
    D3DXMatrixIdentity(&m_mat);
    m_pMesh  = NULL;
m_pChild = NULL;
m_pNext = NULL;
}
CDXUTMeshFrame::~CDXUTMeshFrame()
{
SAFE_DELETE( m_pChild );
SAFE_DELETE( m_pNext );
}

 

FindMesh()和FindFrame()是两个递归查找函数,根据输入的网格名称和框架名称查找对应的网格和框架:

CDXUTMesh* CDXUTMeshFrame::FindMesh( LPCWSTR strMeshName )
{
CDXUTMesh* pMesh;
    if( m_pMesh )
if( !lstrcmpi(m_pMesh->m_strName, strMeshName) )
return m_pMesh;
    if( m_pChild )
if( NULL != ( pMesh = m_pChild->FindMesh(strMeshName) ) )
return pMesh;
    if( m_pNext )
if( NULL != ( pMesh = m_pNext->FindMesh(strMeshName) ) )
return pMesh;
    return NULL;
}
CDXUTMeshFrame* CDXUTMeshFrame::FindFrame( LPCWSTR strFrameName )
{
CDXUTMeshFrame* pFrame;
    if( !lstrcmpi(m_strName, strFrameName) )
return this;
    if( m_pChild )
if( NULL != ( pFrame = m_pChild->FindFrame(strFrameName) ) )
return pFrame;
    if( m_pNext )
if( NULL != ( pFrame = m_pNext->FindFrame(strFrameName) ) )
return pFrame;
    return NULL;
}

 

lstrcmpi()在比较两个字符串时忽略大小写:

The lstrcmpi function compares two character strings. The comparison is not case sensitive.

To perform a comparison that is case sensitive, use the lstrcmp function.

Syntax

int lstrcmpi(      

    LPCTSTR lpString1,
    LPCTSTR lpString2
);

Parameters

lpString1
[in] Pointer to the first null-terminated string to be compared.
lpString2
[in] Pointer to the second null-terminated string to be compared.

Return Value

If the string pointed to by lpString1 is less than the string pointed to by lpString2, the return value is negative. If the string pointed to by lpString1 is greater than the string pointed to by lpString2, the return value is positive. If the strings are equal, the return value is zero.

Remarks

The lstrcmpi function compares two strings by checking the first characters against each other, the second characters against each other, and so on until it finds an inequality or reaches the ends of the strings.

Note that the lpString1 and lpString2 parameters must be null terminated, otherwise the string comparison can be incorrect.

The function returns the difference of the values of the first unequal characters it encounters. For example, lstrcmpi determines that "abcz" is greater than "abcdefg" and returns the difference of z and d.

The language (user locale) selected by the user at setup time, or through Control Panel, determines which string is greater (or whether the strings are the same). If no language (user locale) is selected, the system performs the comparison by using default values.

For some locales, the lstrcmpi function may be insufficient. If this occurs, use CompareString to ensure proper comparison. For example, in Japan call with the NORM_IGNORECASE, NORM_IGNOREKANATYPE, and NORM_IGNOREWIDTH values to achieve the most appropriate non-exact string comparison. The NORM_IGNOREKANATYPE and NORM_IGNOREWIDTH values are ignored in non-Asian locales, so you can set these values for all locales and be guaranteed to have a culturally correct "insensitive" sorting regardless of the locale. Note that specifying these values slows performance, so use them only when necessary.

With a double-byte character set (DBCS) version of the system, this function can compare two DBCS strings.

The lstrcmpi function uses a word sort, rather than a string sort. A word sort treats hyphens and apostrophes differently than it treats other symbols that are not alphanumeric, in order to ensure that words such as "coop" and "co-op" stay together within a sorted list. For a detailed discussion of word sorts and string sorts, see the Remarks section for the CompareString function.

 

EnumMeshes()是一个递归枚举函数,对所有框架的所有网格递归调用传递进来的函数:

bool CDXUTMeshFrame::EnumMeshes( bool (*EnumMeshCB)(CDXUTMesh*, void*), void* pContext )
{
if( m_pMesh )
EnumMeshCB( m_pMesh, pContext );
    if( m_pChild )
m_pChild->EnumMeshes( EnumMeshCB, pContext );
    if( m_pNext )
m_pNext->EnumMeshes( EnumMeshCB, pContext );
    return TRUE;
}
 

Destroy()、RestoreDeviceObjects()、InvalidateDeviceObjects()分别当摧毁网格框架、设备恢复、设备丢失时调用,需要注意的是该类的析构函数并没有释放分配的资源,只是删除了链表指针,必须显式调用Destroy()来释放资源:

HRESULT CDXUTMeshFrame::Destroy()
{
if( m_pMesh ) m_pMesh->Destroy();
if( m_pChild ) m_pChild->Destroy();
if( m_pNext ) m_pNext->Destroy();
    SAFE_DELETE( m_pMesh );
SAFE_DELETE( m_pNext );
SAFE_DELETE( m_pChild );
    return S_OK;
}
HRESULT CDXUTMeshFrame::RestoreDeviceObjects( LPDIRECT3DDEVICE9 pd3dDevice )
{
if( m_pMesh ) m_pMesh->RestoreDeviceObjects( pd3dDevice );
if( m_pChild ) m_pChild->RestoreDeviceObjects( pd3dDevice );
if( m_pNext ) m_pNext->RestoreDeviceObjects( pd3dDevice );
    return S_OK;
}
HRESULT CDXUTMeshFrame::InvalidateDeviceObjects()
{
if( m_pMesh ) m_pMesh->InvalidateDeviceObjects();
if( m_pChild ) m_pChild->InvalidateDeviceObjects();
if( m_pNext ) m_pNext->InvalidateDeviceObjects();
    return S_OK;
}

 

Render()负责网格框架的绘制,它只是调用CDXUTMesh::Render()来负责网格的绘制,由于框架的层次包含关系,所以该函数也是一个递归函数。需要注意的是该函数包含的最后一个参数,它允许用户指定世界坐标变换矩阵,如果该参数为NULL,则从设备获取已设置好的世界坐标矩阵,注意如果是虚拟设备,必须设置该矩阵,不能为NULL。

HRESULT CDXUTMeshFrame::Render( LPDIRECT3DDEVICE9 pd3dDevice, 
bool bDrawOpaqueSubsets, bool bDrawAlphaSubsets,
D3DXMATRIX* pmatWorldMatrix )
{
// For pure devices, specify the world transform.
// If the world transform is not specified on pure devices, this function will fail.
    D3DXMATRIX matSavedWorld, matWorld;
    if (NULL == pmatWorldMatrix)
pd3dDevice->GetTransform(D3DTS_WORLD, &matSavedWorld);
else
matSavedWorld = *pmatWorldMatrix;
    D3DXMatrixMultiply(&matWorld, &m_mat, &matSavedWorld);
pd3dDevice->SetTransform(D3DTS_WORLD, &matWorld);
    if( m_pMesh )
m_pMesh->Render(pd3dDevice, bDrawOpaqueSubsets, bDrawAlphaSubsets);
    if( m_pChild )
m_pChild->Render(pd3dDevice, bDrawOpaqueSubsets, bDrawAlphaSubsets, &matWorld);
    pd3dDevice->SetTransform(D3DTS_WORLD, &matSavedWorld);
    if( m_pNext )
m_pNext->Render( pd3dDevice, bDrawOpaqueSubsets, bDrawAlphaSubsets, &matSavedWorld );
    return S_OK;
}

代码中需要注意的一点是,调用Render()绘制兄弟框架时传递的世界坐标矩阵是matSavedWorld,而绘制子框架时传递的世界坐标矩阵是matWorld。


posted on 2008-06-01 07:50 lovedday 阅读(1005) 评论(0)  编辑 收藏 引用 所属分类: ■ DXUT Research


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


公告

导航

统计

常用链接

随笔分类(178)

3D游戏编程相关链接

搜索

最新评论