Modified source engine (2017) developed by valve and leaked in 2020. Not for commercial purporses
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

437 lines
9.3 KiB

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