You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
436 lines
9.3 KiB
436 lines
9.3 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// $NoKeywords: $ |
|
// |
|
//=============================================================================// |
|
|
|
#include "MAX.H" |
|
#include "DECOMP.H" |
|
#include "STDMAT.H" |
|
#include "ANIMTBL.H" |
|
#include "istdplug.h" |
|
#include "phyexp.h" |
|
#include "BonesPro.h" |
|
|
|
#include "vweightexprc.h" |
|
#include "vweightexp.h" |
|
#include "vweightimp.h" |
|
|
|
|
|
// Save for use with dialogs |
|
static HINSTANCE hInstance; |
|
|
|
// We just need one of these to hand off to 3DSMAX. |
|
static VWeightExportClassDesc VWeightExportCD; |
|
static VWeightImportClassDesc VWeightImportCD; |
|
|
|
|
|
//=================================================================== |
|
// Required plug-in export functions |
|
// |
|
BOOL WINAPI DllMain( HINSTANCE hinstDLL, ULONG fdwReason, LPVOID lpvReserved) |
|
{ |
|
static int fFirstTimeHere = TRUE; |
|
if (fFirstTimeHere) |
|
{ |
|
fFirstTimeHere = FALSE; |
|
hInstance = hinstDLL; |
|
} |
|
return TRUE; |
|
} |
|
|
|
|
|
EXPORT_THIS int LibNumberClasses(void) |
|
{ |
|
return 2; |
|
} |
|
|
|
|
|
EXPORT_THIS ClassDesc *LibClassDesc(int iWhichClass) |
|
{ |
|
switch(iWhichClass) |
|
{ |
|
case 0: return &VWeightExportCD; |
|
case 1: return &VWeightImportCD; |
|
default: return 0; |
|
} |
|
} |
|
|
|
|
|
EXPORT_THIS const TCHAR *LibDescription() |
|
{ |
|
return _T("Valve VVW Plug-in."); |
|
} |
|
|
|
|
|
EXPORT_THIS ULONG LibVersion() |
|
{ |
|
return VERSION_3DSMAX; |
|
} |
|
|
|
|
|
|
|
//=================================================================== |
|
// Utility functions |
|
// |
|
|
|
int AssertFailedFunc(char *sz) |
|
{ |
|
MessageBox(GetActiveWindow(), sz, "Assert failure", MB_OK); |
|
int Set_Your_Breakpoint_Here = 1; |
|
return 1; |
|
} |
|
|
|
|
|
//================================================================= |
|
// Methods for CollectModelTEP |
|
// |
|
Modifier *FindPhysiqueModifier (INode *nodePtr) |
|
{ |
|
// Get object from node. Abort if no object. |
|
Object *ObjectPtr = nodePtr->GetObjectRef(); |
|
if (!ObjectPtr) return NULL; |
|
|
|
// Is derived object ? |
|
if (ObjectPtr->SuperClassID() == GEN_DERIVOB_CLASS_ID) |
|
{ |
|
// Yes -> Cast. |
|
IDerivedObject *DerivedObjectPtr = static_cast<IDerivedObject*>(ObjectPtr); |
|
|
|
// Iterate over all entries of the modifier stack. |
|
int ModStackIndex = 0; |
|
while (ModStackIndex < DerivedObjectPtr->NumModifiers()) |
|
{ |
|
// Get current modifier. |
|
Modifier *ModifierPtr = DerivedObjectPtr->GetModifier(ModStackIndex); |
|
|
|
// Is this Physique ? |
|
if (ModifierPtr->ClassID() == Class_ID( PHYSIQUE_CLASS_ID_A, PHYSIQUE_CLASS_ID_B) ) |
|
{ |
|
// Yes -> Exit. |
|
return ModifierPtr; |
|
} |
|
// Next modifier stack entry. |
|
ModStackIndex++; |
|
} |
|
} |
|
// Not found. |
|
return NULL; |
|
} |
|
|
|
Modifier *FindBonesProModifier (INode *nodePtr) |
|
{ |
|
// Get object from node. Abort if no object. |
|
Object *ObjectPtr = nodePtr->GetObjectRef(); |
|
if (!ObjectPtr) return NULL; |
|
|
|
// Is derived object ? |
|
if (ObjectPtr->SuperClassID() == GEN_DERIVOB_CLASS_ID) |
|
{ |
|
// Yes -> Cast. |
|
IDerivedObject *DerivedObjectPtr = static_cast<IDerivedObject*>(ObjectPtr); |
|
|
|
// Iterate over all entries of the modifier stack. |
|
int ModStackIndex = 0; |
|
while (ModStackIndex < DerivedObjectPtr->NumModifiers()) |
|
{ |
|
// Get current modifier. |
|
Modifier *ModifierPtr = DerivedObjectPtr->GetModifier(ModStackIndex); |
|
|
|
// Is this Bones Pro OSM? |
|
if (ModifierPtr->ClassID() == BP_CLASS_ID_OSM ) |
|
{ |
|
// Yes -> Exit. |
|
return ModifierPtr; |
|
} |
|
// Is this Bones Pro WSM? |
|
if (ModifierPtr->ClassID() == BP_CLASS_ID_WSM ) |
|
{ |
|
// Yes -> Exit. |
|
return ModifierPtr; |
|
} |
|
// Next modifier stack entry. |
|
ModStackIndex++; |
|
} |
|
} |
|
// Not found. |
|
return NULL; |
|
} |
|
|
|
|
|
|
|
//======================================================================== |
|
// Utility functions for getting/setting the personal "node index" property. |
|
// NOTE: I'm storing a string-property because I hit a 3DSMax bug in v1.2 when I |
|
// NOTE: tried using an integer property. |
|
// FURTHER NOTE: those properties seem to change randomly sometimes, so I'm |
|
// implementing my own. |
|
|
|
typedef struct |
|
{ |
|
char szNodeName[MAX_NAME_CHARS]; |
|
} NAMEMAP; |
|
const int MAX_NAMEMAP = 512; |
|
static NAMEMAP g_NameMap[MAX_NAMEMAP]; |
|
static int g_cNameMap = 0; |
|
|
|
void ResetINodeMap( void ) |
|
{ |
|
g_cNameMap = 0; |
|
} |
|
|
|
int BuildINodeMap(INode *pnode) |
|
{ |
|
if (!FUndesirableNode(pnode)) |
|
{ |
|
AddINode(pnode); |
|
} |
|
|
|
// For each child of this node, we recurse into ourselves |
|
// until no more children are found. |
|
for (int c = 0; c < pnode->NumberOfChildren(); c++) |
|
{ |
|
BuildINodeMap(pnode->GetChildNode(c)); |
|
} |
|
|
|
return g_cNameMap; |
|
} |
|
|
|
|
|
int GetIndexOfNodeName(char *szNodeName, BOOL fAssertPropExists) |
|
{ |
|
for (int inm = 0; inm < g_cNameMap; inm++) |
|
{ |
|
if (FStrEq(g_NameMap[inm].szNodeName, szNodeName)) |
|
{ |
|
return inm; |
|
} |
|
} |
|
|
|
return -1; |
|
} |
|
|
|
int GetIndexOfINode( INode *pnode, BOOL fAssertPropExists ) |
|
{ |
|
return GetIndexOfNodeName( pnode->GetName(), fAssertPropExists ); |
|
} |
|
|
|
void AddINode( INode *pnode ) |
|
{ |
|
TSTR strNodeName(pnode->GetName()); |
|
for (int inm = 0; inm < g_cNameMap; inm++) |
|
{ |
|
if (FStrEq(g_NameMap[inm].szNodeName, (char*)strNodeName)) |
|
{ |
|
return; |
|
} |
|
} |
|
|
|
ASSERT_MBOX(g_cNameMap < MAX_NAMEMAP, "NAMEMAP is full"); |
|
strcpy(g_NameMap[g_cNameMap++].szNodeName, (char*)strNodeName); |
|
} |
|
|
|
|
|
//============================================================= |
|
// Returns TRUE if a node should be ignored during tree traversal. |
|
// |
|
BOOL FUndesirableNode(INode *pnode) |
|
{ |
|
// Get Node's underlying object, and object class name |
|
Object *pobj = pnode->GetObjectRef(); |
|
|
|
if (!pobj) |
|
return TRUE; |
|
// Don't care about lights, dummies, and cameras |
|
if (pobj->SuperClassID() == CAMERA_CLASS_ID) |
|
return TRUE; |
|
if (pobj->SuperClassID() == LIGHT_CLASS_ID) |
|
return TRUE; |
|
if (!strstr(pnode->GetName(), "Bip01" )) |
|
return TRUE; |
|
|
|
return FALSE; |
|
|
|
// Actually, if it's not selected, pretend it doesn't exist! |
|
//if (!pnode->Selected()) |
|
// return TRUE; |
|
//return FALSE; |
|
} |
|
|
|
|
|
//============================================================= |
|
// Returns TRUE if a node has been marked as skippable |
|
// |
|
BOOL FNodeMarkedToSkip(INode *pnode) |
|
{ |
|
return (::GetIndexOfINode(pnode) == UNDESIRABLE_NODE_MARKER); |
|
} |
|
|
|
|
|
|
|
//============================================================= |
|
// gets a weighted value for the current system of nodes |
|
// |
|
void GetUnifiedCoord( Point3 &p1, MaxVertWeight pweight[], MaxNode maxNode[], int cMaxNode ) |
|
{ |
|
float flMin = 1E20f; |
|
for (int iNode = 0; iNode < cMaxNode; iNode++) |
|
{ |
|
float f = (p1 - maxNode[iNode].mat3NodeTM.GetTrans()).LengthSquared(); |
|
if (f > 0 && f < flMin) |
|
flMin = f; |
|
pweight[iNode].flDist = f; |
|
} |
|
|
|
float flTotal = 0; |
|
float flInvMin = 1.0 / flMin; |
|
for (iNode = 0; iNode < cMaxNode; iNode++) |
|
{ |
|
if (pweight[iNode].flDist > 0) |
|
{ |
|
pweight[iNode].flDist = flInvMin / pweight[iNode].flDist; |
|
} |
|
else |
|
{ |
|
pweight[iNode].flDist = 10.0; |
|
} |
|
flTotal += pweight[iNode].flDist; |
|
} |
|
|
|
float flInvTotal; |
|
if (flTotal > 0) |
|
{ |
|
flInvTotal = 1.0 / flTotal; |
|
} |
|
else |
|
{ |
|
flInvTotal = 1.0; |
|
} |
|
|
|
for (iNode = 0; iNode < cMaxNode; iNode++) |
|
{ |
|
pweight[iNode].flDist = pweight[iNode].flDist * flInvTotal; |
|
// fprintf(m_pfile, "%8.4f ", pweight[iNode].flDist ); |
|
} |
|
} |
|
|
|
|
|
int GetBoneWeights( IPhyContextExport *mcExport, int iVertex, MaxVertWeight *pweight) |
|
{ |
|
float fTotal = 0; |
|
IPhyVertexExport *vtxExport = mcExport->GetVertexInterface(iVertex); |
|
|
|
if (vtxExport) |
|
{ |
|
if (vtxExport->GetVertexType() & BLENDED_TYPE) |
|
{ |
|
IPhyBlendedRigidVertex *pBlend = ((IPhyBlendedRigidVertex *)vtxExport); |
|
|
|
for (int i = 0; i < pBlend->GetNumberNodes(); i++) |
|
{ |
|
int index = GetIndexOfINode( pBlend->GetNode( i ) ); |
|
if (index >= 0) |
|
{ |
|
pweight[index].flWeight = pBlend->GetWeight( i ); |
|
fTotal += pweight[index].flWeight; |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
INode *Bone = ((IPhyRigidVertex *)vtxExport)->GetNode(); |
|
int index = GetIndexOfINode(Bone); |
|
if (index >= 0) |
|
{ |
|
pweight[index].flWeight = 100.0; |
|
} |
|
} |
|
mcExport->ReleaseVertexInterface(vtxExport); |
|
} |
|
return (fTotal > 0); |
|
} |
|
|
|
|
|
int GetBoneWeights( Modifier * bonesProMod, int iVertex, MaxVertWeight *pweight) |
|
{ |
|
int iTotal = 0; |
|
int nb = bonesProMod->SetProperty( BP_PROPID_GET_N_BONES, NULL ); |
|
|
|
for ( int iBone = 0; iBone < nb; iBone++) |
|
{ |
|
BonesPro_BoneVertex bv; |
|
bv.bindex = iBone; |
|
bv.vindex = iVertex; |
|
bonesProMod->SetProperty( BP_PROPID_GET_BV, &bv ); |
|
|
|
if (bv.included > 0 && bv.forced_weight >= 0) |
|
{ |
|
BonesPro_Bone bone; |
|
bone.t = BP_TIME_ATTACHED; |
|
bone.index = iBone; |
|
bonesProMod->SetProperty( BP_PROPID_GET_BONE_STAT, &bone ); |
|
|
|
if (bone.node != NULL) |
|
{ |
|
int index = GetIndexOfINode( bone.node ); |
|
|
|
if (index >= 0) |
|
{ |
|
pweight[index].flWeight = bv.forced_weight; |
|
iTotal++; |
|
} |
|
} |
|
} |
|
} |
|
return iTotal; |
|
} |
|
|
|
|
|
void SetBoneWeights( Modifier * bonesProMod, int iVertex, MaxVertWeight *pweight) |
|
{ |
|
int nb = bonesProMod->SetProperty( BP_PROPID_GET_N_BONES, NULL ); |
|
|
|
// FILE *fp = fopen("bone2.txt", "w"); |
|
|
|
for ( int iBone = 0; iBone < nb; iBone++) |
|
{ |
|
BonesPro_Bone bone; |
|
bone.t = BP_TIME_ATTACHED; |
|
bone.index = iBone; |
|
bonesProMod->SetProperty( BP_PROPID_GET_BONE_STAT, &bone ); |
|
|
|
/* |
|
if (GetIndexOfINode( bone.node ) >= 0) |
|
{ |
|
fprintf( fp, "\"%s\" %d\n", bone.name, GetIndexOfINode( bone.node ) ); |
|
} |
|
else |
|
{ |
|
fprintf( fp, "\"%s\"\n", bone.name ); |
|
} |
|
*/ |
|
|
|
BonesPro_BoneVertex bv; |
|
bv.bindex = iBone; |
|
bv.vindex = iVertex; |
|
bv.included = 0; |
|
bv.forced_weight = -1; |
|
|
|
if (bone.node != NULL) |
|
{ |
|
int index = GetIndexOfINode( bone.node ); |
|
|
|
if (index >= 0 && pweight[index].flWeight >= 0) |
|
{ |
|
bv.included = 1; |
|
bv.forced_weight = pweight[index].flWeight; |
|
} |
|
} |
|
bonesProMod->SetProperty( BP_PROPID_SET_BV, &bv ); |
|
} |
|
//fclose(fp); |
|
//exit(1); |
|
} |
|
|
|
|