summaryrefslogtreecommitdiff
path: root/utils/vweightexp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /utils/vweightexp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'utils/vweightexp')
-rw-r--r--utils/vweightexp/vweight.cpp436
-rw-r--r--utils/vweightexp/vweightexp.cpp356
-rw-r--r--utils/vweightexp/vweightexp.def8
-rw-r--r--utils/vweightexp/vweightexp.h183
-rw-r--r--utils/vweightexp/vweightexp.vcproj189
-rw-r--r--utils/vweightexp/vweightexprc.h28
-rw-r--r--utils/vweightexp/vweightimp.cpp354
-rw-r--r--utils/vweightexp/vweightimp.h130
8 files changed, 1684 insertions, 0 deletions
diff --git a/utils/vweightexp/vweight.cpp b/utils/vweightexp/vweight.cpp
new file mode 100644
index 0000000..b873ba5
--- /dev/null
+++ b/utils/vweightexp/vweight.cpp
@@ -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);
+}
+
diff --git a/utils/vweightexp/vweightexp.cpp b/utils/vweightexp/vweightexp.cpp
new file mode 100644
index 0000000..19bc32c
--- /dev/null
+++ b/utils/vweightexp/vweightexp.cpp
@@ -0,0 +1,356 @@
+//========= 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"
+
+
+//===================================================================
+// Global variable definitions
+//
+
+// For OutputDebugString and misc sprintf's
+static char st_szDBG[300];
+
+
+
+//=====================================================================
+// Methods for VWeightExportClass
+//
+
+CONSTRUCTOR VWeightExportClass::VWeightExportClass(void)
+{
+ m_cMaxNode = 0;
+ m_cMaxVertex = 0;
+}
+
+
+DESTRUCTOR VWeightExportClass::~VWeightExportClass(void)
+{
+ for (int i = 0; i < m_cMaxVertex; i++)
+ {
+ delete[] m_MaxVertex[i];
+ }
+}
+
+
+int VWeightExportClass::DoExport(const TCHAR *name, ExpInterface *ei, Interface *pi, BOOL suppressPrompts, DWORD options)
+{
+ ExpInterface *pexpiface = ei; // Hungarian
+ Interface *piface = pi; // Hungarian
+
+ // Reset the name-map property manager
+ ResetINodeMap();
+
+ // Break up filename, re-assemble longer versions
+ TSTR strPath, strFile, strExt;
+ TCHAR szFile[MAX_PATH];
+ SplitFilename(TSTR(name), &strPath, &strFile, &strExt);
+ sprintf(szFile, "%s\\%s.%s", (char*)strPath, (char*)strFile, DEFAULT_EXT);
+
+
+ // Get animation metrics
+ m_intervalOfAnimation = piface->GetAnimRange();
+ m_tvStart = m_intervalOfAnimation.Start();
+ m_tvEnd = m_intervalOfAnimation.End();
+ m_tpf = ::GetTicksPerFrame();
+
+
+ Interface *ip = GetCOREInterface();
+
+ ResetINodeMap( );
+ m_cMaxNode = BuildINodeMap( ip->GetRootNode() );
+
+ // Count nodes, label them, collect into array
+ CollectNodes( ip->GetRootNode() );
+
+ CollectModel( pexpiface );
+
+#if 1
+ FILE *pFile;
+ if ((pFile = fopen(szFile, "wb")) == NULL)
+ return FALSE/*failure*/;
+
+ int version = 1;
+ fwrite( &version, 1, sizeof( int ), pFile );
+
+ int i, j;
+
+ fwrite( &m_cMaxNode, 1, sizeof( int ), pFile );
+ fwrite( &m_cMaxVertex, 1, sizeof( int ), pFile );
+
+ for (i = 0; i < m_cMaxNode; i++)
+ {
+ fwrite( &m_MaxNode[i], 1, sizeof(m_MaxNode[i]), pFile );
+ }
+
+ for (j = 0; j < m_cMaxVertex; j++)
+ {
+ fwrite( m_MaxVertex[j], m_cMaxNode, sizeof(MaxVertWeight), pFile );
+ }
+
+ fclose( pFile );
+#else
+ FILE *pFile;
+ if ((pFile = fopen(szFile, "w")) == NULL)
+ return FALSE/*failure*/;
+
+ fprintf( pFile, "version %d\n", 1 );
+
+ int i, j;
+
+ fprintf(pFile, "%d\n", m_cMaxNode );
+ fprintf(pFile, "%d\n", m_cMaxVertex );
+
+ for (i = 0; i < m_cMaxNode; i++)
+ {
+ fprintf(pFile, "%5d \"%s\" %3d\n",
+ i, m_MaxNode[i].szNodeName, m_MaxNode[i].imaxnodeParent );
+ }
+
+ for (j = 0; j < m_cMaxVertex; j++)
+ {
+ fprintf( pFile, "%d ", j );
+
+ for (int i = 0; i < m_cMaxNode; i++)
+ {
+ // if (strstr(m_MaxNode[i].szNodeName, "Bip01 R Finger"))
+ // if (m_MaxNode[i].szNodeName[0] == 'D')
+ {
+ fprintf(pFile, " %5.3f", m_MaxVertex[j][i].flDist );
+ fprintf(pFile, " %3.0f", m_MaxVertex[j][i].flWeight );
+ }
+ }
+ fprintf(pFile, "\n" );
+ }
+
+ fclose( pFile );
+#endif
+
+ // Tell user that exporting is finished (it can take a while with no feedback)
+ char szExportComplete[300];
+ sprintf(szExportComplete, "Exported %s.", szFile);
+ MessageBox(GetActiveWindow(), szExportComplete, "Status", MB_OK);
+
+
+ return 1/*success*/;
+}
+
+
+void VWeightExportClass::CollectNodes( INode *pnode )
+{
+ // Get pre-stored "index"
+ int index = ::GetIndexOfINode(pnode);
+
+ if (index >= 0)
+ {
+ // Get name, store name in array
+ TSTR strNodeName(pnode->GetName());
+ strcpy(m_MaxNode[index].szNodeName, (char*)strNodeName);
+
+ // Get Node's time-zero Transformation Matrices
+ m_MaxNode[index].mat3NodeTM = pnode->GetNodeTM(0);
+ m_MaxNode[index].mat3ObjectTM = pnode->GetObjectTM(0);
+ }
+
+ for (int c = 0; c < pnode->NumberOfChildren(); c++)
+ {
+ CollectNodes(pnode->GetChildNode(c));
+ }
+
+ return;
+}
+
+
+
+BOOL VWeightExportClass::CollectModel( ExpInterface *pexpiface)
+{
+ // Dump mesh info: vertices, normals, UV texture map coords, bone assignments
+ CollectModelTEP procCollectModel;
+
+ // init data
+ m_cMaxVertex = 0;
+
+ procCollectModel.m_phec = this;
+ //fprintf(pFile, "triangles\n" );
+ procCollectModel.m_tvToDump = m_tvStart;
+ (void) pexpiface->theScene->EnumTree(&procCollectModel);
+ //fprintf(pFile, "end\n" );
+ return TRUE;
+}
+
+
+// #define DEBUG_MESH_DUMP
+
+//=================================================================
+// Methods for CollectModelTEP
+//
+int CollectModelTEP::callback(INode *pnode)
+{
+ if (::FNodeMarkedToSkip(pnode))
+ return TREE_CONTINUE;
+
+ if ( !pnode->Selected())
+ return TREE_CONTINUE;
+
+ // clear physique export parameters
+ m_mcExport = NULL;
+ m_phyExport = NULL;
+ m_phyMod = NULL;
+ m_bonesProMod = NULL;
+
+ ASSERT_MBOX(!(pnode)->IsRootNode(), "Encountered a root node!");
+
+ int iNode = ::GetIndexOfINode(pnode);
+ TSTR strNodeName(pnode->GetName());
+
+ // The Footsteps node apparently MUST have a dummy mesh attached! Ignore it explicitly.
+ if (FStrEq((char*)strNodeName, "Bip01 Footsteps"))
+ return TREE_CONTINUE;
+
+ // Helper nodes don't have meshes
+ Object *pobj = pnode->GetObjectRef();
+ if (pobj->SuperClassID() == HELPER_CLASS_ID)
+ return TREE_CONTINUE;
+
+ // Get Node's object, convert to a triangle-mesh object, so I can access the Faces
+ ObjectState os = pnode->EvalWorldState(m_tvToDump);
+ pobj = os.obj;
+
+ // Shouldn't have gotten this far if it's a helper object
+ if (pobj->SuperClassID() == HELPER_CLASS_ID)
+ {
+ sprintf(st_szDBG, "ERROR--Helper node %s has an attached mesh, and it shouldn't.", (char*)strNodeName);
+ ASSERT_AND_ABORT(FALSE, st_szDBG);
+ }
+
+ // convert mesh to triobject
+ if (!pobj->CanConvertToType(triObjectClassID))
+ return TREE_CONTINUE;
+ TriObject *ptriobj = (TriObject*)pobj->ConvertToType(m_tvToDump, triObjectClassID);
+
+ if (ptriobj == NULL)
+ return TREE_CONTINUE;
+
+ Mesh *pmesh = &ptriobj->mesh;
+
+ // We want the vertex coordinates in World-space, not object-space
+ Matrix3 mat3ObjectTM = pnode->GetObjectTM(m_tvToDump);
+
+ // initialize physique export parameters
+ m_phyMod = FindPhysiqueModifier(pnode);
+ if (m_phyMod)
+ {
+ // Physique Modifier exists for given Node
+ m_phyExport = (IPhysiqueExport *)m_phyMod->GetInterface(I_PHYINTERFACE);
+
+ if (m_phyExport)
+ {
+ // create a ModContext Export Interface for the specific node of the Physique Modifier
+ m_mcExport = (IPhyContextExport *)m_phyExport->GetContextInterface(pnode);
+
+ if (m_mcExport)
+ {
+ // convert all vertices to Rigid
+ m_mcExport->ConvertToRigid(TRUE);
+ }
+ }
+ }
+
+ // initialize bones pro export parameters
+ m_wa = NULL;
+ m_bonesProMod = FindBonesProModifier(pnode);
+ if (m_bonesProMod)
+ {
+ m_bonesProMod->SetProperty( BP_PROPID_GET_WEIGHTS, &m_wa );
+ }
+
+
+ int cVerts = pmesh->getNumVerts();
+
+ // Dump the triangle face info
+ int cFaces = pmesh->getNumFaces();
+
+ int *iUsed = new int[cVerts];
+
+ for (int iVert = 0; iVert < cVerts; iVert++)
+ {
+ iUsed[iVert] = 0;
+ }
+
+ for (int iFace = 0; iFace < cFaces; iFace++)
+ {
+ if (pmesh->faces[iFace].flags & HAS_TVERTS)
+ {
+ iUsed[pmesh->faces[iFace].getVert(0)] = 1;
+ iUsed[pmesh->faces[iFace].getVert(1)] = 1;
+ iUsed[pmesh->faces[iFace].getVert(2)] = 1;
+ }
+ }
+
+ for (iVert = 0; iVert < cVerts; iVert++)
+ {
+ MaxVertWeight *pweight = m_phec->m_MaxVertex[m_phec->m_cMaxVertex] = new MaxVertWeight [m_phec->m_cMaxNode];
+
+ Point3 pt3Vertex1 = pmesh->getVert(iVert);
+ Point3 v1 = pt3Vertex1 * mat3ObjectTM;
+
+ GetUnifiedCoord( v1, pweight, m_phec->m_MaxNode, m_phec->m_cMaxNode );
+
+ if (CollectWeights( iVert, pweight ))
+ {
+ m_phec->m_cMaxVertex++;
+ }
+ }
+
+ // fflush( m_pfile );
+
+ return TREE_CONTINUE;
+}
+
+
+int CollectModelTEP::CollectWeights(int iVertex, MaxVertWeight *pweight)
+{
+ for (int index = 0; index < m_phec->m_cMaxNode; index++)
+ {
+ pweight[index].flWeight = -1;
+ }
+
+ if (m_mcExport)
+ {
+ return GetBoneWeights( m_mcExport, iVertex, pweight );
+ }
+ else
+ {
+ return GetBoneWeights( m_bonesProMod, iVertex, pweight );
+ }
+}
+
+void CollectModelTEP::cleanup(void)
+{
+ if (m_phyMod && m_phyExport)
+ {
+ if (m_mcExport)
+ {
+ m_phyExport->ReleaseContextInterface(m_mcExport);
+ m_mcExport = NULL;
+ }
+ m_phyMod->ReleaseInterface(I_PHYINTERFACE, m_phyExport);
+ m_phyExport = NULL;
+ m_phyMod = NULL;
+ }
+}
+
diff --git a/utils/vweightexp/vweightexp.def b/utils/vweightexp/vweightexp.def
new file mode 100644
index 0000000..b39737b
--- /dev/null
+++ b/utils/vweightexp/vweightexp.def
@@ -0,0 +1,8 @@
+LIBRARY vweightexp
+EXPORTS
+ LibDescription @1
+ LibNumberClasses @2
+ LibClassDesc @3
+ LibVersion @4
+SECTIONS
+ .data READ WRITE
diff --git a/utils/vweightexp/vweightexp.h b/utils/vweightexp/vweightexp.h
new file mode 100644
index 0000000..85ce670
--- /dev/null
+++ b/utils/vweightexp/vweightexp.h
@@ -0,0 +1,183 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+//===================================================================
+// Useful macros
+//
+#define CONSTRUCTOR
+#define DESTRUCTOR
+
+#define EXPORT_THIS __declspec(dllexport)
+
+#define DEFAULT_EXT _T("vvw")
+
+#define FStrEq(sz1, sz2) (strcmp((sz1), (sz2)) == 0)
+
+
+//=============================================================================
+// TREE-ENUMERATION PROCEDURES
+//=============================================================================
+
+#define ASSERT_AND_ABORT(f, sz) \
+ if (!(f)) \
+ { \
+ ASSERT_MBOX(FALSE, sz); \
+ cleanup( ); \
+ return TREE_ABORT; \
+ }
+
+
+// Integer constants for this class
+enum
+ {
+ MAX_NAME_CHARS = 70,
+ UNDESIRABLE_NODE_MARKER = -7777
+ };
+
+// For keeping info about each (non-ignored) 3dsMax node in the tree
+typedef struct
+{
+ char szNodeName[MAX_NAME_CHARS]; // usefull for lookups
+ Matrix3 mat3NodeTM; // node's transformation matrix (at time zero)
+ Matrix3 mat3ObjectTM; // object-offset transformation matrix (at time zero)
+ int imaxnodeParent; // cached index of parent node
+} MaxNode;
+
+typedef struct
+{
+ float flDist;
+ float flWeight;
+} MaxVertWeight;
+
+//===================================================================
+// Class that implements the scene-export.
+//
+class VWeightExportClass : public SceneExport
+{
+ friend BOOL CALLBACK ExportOptionsDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
+ friend class CollectModelTEP;
+
+public:
+ CONSTRUCTOR VWeightExportClass (void);
+ DESTRUCTOR ~VWeightExportClass (void);
+
+ // Required by classes derived from SceneExport
+ virtual int ExtCount (void) { return 1; }
+ virtual const TCHAR* Ext (int i) { return DEFAULT_EXT; }
+ virtual const TCHAR* LongDesc (void) { return _T("Valve Skeletal Model Exporter for 3D Studio Max"); }
+ virtual const TCHAR* ShortDesc (void) { return _T("Valve VVW"); }
+ virtual const TCHAR* AuthorName (void) { return _T("Valve, LLC"); }
+ virtual const TCHAR* CopyrightMessage(void) { return _T("Copyright (c) 1998, Valve LLC"); }
+ virtual const TCHAR* OtherMessage1 (void) { return _T(""); }
+ virtual const TCHAR* OtherMessage2 (void) { return _T(""); }
+ virtual unsigned int Version (void) { return 201; }
+ virtual void ShowAbout (HWND hWnd) { return; }
+ // virtual int DoExport (const TCHAR *name, ExpInterface *ei, Interface *i);
+ virtual int DoExport(const TCHAR *name,ExpInterface *ei,Interface *i, BOOL suppressPrompts=FALSE,DWORD options=0); // Export file
+
+ MaxNode m_MaxNode[512]; // array of nodes
+ long m_cMaxNode; // # of nodes
+
+ MaxVertWeight *m_MaxVertex[10000];
+ long m_cMaxVertex;
+
+ // Animation metrics (gleaned from 3dsMax and cached for convenience)
+ Interval m_intervalOfAnimation;
+ TimeValue m_tvStart;
+ TimeValue m_tvEnd;
+ int m_tpf; // ticks-per-frame
+
+private:
+ void CollectNodes( INode *pnode );
+ BOOL CollectModel( ExpInterface *pexpiface );
+};
+
+
+//===================================================================
+// Basically just a ClassFactory for communicating with 3DSMAX.
+//
+class VWeightExportClassDesc : public ClassDesc
+{
+public:
+ int IsPublic (void) { return TRUE; }
+ void * Create (BOOL loading=FALSE) { return new VWeightExportClass; }
+ const TCHAR * ClassName (void) { return _T("VWeightExport"); }
+ SClass_ID SuperClassID (void) { return SCENE_EXPORT_CLASS_ID; }
+ Class_ID ClassID (void) { return Class_ID(0x554b1092, 0x206a444f); }
+ const TCHAR * Category (void) { return _T(""); }
+};
+
+
+//===================================================================
+// Tree Enumeration Callback
+// Just counts the nodes in the node tree
+//
+class CountNodesTEP : public ITreeEnumProc
+{
+public:
+ virtual int callback(INode *node);
+ int m_cNodes; // running count of nodes
+};
+
+
+//===================================================================
+// Tree Enumeration Callback
+// Collects the nodes in the tree into the global array
+//
+class CollectNodesTEP : public ITreeEnumProc
+{
+public:
+ virtual int callback(INode *node);
+ VWeightExportClass *m_phec;
+};
+
+
+
+//===================================================================
+// Tree Enumeration Callback
+// Dumps the triangle meshes to a file.
+//
+class CollectModelTEP : public ITreeEnumProc
+{
+public:
+ virtual int callback(INode *node);
+ void cleanup(void);
+ // FILE *m_pfile; // write to this file
+ TimeValue m_tvToDump; // dump snapshot at this frame time
+ VWeightExportClass *m_phec;
+ IPhyContextExport *m_mcExport;
+ IPhysiqueExport *m_phyExport;
+ Modifier *m_phyMod;
+ Modifier *m_bonesProMod;
+ BonesPro_WeightArray *m_wa;
+private:
+ int CollectWeights( int iVertex, MaxVertWeight *pweight );
+};
+
+
+//===================================================================
+// Prototype declarations
+//
+void ResetINodeMap( void );
+int BuildINodeMap(INode *pnode);
+void AddINode( INode *pnode );
+int GetIndexOfNodeName( TCHAR *szNodeName, BOOL fAssertPropExists = TRUE );
+int GetIndexOfINode( INode *pnode, BOOL fAssertPropExists = TRUE);
+
+BOOL FUndesirableNode( INode *pnode);
+BOOL FNodeMarkedToSkip( INode *pnode);
+Modifier *FindPhysiqueModifier( INode *nodePtr );
+Modifier *FindBonesProModifier( INode *nodePtr );
+int AssertFailedFunc(char *sz);
+#define ASSERT_MBOX(f, sz) ((f) ? 1 : AssertFailedFunc(sz))
+void GetUnifiedCoord( Point3 &p1, MaxVertWeight pweight[], MaxNode maxNode[], int cMaxNode );
+
+int GetBoneWeights( IPhyContextExport *mcExport, int iVertex, MaxVertWeight *pweight);
+int GetBoneWeights( Modifier * bonesProMod, int iVertex, MaxVertWeight *pweight);
+void SetBoneWeights( Modifier * bonesProMod, int iVertex, MaxVertWeight *pweight);
+
diff --git a/utils/vweightexp/vweightexp.vcproj b/utils/vweightexp/vweightexp.vcproj
new file mode 100644
index 0000000..b367641
--- /dev/null
+++ b/utils/vweightexp/vweightexp.vcproj
@@ -0,0 +1,189 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="vweightexp"
+ ProjectGUID="{6233E118-9880-4484-8243-AB7BE7AF96A1}"
+ SccProjectName=""
+ SccLocalPath="">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory=".\Debug"
+ IntermediateDirectory=".\Debug"
+ ConfigurationType="2"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\MAXSDK\INCLUDE"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;VWEIGHTEXP_EXPORTS"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderFile=".\Debug/vweightexp.pch"
+ AssemblerListingLocation=".\Debug/"
+ ObjectFile=".\Debug/"
+ ProgramDataBaseFileName=".\Debug/"
+ BrowseInformation="1"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="4"
+ CompileAs="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="maxutil.lib geom.lib mesh.lib core.lib odbc32.lib odbccp32.lib"
+ OutputFile="c:\3DSMAX3_1\plugins\VWEIGHTEXP.DLE"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ AdditionalLibraryDirectories="..\..\maxsdk\lib"
+ ModuleDefinitionFile=".\vweightexp.def"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile=".\Debug/VWEIGHTEXP.pdb"
+ ImportLibrary=".\Debug/VWEIGHTEXP.lib"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="_DEBUG"
+ MkTypLibCompatible="TRUE"
+ SuppressStartupBanner="TRUE"
+ TargetEnvironment="1"
+ TypeLibraryName=".\Debug/vweightexp.tlb"
+ HeaderFileName=""/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory=".\Release"
+ IntermediateDirectory=".\Release"
+ ConfigurationType="2"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="..\..\MAXSDK\INCLUDE"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;VWEIGHTEXP_EXPORTS"
+ StringPooling="TRUE"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="TRUE"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderFile=".\Release/vweightexp.pch"
+ AssemblerListingLocation=".\Release/"
+ ObjectFile=".\Release/"
+ ProgramDataBaseFileName=".\Release/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ CompileAs="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="maxutil.lib geom.lib mesh.lib core.lib odbc32.lib odbccp32.lib"
+ OutputFile="c:\3DSMAX3_1\plugins\VWEIGHTEXP.DLE"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ AdditionalLibraryDirectories="..\..\maxsdk\lib"
+ ModuleDefinitionFile=".\vweightexp.def"
+ ProgramDatabaseFile=".\Release/VWEIGHTEXP.pdb"
+ ImportLibrary=".\Release/VWEIGHTEXP.lib"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="NDEBUG"
+ MkTypLibCompatible="TRUE"
+ SuppressStartupBanner="TRUE"
+ TargetEnvironment="1"
+ TypeLibraryName=".\Release/vweightexp.tlb"
+ HeaderFileName=""/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat">
+ <File
+ RelativePath="vweight.cpp">
+ </File>
+ <File
+ RelativePath="vweightexp.cpp">
+ </File>
+ <File
+ RelativePath="vweightexp.def">
+ </File>
+ <File
+ RelativePath="vweightimp.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl">
+ <File
+ RelativePath="vweightexp.h">
+ </File>
+ <File
+ RelativePath="vweightexprc.h">
+ </File>
+ <File
+ RelativePath="vweightimp.h">
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe">
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/utils/vweightexp/vweightexprc.h b/utils/vweightexp/vweightexprc.h
new file mode 100644
index 0000000..e6482bf
--- /dev/null
+++ b/utils/vweightexp/vweightexprc.h
@@ -0,0 +1,28 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by smdlexp.rc
+//
+#define IDD_SMDLEXP_UI 101
+#define IDD_EXPORTOPTIONS 101
+#define IDC_CHECK_SKELETAL 1000
+#define IDC_CHECK_DEFORM 1001
+#define IDC_CHECK_REFFRAME 1002
+#define IDC_CHECK_PHYSIQUE 1003
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 102
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1006
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/utils/vweightexp/vweightimp.cpp b/utils/vweightexp/vweightimp.cpp
new file mode 100644
index 0000000..87921dc
--- /dev/null
+++ b/utils/vweightexp/vweightimp.cpp
@@ -0,0 +1,354 @@
+//========= 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"
+
+
+//===================================================================
+// Global variable definitions
+//
+
+// For OutputDebugString and misc sprintf's
+static char st_szDBG[8193];
+
+
+
+//=====================================================================
+// Methods for VWeightImportClass
+//
+
+CONSTRUCTOR VWeightImportClass::VWeightImportClass(void)
+{
+ m_cSrcMaxNodes = 0;
+ m_cSrcMaxVertex = 0;
+ m_cMaxNodes = 0;
+}
+
+
+DESTRUCTOR VWeightImportClass::~VWeightImportClass(void)
+{
+ for (int i = 0; i < m_cSrcMaxVertex; i++)
+ {
+ delete[] m_SrcMaxVertex[i];
+ }
+}
+
+
+int VWeightImportClass::DoImport(const TCHAR *name, ImpInterface *ii, Interface *pi, BOOL suppressPrompts)
+{
+ ImpInterface *pimpiface = ii;
+ Interface *piface = pi;
+
+ // Break up filename, re-assemble longer versions
+ TSTR strPath, strFile, strExt;
+ TCHAR szFile[MAX_PATH];
+ SplitFilename(TSTR(name), &strPath, &strFile, &strExt);
+ sprintf(szFile, "%s\\%s.%s", (char*)strPath, (char*)strFile, DEFAULT_EXT);
+
+
+ // Get animation metrics
+ m_intervalOfAnimation = piface->GetAnimRange();
+ m_tvStart = m_intervalOfAnimation.Start();
+ m_tvEnd = m_intervalOfAnimation.End();
+ m_tpf = ::GetTicksPerFrame();
+
+ Interface *ip = GetCOREInterface();
+
+ ResetINodeMap( );
+ m_cMaxNodes = BuildINodeMap( ip->GetRootNode() );
+
+ CollectNodes( ip->GetRootNode() );
+
+ // read src data
+ FILE *pFile;
+ if ((pFile = fopen(szFile, "rb")) == NULL)
+ return FALSE/*failure*/;
+
+ int version = 1;
+ fread( &version, 1, sizeof( int ), pFile );
+
+ int i, j;
+
+ fread( &m_cSrcMaxNodes, 1, sizeof( int ), pFile );
+ fread( &m_cSrcMaxVertex, 1, sizeof( int ), pFile );
+
+ for (i = 0; i < m_cSrcMaxNodes; i++)
+ {
+ fread( &m_SrcMaxNode[i], 1, sizeof(m_SrcMaxNode[i]), pFile );
+ }
+
+ int cNodes = (m_cSrcMaxNodes > m_cMaxNodes) ? m_cSrcMaxNodes : m_cMaxNodes;
+ for (j = 0; j < m_cSrcMaxVertex; j++)
+ {
+ m_SrcMaxVertex[j] = new MaxVertWeight [cNodes];
+ fread( m_SrcMaxVertex[j], m_cSrcMaxNodes, sizeof(MaxVertWeight), pFile );
+ }
+
+ fclose( pFile );
+
+ RemapSrcWeights( );
+
+ NodeEnum( ip->GetSelNode( 0 ) );
+
+ // Tell user that exporting is finished (it can take a while with no feedback)
+ char szExportComplete[300];
+ sprintf(szExportComplete, "Imported %s.", szFile);
+ MessageBox(GetActiveWindow(), szExportComplete, "Status", MB_OK);
+
+ return 1/*success*/;
+}
+
+
+void VWeightImportClass::CollectNodes( INode *pnode )
+{
+ // Get pre-stored "index"
+ int index = ::GetIndexOfINode(pnode);
+
+ if (index >= 0)
+ {
+ // Get name, store name in array
+ TSTR strNodeName(pnode->GetName());
+ strcpy(m_MaxNode[index].szNodeName, (char*)strNodeName);
+
+ // Get Node's time-zero Transformation Matrices
+ m_MaxNode[index].mat3NodeTM = pnode->GetNodeTM(0);
+ m_MaxNode[index].mat3ObjectTM = pnode->GetObjectTM(0);
+ }
+
+ for (int c = 0; c < pnode->NumberOfChildren(); c++)
+ {
+ CollectNodes(pnode->GetChildNode(c));
+ }
+
+ return;
+}
+
+
+void VWeightImportClass::NodeEnum( INode *node )
+{
+#if 0
+ // For each child of this node, we recurse into ourselves
+ // until no more children are found.
+ for (int c = 0; c < node->NumberOfChildren(); c++)
+ {
+ NodeEnum(node->GetChildNode(c));
+ }
+#endif
+
+ UpdateModel( node );
+}
+
+void VWeightImportClass::RemapSrcWeights( )
+{
+ int index;
+
+ for (index = 0; index < m_cMaxNodes; index++)
+ {
+ m_iToSrc[index] = -1;
+ }
+
+ for (int iSrc = 0; iSrc < m_cSrcMaxNodes; iSrc++)
+ {
+ index = GetIndexOfNodeName( (char*) m_SrcMaxNode[iSrc].szNodeName );
+ if (index >= 0)
+ {
+ m_iToSrc[index] = iSrc;
+ }
+ else
+ {
+ iSrc = iSrc;
+ }
+ }
+
+ MaxVertWeight flTmp[512];
+ for (index = 0; index < m_cMaxNodes; index++)
+ {
+ flTmp[index].flDist = 0.0;
+ flTmp[index].flWeight = 0.0;
+ }
+
+ for (int iVert = 0; iVert < m_cSrcMaxVertex; iVert++)
+ {
+ for (index = 0; index < m_cMaxNodes; index++)
+ {
+ if (m_iToSrc[index] >= 0)
+ {
+ flTmp[index] = m_SrcMaxVertex[iVert][m_iToSrc[index]];
+ }
+ }
+ for (index = 0; index < m_cMaxNodes; index++)
+ {
+ m_SrcMaxVertex[iVert][index] = flTmp[index];
+ }
+ }
+}
+
+
+int VWeightImportClass::UpdateModel(INode *pnode)
+{
+ if (::FNodeMarkedToSkip(pnode))
+ return TREE_CONTINUE;
+
+ if ( !pnode->Selected())
+ return TREE_CONTINUE;
+
+ // clear physique export parameters
+ m_mcExport = NULL;
+ m_phyExport = NULL;
+ m_phyMod = NULL;
+ m_bonesProMod = NULL;
+
+ ASSERT_MBOX(!(pnode)->IsRootNode(), "Encountered a root node!");
+
+ int iNode = ::GetIndexOfINode(pnode);
+ TSTR strNodeName(pnode->GetName());
+
+ // The Footsteps node apparently MUST have a dummy mesh attached! Ignore it explicitly.
+ if (FStrEq((char*)strNodeName, "Bip01 Footsteps"))
+ return TREE_CONTINUE;
+
+ // Helper nodes don't have meshes
+ Object *pobj = pnode->GetObjectRef();
+ if (pobj->SuperClassID() == HELPER_CLASS_ID)
+ return TREE_CONTINUE;
+
+ // Get Node's object, convert to a triangle-mesh object, so I can access the Faces
+ ObjectState os = pnode->EvalWorldState(m_tvStart);
+ pobj = os.obj;
+
+ // Shouldn't have gotten this far if it's a helper object
+ if (pobj->SuperClassID() == HELPER_CLASS_ID)
+ {
+ return TREE_CONTINUE;
+ }
+
+ // convert mesh to triobject
+ if (!pobj->CanConvertToType(triObjectClassID))
+ return TREE_CONTINUE;
+ TriObject *ptriobj = (TriObject*)pobj->ConvertToType(m_tvStart, triObjectClassID);
+
+ if (ptriobj == NULL)
+ return TREE_CONTINUE;
+
+ Mesh *pmesh = &ptriobj->mesh;
+
+ // We want the vertex coordinates in World-space, not object-space
+ Matrix3 mat3ObjectTM = pnode->GetObjectTM(m_tvStart);
+
+ // initialize physique export parameters
+ m_phyMod = FindPhysiqueModifier(pnode);
+ if (m_phyMod)
+ {
+ // Physique Modifier exists for given Node
+ m_phyExport = (IPhysiqueExport *)m_phyMod->GetInterface(I_PHYINTERFACE);
+
+ if (m_phyExport)
+ {
+ // create a ModContext Export Interface for the specific node of the Physique Modifier
+ m_mcExport = (IPhyContextExport *)m_phyExport->GetContextInterface(pnode);
+
+ if (m_mcExport)
+ {
+ // convert all vertices to Rigid
+ m_mcExport->ConvertToRigid(TRUE);
+ }
+ }
+ }
+
+ // initialize bones pro export parameters
+ m_wa = NULL;
+ m_bonesProMod = FindBonesProModifier(pnode);
+ if (m_bonesProMod)
+ {
+ m_bonesProMod->SetProperty( BP_PROPID_GET_WEIGHTS, &m_wa );
+ }
+
+
+ int cVerts = pmesh->getNumVerts();
+
+ // Dump the triangle face info
+ int cFaces = pmesh->getNumFaces();
+
+ MaxVertWeight mvTmp[512];
+
+ for (int iVert = 0; iVert < cVerts; iVert++)
+ {
+ Point3 pt3Vertex1 = pmesh->getVert(iVert);
+ Point3 v1 = pt3Vertex1 * mat3ObjectTM;
+
+ if (v1.x < -24.0)
+ {
+ v1 = v1;
+ }
+
+ GetUnifiedCoord( v1, mvTmp, m_MaxNode, m_cMaxNodes );
+ GetBoneWeights( m_bonesProMod, iVert, mvTmp );
+
+ int iClosest = -1;
+ float flMinDist = 1E30f;
+ for (int iVert2 = 0; iVert2 < m_cSrcMaxVertex; iVert2++)
+ {
+ float flDist = 0;
+ for (int index = 0; index < m_cMaxNodes && flDist < flMinDist; index++)
+ {
+ if (m_iToSrc[index]>=0)
+ {
+ float tmp = mvTmp[index].flDist - m_SrcMaxVertex[iVert2][index].flDist;
+ flDist += (tmp * tmp);
+ }
+ }
+ if (flDist < flMinDist)
+ {
+ iClosest = iVert2;
+ flMinDist = flDist;
+ }
+ }
+
+ if (iClosest != -1)
+ {
+ SetBoneWeights( m_bonesProMod, iVert, m_SrcMaxVertex[iClosest] );
+ }
+ }
+
+ if (m_bonesProMod)
+ {
+ m_bonesProMod->SetProperty ( BP_PROPID_REFRESH, NULL );
+ }
+ // fflush( m_pfile );
+
+ return TREE_CONTINUE;
+}
+
+
+
+void UpdateModelTEP::cleanup(void)
+{
+ if (m_phyMod && m_phyExport)
+ {
+ if (m_mcExport)
+ {
+ m_phyExport->ReleaseContextInterface(m_mcExport);
+ m_mcExport = NULL;
+ }
+ m_phyMod->ReleaseInterface(I_PHYINTERFACE, m_phyExport);
+ m_phyExport = NULL;
+ m_phyMod = NULL;
+ }
+}
+
+
diff --git a/utils/vweightexp/vweightimp.h b/utils/vweightexp/vweightimp.h
new file mode 100644
index 0000000..9a0e586
--- /dev/null
+++ b/utils/vweightexp/vweightimp.h
@@ -0,0 +1,130 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+//===================================================================
+// Useful macros
+//
+#define CONSTRUCTOR
+#define DESTRUCTOR
+
+#define EXPORT_THIS __declspec(dllexport)
+
+#define DEFAULT_EXT _T("vvw")
+
+#define FStrEq(sz1, sz2) (strcmp((sz1), (sz2)) == 0)
+
+
+//===================================================================
+// Class that implements the scene-export.
+//
+class VWeightImportClass : public SceneImport
+{
+ // friend BOOL CALLBACK ImportOptionsDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
+ // friend class DumpModelTEP;
+ // friend class DumpDeformsTEP;
+
+public:
+ CONSTRUCTOR VWeightImportClass (void);
+ DESTRUCTOR ~VWeightImportClass (void);
+
+ // Required by classes derived from SceneExport
+ virtual int ExtCount (void) { return 1; }
+ virtual const TCHAR* Ext (int i) { return DEFAULT_EXT; }
+ virtual const TCHAR* LongDesc (void) { return _T("Valve Skeletal Model Exporter for 3D Studio Max"); }
+ virtual const TCHAR* ShortDesc (void) { return _T("Valve VVW"); }
+ virtual const TCHAR* AuthorName (void) { return _T("Valve, LLC"); }
+ virtual const TCHAR* CopyrightMessage(void) { return _T("Copyright (c) 1998, Valve LLC"); }
+ virtual const TCHAR* OtherMessage1 (void) { return _T(""); }
+ virtual const TCHAR* OtherMessage2 (void) { return _T(""); }
+ virtual unsigned int Version (void) { return 201; }
+ virtual void ShowAbout (HWND hWnd) { return; }
+ // virtual int DoExport (const TCHAR *name, ExpInterface *ei, Interface *i);
+ virtual int DoImport(const TCHAR *name,ImpInterface *ii,Interface *i, BOOL suppressPrompts=FALSE); // Export file
+
+ MaxNode m_SrcMaxNode[512]; // array of nodes
+ long m_cSrcMaxNodes; // # of nodes
+
+ MaxVertWeight *m_SrcMaxVertex[10000];
+ long m_cSrcMaxVertex;
+
+ MaxNode m_MaxNode[512]; // array of nodes
+ long m_cMaxNodes; // # of nodes
+
+ int m_iToSrc[512]; // translate src nodes to local bones
+
+ // Animation metrics (gleaned from 3dsMax and cached for convenience)
+ Interval m_intervalOfAnimation;
+ TimeValue m_tvStart;
+ TimeValue m_tvEnd;
+ int m_tpf; // ticks-per-frame
+
+private:
+ void CollectNodes( INode *pnode );
+ void NodeEnum( INode *node );
+ int UpdateModel( INode *node );
+ void CollectWeights(int iVertex, MaxVertWeight *pweight);
+ void RemapSrcWeights( void );
+
+ IPhyContextExport *m_mcExport;
+ IPhysiqueExport *m_phyExport;
+ Modifier *m_phyMod;
+ Modifier *m_bonesProMod;
+ BonesPro_WeightArray *m_wa;
+
+};
+
+
+//===================================================================
+// Basically just a ClassFactory for communicating with 3DSMAX.
+//
+class VWeightImportClassDesc : public ClassDesc
+{
+public:
+ int IsPublic (void) { return TRUE; }
+ void * Create (BOOL loading=FALSE) { return new VWeightImportClass; }
+ const TCHAR * ClassName (void) { return _T("VWeightImport"); }
+ SClass_ID SuperClassID (void) { return SCENE_IMPORT_CLASS_ID; }
+ Class_ID ClassID (void) { return Class_ID(0x554b1092, 0x206a444f); }
+ const TCHAR * Category (void) { return _T(""); }
+};
+
+
+//===================================================================
+// Tree Enumeration Callback
+// Collects the nodes in the tree into the global array
+//
+class UpdateNodesTEP : public ITreeEnumProc
+{
+public:
+ virtual int callback(INode *node);
+ VWeightImportClass *m_phec;
+};
+
+
+//===================================================================
+// Tree Enumeration Callback
+// Dumps the triangle meshes to a file.
+//
+class UpdateModelTEP : public ITreeEnumProc
+{
+public:
+ virtual int callback(INode *node);
+ void cleanup(void);
+ // FILE *m_pfile; // write to this file
+ TimeValue m_tvToDump; // dump snapshot at this frame time
+ VWeightImportClass *m_phec;
+ IPhyContextExport *m_mcExport;
+ IPhysiqueExport *m_phyExport;
+ Modifier *m_phyMod;
+ Modifier *m_bonesProMod;
+ BonesPro_WeightArray *m_wa;
+private:
+ void CollectWeights( int iVertex, MaxVertWeight *pweight );
+};
+
+