www.pudn.com > XFileLoadingCode.zip > DXUTMesh.cpp


//----------------------------------------------------------------------------- 
// File: DXUTMesh.cpp 
// 
// Desc: Support code for loading DirectX .X files. 
// 
// Copyright (c) Microsoft Corporation. All rights reserved. 
//----------------------------------------------------------------------------- 
#include "dxstdafx.h" 
#include  
#include  
#include  
#include "DXUTMesh.h" 
#undef min // use __min instead 
#undef max // use __max instead 
 
 
 
 
//----------------------------------------------------------------------------- 
CDXUTMesh::CDXUTMesh( LPCWSTR strName ) 
{ 
    StringCchCopy( m_strName, 512, strName ); 
    m_pMesh              = NULL; 
    m_dwNumMaterials     = 0L; 
    m_pMaterials         = NULL; 
    m_pTextures          = NULL; 
    m_bUseMaterials      = TRUE; 
} 
 
 
 
 
//----------------------------------------------------------------------------- 
CDXUTMesh::~CDXUTMesh() 
{ 
    Destroy(); 
} 
 
 
 
 
//----------------------------------------------------------------------------- 
HRESULT CDXUTMesh::Create( LPDIRECT3DDEVICE9 pd3dDevice, LPCWSTR strFilename ) 
{ 
    WCHAR        strPath[MAX_PATH]; 
    LPD3DXBUFFER pAdjacencyBuffer = NULL; 
    LPD3DXBUFFER pMtrlBuffer = NULL; 
    HRESULT      hr; 
 
    // Cleanup previous mesh if any 
    Destroy(); 
 
    // Find the path for the file, and convert it to ANSI (for the D3DX API) 
    DXUTFindDXSDKMediaFileCch( strPath, sizeof(strPath) / sizeof(WCHAR), strFilename ); 
 
    // Load the mesh 
    if( FAILED( hr = D3DXLoadMeshFromX( strPath, D3DXMESH_MANAGED, pd3dDevice,  
                                        &pAdjacencyBuffer, &pMtrlBuffer, NULL, 
                                        &m_dwNumMaterials, &m_pMesh ) ) ) 
    { 
        return hr; 
    } 
 
    // Optimize the mesh for performance 
    if( FAILED( hr = m_pMesh->OptimizeInplace( 
                        D3DXMESHOPT_COMPACT | D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_VERTEXCACHE, 
                        (DWORD*)pAdjacencyBuffer->GetBufferPointer(), NULL, NULL, NULL ) ) ) 
    { 
        SAFE_RELEASE( pAdjacencyBuffer ); 
        SAFE_RELEASE( pMtrlBuffer ); 
        return hr; 
    } 
 
    // Set strPath to the path of the mesh file 
    WCHAR *pLastBSlash = wcsrchr( strPath, L'\\' ); 
    if( pLastBSlash ) 
        *(pLastBSlash + 1) = L'\0'; 
    else 
        *strPath = L'\0'; 
 
    D3DXMATERIAL* d3dxMtrls = (D3DXMATERIAL*)pMtrlBuffer->GetBufferPointer(); 
    hr = CreateMaterials( strPath, pd3dDevice, d3dxMtrls, m_dwNumMaterials ); 
 
    SAFE_RELEASE( pAdjacencyBuffer ); 
    SAFE_RELEASE( pMtrlBuffer ); 
 
    // Extract data from m_pMesh for easy access 
    D3DVERTEXELEMENT9 decl[MAX_FVF_DECL_SIZE]; 
    m_dwNumVertices    = m_pMesh->GetNumVertices(); 
    m_dwNumFaces       = m_pMesh->GetNumFaces(); 
    m_dwBytesPerVertex = m_pMesh->GetNumBytesPerVertex(); 
    m_pMesh->GetIndexBuffer( &m_pIB ); 
    m_pMesh->GetVertexBuffer( &m_pVB ); 
    m_pMesh->GetDeclaration( decl ); 
    pd3dDevice->CreateVertexDeclaration( decl, &m_pDecl ); 
 
    return hr; 
} 
 
 
//----------------------------------------------------------------------------- 
HRESULT CDXUTMesh::Create( LPDIRECT3DDEVICE9 pd3dDevice, 
                           LPD3DXFILEDATA pFileData ) 
{ 
    LPD3DXBUFFER pMtrlBuffer = NULL; 
    LPD3DXBUFFER pAdjacencyBuffer = NULL; 
    HRESULT      hr; 
 
    // Cleanup previous mesh if any 
    Destroy(); 
 
    // Load the mesh from the DXFILEDATA object 
    if( FAILED( hr = D3DXLoadMeshFromXof( pFileData, D3DXMESH_MANAGED, pd3dDevice, 
                                          &pAdjacencyBuffer, &pMtrlBuffer, NULL, 
                                          &m_dwNumMaterials, &m_pMesh ) ) ) 
    { 
        return hr; 
    } 
 
    // Optimize the mesh for performance 
    if( FAILED( hr = m_pMesh->OptimizeInplace( 
                        D3DXMESHOPT_COMPACT | D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_VERTEXCACHE, 
                        (DWORD*)pAdjacencyBuffer->GetBufferPointer(), NULL, NULL, NULL ) ) ) 
    { 
        SAFE_RELEASE( pAdjacencyBuffer ); 
        SAFE_RELEASE( pMtrlBuffer ); 
        return hr; 
    } 
 
    D3DXMATERIAL* d3dxMtrls = (D3DXMATERIAL*)pMtrlBuffer->GetBufferPointer(); 
    hr = CreateMaterials( L"", pd3dDevice, d3dxMtrls, m_dwNumMaterials ); 
 
    SAFE_RELEASE( pAdjacencyBuffer ); 
    SAFE_RELEASE( pMtrlBuffer ); 
 
    // Extract data from m_pMesh for easy access 
    D3DVERTEXELEMENT9 decl[MAX_FVF_DECL_SIZE]; 
    m_dwNumVertices    = m_pMesh->GetNumVertices(); 
    m_dwNumFaces       = m_pMesh->GetNumFaces(); 
    m_dwBytesPerVertex = m_pMesh->GetNumBytesPerVertex(); 
    m_pMesh->GetIndexBuffer( &m_pIB ); 
    m_pMesh->GetVertexBuffer( &m_pVB ); 
    m_pMesh->GetDeclaration( decl ); 
    pd3dDevice->CreateVertexDeclaration( decl, &m_pDecl ); 
 
    return hr; 
} 
 
 
//----------------------------------------------------------------------------- 
HRESULT CDXUTMesh::Create( LPDIRECT3DDEVICE9 pd3dDevice, ID3DXMesh* pInMesh,  
                           D3DXMATERIAL* pd3dxMaterials, DWORD dwMaterials ) 
{ 
    // Cleanup previous mesh if any 
    Destroy(); 
 
    // Optimize the mesh for performance 
    DWORD *rgdwAdjacency = NULL; 
    rgdwAdjacency = new DWORD[pInMesh->GetNumFaces() * 3]; 
    if( rgdwAdjacency == NULL ) 
        return E_OUTOFMEMORY; 
    pInMesh->GenerateAdjacency(1e-6f,rgdwAdjacency); 
 
    D3DVERTEXELEMENT9 decl[MAX_FVF_DECL_SIZE]; 
    pInMesh->GetDeclaration( decl ); 
 
    DWORD dwOptions = pInMesh->GetOptions(); 
    dwOptions &= ~(D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM | D3DXMESH_WRITEONLY); 
    dwOptions |= D3DXMESH_MANAGED; 
    dwOptions |= D3DXMESHOPT_COMPACT | D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_VERTEXCACHE; 
 
    ID3DXMesh* pTempMesh = NULL; 
    if( FAILED( pInMesh->Optimize( dwOptions, rgdwAdjacency, NULL, NULL, NULL, &pTempMesh ) ) ) 
    { 
        SAFE_DELETE_ARRAY( rgdwAdjacency ); 
        return E_FAIL; 
    } 
 
    SAFE_DELETE_ARRAY( rgdwAdjacency ); 
    SAFE_RELEASE( m_pMesh ); 
    m_pMesh = pTempMesh; 
 
    HRESULT hr; 
    hr = CreateMaterials( L"", pd3dDevice, pd3dxMaterials, dwMaterials ); 
 
    // Extract data from m_pMesh for easy access 
    m_dwNumVertices    = m_pMesh->GetNumVertices(); 
    m_dwNumFaces       = m_pMesh->GetNumFaces(); 
    m_dwBytesPerVertex = m_pMesh->GetNumBytesPerVertex(); 
    m_pMesh->GetIndexBuffer( &m_pIB ); 
    m_pMesh->GetVertexBuffer( &m_pVB ); 
    m_pMesh->GetDeclaration( decl ); 
    pd3dDevice->CreateVertexDeclaration( decl, &m_pDecl ); 
 
    return hr; 
} 
 
 
//----------------------------------------------------------------------------- 
HRESULT CDXUTMesh::CreateMaterials( LPCWSTR strPath, IDirect3DDevice9 *pd3dDevice, D3DXMATERIAL* d3dxMtrls, DWORD dwNumMaterials ) 
{ 
    // Get material info for the mesh 
    // Get the array of materials out of the buffer 
    m_dwNumMaterials = dwNumMaterials; 
    if( d3dxMtrls && m_dwNumMaterials > 0 ) 
    { 
        // Allocate memory for the materials and textures 
        m_pMaterials = new D3DMATERIAL9[m_dwNumMaterials]; 
        if( m_pMaterials == NULL ) 
            return E_OUTOFMEMORY; 
        m_pTextures = new LPDIRECT3DBASETEXTURE9[m_dwNumMaterials]; 
        if( m_pTextures == NULL ) 
            return E_OUTOFMEMORY; 
        m_strMaterials = new CHAR[m_dwNumMaterials][MAX_PATH]; 
        if( m_strMaterials == NULL ) 
            return E_OUTOFMEMORY; 
 
        // Copy each material and create its texture 
        for( DWORD i=0; iQueryInterface( IID_IDirect3DBaseTexture9, (LPVOID*)&m_pTextures[i] ); 
                            // Release the specialized instance 
                            pTex->Release(); 
                        } 
                        break; 
                    } 
                    case D3DRTYPE_CUBETEXTURE: 
                    { 
                        IDirect3DCubeTexture9 *pTex; 
                        if( SUCCEEDED( D3DXCreateCubeTextureFromFile( pd3dDevice, strTexture, &pTex ) ) ) 
                        { 
                            // Obtain the base texture interface 
                            pTex->QueryInterface( IID_IDirect3DBaseTexture9, (LPVOID*)&m_pTextures[i] ); 
                            // Release the specialized instance 
                            pTex->Release(); 
                        } 
                        break; 
                    } 
                    case D3DRTYPE_VOLUMETEXTURE: 
                    { 
                        IDirect3DVolumeTexture9 *pTex; 
                        if( SUCCEEDED( D3DXCreateVolumeTextureFromFile( pd3dDevice, strTexture, &pTex ) ) ) 
                        { 
                            // Obtain the base texture interface 
                            pTex->QueryInterface( IID_IDirect3DBaseTexture9, (LPVOID*)&m_pTextures[i] ); 
                            // Release the specialized instance 
                            pTex->Release(); 
                        } 
                        break; 
                    } 
                } 
            } 
        } 
    } 
    return S_OK; 
} 
 
 
//----------------------------------------------------------------------------- 
HRESULT CDXUTMesh::SetFVF( LPDIRECT3DDEVICE9 pd3dDevice, DWORD dwFVF ) 
{ 
    LPD3DXMESH pTempMesh = NULL; 
 
    if( m_pMesh ) 
    { 
        if( FAILED( m_pMesh->CloneMeshFVF( m_pMesh->GetOptions(), dwFVF, 
                                           pd3dDevice, &pTempMesh ) ) ) 
        { 
            SAFE_RELEASE( pTempMesh ); 
            return E_FAIL; 
        } 
 
        DWORD dwOldFVF = 0; 
        dwOldFVF = m_pMesh->GetFVF(); 
        SAFE_RELEASE( m_pMesh ); 
        m_pMesh = pTempMesh; 
 
        // Compute normals if they are being requested and 
        // the old mesh does not have them. 
        if( !(dwOldFVF & D3DFVF_NORMAL) && dwFVF & D3DFVF_NORMAL ) 
        { 
            D3DXComputeNormals( m_pMesh, NULL ); 
        } 
    } 
 
    return S_OK; 
} 
 
 
 
 
//----------------------------------------------------------------------------- 
// Convert the mesh to the format specified by the given vertex declarations. 
//----------------------------------------------------------------------------- 
HRESULT CDXUTMesh::SetVertexDecl( LPDIRECT3DDEVICE9 pd3dDevice, const D3DVERTEXELEMENT9 *pDecl,  
                                  bool bAutoComputeNormals, bool bAutoComputeTangents,  
                                  bool bSplitVertexForOptimalTangents ) 
{ 
    LPD3DXMESH pTempMesh = NULL; 
 
    if( m_pMesh ) 
    { 
        if( FAILED( m_pMesh->CloneMesh( m_pMesh->GetOptions(), pDecl, 
                                        pd3dDevice, &pTempMesh ) ) ) 
        { 
            SAFE_RELEASE( pTempMesh ); 
            return E_FAIL; 
        } 
    } 
 
 
    // Check if the old declaration contains a normal. 
    bool bHadNormal = false; 
    bool bHadTangent = false; 
    D3DVERTEXELEMENT9 aOldDecl[MAX_FVF_DECL_SIZE]; 
    if( m_pMesh && SUCCEEDED( m_pMesh->GetDeclaration( aOldDecl ) ) ) 
    { 
        for( UINT index = 0; index < D3DXGetDeclLength( aOldDecl ); ++index ) 
        { 
            if( aOldDecl[index].Usage == D3DDECLUSAGE_NORMAL ) 
            { 
                bHadNormal = true; 
            } 
            if( aOldDecl[index].Usage == D3DDECLUSAGE_TANGENT ) 
            { 
                bHadTangent = true; 
            } 
        } 
    } 
 
    // Check if the new declaration contains a normal. 
    bool bHaveNormalNow = false; 
    bool bHaveTangentNow = false; 
    D3DVERTEXELEMENT9 aNewDecl[MAX_FVF_DECL_SIZE]; 
    if( pTempMesh && SUCCEEDED( pTempMesh->GetDeclaration( aNewDecl ) ) ) 
    { 
        for( UINT index = 0; index < D3DXGetDeclLength( aNewDecl ); ++index ) 
        { 
            if( aNewDecl[index].Usage == D3DDECLUSAGE_NORMAL ) 
            { 
                bHaveNormalNow = true; 
            } 
            if( aNewDecl[index].Usage == D3DDECLUSAGE_TANGENT ) 
            { 
                bHaveTangentNow = true; 
            } 
        } 
    } 
 
    SAFE_RELEASE( m_pMesh ); 
 
    if( pTempMesh ) 
    { 
        m_pMesh = pTempMesh; 
 
        if( !bHadNormal && bHaveNormalNow && bAutoComputeNormals ) 
        { 
            // Compute normals in case the meshes have them 
            D3DXComputeNormals( m_pMesh, NULL ); 
        } 
 
        if( bHaveNormalNow && !bHadTangent && bHaveTangentNow && bAutoComputeTangents ) 
        { 
            ID3DXMesh* pNewMesh; 
            HRESULT hr; 
 
            DWORD *rgdwAdjacency = NULL; 
            rgdwAdjacency = new DWORD[m_pMesh->GetNumFaces() * 3]; 
            if( rgdwAdjacency == NULL ) 
                return E_OUTOFMEMORY; 
            V( m_pMesh->GenerateAdjacency(1e-6f,rgdwAdjacency) ); 
 
            float fPartialEdgeThreshold; 
            float fSingularPointThreshold; 
            float fNormalEdgeThreshold; 
            if( bSplitVertexForOptimalTangents ) 
            { 
                fPartialEdgeThreshold = 0.01f; 
                fSingularPointThreshold = 0.25f; 
                fNormalEdgeThreshold = 0.01f; 
            } 
            else 
            { 
                fPartialEdgeThreshold = -1.01f; 
                fSingularPointThreshold = 0.01f; 
                fNormalEdgeThreshold = -1.01f; 
            } 
 
            // Compute tangents, which are required for normal mapping 
            hr = D3DXComputeTangentFrameEx( m_pMesh,  
                                            D3DDECLUSAGE_TEXCOORD, 0,  
                                            D3DDECLUSAGE_TANGENT, 0, 
                                            D3DX_DEFAULT, 0,  
                                            D3DDECLUSAGE_NORMAL, 0, 
                                            0, rgdwAdjacency,  
                                            fPartialEdgeThreshold, fSingularPointThreshold, fNormalEdgeThreshold,  
                                            &pNewMesh, NULL ); 
 
            SAFE_DELETE_ARRAY( rgdwAdjacency ); 
            if( FAILED(hr) ) 
                return hr; 
 
            SAFE_RELEASE( m_pMesh ); 
            m_pMesh = pNewMesh; 
        } 
    } 
 
    return S_OK; 
} 
 
 
 
 
//----------------------------------------------------------------------------- 
HRESULT CDXUTMesh::RestoreDeviceObjects( LPDIRECT3DDEVICE9 pd3dDevice ) 
{ 
    return S_OK; 
} 
 
 
 
 
//----------------------------------------------------------------------------- 
HRESULT CDXUTMesh::InvalidateDeviceObjects() 
{ 
    SAFE_RELEASE( m_pIB ); 
    SAFE_RELEASE( m_pVB ); 
    SAFE_RELEASE( m_pDecl ); 
 
    return S_OK; 
} 
 
 
 
 
//----------------------------------------------------------------------------- 
HRESULT CDXUTMesh::Destroy() 
{ 
    InvalidateDeviceObjects(); 
    for( UINT i=0; iSetMaterial( &m_pMaterials[i] ); 
                pd3dDevice->SetTexture( 0, m_pTextures[i] ); 
            } 
            m_pMesh->DrawSubset( i ); 
        } 
    } 
 
    // Then, draw the subsets with alpha 
    if( bDrawAlphaSubsets && m_bUseMaterials ) 
    { 
        for( DWORD i=0; iSetMaterial( &m_pMaterials[i] ); 
            pd3dDevice->SetTexture( 0, m_pTextures[i] ); 
            m_pMesh->DrawSubset( i ); 
        } 
    } 
 
    return S_OK; 
} 
 
 
 
 
//----------------------------------------------------------------------------- 
HRESULT CDXUTMesh::Render( ID3DXEffect *pEffect, 
                           D3DXHANDLE hTexture, 
                           D3DXHANDLE hDiffuse, 
                           D3DXHANDLE hAmbient, 
                           D3DXHANDLE hSpecular, 
                           D3DXHANDLE hEmissive, 
                           D3DXHANDLE hPower, 
                           bool bDrawOpaqueSubsets, 
                           bool bDrawAlphaSubsets ) 
{ 
    if( NULL == m_pMesh ) 
        return E_FAIL; 
 
    UINT cPasses; 
    // Frist, draw the subsets without alpha 
    if( bDrawOpaqueSubsets ) 
    { 
        pEffect->Begin( &cPasses, 0 ); 
        for( UINT p = 0; p < cPasses; ++p ) 
        { 
            pEffect->BeginPass( p ); 
            for( DWORD i=0; iSetTexture( hTexture, m_pTextures[i] ); 
                    // D3DCOLORVALUE and D3DXVECTOR4 are data-wise identical. 
                    // No conversion is needed. 
                    if( hDiffuse ) 
                        pEffect->SetVector( hDiffuse, (D3DXVECTOR4*)&m_pMaterials[i].Diffuse ); 
                    if( hAmbient ) 
                        pEffect->SetVector( hAmbient, (D3DXVECTOR4*)&m_pMaterials[i].Ambient ); 
                    if( hSpecular ) 
                        pEffect->SetVector( hSpecular, (D3DXVECTOR4*)&m_pMaterials[i].Specular ); 
                    if( hEmissive ) 
                        pEffect->SetVector( hEmissive, (D3DXVECTOR4*)&m_pMaterials[i].Emissive ); 
                    if( hPower ) 
                        pEffect->SetFloat( hPower, m_pMaterials[i].Power ); 
                    pEffect->CommitChanges(); 
                } 
                m_pMesh->DrawSubset( i ); 
            } 
            pEffect->EndPass(); 
        } 
        pEffect->End(); 
    } 
 
    // Then, draw the subsets with alpha 
    if( bDrawAlphaSubsets && m_bUseMaterials ) 
    { 
        pEffect->Begin( &cPasses, 0 ); 
        for( UINT p = 0; p < cPasses; ++p ) 
        { 
            pEffect->BeginPass( p ); 
            for( DWORD i=0; iSetTexture( hTexture, m_pTextures[i] ); 
                    // D3DCOLORVALUE and D3DXVECTOR4 are data-wise identical. 
                    // No conversion is needed. 
                    if( hDiffuse ) 
                        pEffect->SetVector( hDiffuse, (D3DXVECTOR4*)&m_pMaterials[i].Diffuse ); 
                    if( hAmbient ) 
                        pEffect->SetVector( hAmbient, (D3DXVECTOR4*)&m_pMaterials[i].Ambient ); 
                    if( hSpecular ) 
                        pEffect->SetVector( hSpecular, (D3DXVECTOR4*)&m_pMaterials[i].Specular ); 
                    if( hEmissive ) 
                        pEffect->SetVector( hEmissive, (D3DXVECTOR4*)&m_pMaterials[i].Emissive ); 
                    if( hPower ) 
                        pEffect->SetFloat( hPower, m_pMaterials[i].Power ); 
                    pEffect->CommitChanges(); 
                } 
                m_pMesh->DrawSubset( i ); 
            } 
            pEffect->EndPass(); 
        } 
        pEffect->End(); 
    } 
 
    return S_OK; 
} 
 
 
 
 
//----------------------------------------------------------------------------- 
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 ); 
} 
 
 
 
 
//----------------------------------------------------------------------------- 
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; 
} 
 
 
 
 
//----------------------------------------------------------------------------- 
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; 
} 
 
 
 
 
//----------------------------------------------------------------------------- 
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; 
} 
 
 
 
 
//----------------------------------------------------------------------------- 
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; 
} 
 
 
 
 
//----------------------------------------------------------------------------- 
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; 
 
        WideCharToMultiByte( CP_ACP, 0, strName, -1, strAnsiName, 512, NULL, NULL ); 
        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; 
} 
 
 
 
 
//----------------------------------------------------------------------------- 
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; 
} 
 
 
 
 
//----------------------------------------------------------------------------- 
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; 
} 
 
 
 
 
//----------------------------------------------------------------------------- 
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; 
} 
 
 
 
 
//----------------------------------------------------------------------------- 
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; 
}