deargui-vpl/ref/virtools/Samples/Plugins/x Loader/XloaderCharacter.cpp

958 lines
31 KiB
C++

/*************************************************************************/
/* File : XLoader.cpp */
/* */
/* DirectX .X files loader */
/* */
/* Virtools SDK */
/* Copyright (c) Virtools 2000, All Rights Reserved. */
/*************************************************************************/
#include "XLoader.h"
#include "InitGuid.h"
char *RemoveX3DS(char *name);
/* {3CF169CE-FF7C-44ab-93C0-F78F62D172E2} */
DEFINE_GUID(TID_XSkinMeshHeader,
0x3CF169CE, 0xFF7C, 0x44ab, 0x93, 0xc0, 0xF7, 0x8F, 0x62, 0xD1, 0x72, 0xE2);
/* {6F0D123B-BAD2-4167-A0D0-80224F25FABB} */
DEFINE_GUID(TID_SkinWeights,
0x6F0D123B, 0xBAD2, 0x4167, 0xA0, 0xD0, 0x80, 0x22, 0x4F, 0x25, 0xFA, 0xBB);
#ifdef CK_LIB
#define CKGetPluginInfoCount CKGet_XLoader_PluginInfoCount
#define CKGetPluginInfo CKGet_XLoader_PluginInfo
#define CKGetReader CKGet_XLoader_Reader
#else
#define CKGetPluginInfoCount CKGetPluginInfoCount
#define CKGetPluginInfo CKGetPluginInfo
#define CKGetReader CKGetReader
#endif
//********************************************************************************
//********************************************************************************
//*************** PLUGIN DECLARATION ********************************************
//********************************************************************************
//********************************************************************************
#define X_PLUGIN_VERSION 0x0000001
#define X_READER_GUID CKGUID(0x31011515,0x71af1e3f)
CKPluginInfo g_PluginInfos;
/*************************************************
Returns the number of plugins in this DLL (1)
**************************************************/
int CKGetPluginInfoCount() {
if (VxGetOs() == VXOS_WINNT4) return 0;
return 1;
}
/*************************************************
Returns info about this plugin
**************************************************/
CKPluginInfo* CKGetPluginInfo(int index)
{
// Not Valid under Win NT 4
if (VxGetOs() == VXOS_WINNT4) return 0;
g_PluginInfos.m_GUID=X_READER_GUID;
g_PluginInfos.m_Extension="X";
g_PluginInfos.m_Description="Microsoft DirectX";
g_PluginInfos.m_Author="Virtools";
g_PluginInfos.m_Summary="DirectX File Reader";
g_PluginInfos.m_Version=X_PLUGIN_VERSION;
g_PluginInfos.m_InitInstanceFct=NULL; //
g_PluginInfos.m_Type=CKPLUGIN_MODEL_READER; // Plugin Type
return &g_PluginInfos;
}
CKDataReader* CKGetReader(int index)
{
return new CKXReader();
}
//********************************************************************************
//********************************************************************************
//************* READER IMPLEMENTATION ********************************************
//********************************************************************************
//********************************************************************************
CKPluginInfo* CKXReader::GetReaderInfo() {
return &g_PluginInfos;
}
//------- Returns the name of a LPDIRECTXFILEOBJECT
XString GetFileObjectName(LPDIRECTXFILEOBJECT obj)
{
if (!obj) return XString("");
DWORD NameSize = 0;
if (FAILED(obj->GetName(NULL,&NameSize)))
return XString("");
if (!NameSize)
return XString("");
NameSize++;
XString Temp(NameSize);
if (FAILED(obj->GetName(Temp.Str(),&NameSize)))
return XString("");
return Temp;
}
/*************************************************************
Main Loading function
*************************************************************/
CKERROR CKXReader::Load(CKContext* context,CKSTRING FileName,CKObjectArray *array,CKDWORD LoadFlags,CKCharacter *carac)
{
if(!array) return CKERR_INVALIDPARAMETER;
if(!FileName) return CKERR_INVALIDPARAMETER;
HRESULT hr = S_OK;
m_Context = context;
m_LoadFlags = LoadFlags;
m_Character = carac;
m_FileName = FileName;
m_AnimationLength = 0;
// Create the XFile object
if (DXFILE_OK != DirectXFileCreate(&m_XFile)) return CKERR_NOTIMPLEMENTED;
// Create the XFile enumerator
if (FAILED(m_XFile->CreateEnumObject(FileName,DXFILELOAD_FROMFILE,&m_XFileEnumerator))) {
CleanUp();
return CKERR_INVALIDFILE;
}
// Create the exporter object
m_VirtoolsExport = new Export2Virtools(context, FALSE);
// Register templates for d3drm and patch extensions.
if( FAILED( hr = m_XFile->RegisterTemplates( (VOID*)D3DRM_XTEMPLATES,
D3DRM_XTEMPLATE_BYTES ) ) )
{
CleanUp();
return CKERR_INVALIDFILE;
}
m_CreationOptions = CK_OBJECTCREATION_NONAMECHECK;
if (LoadFlags & (CK_LOAD_AS_DYNAMIC_OBJECT))
m_CreationOptions = CK_OBJECTCREATION_OPTIONS(m_CreationOptions|CK_OBJECTCREATION_DYNAMIC);
m_VirtoolsExport->SetObjectsCreationOptions(m_CreationOptions);
m_3dObjectsClass = m_Character ? CKCID_BODYPART : ((m_LoadFlags & CK_LOAD_ASCHARACTER)!=0) ? CKCID_BODYPART : CKCID_3DOBJECT;
LPDIRECTXFILEDATA pXData = NULL;
// Enumerate top level objects.
// Top level objects are always data object.
while (SUCCEEDED(m_XFileEnumerator->GetNextDataObject(&pXData)))
{
HRESULT hr = LoadFileData(pXData,NULL);
SAFERELEASE(pXData);
}
if (FAILED(hr)) {
CleanUp();
return CKERR_INVALIDFILE;
}
//We set the skinning information now that we are sure all bones are loaded
int i;
for(i=0;i<m_BonesName.Size();i++)
{
XCKObjectsHashTableIt it = m_FrameHashTable.Find(m_BonesName[i]);
CK3dEntity* Bone = (it==m_FrameHashTable.End()) ? NULL : (CK3dEntity*)*it;
CKSkinBoneData* BoneData = (m_Skins[i])->GetBoneData(m_BonesIndex[i]);
BoneData->SetBone(Bone);
BoneData->SetBoneInitialInverseMatrix(Bone->GetInverseWorldMatrix());
}
m_BonesName.Clear();
m_BonesIndex.Clear();
m_Skins.Clear();
if (m_VirtoolsExport->GetGlobalAnimation())
m_VirtoolsExport->GetGlobalAnimation()->SetLength(m_AnimationLength);
//---- There are some meshes without a frame
if (m_MeshHashTable.Size() && !m_FrameHashTable.Size()) {
XCKObjectsHashTableIt Begin = m_MeshHashTable.Begin();
XCKObjectsHashTableIt End = m_MeshHashTable.End();
for (;Begin!=End;++Begin) {
CKMesh* m = (CKMesh*)*Begin;
CK3dEntity* NewFrame = NULL;
if (CharacterMode())
NewFrame = (CK3dEntity*)m_VirtoolsExport->AddCharacterBodyPart((char *)m->GetName());
else
NewFrame = (CK3dEntity*)m_VirtoolsExport->Add3dObject((char *)m->GetName());
NewFrame->SetCurrentMesh(m);
}
}
//--- No character was given
//--- but one should be created...
if (!m_Character) {
if ((m_LoadFlags & CK_LOAD_ASCHARACTER)) {
CKPathSplitter Splitter(FileName);
m_VirtoolsExport->CreateCharacter(Splitter.GetName());
}
}
BOOL AnimationOnly = FALSE;
//--- Only animations were asked...
if ((m_LoadFlags & CK_LOAD_ANIMATION) && !(m_LoadFlags & CK_LOAD_GEOMETRY)) {
// we are loading animations and need to find the entities
// to which they apply
m_VirtoolsExport->ResolveAnimationsTargets(m_Character);
AnimationOnly = TRUE;
}
//-- Generate the list of objects in the array
m_VirtoolsExport->GenerateObjects(array,AnimationOnly);
return CK_OK;
}
#define RELEASEEXIT(ErrorCode,ToRelease) {\
SAFERELEASE(ToRelease);\
return ErrorCode;\
}\
/*********************************************
Loads a 3DEntity transformation Matrix
*********************************************/
HRESULT CKXReader::LoadTransformationMatrix(LPDIRECTXFILEDATA CurData,CK3dEntity* Parent)
{
VxMatrix* Mat;
DWORD Size = 0;
HRESULT hr = CurData->GetData(NULL, &Size, (void **)&Mat);
if (SUCCEEDED(hr) && Parent) {
Parent->SetLocalMatrix(*Mat,TRUE);
}
return hr;
}
/***************************************************************
Loads a material (reference or data) and returns a pointer
to the created CKMaterial
**************************************************************/
CKMaterial* CKXReader::LoadMaterial(LPDIRECTXFILEOBJECT CurObject)
{
HRESULT hr = S_OK;
CKMaterial* Material = NULL;
if (m_LoadFlags & CK_LOAD_GEOMETRY) {
LPDIRECTXFILEDATA CurData = NULL;
LPDIRECTXFILEDATAREFERENCE CurDataRef = NULL;
XString MaterialName = GetFileObjectName(CurObject);
// Reference or data ?
if (SUCCEEDED(CurObject->QueryInterface(IID_IDirectXFileDataReference,(LPVOID *)&CurDataRef))) {
// REFERENCE : we find the material from its name and return it
if (SUCCEEDED(CurDataRef->Resolve(&CurData))) {
MaterialName = GetFileObjectName(CurData);
XCKObjectsHashTableIt it=m_MaterialHashTable.Find(MaterialName);
Material = (it==m_MaterialHashTable.End()) ? NULL : (CKMaterial*)*it;
SAFERELEASE(CurData);
}
SAFERELEASE(CurDataRef);
} else
if (SUCCEEDED(CurObject->QueryInterface(IID_IDirectXFileData,(LPVOID *)&CurData))) {
// DATA : we have to create a material
VxColor* Diffuse = 0;
float* Power = 0;
VxColor* Specular = 0;
VxColor* Emissive = 0;
DWORD Size = 0;
//-- Load material data (if some of them are not here we fail...)
if (FAILED(hr = CurData->GetData("faceColor",&Size, (void **)&Diffuse))) RELEASEEXIT(NULL,CurData);
if (FAILED(hr = CurData->GetData("power",&Size, (void **)&Power))) RELEASEEXIT(NULL,CurData);
if (FAILED(hr = CurData->GetData("specularColor",&Size, (void **)&Specular))) RELEASEEXIT(NULL,CurData);
if (FAILED(hr = CurData->GetData("emissiveColor",&Size, (void **)&Emissive))) RELEASEEXIT(NULL,CurData);
//-- Copy the loaded material settings into a VirtoolsMat
VirtoolsMaterial VirtoolsMat;
XString TextureFileName;
VirtoolsMat.m_Specular.a = 0;
VirtoolsMat.m_Emissive.a = 0;
VirtoolsMat.m_Diffuse = *Diffuse;
memcpy(&VirtoolsMat.m_Specular,Specular,3*sizeof(float));
memcpy(&VirtoolsMat.m_Emissive,Emissive,3*sizeof(float));
VirtoolsMat.m_SpecularPower = *Power;
//-- Transparent Material
if (VirtoolsMat.m_Diffuse.a < 1.0f) {
VirtoolsMat.m_AlphaBlending = TRUE;
VirtoolsMat.m_SrcBlendFactor = VXBLEND_SRCALPHA;
VirtoolsMat.m_DstBlendFactor = VXBLEND_INVSRCALPHA;
VirtoolsMat.m_ZWriteEnable = FALSE;
}
//------- Is There a texture ? -------------
LPDIRECTXFILEOBJECT NextObject = NULL;
LPDIRECTXFILEDATA NextData = NULL;
if (SUCCEEDED(CurData->GetNextObject(&NextObject))) {
if SUCCEEDED(NextObject->QueryInterface(IID_IDirectXFileData,(LPVOID *)&NextData)) {
const GUID* DataType = NULL;
if (SUCCEEDED(NextData->GetType(&DataType))) {
if (TID_D3DRMTextureFilename == *DataType) {
char** String = NULL;
DWORD DataSize;
if (SUCCEEDED(NextData->GetData("filename",&DataSize,(void**)&String))) {
// Yes ! there is a texture : try to load it...
if (String && *String) {
TextureFileName = *String;
VirtoolsMat.m_Texture = m_VirtoolsExport->AddTexture(*String,*String);
}
}
}
}
SAFERELEASE(NextData);
}
SAFERELEASE(NextObject);
}
// Rename the material if necessary
if (MaterialName=="") MaterialName = GetUnnamed();
// If a material with this name already exists we
// compare the existing one parameters
XCKObjectsHashTableIt it=m_MaterialHashTable.Find(MaterialName);
Material = (it==m_MaterialHashTable.End()) ? NULL : (CKMaterial*)*it;
if (Material) {
if (Material->GetDiffuse() != VirtoolsMat.m_Diffuse) Material = NULL;
else
if (Material->GetSpecular() != VirtoolsMat.m_Specular) Material = NULL;
else
if (Material->GetEmissive() != VirtoolsMat.m_Emissive) Material = NULL;
else
if (Material->GetPower() != VirtoolsMat.m_SpecularPower) Material = NULL;
else
if (TextureFileName!="") {
CKTexture* tex = Material->GetTexture();
if (tex) {
if (TextureFileName!=tex->GetSlotFileName(0)) {
Material = NULL;
}
} else Material = NULL;
}
}
if (!Material) {
// And finally create the material
Material = m_VirtoolsExport->AddMaterial(&VirtoolsMat,MaterialName.Str());
m_MaterialHashTable.Insert(MaterialName,Material);
}
SAFERELEASE(CurData);
}
}
return Material;
}
/*********************************************************
Loads a mesh vertices colors
**********************************************************/
HRESULT CKXReader::LoadMeshVertexColors(LPDIRECTXFILEDATA CurData,VirtoolsTransitionMesh* m)
{
HRESULT hr;
DWORD* nVertexColors = 0;
DWORD* vertexColors = 0;
DWORD Size;
if (FAILED( hr = CurData->GetData("nVertexColors",&Size, (void **)&nVertexColors))) return hr;
if (FAILED( hr = CurData->GetData("vertexColors",&Size, (void **)&vertexColors))) return hr;
m->m_PrelitMesh = TRUE;
m->m_VertexColors.Resize(m->m_Vertices.Size());
for (DWORD i = 0; i < *nVertexColors; ++i) {
DWORD Index = *vertexColors++;
VxColor* col = (VxColor*)vertexColors;
m->m_VertexColors[Index] = *col;
vertexColors += 4;
}
return hr;
}
/*********************************************************
Loads a mesh vertices texture coordinates
**********************************************************/
HRESULT CKXReader::LoadMeshTextureCoords(LPDIRECTXFILEDATA CurData,VirtoolsTransitionMesh* m)
{
HRESULT hr;
DWORD* nTextureCoords = 0;
VxUV* textureCoords = 0;
DWORD Size;
if (FAILED( hr = CurData->GetData("nTextureCoords",&Size, (void **)&nTextureCoords))) return hr;
if (FAILED( hr = CurData->GetData("textureCoords",&Size, (void **)&textureCoords))) return hr;
for (DWORD i = 0; i < *nTextureCoords; ++i,textureCoords++) {
m->AddUv(*textureCoords);
}
return hr;
}
/*********************************************************
Loads a mesh vertices normals
**********************************************************/
HRESULT CKXReader::LoadMeshNormals(LPDIRECTXFILEDATA CurData,VirtoolsTransitionMesh* m)
{
HRESULT hr;
DWORD* nNormals = 0;
VxVector* normals = 0;
DWORD* nFaceNormals = 0;
DWORD* faceNormals = 0;
DWORD Size;
if (FAILED( hr = CurData->GetData("nNormals",&Size, (void **)&nNormals))) return hr;
if (FAILED( hr = CurData->GetData("normals",&Size, (void **)&normals))) return hr;
if (FAILED( hr = CurData->GetData("nFaceNormals",&Size, (void **)&nFaceNormals))) return hr;
if (FAILED( hr = CurData->GetData("faceNormals",&Size, (void **)&faceNormals))) return hr;
for (DWORD i = 0; i < *nNormals; ++i,normals++) {
m->AddNormal(*normals);
}
for (DWORD i = 0; i < *nFaceNormals; ++i) {
int count = *faceNormals++;
m->AddNormalFace((int *)faceNormals,count);
faceNormals += count;
}
return hr;
}
/*********************************************************
Loads a mesh face materials
**********************************************************/
HRESULT CKXReader::LoadMeshMaterials(LPDIRECTXFILEDATA CurData,VirtoolsTransitionMesh* m)
{
HRESULT hr;
DWORD* nMaterials = 0;
DWORD* nFaceIndexes = 0;
DWORD* FaceIndexes = 0;
DWORD Size;
XArray<CKMaterial*> materials;
if (FAILED( hr = CurData->GetData("nMaterials",&Size, (void **)&nMaterials))) return hr;
if (FAILED( hr = CurData->GetData("nFaceIndexes",&Size, (void **)&nFaceIndexes))) return hr;
if (FAILED( hr = CurData->GetData("FaceIndexes",&Size, (void **)&nFaceIndexes))) return hr;
LPDIRECTXFILEOBJECT NextObject = NULL;
// Enumerate child objects. (We're expecting to find material objects
while (SUCCEEDED(CurData->GetNextObject(&NextObject))) {
// ok found a material we add it to our temp list
materials.PushBack(LoadMaterial(NextObject));
SAFERELEASE(NextObject);
}
if (*nMaterials == 1) {
// If only one material we can apply it to all faces
for (int i=0;i<m->m_Faces.Size();++i)
m->SetFaceMaterial(i,materials[0]);
} else
for (DWORD i = 0; i < *nFaceIndexes; ++i,++FaceIndexes) {
m->SetFaceMaterial(i,materials[*FaceIndexes]);
}
return hr;
}
/*******************************************
Loads bone information
If a skin does not yet exist on the parent entity we
create it, otherwise we had the bone information
and set the weights on the concerned vertices
*******************************************/
HRESULT CKXReader::LoadSkinBone(LPDIRECTXFILEDATA CurData,VirtoolsTransitionMesh* m,CK3dEntity* Parent)
{
HRESULT hr = S_OK;
char** transformNodeName = NULL;
DWORD* nWeights = 0;
DWORD* vertexIndices = 0;
float* weights = 0;
VxMatrix* matrixOffset;
DWORD Size;
if (!Parent) return S_OK;
if (FAILED( hr = CurData->GetData("transformNodeName",&Size, (void **)&transformNodeName))) return hr;
if (FAILED( hr = CurData->GetData("nWeights",&Size, (void **)&nWeights))) return hr;
if (FAILED( hr = CurData->GetData("vertexIndices",&Size, (void **)&vertexIndices))) return hr;
if (FAILED( hr = CurData->GetData("weights",&Size, (void **)&weights))) return hr;
if (FAILED( hr = CurData->GetData("matrixOffset",&Size, (void **)&matrixOffset))) return hr;
CKSkin* Skin = Parent->GetSkin();
if (!Skin) {
Skin = Parent->CreateSkin();
// Inital Matrix
Skin->SetObjectInitMatrix(Parent->GetWorldMatrix());
// The correct number of vertices has not yet been set on the skin,
// we set it and update the vertex original position by the way...
int VCount = m->m_VirtoolsVertices.Size();
Skin->SetVertexCount(VCount);
for (int i=0; i<VCount; ++i) {
CKSkinVertexData* VData = Skin->GetVertexData(i);
VData->SetInitialPos(m->m_VirtoolsVertices[i].Pos);
}
}
//-- Find the Frame that represent the bone
XCKObjectsHashTableIt it=m_FrameHashTable.Find(XString(*transformNodeName));
CK3dEntity* Bone = (it==m_FrameHashTable.End()) ? NULL : (CK3dEntity*)*it;
//-- no vertices are influcenced by this bone
if (!*nWeights) return hr;
int BoneIndex = Skin->GetBoneCount();
//-- Add this bone to the skin
Skin->SetBoneCount(BoneIndex+1);
if (!Bone)
{
//Bone may not have been loaded yet
m_BonesName.PushBack(XString(*transformNodeName));
m_BonesIndex.PushBack(BoneIndex);
m_Skins.PushBack(Skin);
}
else
{
CKSkinBoneData* BoneData = Skin->GetBoneData(BoneIndex);
BoneData->SetBone(Bone);
BoneData->SetBoneInitialInverseMatrix(Bone->GetInverseWorldMatrix());
}
// We are not sure that the virtools mesh contains the same number
// of vertices than the .X Mesh, but we can have the table of
// generated vertices for a given vertex in the .X Mesh...
for (DWORD i = 0; i< *nWeights; ++i,++vertexIndices,++weights) {
const IntArray& newindices = m->GetGeneratedIndices((int)*vertexIndices);
for (int* vi = newindices.Begin(); vi < newindices.End(); ++vi) {
// Need to add a bone on this vertex
CKSkinVertexData* VData = Skin->GetVertexData(*vi);
int VBoneCount = VData->GetBoneCount();
// Add the bone (with its weight) to this vertex
VData->SetBoneCount(VBoneCount+1);
VData->SetBone(VBoneCount,BoneIndex);
VData->SetWeight(VBoneCount,*weights);
}
}
return hr;
}
/*********************************************
Loads a Mesh representation
*********************************************/
HRESULT CKXReader::LoadMesh(LPDIRECTXFILEOBJECT CurObject,CK3dEntity* Parent)
{
HRESULT hr = S_OK;
if (m_LoadFlags & CK_LOAD_GEOMETRY) {
// Reference or data ?
LPDIRECTXFILEDATA CurData = NULL;
LPDIRECTXFILEDATAREFERENCE CurDataRef = NULL;
XString MeshName = GetFileObjectName(CurObject);
if (SUCCEEDED(CurObject->QueryInterface(IID_IDirectXFileDataReference,(LPVOID *)&CurDataRef))) {
// REFERENCE : we find the mesh from its name and set
// it to the Parent entity
if (SUCCEEDED(CurDataRef->Resolve(&CurData))) {
MeshName = GetFileObjectName(CurData);
XCKObjectsHashTableIt it=m_MeshHashTable.Find(MeshName);
CKMesh* mesh = (it==m_MeshHashTable.End()) ? NULL : (CKMesh*)*it;
Parent->SetCurrentMesh(mesh);
SAFERELEASE(CurData);
}
SAFERELEASE(CurDataRef);
} else
if (SUCCEEDED(CurObject->QueryInterface(IID_IDirectXFileData,(LPVOID *)&CurData))) {
// DATA : we have to create a mesh
DWORD Size;
// Mesh Data
DWORD* nVertices = 0;
VxVector* vertices = 0;
DWORD* nFaces = 0;
DWORD** faces = 0;
BOOL Generated = FALSE;
// Load vertex and faces data (if some of them are not here we fail...)
if (FAILED(hr = CurData->GetData("nVertices",&Size, (void **)&nVertices))) RELEASEEXIT(hr,CurData);
if (FAILED(hr = CurData->GetData("vertices",&Size, (void **)&vertices))) RELEASEEXIT(hr,CurData);
if (FAILED(hr = CurData->GetData("nFaces",&Size, (void **)&nFaces))) RELEASEEXIT(hr,CurData);
if (FAILED(hr = CurData->GetData("faces",&Size, (void **)&faces))) RELEASEEXIT(hr,CurData);
VirtoolsTransitionMesh TransitionMesh(m_VirtoolsExport);
//------- Add Vertices position
for (DWORD i=0;i<*nVertices;++i,++vertices)
TransitionMesh.AddPosition(*vertices);
//------- Add faces
for (DWORD i=0;i<*nFaces;++i) {
int count = (int)*faces++;
TransitionMesh.AddFace((int *)faces,count,NULL);
faces += count;
}
LPDIRECTXFILEDATA NextData = NULL;
LPDIRECTXFILEOBJECT NextObject = NULL;
// Enumerate child objects. (We're expecting to find texture coords, vertex colors or material list
while (SUCCEEDED(CurData->GetNextObject(&NextObject))) {
// Query the child for it's FileData
if SUCCEEDED(NextObject->QueryInterface(IID_IDirectXFileData,(LPVOID *)&NextData)) {
const GUID* DataType = NULL;
if (SUCCEEDED(NextData->GetType(&DataType))) {
if (TID_D3DRMMeshFaceWraps == *DataType) {
// Not supported for the moment, Skip...
} else
if (TID_D3DRMMeshVertexColors == *DataType) {
//****** Load vertex Colors
LoadMeshVertexColors(NextData,&TransitionMesh);
} else
if (TID_D3DRMMeshTextureCoords == *DataType) {
//****** Load texture coordinates
LoadMeshTextureCoords(NextData,&TransitionMesh);
} else
if (TID_D3DRMMeshMaterialList == *DataType) {
//****** Load material list
LoadMeshMaterials(NextData,&TransitionMesh);
} else
if (TID_D3DRMMeshNormals == *DataType) {
//****** Load material list
LoadMeshNormals(NextData,&TransitionMesh);
} else
if (TID_SkinWeights == *DataType) {
//----- To load the skin data we need to
//----- have the appropriate number of
//----- virtools vertices computed
if (!Generated) {
TransitionMesh.GenerateVirtoolsData();
Generated = TRUE;
}
//****** Load bone info
LoadSkinBone(NextData,&TransitionMesh,Parent);
} else
if (TID_XSkinMeshHeader == *DataType) {
// No need to load this
}
}
SAFERELEASE(NextData);
}
SAFERELEASE(NextObject);
}
// Rename the mesh if necessary
if (MeshName=="")
if (Parent) {
MeshName = Parent->GetName();
MeshName << "_Mesh";
} else {
MeshName << GetUnnamed();
}
if (!Generated)
TransitionMesh.GenerateVirtoolsData();
// And finally create the mesh
CKMesh* Mesh = m_VirtoolsExport->AddMesh(&TransitionMesh,MeshName.CStr());
m_MeshHashTable.Insert(MeshName,Mesh);
if (Parent) {
if (Parent->GetMeshCount()) {
// A mesh has already been set on this entity
// we need to create a new frame to hold this one
CK3dEntity* NewFrame = NULL;
if (CharacterMode())
NewFrame = (CK3dEntity*)m_VirtoolsExport->AddCharacterBodyPart(MeshName.CStr());
else
NewFrame = (CK3dEntity*)m_VirtoolsExport->Add3dObject(MeshName.CStr());
NewFrame->SetParent(Parent,FALSE);
NewFrame->SetCurrentMesh(Mesh);
} else {
Parent->SetCurrentMesh(Mesh);
}
}
SAFERELEASE(CurData);
}
}
return hr;
}
/***************************************************
Loads an animation Set (group of sub animations)
****************************************************/
HRESULT CKXReader::LoadAnimationSet(LPDIRECTXFILEDATA CurData)
{
HRESULT hr = S_OK;
XString AnimationName = GetFileObjectName(CurData);
if (AnimationName=="") {
CKPathSplitter Splitter(m_FileName.Str());
AnimationName = Splitter.GetName();
}
m_VirtoolsExport->CreateGlobalAnimation(AnimationName.Str());
LPDIRECTXFILEDATA NextData = NULL;
LPDIRECTXFILEOBJECT NextObject = NULL;
// Enumerate child objects. (We're expecting to find animations
while (SUCCEEDED(CurData->GetNextObject(&NextObject))) {
// Query the child for it's FileData
if SUCCEEDED(NextObject->QueryInterface(IID_IDirectXFileData,(LPVOID *)&NextData)) {
const GUID* DataType = NULL;
if (SUCCEEDED(NextData->GetType(&DataType))) {
if (TID_D3DRMAnimation == *DataType) {
hr = LoadAnimation(NextData);
}
}
SAFERELEASE(NextData);
}
SAFERELEASE(NextObject);
}
return hr;
}
/**************************************************************
+ Adds a list of position keys to the animation
+ Only linear animation are supported in .x files so we directly
use the CKObjectAnimation AddPosition method instead of using CKAnimController
******************************************************************/
void CKXReader::LoadAnimationPositionKey(CKObjectAnimation* anim,DWORD KeyCount,DWORD* keys)
{
XFileVectorKey* vkeys = (XFileVectorKey*)keys;
for (DWORD i = 0; i< KeyCount; ++i,++vkeys) {
m_AnimationLength = max (m_AnimationLength,(float)vkeys->Time);
anim->AddPositionKey((float)vkeys->Time,&vkeys->Key);
}
}
/**************************************************************
+ Adds a list of rotation keys to the animation
+ Only linear animation are supported in .x files so we directly
use the CKObjectAnimation AddRtoationKey method instead of using CKAnimController
+ Warning .X file store quaternions in this order : w,x,y,z
******************************************************************/
void CKXReader::LoadAnimationRotationKey(CKObjectAnimation* anim,DWORD KeyCount,DWORD* keys)
{
XFileRotateKey* rkeys = (XFileRotateKey*)keys;
for (DWORD i = 0; i< KeyCount; ++i,++rkeys) {
m_AnimationLength = max (m_AnimationLength,(float)rkeys->Time);
VxQuaternion quat(rkeys->x,rkeys->y,rkeys->z,rkeys->w);
anim->AddRotationKey((float)rkeys->Time,&quat);
}
}
/**************************************************************
+ Adds a list of scale keys to the animation
+ Only linear animation are supported in .x files so we directly
use the CKObjectAnimation AddScaleKey method instead of using CKAnimController
******************************************************************/
void CKXReader::LoadAnimationScaleKey(CKObjectAnimation* anim,DWORD KeyCount,DWORD* keys)
{
XFileVectorKey* vkeys = (XFileVectorKey*)keys;
for (DWORD i = 0; i< KeyCount; ++i,++vkeys) {
m_AnimationLength = max (m_AnimationLength,(float)vkeys->Time);
anim->AddScaleKey((float)vkeys->Time,&vkeys->Key);
}
}
/**************************************************************
+ Adds a list of matrix keys to the animation
+ Matrix keys need to be converted to standard PRS keys
*****************************************************************/
void CKXReader::LoadAnimationMatrixKey(CKObjectAnimation* anim,DWORD KeyCount,DWORD* keys)
{
XFileMatrixKey* mkeys = (XFileMatrixKey*)keys;
for (DWORD i = 0; i< KeyCount; ++i,++mkeys) {
m_AnimationLength = max (m_AnimationLength,(float)mkeys->Time);
float time = (float)mkeys->Time;
VxMatrix Mat = mkeys->Key;
VxQuaternion q,qs;
VxVector p,s;
Vx3DDecomposeMatrixTotal(Mat,q,p,s,qs);
anim->AddRotationKey(time,&q);
anim->AddScaleKey(time,&s);
anim->AddPositionKey(time,&p);
// Matrix (especially coming from bipeds) may contain some shearing)
anim->AddScaleAxisKey(time,&qs);
}
}
/*********************************************************
***********************************************************/
HRESULT CKXReader::LoadAnimation(LPDIRECTXFILEDATA CurData)
{
LPDIRECTXFILEDATA NextData = NULL;
LPDIRECTXFILEDATAREFERENCE NextDataRef = NULL;
LPDIRECTXFILEOBJECT NextObject = NULL;
XString EntityName="";
CK3dEntity* Entity = NULL;
CKObjectAnimation* Animation = (CKObjectAnimation*)m_Context->CreateObject(CKCID_OBJECTANIMATION,NULL,m_CreationOptions);
// Enumerate child objects. (We're expecting to find animation keys and a reference
// to the animated frame
while (SUCCEEDED(CurData->GetNextObject(&NextObject))) {
// Query the child for it's FileData
if SUCCEEDED(NextObject->QueryInterface(IID_IDirectXFileData,(LPVOID *)&NextData)) {
const GUID* DataType = NULL;
// Enemerate animation keys
if (SUCCEEDED(NextData->GetType(&DataType))) {
if (TID_D3DRMAnimationKey == *DataType) {
DWORD* keyType = NULL;
DWORD* nKeys = NULL;
DWORD* keys = NULL;
DWORD Size;
NextData->GetData("keyType",&Size, (void **)&keyType);
NextData->GetData("nKeys",&Size, (void **)&nKeys);
NextData->GetData("keys",&Size, (void **)&keys);
if (*nKeys) {
switch (*keyType) {
case 0:LoadAnimationRotationKey(Animation,*nKeys,keys); break;
case 1:LoadAnimationScaleKey(Animation,*nKeys,keys); break;
case 2:LoadAnimationPositionKey(Animation,*nKeys,keys); break;
case 4:LoadAnimationMatrixKey(Animation,*nKeys,keys); break;
}
}
}
}
SAFERELEASE(NextData);
} else
if SUCCEEDED(NextObject->QueryInterface(IID_IDirectXFileDataReference,(LPVOID *)&NextDataRef)) {
//--- Get the reference to the target frame
if (SUCCEEDED(NextDataRef->Resolve(&NextData))) {
EntityName = GetFileObjectName(NextData);
XCKObjectsHashTableIt it=m_FrameHashTable.Find(EntityName);
Entity = (it==m_FrameHashTable.End()) ? NULL : (CK3dEntity*)*it;
SAFERELEASE(NextData);
}
SAFERELEASE(NextDataRef);
}
SAFERELEASE(NextObject);
}
//----------------------
//-- Set the target entity and add to exporter
Animation->SetName(EntityName.Str());
Animation->Set3dEntity(Entity);
m_VirtoolsExport->AddObjectAnimation(Animation);
return S_OK;
}
/*********************************************
Loads top level file data (frame , mesh,material,animation sets,etc..)
*********************************************/
HRESULT CKXReader::LoadFileData(LPDIRECTXFILEDATA CurData,CK3dEntity* Parent)
{
HRESULT hr = S_OK;
const GUID* DataType;
// Get the type of the object
hr = CurData->GetType(&DataType);
if (FAILED(hr)) return hr;
if (TID_D3DRMMaterial == *DataType) {
if (m_LoadFlags & CK_LOAD_GEOMETRY) {
LoadMaterial(CurData);
}
} else
if (TID_D3DRMMesh == *DataType) {
if (m_LoadFlags & CK_LOAD_GEOMETRY) {
hr = LoadMesh(CurData,Parent);
}
} else
if (TID_D3DRMFrameTransformMatrix == *DataType) {
if (m_LoadFlags & CK_LOAD_GEOMETRY) {
hr = LoadTransformationMatrix(CurData,Parent);
}
} else
if (TID_D3DRMAnimationSet == *DataType) {
hr = LoadAnimationSet(CurData);
} else
if (TID_D3DRMAnimation == *DataType) {
hr = LoadAnimation(CurData);
} else
if (TID_D3DRMFrame == *DataType) {
//------ A child frame -------
LPDIRECTXFILEDATA NextData = NULL;
LPDIRECTXFILEOBJECT NextObject = NULL;
CK3dEntity* NewFrame = NULL;
if (m_LoadFlags & CK_LOAD_GEOMETRY) {
XString FrameName = GetFileObjectName(CurData);
if (CharacterMode())
NewFrame = (CK3dEntity*)m_VirtoolsExport->AddCharacterBodyPart(FrameName.Str());
else
NewFrame = (CK3dEntity*)m_VirtoolsExport->Add3dObject(FrameName.Str());
m_FrameHashTable.Insert(FrameName,NewFrame);
NewFrame->SetParent(Parent);
}
// Enumerate child objects.
while (SUCCEEDED(CurData->GetNextObject(&NextObject))) {
// Query the child for it's FileData
if (SUCCEEDED(NextObject->QueryInterface(IID_IDirectXFileData,(LPVOID *)&NextData))) {
LoadFileData(NextData,NewFrame);
SAFERELEASE(NextData);
}
SAFERELEASE(NextObject);
}
} else {
// Unsuported Data Type
hr = S_OK;
}
return hr;
}