写过Advanced Animation with DirectX书里代码的都知道,在现在的DX9.0c中并没有IDirectXFile、IDirectXFileEnumObject、IDirectXFileData 、IDirectXFileDataReference等对象,你在网上到处都可以找见这种类型的错误,关键是如何解决,这里因为新版SDK支持的com对象是ID3DXFile、 ID3DXFileEnumObject 、ID3DXFileData,但是没有ID3DXFileDataReference对象,因为在ID3DXFileData对象里面封装了一个函数isReference(),到时候只要调用此函数即可知道该数据对象是不是引用,而得到数据的首指针也变了,以前直接IDirectXFileData::GetData即可,但新版的明显对其做了安全性要求,将ID3DXFileData锁定数据才能取出,ID3DXFileData::Lock
而且遍历子对象已经不是直接指向下一个对象,而是先取出子对象的个数,然后根据子对象索引来取出子对象,然后再遍历。
好了在代码中由于好多类派生了XParser,所以这里只对这个类代码进行修正,其他的和这个修改完全一样,只要你知道遍历、解析子对象即可
原版的XParser.cpp:
#include "XParser.h"
BOOL cXParser::Parse(char *Filename, void **Data)
{
IDirectXFile *pDXFile = NULL;
IDirectXFileEnumObject *pDXEnum = NULL;
IDirectXFileData *pDXData = NULL;
// Error checking
if(Filename == NULL)
return FALSE;
// Create the file object
if(FAILED(DirectXFileCreate(&pDXFile)))
return FALSE;
// Register the common templates
if(FAILED(pDXFile->RegisterTemplates( \
(LPVOID)D3DRM_XTEMPLATES, \
D3DRM_XTEMPLATE_BYTES))) {
pDXFile->Release();
return FALSE;
}
// Create an enumeration object
if(FAILED(pDXFile->CreateEnumObject((LPVOID)Filename, \
DXFILELOAD_FROMFILE, \
&pDXEnum))) {
pDXFile->Release();
return FALSE;
}
// Call the begin parse function, continuing if allowed
if(BeginParse(Data) == TRUE) {
// Loop through all top-level objects, breaking on errors
BOOL ParseResult;
while(SUCCEEDED(pDXEnum->GetNextDataObject(&pDXData))) //此函数枚举兄弟节点数据(同属于顶级数据即第一层次数据)
{
ParseResult = ParseObject(pDXData, NULL, 0, Data, FALSE);//解析子数据
XPReleaseCOM(pDXData);
if(ParseResult == FALSE)
break;
}
}
// Call end parse function
EndParse(Data);
// Release used COM objects
XPReleaseCOM(pDXEnum);
XPReleaseCOM(pDXFile);
return TRUE;
}
BOOL cXParser::ParseChildObjects( \
IDirectXFileData *pDataObj, \
DWORD Depth, void **Data, \
BOOL ForceReference)
{
IDirectXFileObject *pSubObj = NULL;
IDirectXFileData *pSubData = NULL;
IDirectXFileDataReference *pDataRef = NULL;
BOOL ParseResult = TRUE;
// Scan for embedded templates
while(SUCCEEDED(pDataObj->GetNextObject(&pSubObj)))//枚举子数据对象
{
// Process embedded references
if(SUCCEEDED(pSubObj->QueryInterface(//检查枚举出来的对象是否实例化
IID_IDirectXFileDataReference,// 查看其是否为引用数据对象
(void**)&pDataRef))) {
// Resolve the data object
if(SUCCEEDED(pDataRef->Resolve(&pSubData))) {//如果是引用数据对象,先解决它,至于如何解决不得而知,可能将数据进行拷贝
// Parse the object, remembering the return code
ParseResult = ParseObject(pSubData, pDataObj, //解析子对象
Depth+1, Data, TRUE);
XPReleaseCOM(pSubData);
}
XPReleaseCOM(pDataRef);
// Return on parsing failure
if(ParseResult == FALSE)
return FALSE;
} else
// Process non-referenced embedded templates
if(SUCCEEDED(pSubObj->QueryInterface( // 查看是否为实例对象
IID_IDirectXFileData, \
(void**)&pSubData))) {
// Parse the object, remembering the return code
ParseResult = ParseObject(pSubData, pDataObj, \
Depth+1, Data, \
ForceReference);
XPReleaseCOM(pSubData);
}
// Release the data object
XPReleaseCOM(pSubObj);
// Return on parsing failure
if(ParseResult == FALSE)
return FALSE;
}
return TRUE;
}
const GUID *cXParser::GetObjectGUID( \
IDirectXFileData *pDataObj)
{
const GUID *Type = NULL;
// Error checking
if(pDataObj == NULL)
return NULL;
// Get the template type
if(FAILED(pDataObj->GetType(&Type)))
return NULL;
return Type;
}
char *cXParser::GetObjectName(IDirectXFileData *pDataObj)
{
char *Name = NULL;
DWORD Size = 0;
// Error checking
if(pDataObj == NULL)
return NULL;
// Get the template name (if any)
if(FAILED(pDataObj->GetName(NULL, &Size)))
return NULL;
// Allocate a name buffer and retrieve name
if(Size) {
if((Name = new char[Size]) != NULL)
pDataObj->GetName(Name, &Size);
}
return Name;
}
void *cXParser::GetObjectData( //获取数据指针,在9.0c下,用lock即可
IDirectXFileData *pDataObj, \
DWORD *Size)
{
void *TemplateData = NULL;
DWORD TemplateSize = 0;
// Error checking
if(pDataObj == NULL)
return NULL;
// Get a data pointer to template
pDataObj->GetData(NULL,&TemplateSize,(PVOID*)&TemplateData);
// Save size if needed
if(Size != NULL)
*Size = TemplateSize;
return TemplateData;
}
修正后的XParser.cpp:
#include "XParser.h"
BOOL cXParser::Parse(char *Filename, void **Data)
{
ID3DXFile *pDXFile = NULL;
ID3DXFileEnumObject *pDXEnum = NULL;
ID3DXFileData *pDXData = NULL;
// Error checking
if(Filename == NULL)
return FALSE;
// Create the file object
if(FAILED(D3DXFileCreate(&pDXFile)))
return FALSE;
// Register the common templates
if(FAILED(pDXFile->RegisterTemplates( \
(LPVOID)D3DRM_XTEMPLATES, \
D3DRM_XTEMPLATE_BYTES))) {
pDXFile->Release();
return FALSE;
}
// Create an enumeration object
if(FAILED(pDXFile->CreateEnumObject((LPVOID)Filename, \
DXFILELOAD_FROMFILE, \
&pDXEnum))) {
pDXFile->Release();
return FALSE;
}
// Call the begin parse function, continuing if allowed
if(BeginParse(Data) == TRUE) {
Loop through all top-level objects, breaking on errors
//BOOL ParseResult;
//while(SUCCEEDED(pDXEnum->GetNextDataObject(&pDXData))) {
// ParseResult = ParseObject(pDXData, NULL, 0, Data, FALSE);
// XPReleaseCOM(pDXData);
// if(ParseResult == FALSE)
// break;
//}
SIZE_T num_child;
pDXEnum->GetChildren(&num_child);
BOOL ParseResult;
for(SIZE_T i = 0; i < num_child; i++)
{
if(FAILED(pDXEnum->GetChild(i, &pDXData)))
return NULL;
ParseResult = ParseObject(pDXData, NULL,0,Data,FALSE);
XPReleaseCOM(pDXData);
if(ParseResult == FALSE)
break;
}
}
// Call end parse function
EndParse(Data);
// Release used COM objects
XPReleaseCOM(pDXEnum);
XPReleaseCOM(pDXFile);
return TRUE;
}
BOOL cXParser::ParseChildObjects( \
ID3DXFileData *pDataObj, \
DWORD Depth, void **Data, \
BOOL ForceReference)
{
ID3DXFileData *pSubObj = NULL;//用于存放子数据对象
SIZE_T num_child; //
BOOL ParseResult = TRUE;
pDataObj->GetChildren(&num_child);//取子对象个数
for(SIZE_T j = 0; j < num_child; j++) //按索引一一取出子对象,并解析
{
pDataObj->GetChild(j, &pSubObj); //取出索引为i的子对象
if(pSubObj->IsReference()){//这个判断是绝对要的,否则假如你自己直接用
//ParseObject(pSubObj,pDataObj,Depth+1, Data,pSubObj->IsReference());
//会有意想不到的结果,我调试了两天,在各大论坛都没找见,至于为什么,我也在发问,那位知道的告我一声
//QQ群在上面,或者帮我到gamedev发问,我英语不太好
ForceReference = true;//假如是引用那么将引用标记设为true,否则直接传到下游解析
}
ParseResult = ParseObject(pSubObj,pDataObj,Depth+1, Data,ForceReference);
XPReleaseCOM(pSubObj);
// Return on parsing failure
if(ParseResult == FALSE)
return FALSE;
}
//ID3DXFileData *pSubObj = NULL;
//ID3DXFileData *pSubData = NULL;
//IDirectXFileDataReference *pDataRef = NULL;
//BOOL ParseResult = TRUE;
Scan for embedded templates
//while(SUCCEEDED(pDataObj->GetNextObject(&pSubObj))) {
// // Process embedded references
// if(SUCCEEDED(pSubObj->QueryInterface( \
// IID_IDirectXFileDataReference, \
// (void**)&pDataRef))) {
// // Resolve the data object
// if(SUCCEEDED(pDataRef->Resolve(&pSubData))) {
// // Parse the object, remembering the return code
// ParseResult = ParseObject(pSubData, pDataObj, \
// Depth+1, Data, TRUE);
// XPReleaseCOM(pSubData);
// }
// XPReleaseCOM(pDataRef);
// // Return on parsing failure
// if(ParseResult == FALSE)
// return FALSE;
// } else
// // Process non-referenced embedded templates
// if(SUCCEEDED(pSubObj->QueryInterface( \
// IID_IDirectXFileData, \
// (void**)&pSubData))) {
// // Parse the object, remembering the return code
// ParseResult = ParseObject(pSubData, pDataObj, \
// Depth+1, Data, \
// ForceReference);
// XPReleaseCOM(pSubData);
// }
// // Release the data object
// XPReleaseCOM(pSubObj);
// // Return on parsing failure
// if(ParseResult == FALSE)
// return FALSE;
//}
return TRUE;
}
const GUID *cXParser::GetObjectGUID( //查看在sdk中的 windows_graphics.chm这个API文档,里面有函数的详解
ID3DXFileData *pDataObj)
{
GUID* Type = new GUID;
// Error checking
if(pDataObj == NULL)
return NULL;
// Get the template type
if(FAILED(pDataObj->GetType(Type)))//新版取GUID函数,注意,这里Type是new出来的,那么假如你用完,你可以在用完后直接释放,切记不要造成内存泄漏,而且此函数参数的数据类型和旧版取GUID不同了
return NULL;
return Type;
}
char *cXParser::GetObjectName(ID3DXFileData *pDataObj)
{
char *Name = NULL;
DWORD Size = 0;
// Error checking
if(pDataObj == NULL)
return NULL;
// Get the template name (if any)
if(FAILED(pDataObj->GetName(NULL, &Size)))//获取名字的长度
return NULL;
// Allocate a name buffer and retrieve name
if(Size) {
if((Name = new char[Size]) != NULL)
pDataObj->GetName(Name, &Size);//获取名字,这里也有new,不过好像不会造成内存泄漏,好像在哪个析构函数里有释放名字的,应该是在frame_EX和container_EX里面,就是两个扩展结构里,不过我乱说的,你自己有必要去看看,我太懒了
}
return Name;
}
void *cXParser::GetObjectData( \
ID3DXFileData *pDataObj, \
DWORD *Size)
{
void *TemplateData;
SIZE_T TemplateSize=0;;
// Error checking
if(pDataObj == NULL)
return NULL;
// Get a data pointer to template
pDataObj->Lock(&TemplateSize,(LPCVOID*)(VOID **)&TemplateData);//取数据,这里有个很奇怪的现象,加完锁之后应该在用完之前在解锁,但可惜,这里就已经解锁了,不知是何原因,难道,只要在取数据指针时才要保证安全性,我感觉不可能,这里很有可能是为了和本书兼容
if (NULL==TemplateData)
{
return NULL;
}
// Save size if needed
if(Size != NULL)
*Size = TemplateSize;
pDataObj->Unlock();
return TemplateData;
}
好了头文件自己改了,还有就是Direct3D.h里的内置对象要修改一下,你可以用它直接继承XParser即可,只修改一部分部件即可。