维爱迪-动画创作家园 >> 动画理论 >> 3D游戏角色动画 |
第六,枚举数据对象:
注册完模版,打开X文件并且得到一个枚举对象接口,下面需要从X文件读出数据。枚举对象接口指针指向文件的第一个数据对象,因为每一个数据对象可能包含内嵌数据对象或者引用的数据对象,所以与第一个数据对象同在一层级的其它数据对象为同层级数据对象。至于包含的子数据对象的类型,需要对其分别的行进询问。可以使用HRESULT IDirectXFileEnumObject::GetNextDataObject (LPDIRECTXFILEDATA* ppDataObj)得到一个IDirectXFileData接口。它只有一个参数:
IDirectXFileData *pData;
HRESULT hr = pEnum->GetNextDataObject(&pData);
利用此函数,可以不断地访问同一层级的数据对象接口,具体代码如下:
while(SUCCEEDED(pEnum->GetNextDataObject(&pData))) {
// 这里可以对pData数据对象进行操作。
pData->Release();//释放接口。
}
当返回值为FAILED,表示已经访问完所有的接口。当访问值为SUCCEEDED,你需要继续判断这个数据对象是否包含子对象。利用接口IDirectXFileObject,和HRESULT IDirectXFileData::GetNextObject( LPDIRECTXFILEOBJECT* ppChildObj)函数,代码如下:
IDirectXFileObject *pObject;
while(SUCCEEDED(pData->GetNextObject(&pObject)))
{
// 如果一个子对象存在,需要继续询问它,判断出它的类型为内嵌数据对象或者引用的数
// 据对象。
pObject->Release();// 释放接口。
}
接下来询问接口,看其是否为内嵌数据对象:
IDirectXFileData *pSubData;
if(SUCCEEDED(pObject->QueryInterface( \
IID_IDirectXFileData, (void**)&pSubData))) {
// 如果询问内嵌数据对象成功,可以对pSubData数据对象进行操作
pSubData->Release();//释放接口。
}
看其是否为引用数据对象:
IDirectXFileDataReference *pRef;
IDirectXFileData *pSubData;
if(SUCCEEDED(pSubObj->QueryInterface( IID_IDirectXFileDataReference, \
(void**)&pRef))) {
// 如果询问引用的数据对象成功,解析出引用的原型。
pRef->Resolve(&pSubData);
//这里可以对pData数据对象进行操作。
pRef->Release();
pSubData->Release();//释放接口。
}
现在整理下思路:大体的思路其实很简单,首先枚举最顶层的数据对象,然后判断其是否有子对象,这个子对象可能是内嵌对象或者引用对象二者之一,分别询问其接口,就可以判断出具体的类型。
下面是完整的Parse模版的函数:
BOOL Parse(char *Filename)
{
IDirectXFile *pFile = NULL;
IDirectXFileEnumObject *pEnum = NULL;
IDirectXFileData *pData = NULL;
if(FAILED(DirectXFileCreate(&pFile)))
return FALSE;
//注册标准模版。
if(FAILED(pFile->RegisterTemplates( \
(LPVOID)D3DRM_XTEMPLATES, D3DRM_XTEMPLATE_BYTES)))
return FALSE;
//创建一个枚举对象接口。
if(FAILED(pDXFile->CreateEnumObject((LPVOID)Filename, \
DXFILELOAD_FROMFILE, \
&pEnum))) {
pFile->Release();
return FALSE;
}
// 遍历所有的顶层数据对象。
while(SUCCEEDED(pEnum->GetNextDataObject(&pData))) {
// 用ParseObject解析其子数据对象。
ParseObject(pData);
pData->Release();
}
pEnum->Release();
pFile->Release();
return TRUE;
}
这个函数的主要部分在ParseObject(pData),它负责解析子数据对象:
void ParseObject(IDirectXFileData *pData)
{
IDirectXFileObject *pObject = NULL;
IDirectXFileData *pSubData = NULL;
IDirectXFileDataReference *pRef = NULL;
while(SUCCEEDED(pData->GetNextObject(&pObject))) {
if(SUCCEEDED(pObject->QueryInterface( IID_IDirectXFileDataReference, (void**)&pRef))) {
pRef->Resolve(&pSubData);
ParseObject(pSubData);
pSubData->Release();
pRef->Release(); }
if(SUCCEEDED(pObject->QueryInterface( IID_IDirectXFileData, (void**)&pSubData))) {
ParseObject(pSubData);
pSubData->Release();
}
pObject->Release();
}
}
这是个递归函数,调用函数自身。判断子对象的类别,对其继续解析,直到返回值为FAILED,表示已没有子对象。从上面可以看出,这个函数除了枚举所有的对象,并没有做任何事情,下面就要从这些数据对象检索数据。