HRESULT CXMesh::LoadFromXData(char* Filename, LPDIRECTXFILEDATA XObj)
{
	HRESULT res = S_OK;

	CBRenderD3D* Rend = (CBRenderD3D*)Game->m_Renderer;

	// get name
	res = CXModel::LoadName(this, XObj);
	if(FAILED(res))
	{
		Game->LOG(res, "Error loading mesh name");
		return res;
	}

	// load mesh
	LPD3DXBUFFER BufMaterials = NULL;
	LPD3DXBUFFER BufAdjacency = NULL;
	LPD3DXBUFFER BufBoneOffset = NULL;
	UINT NumFaces;

	DWORD NumMaterials;

#ifdef WME_D3D9
	LPD3DXMESH Mesh;
	LPD3DXSKININFO SkinInfo;

	res = D3DXLoadSkinMeshFromXof(XObj, D3DXMESH_MANAGED, Rend->m_Device, &BufAdjacency, 
		&BufMaterials, NULL, &NumMaterials, &SkinInfo, &Mesh);
	
	if(SUCCEEDED(res)) m_SkinMesh = new CSkinMeshHelper(Mesh, SkinInfo);
#else	
	LPD3DXBUFFER BufBoneNames = NULL;
	LPD3DXSKINMESH SkinMesh;
	res = D3DXLoadSkinMeshFromXof(XObj, D3DXMESH_MANAGED, Rend->m_Device, &BufAdjacency, 
		&BufMaterials, &NumMaterials, &BufBoneNames, &BufBoneOffset, &SkinMesh);
	
	if(SUCCEEDED(res)) m_SkinMesh = new CSkinMeshHelper(SkinMesh, BufBoneOffset, BufBoneNames);
#endif


	if(FAILED(res))
	{
		Game->LOG(res, "Error loading skin mesh");
		return res;
	}

	NumFaces = m_SkinMesh->GetNumFaces();


	DWORD NumBones = m_SkinMesh->GetNumBones();

	// Process skinning data
	if(NumBones)
	{
		// bones are available
		m_BoneMatrices = new D3DXMATRIX*[NumBones];

		DWORD* Adjacency = (DWORD*)(BufAdjacency->GetBufferPointer());
		m_SkinAdjacency = new DWORD[NumFaces * 3];
		memcpy(m_SkinAdjacency, Adjacency, NumFaces * 3 * sizeof(DWORD));

		GenerateMesh();
	}
	else
	{
		// no bones are found, blend the mesh and use it as a static mesh
		m_SkinMesh->GetOriginalMesh(&m_StaticMesh);
		m_StaticMesh->CloneMeshFVF(m_StaticMesh->GetOptions(), m_StaticMesh->GetFVF(), Rend->m_Device, &m_BlendedMesh);

		SAFE_DELETE(m_SkinMesh);
		m_NumAttrs = NumMaterials;

		if(m_BlendedMesh)
		{
			NumFaces = m_BlendedMesh->GetNumFaces();
			m_Adjacency = new DWORD[NumFaces * 3];
			m_BlendedMesh->GenerateAdjacency(0, m_Adjacency);
		}
	}


	// check for materials
	if((BufMaterials == NULL) || (NumMaterials == 0))
	{
		// no materials are found, create default material
		C3DMaterial* Mat = new C3DMaterial(Game);
		Mat->m_Material.Diffuse.r = 0.5f;
		Mat->m_Material.Diffuse.g = 0.5f;
		Mat->m_Material.Diffuse.b = 0.5f;
		Mat->m_Material.Specular = Mat->m_Material.Diffuse;
		Mat->m_Material.Ambient = Mat->m_Material.Diffuse;

		m_Materials.Add(Mat);

		m_NumAttrs = 1;
	}
	else
	{
		// texture relative path base
		char PathTemp[MAX_PATH+1];
		int PathLength;
		for (PathLength = strlen(Filename); PathLength--;)
		{
			if(Filename[PathLength] == '/' || Filename[PathLength] == '\\' )
			{
				PathLength++;
				break;
			}
		}
		strncpy(PathTemp, Filename, PathLength);


		// load the materials
		D3DXMATERIAL* FileMats = (D3DXMATERIAL*)BufMaterials->GetBufferPointer();
		for(int i = 0; i < (int)NumMaterials; i++)
		{
			C3DMaterial* Mat = new C3DMaterial(Game);
			Mat->m_Material = FileMats[i].MatD3D;
			Mat->m_Material.Ambient = Mat->m_Material.Diffuse;
						
			if(FileMats[i].pTextureFilename != NULL)
			{
				strcpy(PathTemp + PathLength, FileMats[i].pTextureFilename);
				Mat->SetTexture(PathTemp, true);
			}

			m_Materials.Add(Mat);
		}
		m_NumAttrs = m_Materials.GetSize();
	}

	RELEASE(BufAdjacency);
	RELEASE(BufMaterials);
	RELEASE(BufBoneOffset);

	return S_OK;
}
void cMesh::ParseXFileData(ID3DXFileData *pDataObj, sFrame *ParentFrame, char *TexturePath)
{
  ID3DXFileData *pSubObj  = NULL;
  ID3DXFileData *pSubData = NULL;
  IDirectXFileDataReference *pDataRef = NULL;
  GUID Type = GUID_NULL;
  char       *Name = NULL;
  DWORD       Size;
  sFrame     *SubFrame = NULL;
  char        Path[MAX_PATH];

  sFrame     *Frame = NULL;
  //D3DXMATRIX *FrameMatrix = NULL;

  sMesh         *Mesh = NULL;
  ID3DXBuffer   *MaterialBuffer = NULL;
  D3DXMATERIAL  *Materials = NULL;
  ID3DXBuffer   *Adjacency = NULL;
  DWORD         *AdjacencyIn = NULL;
  DWORD         *AdjacencyOut = NULL;

  DWORD i;
  BYTE  **Ptr;

  // Get the template type
  if(FAILED(pDataObj->GetType((&Type))))
    return;

  // Get the template name (if any)
  if(FAILED(pDataObj->GetName(NULL, &Size)))
    return;
  if(Size) {
    if((Name = new char[Size]) != NULL)
      pDataObj->GetName(Name, &Size);
  }

  // Give template a default name if none found
  if(Name == NULL) {
    if((Name = new char[9]) == NULL)
      return;
    strcpy(Name, "$NoName$");
  }

  // Set sub frame
  SubFrame = ParentFrame;

  // Process the templates

  // Frame
  if(IsEqualGUID(Type, TID_D3DRMFrame)) {
    // Create a new frame structure
    Frame = new sFrame();

    // Store the name
    Frame->m_Name = Name;
    Name = NULL;

    // Add to parent frame
    Frame->m_Parent = ParentFrame;
    Frame->m_Sibling = ParentFrame->m_Child;
    ParentFrame->m_Child = Frame;

    // Increase frame count
    m_NumFrames++;

    // Set sub frame parent
    SubFrame = Frame;
  }

  // Frame transformation matrix
  if(Type == TID_D3DRMFrameTransformMatrix) {
	BYTE** DataPtr = NULL;

    if(FAILED(pDataObj->Lock(&Size, (LPCVOID*)&DataPtr)))
      return;

	memcpy(&ParentFrame->m_matOriginal, (void*)DataPtr, Size);
	pDataObj->Unlock();
  }

  // Mesh
  if(Type == TID_D3DRMMesh) {

    // See if mesh already loaded
    if(m_Meshes == NULL || m_Meshes->FindMesh(Name) == NULL) {

      // Create a new mesh structure
      Mesh = new sMesh();

      // Store the name
      Mesh->m_Name = Name;
      Name = NULL;

      // Load mesh data
      if(FAILED(D3DXLoadSkinMeshFromXof(pDataObj, 0,
                  m_Graphics->GetDeviceCOM(), 
                  &Adjacency,
                  &MaterialBuffer, NULL, &Mesh->m_NumMaterials,
                  &Mesh->m_SkinInfo, 
                  &Mesh->m_Mesh))) {
        delete Mesh;
        return;
      }

      // Calculate the bounding box and sphere
      if(SUCCEEDED(Mesh->m_Mesh->LockVertexBuffer(D3DLOCK_READONLY, (void**)&Ptr))) {
        D3DXComputeBoundingBox((D3DXVECTOR3*)Ptr, Mesh->m_Mesh->GetNumVertices(), 
                                Mesh->m_Mesh->GetNumBytesPerVertex(), &Mesh->m_Min, &Mesh->m_Max);

        D3DXComputeBoundingSphere((D3DXVECTOR3*)Ptr, Mesh->m_Mesh->GetNumVertices(), 
                                Mesh->m_Mesh->GetNumBytesPerVertex(),
                                &D3DXVECTOR3(0.0f,0.0f,0.0f), &Mesh->m_Radius);

        Mesh->m_Mesh->UnlockVertexBuffer();
      }

      // Store # of bones (if any)
      if(Mesh->m_SkinInfo)
        Mesh->m_NumBones = Mesh->m_SkinInfo->GetNumBones();

      // Create a matching skinned mesh if bone exist
      if(Mesh->m_SkinInfo != NULL && Mesh->m_NumBones != 0) {
        if(FAILED(Mesh->m_Mesh->CloneMeshFVF(0, Mesh->m_Mesh->GetFVF(),
                  m_Graphics->GetDeviceCOM(), &Mesh->m_SkinMesh)))
          ReleaseCOM(Mesh->m_SkinInfo);
      }

      // Create an array of matrices to store bone transformations
      if(Mesh->m_SkinInfo != NULL && Mesh->m_NumBones != 0) {
       
       // Create the bone matrix array and clear it out
        Mesh->m_Matrices = new D3DXMATRIX[Mesh->m_NumBones];
        for(i=0;i<Mesh->m_NumBones;i++)
          D3DXMatrixIdentity(&Mesh->m_Matrices[i]);

        // Create the frame mapping matrix array and clear out
        Mesh->m_FrameMatrices = new D3DXMATRIX*[Mesh->m_NumBones];
        for(i=0;i<Mesh->m_NumBones;i++)
          Mesh->m_FrameMatrices[i] = NULL;
      }

      // Load materials or create a default one if none
      if(!Mesh->m_NumMaterials) {
        // Create a default one
        Mesh->m_Materials = new D3DMATERIAL9[1];
        Mesh->m_Textures  = new LPDIRECT3DTEXTURE9[1];

        ZeroMemory(Mesh->m_Materials, sizeof(D3DMATERIAL9));
        Mesh->m_Materials[0].Diffuse.r = 1.0f;
        Mesh->m_Materials[0].Diffuse.g = 1.0f;
        Mesh->m_Materials[0].Diffuse.b = 1.0f;
        Mesh->m_Materials[0].Diffuse.a = 1.0f;
        Mesh->m_Materials[0].Ambient   = Mesh->m_Materials[0].Diffuse;
        Mesh->m_Materials[0].Specular  = Mesh->m_Materials[0].Diffuse;
        Mesh->m_Textures[0] = NULL;

        Mesh->m_NumMaterials = 1;
      } else {
        // Load the materials
        Materials = (D3DXMATERIAL*)MaterialBuffer->GetBufferPointer();
        Mesh->m_Materials = new D3DMATERIAL9[Mesh->m_NumMaterials];
        Mesh->m_Textures  = new LPDIRECT3DTEXTURE9[Mesh->m_NumMaterials];

        for(i=0;i<Mesh->m_NumMaterials;i++) {
          Mesh->m_Materials[i] = Materials[i].MatD3D;
          Mesh->m_Materials[i].Ambient = Mesh->m_Materials[i].Diffuse;
       
          // Build a texture path and load it
          sprintf(Path, "%s%s", TexturePath, Materials[i].pTextureFilename);
          if(FAILED(D3DXCreateTextureFromFile(m_Graphics->GetDeviceCOM(),
                                              Path,
                                              &Mesh->m_Textures[i]))) {
            Mesh->m_Textures[i] = NULL;
          }
        }
      }
      ReleaseCOM(MaterialBuffer);

      // link in mesh
      Mesh->m_Next = m_Meshes;
      m_Meshes = Mesh;
      m_NumMeshes++;
    } else {
      // Find mesh in list
      Mesh = m_Meshes->FindMesh(Name);
    }

    // Add mesh to frame 
    if(Mesh != NULL)
      ParentFrame->AddMesh(Mesh);
  }

  // Skip animation sets and animations
  if(Type == TID_D3DRMAnimationSet || Type == TID_D3DRMAnimation || Type == TID_D3DRMAnimationKey) {
    delete [] Name;
    return;
  }

  // Release name buffer
  delete [] Name;

  SIZE_T count;
  if (FAILED(pDataObj->GetChildren(&count)))
	  return;

  SIZE_T c = 0;

  // Scan for embedded templates
  while(c < count) {
	if (FAILED(pDataObj->GetChild(c, &pSubObj)))
		break;
	c++;

    // Process embedded references
	if (pSubObj->IsReference())
	{
		if (SUCCEEDED(pSubObj->GetChild(0, &pSubData)))
		{
			ParseXFileData(pSubData, SubFrame, TexturePath);
			ReleaseCOM(pSubData);
		}
	}
    /*if(SUCCEEDED(pSubObj->QueryInterface(IID_IDirectXFileDataReference, (void**)&pDataRef))) {
      if(SUCCEEDED(pDataRef->Resolve(&pSubData))) {
        ParseXFileData(pSubData, SubFrame, TexturePath);
        ReleaseCOM(pSubData);
      }
      ReleaseCOM(pDataRef);
    }*/

    // Process non-referenced embedded templates
    if(SUCCEEDED(pSubObj->QueryInterface(IID_ID3DXFileData, (void**)&pSubData))) {
      ParseXFileData(pSubData, SubFrame, TexturePath);
      ReleaseCOM(pSubData);
    }
    ReleaseCOM(pSubObj);
  }

  return;
}