⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 allocatehierarchy.cpp

📁 骨骼动画 此程序演示了如何在你的游戏中使用骨骼动画技术。
💻 CPP
字号:
// 个性化注释:天兵 zzprogram@126.com

#include "AllocateHierarchy.h"

//-----------------------------------------------------------------------------
// Name: AllocateName()
// Desc: 第2个被调用,只是拷贝字符串函数罢了。没啥大不了,学生们可以略过... ...
//-----------------------------------------------------------------------------
HRESULT AllocateName( LPTSTR *ppDst, LPCTSTR pScr )
{
	// 将Name的字符串内容保存到pNewName中去
    UINT cbLength;
	
    if (pScr != NULL)
    {
        cbLength = lstrlen(pScr) + 1;
        *ppDst = new TCHAR[cbLength];
        if (*ppDst == NULL)
            return E_OUTOFMEMORY;
        memcpy( *ppDst, pScr, cbLength*sizeof(TCHAR) );
    }
    else
    {
        *ppDst = NULL;
    }
	
    return S_OK;
}


//-----------------------------------------------------------------------------
// Name: CAllocateHierarchy::CreateFrame()
// Desc: 第1个被调用,Name是根框架的名字,用来创建整个框架层次(由DX系统内部完成)
// 递归遍例每一个框架(Frame),本例中第一个框架名字叫:Object03
// 第二个是个无名字的框架,第3个框架名字叫:Bip01,第4个是无名字框架,第5个叫Bip01_Footsteps ... ...
//-----------------------------------------------------------------------------
// Name参数的值是"Object03",是该模型的根框架
HRESULT CAllocateHierarchy::CreateFrame(LPCTSTR Name, LPD3DXFRAME *ppNewFrame)
{
    HRESULT hr = S_OK;
    D3DXFRAME_EX *pFrame = NULL;	
    *ppNewFrame = NULL;
	
	// 第一次进来的时候,pFrame可是根框架,不要小看了它。
    pFrame = new D3DXFRAME_EX;	// 创建一个扩展的框架(我们自定义的嘛,你没忘吧?),在这里终于用上了...
    if (pFrame == NULL)		// 分配内存失败? 那就没得玩了~~
    {
        hr = E_OUTOFMEMORY;
        goto e_Exit;
    }
	
	// 只拷贝字符串从Name到pFrame->Name中(别看它好象很可怕的样子,其实没什么大不了地,我们第一本书就学过这个了!)
    hr = AllocateName( &pFrame->Name, Name );
    if (FAILED(hr))		// 哎呀~ 这就是传说中的“goto”~~ 难道真是走投无路了吗??
        goto e_Exit;
	
 
    D3DXMatrixIdentity( &pFrame->TransformationMatrix );				// 单位化当前框架的相对变换矩阵(相对于父框架的变换矩阵)
    D3DXMatrixIdentity( &pFrame->CombinedTransformationMatrix );		// 单位化当前框架的变换矩阵(世界变换矩阵)
	
    pFrame->pMeshContainer = NULL;		// 初始化网格容器
    pFrame->pFrameSibling = NULL;		// 初始化兄弟节点
    pFrame->pFrameFirstChild = NULL;	// 初始化首个子节点
	
    *ppNewFrame = pFrame;	// 指向这个刚创建的框架(还热乎的吧? 不信你摸摸)
    pFrame = NULL;			// pFrame对我们来说,已经没有利用价值了
	e_Exit:					// 同学们不要学这个人写代码。。。因为此人很黄,很暴力! 你跟他学那就是:很傻,很天真! 啊哈哈哈~~~
    //delete pFrame;		// 是时候了,我们干掉它(其实没什么用处,看看前面已经执行过:pFrame = NULL;,说明pFrame指向了空,已经没什么好delete的了)
    return hr;
}




//-----------------------------------------------------------------------------
// Name: CAllocateHierarchy::CreateMeshContainer()
// Desc: 
//-----------------------------------------------------------------------------
#if ((D3D_SDK_VERSION&0xFF)==31)	// Directx9.0b

HRESULT CAllocateHierarchy::CreateMeshContainer(
	LPCTSTR Name, 
	LPD3DXMESHDATA pMeshData,
	LPD3DXMATERIAL pMaterials, 
	LPD3DXEFFECTINSTANCE pEffectInstances, 
	DWORD NumMaterials, 
	DWORD *pAdjacency, 
	LPD3DXSKININFO pSkinInfo, 
	LPD3DXMESHCONTAINER *ppNewMeshContainer) 
#else	// Direct9.0c
	LRESULT CAllocateHierarchy::CreateMeshContainer(
		LPCTSTR Name, 
		CONST D3DXMESHDATA *pMeshData,
		CONST D3DXMATERIAL *pMaterials, 
		CONST D3DXEFFECTINSTANCE *pEffectInstances, 
		DWORD NumMaterials, 
		CONST DWORD *pAdjacency, 
		LPD3DXSKININFO pSkinInfo, 
		LPD3DXMESHCONTAINER *ppNewMeshContainer) 
#endif
{
    HRESULT hr;	// 你应该这个破玩意儿是干什么的吧?
	// 下面用到了我们扩展的自定义结构体(请允许我这么说:)),这个结构扩展了相当多的数据成员,也许你已经忘了。。。
    D3DXMESHCONTAINER_EX *pMeshContainer = NULL;	// 使用前置空先(这是个好习惯)
    UINT NumFaces;	// 面数
    LPDIRECT3DDEVICE9 pd3dDevice = NULL;	
    LPD3DXMESH pMesh = NULL;	// 这是真正的网格接口
    *ppNewMeshContainer = NULL;
	
    // 这个例子不能处理细节度网格模型,一旦被发现(是ID3DXPatchMesh)就全完了!
    if (pMeshData->Type != D3DXMESHTYPE_MESH)
    {
        hr = E_FAIL;
        goto e_Exit;
    }
	
    // get the pMesh interface pointer out of the mesh data structure
	// 终于指到它想要指的了(当然是一个网格模型LPD3DXMESH)
    pMesh = pMeshData->pMesh;
	
    // 如果没有灵活顶点格式,即失败!
    if (pMesh->GetFVF() == 0)
    {
        hr = E_FAIL;
        goto e_Exit;
    }
	
    // new一个扩展的网格容器结构
    pMeshContainer = new D3DXMESHCONTAINER_EX;
    if (pMeshContainer == NULL)
    {
        hr = E_OUTOFMEMORY;
        goto e_Exit;
    }
    memset(pMeshContainer, 0, sizeof(D3DXMESHCONTAINER_EX));
	
    // 将名字拷贝过去(刚干了点正事。。。)
    hr = AllocateName(&pMeshContainer->Name, Name);
    if (FAILED(hr))
        goto e_Exit;        
	
    pMesh->GetDevice(&pd3dDevice);		// 取得设备,保存在pd3dDevice变量中
    NumFaces = pMesh->GetNumFaces();	// 取得模型的面数
	
    // 如果mesh中没有法线信息。。。真倒霉~
    if (!(pMesh->GetFVF() & D3DFVF_NORMAL))
    {
        pMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH;
		
        // 马上克隆一个有法线的模型(但这个法线嘛,只是个空壳而已,也就是说只是在顶点缓冲区中保留了法线的存储空间,并不自动生成正确的法线数据)
        hr = pMesh->CloneMeshFVF( pMesh->GetOptions(), 
			pMesh->GetFVF() | D3DFVF_NORMAL, 
			pd3dDevice, &pMeshContainer->MeshData.pMesh );
        if (FAILED(hr))
            goto e_Exit;
		
        // 为了以后还能使用pMesh干活,必须用它再指向新的网格模型
        pMesh = pMeshContainer->MeshData.pMesh;
		
        // 为每个顶点生成法线(这个函数干得可是个累活,想想吧同学们,无数的叉乘在下面的函数中计算)
        D3DXComputeNormals( pMesh, NULL );
    }
    else  // 为网格容器增加一个网格引用计数(是为了不想过早释放它吧?因为以后还想用pMeshContainer->MeshData.pMesh来干活呢)
    {
        pMeshContainer->MeshData.pMesh = pMesh;
        pMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH;
		
        pMesh->AddRef();
    }

	
    // allocate memory to contain the material information.  This sample uses
    //   the D3D9 materials and texture names instead of the EffectInstance style materials
    pMeshContainer->NumMaterials = max(1, NumMaterials);	// 取得材质数量,NumMaterials是上层函数的参数
    pMeshContainer->pMaterials = new D3DXMATERIAL[pMeshContainer->NumMaterials];		// 创建 材质 数组
    pMeshContainer->ppTextures = new LPDIRECT3DTEXTURE9[pMeshContainer->NumMaterials];	// 创建 纹理 数组
    pMeshContainer->pAdjacency = new DWORD[NumFaces*3];									// 创建 邻接 数组
    if ((pMeshContainer->pAdjacency == NULL) || (pMeshContainer->pMaterials == NULL))
    {
        hr = E_OUTOFMEMORY;
        goto e_Exit;
    }
	
    memcpy(pMeshContainer->pAdjacency, pAdjacency, sizeof(DWORD) * NumFaces*3);	// 拷贝内存,pAdjacency同样是上层函数的参数
    memset(pMeshContainer->ppTextures, 0, sizeof(LPDIRECT3DTEXTURE9) * pMeshContainer->NumMaterials);	// 清空内存(纹理数组的指针)
	
    // 如果有材质,拷贝它们
    if (NumMaterials > 0)            
    {
        memcpy(pMeshContainer->pMaterials, pMaterials, sizeof(D3DXMATERIAL) * NumMaterials);	// 拷贝材质数组内容到pMeshContainer->pMaterials
		
        for (UINT i=0; i<NumMaterials; i++)
        {
            if (pMeshContainer->pMaterials[i].pTextureFilename != NULL)
            {
				// 加载纹理,失败则纹理为NULL
				if( FAILED( D3DXCreateTextureFromFile( 
														pd3dDevice,											// 设备
														pMeshContainer->pMaterials[i].pTextureFilename,		// 纹理文件名
														&pMeshContainer->ppTextures[i] ) ) )				// 纹理接口指针
					pMeshContainer->ppTextures[i] = NULL;		// 加载失败时
				
				// 不要保存一个指向动态内存的指针,加载完就置空
                pMeshContainer->pMaterials[i].pTextureFilename = NULL;
            }
        }
    }
    else // 如果没找到材质,使用默认的
    {
        pMeshContainer->pMaterials[0].pTextureFilename = NULL;
        memset( &pMeshContainer->pMaterials[0].MatD3D, 0, sizeof(D3DMATERIAL9) );
        pMeshContainer->pMaterials[0].MatD3D.Diffuse.r = 0.5f;
        pMeshContainer->pMaterials[0].MatD3D.Diffuse.g = 0.5f;
        pMeshContainer->pMaterials[0].MatD3D.Diffuse.b = 0.5f;
        pMeshContainer->pMaterials[0].MatD3D.Specular = pMeshContainer->pMaterials[0].MatD3D.Diffuse;
    }
	
    // if there is skinning information, save off the required data and then setup for HW skinning
	// 如果有蒙皮信息,保存蒙皮信息,并且设置硬件蒙皮
    if (pSkinInfo != NULL)
    {
        pMeshContainer->pSkinInfo = pSkinInfo;	// 首先保存蒙皮信息
        pSkinInfo->AddRef();		
        pMeshContainer->pOrigMesh = pMesh;		// 原始网格模型数据
        pMesh->AddRef();


		
		// 需要一个变换顶点的偏移矩阵的数组(将顶点从模型空间变换到骨骼空间),
        UINT iNumBone = pSkinInfo->GetNumBones();	// 骨骼数量
        pMeshContainer->pBoneOffsetMatrices = new D3DXMATRIX[iNumBone];	// 创建这个偏移矩阵的数组
        if (pMeshContainer->pBoneOffsetMatrices == NULL)
        {
            hr = E_OUTOFMEMORY;
            goto e_Exit;
        }
		
        // 保存每块骨头的偏移矩阵
        for (UINT i=0; i < iNumBone; i++)
        {
            pMeshContainer->pBoneOffsetMatrices[i] = *(pMeshContainer->pSkinInfo->GetBoneOffsetMatrix(i));
        }


		
        // GenerateSkinnedMesh will take the general skinning information and transform it to a HW friendly version
		// GenerateSkinnedMesh方法是CSkinMesh类定义的方法,将提供一般的蒙皮信息,并用一个合适版本的HW(硬件)变换它
        hr = m_pSkinMesh->GenerateSkinnedMesh( pMeshContainer );
        if (FAILED(hr))
            goto e_Exit;
    }
	
    *ppNewMeshContainer = pMeshContainer;
    pMeshContainer = NULL;

e_Exit:
    SAFE_RELEASE(pd3dDevice);
	
	// 释放pMeshContainer所分配的内存
    if (pMeshContainer != NULL)
    {
        DestroyMeshContainer(pMeshContainer);
    }
	
    return hr;
}




//-----------------------------------------------------------------------------
// Name: CAllocateHierarchy::DestroyFrame()
// Desc: 释放框架分配的内存
//-----------------------------------------------------------------------------
HRESULT CAllocateHierarchy::DestroyFrame( LPD3DXFRAME pFrameToFree ) 
{
    SAFE_DELETE_ARRAY( pFrameToFree->Name );
    SAFE_DELETE( pFrameToFree );
    return S_OK; 
}




//-----------------------------------------------------------------------------
// Name: CAllocateHierarchy::DestroyMeshContainer()
// Desc: 释放网格模型容器分配的内存
//-----------------------------------------------------------------------------
HRESULT CAllocateHierarchy::DestroyMeshContainer(LPD3DXMESHCONTAINER pMeshContainerBase)
{
    UINT i;
    D3DXMESHCONTAINER_EX *pMeshContainer = (D3DXMESHCONTAINER_EX*)pMeshContainerBase;
	
    SAFE_DELETE_ARRAY( pMeshContainer->Name );
    SAFE_DELETE_ARRAY( pMeshContainer->pAdjacency );
    SAFE_DELETE_ARRAY( pMeshContainer->pMaterials );
    SAFE_DELETE_ARRAY( pMeshContainer->pBoneOffsetMatrices );
	
    // 释放纹理数组
    if (pMeshContainer->ppTextures != NULL)
    {
        for (i = 0; i < pMeshContainer->NumMaterials; i++)
        {
            SAFE_RELEASE( pMeshContainer->ppTextures[i] );
        }
    }
	
    SAFE_DELETE_ARRAY( pMeshContainer->ppTextures );
    SAFE_DELETE_ARRAY( pMeshContainer->ppBoneMatrixPtrs );
    SAFE_RELEASE( pMeshContainer->pBoneCombinationBuf );
    SAFE_RELEASE( pMeshContainer->MeshData.pMesh );
    SAFE_RELEASE( pMeshContainer->pSkinInfo );
    SAFE_RELEASE( pMeshContainer->pOrigMesh );
    SAFE_DELETE( pMeshContainer );
    return S_OK;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -