//Frist processing bone weights
BOOL ProcessingBoneWeights(INode* pNode,INode* pRoot,BoneData* BD)
{
if((!pNode)||(!IsMesh(pNode)))
return FALSE;
Modifier* pmf=GetPhysiqueMod(pNode);
if(pmf)
GetPhysiqueWeights(pNode, pRoot, pmf, BD);
else
{
pmf = GetSkinMod(pNode);
if (pmf)
GetSkinWeights(pNode,pMeshIdx,pRoot, pmf, BD);
}
int num=pNode->NumberOfChildren();
for(int n=0;n<num;n++)
{
ProcessingBoneWeights(pNode->GetChildNode(n),pRoot,BD);
}
return TRUE;
}
//here just take with Physique and Skin Modify ....
static Modifier* GetPhysiqueMod(INode* pNode)
{
Object* pObj=pNode->GetObjectRef();
if(!pObj)
return NULL;
while(pObj->SuperClassID()==GEN_DERIVOB_CLASS_ID)
{
IDerivedObject* pDerivedObj = static_cast<IDerivedObject*>(pObj);
int modStackIndex=0;
while(modStackIndex<pDerivedObj->NumModifiers())
{
Modifier* mod=pDerivedObj->GetModifier(modStackIndex);
if(mod->ClassID()==Class_ID(PHYSIQUE_CLASS_ID_A, PHYSIQUE_CLASS_ID_B))
return mod;
modStackIndex++;
}
pObj=pDerivedObj->GetObjRef();
}
return NULL;
}
static Modifier* GetSkinMod(INode* pNode)
{
Object* pObj=pNode->GetObjectRef();
if(!pObj)
return NULL;
while(pObj->SuperClassID()==GEN_DERIVOB_CLASS_ID)
{
IDerivedObject* pDerivedObj = static_cast<IDerivedObject*>(pObj);
int modStackIndex=0;
while(modStackIndex<pDerivedObj->NumModifiers())
{
Modifier* mod=pDerivedObj->GetModifier(modStackIndex);
if(mod->ClassID()==SKIN_CLASSID)
return mod;
modStackIndex++;
}
pObj=pDerivedObj->GetObjRef();
}
return NULL;
}
// Get an index from a node pointer
int GetBoneIndex(INode *pRoot, INode *pNode)
{
if(!IsBone(pNode))
return -1;
int boneCount = 0;
return RecursiveGetBoneIndex(pRoot, pNode, boneCount);
}
//if there is more than one mesh ,we will use pMeshIdx
BOOL GetSkinWeights(INode* pNode,int* pMeshIdx,INode* pRoot,Modifier* pMod,BoneData* BD)
{
ISkin* skin = (ISkin*)pMod->GetInterface(I_SKIN);
if(skin)
{
ISkinContextData* skincontext = skin->GetContextInterface(pNode);
if(skincontext)
{
int numVert=skincontext->GetNumPoints();
for(int i=0;i<numVert;i++)
{
int numBones=skincontext->GetNumAssignedBones(i);
for(int j=0;j<numBones;j++)
{
INode* bone=skin->GetBone(skincontext->GetAssignedBone(i,j));//do not use j,but use GetAssignedBone(i,j)
int boneIdx;
if(bone)
{
boneIdx=GetBoneIndex(pRoot, bone);
if(boneIdx==-1)
continue;
}
else
continue;
BoneWeight_hdr wData;
wData.meshIdx=*pMeshIdx;
wData.vertIdx=i;
wData.weight=skincontext->GetBoneWeight(i,j);
bool notfound = true;
for(int v=0;notfound&&v<BD[boneIdx].weightVect.size();v++)
{
if(BD[boneIdx].weightVect[v].vertIdx==wData.vertIdx&&BD[boneIdx].weightVect[v].meshIdx==wData.meshIdx)
{
BD[boneIdx].weightVect[v].weight += wData.weight;
notfound = false;
}
}
if(notfound)
{
BD[boneIdx].weightVect.push_back(wData);
BD[boneIdx].boneHdr.vertexCnt=BD[boneIdx].weightVect.size();
}
}
}
}
pMod->ReleaseInterface(I_SKIN, skin);
}
return TRUE;
}
BOOL GetPhysiqueWeights(INode *pNode, int* pMeshIdx,INode *pRoot, Modifier *pMod, BoneData *BD)
{
IPhysiqueExport* phyInterface=(IPhysiqueExport*)pMod->GetInterface(I_PHYINTERFACE);
if(phyInterface)
{
// create a ModContext Export Interface for the specific node of the Physique Modifier
IPhyContextExport *modContextInt = (IPhyContextExport*)phyInterface->GetContextInterface(pNode);
// needed by vertex interface (only Rigid one supported for now)
modContextInt->ConvertToRigid(TRUE);
// more than a single bone per vertex
modContextInt->AllowBlending(TRUE);
if(modContextInt)
{
int totalVtx=modContextInt->GetNumberVertices();
for(int i=0;i<totalVtx;i++)
{
IPhyVertexExport* vtxInterface=(IPhyVertexExport*)modContextInt->GetVertexInterface(i);
if(vtxInterface)
{
int vertType=vtxInterface->GetVertexType();
if(vertType==RIGID_TYPE)
{
INode* boneNode=((IPhyRigidVertex*)vtxInterface)->GetNode();
int boneIdx=GetBoneIndex(pRoot, boneNode);
BoneWeight_hdr wData;
wData.meshIdx=*pMeshIdx;
wData.vertIdx=i;
wData.weight=1.0f;
BD[boneIdx].weightVect.push_back(wData);
BD[boneIdx].boneHdr.vertexCnt=BD[boneIdx].weightVect.size();
}
else if(vertType==RIGID_BLENDED_TYPE)
{
IPhyBlendedRigidVertex *vtxBlendedInt = (IPhyBlendedRigidVertex*)vtxInterface;
for(int j=0;j<vtxBlendedInt->GetNumberNodes();j++)
{
INode* boneNode=vtxBlendedInt->GetNode(j);
int boneIdx=GetBoneIndex(pRoot, boneNode);
BoneWeight_hdr wData;
wData.meshIdx=*pMeshIdx;
wData.vertIdx=i;
wData.weight=vtxBlendedInt->GetWeight(j);
//check vertex existence for this bone
bool notfound = true;
for(int v=0;notfound&&v<BD[boneIdx].weightVect.size();v++)
{
if(BD[boneIdx].weightVect[v].vertIdx==wData.vertIdx&&BD[boneIdx].weightVect[v].meshIdx==wData.meshIdx)
{
BD[boneIdx].weightVect[v].weight += wData.weight;
notfound = false;
}
}
if(notfound)
{
BD[boneIdx].weightVect.push_back(wData);
BD[boneIdx].boneHdr.vertexCnt=BD[boneIdx].weightVect.size();
}
}
}
}
}
phyInterface->ReleaseContextInterface(modContextInt);
}
pMod->ReleaseInterface(I_PHYINTERFACE, phyInterface);
}
return FALSE;
}
//===========================================
Matrix3 GetBoneTM(INode *pNode, TimeValue t)
{
Matrix3 tm(1);
tm = pNode->GetNodeTM(t);
tm.NoScale();
return tm;
}
// ============================================================================
// Recursive iterator to get a bone index, used with GetBoneIndex
int RecursiveGetBoneIndex(INode *pRoot, INode *pNodeTest, int &boneCount)
{
int boneIdx = -1;
if(IsBone(pRoot))
{
boneIdx = boneCount;
boneCount++;
if(pRoot == pNodeTest)
return boneIdx;
}
// recurse child nodes
for(int i = 0; i < pRoot->NumberOfChildren(); i++)
{
int boneIdx = RecursiveGetBoneIndex(pRoot->GetChildNode(i), pNodeTest, boneCount);
if(boneIdx >= 0)
return boneIdx;
}
return -1;
}
// Get the number of direct child bones of a node
int GetChildBoneCount(INode *pNode)
{
int count = 0;
for(int i = 0; i < pNode->NumberOfChildren(); i++)
{
if(IsBone(pNode->GetChildNode(i)))
count++;
}
return count;
}
int ProcessBoneStruct(INode *pNode, INode *pRoot,int parentIdx, BoneData* BD)
{
if(IsBone(pNode))
{
int currIdx=GetBoneIndex(pRoot,pNode);
assert(-1!=currIdx);
Bone_hdr &boneHdr=BD[currIdx].boneHdr;
// get the bones inverse base matrix at time 0
Matrix3 tm=GetBoneTM(pNode,0);
tm.Invert();
MAXtoGL(tm,boneHdr.inverseOrientationTM);
boneHdr.parentIdx=parentIdx;
boneHdr.childCnt=GetChildBoneCount(pNode);
if(boneHdr.childCnt>0)
{
BD[currIdx].childIdxVect.reserve(boneHdr.childCnt);
for(int i=0;i<pNode->NumberOfChildren();i++)
{
int cIdx=ProcessBoneStruct(pNode->GetChildNode(i),pRoot,currIdx,BD);
if(cIdx>=0)
BD[currIdx].childIdxVect.push_back(cIdx);
}
}
assert(BD[currIdx].childIdxVect.size()==BD[currIdx].boneHdr.childCnt);
return currIdx;
}
else
{
for (int i=0; i<pNode->NumberOfChildren(); ++i)
ProcessBoneStruct(pNode->GetChildNode(i),pRoot,-1, BD);
return -1;
}
}
// used by GetBoneByIndex
static bool BuildIter(INode* pnode, INode** const Iterator, int& currIdx) {
if(IsBone(pnode)){
Iterator[currIdx++] = pnode;
}
for(int i = 0; i < pnode->NumberOfChildren(); i++) {
BuildIter(pnode->GetChildNode(i),Iterator,currIdx);
}
return true;
}
// Get bone pointer from an index, this should get passed the root node
INode* GetBoneByIndex(INode* const pRoot, int index) {
INode* bone = NULL;
const int bone_cnt = CountBones(pRoot);
if (index>=bone_cnt)
return NULL;
INode** const Iterator = new INode* [bone_cnt];
int currIdx=0;
BuildIter(pRoot,Iterator,currIdx);
assert(currIdx==bone_cnt);
bone = Iterator[index];
assert (GetBoneIndex(pRoot,bone)==index);
delete [] Iterator;
assert (IsBone(bone));
return bone;
}
int ProcessBoneAnim (INode *pRoot, Interval range, ULONG sampleD, BoneData* BD)
{
int keycnt=0;
int totalbones=CountBones(pRoot);
const ULONG start = TicksToMilliSec(range.Start());
const ULONG end = TicksToMilliSec(range.End());
if(!totalbones)
return 0;
for(int idx=0;idx<totalbones;idx++)
{
INode *pBone=GetBoneByIndex(pRoot,idx);
assert(IsBone(pBone));
ULONG msec=0;
for(msec=start;msec<end+sampleD;msec+=sampleD)
{
BoneKey_hdr keyHdr;
memset(&keyHdr,0,sizeof(BoneKey_hdr));
if(msec>end)
keyHdr.time=end;
else
keyHdr.time=msec;
Matrix3 tm;
TimeValue t;
t=MilliSecToTicks(msec);
tm=GetBoneTM(pBone,t);
MAXtoGL(tm);
Point3 pt=tm.GetTrans();
keyHdr.pos[0]=pt.x;
keyHdr.pos[1]=pt.y;
keyHdr.pos[2]=pt.z;
Quat quat(tm);
quat.Normalize();
keyHdr.quat[0] = quat.x;
keyHdr.quat[1] = quat.y;
keyHdr.quat[2] = quat.z;
keyHdr.quat[3] = quat.w;
BD[idx].keyVect.push_back(keyHdr);
}
}
keycnt = BD[0].keyVect.size();
return keycnt;
}