Moved modified HL SDK to trunk

This commit is contained in:
Scott Ehlert
2006-08-27 02:22:59 +00:00
parent 28c4ea4fec
commit 30235e05e5
900 changed files with 344676 additions and 0 deletions

View File

@ -0,0 +1,951 @@
/***
*
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
*
****/
#include "MAX.H"
#include "DECOMP.H"
#include "STDMAT.H"
#include "ANIMTBL.H"
#include "istdplug.h"
#include "phyexp.h"
#include "smexprc.h"
#include "smedefs.h"
//===================================================================
// Prototype declarations
//
int GetIndexOfINode(INode *pnode,BOOL fAssertPropExists = TRUE);
void SetIndexOfINode(INode *pnode, int inode);
BOOL FUndesirableNode(INode *pnode);
BOOL FNodeMarkedToSkip(INode *pnode);
float FlReduceRotation(float fl);
//===================================================================
// Global variable definitions
//
// Save for use with dialogs
static HINSTANCE hInstance;
// We just need one of these to hand off to 3DSMAX.
static SmdExportClassDesc SmdExportCD;
// For OutputDebugString and misc sprintf's
static char st_szDBG[300];
// INode mapping table
static int g_inmMac = 0;
//===================================================================
// Utility functions
//
static int AssertFailedFunc(char *sz)
{
MessageBox(GetActiveWindow(), sz, "Assert failure", MB_OK);
int Set_Your_Breakpoint_Here = 1;
return 1;
}
#define ASSERT_MBOX(f, sz) ((f) ? 1 : AssertFailedFunc(sz))
//===================================================================
// 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 1;
}
EXPORT_THIS ClassDesc *LibClassDesc(int iWhichClass)
{
switch(iWhichClass)
{
case 0: return &SmdExportCD;
default: return 0;
}
}
EXPORT_THIS const TCHAR *LibDescription()
{
return _T("Valve SMD Plug-in.");
}
EXPORT_THIS ULONG LibVersion()
{
return VERSION_3DSMAX;
}
//=====================================================================
// Methods for SmdExportClass
//
CONSTRUCTOR SmdExportClass::SmdExportClass(void)
{
m_rgmaxnode = NULL;
}
DESTRUCTOR SmdExportClass::~SmdExportClass(void)
{
if (m_rgmaxnode)
delete[] m_rgmaxnode;
}
int SmdExportClass::DoExport(const TCHAR *name,ExpInterface *ei,Interface *i, BOOL suppressPrompts)
{
ExpInterface *pexpiface = ei; // Hungarian
Interface *piface = i; // Hungarian
// Reset the name-map property manager
g_inmMac = 0;
// Present the user with the Export Options dialog
if (DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_EXPORTOPTIONS), GetActiveWindow(),
ExportOptionsDlgProc, (LPARAM)this) <= 0)
return 0; // error or cancel
// 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);
/*
if (m_fReferenceFrame)
sprintf(szFile, "%s\\%s_model.%s", (char*)strPath, (char*)strFile, DEFAULT_EXT);
*/
FILE *pFile;
if ((pFile = fopen(szFile, "w")) == NULL)
return FALSE/*failure*/;
fprintf( pFile, "version %d\n", 1 );
// Get animation metrics
m_intervalOfAnimation = piface->GetAnimRange();
m_tvStart = m_intervalOfAnimation.Start();
m_tvEnd = m_intervalOfAnimation.End();
m_tpf = ::GetTicksPerFrame();
// Count nodes, label them, collect into array
if (!CollectNodes(pexpiface))
return 0; /*fail*/
// Output nodes
if (!DumpBones(pFile, pexpiface))
{
fclose( pFile );
return 0; /*fail*/
}
// Output bone rotations, for each frame. Do only first frame if this is the reference frame MAX file
DumpRotations(pFile, pexpiface);
// Output triangle meshes (first frame/all frames), if this is the reference frame MAX file
if (m_fReferenceFrame)
{
DumpModel(pFile, pexpiface);
}
// 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);
fclose( pFile );
return 1/*success*/;
}
BOOL SmdExportClass::CollectNodes( ExpInterface *pexpiface)
{
// Count total nodes in the model, so I can alloc array
// Also "brands" each node with node index, or with "skip me" marker.
CountNodesTEP procCountNodes;
procCountNodes.m_cNodes = 0;
(void) pexpiface->theScene->EnumTree(&procCountNodes);
ASSERT_MBOX(procCountNodes.m_cNodes > 0, "No nodes!");
// Alloc and fill array
m_imaxnodeMac = procCountNodes.m_cNodes;
m_rgmaxnode = new MaxNode[m_imaxnodeMac];
ASSERT_MBOX(m_rgmaxnode != NULL, "new failed");
CollectNodesTEP procCollectNodes;
procCollectNodes.m_phec = this;
(void) pexpiface->theScene->EnumTree(&procCollectNodes);
return TRUE;
}
BOOL SmdExportClass::DumpBones(FILE *pFile, ExpInterface *pexpiface)
{
// Dump bone names
DumpNodesTEP procDumpNodes;
procDumpNodes.m_pfile = pFile;
procDumpNodes.m_phec = this;
fprintf(pFile, "nodes\n" );
(void) pexpiface->theScene->EnumTree(&procDumpNodes);
fprintf(pFile, "end\n" );
return TRUE;
}
BOOL SmdExportClass::DumpRotations(FILE *pFile, ExpInterface *pexpiface)
{
// Dump bone-rotation info, for each frame
// Also dumps root-node translation info (the model's world-position at each frame)
DumpFrameRotationsTEP procDumpFrameRotations;
procDumpFrameRotations.m_pfile = pFile;
procDumpFrameRotations.m_phec = this;
TimeValue m_tvTill = (m_fReferenceFrame) ? m_tvStart : m_tvEnd;
fprintf(pFile, "skeleton\n" );
for (TimeValue tv = m_tvStart; tv <= m_tvTill; tv += m_tpf)
{
fprintf(pFile, "time %d\n", tv / GetTicksPerFrame() );
procDumpFrameRotations.m_tvToDump = tv;
(void) pexpiface->theScene->EnumTree(&procDumpFrameRotations);
}
fprintf(pFile, "end\n" );
return TRUE;
}
BOOL SmdExportClass::DumpModel( FILE *pFile, ExpInterface *pexpiface)
{
// Dump mesh info: vertices, normals, UV texture map coords, bone assignments
DumpModelTEP procDumpModel;
procDumpModel.m_pfile = pFile;
procDumpModel.m_phec = this;
fprintf(pFile, "triangles\n" );
procDumpModel.m_tvToDump = m_tvStart;
(void) pexpiface->theScene->EnumTree(&procDumpModel);
fprintf(pFile, "end\n" );
return TRUE;
}
//=============================================================================
// TREE-ENUMERATION PROCEDURES
//=============================================================================
#define ASSERT_AND_ABORT(f, sz) \
if (!(f)) \
{ \
ASSERT_MBOX(FALSE, sz); \
cleanup( ); \
return TREE_ABORT; \
}
//=================================================================
// Methods for CountNodesTEP
//
int CountNodesTEP::callback( INode *node)
{
INode *pnode = node; // Hungarian
ASSERT_MBOX(!(pnode)->IsRootNode(), "Encountered a root node!");
if (::FUndesirableNode(pnode))
{
// Mark as skippable
::SetIndexOfINode(pnode, SmdExportClass::UNDESIRABLE_NODE_MARKER);
return TREE_CONTINUE;
}
// Establish "node index"--just ascending ints
::SetIndexOfINode(pnode, m_cNodes);
m_cNodes++;
return TREE_CONTINUE;
}
//=================================================================
// Methods for CollectNodesTEP
//
int CollectNodesTEP::callback(INode *node)
{
INode *pnode = node; // Hungarian
ASSERT_MBOX(!(pnode)->IsRootNode(), "Encountered a root node!");
if (::FNodeMarkedToSkip(pnode))
return TREE_CONTINUE;
// Get pre-stored "index"
int iNode = ::GetIndexOfINode(pnode);
ASSERT_MBOX(iNode >= 0 && iNode <= m_phec->m_imaxnodeMac-1, "Bogus iNode");
// Get name, store name in array
TSTR strNodeName(pnode->GetName());
strcpy(m_phec->m_rgmaxnode[iNode].szNodeName, (char*)strNodeName);
// Get Node's time-zero Transformation Matrices
m_phec->m_rgmaxnode[iNode].mat3NodeTM = pnode->GetNodeTM(0/*TimeValue*/);
m_phec->m_rgmaxnode[iNode].mat3ObjectTM = pnode->GetObjectTM(0/*TimeValue*/);
// I'll calculate this later
m_phec->m_rgmaxnode[iNode].imaxnodeParent = SmdExportClass::UNDESIRABLE_NODE_MARKER;
return TREE_CONTINUE;
}
//=================================================================
// Methods for DumpNodesTEP
//
int DumpNodesTEP::callback(INode *pnode)
{
ASSERT_MBOX(!(pnode)->IsRootNode(), "Encountered a root node!");
if (::FNodeMarkedToSkip(pnode))
return TREE_CONTINUE;
// Get node's parent
INode *pnodeParent;
pnodeParent = pnode->GetParentNode();
// The model's root is a child of the real "scene root"
TSTR strNodeName(pnode->GetName());
BOOL fNodeIsRoot = pnodeParent->IsRootNode( );
int iNode = ::GetIndexOfINode(pnode);
int iNodeParent = ::GetIndexOfINode(pnodeParent, !fNodeIsRoot/*fAssertPropExists*/);
// Convenient time to cache this
m_phec->m_rgmaxnode[iNode].imaxnodeParent = fNodeIsRoot ? SmdExportClass::UNDESIRABLE_NODE_MARKER : iNodeParent;
// Root node has no parent, thus no translation
if (fNodeIsRoot)
iNodeParent = -1;
// Dump node description
fprintf(m_pfile, "%3d \"%s\" %3d\n",
iNode,
strNodeName,
iNodeParent );
return TREE_CONTINUE;
}
//=================================================================
// Methods for DumpFrameRotationsTEP
//
int DumpFrameRotationsTEP::callback(INode *pnode)
{
ASSERT_MBOX(!(pnode)->IsRootNode(), "Encountered a root node!");
if (::FNodeMarkedToSkip(pnode))
return TREE_CONTINUE;
int iNode = ::GetIndexOfINode(pnode);
TSTR strNodeName(pnode->GetName());
// The model's root is a child of the real "scene root"
INode *pnodeParent = pnode->GetParentNode();
BOOL fNodeIsRoot = pnodeParent->IsRootNode( );
// Get Node's "Local" Transformation Matrix
Matrix3 mat3NodeTM = pnode->GetNodeTM(m_tvToDump);
Matrix3 mat3ParentTM = pnodeParent->GetNodeTM(m_tvToDump);
mat3NodeTM.NoScale(); // Clear these out because they apparently
mat3ParentTM.NoScale(); // screw up the following calculation.
Matrix3 mat3NodeLocalTM = mat3NodeTM * Inverse(mat3ParentTM);
Point3 rowTrans = mat3NodeLocalTM.GetTrans();
// Get the rotation (via decomposition into "affine parts", then quaternion-to-Euler)
// Apparently the order of rotations returned by QuatToEuler() is X, then Y, then Z.
AffineParts affparts;
float rgflXYZRotations[3];
decomp_affine(mat3NodeLocalTM, &affparts);
QuatToEuler(affparts.q, rgflXYZRotations);
float xRot = rgflXYZRotations[0]; // in radians
float yRot = rgflXYZRotations[1]; // in radians
float zRot = rgflXYZRotations[2]; // in radians
// Get rotations in the -2pi...2pi range
xRot = ::FlReduceRotation(xRot);
yRot = ::FlReduceRotation(yRot);
zRot = ::FlReduceRotation(zRot);
// Print rotations
//fprintf(m_pfile, "%3d %8.4f %8.4f %8.4f %8.4f %8.4f %8.4f\n",
fprintf(m_pfile, "%3d %f %f %f %f %f %f\n",
// Node:%-15s Rotation (x,y,z)\n",
iNode, rowTrans.x, rowTrans.y, rowTrans.z, xRot, yRot, zRot);
return TREE_CONTINUE;
}
//=================================================================
// Methods for DumpModelTEP
//
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;
}
// #define DEBUG_MESH_DUMP
//=================================================================
// Methods for DumpModelTEP
//
int DumpModelTEP::callback(INode *pnode)
{
Object* pobj;
int fHasMat = TRUE;
// clear physique export parameters
m_mcExport = NULL;
m_phyExport = NULL;
m_phyMod = NULL;
ASSERT_MBOX(!(pnode)->IsRootNode(), "Encountered a root node!");
if (::FNodeMarkedToSkip(pnode))
return TREE_CONTINUE;
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
pobj = pnode->GetObjectRef();
if (pobj->SuperClassID() == HELPER_CLASS_ID)
return TREE_CONTINUE;
// The model's root is a child of the real "scene root"
INode *pnodeParent = pnode->GetParentNode();
BOOL fNodeIsRoot = pnodeParent->IsRootNode( );
// Get node's material: should be a multi/sub (if it has a material at all)
Mtl *pmtlNode = pnode->GetMtl();
if (pmtlNode == NULL)
{
return TREE_CONTINUE;
fHasMat = FALSE;
}
else if (!(pmtlNode->ClassID() == Class_ID(MULTI_CLASS_ID, 0) && pmtlNode->IsMultiMtl()))
{
// sprintf(st_szDBG, "ERROR--Material on node %s isn't a Multi/Sub-Object", (char*)strNodeName);
// ASSERT_AND_ABORT(FALSE, st_szDBG);
fHasMat = FALSE;
}
// 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;
TriObject *ptriobj;
BOOL fConvertedToTriObject =
pobj->CanConvertToType(triObjectClassID) &&
(ptriobj = (TriObject*)pobj->ConvertToType(m_tvToDump, triObjectClassID)) != NULL;
if (!fConvertedToTriObject)
return TREE_CONTINUE;
Mesh *pmesh = &ptriobj->mesh;
// 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);
}
// Ensure that the vertex normals are up-to-date
pmesh->buildNormals();
// 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);
}
}
}
// Dump the triangle face info
int cFaces = pmesh->getNumFaces();
for (int iFace = 0; iFace < cFaces; iFace++)
{
Face* pface = &pmesh->faces[iFace];
TVFace* ptvface = &pmesh->tvFace[iFace];
DWORD smGroupFace = pface->getSmGroup();
// Get face's 3 indexes into the Mesh's vertex array(s).
DWORD iVertex0 = pface->getVert(0);
DWORD iVertex1 = pface->getVert(1);
DWORD iVertex2 = pface->getVert(2);
ASSERT_AND_ABORT((int)iVertex0 < pmesh->getNumVerts(), "Bogus Vertex 0 index");
ASSERT_AND_ABORT((int)iVertex1 < pmesh->getNumVerts(), "Bogus Vertex 1 index");
ASSERT_AND_ABORT((int)iVertex2 < pmesh->getNumVerts(), "Bogus Vertex 2 index");
// Get the 3 Vertex's for this face
Point3 pt3Vertex0 = pmesh->getVert(iVertex0);
Point3 pt3Vertex1 = pmesh->getVert(iVertex1);
Point3 pt3Vertex2 = pmesh->getVert(iVertex2);
// Get the 3 RVertex's for this face
// NOTE: I'm using getRVertPtr instead of getRVert to work around a 3DSMax bug
RVertex *prvertex0 = pmesh->getRVertPtr(iVertex0);
RVertex *prvertex1 = pmesh->getRVertPtr(iVertex1);
RVertex *prvertex2 = pmesh->getRVertPtr(iVertex2);
// Find appropriate normals for each RVertex
// A vertex can be part of multiple faces, so the "smoothing group"
// is used to locate the normal for this face's use of the vertex.
Point3 pt3Vertex0Normal;
Point3 pt3Vertex1Normal;
Point3 pt3Vertex2Normal;
if (smGroupFace)
{
pt3Vertex0Normal = Pt3GetRVertexNormal(prvertex0, smGroupFace);
pt3Vertex1Normal = Pt3GetRVertexNormal(prvertex1, smGroupFace);
pt3Vertex2Normal = Pt3GetRVertexNormal(prvertex2, smGroupFace);
}
else
{
pt3Vertex0Normal = pmesh->getFaceNormal( iFace );
pt3Vertex1Normal = pmesh->getFaceNormal( iFace );
pt3Vertex2Normal = pmesh->getFaceNormal( iFace );
}
ASSERT_AND_ABORT( Length( pt3Vertex0Normal ) <= 1.1, "bogus orig normal 0" );
ASSERT_AND_ABORT( Length( pt3Vertex1Normal ) <= 1.1, "bogus orig normal 1" );
ASSERT_AND_ABORT( Length( pt3Vertex2Normal ) <= 1.1, "bogus orig normal 2" );
// Get Face's sub-material from node's material, to get the bitmap name.
// And no, there isn't a simpler way to get the bitmap name, you have to
// dig down through all these levels.
TCHAR szBitmapName[256] = "null.bmp";
if (fHasMat)
{
MtlID mtlidFace = pface->getMatID();
if (mtlidFace >= pmtlNode->NumSubMtls())
{
sprintf(st_szDBG, "ERROR--Bogus sub-material index %d in node %s; highest valid index is %d",
mtlidFace, (char*)strNodeName, pmtlNode->NumSubMtls()-1);
// ASSERT_AND_ABORT(FALSE, st_szDBG);
mtlidFace = 0;
}
Mtl *pmtlFace = pmtlNode->GetSubMtl(mtlidFace);
ASSERT_AND_ABORT(pmtlFace != NULL, "NULL Sub-material returned");
if ((pmtlFace->ClassID() == Class_ID(MULTI_CLASS_ID, 0) && pmtlFace->IsMultiMtl()))
{
// it's a sub-sub material. Gads.
pmtlFace = pmtlFace->GetSubMtl(mtlidFace);
ASSERT_AND_ABORT(pmtlFace != NULL, "NULL Sub-material returned");
}
if (!(pmtlFace->ClassID() == Class_ID(DMTL_CLASS_ID, 0)))
{
sprintf(st_szDBG,
"ERROR--Sub-material with index %d (used in node %s) isn't a 'default/standard' material [%x].",
mtlidFace, (char*)strNodeName, pmtlFace->ClassID());
ASSERT_AND_ABORT(FALSE, st_szDBG);
}
StdMat *pstdmtlFace = (StdMat*)pmtlFace;
Texmap *ptexmap = pstdmtlFace->GetSubTexmap(ID_DI);
// ASSERT_AND_ABORT(ptexmap != NULL, "NULL diffuse texture")
if (ptexmap != NULL)
{
if (!(ptexmap->ClassID() == Class_ID(BMTEX_CLASS_ID, 0)))
{
sprintf(st_szDBG,
"ERROR--Sub-material with index %d (used in node %s) doesn't have a bitmap as its diffuse texture.",
mtlidFace, (char*)strNodeName);
ASSERT_AND_ABORT(FALSE, st_szDBG);
}
BitmapTex *pbmptex = (BitmapTex*)ptexmap;
strcpy(szBitmapName, pbmptex->GetMapName());
TSTR strPath, strFile;
SplitPathFile(TSTR(szBitmapName), &strPath, &strFile);
strcpy(szBitmapName,strFile);
}
}
UVVert UVvertex0( 0, 0, 0 );
UVVert UVvertex1( 1, 0, 0 );
UVVert UVvertex2( 0, 1, 0 );
// All faces must have textures assigned to them
if (pface->flags & HAS_TVERTS)
{
// Get TVface's 3 indexes into the Mesh's TVertex array(s).
DWORD iTVertex0 = ptvface->getTVert(0);
DWORD iTVertex1 = ptvface->getTVert(1);
DWORD iTVertex2 = ptvface->getTVert(2);
ASSERT_AND_ABORT((int)iTVertex0 < pmesh->getNumTVerts(), "Bogus TVertex 0 index");
ASSERT_AND_ABORT((int)iTVertex1 < pmesh->getNumTVerts(), "Bogus TVertex 1 index");
ASSERT_AND_ABORT((int)iTVertex2 < pmesh->getNumTVerts(), "Bogus TVertex 2 index");
// Get the 3 TVertex's for this TVFace
// NOTE: I'm using getRVertPtr instead of getRVert to work around a 3DSMax bug
UVvertex0 = pmesh->getTVert(iTVertex0);
UVvertex1 = pmesh->getTVert(iTVertex1);
UVvertex2 = pmesh->getTVert(iTVertex2);
}
else
{
//sprintf(st_szDBG, "ERROR--Node %s has a textureless face. All faces must have an applied texture.", (char*)strNodeName);
//ASSERT_AND_ABORT(FALSE, st_szDBG);
}
/*
const char *szExpectedExtension = ".bmp";
if (stricmp(szBitmapName+strlen(szBitmapName)-strlen(szExpectedExtension), szExpectedExtension) != 0)
{
sprintf(st_szDBG, "Node %s uses %s, which is not a %s file", (char*)strNodeName, szBitmapName, szExpectedExtension);
ASSERT_AND_ABORT(FALSE, st_szDBG);
}
*/
// Determine owning bones for the vertices.
int iNodeV0, iNodeV1, iNodeV2;
if (m_mcExport)
{
// The Physique add-in allows vertices to be assigned to bones arbitrarily
iNodeV0 = InodeOfPhyVectex( iVertex0 );
iNodeV1 = InodeOfPhyVectex( iVertex1 );
iNodeV2 = InodeOfPhyVectex( iVertex2 );
}
else
{
// Simple 3dsMax model: the vertices are owned by the object, and hence the node
iNodeV0 = iNode;
iNodeV1 = iNode;
iNodeV2 = iNode;
}
// Rotate the face vertices out of object-space, and into world-space space
Point3 v0 = pt3Vertex0 * mat3ObjectTM;
Point3 v1 = pt3Vertex1 * mat3ObjectTM;
Point3 v2 = pt3Vertex2 * mat3ObjectTM;
Matrix3 mat3ObjectNTM = mat3ObjectTM;
mat3ObjectNTM.NoScale( );
ASSERT_AND_ABORT( Length( pt3Vertex0Normal ) <= 1.1, "bogus pre normal 0" );
pt3Vertex0Normal = VectorTransform(mat3ObjectNTM, pt3Vertex0Normal);
ASSERT_AND_ABORT( Length( pt3Vertex0Normal ) <= 1.1, "bogus post normal 0" );
ASSERT_AND_ABORT( Length( pt3Vertex1Normal ) <= 1.1, "bogus pre normal 1" );
pt3Vertex1Normal = VectorTransform(mat3ObjectNTM, pt3Vertex1Normal);
ASSERT_AND_ABORT( Length( pt3Vertex1Normal ) <= 1.1, "bogus post normal 1" );
ASSERT_AND_ABORT( Length( pt3Vertex2Normal ) <= 1.1, "bogus pre normal 2" );
pt3Vertex2Normal = VectorTransform(mat3ObjectNTM, pt3Vertex2Normal);
ASSERT_AND_ABORT( Length( pt3Vertex2Normal ) <= 1.1, "bogus post normal 2" );
// Finally dump the bitmap name and 3 lines of face info
fprintf(m_pfile, "%s\n", szBitmapName);
fprintf(m_pfile, "%3d %8.4f %8.4f %8.4f %8.4f %8.4f %8.4f %8.4f %8.4f\n",
iNodeV0, v0.x, v0.y, v0.z,
pt3Vertex0Normal.x, pt3Vertex0Normal.y, pt3Vertex0Normal.z,
UVvertex0.x, UVvertex0.y);
fprintf(m_pfile, "%3d %8.4f %8.4f %8.4f %8.4f %8.4f %8.4f %8.4f %8.4f\n",
iNodeV1, v1.x, v1.y, v1.z,
pt3Vertex1Normal.x, pt3Vertex1Normal.y, pt3Vertex1Normal.z,
UVvertex1.x, UVvertex1.y);
fprintf(m_pfile, "%3d %8.4f %8.4f %8.4f %8.4f %8.4f %8.4f %8.4f %8.4f\n",
iNodeV2, v2.x, v2.y, v2.z,
pt3Vertex2Normal.x, pt3Vertex2Normal.y, pt3Vertex2Normal.z,
UVvertex2.x, UVvertex2.y);
}
cleanup( );
return TREE_CONTINUE;
}
void DumpModelTEP::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;
}
}
int DumpModelTEP::InodeOfPhyVectex(int iVertex)
{
int iNode = 0;
IPhyVertexExport *vtxExport = m_mcExport->GetVertexInterface(iVertex);
if (vtxExport)
{
//need to check if vertex has blending
if (vtxExport->GetVertexType() & BLENDED_TYPE)
{
//
}
else
{
INode *Bone = ((IPhyRigidVertex *)vtxExport)->GetNode();
iNode = GetIndexOfINode(Bone);
}
m_mcExport->ReleaseVertexInterface(vtxExport);
}
return iNode;
}
Point3 DumpModelTEP::Pt3GetRVertexNormal(RVertex *prvertex, DWORD smGroupFace)
{
// Lookup the appropriate vertex normal, based on smoothing group.
int cNormals = prvertex->rFlags & NORCT_MASK;
ASSERT_MBOX((cNormals == 1 && prvertex->ern == NULL) ||
(cNormals > 1 && prvertex->ern != NULL), "BOGUS RVERTEX");
if (cNormals == 1)
return prvertex->rn.getNormal();
else
{
for (int irn = 0; irn < cNormals; irn++)
if (prvertex->ern[irn].getSmGroup() & smGroupFace)
break;
if (irn >= cNormals)
{
irn = 0;
// ASSERT_MBOX(irn < cNormals, "unknown smoothing group\n");
}
return prvertex->ern[irn].getNormal();
}
}
//===========================================================
// Dialog proc for export options
//
static BOOL CALLBACK ExportOptionsDlgProc(
HWND hDlg,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
static SmdExportClass *pexp;
switch (message)
{
case WM_INITDIALOG:
pexp = (SmdExportClass*) lParam;
CheckRadioButton(hDlg, IDC_CHECK_SKELETAL, IDC_CHECK_REFFRAME, IDC_CHECK_SKELETAL);
return FALSE;
case WM_DESTROY:
return FALSE;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDOK:
pexp->m_fReferenceFrame = IsDlgButtonChecked(hDlg, IDC_CHECK_REFFRAME);
EndDialog(hDlg, 1); // 1 indicates "ok to export"
return TRUE;
case IDCANCEL: // 0 indicates "cancel export"
EndDialog(hDlg, 0);
return TRUE;
case IDC_CHECK_SKELETAL:
case IDC_CHECK_REFFRAME:
CheckRadioButton(hDlg, IDC_CHECK_SKELETAL, IDC_CHECK_REFFRAME, LOWORD(wParam));
break;
}
}
return FALSE;
}
//========================================================================
// 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[SmdExportClass::MAX_NAME_CHARS];
int iNode;
} NAMEMAP;
const int MAX_NAMEMAP = 512;
static NAMEMAP g_rgnm[MAX_NAMEMAP];
int GetIndexOfINode(INode *pnode, BOOL fAssertPropExists)
{
TSTR strNodeName(pnode->GetName());
for (int inm = 0; inm < g_inmMac; inm++)
if (FStrEq(g_rgnm[inm].szNodeName, (char*)strNodeName))
return g_rgnm[inm].iNode;
if (fAssertPropExists)
ASSERT_MBOX(FALSE, "No NODEINDEXSTR property");
return -7777;
}
void SetIndexOfINode(INode *pnode, int inode)
{
TSTR strNodeName(pnode->GetName());
NAMEMAP *pnm;
for (int inm = 0; inm < g_inmMac; inm++)
if (FStrEq(g_rgnm[inm].szNodeName, (char*)strNodeName))
break;
if (inm < g_inmMac)
pnm = &g_rgnm[inm];
else
{
ASSERT_MBOX(g_inmMac < MAX_NAMEMAP, "NAMEMAP is full");
pnm = &g_rgnm[g_inmMac++];
strcpy(pnm->szNodeName, (char*)strNodeName);
}
pnm->iNode = inode;
}
//=============================================================
// 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();
// Don't care about lights, dummies, and cameras
if (pobj->SuperClassID() == CAMERA_CLASS_ID)
return TRUE;
if (pobj->SuperClassID() == LIGHT_CLASS_ID)
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) == SmdExportClass::UNDESIRABLE_NODE_MARKER);
}
//=============================================================
// Reduces a rotation to within the -2PI..2PI range.
//
static float FlReduceRotation(float fl)
{
while (fl >= TWOPI)
fl -= TWOPI;
while (fl <= -TWOPI)
fl += TWOPI;
return fl;
}

View File

@ -0,0 +1,8 @@
LIBRARY smdlexp
EXPORTS
LibDescription @1
LibNumberClasses @2
LibClassDesc @3
LibVersion @4
SECTIONS
.data READ WRITE

View File

@ -0,0 +1,135 @@
# Microsoft Developer Studio Project File - Name="smdlexp" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
CFG=smdlexp - Win32 Release
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "smdlexp.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "smdlexp.mak" CFG="smdlexp - Win32 Release"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "smdlexp - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE "smdlexp - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""$/SDKSrc/Tools/utils/smdlexp", GVGBAAAA"
# PROP Scc_LocalPath "."
CPP=cl.exe
MTL=midl.exe
RSC=rc.exe
!IF "$(CFG)" == "smdlexp - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir ".\Release"
# PROP BASE Intermediate_Dir ".\Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir ".\Release"
# PROP Intermediate_Dir ".\Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
# ADD CPP /nologo /MT /W3 /GX /O2 /I "\3DSMAX2.5\MAXSDK\INCLUDE" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
# ADD BASE MTL /nologo /D "NDEBUG" /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib COMCTL32.LIB /nologo /subsystem:windows /dll /machine:I386 /out:"\3dsmax2.5\Plugins\smdlexp.dle"
!ELSEIF "$(CFG)" == "smdlexp - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir ".\Debug"
# PROP BASE Intermediate_Dir ".\Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir ".\Debug"
# PROP Intermediate_Dir ".\Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c
# ADD CPP /nologo /MD /W3 /Gm /GX /ZI /Od /I "\3DSMAX2.5\MAXSDK\INCLUDE" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /FD /c
# ADD BASE MTL /nologo /D "_DEBUG" /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /debug /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib COMCTL32.LIB /nologo /subsystem:windows /dll /debug /machine:I386 /out:"\3DSMAX2.5\plugins\SMDLEXP.DLE"
!ENDIF
# Begin Target
# Name "smdlexp - Win32 Release"
# Name "smdlexp - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;for;f90"
# Begin Source File
SOURCE=.\smdlexp.cpp
# End Source File
# Begin Source File
SOURCE=.\smdlexp.def
# End Source File
# Begin Source File
SOURCE=.\smdlexp.rc
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
# Begin Source File
SOURCE=.\smedefs.h
# End Source File
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe"
# End Group
# Begin Source File
SOURCE=\3DSMAX2.5\Maxsdk\LIB\UTIL.LIB
# End Source File
# Begin Source File
SOURCE=\3DSMAX2.5\Maxsdk\LIB\GEOM.LIB
# End Source File
# Begin Source File
SOURCE=\3DSMAX2.5\Maxsdk\LIB\MESH.LIB
# End Source File
# Begin Source File
SOURCE=\3DSMAX2.5\Maxsdk\LIB\CORE.LIB
# End Source File
# End Target
# End Project

View File

@ -0,0 +1,33 @@
Microsoft Developer Studio Workspace File, Format Version 6.00
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
###############################################################################
Project: "smdlexp"=.\smdlexp.dsp - Package Owner=<4>
Package=<5>
{{{
begin source code control
"$/SDKSrc/Tools/utils/smdlexp", GVGBAAAA
.
end source code control
}}}
Package=<4>
{{{
}}}
###############################################################################
Global:
Package=<5>
{{{
}}}
Package=<3>
{{{
}}}
###############################################################################

View File

@ -0,0 +1,147 @@
//Microsoft Developer Studio generated resource script.
//
#include "smexprc.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_EXPORTOPTIONS DIALOG DISCARDABLE 0, 0, 186, 42
STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "SMD Exporter"
FONT 8, "MS Sans Serif"
BEGIN
DEFPUSHBUTTON "OK",IDOK,129,7,50,14
PUSHBUTTON "Cancel",IDCANCEL,129,22,50,14
CONTROL "Skeletal Animation",IDC_CHECK_SKELETAL,"Button",
BS_AUTORADIOBUTTON | WS_GROUP,15,10,74,10
CONTROL "Reference Frame",IDC_CHECK_REFFRAME,"Button",
BS_AUTORADIOBUTTON | WS_GROUP,15,24,71,10
END
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO DISCARDABLE
BEGIN
IDD_EXPORTOPTIONS, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 179
TOPMARGIN, 7
BOTTOMMARGIN, 36
END
END
#endif // APSTUDIO_INVOKED
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE DISCARDABLE
BEGIN
"smexprc.h\0"
END
2 TEXTINCLUDE DISCARDABLE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END
3 TEXTINCLUDE DISCARDABLE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
#ifndef _MAC
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 2,0,0,1
PRODUCTVERSION 2,0,0,1
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
FILETYPE 0x2L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "Comments", "\0"
VALUE "CompanyName", "Valve LLC\0"
VALUE "FileDescription", "SMD file exporter (3D Studio Max plugin)\0"
VALUE "FileVersion", "2, 0, 0, 1\0"
VALUE "InternalName", "SMDLEXP\0"
VALUE "LegalCopyright", "Copyright <20> 1998, Valve LLC\0"
VALUE "LegalTrademarks", "The following are registered trademarks of Autodesk, Inc.: 3D Studio MAX. The following are trademarks of Autodesk, Inc.: Kinetix, Kinetix(logo), BIPED, Physique, Character Studio, MAX DWG, DWG Unplugged, Heidi, FLI, FLC, DXF.\0"
VALUE "OriginalFilename", "SMDLEXP.DLE\0"
VALUE "PrivateBuild", "\0"
VALUE "ProductName", "Valve LLC SMDLEXP\0"
VALUE "ProductVersion", "2, 0, 0, 1\0"
VALUE "SpecialBuild", "\0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
#endif // !_MAC
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

View File

@ -0,0 +1,174 @@
/***
*
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
*
****/
//===================================================================
// Useful macros
//
#define CONSTRUCTOR
#define DESTRUCTOR
#define EXPORT_THIS __declspec(dllexport)
#define DEFAULT_EXT _T("smd")
#define FStrEq(sz1, sz2) (strcmp((sz1), (sz2)) == 0)
//===================================================================
// Class that implements the scene-export.
//
class SmdExportClass : public SceneExport
{
friend BOOL CALLBACK ExportOptionsDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
friend class DumpModelTEP;
friend class DumpDeformsTEP;
public:
CONSTRUCTOR SmdExportClass (void);
DESTRUCTOR ~SmdExportClass (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 SMD"); }
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); // Export file
// 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
float xRotFirstFrame; // 1st frame's X rotation
float yRotFirstFrame; // 1st frame's Y rotation
float zRotFirstFrame; // 1st frame's Z rotation
} MaxNode;
MaxNode *m_rgmaxnode; // array of nodes
long m_imaxnodeMac; // # of nodes
// 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:
BOOL CollectNodes (ExpInterface *expiface);
BOOL DumpBones (FILE *pFile, ExpInterface *pexpiface);
BOOL DumpRotations (FILE *pFile, ExpInterface *pexpiface);
BOOL DumpModel (FILE *pFile, ExpInterface *pexpiface);
BOOL DumpDeforms (FILE *pFile, ExpInterface *pexpiface);
// Is this MAX file just the reference frame, or an animation?
// If TRUE, the "bones" and "mesh" files will be created.
// If FALSE, the "rots" file will be created.
BOOL m_fReferenceFrame;
};
//===================================================================
// Basically just a ClassFactory for communicating with 3DSMAX.
//
class SmdExportClassDesc : public ClassDesc
{
public:
int IsPublic (void) { return TRUE; }
void * Create (BOOL loading=FALSE) { return new SmdExportClass; }
const TCHAR * ClassName (void) { return _T("SmdExport"); }
SClass_ID SuperClassID (void) { return SCENE_EXPORT_CLASS_ID; }
Class_ID ClassID (void) { return Class_ID(0x774a43fd, 0x794d2210); }
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);
SmdExportClass *m_phec;
};
//===================================================================
// Tree Enumeration Callback
// Dumps the bone offsets to a file.
//
class DumpNodesTEP : public ITreeEnumProc
{
public:
virtual int callback(INode *node);
FILE *m_pfile; // write to this file
SmdExportClass *m_phec;
};
//===================================================================
// Tree Enumeration Callback
// Dumps the per-frame bone rotations to a file.
//
class DumpFrameRotationsTEP : 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
SmdExportClass *m_phec;
};
//===================================================================
// Tree Enumeration Callback
// Dumps the triangle meshes to a file.
//
class DumpModelTEP : 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
SmdExportClass *m_phec;
IPhyContextExport *m_mcExport;
IPhysiqueExport *m_phyExport;
Modifier *m_phyMod;
private:
int InodeOfPhyVectex( int iVertex0 );
Point3 Pt3GetRVertexNormal(RVertex *prvertex, DWORD smGroupFace);
};

View File

@ -0,0 +1,21 @@
//{{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