|
|
//========= 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);
}
|