Team Fortress 2 Source Code as on 22/4/2020
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.
 
 
 
 
 
 

356 lines
8.1 KiB

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