博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

模型节点的缓存

Posted on 2011-06-03 13:55  +石头+  阅读(393)  评论(0)    收藏  举报

在游戏中,像树,石头等物体在地图上通常要渲染很多个,如果每个模型都是加载 新资源,这样加载时间会非常长,占用内存也会非常多。所以我们利用缓存来解决这个问题。如果是新资源就加载,如果加载过就读取缓存中的。

我们封装一个类来保存节点的缓存,其中包括Lod的层级模型,文件名(.x),材质层数,材质指针,以及其他的功能的函数:

typedef class CDXMeshNode

{

public:

    CDXMeshNode(LPDIRECT3DDEVICE9 DVC,void* Parent );

    ~CDXMeshNode();

 

    LPD3DXMESH GenMesh;

    LPD3DXMESH LODMeshs[MAXLODLEVEL];

    int                Index;

    D3DMATERIAL9    *mMat;

    DWORD            mAttCount;

    char*            mName;

    HRESULT            QCreate(char*    sName);                        

    void            QUsing();

    void            QRelease();

    void            Render(short iLOD,bool UserSelfMat,LPDIRECT3DTEXTURE9* Face);

    HRESULT            MakeMeshLOD(DWORD* pAdj);

private:

    void     *mParent;

    LPDIRECT3DDEVICE9 mDVC;

    int mRef;

    HRESULT            LoadFromFile();

}*LPMESHNODE;

我们曾经类CDXMeshBuffer来管理节点类(方便对节点的获取和析构),把节点类存储在一个EasyList中。

class CDXMeshBuffer

{

public:

    CDXMeshBuffer(void){};

public:

    ~CDXMeshBuffer(void){};

    void        Init(LPDIRECT3DDEVICE9 DVC);

    LPMESHNODE QCreateMesh(char*    sFile);

    HRESULT QReleaseMesh(char*    sFile);

    DWORD GetMeshCount();

    HRESULT        ReleaseAll();

    HRESULT        DeleteMesh(char*    sFile);

private:

    LPDIRECT3DDEVICE9 mDVC;

    CEasyList mMeshes;

    LPMESHNODE GetMeshNodeByName(char*    sFile);

};

extern CDXMeshBuffer gMeshBuffer;

两个类的实现:

CDXMeshNode::CDXMeshNode( LPDIRECT3DDEVICE9 DVC ,void* Parent )

{

    mMat=NULL;

    Index=-1;

    mAttCount=0;;

    mName=NULL;

    mDVC=DVC;

    mParent=Parent;

    GenMesh=NULL;

    ZeroMemory(LODMeshs,MAXLODLEVEL*sizeof(LPD3DXMESH));

    mRef=0;

}

HRESULT CDXMeshNode::QCreate( char* sName )

{

    mName=new char[strlen(sName)+1];

    strcpy(mName,sName);

    HRESULT hr= LoadFromFile();

    if (!FAILED(hr))

    {

        mRef++;

    }

    return hr;

 

}

 

void CDXMeshNode::QUsing( )

{

 

    mRef++;

 

}

 

void CDXMeshNode::QRelease()

{

    mRef--;

    if (mRef<1)

    {

        if (mParent)

        {

            ((CDXMeshBuffer*)mParent)->DeleteMesh(mName);

        }

    }

 

}

CDXMeshNode::~CDXMeshNode( void )

{

    if(mRef>0) return ;

    if (GenMesh)

    {

        SAFE_RELEASE(GenMesh);

    }

    for (int i=0;i<MAXLODLEVEL;i++)

    {

        if (LODMeshs[i])

        {

            SAFE_RELEASE(LODMeshs[i]);

        }

    }

    if (mMat)

    {

        delete mMat;

    }

    if (mName)

    {

        delete []mName;

        mName=NULL;

    }

}

 

HRESULT CDXMeshNode::LoadFromFile( )

{

    HRESULT hr;

    LPD3DXMESH pMesh;

    LPD3DXBUFFER pAdj;

    LPD3DXBUFFER pMat;

 

    hr=D3DXLoadMeshFromXA(mName,

        D3DXMESH_MANAGED, mDVC, &pAdj,

        &pMat, NULL, &mAttCount, &pMesh) ;

 

    if (FAILED(hr)) return hr;

 

    GenMesh=pMesh;

 

    hr=MakeMeshLOD((DWORD*)pAdj->GetBufferPointer());

    mMat=new D3DMATERIAL9[mAttCount];

    ZeroMemory(mMat,mAttCount*sizeof(D3DMATERIAL9));

 

    D3DXMATERIAL *pMatList;

    pMatList=(D3DXMATERIAL *)pMat->GetBufferPointer();

    for (int i=0;i<mAttCount;i++)

    {

        mMat[i]=pMatList[i].MatD3D;

        mMat[i].Ambient.a=0.3;

        mMat[i].Ambient.r=0.3;

        mMat[i].Ambient.g=0.3;

        mMat[i].Ambient.b=0.3;

    }

    SAFE_RELEASE(pAdj);

    SAFE_RELEASE(pMat);

 

    if (FAILED(hr)) return hr;

 

    return S_OK;

}

 

void CDXMeshNode::Render( short iLOD,bool UserSelfMat,LPDIRECT3DTEXTURE9* Face )

{

    

    for (int i=0;i<mAttCount;i++)

    {

        if (!LODMeshs[i])

        {

            continue;

        }

        if (UserSelfMat)

        {

            mDVC->SetMaterial(&mMat[i]);

        }

        

        if (Face)

        {

            mDVC->SetTexture(0,Face[i]);

        }

        

        LODMeshs[i]->DrawSubset(i);

    }

}

 

HRESULT CDXMeshNode::MakeMeshLOD( DWORD* pAdj )

{

    HRESULT hr;

    if ((GenMesh==NULL) || (pAdj==NULL) )

    {

        return S_FALSE;

    }

    LPD3DXMESH pTempMesh =NULL; //临时网格模型变量

    //清理

    hr = D3DXCleanMesh( D3DXCLEAN_SIMPLIFICATION, GenMesh,pAdj,&pTempMesh,pAdj, NULL ) ;

    if (FAILED(hr)) return hr;

    GenMesh->Release();

    GenMesh = pTempMesh;

 

    //焊接

    D3DXWELDEPSILONS Epsilons;

    ZeroMemory( &Epsilons, sizeof(D3DXWELDEPSILONS) );

    Epsilons.Normal=0.01;

    Epsilons.Position=0.1;

 

    hr = D3DXWeldVertices( GenMesh,D3DXWELDEPSILONS_WELDPARTIALMATCHES,

        &Epsilons,pAdj,pAdj, NULL, NULL );

    if (FAILED(hr)) return hr;

    //检查对原始网格模型进行整理、简化之后,还需要检查处理后的网格模型是否有效

    hr = D3DXValidMesh( GenMesh, pAdj, NULL );

    if (FAILED(hr)) return hr;

    DWORD MaxVetex=GenMesh->GetNumVertices();

    LPD3DXPMESH ppMesh=NULL;

    hr = D3DXGeneratePMesh( GenMesh, pAdj,NULL, NULL, 1, D3DXMESHSIMP_VERTEX, &ppMesh );

    if (FAILED(hr)) return hr;

 

    MaxVetex=GenMesh->GetNumVertices();

    for (int i=0;i<MAXLODLEVEL;i++)

    {

        ppMesh->SetNumVertices(MaxVetex*0.8);

        hr=ppMesh->CloneMeshFVF(ppMesh->GetOptions(),ppMesh->GetFVF(),mDVC,&LODMeshs[i]);

        if (FAILED(hr)) return hr;

        MaxVetex=LODMeshs[i]->GetNumVertices();

        MaxVetex=ppMesh->GetNumVertices();

        if( !(LODMeshs[i]->GetFVF() & D3DFVF_NORMAL) )

        {

            ID3DXMesh* pTempMesh;

            hr=LODMeshs[i]->CloneMeshFVF( LODMeshs[i]->GetOptions(),

                LODMeshs[i]->GetFVF() | D3DFVF_NORMAL,

                mDVC, &pTempMesh ) ;

            SAFE_RELEASE( LODMeshs[i] );

            LODMeshs[i] = pTempMesh;

        }

        hr=D3DXComputeNormals( LODMeshs[i], NULL ) ;

    }

 

    SAFE_RELEASE(ppMesh);

    return S_OK;

}

LPMESHNODE CDXMeshBuffer::QCreateMesh( char* sFile )

{

    LPMESHNODE pMeshNode=NULL;

    pMeshNode=GetMeshNodeByName(sFile);

    if (!pMeshNode)

    {

        pMeshNode =new CDXMeshNode(mDVC,this);

        pMeshNode->QCreate(sFile);

        mMeshes.Add(pMeshNode);

    }else

    {

        pMeshNode->QUsing();

    }

 

    return pMeshNode;

}

 

LPMESHNODE CDXMeshBuffer::GetMeshNodeByName( char* sFile )

{

    LPMESHNODE pMeshNode=NULL;    

    CListCursor Cursor;

    Cursor.Create(&mMeshes);

    pMeshNode=(LPMESHNODE)(Cursor.First());

    int i=0;

    while(pMeshNode)

    {

        if (strcmp(pMeshNode->mName,sFile)==0)

        {

            pMeshNode->Index=i;

            return pMeshNode;

        }

        i++;

        pMeshNode=(LPMESHNODE)(Cursor.Next());

    }

    return NULL;

}

 

 

HRESULT CDXMeshBuffer::QReleaseMesh( char* sFile )

{

    return S_OK;

}

 

DWORD CDXMeshBuffer::GetMeshCount()

{

    return mMeshes.Count();

}

 

HRESULT CDXMeshBuffer::ReleaseAll()

{

    return S_OK;

}

 

void CDXMeshBuffer::Init( LPDIRECT3DDEVICE9 DVC )

{

    mDVC=DVC;

}

 

HRESULT CDXMeshBuffer::DeleteMesh( char* sFile )

{

    LPMESHNODE pNode=(LPMESHNODE)(GetMeshNodeByName(sFile));

    if (pNode>=0)

    {

        if (pNode->Index>=0)

        {

            mMeshes.Delete(pNode->Index);

        }

        delete pNode;

 

    }

    return S_OK;

}

 

 

 

CDXMeshBuffer gMeshBuffer;