D3D中.X文件的解析

一个完整的.X文件类似这样的结构:
xof 0303txt 0032
//定义模板
template FVFData {
 <b6e70a0e-8ef9-4e83-94ad-ecc8b0c04897>
 DWORD dwFVF;
 DWORD nDWords;
 array DWORD data[nDWords];
}

template EffectInstance {
 <e331f7e4-0559-4cc2-8e99-1cec1657928f>
 STRING EffectFilename;
 [...]
}

template EffectParamFloats {
 <3014b9a0-62f5-478c-9b86-e4ac9f4e418b>
 STRING ParamName;
 DWORD  nFloats;
 array  FLOAT Floats[nFloats];
}

template EffectParamString {
 <1dbc4c88-94c1-46ee-9076-2c28818c9481>
 STRING ParamName;
 STRING Value;
}

template EffectParamDWord {
 <e13963bc-ae51-4c5d-b00f-cfa3a9d97ce5>
 STRING ParamName;
 DWORD Value;
}

//主框架
Frame BoxFrame{
 
 FrameTransformMatrix {
  1.000000,0.000000,0.000000,0.000000,0.000000,1.000000,0.000000,0.000000,0.000000,0.000000,1.000000,0.000000,-22.441198,0.000000,-15.434750,1.000000;;
 }

//Mesh对象
 Mesh  {
  20;
  -28.216623;0.000000;-55.879185;,
  28.216623;0.000000;-55.879185;,
  -28.216623;0.000000;55.879185;,
  28.216623;0.000000;55.879185;,
  -28.216623;54.767735;-55.879185;,
  28.216623;54.767735;-55.879185;,
  -28.216623;54.767735;55.879185;,
  28.216623;54.767735;55.879185;,
  -28.216623;0.000000;-55.879185;,
  28.216623;54.767735;-55.879185;,
  28.216623;0.000000;-55.879185;,
  -28.216623;54.767735;-55.879185;,
  28.216623;0.000000;55.879185;,
  28.216623;54.767735;-55.879185;,
  28.216623;0.000000;55.879185;,
  -28.216623;54.767735;55.879185;,
  -28.216623;0.000000;55.879185;,
  28.216623;54.767735;55.879185;,
  -28.216623;0.000000;55.879185;,
  -28.216623;54.767735;-55.879185;;
  12;
  3;0,3,2;,
  3;3,0,1;,
  3;4,7,5;,
  3;7,4,6;,
  3;8,9,10;,
  3;9,8,11;,
  3;1,7,12;,
  3;7,1,13;,
  3;14,15,16;,
  3;15,14,17;,
  3;18,19,0;,
  3;19,18,6;;

  MeshNormals  {
   6;
   0.000000;-1.000000;0.000000;,
   0.000000;1.000000;0.000000;,
   0.000000;0.000000;-1.000000;,
   1.000000;0.000000;0.000000;,
   0.000000;0.000000;1.000000;,
   -1.000000;0.000000;0.000000;;
   12;
   3;0,0,0;,
   3;0,0,0;,
   3;1,1,1;,
   3;1,1,1;,
   3;2,2,2;,
   3;2,2,2;,
   3;3,3,3;,
   3;3,3,3;,
   3;4,4,4;,
   3;4,4,4;,
   3;5,5,5;,
   3;5,5,5;;
  }

  MeshMaterialList  {
   1;
   12;
   0,
   0,
   0,
   0,
   0,
   0,
   0,
   0,
   0,
   0,
   0,
   0;

   Material {
    0.341176;0.878431;0.560784;1.000000;;
    0.000000;
    0.341176;0.878431;0.560784;;
    0.000000;0.000000;0.000000;;
   }
  }

  MeshTextureCoords  {
   20;
   1.000000;1.000000;,
   0.000000;1.000000;,
   1.000000;0.000000;,
   0.000000;0.000000;,
   0.000000;1.000000;,
   1.000000;1.000000;,
   0.000000;0.000000;,
   1.000000;0.000000;,
   0.000000;1.000000;,
   1.000000;0.000000;,
   1.000000;1.000000;,
   0.000000;0.000000;,
   1.000000;1.000000;,
   0.000000;0.000000;,
   0.000000;1.000000;,
   1.000000;0.000000;,
   1.000000;1.000000;,
   0.000000;0.000000;,
   0.000000;1.000000;,
   1.000000;0.000000;;
  }

EffectInstance  tt{
 "fdsfds";
}
 }
}
1.其中的xof 0303txt 0032解释为:xof表示这是一个真正的X文件。0303txt表示通知程序使用Directx的X文件,版本为3.3的模版,其中txt表示此文件为文本文件,可读,并非是一个2进制文件。0032表示一个浮点数的位数为32,如果想要用64位的浮点数,可以写成0064。
2.模板的声明有三种类型:
template ClosedTemplate {
<4C9D055B-C64D-4bfe-A7D9-981F507E45FF>
DWORD ClosedData;
}
template OpenTemplate {
<4C9D055B-C64D-4bff-A7D9-981F507E45FF>
DWORD OpenData;
[...]
}
template RestrictedTemplate {
<4C9D055B-C64D-4c00-A7D9-981F507E45FF>
DWORD RestrictedData;
[ClosedTemplate]
[OpenTemplate]
}
ClosedTemplate是标准的模版声明。
OpenTemplate中包含一个[...],表示这是一个开放模版。开放模版允许在[]中内嵌任何数据对象。例如
,你可以实例化OpenTemplate,在里面定义一个OpenData变量和内嵌一个ClosedTemplate的实例。
RestrictedTemplate为约束模版。约束模版实例化时只允许包含它列出的数据对象,如,不能在
RestrictedTemplate包含[ClosedTemplate],[OpenTemplate]以外的数据对象。
3.访问.X文件:
访问任何X文件首先要调用DirectXFileCreate函数创建一个IDirectXFile接口。
IDirectXFile *pDXFile = NULL;
HRESULT Result = DirectXFileCreate(&pDXFile);//用&pDXFile返回指向接口的指针。用SUCCEEDED或者
FAILED宏判断返回值是否有效。
4.注册一个定制或者标准模版:
你可以把X文件中的模版移除,直接在代码里定义那些模版。IDirectXFile接口支持这样的特性。需要调用IDirectXfile::RegisterTemplates函数。
HRESULT IDirectXfile::RegisterTemplates(
LPVOID pvData,         // 一个定义模版数据的缓存,应该精确无误。
DWORD cbSize);         // pvData缓存的字节数。
可以如下定义一个模版数据的缓存:
char *Templates = "
"xof 0303txt 0032 /  //标准X文件头。
template CustomTemplate { <4c944580-9e9a-11cf-ab43-0120af71e433> DWORD Length; array DWORD values[Length]; }";
之后再用RegisterTemplates将其注册:
pFile->RegisterTemplates(Templates, strlen(Templates));
注册标准模版:
首先需要在代码中包含rmxfguid.h和rmxftmpl.h。rmxfguid.h定义了各个标准模版的GUDI,rmxftmpl.h以
2进制数据形式定义了标准模版数据的缓存和其字节数。然后调用RegisterTemplates将其注册:
pFile->RegisterTemplates(D3DRM_XTEMPLATES, D3DRM_XTEMPLATE_BYTES);
5.打开X文件:
创建完IDirectXFile接口,注册模版之后需要打开X文件,枚举其数据对象。调用
IDirectXfile::CreateEnumObject函数。
HRESULT IDirectXfile::CreateEnumObject(LPVOID pvSource, // .X filename
DXFILELOADOPTIONS dwLoadOptions,                         // Load options
LPDIRECTXFILEENUMOBJECT* ppEnumObj);                     // Enum interface
当调用CreateEnumObject函数,用pvSource指定一个文件的名字,用ppEnumObj返回一个枚举对象接口指
针。用dwLoadOptions指定load操作方式。当指定DXFILELOAD_FROMFILE值,告诉DirectX从磁盘载入一个
文件。还有DXFILELOAD_FROMRESOURCE,DXFILELOAD_FROMMEMORY和DXFILELOAD_FROMURL分别表示从一个资
源,内存缓冲和Internet上加载X文件。当从Internet加载文件时,需要为其指定完整的网址。
下面代码从磁盘加载X文件:
strcpy(Filename,"test.x");
IDirectXFileEnumObject *pEnum;
pFile->CreateEnumObject((LPVOID)Filename, DXFILELOAD_FROMFILE, &pEnum);
Filename指向一个有效的文件名,pEnum返回一个枚举对象接口指针。
6.枚举数据对象:
注册完模版,打开X文件并且得到一个枚举对象接口,下面需要从X文件读出数据。枚举对象接口指针指向
文件的第一个数据对象,因为每一个数据对象可能包含内嵌数据对象或者引用的数据对象,所以与第一个
数据对象同在一层级的其它数据对象为同层级数据对象。至于包含的子数据对象的类型,需要对其分别的
行进询问。
可以用 HRESULT IDirectXFileEnumObject::GetNextDataObject(LPDIRECTXFILEDATA*ppDataObj)得到一
个IDirectXFileData接口。它只有一个参数,如下:
IDirectXFileData *pData;
HRESULT hr = pEnum->GetNextDataObject(&pData);
利用此函数,可以不断地访问同一层级的数据对象接口,具体代码如下:
while(SUCCEEDED(pEnum->GetNextDataObject(&pData))) {
// 这里可以对pData数据对象进行操作。
ParseResult = ParseXFileData(m_pDXData); //ParseXFileData为解析函数
pData->Release();//释放接口。
}
当返回值为FAILED,表示已经访问完所有的接口。当访问值为SUCCEEDED,你需要继续判断这个数据对象
7.解析函数:
判断数据对象是否包含子对象。利用接口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数据对象进行操作
ParseXFileData(pSubData);
pSubData->Release();//释放接口。
}

看其是否为引用数据对象:
IDirectXFileDataReference *pRef;
IDirectXFileData *pSubData;
if(SUCCEEDED(pSubObj->QueryInterface( IID_IDirectXFileDataReference, (void**)&pRef))) {
// 如果询问引用的数据对象成功,解析出引用的原型。
pRef->Resolve(&pSubData);
//这里可以对pData数据对象进行操作。
ParseXFileData(pSubData);
pRef->Release();
pSubData->Release();//释放接口。
}
现在总结下整体思路:大体的思路其实很简单,首先枚举最顶层的数据对象,然后判断其是否有子对象,这个子对象可能是内嵌对象或者引用对象二者之一,分别询问其接口,就可以判断出具体的类型。

阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭