#include "mesh.h"
#include "dxmaterial.h"

#include <sys/stat.h> //fstat stuff

CShadowVolume::CShadowVolume(void)
{
	m_pVertices = new DXVector3[MAXSVVERTICE];
	m_dwNumVertices=0;
}

CShadowVolume::~CShadowVolume(void)
{
	if(m_pVertices)
		delete [] m_pVertices;
}

HRESULT CShadowVolume::Render( DeviceStateManager*device )
{
	if(!m_dwNumVertices)
		return S_OK;

    device->SetFVF( D3DFVF_XYZ );
	
	device->DrawPrimitiveUP( PT_TRIANGLELIST, m_dwNumVertices/3,m_pVertices, sizeof(DXVector3) );

	return S_OK;
}

void CShadowVolume::AddEdge( WORD* pEdges, DWORD& dwNumEdges, WORD v0, WORD v1 )
{
    // Remove interior edges (which appear in the list twice)
    for( DWORD i=0; i < dwNumEdges; i++ )
    {
        if( ( pEdges[2*i+0] == v0 && pEdges[2*i+1] == v1 ) ||
            ( pEdges[2*i+0] == v1 && pEdges[2*i+1] == v0 ) )
        {
            if( dwNumEdges > 1 )
            {
                pEdges[2*i+0] = pEdges[2*(dwNumEdges-1)+0];
                pEdges[2*i+1] = pEdges[2*(dwNumEdges-1)+1];
            }
            dwNumEdges--;
            return;
        }
    }

    pEdges[2*dwNumEdges+0] = v0;
    pEdges[2*dwNumEdges+1] = v1;
    dwNumEdges++;
}

void CShadowVolume::Clear(void)
{
	m_dwNumVertices = 0;
}

HRESULT CShadowVolume::BuildFromMesh( LPD3DXMESH pMesh, DXVector3 vLight ,bool self)
{
	Clear();

	if(!pMesh)
		return E_FAIL;

    // Note: the MESHVERTEX format depends on the FVF of the mesh
    struct MESHVERTEX { DXVector3 p; DXVector3 n; float  tu;float  tv;};

    MESHVERTEX* pVertices;
    WORD*       pIndices;

    // Lock the geometry buffers
    pMesh->LockVertexBuffer( 0L, (LPVOID*)&pVertices );
    pMesh->LockIndexBuffer( 0L, (LPVOID*)&pIndices );
    DWORD dwNumFaces    = pMesh->GetNumFaces();

    // Allocate a temporary edge list
    WORD* pEdges = new WORD[dwNumFaces*6];
    if( pEdges == NULL )
    {
        pMesh->UnlockVertexBuffer();
        pMesh->UnlockIndexBuffer();
        return E_OUTOFMEMORY;
    }
    DWORD dwNumEdges = 0;
    // For each face
    for( DWORD i=0; i<dwNumFaces; i++ )
    {
        WORD wFace0 = pIndices[3*i+0];
        WORD wFace1 = pIndices[3*i+1];
        WORD wFace2 = pIndices[3*i+2];

        DXVector3 v0 = pVertices[wFace0].p;
        DXVector3 v1 = pVertices[wFace1].p;
        DXVector3 v2 = pVertices[wFace2].p;

        // Transform vertices or transform light?
        DXVector3 vCross1(v2-v1);
        DXVector3 vCross2(v1-v0);
        DXVector3 vNormal;
        D3DXVec3Cross(vNormal, vCross1, vCross2 );

		if( D3DXVec3Dot(vNormal, vLight ) <= 0.0f )
        //if( D3DXVec3Dot( &vNormal, &vLight ) >= 0.0f )
        {
		/*	if(self)
			{
				m_pVertices[m_dwNumVertices++] = v0;
				m_pVertices[m_dwNumVertices++] = v2;
				m_pVertices[m_dwNumVertices++] = v1;
			}*/
            AddEdge( pEdges, dwNumEdges, wFace0, wFace1 );
            AddEdge( pEdges, dwNumEdges, wFace1, wFace2 );
            AddEdge( pEdges, dwNumEdges, wFace2, wFace0 );
        }
    }

    for(DWORD i=0; i<dwNumEdges; i++ )
    {
        DXVector3 v1 = pVertices[pEdges[2*i+0]].p;
        DXVector3 v2 = pVertices[pEdges[2*i+1]].p;
        DXVector3 v3 = (v1 - vLight)/100;
        DXVector3 v4 = (v2 - vLight)/100;

        // Add a quad (two triangles) to the vertex list
        m_pVertices[m_dwNumVertices++] = v1;
        m_pVertices[m_dwNumVertices++] = v2;
        m_pVertices[m_dwNumVertices++] = v3;

        m_pVertices[m_dwNumVertices++] = v2;
        m_pVertices[m_dwNumVertices++] = v4;
        m_pVertices[m_dwNumVertices++] = v3;
    }
    // Delete the temporary edge list
    delete[] pEdges;

    // Unlock the geometry buffers
    pMesh->UnlockVertexBuffer();
    pMesh->UnlockIndexBuffer();

    return S_OK;
}

//CMesh::CMesh(void)
//{
//	m_Device = NULL;
//	m_pMesh=NULL;
////	m_pSysMesh=NULL;		
//	m_dwNumMaterials=NULL;
//
//	m_bInvalidated=TRUE;
//}

CMesh::~CMesh(void)
{
	InvalidateDeviceObjects();

	delete [] m_Materials;

	SAFERELEASE(m_VB);
	SAFERELEASE(m_IB);
	SAFERELEASE(m_pMesh);

	delete [] m_pDrawCalls;

	delete m_VDecl;

	delete [] m_pAttributeTable;
}

LPD3DXMESH CMesh::GetMesh(void)
{
	return m_pMesh;
}

static const int g_CMeshRBFV = 10; //CMesh raw binary file version

CMesh::CMesh(DeviceStateManager*device,XString FileName,XString Path)
{
	m_Device = device;
	m_pMesh=NULL;
//	m_pSysMesh=NULL;		
	m_dwNumMaterials=NULL;
//    m_pMaterials=NULL;
//    m_pTextures=NULL;
	m_strFileName=FileName;
	m_strPath=Path;
	m_bUseMaterials=TRUE;
	m_bInvalidated=TRUE;
	m_Materials = NULL;
	m_pAttributeTable = NULL;
	m_VDecl = NULL;
	m_VB = NULL;
	m_IB = NULL;
	m_pDrawCalls = NULL;
	Create(device);
}

HRESULT CMesh::Create(DeviceStateManager*device)
{
	LPD3DXBUFFER pAdjacencyBuffer = NULL;
    LPD3DXBUFFER pMtrlBuffer = NULL;
    HRESULT      hr;
	XString		file;
	
	file=m_strPath;
	file.appand(m_strFileName);

	//check if raw binary file exists
	if (ReadRawBinary())
		return S_OK;//already read from raw file

	//if( FAILED( hr = D3DXLoadMeshFromX(file.getbuffer(), D3DXMESH_MANAGED, device->GetDevice(), &pAdjacencyBuffer, &pMtrlBuffer, NULL, &m_dwNumMaterials, &m_pMesh ) ) )
	if( FAILED( hr = D3DXLoadMeshFromX(file.getbuffer(), D3DXMESH_MANAGED, device->GetDevice(), NULL, &pMtrlBuffer, NULL, &m_dwNumMaterials, &m_pMesh ) ) )
    {
        return hr;
    }

	//generate normals
	DWORD fvf=m_pMesh->GetFVF();
	if (!(fvf&D3DFVF_NORMAL))
	{
		fvf|=D3DFVF_NORMAL;
		ID3DXMesh *newMesh;
		if (FAILED(m_pMesh->CloneMeshFVF(D3DXMESH_MANAGED,fvf,device->GetDevice(),&newMesh))) 
		{
			// handle error and exit
		}
		m_pMesh->Release();
		m_pMesh=newMesh;

		D3DXComputeNormals(m_pMesh, NULL); 
	}

	DWORD* rgdwAdjacency = new DWORD[m_pMesh->GetNumFaces() * 3];
    m_pMesh->GenerateAdjacency(1e-6f, rgdwAdjacency);
    m_pMesh->OptimizeInplace(D3DXMESHOPT_VERTEXCACHE, rgdwAdjacency, NULL, NULL, NULL);
	delete [] rgdwAdjacency;

	m_pMesh->GetAttributeTable(NULL, &m_NumAttributeGroups); // to retrieve size
	if(m_NumAttributeGroups > 0)
	{
		m_pAttributeTable = new D3DXATTRIBUTERANGE[m_NumAttributeGroups];
		m_pMesh->GetAttributeTable(m_pAttributeTable, &(m_NumAttributeGroups));
	}
	else
	{
		m_pAttributeTable = NULL;
	}

	D3DVERTEXELEMENT9 Declaration[MAX_FVF_DECL_SIZE];
	m_pMesh->GetDeclaration(Declaration);
	m_VDecl = new VertexDeclaration(device, Declaration);

	m_pMesh->GetVertexBuffer(&m_VB);
	m_pMesh->GetIndexBuffer(&m_IB);

	void* pVB;
	m_VB->Lock(0, 0, &pVB, 0);

	D3DXComputeBoundingSphere((D3DXVECTOR3*)pVB, m_pMesh->GetNumVertices(), m_pMesh->GetNumBytesPerVertex(), (D3DXVECTOR3*)&m_Bound.Center, &m_Bound.Radius);

	m_VB->Unlock();

	m_NumBytesPerVertex = m_pMesh->GetNumBytesPerVertex();

	if( pMtrlBuffer && m_dwNumMaterials > 0 )
    {
        // Allocate memory for the materials and textures
		m_Materials = new DXMaterial[m_dwNumMaterials];


        D3DXMATERIAL* d3dxMtrls = (D3DXMATERIAL*)pMtrlBuffer->GetBufferPointer();
//        m_pMaterials = new D3DMATERIAL9[m_dwNumMaterials];
/*        if( m_pMaterials == NULL )
        {
			if(pAdjacencyBuffer)
				pAdjacencyBuffer->Release();
			pAdjacencyBuffer=NULL;

			if(pMtrlBuffer)
				pMtrlBuffer->Release();
			pMtrlBuffer=NULL;
    
			return E_OUTOFMEMORY;
        }
        m_pTextures  = new LPDIRECT3DTEXTURE9[m_dwNumMaterials];
        if( m_pTextures == NULL )
        {
            if(pAdjacencyBuffer)
				pAdjacencyBuffer->Release();
			pAdjacencyBuffer=NULL;

			if(pMtrlBuffer)
				pMtrlBuffer->Release();
			pMtrlBuffer=NULL;
    
			return E_OUTOFMEMORY;
        }*/

        // Copy each material and create its texture
        for( DWORD i=0; i<m_dwNumMaterials; i++ )
        {
            // Copy the material
            /*m_pMaterials[i]         = d3dxMtrls[i].MatD3D;
            m_pTextures[i]          = NULL;

            // Create a texture
            if( d3dxMtrls[i].pTextureFilename )
            {
                XString strTexture;

				strTexture=m_strPath;
				strTexture.appand(d3dxMtrls[i].pTextureFilename);
                
                if( FAILED( D3DXCreateTextureFromFile( device->GetDevice(), strTexture.getbuffer(), 
                                                       &m_pTextures[i] ) ) )
                    m_pTextures[i] = NULL;
            }*/


			m_Materials[i].SetAmbient(d3dxMtrls[i].MatD3D.Ambient);
			m_Materials[i].SetDiffuse(d3dxMtrls[i].MatD3D.Diffuse);
			m_Materials[i].SetSpecular(d3dxMtrls[i].MatD3D.Specular);
			m_Materials[i].SetEmissive(d3dxMtrls[i].MatD3D.Emissive);
			m_Materials[i].SetSpecularExponent(d3dxMtrls[i].MatD3D.Power);
			if(d3dxMtrls[i].pTextureFilename)
				m_Materials[i].SetTexture(device, m_strPath + d3dxMtrls[i].pTextureFilename);
        }
    }

	//RestoreDeviceObjects(device);
	
	pMtrlBuffer->Release();
	//pAdjacencyBuffer->Release();

	SaveRawBinary();

	return S_OK;
}

bool CMesh::ReadRawBinary(void)
{
	FILE* fbin;
	if (0 == fopen_s(&fbin, (m_strPath + m_strFileName + XString(".bin")).getbuffer(), "rb"))
	{
		//check version
		int version;
		fread(&version, sizeof(int), 1, fbin);

		if (version != g_CMeshRBFV)
		{
			fclose(fbin);
			return false;
		}

		__time64_t mtime;
		__int64 size;
		fread(&mtime, sizeof(mtime), 1, fbin); //modification time
		fread(&size, sizeof(size), 1, fbin); //file size

		//check if also xfile is present and check if necessary file date and size
		struct _stat64 buf;
		if (0 == _stat64((m_strPath + m_strFileName).getbuffer(), &buf))
		{
			//exit and load xmesh if modification time or size does not match, otherwise proceed with binary file
			if (buf.st_mtime != mtime || buf.st_size != size)
			{
				fclose(fbin);
				return false;
			}
		}

		//read vertex declaration
		int vdcount;
		D3DVERTEXELEMENT9 decl[MAX_FVF_DECL_SIZE];

		fread(&vdcount, sizeof(int), 1, fbin);
		fread(&decl, sizeof(D3DVERTEXELEMENT9), vdcount + 1, fbin);

		m_VDecl = new VertexDeclaration(m_Device, decl);

		m_NumBytesPerVertex = D3DXGetDeclVertexSize(decl, 0);

		//write attributetable
		fread(&m_NumAttributeGroups, sizeof(int), 1, fbin);
		m_pAttributeTable = new D3DXATTRIBUTERANGE[m_NumAttributeGroups];
		fread(m_pAttributeTable, sizeof(D3DXATTRIBUTERANGE), m_NumAttributeGroups, fbin);
		
		//write materials
		fread(&m_dwNumMaterials, sizeof(int), 1, fbin);
		m_Materials = new DXMaterial[m_dwNumMaterials];

		for (unsigned i = 0; i < m_dwNumMaterials; i++)
		{
			D3DMATERIAL9 mat;
			XString texfile;

			fread(&mat, sizeof(D3DMATERIAL9), 1, fbin);
			texfile.Read(fbin);

			m_Materials[i].SetMaterial(mat);
			m_Materials[i].SetTexture(m_Device, m_strPath + texfile);
		}

		//write obs
		fread(&m_Bound, sizeof(OBS), 1, fbin);

		//write vertexbuffer
		D3DVERTEXBUFFER_DESC vbdesc;
		fread(&vbdesc, sizeof(D3DVERTEXBUFFER_DESC), 1, fbin);
		m_Device->GetDevice()->CreateVertexBuffer(vbdesc.Size, vbdesc.Usage, vbdesc.Format, vbdesc.Pool, &m_VB, NULL);

		void* vbdata;
		m_VB->Lock(0, 0, &vbdata, 0);
		fread(vbdata, sizeof(byte), vbdesc.Size, fbin);
		m_VB->Unlock();

		//write indexbuffer
		D3DINDEXBUFFER_DESC ibdesc;
		fread(&ibdesc, sizeof(D3DINDEXBUFFER_DESC), 1, fbin);
		m_Device->GetDevice()->CreateIndexBuffer(ibdesc.Size, ibdesc.Usage, ibdesc.Format, ibdesc.Pool, &m_IB, NULL);
				
		void* ibdata;
		m_IB->Lock(0, 0, &ibdata, 0);
		fread(ibdata, sizeof(byte), ibdesc.Size, fbin);
		m_IB->Unlock();

		fclose(fbin);
		return true;
	}

	return false;
}

bool CMesh::SaveRawBinary(void) const
{
	FILE* fbin;
	if (0 == fopen_s(&fbin, (m_strPath + m_strFileName + XString(".bin")).getbuffer(), "wb"))
	{
		//write version number
		fwrite(&g_CMeshRBFV, sizeof(int), 1, fbin);

		//write filestats of xmeshfile
		struct _stat64 buf;
		ZeroMemory(&buf, sizeof(buf));

		if (0 == _stat64((m_strPath + m_strFileName).getbuffer(), &buf))
		{
			//dont care, we have the mesh and want to safe it
		}

		fwrite(&buf.st_mtime, sizeof(buf.st_mtime), 1, fbin); //modification time
		fwrite(&buf.st_size, sizeof(buf.st_size), 1, fbin); //file size

		//write vertex declaration
		int vdcount = m_VDecl->GetElementCount();
		fwrite(&vdcount, sizeof(int), 1, fbin);
		fwrite(m_VDecl->GetDeclElements(), sizeof(D3DVERTEXELEMENT9), vdcount + 1, fbin);

		//write attributetable
		fwrite(&m_NumAttributeGroups, sizeof(int), 1, fbin);
		fwrite(m_pAttributeTable, sizeof(D3DXATTRIBUTERANGE), m_NumAttributeGroups, fbin);
		
		//write materials
		fwrite(&m_dwNumMaterials, sizeof(int), 1, fbin);
		for (unsigned i = 0; i < m_dwNumMaterials; i++)
		{
			fwrite(&m_Materials[i].GetMaterial(), sizeof(D3DMATERIAL9), 1, fbin);

			XString texfile = m_Materials[i].GetTextureFilename().SubStr(m_strPath.getlen(), 0);
			texfile.Write(fbin);
		}

		//write obs
		fwrite(&m_Bound, sizeof(OBS), 1, fbin);

		//write vertexbuffer
		D3DVERTEXBUFFER_DESC vbdesc;
		m_VB->GetDesc(&vbdesc);
		fwrite(&vbdesc, sizeof(D3DVERTEXBUFFER_DESC), 1, fbin);
		
		void* vbdata;
		m_VB->Lock(0, 0, &vbdata, 0);
		fwrite(vbdata, sizeof(byte), vbdesc.Size, fbin);
		m_VB->Unlock();

		//write indexbuffer
		D3DINDEXBUFFER_DESC ibdesc;
		m_IB->GetDesc(&ibdesc);
		fwrite(&ibdesc, sizeof(D3DINDEXBUFFER_DESC), 1, fbin);
		
		void* ibdata;
		m_IB->Lock(0, 0, &ibdata, 0);
		fwrite(ibdata, sizeof(byte), ibdesc.Size, fbin);
		m_IB->Unlock();

		fclose(fbin);
		return true;
	}

	return false;
}

void CMesh::BuildDrawCalls(void)
{
	if(m_dwNumMaterials > 0 && m_pAttributeTable)
	{
		m_pDrawCalls = new RenderJobDrawCall[m_dwNumMaterials];
		for(unsigned i=0; i<m_dwNumMaterials; i++)
		{
			RenderJobDrawCall* dc = m_pDrawCalls + i;

			dc->VB = m_VB;
			dc->IB = m_IB;
			dc->VDecl = m_VDecl;
			dc->VertexStride = m_NumBytesPerVertex;
			
			dc->PrimitiveType = PT_TRIANGLELIST;
			dc->BaseVertexIndex = 0;
			dc->MinIndex = m_pAttributeTable[i].VertexStart;
			dc->NumVertices = m_pAttributeTable[i].VertexCount;
			dc->StartIndex = m_pAttributeTable[i].FaceStart*3;
			dc->PrimitiveCount = m_pAttributeTable[i].FaceCount;
		}
	}
}

HRESULT CMesh::RestoreDeviceObjects(DeviceStateManager*device)
{
    //if( NULL == m_pSysMesh )
    //	return E_FAIL;

	if(m_pMesh)
		return S_OK;

    // Make a local memory version of the mesh. Note: because we are passing in
    // no flags, the default behavior is to clone into local memory.
    //if( FAILED( m_pSysMesh->CloneMeshFVF( 0 , m_pSysMesh->GetFVF(),
      //                                       device->GetDevice(), &m_pMesh ) ) )
        //return E_FAIL;

	//m_pMesh->GetVertexBuffer(&vb);
	//m_pMesh->GetIndexBuffer(&ib);

    return S_OK;
}

HRESULT CMesh::InvalidateDeviceObjects()
{
  //  if(m_pMesh)
	//	m_pMesh->Release();
	//m_pMesh=NULL;

    return S_OK;
}

HRESULT CMesh::Render(DeviceStateManager*device,D3DXMATRIX Position,bool bDrawOpaqueSubsets,
                          bool bDrawAlphaSubsets )
{
	//D3DXMATRIX oldPos;
	//D3DMATERIAL9 oldMat;
	//LPDIRECT3DBASETEXTURE9 oldTex;
	//DWORD oldFVF;

    if( NULL == m_pMesh )
        return E_FAIL;

    // Frist, draw the subsets without alpha

	//ZeroMemory( oldMat, sizeof(D3DMATERIAL9) );
   /* oldMat.Diffuse.r = oldMat.Ambient.r = 0.5;
    oldMat.Diffuse.g = oldMat.Ambient.g = 0.5;
    oldMat.Diffuse.b = oldMat.Ambient.b = 0.5;
    oldMat.Diffuse.a = oldMat.Ambient.a = 0.0;*/

	//(*m_ppDevice)->GetTransform(D3DTS_WORLD,&oldPos);
	//(*m_ppDevice)->GetMaterial(&oldMat);
	//(*m_ppDevice)->GetTexture(0,&oldTex);
	//(*m_ppDevice)->GetFVF(&oldFVF);

	//wlog("%r %f %f %f %f %f %f %f %f",hr,oldMat->Diffuse.r , oldMat->Ambient.r ,oldMat->Diffuse.g ,oldMat->Ambient.g , oldMat->Diffuse.b , oldMat->Ambient.b , oldMat->Diffuse.a , oldMat->Ambient.a );

	device->SetWorldMatrix( Position);

   /* if( bDrawOpaqueSubsets )
    {
        for( DWORD i=0; i<m_dwNumMaterials; i++ )
        {
            if( m_bUseMaterials )
            {
                if( m_pMaterials[i].Diffuse.a < 1.0f )
                    continue;
                device->SetMaterial( m_pMaterials[i] );
              //  device->SetTexture( 0, m_pTextures[i] );
            }
			
            m_pMesh->DrawSubset( i );
        }
    }
    // Then, draw the subsets with alpha
    if( bDrawAlphaSubsets && m_bUseMaterials )
    {
        for( DWORD i=0; i<m_dwNumMaterials; i++ )
        {
            if( m_pMaterials[i].Diffuse.a == 1.0f )
                continue;

            // Set the material and texture
            device->SetMaterial( m_pMaterials[i] );
            // device->SetTexture( 0, m_pTextures[i] );
            m_pMesh->DrawSubset( i );
        }
    }*/
	
	//(*m_ppDevice)->SetTransform(D3DTS_WORLD,&oldPos);
	//(*m_ppDevice)->SetMaterial(&oldMat);
	//(*m_ppDevice)->SetTexture(0,oldTex);
	//(*m_ppDevice)->SetFVF(oldFVF);
	
    return S_OK;
}

HRESULT CMesh::Render(DeviceStateManager*device,D3DXMATRIX Position,DXMaterial *mat)
{
	device->SetWorldMatrix( Position);

    if(mat)
	{
		mat->Setup(device);
		
		m_pMesh->DrawSubset(0);
    }

	return S_OK;
}

void CMesh::DrawSubset(DeviceStateManager*device, const DWORD pAttribID)
{
	LPDIRECT3DVERTEXBUFFER9 pVB;
	LPDIRECT3DINDEXBUFFER9 pIB;

	m_pMesh->GetVertexBuffer(&pVB);
	m_pMesh->GetIndexBuffer(&pIB);

	device->SetStreamSource(0, pVB, 0, m_pMesh->GetNumBytesPerVertex());
	device->SetIndices(pIB);
	device->SetVertexDeclaration(m_VDecl);

	device->DrawIndexedPrimitive(PT_TRIANGLELIST, 0, m_pAttributeTable[pAttribID].VertexStart, m_pAttributeTable[pAttribID].VertexCount, m_pAttributeTable[pAttribID].FaceStart*3, m_pAttributeTable[pAttribID].FaceCount);

	pIB->Release();
	pVB->Release();
}

//AniMesh

CAniMesh::CAniMesh(void)
{
	m_dTime=0;
	m_bInvalidated=TRUE;
}

CAniMesh::~CAniMesh(void)
{
	if (m_pAnimController)
		m_pAnimController->Release();
	m_pAnimController=NULL;

	DeleteMesh(m_pFrameRoot);

//	m_pAllocHist->Release();
	delete m_pAllocHist;
	m_pAllocHist=NULL;

	InvalidateDeviceObjects();
}

CAniMesh::CAniMesh(DeviceStateManager*device,XString FileName,XString Path)
{
	m_strFileName=FileName;
	m_strPath=Path;
	m_bInvalidated=TRUE;
	m_dTime=0;
	Create(device);
}

LPD3DXFRAME CAniMesh::GetFrameRoot(void)
{
	return m_pFrameRoot;
}

HRESULT CAniMesh::Create(DeviceStateManager*device)
{
    HRESULT      hr;
	XString		file;

	m_pAllocHist = new CAllocateHierarchy(this,m_strPath);

	file=m_strPath;
	file.appand(m_strFileName);

	hr = D3DXLoadMeshHierarchyFromX(file.getbuffer(), D3DXMESH_MANAGED, device->GetDevice(), m_pAllocHist, NULL, &m_pFrameRoot, &m_pAnimController);
    if (FAILED(hr))
        return hr;

	if(m_pAnimController)
	{
		m_pAnimController->SetTrackPosition(0,0);
		m_dTime=timeGetTime()/1000.;
		//wlog("%f",m_dTime);
	}

	D3DXMATRIX mat;
	D3DXMatrixTranslation( &mat, 0.f, 0.f, 0.0f );	

	UpdateFrameMatrices(m_pFrameRoot, &mat);
	
	return S_OK;
}

HRESULT CAniMesh::RestoreDeviceObjects(DeviceStateManager*device)
{
	
    return S_OK;
}

void CAniMesh::SetAlphaValue(float a)
{
	SetAlpha(m_pFrameRoot,a);
}

HRESULT CAniMesh::InvalidateDeviceObjects()
{

    return S_OK;
}

HRESULT CAniMesh::Render(DeviceStateManager*device,D3DXMATRIX Position)
{
	//D3DXMATRIX oldPos;
	//D3DMATERIAL9 oldMat;
	//LPDIRECT3DBASETEXTURE9 oldTex;
	//DWORD oldFVF;
	//double ttime;

	//(*m_ppDevice)->GetTransform(D3DTS_WORLD,&oldPos);
	//(*m_ppDevice)->GetMaterial(&oldMat);
	//(*m_ppDevice)->GetTexture(0,&oldTex);
	//(*m_ppDevice)->GetFVF(&oldFVF);

	if(!m_pFrameRoot)
	{
//		wlog("noframeroot!");
		return S_OK;
	}
    
//    (*m_ppDevice)->SetRenderState( D3DRS_NORMALIZENORMALS, TRUE );

	//wlog("begin render");
	RenderFrame(device,m_pFrameRoot,&Position,TRUE);
	//wlog("end");

	//(*m_ppDevice)->SetRenderState( D3DRS_NORMALIZENORMALS, FALSE );
	
	//(*m_ppDevice)->SetTransform(D3DTS_WORLD,&oldPos);
	//(*m_ppDevice)->SetMaterial(&oldMat);
	//(*m_ppDevice)->SetTexture(0,oldTex);
	//(*m_ppDevice)->SetFVF(oldFVF);

    return S_OK;
}

void CAniMesh::SetAlpha(LPD3DXFRAME pFrameBase,float a)
{
	D3DXFRAME_DERIVED *pFrame = (D3DXFRAME_DERIVED*)pFrameBase;

	if (!pFrame)
		return ;

	if (pFrame->pFrameSibling != NULL)
	{
		SetAlpha(pFrame->pFrameSibling,a);
	}
	if (pFrame->pFrameFirstChild != NULL)
	{
		SetAlpha(pFrame->pFrameFirstChild,a);
	}

	D3DXMESHCONTAINER_DERIVED *pMeshContainer;
    pMeshContainer = (D3DXMESHCONTAINER_DERIVED*)(pFrame->pMeshContainer);
	
	DWORD iMaterial;

	while (pMeshContainer != NULL)
    {
		for (iMaterial = 0; iMaterial < pMeshContainer->NumMaterials; iMaterial++)
        {
            pMeshContainer->pMaterials[iMaterial].MatD3D.Ambient.a = pMeshContainer->pMaterials[iMaterial].MatD3D.Diffuse.a = a;
        }
        pMeshContainer = (D3DXMESHCONTAINER_DERIVED*)pMeshContainer->pNextMeshContainer;
	}

}

void CAniMesh::DeleteMesh(LPD3DXFRAME pFrameBase)
{
    D3DXFRAME_DERIVED *pFrame = (D3DXFRAME_DERIVED*)pFrameBase;

	if (!pFrame)
		return ;

	if (m_pAllocHist)
	{
		if (pFrame->pFrameSibling != NULL)
		{
			DeleteMesh(pFrame->pFrameSibling);
		}
		if (pFrame->pFrameFirstChild != NULL)
		{
			DeleteMesh(pFrame->pFrameFirstChild);
		}
		m_pAllocHist->DestroyFrame(pFrameBase);
	}
}

void CAniMesh::UpdateFrameMatrices(LPD3DXFRAME pFrameBase, LPD3DXMATRIX pParentMatrix)
{
    D3DXFRAME_DERIVED *pFrame = (D3DXFRAME_DERIVED*)pFrameBase;

    if (pParentMatrix != NULL)
        D3DXMatrixMultiply(&pFrame->CombinedTransformationMatrix, &pFrame->TransformationMatrix, pParentMatrix);
    else
        pFrame->CombinedTransformationMatrix = pFrame->TransformationMatrix;

    if (pFrame->pFrameSibling != NULL)
    {
        UpdateFrameMatrices(pFrame->pFrameSibling, pParentMatrix);
    }

    if (pFrame->pFrameFirstChild != NULL)
    {
        UpdateFrameMatrices(pFrame->pFrameFirstChild, &pFrame->CombinedTransformationMatrix);
    }
}

HRESULT CAniMesh::Update(void)
{
	D3DXMATRIX mat;
	D3DXMatrixTranslation( &mat, 0.f, 0.f, 0.0f );	

	if(!m_pAnimController)
		return S_OK;

	double elapsedTime;
	elapsedTime=timeGetTime()/1000.-m_dTime;
	m_dTime=timeGetTime()/1000.;
	
	m_pAnimController->SetTrackPosition(0,m_pAnimController->GetTime()+elapsedTime);

	UpdateFrameMatrices(m_pFrameRoot, &mat);

	return S_OK;
}

HRESULT CAniMesh::RenderSingleFrame(DeviceStateManager*device,LPD3DXFRAME pFrame,D3DXMATRIX Position)
{
	//D3DXMATRIX oldPos;
	//D3DMATERIAL9 oldMat;
	//LPDIRECT3DBASETEXTURE9 oldTex;
	//double	ttime;
	//
	//(*m_ppDevice)->GetTransform(D3DTS_WORLD,&oldPos);
	//(*m_ppDevice)->GetMaterial(&oldMat);
	//(*m_ppDevice)->GetTexture(0,&oldTex);

	if(!pFrame)
		return S_OK;

	//wlog("begin render");
	RenderFrame(device,pFrame,&Position,FALSE);
	//wlog("end");

	//(*m_ppDevice)->SetTransform(D3DTS_WORLD,&oldPos);
	//(*m_ppDevice)->SetMaterial(&oldMat);
	//(*m_ppDevice)->SetTexture(0,oldTex);

    return S_OK;
}

HRESULT CAniMesh::SetFrameTime(double Frame)
{
	D3DXMATRIX mat;
	D3DXMatrixTranslation( &mat, 0.f, 0.f, 0.0f );	

	if(m_pAnimController)
	{
		m_pAnimController->SetTrackPosition(0,Frame);

		UpdateFrameMatrices(m_pFrameRoot, &mat);
	}

	return S_OK;
}

HRESULT CAniMesh::RenderFrame(DeviceStateManager*device,LPD3DXFRAME pFrame,D3DXMATRIX *Position,bool whithsubframe)
{
	D3DXMESHCONTAINER_DERIVED *pMeshContainer;
    UINT iMaterial;

	if(!pFrame)
		return S_OK;

	D3DXMATRIX trans;

	D3DXMatrixMultiply(&trans,&((D3DXFRAME_DERIVED*)pFrame)->CombinedTransformationMatrix,Position);

    pMeshContainer = (D3DXMESHCONTAINER_DERIVED*)pFrame->pMeshContainer;

    while (pMeshContainer != NULL)
    {
		device->SetWorldMatrix( trans);
		//(*m_ppDevice)->SetTransform(D3DTS_WORLD,&Position);

        for (iMaterial = 0; iMaterial < pMeshContainer->NumMaterials; iMaterial++)
        {
            device->SetMaterial( pMeshContainer->pMaterials[iMaterial].MatD3D );
            device->SetTexture( 0, pMeshContainer->ppTextures[iMaterial] );
            pMeshContainer->MeshData.pMesh->DrawSubset(0);
        }

        pMeshContainer = (D3DXMESHCONTAINER_DERIVED*)pMeshContainer->pNextMeshContainer;
	}

	if(whithsubframe)
	{
		if (pFrame->pFrameSibling != NULL)
		{
			RenderFrame(device,pFrame->pFrameSibling,Position,TRUE);
		}

		if (pFrame->pFrameFirstChild != NULL)
		{
			RenderFrame(device,pFrame->pFrameFirstChild,Position,TRUE);
		}
	}

    return S_OK;
}

LPD3DXFRAME CAniMesh::getFrame(XString*Name,LPD3DXFRAME startFrame)
{
	LPD3DXFRAME hFrame;

	if(!startFrame)
	{
		startFrame=m_pFrameRoot;
		if(!startFrame)
			return NULL;
	}

	if(startFrame->Name && Name->getbuffer() && !strcmp(startFrame->Name,Name->getbuffer()))
		return startFrame;
	
	if(startFrame->pFrameFirstChild)
	{
		hFrame = getFrame(Name,startFrame->pFrameFirstChild);
		if(hFrame)
			return hFrame;
	}

	if(startFrame->pFrameSibling)
	{
		hFrame = getFrame(Name,startFrame->pFrameSibling);
		if(hFrame)
			return hFrame;
	}
	
	return NULL;
}

//Alloc
//-----------------------------------------------------------------------------
// Name: AllocateName()
// Desc: Allocates memory for a XString to hold the name of a frame or mesh
//-----------------------------------------------------------------------------
HRESULT AllocateName( LPCTSTR Name, LPTSTR *pNewName )
{
    UINT cbLength;

    if (Name != NULL)
    {
        cbLength = lstrlen(Name) + 1;
        *pNewName = new TCHAR[cbLength];
        if (*pNewName == NULL)
            return E_OUTOFMEMORY;
        memcpy(*pNewName, Name, cbLength*sizeof(TCHAR));
    }
    else
    {
        *pNewName = NULL;
    }

    return S_OK;
}

//-----------------------------------------------------------------------------
// Name: CAllocateHierarchy::CreateFrame()
// Desc: 
//-----------------------------------------------------------------------------
HRESULT CAllocateHierarchy::CreateFrame(LPCTSTR Name, LPD3DXFRAME *ppNewFrame)
{
    HRESULT hr = S_OK;
    D3DXFRAME_DERIVED *pFrame;

	//wlog("create frame start");

    *ppNewFrame = NULL;

    pFrame = new D3DXFRAME_DERIVED;
    if (pFrame == NULL)
    {
        hr = E_OUTOFMEMORY;
        goto e_Exit;
    }

	//wlog("fname: %s",Name);

	hr= AllocateName(Name,&pFrame->Name);

	//wlog("fname: %s",Name);

	if (FAILED(hr))
        goto e_Exit;

    // initialize other data members of the frame
    D3DXMatrixIdentity(&pFrame->TransformationMatrix);
	D3DXMatrixIdentity(&pFrame->CombinedTransformationMatrix);

    pFrame->pMeshContainer = NULL;
    pFrame->pFrameSibling = NULL;
    pFrame->pFrameFirstChild = NULL;

    *ppNewFrame = pFrame;
    pFrame = NULL;
e_Exit:
	if(pFrame)
		delete pFrame;
	//wlog("end");
    return hr;
}




//-----------------------------------------------------------------------------
// Name: CAllocateHierarchy::CreateMeshContainer()
// Desc: 
//-----------------------------------------------------------------------------
HRESULT CAllocateHierarchy::CreateMeshContainer(LPCSTR Name,
    const D3DXMESHDATA *pMeshData,
    const D3DXMATERIAL *pMaterials,
    const D3DXEFFECTINSTANCE *pEffectInstances,
    DWORD NumMaterials,
    const DWORD *pAdjacency,
    LPD3DXSKININFO pSkinInfo,
    LPD3DXMESHCONTAINER *ppNewMeshContainer
)
{

	//wlog("create container start");

    HRESULT hr=S_OK;
	XString str;
    D3DXMESHCONTAINER_DERIVED *pMeshContainer = NULL;
    UINT NumFaces;
    UINT iMaterial;
    UINT cBones;
    LPDIRECT3DDEVICE9 pd3dDevice = NULL;

    LPD3DXMESH pMesh = NULL;

    *ppNewMeshContainer = NULL;

    // this sample does not handle patch meshes, so fail when one is found
    if (pMeshData->Type != D3DXMESHTYPE_MESH)
    {
        hr = E_FAIL;
        goto e_Exit;
    }

    // get the pMesh interface pointer out of the mesh data structure
    pMesh = pMeshData->pMesh;

    // this sample does not FVF compatible meshes, so fail when one is found
    if (pMesh->GetFVF() == 0)
    {
        hr = E_FAIL;
        goto e_Exit;
    }

    // allocate the overloaded structure to return as a D3DXMESHCONTAINER
    pMeshContainer = new D3DXMESHCONTAINER_DERIVED;
    if (pMeshContainer == NULL)
    {
        hr = E_OUTOFMEMORY;
        goto e_Exit;
    }
    memset(pMeshContainer, 0, sizeof(D3DXMESHCONTAINER));

    // make sure and copy the name.  All memory as input belongs to caller, interfaces can be addref'd though

	
	hr = AllocateName(Name, &pMeshContainer->Name);
	
    if (FAILED(hr))
        goto e_Exit;        

	//wlog("mitte");

    pMesh->GetDevice(&pd3dDevice);
    NumFaces = pMesh->GetNumFaces();

    // if no normals are in the mesh, add them
    if (!(pMesh->GetFVF() & D3DFVF_NORMAL))
    {
        pMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH;

        // clone the mesh to make room for the normals
        hr = pMesh->CloneMeshFVF( pMesh->GetOptions(), 
                                    pMesh->GetFVF() | D3DFVF_NORMAL, 
                                    pd3dDevice, &pMeshContainer->MeshData.pMesh );
        if (FAILED(hr))
            goto e_Exit;

        // get the new pMesh pointer back out of the mesh container to use
        // NOTE: we do not release pMesh because we do not have a reference to it yet
        pMesh = pMeshContainer->MeshData.pMesh;

        // now generate the normals for the pmesh
        D3DXComputeNormals( pMesh, NULL );
		//wlog("no normals - normals generated");
    }
    else  // if no normals, just add a reference to the mesh for the mesh container
    {
        pMeshContainer->MeshData.pMesh = pMesh;
        pMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH;
	
		//wlog("normals");
        pMesh->AddRef();

		/*DXVector3 * d;
		pMesh->LockVertexBuffer(0,(void**)&d);
		d++;
		wlog("asdf: %f %f %f",d->x,d->y,d->z);
		pMesh->UnlockVertexBuffer();*/
    }
        
    // allocate memory to contain the material information.  This sample uses
    //   the D3D9 materials and texture names instead of the EffectInstance style materials
    pMeshContainer->NumMaterials = _max(1, NumMaterials);
    pMeshContainer->pMaterials = new D3DXMATERIAL[pMeshContainer->NumMaterials];
    pMeshContainer->pAdjacency = new DWORD[NumFaces*3];

    if ((pMeshContainer->pAdjacency == NULL) || (pMeshContainer->pMaterials == NULL))
    {
        hr = E_OUTOFMEMORY;
        goto e_Exit;
    }

    memcpy(pMeshContainer->pAdjacency, pAdjacency, sizeof(DWORD) * NumFaces*3);

    // if materials provided, copy them

    if (NumMaterials > 0)            
    {
		pMeshContainer->NumMaterials = NumMaterials;
		pMeshContainer->ppTextures = new LPDIRECT3DTEXTURE9[NumMaterials];
		ZeroMemory(pMeshContainer->ppTextures,sizeof(LPDIRECT3DTEXTURE9)*NumMaterials);

        memcpy(pMeshContainer->pMaterials, pMaterials, sizeof(D3DXMATERIAL) * NumMaterials);

        for (iMaterial = 0; iMaterial < NumMaterials; iMaterial++)
        {
			pMeshContainer->pMaterials[iMaterial].MatD3D.Ambient=pMeshContainer->pMaterials[iMaterial].MatD3D.Diffuse;
			//wlog("asdf");
			//wlog("tex:");//%s",tex.getbuffer());
			str=m_strPath;
			//wlog("ad");
			str.appand(pMeshContainer->pMaterials[iMaterial].pTextureFilename);
			//wlog("sf");
			if( FAILED( D3DXCreateTextureFromFile( pd3dDevice,str.getbuffer() , 
                                                       &pMeshContainer->ppTextures[iMaterial] ) ) )
			{
//				wlog("error creating texture %s", pMeshContainer->pMaterials[iMaterial].pTextureFilename);
			}
			//wlog("fdsa");
		//	wlog("%f %f %f",pMeshContainer->pMaterials[iMaterial].MatD3D.Diffuse.r,pMeshContainer->pMaterials[iMaterial].MatD3D.Diffuse.g,pMeshContainer->pMaterials[iMaterial].MatD3D.Diffuse.b);
		//	wlog("%f %f %f",pMeshContainer->pMaterials[iMaterial].MatD3D.Specular.r,pMeshContainer->pMaterials[iMaterial].MatD3D.Specular.g,pMeshContainer->pMaterials[iMaterial].MatD3D.Specular.b);
		//	wlog("%f %f %f",pMeshContainer->pMaterials[iMaterial].MatD3D.Ambient.r,pMeshContainer->pMaterials[iMaterial].MatD3D.Ambient.g,pMeshContainer->pMaterials[iMaterial].MatD3D.Ambient.b);
        }
    }
    else // if no materials provided, use a default one
    {
		pMeshContainer->NumMaterials = 1;
        pMeshContainer->pMaterials[0].pTextureFilename = NULL;
        memset(&pMeshContainer->pMaterials[0].MatD3D, 0, sizeof(D3DMATERIAL9));
        pMeshContainer->pMaterials[0].MatD3D.Diffuse.r = 1.0f;
        pMeshContainer->pMaterials[0].MatD3D.Diffuse.g = 1.0f;
        pMeshContainer->pMaterials[0].MatD3D.Diffuse.b = 1.0f;
		pMeshContainer->pMaterials[0].MatD3D.Ambient.r = 1.0f;
        pMeshContainer->pMaterials[0].MatD3D.Ambient.g = 1.0f;
        pMeshContainer->pMaterials[0].MatD3D.Ambient.b = 1.0f;
		//wlog("asdfasdfa");
        pMeshContainer->pMaterials[0].MatD3D.Specular = pMeshContainer->pMaterials[0].MatD3D.Diffuse;
    }

    // if there is skinning information, save off the required data and then setup for HW skinning
    if (pSkinInfo != NULL)
    {
        // first save off the SkinInfo and original mesh data
        pMeshContainer->pSkinInfo = pSkinInfo;
        pSkinInfo->AddRef();

        pMesh->AddRef();

        // Will need an array of offset matrices to move the vertices from the figure space to the bone's space
        cBones = pSkinInfo->GetNumBones();
        
 
        if (FAILED(hr))
            goto e_Exit;
    }

    *ppNewMeshContainer = pMeshContainer;
    pMeshContainer = NULL;
e_Exit:
    if(pd3dDevice)
		pd3dDevice->Release();

    // call Destroy function to properly clean up the memory allocated 
    if (pMeshContainer != NULL)
    {
        DestroyMeshContainer(pMeshContainer);
    }

	//wlog("end");

    return hr;
}


CAllocateHierarchy::CAllocateHierarchy(CAniMesh *pMesh,XString Path)
{
	m_pMesh=pMesh;
	m_strPath=Path;
}


//-----------------------------------------------------------------------------
// Name: CAllocateHierarchy::DestroyFrame()
// Desc: 
//-----------------------------------------------------------------------------
HRESULT CAllocateHierarchy::DestroyFrame(LPD3DXFRAME pFrameToFree) 
{
    if(pFrameToFree->Name)
		delete [] pFrameToFree->Name;
	pFrameToFree->Name=NULL;
	if(pFrameToFree->pMeshContainer)
		DestroyMeshContainer(pFrameToFree->pMeshContainer);
    if( pFrameToFree)
		delete pFrameToFree;
	pFrameToFree=NULL;
    return S_OK; 
}




//-----------------------------------------------------------------------------
// Name: CAllocateHierarchy::DestroyMeshContainer()
// Desc: 
//-----------------------------------------------------------------------------
HRESULT CAllocateHierarchy::DestroyMeshContainer(LPD3DXMESHCONTAINER pMeshContainerBase)
{
    D3DXMESHCONTAINER_DERIVED *pMeshContainer = (D3DXMESHCONTAINER_DERIVED*)pMeshContainerBase;

    if( pMeshContainer->Name )
		delete [] pMeshContainer->Name ;
	pMeshContainer->Name=NULL;
    if( pMeshContainer->pAdjacency )
		delete [] pMeshContainer->pAdjacency ;
	pMeshContainer->pAdjacency=NULL;
    if( pMeshContainer->pMaterials )
		delete [] pMeshContainer->pMaterials;
	pMeshContainer->pMaterials=NULL;

    if( pMeshContainer->MeshData.pMesh )
		pMeshContainer->MeshData.pMesh->Release();
	pMeshContainer->MeshData.pMesh=NULL;
    if( pMeshContainer->pSkinInfo )
		pMeshContainer->pSkinInfo->Release();
	pMeshContainer->pSkinInfo=NULL;

	if(pMeshContainer->ppTextures)
	{
		DWORD i;
		for (i=0;i<pMeshContainer->NumMaterials;i++)
		{
			if(pMeshContainer->ppTextures[i])
				pMeshContainer->ppTextures[i]->Release();
		}
		delete [] pMeshContainer->ppTextures;
	}

    if( pMeshContainer )
		delete pMeshContainer;
	pMeshContainer=NULL;
    return S_OK;
}

XMeshAllocateHierarchy::XMeshAllocateHierarchy(DeviceStateManager* const device)
{
	m_Device = device;
}

HRESULT XMeshAllocateHierarchy::CreateFrame(LPCTSTR Name, LPD3DXFRAME *ppNewFrame)
{    
	// Create a frame
	// Using my drived struct here
	XMESHFRAME* pFrame = new XMESHFRAME;
	ZeroMemory(pFrame, sizeof(XMESHFRAME));

	// Inicilize the passed in frame
	*ppNewFrame = NULL;

	// Put the name in the frame
	if(Name)
	{
		unsigned nNameSize = (unsigned)strlen(Name) + 1;
		pFrame->Name = new char[nNameSize];
		memcpy(pFrame->Name, Name, nNameSize*sizeof(char));
	}
	else
		pFrame->Name = NULL;
	
	// Inicilize the rest of the frame
	pFrame->pFrameFirstChild = NULL;
	pFrame->pFrameSibling = NULL;
	pFrame->pMeshContainer = NULL;
	D3DXMatrixIdentity((D3DXMATRIX*)&pFrame->matCombined);
	D3DXMatrixIdentity((D3DXMATRIX*)&pFrame->TransformationMatrix);

	// Set the output frame to the one that we have
	*ppNewFrame = (LPD3DXFRAME)pFrame;

	// Returns an HRESULT so give it the AOk result
    return S_OK;
}

HRESULT XMeshAllocateHierarchy::CreateMeshContainer(LPCSTR Name, const D3DXMESHDATA *pMeshData,
		const D3DXMATERIAL *pMaterials, const D3DXEFFECTINSTANCE *pEffectInstances,
		DWORD NumMaterials, const DWORD *pAdjacency, LPD3DXSKININFO pSkinInfo,
		LPD3DXMESHCONTAINER *ppNewMeshContainer)
{

    // Create a Temp mesh contianer
	// Using my drived struct here
	XMESHCONTAINER* pMeshContainer = new XMESHCONTAINER;
	ZeroMemory(pMeshContainer, sizeof(XMESHCONTAINER));

	// Inicialize passed in Container
	*ppNewMeshContainer = NULL;

	if(Name)
	{
		// Put in the name
		unsigned nNameSize = (unsigned)strlen(Name) + 1;
		pMeshContainer->Name = new char[nNameSize];
		memcpy(pMeshContainer->Name, Name, nNameSize*sizeof(char));
	}
	else
	{
		pMeshContainer->Name = NULL;
	}

	pMeshContainer->pUserInfo = NULL;

	pMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH;
	
	// Get the number of Faces for adjacency
	DWORD dwFaces = pMeshData->pMesh->GetNumFaces();

	//Get Initcilize all the other data
	pMeshContainer->NumMaterials = NumMaterials;

	//Create the arrays for the materials and the textures
	pMeshContainer->pMaterials = new DXMaterial[pMeshContainer->NumMaterials];
	((LPD3DXMESHCONTAINER)pMeshContainer)->pMaterials = NULL;

	// Multiply by 3 because there are three adjacent triangles
	pMeshContainer->pAdjacency = new DWORD[dwFaces*3];
	memcpy(pMeshContainer->pAdjacency, pAdjacency, sizeof(DWORD) * dwFaces*3);
	
	//get the current vertex declaration
	D3DVERTEXELEMENT9 Declaration[MAX_FVF_DECL_SIZE];
	pMeshData->pMesh->GetDeclaration(Declaration);

	pMeshContainer->NumTexCoordSets = 0;
	pMeshContainer->HasNormals = false;
	pMeshContainer->HasTangents = false;

	//bool bHasNormal = false;
    //bool bHasTangent = false;
	//bool bHasTexCoords = false;
	unsigned DeclLength = D3DXGetDeclLength(Declaration);
	for( unsigned index = 0; index < DeclLength; ++index )
    {
        if( Declaration[index].Usage == D3DDECLUSAGE_NORMAL )
        {
            pMeshContainer->HasNormals = true;
        }
        if( Declaration[index].Usage == D3DDECLUSAGE_TANGENT )
        {
            pMeshContainer->HasTangents = true;
        }
		if( Declaration[index].Usage == D3DDECLUSAGE_TEXCOORD )
		{
			pMeshContainer->NumTexCoordSets++;
		}
    }

	//add normal and tangent if not in current mehs
	int VBytes = pMeshData->pMesh->GetNumBytesPerVertex();
	if(!pMeshContainer->HasNormals)
	{
		//copy decl_end to new end of array
		Declaration[DeclLength + 1] = Declaration[DeclLength];

		//add decl for normal
		Declaration[DeclLength].Stream = 0;
		Declaration[DeclLength].Offset = VBytes;
		Declaration[DeclLength].Type = D3DDECLTYPE_FLOAT3;
		Declaration[DeclLength].Method = D3DDECLMETHOD_DEFAULT;
		Declaration[DeclLength].Usage = D3DDECLUSAGE_NORMAL;
		Declaration[DeclLength].UsageIndex = 0;

		//new vertex size increases by float3
		VBytes += sizeof(float) * 3;

		//decllenght is now +1
		DeclLength++;
	}

	//we would like to have tangents, but this is only possible if there are texcoords
	if(!pMeshContainer->HasTangents && pMeshContainer->NumTexCoordSets > 0)
	{
		//copy decl_end to new end of array
		Declaration[DeclLength + 1] = Declaration[DeclLength];

		//add decl for tangent
		Declaration[DeclLength].Stream = 0;
		Declaration[DeclLength].Offset = VBytes;
		Declaration[DeclLength].Type = D3DDECLTYPE_FLOAT3;
		Declaration[DeclLength].Method = D3DDECLMETHOD_DEFAULT;
		Declaration[DeclLength].Usage = D3DDECLUSAGE_TANGENT;
		Declaration[DeclLength].UsageIndex = 0;

		//new vertex size increases by float3
		VBytes += sizeof(float) * 3;

		//decllenght is now +1
		DeclLength++;
	}

	//build decl
	pMeshContainer->VDecl = new VertexDeclaration(m_Device, Declaration);

	DWORD options = D3DXMESH_MANAGED;

	if (pMeshData->pMesh->GetNumVertices() >= 0xffff || pMeshData->pMesh->GetNumFaces() >= 0xffff / 3)
		options |= D3DXMESH_32BIT;

	//clone mesh with new vdecl
	HRESULT hr = pMeshData->pMesh->CloneMesh(options, Declaration, m_Device->GetDevice(), &pMeshContainer->MeshData.pMesh);
	if(FAILED(hr))
	{
		wlog("CloneMesh failed! %r", hr);
		return 0;
	}

	hr = pMeshContainer->MeshData.pMesh->OptimizeInplace(D3DXMESHOPT_COMPACT | D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_VERTEXCACHE, pMeshContainer->pAdjacency, NULL, NULL, NULL);
	if (FAILED(hr))
	{
		wlog("OptimizeInplace failed: %r", hr);
	}

	//compute normal if needed
	if(!pMeshContainer->HasNormals)
    {
		// Compute normals in case the meshes have them
        hr = D3DXComputeNormals( pMeshContainer->MeshData.pMesh, NULL );

		if(FAILED(hr))
		{
			wlog("ComputeNormals failed! %r", hr);
		}
		else
		{
			pMeshContainer->HasNormals = true;
		}
    }

	//build tangents if needed
	if(!pMeshContainer->HasTangents && pMeshContainer->NumTexCoordSets > 0)
	{
		LPD3DXMESH m = NULL;

		DWORD *adj = new DWORD[dwFaces * 3];
		//clean bowtie vertices out of mesh, otherwise the computed mesh will be invalid
		hr = D3DXCleanMesh(D3DXCLEAN_BOWTIES, pMeshContainer->MeshData.pMesh, pMeshContainer->pAdjacency, &m, adj, NULL);

		if(FAILED(hr))
		{
			delete adj;
			wlog("D3DXCleanMesh failed: %r", hr);
		}
		else
		{
			pMeshContainer->MeshData.pMesh->Release();
			pMeshContainer->MeshData.pMesh = m;
			m = NULL;

			delete pMeshContainer->pAdjacency;
			pMeshContainer->pAdjacency = adj;
			adj = NULL;

			float fPartialEdgeThreshold;
			float fSingularPointThreshold;
			float fNormalEdgeThreshold;

			//if( bSplitVertexForOptimalTangents )
			if( 1 )
			{
				fPartialEdgeThreshold = 0.01f;
				fSingularPointThreshold = 0.25f;
				fNormalEdgeThreshold = 0.01f;
			}
			else
			{
				fPartialEdgeThreshold = -1.01f;
				fSingularPointThreshold = 0.01f;
				fNormalEdgeThreshold = -1.01f;
			}

			// Compute tangents, which are required for normal mapping
			hr = D3DXComputeTangentFrameEx( pMeshContainer->MeshData.pMesh, 
											D3DDECLUSAGE_TEXCOORD, 0, 
											D3DDECLUSAGE_TANGENT, 0,
											D3DX_DEFAULT, 0, 
											D3DDECLUSAGE_NORMAL, 0,
											0, pMeshContainer->pAdjacency, 
											fPartialEdgeThreshold, fSingularPointThreshold, fNormalEdgeThreshold, 
											&m, NULL);

			if(FAILED(hr))
			{
				wlog("ComputeTangent failed! %r", hr);
			}
			else 
			{
				pMeshContainer->MeshData.pMesh->Release();
				pMeshContainer->MeshData.pMesh = m;
				pMeshContainer->HasTangents = true;
			}
		}
	}

	for(DWORD dw = 0; dw < NumMaterials; ++dw)
	{
		pMeshContainer->pMaterials[dw].SetAmbient(pMaterials[dw].MatD3D.Ambient);
		pMeshContainer->pMaterials[dw].SetDiffuse(pMaterials[dw].MatD3D.Diffuse);
		pMeshContainer->pMaterials[dw].SetSpecular(pMaterials[dw].MatD3D.Specular);
		pMeshContainer->pMaterials[dw].SetEmissive(pMaterials[dw].MatD3D.Emissive);
		pMeshContainer->pMaterials[dw].SetSpecularExponent(pMaterials[dw].MatD3D.Power);

		if(pMaterials[dw].pTextureFilename && strlen(pMaterials[dw].pTextureFilename) > 0)
		{
			pMeshContainer->pMaterials[dw].SetTexture(m_Device, pMaterials[dw].pTextureFilename);
		}
	}

	//need to call optimize before GetAttributeTable, otherwise it will be 0
	hr = pMeshContainer->MeshData.pMesh->OptimizeInplace(D3DXMESHOPT_COMPACT | D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_VERTEXCACHE, pMeshContainer->pAdjacency, NULL, NULL, NULL);
	if (FAILED(hr))
	{
		wlog("OptimizeInplace failed: %r", hr);
	}

	hr = pMeshContainer->MeshData.pMesh->GetAttributeTable(NULL, &(pMeshContainer->NumAttributeGroups)); // to retrieve size
	if (FAILED(hr))
	{
		wlog("GetAttributeTable failed! %r", hr);
	}
	else if(pMeshContainer->NumAttributeGroups > 0)
	{
		pMeshContainer->pAttributeTable = new D3DXATTRIBUTERANGE[pMeshContainer->NumAttributeGroups];
		hr = pMeshContainer->MeshData.pMesh->GetAttributeTable(pMeshContainer->pAttributeTable, &(pMeshContainer->NumAttributeGroups));

		if (FAILED(hr))
		{
			wlog("GetAttributeTable failed %r: ",hr);
		}
	}
	else
	{
		wlog("Open Mesh Error: AttributeTable empty");
	}

	if(pSkinInfo)
	{
		// first save off the SkinInfo and original mesh data
	    pMeshContainer->pSkinInfo = pSkinInfo;
	    pSkinInfo->AddRef();

	    // Will need an array of offset matrices to move the vertices from 
		//	the figure space to the bone's space
	    UINT uBones = pSkinInfo->GetNumBones();
	    pMeshContainer->pBoneOffsets = new D3DXMATRIX[uBones];

		//Create the arrays for the bones and the frame matrices
		pMeshContainer->ppFrameMatrices = new D3DXMATRIX*[uBones];

	    // get each of the bone offset matrices so that we don't need to 
		//	get them later
	    for (UINT i = 0; i < uBones; i++)
	        pMeshContainer->pBoneOffsets[i] = *(pMeshContainer->pSkinInfo->GetBoneOffsetMatrix(i));
	}
	else
	{
		pMeshContainer->pSkinInfo = NULL;
		pMeshContainer->pBoneOffsets = NULL;
		pMeshContainer->pSkinMesh = NULL;
		pMeshContainer->ppFrameMatrices = NULL;
	}

	pMeshContainer->MeshData.pMesh->GetVertexBuffer(&pMeshContainer->VB);
	pMeshContainer->MeshData.pMesh->GetIndexBuffer(&pMeshContainer->IB);

	pMeshContainer->pDrawCalls = NULL;

	if(pMeshContainer->VB)
	{
		void* pVB;
		pMeshContainer->VB->Lock(0, 0, &pVB, 0);

		DXVector3 vmin, vmax;
		D3DXComputeBoundingBox((D3DXVECTOR3*)pVB, pMeshContainer->MeshData.pMesh->GetNumVertices(), pMeshContainer->MeshData.pMesh->GetNumBytesPerVertex(), (D3DXVECTOR3*)&vmin, (D3DXVECTOR3*)&vmax);
		pMeshContainer->BBox.SetVolume(vmin, vmax);

		D3DXComputeBoundingSphere((D3DXVECTOR3*)pVB, pMeshContainer->MeshData.pMesh->GetNumVertices(), pMeshContainer->MeshData.pMesh->GetNumBytesPerVertex(), (D3DXVECTOR3*)&pMeshContainer->BSphere.Center, &pMeshContainer->BSphere.Radius);

		pMeshContainer->VB->Unlock();

		pMeshContainer->VB->PreLoad();
		pMeshContainer->IB->PreLoad();

		//build drawcalls
		pMeshContainer->pDrawCalls = new RenderJobDrawCall[pMeshContainer->NumAttributeGroups];
		for(DWORD dw = 0; dw < pMeshContainer->NumAttributeGroups; ++dw)
		{
			RenderJobDrawCall* dc = pMeshContainer->pDrawCalls + dw;

			LPD3DXMESH pDrawMesh = (pMeshContainer->pSkinInfo) ? pMeshContainer->pSkinMesh: pMeshContainer->MeshData.pMesh;

			dc->VB = pMeshContainer->VB;
			dc->IB = pMeshContainer->IB;
			dc->VDecl = pMeshContainer->VDecl;
			dc->VertexStride = pDrawMesh->GetNumBytesPerVertex();
			
			dc->PrimitiveType = PT_TRIANGLELIST;
			dc->BaseVertexIndex = 0;
			dc->MinIndex = pMeshContainer->pAttributeTable[dw].VertexStart;
			dc->NumVertices = pMeshContainer->pAttributeTable[dw].VertexCount;
			dc->StartIndex = pMeshContainer->pAttributeTable[dw].FaceStart*3;
			dc->PrimitiveCount = pMeshContainer->pAttributeTable[dw].FaceCount;
		}
	}
	else
	{
		wlog("Open Mesh Error: No VB");
	}
	
	//pMeshContainer->pMaterials = NULL;
	//pMeshContainer->pEffects = NULL;

	//pMeshContainer->MeshData.pMesh->OptimizeInplace(
	//	D3DXMESHOPT_VERTEXCACHE|D3DXMESHOPT_COMPACT|D3DXMESHOPT_ATTRSORT,
	//	pMeshContainer->pAdjacency,NULL,NULL,NULL);

	// Set the output mesh container to the temp one
	*ppNewMeshContainer = pMeshContainer;
    pMeshContainer = NULL;

	// Returns an HRESULT so give it the AOk result
    return S_OK;
}

HRESULT XMeshAllocateHierarchy::DestroyFrame(LPD3DXFRAME pFrameToFree) 
{
	//Convert the frame
	XMESHFRAME* pFrame = (XMESHFRAME*)pFrameToFree;

	// Delete the name
	SAFEDELETEARRAY(pFrame->Name)
	
	//if(pFrame->pMeshContainer)
	//	DestroyMeshContainer(pFrame->pMeshContainer);

	// Delete the frame
    SAFEDELETE(pFrame)

	// Returns an HRESULT so give it the AOk result
    return S_OK; 
}

HRESULT XMeshAllocateHierarchy::DestroyMeshContainer(LPD3DXMESHCONTAINER pMeshContainerBase)
{
	//Convert to my derived struct type
    XMESHCONTAINER* pMeshContainer = (XMESHCONTAINER*)pMeshContainerBase;
	
	// if there is a name
	SAFEDELETEARRAY(pMeshContainer->Name)

	//if there are materials
	SAFEDELETEARRAY(pMeshContainer->pMaterials)

	// if there is adjacency data
	SAFEDELETEARRAY(pMeshContainer->pAdjacency) 
	
	// if there are bone parts
	SAFEDELETEARRAY(pMeshContainer->pBoneOffsets)
	
	//if there are frame matrices
	SAFEDELETEARRAY(pMeshContainer->ppFrameMatrices)
	
	SAFEDELETEARRAY(pMeshContainer->pAttributeTable)
	
	//if there is a copy of the mesh here
	SAFERELEASE(pMeshContainer->pSkinMesh)
	
	//if there is a mesh
	SAFERELEASE(pMeshContainer->MeshData.pMesh)
	
	// if there is skin information
	SAFERELEASE(pMeshContainer->pSkinInfo)

	delete pMeshContainer->VDecl;

	SAFERELEASE(pMeshContainer->VB);
	SAFERELEASE(pMeshContainer->IB);

	delete [] pMeshContainer->pDrawCalls;

	pMeshContainer->pDrawCalls = NULL;
	
	//Delete the mesh container
	SAFEDELETE(pMeshContainer)

	// Returns an HRESULT so give it the AOk result
    return S_OK;
}

XMesh::XMesh(DeviceStateManager* const device, const XString& pathfn)
{
	m_Device = device;

	m_pFrameRoot = NULL;
	m_pFrameHierarchyArray = NULL;
	m_pAnimController = NULL;
	m_pBoneMatrices = NULL;
	m_uMaxBones = 0;
	m_pAllocHist = NULL;
	m_CurrentAnimation = -1;

	m_AnimationSetCount = 0;

	int lastslash = pathfn.instrrev("\\", 0);
	if(lastslash > 0)
		m_FilePath = pathfn.SubStr(0, lastslash);
	else
		lastslash = 0;
	m_FileName = pathfn.SubStr(lastslash, 0);

	m_FrameCount = 0;
	m_SubsetCount = 0;
	m_pDrawCallIndex = NULL;

	m_pAllocHist = new XMeshAllocateHierarchy(device);

	LoadXFile();
}

XMesh::~XMesh(void)
{
	//Delete Animation Controller
	SAFERELEASE(m_pAnimController);
	
	//if there is a frame hierarchyo
	if(m_pFrameRoot)
	{
		D3DXFrameDestroy(m_pFrameRoot, m_pAllocHist);
		m_pFrameRoot = NULL;
	}

	delete [] m_pDrawCallIndex;

	//Delete the bones
	delete [] m_pBoneMatrices;

	delete [] m_pFrameHierarchyArray;

	delete m_pAllocHist;
}

void XMesh::LoadXFile()
{
	HRESULT hr = D3DXLoadMeshHierarchyFromX((m_FilePath + m_FileName).getbuffer(), D3DXMESH_MANAGED, m_Device->GetDevice(), m_pAllocHist, NULL, (LPD3DXFRAME*)&m_pFrameRoot, &m_pAnimController);

    if (FAILED(hr))
	{
		wlog("Error loading mesh \"%s\" %r", (m_FilePath + m_FileName).getbuffer(), hr);
        return ;
	}

	if(m_pAnimController)
	{
		m_AnimationSetCount = m_pAnimController->GetMaxNumAnimationSets();

//		m_pAnimController->SetTrackPosition(0,0);
//		m_dTime=timeGetTime()/1000.;
		//wlog("%f",m_dTime);
	}

	if(m_pFrameRoot)
	{
		//Set the bones up and counts number of subsets
		SetupHierarchy(m_pFrameRoot, NULL);

		m_pFrameHierarchyArray = new XMESHFRAME*[m_FrameCount];

		m_pDrawCallIndex = new RenderJobDrawCall*[m_SubsetCount];
		ZeroMemory(m_pDrawCallIndex, sizeof(RenderJobDrawCall*) * m_SubsetCount);

		unsigned idc = 0;
		BuildDrawCallIndex(m_pFrameRoot, idc);

		int iframe = 0;
		InitFrameHieraryArray(m_pFrameRoot, iframe);

		//Setup the bone matrices array 
		m_pBoneMatrices  = new DXMatrix[m_uMaxBones];
		ZeroMemory(m_pBoneMatrices, sizeof(D3DXMATRIX)*m_uMaxBones);

		UpdateFrameMatrices(m_pFrameRoot, NULL);
		
		m_BSphere.Center = DXVector3(0, 0, 0);
		m_BSphere.Radius = 0;
		m_BBox.SetVolume(DXVector3(0, 0, 0), DXVector3(0, 0, 0));

		UpdateBound(m_pFrameRoot);

		//Calculate the Bounding Sphere
		//D3DXFrameCalculateBoundingSphere((LPD3DXFRAME)m_pFrameRoot, (D3DXVECTOR3*)&m_BSphere.Center, &m_BSphere.Radius);
	}

	/*D3DXMATRIX mat;
	D3DXMatrixTranslation( &mat, 0.f, 0.f, 0.0f );	*/
}

void XMesh::InitFrameHieraryArray(XMESHFRAME* const pFrame, int& iframe)
{
	m_pFrameHierarchyArray[iframe++] = pFrame;

	//Check your Sister
	if(pFrame->pFrameSibling)
		InitFrameHieraryArray((XMESHFRAME*)pFrame->pFrameSibling, iframe);

	//Check your Son
	if(pFrame->pFrameFirstChild)
		InitFrameHieraryArray((XMESHFRAME*)pFrame->pFrameFirstChild, iframe);
}

void XMesh::BuildDrawCallIndex(XMESHFRAME* const pFrame, unsigned& idc)
{
	XMESHCONTAINER* pMesh = (XMESHCONTAINER*)pFrame->pMeshContainer;

	//Set up the bones on the mesh
	if (pMesh)
	{		
		for (unsigned i = 0; i < pMesh->NumAttributeGroups; i++)
			m_pDrawCallIndex[idc++] = pMesh->pDrawCalls + i;
	}

	//Check your Sister
	if(pFrame->pFrameSibling)
		BuildDrawCallIndex((XMESHFRAME*)pFrame->pFrameSibling, idc);

	//Check your Son
	if(pFrame->pFrameFirstChild)
		BuildDrawCallIndex((XMESHFRAME*)pFrame->pFrameFirstChild, idc);
}

void XMesh::UpdateBound(XMESHFRAME* const pFrame)
{
	XMESHCONTAINER* pMesh = (XMESHCONTAINER*)pFrame->pMeshContainer;

	if(pMesh)
	{
		float s = _max(pFrame->matCombined.GetXAxis().Length(),_max(pFrame->matCombined.GetYAxis().Length(), pFrame->matCombined.GetZAxis().Length()));
		
		DXVector3 c;
		D3DXVec3TransformCoord((D3DXVECTOR3*)&c, (D3DXVECTOR3*)&(pMesh->BSphere.Center), (D3DXMATRIX*)&(pFrame->matCombined));
		//c = pMesh->BSphere.Center;
		OBS sphere(c, pMesh->BSphere.Radius * s);
		m_BSphere.Unify(sphere);

		OBB b(pMesh->BBox.GetMin(), pMesh->BBox.GetMax());
		b.SetOrientation(pFrame->matCombined);
		m_BBox.Unify(b.BuildAABB());
	}

	//Check your Sister
	if(pFrame->pFrameSibling)
		UpdateBound((XMESHFRAME*)pFrame->pFrameSibling);

	//Check your Son
	if(pFrame->pFrameFirstChild)
		UpdateBound((XMESHFRAME*)pFrame->pFrameFirstChild);
}

void XMesh::SetupHierarchy(XMESHFRAME* const pFrame, DXMatrix* const pParentMatrix)
{
	XMESHCONTAINER* pMesh = (XMESHCONTAINER*)pFrame->pMeshContainer;

	m_FrameCount++;

	//Set up the bones on the mesh
	if(pMesh)
	{		
		m_SubsetCount += pMesh->NumAttributeGroups;

		// if there is a skinmesh, then setup the bone matrices
		if(pMesh->pSkinInfo)
		{
			//Create a copy of the mesh
			pMesh->MeshData.pMesh->CloneMeshFVF(D3DXMESH_MANAGED, pMesh->MeshData.pMesh->GetFVF(), m_Device->GetDevice(), &pMesh->pSkinMesh);

			if(m_uMaxBones < pMesh->pSkinInfo->GetNumBones())
			{
				//Get the number of bones
				m_uMaxBones = pMesh->pSkinInfo->GetNumBones();
			}

			XMESHFRAME* pTempFrame = NULL;

			//For each bone 
			for (UINT i = 0; i < pMesh->pSkinInfo->GetNumBones(); i++)
			{   
				// Find the frame
				pTempFrame = (XMESHFRAME*)D3DXFrameFind((LPD3DXFRAME)m_pFrameRoot, pMesh->pSkinInfo->GetBoneName(i));

				//set the bone part
				pMesh->ppFrameMatrices[i] = (D3DXMATRIX*)&pTempFrame->matCombined;
			}
		}
	}

	//Check your Sister
	if(pFrame->pFrameSibling)
		SetupHierarchy((XMESHFRAME*)pFrame->pFrameSibling, pParentMatrix);

	//Check your Son
	if(pFrame->pFrameFirstChild)
		SetupHierarchy((XMESHFRAME*)pFrame->pFrameFirstChild, &pFrame->matCombined);
}

void XMesh::SetAnimation(const DWORD anim)
{
	// If the animation is not one that we are already using
	//	and the passed in flag is not bigger than the number of animations
	if(anim != m_CurrentAnimation && anim < m_AnimationSetCount) 
	{ 
		m_CurrentAnimation = anim;
		LPD3DXANIMATIONSET AnimSet = NULL;
		m_pAnimController->GetAnimationSet(m_CurrentAnimation, &AnimSet);
		m_pAnimController->SetTrackAnimationSet(0, AnimSet);
		SAFERELEASE(AnimSet);
	}
}

void XMesh::Update(float dElapsedTime)
{
	/*//Set the time for animation
	if(m_pAnimController && m_CurrentAnimation != -1)
		m_pAnimController->SetTrackPosition(0, m_pAnimController->GetTime() + dElapsedTime);

	//Update the frame hierarchy
	if(m_pFrameRoot)
	{
		UpdateFrameMatrices(m_pFrameRoot, NULL);
		
		XMESHCONTAINER* pMesh = m_pFirstMesh;
		if(pMesh)
		{
			if(pMesh->pSkinInfo)
			{
				UINT Bones = pMesh->pSkinInfo->GetNumBones();
				for (UINT i = 0; i < Bones; ++i)
				{	
					D3DXMatrixMultiply((D3DXMATRIX*)&m_pBoneMatrices[i], (D3DXMATRIX*)&pMesh->pBoneOffsets[i], (D3DXMATRIX*)pMesh->ppFrameMatrices[i]	);
				}

				// Lock the meshes' vertex buffers
				void *SrcPtr, *DestPtr;
				pMesh->MeshData.pMesh->LockVertexBuffer(D3DLOCK_READONLY, (void**)&SrcPtr);
				pMesh->pSkinMesh->LockVertexBuffer(0, (void**)&DestPtr);

				// Update the skinned mesh using provided transformations
				pMesh->pSkinInfo->UpdateSkinnedMesh((D3DXMATRIX*)m_pBoneMatrices, NULL, SrcPtr, DestPtr);

				// Unlock the meshes vertex buffers
				pMesh->pSkinMesh->UnlockVertexBuffer();
				pMesh->MeshData.pMesh->UnlockVertexBuffer();
			}
		}
	}*/
}

void XMesh::UpdateFrameMatrices(XMESHFRAME* const pFrame, DXMatrix* const pParentMatrix)
{	
	//Parent check
	if (pParentMatrix)
	{
		D3DXMatrixMultiply((D3DXMATRIX*)&pFrame->matCombined, (D3DXMATRIX*)&pFrame->TransformationMatrix, (D3DXMATRIX*)pParentMatrix);
	}
	else
	{
		pFrame->matCombined = pFrame->TransformationMatrix;
	}

	//Do the kid too
	if (pFrame->pFrameSibling)
	{
		UpdateFrameMatrices((XMESHFRAME*)pFrame->pFrameSibling, pParentMatrix);
	}

	//make sure you get the first kid
	if (pFrame->pFrameFirstChild)
	{
		UpdateFrameMatrices((XMESHFRAME*)pFrame->pFrameFirstChild, &pFrame->matCombined);
	}
}

void XMesh::DrawFrame(XMESHFRAME* const pFrame)
{
	XMESHCONTAINER* pMesh = (XMESHCONTAINER*)pFrame->pMeshContainer;

	m_Device->SetWorldMatrix(pFrame->matCombined);

	//While there is a mesh try toXMESHCONTAINER
	while(pMesh)
	{
		//Select the mesh to draw
		LPD3DXMESH pDrawMesh = (pMesh->pSkinInfo) ? pMesh->pSkinMesh: pMesh->MeshData.pMesh;
		
		//Draw each mesh subset with correct materials and texture
		for (DWORD i = 0; i < pMesh->NumAttributeGroups; ++i)
		{
			pMesh->pMaterials[i].Setup(m_Device);
			pDrawMesh->DrawSubset(i);
		}

		//Go to the next one
		pMesh = (XMESHCONTAINER*)pMesh->pNextMeshContainer;
	}

	//Check your Sister
	if(pFrame->pFrameSibling)
		DrawFrame((XMESHFRAME*)pFrame->pFrameSibling);

	//Check your Son
	if(pFrame->pFrameFirstChild)
		DrawFrame((XMESHFRAME*)pFrame->pFrameFirstChild);
}

void XMESHCONTAINER::DrawMeshSubset(DeviceStateManager* device, const DWORD pAttribID)
{
	LPD3DXMESH pDrawMesh = (pSkinInfo) ? pSkinMesh: MeshData.pMesh;

	//pDrawMesh->DrawSubset(pAttribID);

	LPDIRECT3DVERTEXBUFFER9 pVB;
	LPDIRECT3DINDEXBUFFER9 pIB;

	pDrawMesh->GetVertexBuffer(&pVB);
	pDrawMesh->GetIndexBuffer(&pIB);

	device->SetStreamSource(0, pVB, 0, pDrawMesh->GetNumBytesPerVertex());
	device->SetIndices(pIB);
	device->DrawIndexedPrimitive(PT_TRIANGLELIST, 0, pAttributeTable[pAttribID].FaceStart, pAttributeTable[pAttribID].VertexCount, 
		pAttributeTable[pAttribID].VertexStart, pAttributeTable[pAttribID].FaceCount);

	pIB->Release();
	pVB->Release();
}