在《Advanced Animation with DirectX》由于SDK升级带来的麻烦,与代码修正

    写过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即可,只修改一部分部件即可。

你可能感兴趣的:(3D游戏菜鸟之路)