/*************************************************************************/ /* 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;iGetBoneData(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 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;im_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; iGetVertexData(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; }