新书推介:《语义网技术体系》
作者:瞿裕忠,胡伟,程龚
   XML论坛     W3CHINA.ORG讨论区     计算机科学论坛     SOAChina论坛     Blog     开放翻译计划     新浪微博  
 
  • 首页
  • 登录
  • 注册
  • 软件下载
  • 资料下载
  • 核心成员
  • 帮助
  •   Add to Google

    >> 本版讨论高级C/C++编程、代码重构(Refactoring)、极限编程(XP)、泛型编程等话题
    [返回] 计算机科学论坛计算机技术与应用『 C/C++编程思想 』 → DXUT源码分析 ---- 类CDXUTMeshFile 查看新帖用户列表

      发表一个新主题  发表一个新投票  回复主题  (订阅本版) 您是本帖的第 9881 个阅读者浏览上一篇主题  刷新本主题   树形显示贴子 浏览下一篇主题
     * 贴子主题: DXUT源码分析 ---- 类CDXUTMeshFile 举报  打印  转邮箱  推荐  站内收藏  IE收藏夹 
       本主题类别:     
     卷积内核 帅哥哟,离线,有人找我吗?
      
      
      威望:8
      头衔:总统
      等级:博士二年级(版主)
      文章:3942
      积分:27590
      门派:XML.ORG.CN
      院校:(无权查看)
      注册:2004/7/21
    给卷积内核发送一个短消息 把卷积内核加入好友 查看卷积内核的个人资料 搜索卷积内核在『 C/C++编程思想 』的所有贴子 访问卷积内核的主页 引用回复这个贴子 回复这个贴子 查看卷积内核的博客楼主
    发贴心情 DXUT源码分析 ---- 类CDXUTMeshFile
    类CDXUTMeshFile位于DXUTMesh.h和DXUTMesh.cpp中,继承自类CDXUTMeshFrame,其实类CDXUTMeshFrame本身只完成一些基础操作,不是最终使用的一个类,CDXUTMeshFile在CDXUTMeshFrame的基础上将各种操作进一步封装。

    在.x网格模型中使用框架的主要目的是实现模型自身包含的动画,而CDXUTMeshFile和CDXUTMeshFrame虽然考虑了网格模型的层次框架,可是并没有实现对网格模型动画的播放,所以通常不直接使用这两个类,因为对于不包含动画信息的静态网格模型CDXUTMesh类就已经足够了。当然也完全可以像使用CDXUTMesh类一样使用CDXUTMeshFile类来操作不包含动画信息的网格模型。

    来看看CDXUTMeshFile的定义:

    //-----------------------------------------------------------------------------
    // Name: class CDXUTMeshFile
    // Desc: Class for loading and rendering file-based meshes
    //-----------------------------------------------------------------------------
    class CDXUTMeshFile : public CDXUTMeshFrame
    {
        HRESULT LoadMesh( LPDIRECT3DDEVICE9 pd3dDevice, LPD3DXFILEDATA pFileData, CDXUTMeshFrame* pParentFrame );
        HRESULT LoadFrame( LPDIRECT3DDEVICE9 pd3dDevice, LPD3DXFILEDATA pFileData, CDXUTMeshFrame* pParentFrame );

    public:
        HRESULT Create( LPDIRECT3DDEVICE9 pd3dDevice, LPCWSTR strFilename );
        HRESULT CreateFromResource( LPDIRECT3DDEVICE9 pd3dDevice, LPCWSTR strResource, LPCWSTR strType );

        // For pure devices, specify the world transform.
        // If the world transform is not specified on pure devices, this function will fail.
        HRESULT Render( LPDIRECT3DDEVICE9 pd3dDevice, D3DXMATRIX* pmatWorldMatrix = NULL );

        CDXUTMeshFile() : CDXUTMeshFrame( L"CDXUTMeshFile_Root" ) {}
    };


    LoadMesh()负责从ID3DXFileData中加载一个网格,该函数是内部调用的,其实质是调用CDXUTMesh::Create()函数来加载。


    HRESULT CDXUTMeshFile::LoadMesh(LPDIRECT3DDEVICE9 pd3dDevice, LPD3DXFILEDATA pFileData, CDXUTMeshFrame* pParentFrame)
    {
        // Currently only allowing one mesh per frame
        if( pParentFrame->m_pMesh )
            return E_FAIL;

        // Get the mesh name

        CHAR  strAnsiName[512] = {0};
        WCHAR strName[512];
        SIZE_T dwNameLength = 512;
        HRESULT hr;

        if( FAILED( hr = pFileData->GetName(strAnsiName, &dwNameLength) ) )
            return hr;

        MultiByteToWideChar(CP_ACP, 0, strAnsiName, -1, strName, 512);
        strName[511] = 0;

        // Create the mesh

        pParentFrame->m_pMesh = new CDXUTMesh(strName);

        if( pParentFrame->m_pMesh == NULL )
            return E_OUTOFMEMORY;

        pParentFrame->m_pMesh->Create( pd3dDevice, pFileData );

        return S_OK;
    }  

    LoadFrame()用于从ID3DXFileData中加载一个框架:

    HRESULT CDXUTMeshFile::LoadFrame(LPDIRECT3DDEVICE9 pd3dDevice, LPD3DXFILEDATA pFileData, CDXUTMeshFrame* pParentFrame)
    {
        LPD3DXFILEDATA   pChildData = NULL;
        GUID             Guid;
        SIZE_T             cbSize;
        CDXUTMeshFrame*  pCurrentFrame;
        HRESULT             hr;

        // Get the type of the object
        if( FAILED( hr = pFileData->GetType( &Guid ) ) )
            return hr;

        if(Guid == TID_D3DRMMesh)
        {
            hr = LoadMesh(pd3dDevice, pFileData, pParentFrame);

            if( FAILED(hr) )
                return hr;
        }
        if(Guid == TID_D3DRMFrameTransformMatrix)
        {
            D3DXMATRIX* pmatMatrix;
            hr = pFileData->Lock(&cbSize, (LPCVOID*) &pmatMatrix);

            if( FAILED(hr) )
                return hr;

            // Update the parent's matrix with the new one
            pParentFrame->SetMatrix(pmatMatrix);
        }
        if(Guid == TID_D3DRMFrame)
        {
            // Get the frame name
            CHAR   strAnsiName[512] = "";
            WCHAR  strName[512];
            SIZE_T dwNameLength = 512;
            SIZE_T cChildren;

            if( FAILED( hr = pFileData->GetName(strAnsiName, &dwNameLength) ) )
                return hr;

            MultiByteToWideChar(CP_ACP, 0, strAnsiName, -1, strName, 512);
            strName[511] = 0;

            // Create the frame
            pCurrentFrame = new CDXUTMeshFrame(strName);
            if(pCurrentFrame == NULL)
                return E_OUTOFMEMORY;

            pCurrentFrame->m_pNext = pParentFrame->m_pChild;
            pParentFrame->m_pChild = pCurrentFrame;

            // Enumerate child objects

            pFileData->GetChildren(&cChildren);

            for (UINT iChild = 0; iChild < cChildren; iChild++)
            {
                // Query the child for its FileData
                hr = pFileData->GetChild(iChild, &pChildData);

                if( SUCCEEDED(hr) )
                {
                    hr = LoadFrame(pd3dDevice, pChildData, pCurrentFrame);
                    SAFE_RELEASE( pChildData );
                }

                if( FAILED(hr) )
                    return hr;
            }
        }

        return S_OK;
    }
    首先,该函数调用GetType()获取对象的GUID:
        // Get the type of the object    if( FAILED( hr = pFileData->GetType( &Guid ) ) )        return hr;
    接下来根据GUID分别进行相应的操作,若是网格则调用LoadMesh()加载网格,若是框架变换矩阵则设置变换矩阵,若是框架,相应的操作有些复杂,首先获取框架的名称并将其转化为widechar类型:

           if( FAILED( hr = pFileData->GetName(strAnsiName, &dwNameLength) ) )            return hr;
            MultiByteToWideChar(CP_ACP, 0, strAnsiName, -1, strName, 512);        strName[511] = 0;
    接着新建一个CDXUTMeshFrame对象并将其添加进链表:

            // Create the frame        pCurrentFrame = new CDXUTMeshFrame(strName);        if(pCurrentFrame == NULL)            return E_OUTOFMEMORY;
            pCurrentFrame->m_pNext = pParentFrame->m_pChild;        pParentFrame->m_pChild = pCurrentFrame;
    最后遍历子框架并递归调用LoadFrame()加载框架:

            // Enumerate child objects
            pFileData->GetChildren(&cChildren);
            for (UINT iChild = 0; iChild < cChildren; iChild++)        {            // Query the child for its FileData            hr = pFileData->GetChild(iChild, &pChildData);
                if( SUCCEEDED(hr) )            {                hr = LoadFrame(pd3dDevice, pChildData, pCurrentFrame);                SAFE_RELEASE( pChildData );            }
                if( FAILED(hr) )                return hr;        }

    第一个Create()函数负责从模型文件加载网格模型:

    HRESULT CDXUTMeshFile::Create(LPDIRECT3DDEVICE9 pd3dDevice, LPCWSTR strFilename)
    {
        LPD3DXFILE           pDXFile   = NULL;
        LPD3DXFILEENUMOBJECT pEnumObj  = NULL;
        LPD3DXFILEDATA       pFileData = NULL;
        HRESULT hr;
        SIZE_T cChildren;

        // Create a x file object
        if( FAILED( hr = D3DXFileCreate(&pDXFile) ) )
            return E_FAIL;

        // Register templates for d3drm and patch extensions.
        if( FAILED( hr = pDXFile->RegisterTemplates((void*) D3DRM_XTEMPLATES, D3DRM_XTEMPLATE_BYTES) ) )
        {
            SAFE_RELEASE( pDXFile );
            return E_FAIL;
        }

        // Find the path to the file, and convert it to ANSI (for the D3DXOF API)

        WCHAR strPath[MAX_PATH];
        CHAR  strPathANSI[MAX_PATH];
        DXUTFindDXSDKMediaFileCch(strPath, sizeof(strPath) / sizeof(WCHAR), strFilename);
            
        WideCharToMultiByte(CP_ACP, 0, strPath, -1, strPathANSI, MAX_PATH, NULL, NULL);
        strPathANSI[MAX_PATH - 1] = 0;
        
        // Create enum object
        hr = pDXFile->CreateEnumObject((void*) strPathANSI, D3DXF_FILELOAD_FROMFILE, &pEnumObj);

        if( FAILED(hr) )
        {
            SAFE_RELEASE( pDXFile );
            return hr;
        }

        // Enumerate top level objects (which are always frames)
        pEnumObj->GetChildren(&cChildren);

        for (UINT iChild = 0; iChild < cChildren; iChild++)
        {
            hr = pEnumObj->GetChild(iChild, &pFileData);
            if (FAILED(hr))
                return hr;

            hr = LoadFrame(pd3dDevice, pFileData, this);
            SAFE_RELEASE(pFileData);

            if( FAILED(hr) )
            {
                SAFE_RELEASE(pEnumObj);
                SAFE_RELEASE(pDXFile);
                return E_FAIL;
            }
        }

        SAFE_RELEASE(pFileData);
        SAFE_RELEASE(pEnumObj);
        SAFE_RELEASE(pDXFile);

        return S_OK;
    }
    首先函数创建了一个ID3DXFileData对象并注册了XFILE标准模板:
        // Create a x file object    if( FAILED( hr = D3DXFileCreate(&pDXFile) ) )        return E_FAIL;
        // Register templates for d3drm and patch extensions.    if( FAILED( hr = pDXFile->RegisterTemplates((void*) D3DRM_XTEMPLATES, D3DRM_XTEMPLATE_BYTES) ) )    {        SAFE_RELEASE( pDXFile );        return E_FAIL;    }
    接下来查找网格模型文件将路径存储在strPath中,并将该路径转化为ANSI类型存储在strPathANSI中:

        // Find the path to the file, and convert it to ANSI (for the D3DXOF API)
        WCHAR strPath[MAX_PATH];    CHAR  strPathANSI[MAX_PATH];    DXUTFindDXSDKMediaFileCch(strPath, sizeof(strPath) / sizeof(WCHAR), strFilename);        
        WideCharToMultiByte(CP_ACP, 0, strPath, -1, strPathANSI, MAX_PATH, NULL, NULL);    strPathANSI[MAX_PATH - 1] = 0;
    再接下来创建一个ID3DXFileEnumObject枚举对象负责从.x文件中读取数据:

        // Create enum object    hr = pDXFile->CreateEnumObject((void*) strPathANSI, D3DXF_FILELOAD_FROMFILE, &pEnumObj);
        if( FAILED(hr) )    {        SAFE_RELEASE( pDXFile );        return hr;    }
    函数CreateEnumObject()声明如下:

    Creates an enumerator object that will read a .x file.

    HRESULT CreateEnumObject(  LPCVOID pvSource,  D3DXF_FILELOADOPTIONS loadflags,  ID3DXFileEnumObject ** ppEnumObj);
    Parameters
    pvSource
    [out] The data source. Either:
    A file name
    A D3DXF_FILELOADMEMORY structure
    A D3DXF_FILELOADRESOURCE structure
    Depending on the value of loadflags.
    loadflags
    [in] Value that specifies the source of the data. This value can be one of the D3DXF_FILELOADOPTIONS flags.
    ppEnumObj
    [out] Address of a pointer to an ID3DXFileEnumObject interface, representing the created enumerator object.
    Return Values
    If the method succeeds, the return value is S_OK. If the method fails, the return value can be one of the following: D3DXFERR_BADVALUE, D3DXFERR_PARSEERROR.

    Remarks
    After using this method, use one of the ID3DXFileEnumObject methods to retrieve a data object.

    再接下来通过ID3DXFileEnumObjec枚举对象读取数据并调用LoadFrame()加载框架:

        // Enumerate top level objects (which are always frames)    pEnumObj->GetChildren(&cChildren);
        for (UINT iChild = 0; iChild < cChildren; iChild++)    {        hr = pEnumObj->GetChild(iChild, &pFileData);        if (FAILED(hr))            return hr;
            hr = LoadFrame(pd3dDevice, pFileData, this);        SAFE_RELEASE(pFileData);
            if( FAILED(hr) )        {            SAFE_RELEASE(pEnumObj);            SAFE_RELEASE(pDXFile);            return E_FAIL;        }    }
    最后释放不再使用的COM对象:

        SAFE_RELEASE(pFileData);    SAFE_RELEASE(pEnumObj);    SAFE_RELEASE(pDXFile);

    第二个Create()函数与第一个非常类似,只是该函数负责从资源加载网格模型:

    HRESULT CDXUTMeshFile::CreateFromResource(LPDIRECT3DDEVICE9 pd3dDevice, LPCWSTR strResource, LPCWSTR strType)
    {
        LPD3DXFILE           pDXFile   = NULL;
        LPD3DXFILEENUMOBJECT pEnumObj  = NULL;
        LPD3DXFILEDATA       pFileData = NULL;
        HRESULT hr;
        SIZE_T cChildren;

        // Create a x file object
        if( FAILED( hr = D3DXFileCreate(&pDXFile) ) )
            return E_FAIL;

        // Register templates for d3drm and patch extensions.
        if( FAILED( hr = pDXFile->RegisterTemplates((void*) D3DRM_XTEMPLATES, D3DRM_XTEMPLATE_BYTES) ) )
        {
            SAFE_RELEASE( pDXFile );
            return E_FAIL;
        }
        
        CHAR strTypeAnsi[MAX_PATH];
        CHAR strResourceAnsi[MAX_PATH];

        WideCharToMultiByte(CP_ACP, 0, strType, -1, strTypeAnsi, MAX_PATH, NULL, NULL);
        strTypeAnsi[MAX_PATH - 1] = 0;

        WideCharToMultiByte(CP_ACP, 0, strResource, -1, strResourceAnsi, MAX_PATH, NULL, NULL);
        strResourceAnsi[MAX_PATH - 1] = 0;

        D3DXF_FILELOADRESOURCE dxlr;

        dxlr.hModule = NULL;
        dxlr.lpName = strResourceAnsi;
        dxlr.lpType = strTypeAnsi;

        // Create enum object
        hr = pDXFile->CreateEnumObject((void*) &dxlr, D3DXF_FILELOAD_FROMRESOURCE, &pEnumObj);

        if( FAILED(hr) )
        {
            SAFE_RELEASE( pDXFile );
            return hr;
        }

        // Enumerate top level objects (which are always frames)

        pEnumObj->GetChildren(&cChildren);

        for (UINT iChild = 0; iChild < cChildren; iChild++)
        {
            hr = pEnumObj->GetChild(iChild, &pFileData);
            if (FAILED(hr))
                return hr;

            hr = LoadFrame(pd3dDevice, pFileData, this);
            SAFE_RELEASE( pFileData );

            if( FAILED(hr) )
            {
                SAFE_RELEASE(pEnumObj);
                SAFE_RELEASE(pDXFile);
                return E_FAIL;
            }
        }

        SAFE_RELEASE(pFileData);
        SAFE_RELEASE(pEnumObj);
        SAFE_RELEASE(pDXFile);

        return S_OK;
    }

    唯一需要解释的代码是:

        D3DXF_FILELOADRESOURCE dxlr;
        dxlr.hModule = NULL;    dxlr.lpName = strResourceAnsi;    dxlr.lpType = strTypeAnsi;
        // Create enum object    hr = pDXFile->CreateEnumObject((void*) &dxlr, D3DXF_FILELOAD_FROMRESOURCE, &pEnumObj);

    ----------------------------------------------
    事业是国家的,荣誉是单位的,成绩是领导的,工资是老婆的,财产是孩子的,错误是自己的。

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2008/12/26 10:52:00
      鲜花(0)  鸡蛋(0)        点击这里获取本站专享China-pub购书优惠券
     卷积内核 帅哥哟,离线,有人找我吗?
      
      
      威望:8
      头衔:总统
      等级:博士二年级(版主)
      文章:3942
      积分:27590
      门派:XML.ORG.CN
      院校:(无权查看)
      注册:2004/7/21
    给卷积内核发送一个短消息 把卷积内核加入好友 查看卷积内核的个人资料 搜索卷积内核在『 C/C++编程思想 』的所有贴子 访问卷积内核的主页 引用回复这个贴子 回复这个贴子 查看卷积内核的博客2
    发贴心情 
    该代码片段负责从指定的资源中加载网格模型,D3DXF_FILELOADRESOURCE的声明如下:

    Identifies resource data.

    typedef struct D3DXF_FILELOADRESOURCE {    HMODULE hModule;    LPCSTR lpName;    LPCSTR lpType;} D3DXF_FILELOADRESOURCE, *LPD3DXF_FILELOADRESOURCE;
    Members
    hModule
    Handle of the module containing the resource to be loaded. If this member is NULL, the resource must be attached to the executable file that will use it.
    lpName
    Pointer to a string specifying the name of the resource to be loaded. For example, if the resource is a mesh, this member should specify the name of the mesh file.
    lpType
    Pointer to a string specifying the user-defined type identifying the resource.
    Remarks
    This structure identifies a resource to be loaded when an application uses the ID3DXFile::CreateEnumObject method and specifies the D3DXF_FILELOAD_FROMRESOURCE flag.

    Render()函数负责网格模型的渲染,它允许用户在调用时设置一个世界坐标矩阵:

    HRESULT CDXUTMeshFile::Render(LPDIRECT3DDEVICE9 pd3dDevice, D3DXMATRIX* pmatWorldMatrix)
    {
        // For pure devices, specify the world transform.
        // If the world transform is not specified on pure devices, this function will fail.

        // Set up the world transformation
        D3DXMATRIX matSavedWorld, matWorld;

        if (NULL == pmatWorldMatrix)
            pd3dDevice->GetTransform(D3DTS_WORLD, &matSavedWorld);
        else
            matSavedWorld = *pmatWorldMatrix;

        D3DXMatrixMultiply(&matWorld, &matSavedWorld, &m_mat);
        pd3dDevice->SetTransform(D3DTS_WORLD, &matWorld);

        // Render opaque subsets in the meshes
        if(m_pChild)
            m_pChild->Render(pd3dDevice, TRUE, FALSE, &matWorld);

        // Enable alpha blending
        pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
        pd3dDevice->SetRenderState(D3DRS_SRCBLEND,  D3DBLEND_SRCALPHA);
        pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);

        // Render alpha subsets in the meshes
        if(m_pChild)
            m_pChild->Render(pd3dDevice, FALSE, TRUE, &matWorld);

        // Restore state
        pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
        pd3dDevice->SetTransform(D3DTS_WORLD, &matSavedWorld);

        return S_OK;
    }
    因为CDXUTMeshFile继承自CDXUTMeshFrame,并且该类的默认构造函数定义如下:
    CDXUTMeshFile() : CDXUTMeshFrame( L"CDXUTMeshFile_Root" ) {}

    也就是说在创建该类对象时默认创建了一个CDXUTMeshFrame对象,这也意味着在加载网格模型时所有后续的CDXUTMeshFrame对象都是该对象的子对象,所以下面的代码是合法的:

        // Render opaque subsets in the meshes    if(m_pChild)        m_pChild->Render(pd3dDevice, TRUE, FALSE, &matWorld);
        // Enable alpha blending    pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);    pd3dDevice->SetRenderState(D3DRS_SRCBLEND,  D3DBLEND_SRCALPHA);    pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
        // Render alpha subsets in the meshes    if(m_pChild)        m_pChild->Render(pd3dDevice, FALSE, TRUE, &matWorld);
        // Restore state    pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);    pd3dDevice->SetTransform(D3DTS_WORLD, &matSavedWorld);
    先渲染所有不透明的子框架对象,再渲染所有半透明的子框架对象,最后恢复到先前的渲染状态。

    ----------------------------------------------
    事业是国家的,荣誉是单位的,成绩是领导的,工资是老婆的,财产是孩子的,错误是自己的。

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2008/12/26 10:53:00
            点击这里获取本站专享China-pub购书优惠券
     秋十三 帅哥哟,离线,有人找我吗?
      
      
      等级:大三(要不要学学XML呢?)
      文章:124
      积分:593
      门派:XML.ORG.CN
      院校:(无权查看)
      注册:2008/11/12
    给秋十三发送一个短消息 把秋十三加入好友 查看秋十三的个人资料 搜索秋十三在『 C/C++编程思想 』的所有贴子 引用回复这个贴子 回复这个贴子 查看秋十三的博客3
    发贴心情 

    我顶啊!!!
    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2009/1/2 20:32:00
            点击这里获取本站专享China-pub购书优惠券
     GoogleAdSense
      
      
      等级:大一新生
      文章:1
      积分:50
      门派:无门无派
      院校:未填写
      注册:2007-01-01
    给Google AdSense发送一个短消息 把Google AdSense加入好友 查看Google AdSense的个人资料 搜索Google AdSense在『 C/C++编程思想 』的所有贴子 访问Google AdSense的主页 引用回复这个贴子 回复这个贴子 查看Google AdSense的博客广告
    2024/11/26 16:06:14

    本主题贴数3,分页: [1]

    管理选项修改tag | 锁定 | 解锁 | 提升 | 删除 | 移动 | 固顶 | 总固顶 | 奖励 | 惩罚 | 发布公告
    W 3 C h i n a ( since 2003 ) 旗 下 站 点
    苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
    125.000ms