Sign in to follow this  
Sagito

.X files animation loading

Recommended Posts

Hi everyone... Recently, I've learned how to program with DirectX interfaces in order to start the developmentof my own game engine (I'm using Visual C++ 6.0). I've already implemented sound, input and graphical support to my application, but I can't load animations from .X files. I'm trying to load animations with D3DXLoadMeshHierarchyFromX, and, in order to do that, I've created the following class: "class CAllocateHierarchy : public ID3DXAllocateHierarchy" and implemented the functions: CreateFrame, CreateMeshContainer, DestroyFrame and DestroyMeshContainer, according to the DirectX MultiAnimation sample. However, when I create a pointer to this interface ("CAllocateHierarchy * pAH"), it returns NULL or = to 0xcccccccc. Tried everything I could think of, but still can't load any animation... If that helps, I can post my code. Thanks everyone. =)

Share this post


Link to post
Share on other sites
This is the code I've got in my animation dedicated header file (don't mind the comments, they are all in portuguese... =P):


struct D3DXFRAME_DERIV: public D3DXFRAME
{
//D3DXMATRIX MatrizCombinada;

};

D3DXFRAME_DERIV* FrameBase;



struct D3DXMESHCONTAINER_DERIV: public D3DXMESHCONTAINER
{
LPDIRECT3DTEXTURE9* ppTexturas;
D3DMATERIAL9* pMateriais;

LPD3DXMESH pOrigMesh;
D3DXMATRIX* pBoneMatrices;
D3DXMATRIX* pBoneOffsets;
D3DXMATRIX* pFrameMatrices;

};


//Class destinada à gestão das funções CALLBACK presentes na class abstracta
//ID3DXAllocateHierarchy.

class CAllocateHierarchy: public ID3DXAllocateHierarchy
{
public:
STDMETHOD( CreateFrame )( THIS_ LPCSTR Name, LPD3DXFRAME *ppNewFrame );

STDMETHOD( CreateMeshContainer )( THIS_ LPCSTR Name,
CONST D3DXMESHDATA * pMeshData,
CONST D3DXMATERIAL * pMaterials,
CONST D3DXEFFECTINSTANCE * pEffectInstances,
DWORD NumMaterials,
CONST DWORD * pAdjacency,
LPD3DXSKININFO pSkinInfo,
LPD3DXMESHCONTAINER * ppNewMeshContainer );

STDMETHOD( DestroyFrame )( THIS_ LPD3DXFRAME pFrameToFree );

STDMETHOD( DestroyMeshContainer )( THIS_ LPD3DXMESHCONTAINER pMeshContainerToFree );


CAllocateHierarchy();

// STDMETHOD( SetMA )( THIS_ CMultiAnim *pMA );

private:
// CMultiAnim *m_pMA;
};



CAllocateHierarchy::CAllocateHierarchy()
{
MessageBox(0, "Constructor", "", MB_OK);
};

//Class destinada à gestão dos processos das animações
class Anim
{
public:
bool Preparacao(void);

};

//Variável de gestão das funções de animação. Sendo declarada aqui, evita redefinições
//posteriores, podendo ser usada sem problemas nos restantes ficheiros de nível superior.
Anim Animacao;


//////////////////////////////////////Funções////////////////////////////////////////////////////


CHAR *CopiarNome( CHAR *sNome )
{
DWORD dwLen = (DWORD) strlen( sNome );
CHAR * sNovoNome = new CHAR[ dwLen + 1 ];
strncpy( sNovoNome, sNome, dwLen );
sNovoNome[ dwLen ] = '\0';
return sNovoNome;
}

HRESULT CAllocateHierarchy::CreateFrame(LPCSTR Name, LPD3DXFRAME *ppNewFrame)
{
*ppNewFrame = NULL; //Garantia para a minha sanidade mental

D3DXFRAME_DERIV *NovoFrame = new D3DXFRAME_DERIV;
ZeroMemory(NovoFrame, sizeof(D3DXFRAME_DERIV));

if(Name)
NovoFrame->Name = (CHAR*) CopiarNome( (CHAR*) Name );
else
NovoFrame->Name = (CHAR*) CopiarNome( "<sem nome>" );

D3DXMatrixIdentity(&NovoFrame->TransformationMatrix);
// D3DXMatrixIdentity(&NovoFrame->MatrizCombinada);

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

*ppNewFrame = NovoFrame;

return D3D_OK;
}

HRESULT CAllocateHierarchy::CreateMeshContainer(THIS_ LPCSTR Name,
CONST D3DXMESHDATA * pMeshData,
CONST D3DXMATERIAL * pMaterials,
CONST D3DXEFFECTINSTANCE * pEffectInstances,
DWORD NumMaterials,
CONST DWORD * pAdjacency,
LPD3DXSKININFO pSkinInfo,
LPD3DXMESHCONTAINER * ppNewMeshContainer)
{
D3DXMESHCONTAINER_DERIV *NovoMC = new D3DXMESHCONTAINER_DERIV;
ZeroMemory(NovoMC, sizeof(D3DXMESHCONTAINER_DERIV));

*ppNewMeshContainer = NULL;

if(Name)
NovoMC->Name = (CHAR*) CopiarNome( (CHAR*) Name );
else
NovoMC->Name = (CHAR*) CopiarNome( "<sem nome>" );


if(pMeshData->Type != D3DXMESHTYPE_MESH)
{
MessageBox(0, "O objecto existente não é do tipo D3DXMESHTYPE_MESH", "", MB_OK);
return D3DERR_INVALIDCALL;

//Se esta função passar "false" não uso a função LoadMeshHierarchyFromX,
//mas apenas a LoadMeshFromX. Posso me ter enganado e ter tentado carregar uma
//animação de um edificio, por exemplo.
}

NovoMC->MeshData.Type = D3DXMESHTYPE_MESH;


//Carregar as adjacencias

DWORD nFaces = pMeshData->pMesh->GetNumFaces();
NovoMC->pAdjacency = new DWORD[nFaces * 3];
memcpy(NovoMC->pAdjacency, pAdjacency, sizeof(DWORD) * nFaces*3);


//Carregar o device do .x file

LPDIRECT3DDEVICE9 d3dDevice = NULL;
// pMeshData->pMesh->GetDevice(&d3dDevice);
d3dDevice = Device; //Quero que se lixe, eu uso o meu, não interessa o que esta definido!!!!

//Copiar os dados da mesh e coloca los no MeshContainer

pMeshData->pMesh->CloneMeshFVF(D3DXMESH_MANAGED,
pMeshData->pMesh->GetFVF(),
d3dDevice,
&NovoMC->MeshData.pMesh);


//Copiar texturas e materiais

NovoMC->NumMaterials = max(NumMaterials,1);
NovoMC->pMateriais = new D3DMATERIAL9[NovoMC->NumMaterials];
NovoMC->ppTexturas = new LPDIRECT3DTEXTURE9[NovoMC->NumMaterials];
ZeroMemory(NovoMC->ppTexturas,
sizeof(LPDIRECT3DTEXTURE9) * NovoMC->NumMaterials);

if (NumMaterials > 0)
{
// Carregar texturas e copiar todos os materiais
for(DWORD i = 0; i < NumMaterials; ++i)
{
NovoMC->ppTexturas[i] = NULL;
NovoMC->pMateriais[i] = pMaterials[i].MatD3D;

if(pMaterials[i].pTextureFilename)
{
// Converter para UNICODE, para poder uilizar a função D3DXCreateTextureFromFileW
WCHAR wszTexName[MAX_PATH];
MultiByteToWideChar( CP_ACP, 0, pMaterials[i].pTextureFilename, -1, wszTexName, MAX_PATH );


if(FAILED(D3DXCreateTextureFromFile(d3dDevice, pMaterials[i].pTextureFilename, &NovoMC->ppTexturas[i])))
{
NovoMC->ppTexturas[i] = NULL;
}
}
}
}
else
// criar um material para o caso de não existir nenhum pre-definido no ficheiro
{
ZeroMemory(&NovoMC->pMateriais[0], sizeof( D3DMATERIAL9 ) );
NovoMC->pMateriais[0].Diffuse.r = 0.5f;
NovoMC->pMateriais[0].Diffuse.g = 0.5f;
NovoMC->pMateriais[0].Diffuse.b = 0.5f;
NovoMC->pMateriais[0].Specular = NovoMC->pMateriais[0].Diffuse;
NovoMC->ppTexturas[0] = NULL;
}



//Copiar os dados de skinning caso existam

if (pSkinInfo)
{
NovoMC->pSkinInfo = pSkinInfo;
pSkinInfo->AddRef();

UINT numOssos = pSkinInfo->GetNumBones();
NovoMC->pBoneOffsets = new D3DXMATRIX[numOssos];

NovoMC->pFrameMatrices = new D3DXMATRIX[numOssos];

for (UINT i = 0; i < numOssos; i++)
NovoMC->pBoneOffsets[i] = *(NovoMC->pSkinInfo->GetBoneOffsetMatrix(i));

// Nota: Tenho que procurar implementar uma funcao GenerateSkinnedMesh aqui
}
else
{
NovoMC->pSkinInfo = NULL;
NovoMC->pBoneMatrices = NULL;
NovoMC->pBoneOffsets = NULL;
NovoMC->pOrigMesh = NULL;
NovoMC->pFrameMatrices = NULL;
}

d3dDevice->Release();
d3dDevice = NULL;

*ppNewMeshContainer = NovoMC;

return D3D_OK;
}



HRESULT CAllocateHierarchy::DestroyFrame(LPD3DXFRAME pFrameToFree)
{
D3DXFRAME_DERIV *pFrame = (D3DXFRAME_DERIV*)pFrameToFree;

if(pFrame->Name)
delete[] pFrame->Name;
pFrame->Name = NULL;

if (pFrame)
delete pFrame;
pFrame = NULL;

return D3D_OK;
}



HRESULT CAllocateHierarchy::DestroyMeshContainer(LPD3DXMESHCONTAINER pMeshContainerBase)
{
D3DXMESHCONTAINER_DERIV* pMeshContainer = (D3DXMESHCONTAINER_DERIV*)pMeshContainerBase;

SAFE_DELETE_ARRAY(pMeshContainer->Name)

SAFE_DELETE_ARRAY(pMeshContainer->pMateriais)

if(pMeshContainer->ppTexturas)
{
for(UINT i = 0; i < pMeshContainer->NumMaterials; ++i)
SAFE_RELEASE(pMeshContainer->ppTexturas[i]);
}

SAFE_DELETE_ARRAY(pMeshContainer->ppTexturas)

SAFE_DELETE_ARRAY(pMeshContainer->pAdjacency)

SAFE_DELETE_ARRAY(pMeshContainer->pBoneOffsets)

SAFE_DELETE_ARRAY(pMeshContainer->pFrameMatrices)

SAFE_RELEASE(pMeshContainer->pOrigMesh)

SAFE_RELEASE(pMeshContainer->MeshData.pMesh)

SAFE_RELEASE(pMeshContainer->pSkinInfo)

SAFE_DELETE(pMeshContainer);

return D3D_OK;
}



bool Anim::Preparacao()
{
CAllocateHierarchy* pAH;

hr = D3DXLoadMeshHierarchyFromX("tiny.x", D3DXMESH_MANAGED, Device, pAH, NULL, (LPD3DXFRAME *) &FrameBase, &AC);

if FAILED(hr)
return false;

return true;
}



That's all, hope you can help me correcting what is wrong with it... =)

(And as you noticed, I'am from Portugal, so I'am sorry for any mistake in these posts)... =$

Thanks again...

[Edited by - Coder on September 1, 2005 1:08:01 PM]

Share this post


Link to post
Share on other sites
You created a pointer to the hierarchy allocation but I do not see anywhere that you assign it to an object of that type, so it is just a null pointer at the time it is used by the Load function.

This is not the best way of doing this as it has an unneeded allocation for each model loaded, but it should make it work:


bool Anim::Preparacao()
{
CAllocateHierarchy* pAH = new CAllocateHierarchy;

hr = D3DXLoadMeshHierarchyFromX("tiny.x", D3DXMESH_MANAGED, Device, pAH, NULL, (LPD3DXFRAME *) &FrameBase, &AC);

delete pAH;

if FAILED(hr)
return false;

return true;
}

Share this post


Link to post
Share on other sites
Hi Saruman, thanks for posting... =)

I've also tried that solution before, but the code won't compile: "Cannot instantiate abstract class due to following members: -See declaration of CAllocationHierarchy;".

Any clue on how to avoid this error? I've tried to change CAllocationHierarchy in some points, but still no luck... =S

By the way, you said on your post this was not the best way to do it. How should I do it then? (Sorry for all these questions, but I'm a beginner in DirectX and I'm really lost in this hierarchy stuff). =P

Thanks... =D

Share this post


Link to post
Share on other sites
Quote:
Original post by Sagito
Hi Saruman, thanks for posting... =)

I've also tried that solution before, but the code won't compile: "Cannot instantiate abstract class due to following members: -See declaration of CAllocationHierarchy;".

Any clue on how to avoid this error? I've tried to change CAllocationHierarchy in some points, but still no luck... =S

By the way, you said on your post this was not the best way to do it. How should I do it then? (Sorry for all these questions, but I'm a beginner in DirectX and I'm really lost in this hierarchy stuff). =P

Thanks... =D

Those errors mean that you haven't implemented the full abstract class. There are four functions that you need to override and implement and you should make sure they are the same signature as the abstract base class. You left out the line from the debugger that tells which members the compiler is complaining about though so I am unsure where your error is and I'm at work so I don't have time to go through your full codebase there :)

Also when I said it isn't the best way to do it I didn't mean how you are loading the hierarchy, but I meant my example of creating the allocator each time you build a model. You may want to do this depending on your design, although you could also create this as a member somewhere and pass it in to the new model when you are creating it. That way you avoid instantiating it many times unnecessarily.

Share this post


Link to post
Share on other sites
Er... Bad news is that this was the full quote from the compiler. It doesn't say which statement is wrong, or which function is not defined... =@ Just says: "Cannot instantiate abstract class due to following members: -See declaration of CAllocateHierarchy", nothing else comes afterwards.

I have defined all four functions of this class, but I'll re-check them for any errors (which would be easier if I knew what the compiler is complaining about). =P

Is there any other function besides D3DXLoadMeshHierarchyFromX that I can use to load an animation from .X files? =)

Thanks...

Share this post


Link to post
Share on other sites
Well that is the only function used for loading X files unless you want to write a manual parser, which I probably wouldn't suggest.

That error means that somewhere you have not implemented one of the base virtual functions. You might think that you have, but if the signatures differ in any way than you haven't, so you might want to really look at that.

Take a look here for some more help.

EDIT: Get rid of the CAllocateHierarchy constructor and try it.

Share this post


Link to post
Share on other sites
Well, now I managed to figure out that the compiler was complaining about my CreateMeshContainer struct... =) But I tried to adapt that struct using that link you gave me (thanks for it, helped a lot... =D), but it still complains about it... However, now it says twice(?!) something like:

"CAllocateHierarchy: cannot instantiate abstract class due to following members:
See declaration of CAllocateHierarchy

warning C4259: 'long __stdcall ID3DXAllocateHierarchy::CreateMeshContainer(...)': pure virtual function call was nor defined"

I think that function is working now, because it is similar to the one in that link you posted and to the one which is written in DirectX SDK's MultiAnimation sample... Also, the functions signatures seem to be OK, still don't understand what's wrong with this... =S Lol, I'm getting desperate here... =P

Thanks, and sorry again for all the questions...

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this