1
This commit is contained in:
436
utils/vweightexp/vweight.cpp
Normal file
436
utils/vweightexp/vweight.cpp
Normal file
@ -0,0 +1,436 @@
|
||||
//========= 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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user