📄 smdlexp.cpp
字号:
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 (ptvface && (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;
// 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",
iNodeV0, v0.x, v0.y, v0.z,
pt3Vertex0Normal.x, pt3Vertex0Normal.y, pt3Vertex0Normal.z,
UVvertex0.x, UVvertex0.y);
DumpWeights( iVertex0 );
fprintf(m_pfile, "%3d %8.4f %8.4f %8.4f %8.4f %8.4f %8.4f %8.4f %8.4f",
iNodeV1, v1.x, v1.y, v1.z,
pt3Vertex1Normal.x, pt3Vertex1Normal.y, pt3Vertex1Normal.z,
UVvertex1.x, UVvertex1.y);
DumpWeights( iVertex1 );
fprintf(m_pfile, "%3d %8.4f %8.4f %8.4f %8.4f %8.4f %8.4f %8.4f %8.4f",
iNodeV2, v2.x, v2.y, v2.z,
pt3Vertex2Normal.x, pt3Vertex2Normal.y, pt3Vertex2Normal.z,
UVvertex2.x, UVvertex2.y);
DumpWeights( iVertex2 );
}
cleanup( );
return TREE_CONTINUE;
}
#define MAX_BLEND_WEIGHTS 8
static struct {
int iNode;
float flWeight;
} aWeights[MAX_BLEND_WEIGHTS+1];
int AddWeight( int iCount, int iNode, float flWeight )
{
if (flWeight < 0.001)
return iCount;
for (int i = 0; i < iCount; i++)
{
if (aWeights[i].flWeight < flWeight)
{
for (int j = iCount; j > i; j--)
{
aWeights[j] = aWeights[j-1];
}
break;
}
}
aWeights[i].iNode = iNode;
aWeights[i].flWeight = flWeight;
iCount++;
if (iCount > MAX_BLEND_WEIGHTS)
iCount = MAX_BLEND_WEIGHTS;
return iCount;
}
void DumpModelTEP::DumpWeights(int iVertex)
{
if (m_mcExport)
{
IPhyVertexExport *vtxExport = m_mcExport->GetVertexInterface(iVertex);
if (vtxExport)
{
if (vtxExport->GetVertexType() & BLENDED_TYPE)
{
IPhyBlendedRigidVertex *pBlend = ((IPhyBlendedRigidVertex *)vtxExport);
int iCount = 0;
for (int i = 0; i < pBlend->GetNumberNodes(); i++)
{
iCount = AddWeight( iCount, GetIndexOfINode( pBlend->GetNode( i ) ), pBlend->GetWeight( i ) );
}
fprintf(m_pfile, " %2d ", iCount );
for (i = 0; i < iCount; i++)
{
fprintf(m_pfile, " %2d %5.3f ", aWeights[i].iNode, aWeights[i].flWeight );
}
}
else
{
INode *Bone = ((IPhyRigidVertex *)vtxExport)->GetNode();
fprintf(m_pfile, " 1 %2d 1.000", GetIndexOfINode(Bone) );
}
m_mcExport->ReleaseVertexInterface(vtxExport);
}
}
else if (m_wa != NULL)
{
int iCount = 0;
for ( int iBone = 0; iBone < m_wa->nb; iBone++)
{
if (m_wa->w[iVertex * m_wa->nb + iBone] > 0.0)
{
BonesPro_Bone bone;
bone.t = BP_TIME_ATTACHED;
bone.index = iBone;
m_bonesProMod->SetProperty( BP_PROPID_GET_BONE_STAT, &bone );
if (bone.node != NULL)
{
iCount = AddWeight( iCount, GetIndexOfINode( bone.node ), m_wa->w[iVertex * m_wa->nb + iBone] );
}
}
}
fprintf(m_pfile, " %2d ", iCount );
for (int i = 0; i < iCount; i++)
{
fprintf(m_pfile, " %2d %5.3f ", aWeights[i].iNode, aWeights[i].flWeight );
}
}
fprintf(m_pfile, "\n" );
fflush( m_pfile );
}
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;
}
}
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);
SetFocus(GetDlgItem(hDlg,IDOK));
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;
}
//=============================================================
// 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;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -