958 lines
31 KiB
C++
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;
|
|
}
|
|
|