mirror of
https://github.com/nillerusr/source-engine.git
synced 2024-12-22 22:27:05 +00:00
355 lines
7.8 KiB
C++
355 lines
7.8 KiB
C++
|
//========= 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;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|