diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /utils/vweightexp | |
| download | archived-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.cpp | 436 | ||||
| -rw-r--r-- | utils/vweightexp/vweightexp.cpp | 356 | ||||
| -rw-r--r-- | utils/vweightexp/vweightexp.def | 8 | ||||
| -rw-r--r-- | utils/vweightexp/vweightexp.h | 183 | ||||
| -rw-r--r-- | utils/vweightexp/vweightexp.vcproj | 189 | ||||
| -rw-r--r-- | utils/vweightexp/vweightexprc.h | 28 | ||||
| -rw-r--r-- | utils/vweightexp/vweightimp.cpp | 354 | ||||
| -rw-r--r-- | utils/vweightexp/vweightimp.h | 130 |
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 ); +}; + + |