DragonNest/Client/ActorEternity/ActorEternity.cpp
Cussrro 47f7895977 Revert "修复编码问题"
This reverts commit 9e69c01767.
2024-12-21 10:04:04 +08:00

1983 lines
46 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**********************************************************************
*<
FILE: ActorEt.cpp
DESCRIPTION: Appwizard generated plugin
CREATED BY:
HISTORY:
*> Copyright (c) 2003, All Rights Reserved.
**********************************************************************/
#include "Stdafx.h"
#include "Windows.h"
#include "ActorEternity.h"
#include "phyexp.h"
#include "bipexp.h"
#include "DumpUtil.h"
#include "CollisionPrimitive.h"
#include "SaveCamera.h"
//#include "SaveNavigation.h"
#include "MAXScrpt.h"
#include "definsfn.h"
def_visible_primitive( save_ani,"SaveAni");
#define CAPS_RADIUS 0 // these are the ParamBlock indexes
#define CAPS_HEIGHT 1
#define CAPS_CENTERS 2
#define CAPS_SIDES 3
#define CAPS_HSEGS 4
#define CAPS_SMOOTHON 5
#define CAPS_SLICEON 6
#define CAPS_SLICEFROM 7
#define CAPS_SLICETO 8
#define CAPS_GENUVS 9
static Class_ID CAPS_CLASS_ID(0x6d3d77ac, 0x79c939a9);
#define ActorEt_CLASS_ID Class_ID(0x60f6a2ef, 0xd1ef347d)
ActorEt theActorEt;
class ActorEtClassDesc : public ClassDesc2 {
public:
int IsPublic() { return TRUE; }
void * Create(BOOL loading = FALSE) { return &theActorEt; }
const TCHAR * ClassName() { return GetString(IDS_CLASS_NAME); }
SClass_ID SuperClassID() { return UTILITY_CLASS_ID; }
Class_ID ClassID() { return ActorEt_CLASS_ID; }
const TCHAR* Category() { return GetString(IDS_CATEGORY); }
const TCHAR* InternalName() { return _T("ActorEt"); } // returns fixed parsable name (scripter-visible name)
HINSTANCE HInstance() { return hInstance; } // returns owning module handle
};
static ActorEtClassDesc ActorEtDesc;
ClassDesc2* GetActorEtDesc() { return &ActorEtDesc; }
int g_nAniQuality = 0;
static BOOL CALLBACK ActorEtDlgProc(
HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_INITDIALOG:
theActorEt.Init(hWnd);
break;
case WM_DESTROY:
theActorEt.Destroy(hWnd);
break;
case WM_COMMAND:
switch ( HIWORD( wParam ) )
{
case EN_SETFOCUS: DisableAccelerators();
break;
case EN_KILLFOCUS: EnableAccelerators();
break;
}
switch ( LOWORD( wParam ) )
{
case IDC_SAVEMESH:
theActorEt.SaveMesh( hWnd );
break;
case IDC_SAVEANI:
theActorEt.SaveAni( hWnd );
break;
case IDC_SAVECAMERA:
theActorEt.SaveCamera( hWnd );
break;
case IDC_SAVE_NAVIGATION:
theActorEt.SaveNavigation( hWnd );
break;
}
break;
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
case WM_MOUSEMOVE:
theActorEt.m_pMaxInterface->RollupMouseMessage(hWnd,msg,wParam,lParam);
break;
default:
return FALSE;
}
return TRUE;
}
static BOOL CALLBACK ActorEtOptionDlgProc(
HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg) {
case WM_INITDIALOG:
theActorEt.InitOption( hWnd );
break;
case WM_DESTROY:
theActorEt.DestroyOption( hWnd );
break;
case WM_COMMAND:
switch ( LOWORD( wParam ) )
{
case IDC_EXPORT_SELECTED:
theActorEt.m_nExportSelected = _GetCheckBox( hWnd, IDC_EXPORT_SELECTED );
theActorEt.m_RegUtil.SetKeyValue( "ExportSelected", theActorEt.m_nExportSelected );
break;
case IDC_USE_STRIP:
theActorEt.m_nUseStrip = _GetCheckBox( hWnd, IDC_USE_STRIP );
theActorEt.m_RegUtil.SetKeyValue( "UseStrip", theActorEt.m_nUseStrip );
break;
case IDC_GENERATE_LOD:
theActorEt.m_nGenerateLOD = _GetCheckBox( hWnd, IDC_GENERATE_LOD );
theActorEt.m_RegUtil.SetKeyValue( "GenerateLOD", theActorEt.m_nGenerateLOD );
break;
case IDC_GENERATE_UV_ANI:
theActorEt.m_nGenerateUVAni = _GetCheckBox( hWnd, IDC_GENERATE_UV_ANI );
theActorEt.m_RegUtil.SetKeyValue( "GenerateUVAni", theActorEt.m_nGenerateUVAni );
break;
case IDC_EXPORT_VERTEXCOLOR:
theActorEt.m_nExportVertexColor = _GetCheckBox( hWnd, IDC_EXPORT_VERTEXCOLOR );
theActorEt.m_RegUtil.SetKeyValue( "ExportVertexColor", theActorEt.m_nExportVertexColor );
break;
case IDC_EXPORT_TARGET_CAMERA:
theActorEt.m_nExportTargetCamera = _GetCheckBox( hWnd, IDC_EXPORT_TARGET_CAMERA );
theActorEt.m_RegUtil.SetKeyValue( "ExportTargetCamera", theActorEt.m_nExportTargetCamera );
break;
}
break;
default:
return FALSE;
}
return TRUE;
}
//--- ActorEt -------------------------------------------------------
ActorEt::ActorEt()
{
iu = NULL;
m_pMaxInterface = NULL;
hPanel = NULL;
m_hOptionPanel = NULL;
m_RegUtil.SetRegistryPath( "Software\\Eyedentitygames\\ActorEt" );
m_nExportSelected = 0;
m_nUseStrip = 1;
m_nGenerateLOD = 1;
m_nGenerateUVAni = 0;
m_nExportTargetCamera = 0;
m_nNoInfluenceBoneError = 0;
m_nInfluenceBoneExceedError = 0;
m_nMaxWeightZeroError = 0;
}
ActorEt::~ActorEt()
{
}
void ActorEt::BeginEditParams(Interface *ip,IUtil *iu)
{
this->iu = iu;
this->m_pMaxInterface = ip;
hPanel = ip->AddRollupPage(
hInstance,
MAKEINTRESOURCE(IDD_PANEL),
ActorEtDlgProc,
_T("ActorEt - Export"),
0);
m_hOptionPanel = ip->AddRollupPage(
hInstance,
MAKEINTRESOURCE(IDD_OPTION),
ActorEtOptionDlgProc,
_T("ActorEt - Option"),
0);
}
void ActorEt::EndEditParams(Interface *ip,IUtil *iu)
{
this->iu = NULL;
this->m_pMaxInterface = NULL;
ip->DeleteRollupPage(hPanel);
ip->DeleteRollupPage(m_hOptionPanel);
hPanel = NULL;
m_hOptionPanel = NULL;
}
void ActorEt::Init(HWND hWnd)
{
}
void ActorEt::Destroy(HWND hWnd)
{
}
void ActorEt::InitOption(HWND hWnd)
{
m_nUseStrip = 1;
m_nGenerateLOD = 1;
m_nGenerateUVAni = 0;
m_nExportTargetCamera = 0;
m_RegUtil.GetKeyValue( "UseStrip", m_nUseStrip );
_SetCheckBox( hWnd, IDC_USE_STRIP, m_nUseStrip ? 1 : 0 );
m_RegUtil.GetKeyValue( "GenerateLOD", m_nGenerateLOD );
_SetCheckBox( hWnd, IDC_GENERATE_LOD, m_nGenerateLOD ? 1 : 0 );
m_RegUtil.GetKeyValue( "GenerateUVAni", m_nGenerateUVAni );
_SetCheckBox( hWnd, IDC_GENERATE_UV_ANI, m_nGenerateUVAni ? 1 : 0 );
m_RegUtil.GetKeyValue( "ExportVertexColor", m_nExportVertexColor );
_SetCheckBox( hWnd, IDC_EXPORT_VERTEXCOLOR, m_nExportVertexColor ? 1 : 0 );
m_RegUtil.GetKeyValue( "ExportTargetCamera", m_nExportTargetCamera );
_SetCheckBox( hWnd, IDC_EXPORT_TARGET_CAMERA, m_nExportTargetCamera ? 1 : 0 );
}
void ActorEt::DestroyOption(HWND hWnd)
{
m_RegUtil.SetKeyValue( "UseStrip", m_nUseStrip );
m_RegUtil.SetKeyValue( "GenerateLOD", m_nGenerateLOD );
m_RegUtil.SetKeyValue( "GenerateUVAni", m_nGenerateUVAni );
}
void ActorEt::SaveMesh( HWND hWnd )
{
OPENFILENAME Ofn;
char szFullFileName[ _MAX_PATH ], szFileName[ _MAX_PATH ], szSkinName[ _MAX_PATH ], *pFindStr;
m_pBoundingBox = NULL;
memset( szFullFileName, 0, _MAX_PATH );
memset( &Ofn, 0, sizeof( OPENFILENAME ) );
Ofn.lStructSize = sizeof( OPENFILENAME );
Ofn.hwndOwner = hWnd;
Ofn.lpstrFilter = "Eternity Engine Mesh File (*.msh)\0*.msh\0\0";
Ofn.lpstrFile = szFullFileName;
Ofn.nMaxFile = _MAX_PATH;
Ofn.lpstrFileTitle = szFileName;
Ofn.nMaxFileTitle = _MAX_PATH;
Ofn.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
Ofn.lpstrDefExt = "msh";
if( GetSaveFileName( &Ofn ) )
{
m_MaterialList.clear();
GetNodeList();
WriteMesh( Ofn.lpstrFile );
strcpy( szSkinName, Ofn.lpstrFile );
pFindStr = strrchr( szSkinName, '.' );
if( pFindStr )
{
strcpy( pFindStr, ".skn" );
}
else
{
strcat( szSkinName, ".skn" );
}
WriteSkin( szSkinName, Ofn.lpstrFileTitle );
}
}
void ActorEt::SaveAni( HWND hWnd, char *pFileName )
{
if( pFileName )
{
GetNodeList();
WriteAni( pFileName );
}
else
{
OPENFILENAME Ofn;
char szFullFileName[ _MAX_PATH ], szFileName[ _MAX_PATH ];
memset( szFullFileName, 0, _MAX_PATH );
memset( &Ofn, 0, sizeof( OPENFILENAME ) );
Ofn.lStructSize = sizeof( OPENFILENAME );
Ofn.hwndOwner = hWnd;
Ofn.lpstrFilter = "Eternity Engine Animation File (*.ani)\0*.ani\0\0";
Ofn.lpstrFile = szFullFileName;
Ofn.nMaxFile = _MAX_PATH;
Ofn.lpstrFileTitle = szFileName;
Ofn.nMaxFileTitle = _MAX_PATH;
Ofn.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
Ofn.lpstrDefExt = "ani";
if( GetSaveFileName( &Ofn ) )
{
GetNodeList();
WriteAni( Ofn.lpstrFile );
}
}
}
void ActorEt::SaveCamera( HWND hWnd )
{
OPENFILENAME Ofn;
char szFullFileName[ _MAX_PATH ], szFileName[ _MAX_PATH ];
m_pBoundingBox = NULL;
memset( szFullFileName, 0, _MAX_PATH );
memset( &Ofn, 0, sizeof( OPENFILENAME ) );
Ofn.lStructSize = sizeof( OPENFILENAME );
Ofn.hwndOwner = hWnd;
Ofn.lpstrFilter = "Eternity Engine Camera File (*.cam)\0*.cam\0\0";
Ofn.lpstrFile = szFullFileName;
Ofn.nMaxFile = _MAX_PATH;
Ofn.lpstrFileTitle = szFileName;
Ofn.nMaxFileTitle = _MAX_PATH;
Ofn.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
Ofn.lpstrDefExt = "msh";
if( GetSaveFileName( &Ofn ) )
{
GetNodeList();
WriteCamera( Ofn.lpstrFile );
}
}
void ActorEt::SaveNavigation( HWND hWnd )
{
OPENFILENAME Ofn;
char szFullFileName[ _MAX_PATH ], szFileName[ _MAX_PATH ];
m_pBoundingBox = NULL;
memset( szFullFileName, 0, _MAX_PATH );
memset( &Ofn, 0, sizeof( OPENFILENAME ) );
Ofn.lStructSize = sizeof( OPENFILENAME );
Ofn.hwndOwner = hWnd;
Ofn.lpstrFilter = "Eternity Engine Navigation Mesh File (*.nav)\0*.nav\0\0";
Ofn.lpstrFile = szFullFileName;
Ofn.nMaxFile = _MAX_PATH;
Ofn.lpstrFileTitle = szFileName;
Ofn.nMaxFileTitle = _MAX_PATH;
Ofn.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
Ofn.lpstrDefExt = "nav";
if( GetSaveFileName( &Ofn ) )
{
GetNodeList();
WriteNavigation( Ofn.lpstrFile );
}
}
void ActorEt::GetNodeList()
{
int i;
m_vecNodeList.clear();
for( i = 0; i < m_pMaxInterface->GetRootNode()->NumberOfChildren(); i ++ )
{
AddNodeList( m_pMaxInterface->GetRootNode()->GetChildNode( i ) );
}
}
void ActorEt::AddNodeList( INode *pNode )
{
int i;
SNodeInfo NodeInfo;
if( pNode == NULL )
{
return;
}
TCHAR *pNodeName;
pNodeName = pNode->GetName();
NodeInfo.pNode = pNode;
NodeInfo.nNodeFlag = 0;
if( IsMeshObject( pNode ) )
{
NodeInfo.nNodeFlag |= NODE_FLAG_MESH;
}
if( IsBoneObject( pNode ) )
{
NodeInfo.nNodeFlag |= NODE_FLAG_BONE;
}
if( IsCameraObject( pNode ) )
{
NodeInfo.nNodeFlag |= NODE_FLAG_CAMERA;
}
if( IsDummyObject( pNode ) )
{
NodeInfo.nNodeFlag |= NODE_FLAG_DUMMY;
}
if( IsCollisionMeshObject( pNode ) )
{
NodeInfo.nNodeFlag = 0; // Collision Mesh <20≯鼭 <20>ٸ<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>ϼ<EFBFBD> <20><><EFBFBD><EFBFBD>.
NodeInfo.nNodeFlag |= NODE_FLAG_COLLISION;
}
m_vecNodeList.push_back( NodeInfo );
for( i = 0; i < pNode->NumberOfChildren(); i++ )
{
AddNodeList( pNode->GetChildNode( i ) );
}
}
bool ActorEt::IsMeshObject( INode *pNode )
{
Object *pObject;
TCHAR *pNodeName;
pObject = pNode->EvalWorldState( 0 ).obj; // <20>ð<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>־<EFBFBD><D6BE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>..
pNodeName = pNode->GetName();
if( stricmp( pNodeName, "BoundingBox" ) == 0 )
{
m_pBoundingBox = pNode;
return false;
}
if( ( m_nExportSelected ) && ( !pNode->Selected() ) )
{
return false;
}
if( pNode->IsFrozen() )
{
return false;
}
if( pObject->SuperClassID() != GEOMOBJECT_CLASS_ID )
{
return false;
}
// Check Collision Mesh
if( pObject->ClassID() == Class_ID( BOXOBJ_CLASS_ID, 0 ) )
{
return false;
}
if( pObject->ClassID() == Class_ID( SPHERE_CLASS_ID, 0 ) )
{
return false;
}
if( pObject->ClassID() == Class_ID( CYLINDER_CLASS_ID, 0 ) )
{
return false;
}
if( pObject->ClassID() == CAPS_CLASS_ID )
{
return false;
}
// Check Bone
if( pObject->ClassID() == Class_ID( TARGET_CLASS_ID, 0 ) )
{
return false;
}
if( pObject->ClassID() == BONE_OBJ_CLASSID )
{
return false;
}
if( pObject->ClassID() == BIPSLAVE_CONTROL_CLASS_ID )
{
return false;
}
if( pObject->ClassID() == BIPBODY_CONTROL_CLASS_ID )
{
return false;
}
if( pObject->ClassID() == FOOTPRINT_CLASS_ID )
{
return false;
}
if( pObject->ClassID() == Class_ID( 0x9125, 0 ) )
{
return false;
}
// BoxBone Check
if( pNode->GetName()[ 0 ] == '~' )
{
return false;
}
if( pNode->GetName()[ 0 ] == '#' )
{
return false;
}
if( pNode->GetName()[ 0 ] == '@' )
{
return false;
}
return true;
}
bool ActorEt::IsBoneObject( INode *pNode )
{
if( pNode->IsRootNode() ) // <20>ֻ<EFBFBD><D6BB><EFBFBD> <20><> <20><><EFBFBD><EFBFBD> Scene Root
{
return false;
}
if( pNode->IsFrozen() )
{
return false;
}
TCHAR *pNodeName;
pNodeName = pNode->GetName();
if( pNode->GetName()[ 0 ] == '~' )
{
return true;
}
if( pNode->GetName()[ 0 ] == '#' )
{
return false;
}
if( stricmp( pNodeName, "BoundingBox" ) == 0 )
{
return false;
}
if( pNode->GetName()[ 0 ] == '@' )
{
return false;
}
Object *pObject;
pObject = pNode->EvalWorldState( 0 ).obj;
if( pObject->ClassID() == Class_ID( BONE_CLASS_ID, 0 ) )
{
return true;
}
if( pObject->ClassID() == BONE_OBJ_CLASSID )
{
return true;
}
if( pObject->ClassID() == Class_ID( DUMMY_CLASS_ID, 0 ) )
{
return false;
}
Control *pCont = pNode->GetTMController();
if( ( pCont->ClassID() == BIPSLAVE_CONTROL_CLASS_ID ) || ( pCont->ClassID() == BIPBODY_CONTROL_CLASS_ID ) )
{
return true;
}
// Has Animation??
CSaveAni SaveAni;
if( SaveAni.IsExistAniKey( pNode, m_pMaxInterface ) )
{
return true;
}
return false;
}
bool ActorEt::IsCollisionMeshObject( INode *pNode )
{
Object *pObject;
pObject = pNode->EvalWorldState( 0 ).obj;
if( pNode->IsFrozen() )
{
return false;
}
if( ( m_nExportSelected ) && ( !pNode->Selected() ) )
{
return false;
}
TCHAR *pNodeName;
pNodeName = pNode->GetName();
if( pNode->GetName()[ 0 ] == '~' )
{
return false;
}
if( pNode->GetName()[ 0 ] == '#' )
{
return false;
}
if( stricmp( pNodeName, "BoundingBox" ) == 0 )
{
return false;
}
if( pObject->ClassID() == Class_ID( BOXOBJ_CLASS_ID, 0 ) )
{
return true;
}
if( pObject->ClassID() == Class_ID( SPHERE_CLASS_ID, 0 ) )
{
return true;
}
if( pObject->ClassID() == Class_ID( CYLINDER_CLASS_ID, 0 ) )
{
return true;
}
if( pObject->ClassID() == CAPS_CLASS_ID )
{
return true;
}
if( pNode->GetName()[ 0 ] == '@' )
{
return true;
}
return false;
}
bool ActorEt::IsCameraObject( INode *pNode )
{
Object *pObject;
pObject = pNode->EvalWorldState( 0 ).obj; // <20>ð<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>־<EFBFBD><D6BE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>..
if( ( m_nExportSelected ) && ( !pNode->Selected() ) )
{
return false;
}
if( pNode->IsFrozen() )
{
return false;
}
if( pObject->SuperClassID() == CAMERA_CLASS_ID )
{
return true;
}
return false;
}
bool ActorEt::IsDummyObject( INode *pNode )
{
if( ( m_nExportSelected ) && ( !pNode->Selected() ) )
{
return false;
}
if( pNode->IsFrozen() )
{
return false;
}
if( pNode->GetName()[0] == '#' ) {
return true;
}
return false;
}
void ActorEt::GetSelectedBone( std::vector< std::string > &vecSelectedBone )
{
int i;
GetNodeList();
for( i = 0; i < ( int )m_vecNodeList.size(); i++ )
{
if( m_vecNodeList[ i ].pNode->Selected() )
{
if( m_vecNodeList[ i ].nNodeFlag & NODE_FLAG_BONE )
{
vecSelectedBone.push_back( m_vecNodeList[ i ].pNode->GetName() );
}
}
}
}
int ActorEt::GetNodeCount( int nNodeFlag )
{
int i, nNodeCount;
nNodeCount = 0;
for( i = 0; i < ( int )m_vecNodeList.size(); i++ )
{
if( m_vecNodeList[ i ].nNodeFlag & nNodeFlag )
{
nNodeCount++;
}
}
return nNodeCount;
}
INode *ActorEt::FindNode( int nIndex, int nNodeFlag )
{
int i, nNodeCount;
nNodeCount = 0;
for( i = 0; i < ( int )m_vecNodeList.size(); i++ )
{
if( m_vecNodeList[ i ].nNodeFlag & nNodeFlag )
{
if( nNodeCount == nIndex )
{
return m_vecNodeList[ i ].pNode;
}
nNodeCount++;
}
}
return NULL;
}
SNodeInfo *ActorEt::FindNodeInfo( int nIndex, int nNodeFlag )
{
int i, nNodeCount;
nNodeCount = 0;
for( i = 0; i < ( int )m_vecNodeList.size(); i++ )
{
if( m_vecNodeList[ i ].nNodeFlag & nNodeFlag )
{
if( nNodeCount == nIndex )
{
return &m_vecNodeList[ i ];
}
nNodeCount++;
}
}
return NULL;
}
DWORD WINAPI fn( LPVOID arg )
{
return( 0 ); // Dummy function for progress bar
}
void ActorEt::WriteMesh( const char *pFileName )
{
int i, nWriteCount;
FILE *fp;
fp = fopen( pFileName, "wb" );
if( fp == NULL )
{
char str[255];
sprintf(str, "[%s] <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>б<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>̶<EFBFBD>\n <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ʾҽ<CABE><D2BD>ϴ<EFBFBD>.", pFileName);
MessageBox(0, str, "Error Message", MB_OK );
return;
}
SMeshFileHeader MeshHeader;
memset( &MeshHeader, 0, sizeof( SMeshFileHeader ) );
strcpy( MeshHeader.szHeaderString, MESH_FILE_STRING );
MeshHeader.nVersion = MESH_FILE_VERSION;
MeshHeader.nSubMeshCount = GetNodeCount( NODE_FLAG_MESH );
MeshHeader.nLODCount = 1; // <20><EFBFBD><ECBCB1> 1<><31> <20><><EFBFBD><EFBFBD><EFBFBD>Ѵ<EFBFBD>. LOD<4F><44><EFBFBD><EFBFBD><EFBFBD><20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>..
MeshHeader.bUVAni = false; // <20>켱 UV ani <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ѵ<EFBFBD>.
fwrite( &MeshHeader, sizeof( SMeshFileHeader ), 1, fp );
MeshHeader.nBoneCount = GetNodeCount( NODE_FLAG_BONE );
for( i = 0; i < MeshHeader.nBoneCount; i++ )
{
INode *pFindNode;
Matrix3 WorldMat;
char szBoneName[ 256 ];
pFindNode = FindNode( i, NODE_FLAG_BONE );
memset( szBoneName, 0, 256 );
strcpy( szBoneName, pFindNode->GetName() );
fwrite( szBoneName, 256, 1, fp );
WorldMat = pFindNode->GetNodeTM( 0 );
WorldMat = Inverse( WorldMat );
DumpMatrix( fp, WorldMat );
}
m_pMaxInterface->ProgressStart( "Save Mesh...", true, fn, NULL );
nWriteCount = 0;
MeshHeader.MaxVec = Point3( -FLT_MAX, -FLT_MAX, -FLT_MAX );
MeshHeader.MinVec = Point3( FLT_MAX, FLT_MAX, FLT_MAX );
for( i = 0; i < MeshHeader.nSubMeshCount; i++ )
{
SNodeInfo *pNodeInfo;
bool bUseBone;
pNodeInfo = FindNodeInfo( i, NODE_FLAG_MESH );
bUseBone = false;
if( pNodeInfo->nNodeFlag & NODE_FLAG_BONE )
{
bUseBone = true;
}
nWriteCount += ProcessSubMesh( fp, pNodeInfo->pNode, MeshHeader.MaxVec, MeshHeader.MinVec, bUseBone );
m_pMaxInterface->ProgressUpdate( ( int )( i * 100.0f / MeshHeader.nSubMeshCount ) );
if( m_pMaxInterface->GetCancel() )
{
break;
}
}
int nCollisionNodeCount, nCollisionPrimitiveCount = 0;
nCollisionNodeCount = GetNodeCount( NODE_FLAG_COLLISION );
if( nCollisionNodeCount )
{
for( i = 0; i < nCollisionNodeCount; i++ )
{
nCollisionPrimitiveCount += ProcessCollisionPrimitive( fp, FindNode( i, NODE_FLAG_COLLISION ), MeshHeader.MaxVec, MeshHeader.MinVec );
}
}
MeshHeader.nDummyCount = GetNodeCount( NODE_FLAG_DUMMY );
for( i = 0; i < MeshHeader.nDummyCount; i++)
{
INode *pFindNode = FindNode( i, NODE_FLAG_DUMMY );
TimeValue StartTime;
Matrix3 LocalMat;
AffineParts Affine;
char szDummyName[ 256 ];
StartTime = m_pMaxInterface->GetAnimRange().Start();
LocalMat = pFindNode->GetNodeTM( StartTime );
if( pFindNode->GetParentNode() )
{
LocalMat = LocalMat * Inverse( pFindNode->GetParentNode()->GetNodeTM( StartTime ) );
}
decomp_affine( LocalMat, &Affine );
memset( szDummyName, 0, 256 );
strcpy( szDummyName, pFindNode->GetName() );
fwrite( szDummyName, 256, 1, fp );
memset( szDummyName, 0, 256 );
if( pFindNode->GetParentNode() )
{
strcpy( szDummyName, pFindNode->GetParentNode()->GetName() );
}
fwrite( szDummyName, 256, 1, fp );
DumpMatrix( fp, LocalMat );
}
if( m_pBoundingBox )
{
MeshHeader.MaxVec = Point3( -FLT_MAX, -FLT_MAX, -FLT_MAX );
MeshHeader.MinVec = Point3( FLT_MAX, FLT_MAX, FLT_MAX );
CalcBoundingBox( m_pBoundingBox, MeshHeader.MaxVec, MeshHeader.MinVec );
}
MeshHeader.nSubMeshCount = nWriteCount;
MeshHeader.nCollisionPrimitiveCount = nCollisionPrimitiveCount;
fseek( fp, 0, SEEK_SET );
fwrite( &MeshHeader, sizeof( SMeshFileHeader ), 1, fp );
fclose( fp );
m_pMaxInterface->ProgressEnd();
}
int ActorEt::ProcessSubMesh( FILE *fp, INode *pNode, Point3 &MaxVec, Point3 &MinVec, bool bUseBone )
{
int i, nNeedDel;
int nVertexCount, nFaceCount;
bool bPhysique;
TriObject *pTri = GetTriObjectFromNode( pNode, 0, nNeedDel );
if( pTri == NULL )
{
return 0;
}
Mesh *pMesh = &pTri->GetMesh();
pMesh->buildNormals();
nVertexCount = pMesh->getNumVerts();
nFaceCount = pMesh->getNumFaces();
if( ( nVertexCount == 0 ) || ( nFaceCount == 0 ) )
{
if( nNeedDel )
{
delete pTri;
}
return 0;
}
std::vector< Mtl * > MaterialList;
GetMaterialList( pNode, MaterialList );
std::vector< SMAXVertex > VertexList;
std::vector< std::string > BoneList;
bPhysique = GetVertexList( pNode, pMesh, VertexList, BoneList );
int nSaveCount = 0;
CSaveMesh *pSaveMesh;
char szNodeName[ 256 ], szParentName[ 256 ], szOutputName[ 256 ];
strcpy( szNodeName, pNode->GetName() );
if( bUseBone )
{
strcpy( szParentName, pNode->GetName() );
}
else
{
strcpy( szParentName, pNode->GetParentNode()->GetName() );
}
pSaveMesh = new CSaveMesh[ MaterialList.size() ];
for( i = 0; i < MaterialList.size(); i++ )
{
if( MaterialList.size() > 1 )
{
sprintf( szOutputName, "%s_%d", szNodeName, nSaveCount );
}
else
{
strcpy( szOutputName, szNodeName );
}
pSaveMesh[ i ].Initialize( pNode, pMesh, MaterialList[ i ], &BoneList, MaterialList.size(), i, VertexList.size() );
pSaveMesh[ i ].SetMeshName( szOutputName, szParentName );
if( pSaveMesh[ i ].BuildSaveMesh( m_nUseStrip > 0 ) )
{
pSaveMesh[ i ].WriteMesh( fp, VertexList, BoneList, m_nUseStrip > 0, bPhysique, m_nExportVertexColor > 0 );
m_MaterialList.push_back( MaterialList[ i ] );
nSaveCount++;
}
}
GetBoundingBox( VertexList, MaxVec, MinVec );
if( pSaveMesh )
{
delete [] pSaveMesh;
}
if( nNeedDel )
{
delete pTri;
}
return nSaveCount;
}
TriObject *ActorEt::GetTriObjectFromNode( INode *pNode, TimeValue Time, int &deleteIt )
{
deleteIt = FALSE;
Object *obj = pNode->EvalWorldState( Time ).obj;
if( obj == NULL )
{
return NULL;
}
if( obj->CanConvertToType( Class_ID( TRIOBJ_CLASS_ID, 0 ) ) )
{
TriObject *tri = ( TriObject * )obj->ConvertToType( Time, Class_ID( TRIOBJ_CLASS_ID, 0 ) );
if( obj != tri )
{
deleteIt = TRUE;
}
return tri;
}
else
{
return NULL;
}
}
void ActorEt::GetMaterialList( INode *pNode, std::vector< Mtl * > &MaterialList )
{
Mtl *pMtl;
pMtl = pNode->GetMtl();
if( pMtl == NULL )
{
return;
}
if( pMtl->NumSubMtls() > 1 )
{
int i;
Mtl *pSubMtl;
for( i = 0; i < pMtl->NumSubMtls(); i++ )
{
if( pMtl->ClassID() == Class_ID( DMTL_CLASS_ID, 0 ) )
{
if( !( ( StdMat * )pMtl )->MapEnabled( i ) )
{
continue;
}
}
pSubMtl = pMtl->GetSubMtl( i );
if( pSubMtl )
{
MaterialList.push_back( pSubMtl );
}
}
}
else
{
MaterialList.push_back( pMtl );
}
}
bool ActorEt::GetVertexList( INode *pNode, std::vector< SMAXVertex > &VertexList, std::vector< std::string > &BoneList )
{
int nNeedDel;
TriObject *pTri = GetTriObjectFromNode( pNode, 0, nNeedDel );
if( pTri )
{
Mesh *pMesh = &pTri->GetMesh();
bool bRet = GetVertexList( pNode, pMesh, VertexList, BoneList );
if( nNeedDel )
{
delete pTri;
}
return bRet;
}
return false;
}
bool ActorEt::GetVertexList( INode *pNode, Mesh *pMesh, std::vector< SMAXVertex > &VertexList, std::vector< std::string > &BoneList )
{
int i, nVertexCount;
Matrix3 TM, NormalTM;
TM = pNode->GetObjTMAfterWSM( 0 );
// TM.RotateZ( 3.141592654f );
NormalTM = TM;
NormalTM.SetRow( 3, Point3( 0, 0, 0 ) );
nVertexCount = pMesh->getNumVerts();
for( i = 0; i < nVertexCount; i++ )
{
SMAXVertex Vertex;
Point3 Point;
Point = TM * pMesh->verts[i];
Vertex.Vertex.x = Point.x;
Vertex.Vertex.y = Point.z;
Vertex.Vertex.z = Point.y;
if( pMesh->numCVerts )
{
Point = pMesh->vertCol[ i ];
if( Point.x > 1.0f )
{
Point.x = 1.0f;
}
if( Point.y > 1.0f )
{
Point.y = 1.0f;
}
if( Point.z > 1.0f )
{
Point.z = 1.0f;
}
Vertex.dwVertexColor = 0xff000000 + ( ( DWORD )( Point.x * 255 ) << 16 ) + ( ( DWORD )( Point.y * 255 ) << 8 ) + ( DWORD )( Point.z * 255 );
}
else
{
Vertex.dwVertexColor = 0xffffffff;
}
memset( Vertex.fWeight, 0, sizeof( float ) * 4 );
Vertex.nBone[ 0 ] = -1;
Vertex.nBone[ 1 ] = -1;
Vertex.nBone[ 2 ] = -1;
Vertex.nBone[ 3 ] = -1;
VertexList.push_back( Vertex );
}
m_nNoInfluenceBoneError = 0;
m_nInfluenceBoneExceedError = 0;
m_nMaxWeightZeroError = 0;
if( GetPhysiqueData( pNode, VertexList, BoneList ) == 0 )
{
if( GetSkinData( pNode, VertexList, BoneList ) == 0 )
{
return false;
}
}
char szPhysiqueErrorMsg[255]={0,};
if( m_nNoInfluenceBoneError != 0 ) {
sprintf(szPhysiqueErrorMsg, "<EFBFBD>ƹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20>ʴ<EFBFBD>\n<EFBFBD><EFBFBD><EFBFBD>ؽ<EFBFBD><EFBFBD><EFBFBD> %d<><64> <20>ֽ<EFBFBD><D6BD>ϴ<EFBFBD>.", m_nNoInfluenceBoneError);
MessageBox(0, szPhysiqueErrorMsg, "Error", MB_OK );
}
if( m_nInfluenceBoneExceedError != 0 ) {
sprintf(szPhysiqueErrorMsg, "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>޴<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 4<><34><EFBFBD><EFBFBD> <20>ʰ<EFBFBD><CAB0><EFBFBD>\n<EFBFBD><EFBFBD><EFBFBD>ؽ<EFBFBD><EFBFBD><EFBFBD> %d<><64> <20>ֽ<EFBFBD><D6BD>ϴ<EFBFBD>.", m_nInfluenceBoneExceedError);
MessageBox(0, szPhysiqueErrorMsg, "Error", MB_OK );
}
if( m_nMaxWeightZeroError != 0 ) {
sprintf(szPhysiqueErrorMsg, "<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ġ <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 0<><30>\n<EFBFBD><EFBFBD><EFBFBD>ؽ<EFBFBD><EFBFBD><EFBFBD> %d<><64> <20>ֽ<EFBFBD><D6BD>ϴ<EFBFBD>.", m_nMaxWeightZeroError);
MessageBox(0, szPhysiqueErrorMsg, "Error", MB_OK );
}
return true;
}
Point3 ActorEt::GetNodeCenterPos( INode *pNode )
{
Point3 CenterPos(0,0,0);
std::vector< SMAXVertex > VertexList;
std::vector< std::string > BoneList;
GetVertexList( pNode, VertexList, BoneList );
if( VertexList.empty() ) {
Matrix3 Mat = pNode->GetNodeTM(0);
CenterPos = Mat.GetRow(3);
std::swap(CenterPos.y, CenterPos.z);
}
else {
for( int j = 0; j < (int)VertexList.size(); j++) {
CenterPos += VertexList[j].Vertex;
}
CenterPos /= VertexList.size();
}
return CenterPos;
}
struct SortPhysiqueByWeight
{
const bool operator() (const SPhysiqueInfo &a, const SPhysiqueInfo b)
{
return ( a.fWeight > b.fWeight );
}
};
Modifier *FindPhysiqueModifier(INode* pNode)
{
// Get object from node. Abort if no object.
Object* ObjectPtr = pNode->GetObjectRef();
if (!ObjectPtr) return NULL;
// Is derived object ?
while (ObjectPtr->SuperClassID() == GEN_DERIVOB_CLASS_ID && ObjectPtr)
{
// Yes -> Cast.
IDerivedObject *DerivedObjectPtr = (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++;
}
ObjectPtr = DerivedObjectPtr->GetObjRef();
}
// Not found.
return NULL;
}
//------------------------------------------------------------------------------------------------
Modifier *FindSkinModifier( INode *pNode )
{
// Get object from node. Abort if no object.
Object* ObjectPtr =((INode*)pNode)->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);
//DebugBox("Modifier Testing: %i \n",ModStackIndex);
// Is this Physique ?
if( ModifierPtr->ClassID() == Class_ID(SKIN_CLASSID) ) //PHYSIQUE_CLASS_ID_A, PHYSIQUE_CLASS_ID_B))
{
return ModifierPtr;
}
// Next modifier stack entry.
ModStackIndex++;
}
}
// Not found.
return NULL;
}
int ActorEt::GetPhysiqueData( INode *pNode, std::vector< SMAXVertex > &VertexList, std::vector< std::string > &BoneList )
{
int i, j;
int nPhysiqueCount, nType;
int numPhys = 0;
float fSumWeight = 0.f;
IPhyBlendedRigidVertex *pBlendVertex;
IPhyRigidVertex *pRigidVertex;
std::vector< SPhysiqueInfo > PhysiqueInfo;
Modifier *pMod = FindPhysiqueModifier( pNode );
if( pMod == NULL )
{
return 0;
}
if( pMod->ClassID() != Class_ID( PHYSIQUE_CLASS_ID_A, PHYSIQUE_CLASS_ID_B ) )
{
return 0;
}
IPhysiqueExport *pPhysiqueExport = ( IPhysiqueExport * )pMod->GetInterface( I_PHYEXPORT );
IPhyContextExport *pContextExport = ( IPhyContextExport * )pPhysiqueExport->GetContextInterface( pNode );
pContextExport->ConvertToRigid( true );
pContextExport->AllowBlending( true );
nPhysiqueCount = pContextExport->GetNumberVertices();
for( i = 0; i < nPhysiqueCount; i++ )
{
SPhysiqueInfo Info;
IPhyVertexExport *pVertexExport = pContextExport->GetVertexInterface( i );
if( pVertexExport )
{
nType = pVertexExport->GetVertexType();
switch( nType )
{
case RIGID_BLENDED_TYPE:
pBlendVertex = ( IPhyBlendedRigidVertex * )pVertexExport;
PhysiqueInfo.clear();
for( j = 0; j < pBlendVertex->GetNumberNodes(); j++ )
{
INode *pNode = pBlendVertex->GetNode( j );
if( pNode ) {
Info.nBoneIndex = AddBoneNameList( BoneList, pNode->GetName() );
}
else {
m_nNoInfluenceBoneError++;
}
Info.fWeight = pBlendVertex->GetWeight( j );
if( Info.fWeight <= 0.0f )
{
continue;
}
PhysiqueInfo.push_back( Info );
}
std::sort( PhysiqueInfo.begin(), PhysiqueInfo.end(), SortPhysiqueByWeight() );
if( PhysiqueInfo.size() == 0 )
{
VertexList[ i ].nBone[ 0 ] = 0;
VertexList[ i ].fWeight[ 0 ] = 1.0f;
m_nNoInfluenceBoneError++;
}
if( PhysiqueInfo.size() > 4 )
{
m_nInfluenceBoneExceedError++;
}
numPhys = min( 4, PhysiqueInfo.size() );
fSumWeight = 0.f;
for( j = 0; j < numPhys; j++ ) // 4Weight <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>Ѵ<EFBFBD>.
{
VertexList[ i ].nBone[ j ] = PhysiqueInfo[ j ].nBoneIndex;
VertexList[ i ].fWeight[ j ] = PhysiqueInfo[ j ].fWeight;
fSumWeight += PhysiqueInfo[ j ].fWeight;
}
if( numPhys != 0 && fSumWeight <= 0.f ) { // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 0 <20><> <20><><EFBFBD>쿣, <20><><EFBFBD><EFBFBD><EFBFBD>ϰ<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>ش<EFBFBD>.
m_nMaxWeightZeroError++;
for( j = 0; j < numPhys; j++ ) {
VertexList[ i ].fWeight[ j ] = 1.0f / numPhys;
}
}
else { // <20><><EFBFBD><EFBFBD><EFBFBD>޴<EFBFBD> <20><><EFBFBD><EFBFBD> 4<><34> <20>̻<EFBFBD><CCBB><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 1<><31> <20>ƴ<EFBFBD> <20><> <20>ֹǷ<D6B9> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 1<><31> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ش<EFBFBD>.
for( j = 0; j < numPhys; j++ ) {
VertexList[ i ].fWeight[ j ] /= fSumWeight;
}
}
break;
case RIGID_TYPE:
pRigidVertex = ( IPhyRigidVertex * )pVertexExport;
if( pRigidVertex->GetNode() ) {
VertexList[ i ].nBone[ 0 ] = AddBoneNameList( BoneList, pRigidVertex->GetNode()->GetName() );
}
else {
m_nNoInfluenceBoneError++;
}
VertexList[ i ].fWeight[ 0 ] = 1.0f;
break;
default:
break;
}
}
}
pPhysiqueExport->ReleaseContextInterface( pContextExport );
pMod->ReleaseInterface( I_PHYINTERFACE, pPhysiqueExport );
return 1;
}
int ActorEt::GetSkinData( INode *pNode, std::vector< SMAXVertex > &VertexList, std::vector< std::string > &BoneList )
{
int i, j;
int nVertexCount, nAssignedBoneCount, nAssignedBone;
Modifier *pMod = FindSkinModifier( pNode );
INode *pBone;
std::vector< SPhysiqueInfo > PhysiqueInfo;
if( pMod == NULL )
{
return 0;
}
ISkin *pSkin = ( ISkin * )pMod->GetInterface( I_SKIN );
if( pSkin == NULL )
{
return 0;
}
ISkinContextData *pSkinContext = pSkin->GetContextInterface( pNode );
if( pSkinContext == NULL )
{
return 0;
}
nVertexCount = pSkinContext->GetNumPoints();
for( i = 0; i < nVertexCount; i++ )
{
SPhysiqueInfo Info;
nAssignedBoneCount = pSkinContext->GetNumAssignedBones( i );
PhysiqueInfo.clear();
for( j = 0; j < nAssignedBoneCount; j++ )
{
nAssignedBone = pSkinContext->GetAssignedBone( i, j );
pBone = pSkin->GetBone( nAssignedBone );
Info.nBoneIndex = AddBoneNameList( BoneList, pBone->GetName() );
Info.fWeight = pSkinContext->GetBoneWeight( i, j );
if( Info.fWeight <= 0.0f )
{
continue;
}
PhysiqueInfo.push_back( Info );
}
std::sort( PhysiqueInfo.begin(), PhysiqueInfo.end(), SortPhysiqueByWeight() );
if( PhysiqueInfo.size() == 0 )
{
VertexList[ i ].nBone[ 0 ] = 0;
VertexList[ i ].fWeight[ 0 ] = 1.0f;
m_nNoInfluenceBoneError++;
}
if( PhysiqueInfo.size() > 4 )
{
m_nInfluenceBoneExceedError++;
}
int numPhys = min( 4, PhysiqueInfo.size() );
float fSumWeight = 0.f;
for( j = 0; j < numPhys; j++ ) // 4Weight <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>Ѵ<EFBFBD>.
{
VertexList[ i ].nBone[ j ] = PhysiqueInfo[ j ].nBoneIndex;
VertexList[ i ].fWeight[ j ] = PhysiqueInfo[ j ].fWeight;
fSumWeight += PhysiqueInfo[ j ].fWeight;
}
if( numPhys != 0 && fSumWeight <= 0.f ) { // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 0 <20><> <20><><EFBFBD>쿣, <20><><EFBFBD><EFBFBD><EFBFBD>ϰ<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>ش<EFBFBD>.
m_nMaxWeightZeroError++;
for( j = 0; j < numPhys; j++ ) {
VertexList[ i ].fWeight[ j ] = 1.0f / numPhys;
}
}
else { // <20><><EFBFBD><EFBFBD><EFBFBD>޴<EFBFBD> <20><><EFBFBD><EFBFBD> 4<><34> <20>̻<EFBFBD><CCBB><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 1<><31> <20>ƴ<EFBFBD> <20><> <20>ֹǷ<D6B9> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 1<><31> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ش<EFBFBD>.
for( j = 0; j < numPhys; j++ ) {
VertexList[ i ].fWeight[ j ] /= fSumWeight;
}
}
}
pMod->ReleaseInterface(I_SKIN, pSkin);
return 1;
}
int ActorEt::AddBoneNameList( std::vector< std::string > &BoneList, const char *pBoneName )
{
int i;
for( i = 0; i < BoneList.size(); i++ )
{
if( stricmp( pBoneName, BoneList[ i ].c_str() ) == 0 )
{
return i;
}
}
BoneList.push_back( pBoneName );
return BoneList.size() - 1;
}
void ActorEt::WriteAni( const char *pFileName )
{
int i, nAniLength;
FILE *fp;
CSaveAni SaveAni;
char szAniName[ 256 ], *pFindPtr;
fp = fopen( pFileName, "wb" );
if( fp == NULL )
{
char str[255];
sprintf(str, "[%s] <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>б<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>̶<EFBFBD>\n <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ʾҽ<CABE><D2BD>ϴ<EFBFBD>.", pFileName);
MessageBox(0, str, "Error Message", MB_OK );
return;
}
SAniFileHeader FileHeader;
memset( &FileHeader, 0, sizeof( SAniFileHeader ) );
strcpy( FileHeader.szHeaderString, ANI_FILE_STRING );
FileHeader.nVersion = ANI_FILE_VERSION;
FileHeader.nBoneCount = GetNodeCount( NODE_FLAG_BONE );
FileHeader.nAniCount = 1;
fwrite( &FileHeader, 1, sizeof( SAniFileHeader ), fp );
GetDlgItemText( hPanel, IDC_EDIT_ANI_NAME, szAniName, 256 );
if( strlen( szAniName ) == 0 )
{
pFindPtr = (char*)strrchr( pFileName, '\\' );
memset( szAniName, 0, 256 );
if( pFindPtr )
{
strcpy( szAniName, pFindPtr + 1 );
}
else
{
strcpy( szAniName, pFileName );
}
pFindPtr = ( char * )strrchr( szAniName, '.' );
if( pFindPtr )
{
*pFindPtr = 0;
}
}
fwrite( szAniName, 256, 1, fp );
nAniLength = ( m_pMaxInterface->GetAnimRange().End() - m_pMaxInterface->GetAnimRange().Start() ) / GetTicksPerFrame();
nAniLength++;
fwrite( &nAniLength, sizeof( int ), 1, fp );
m_pMaxInterface->ProgressStart( "Save Animation...", true, fn, NULL );
for( i = 0; i < FileHeader.nBoneCount; i++ )
{
INode *pFindNode;
pFindNode = FindNode( i, NODE_FLAG_BONE );
SaveAni.ProcessBone( fp, pFindNode, m_pMaxInterface );
m_pMaxInterface->ProgressUpdate( ( int )( i * 100.0f / FileHeader.nBoneCount ) );
if( m_pMaxInterface->GetCancel() )
{
break;
}
}
fclose( fp );
m_pMaxInterface->ProgressEnd();
}
void ActorEt::WriteSkin( const char *pFileName, const char *pMeshName )
{
int i;
FILE *fp;
CSaveSkin SaveSkin;
fp = fopen( pFileName, "wb" );
if( fp == NULL )
{
char str[255];
sprintf(str, "[%s] <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>б<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>̶<EFBFBD>\n <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ʾҽ<CABE><D2BD>ϴ<EFBFBD>.", pFileName);
MessageBox(0, str, "Error Message", MB_OK );
return;
}
SSkinFileHeader SkinHeader;
memset( &SkinHeader, 0, sizeof( SSkinFileHeader ) );
strcpy( SkinHeader.szHeaderString, SKIN_FILE_STRING );
strcpy( SkinHeader.szMeshName, pMeshName );
SkinHeader.nVersion = SKIN_FILE_VERSION;
SkinHeader.nSubMeshCount = m_MaterialList.size();
fwrite( &SkinHeader, sizeof( SSkinFileHeader ), 1, fp );
for( i = 0; i < m_MaterialList.size(); i++ )
{
SaveSkin.SaveSkin( fp, m_MaterialList[ i ] );
}
fclose( fp );
}
void ActorEt::CalcBoundingBox( INode *pNode, Point3 &MaxVec, Point3 &MinVec )
{
std::vector< SMAXVertex > VertexList;
std::vector< std::string > BoneList;
GetVertexList( pNode, VertexList, BoneList );
GetBoundingBox( VertexList, MaxVec, MinVec );
}
void ActorEt::GetBoundingBox( std::vector< SMAXVertex > &SystemVertex, Point3 &MaxVec, Point3 &MinVec )
{
int i;
Point3 Position;
for( i = 0; i < SystemVertex.size(); i++ )
{
Position = SystemVertex[ i ].Vertex;
if( MaxVec.x < Position.x )
{
MaxVec.x = Position.x;
}
if( MaxVec.y < Position.y )
{
MaxVec.y = Position.y;
}
if( MaxVec.z < Position.z )
{
MaxVec.z = Position.z;
}
if( MinVec.x > Position.x )
{
MinVec.x = Position.x;
}
if( MinVec.y > Position.y )
{
MinVec.y = Position.y;
}
if( MinVec.z > Position.z )
{
MinVec.z = Position.z;
}
}
}
void ActorEt::WriteNavigation( const char *pFileName )
{
int i;
FILE *fp;
fp = fopen( pFileName, "wb" );
if( fp == NULL )
{
char str[255];
sprintf(str, "[%s] <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>б<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>̶<EFBFBD>\n <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ʾҽ<CABE><D2BD>ϴ<EFBFBD>.", pFileName);
MessageBox(0, str, "Error Message", MB_OK );
return;
}
struct SNavFileHeader
{
int nSignature;
int nVersion;
int nTriangleCount;
};
enum NAV_MESH_TYPE
{
NMT_TERRAIN = 0,
NMT_PROP = 1,
};
SNavFileHeader Header;
std::vector< int > vecEntrance;
Header.nSignature = 0xefefefef;
Header.nVersion = 11;
Header.nTriangleCount = 0;
fwrite( &Header, sizeof( SNavFileHeader ), 1, fp );
m_pMaxInterface->ProgressStart( "Save Mesh...", true, fn, NULL );
for( i = 0; i < ( int )m_vecNodeList.size(); i++ )
{
SNodeInfo *pNodeInfo;
pNodeInfo = &m_vecNodeList[ i ];
m_pMaxInterface->ProgressUpdate( ( int )( i * 100.0f / m_vecNodeList.size() ) );
if( m_pMaxInterface->GetCancel() )
{
break;
}
if( ( pNodeInfo->nNodeFlag & NODE_FLAG_MESH ) == 0 )
{
continue;
}
std::vector< SMAXVertex > vecPoint;
GetTriangleList( pNodeInfo->pNode, vecPoint );
if( !vecPoint.empty() )
{
int j, nCount;
nCount = ( int )vecPoint.size() / 3;
for( j = 0; j < nCount; j++ )
{
NAV_MESH_TYPE Type = NMT_PROP;
int nEvent = 0, nWallAttribute[ 3 ];
fwrite( &vecPoint[ j * 3 ].Vertex, sizeof( float ), 3, fp );
fwrite( &vecPoint[ j * 3 + 1 ].Vertex, sizeof( float ), 3, fp );
fwrite( &vecPoint[ j * 3 + 2 ].Vertex, sizeof( float ), 3, fp );
fwrite( &nEvent, sizeof( int ), 1, fp );
fwrite( &Type, sizeof( NAV_MESH_TYPE ), 1, fp );
memset( nWallAttribute, 0, sizeof( int ) * 3 );
fwrite( nWallAttribute, sizeof( int ), 3, fp );
// <20><><EFBFBD>ؽ<EFBFBD> <20>÷<EFBFBD><C3B7><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ƴ<EFBFBD> edge<67><65> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>.
if( vecPoint[ j * 3 ].dwVertexColor != 0xffffffff )
{
if( vecPoint[ j * 3 + 1 ].dwVertexColor != 0xffffffff )
{
vecEntrance.push_back( Header.nTriangleCount + j );
vecEntrance.push_back( 0 );
}
else if( vecPoint[ j * 3 + 2 ].dwVertexColor != 0xffffffff )
{
vecEntrance.push_back( Header.nTriangleCount + j );
vecEntrance.push_back( 2 );
}
}
else if( vecPoint[ j * 3 + 1 ].dwVertexColor != 0xffffffff )
{
if( vecPoint[ j * 3 + 2 ].dwVertexColor != 0xffffffff )
{
vecEntrance.push_back( Header.nTriangleCount + j );
vecEntrance.push_back( 1 );
}
}
}
Header.nTriangleCount += ( int )vecPoint.size() / 3;
}
}
int nSide = -1;
for( i = 0; i < Header.nTriangleCount; i++ )
{
fwrite( &nSide, sizeof( int ), 1, fp );
fwrite( &nSide, sizeof( int ), 1, fp );
fwrite( &nSide, sizeof( int ), 1, fp );
}
if( !vecEntrance.empty() )
{
int nEntranceCount;
nEntranceCount = vecEntrance.size() / 2;
fwrite( &nEntranceCount, sizeof( int ), 1, fp );
fwrite( &vecEntrance[ 0 ], sizeof( int ), nEntranceCount * 2, fp );
}
fseek( fp, 0, SEEK_SET );
fwrite( &Header, sizeof( SNavFileHeader ), 1, fp );
fclose( fp );
m_pMaxInterface->ProgressEnd();
}
int ActorEt::GetTriangleList( INode *pNode, std::vector< SMAXVertex > &vecPoint )
{
int i, j, nNeedDel, nFaceCount;
Matrix3 NormalTM;
bool bNegScale;
TriObject *pTri = GetTriObjectFromNode( pNode, 0, nNeedDel );
if( pTri == NULL )
{
return 0;
}
NormalTM = pNode->GetObjTMAfterWSM( 0 );
bNegScale = TMNegParity( NormalTM );
std::vector< SMAXVertex > VertexList;
std::vector< std::string > BoneList;
Mesh *pMesh = &pTri->GetMesh();
GetVertexList( pNode, &pTri->GetMesh(), VertexList, BoneList );
nFaceCount = pMesh->getNumFaces();
for( i = 0; i < nFaceCount; i++ )
{
Face *pTriFace;
pTriFace = pMesh->faces + i;
for( j = 0; j < 3; j++ )
{
int nFaceIndex;
if( bNegScale )
{
nFaceIndex = j;
}
else
{
nFaceIndex = 2 - j;
}
vecPoint.push_back( VertexList[ pTriFace->getVert( nFaceIndex ) ] );
}
}
if( nNeedDel )
{
delete pTri;
}
return ( int )vecPoint.size();
}
int ActorEt::ProcessCollisionPrimitive( FILE *fp, INode *pNode, Point3 &MaxVec, Point3 &MinVec )
{
int nParamIndex, nCount;
CollisionType Type;
Interval Inter;
Object *pObject;
Matrix3 NormalTM;
IParamArray *iPrimitiveParams;
char szParentName[ 1024 ];
pObject = pNode->EvalWorldState( 0 ).obj;
NormalTM = pNode->GetObjTMAfterWSM( 0 );
if( pObject == NULL )
{
return 0;
}
iPrimitiveParams = pObject->GetParamBlock();
CalcBoundingBox( pNode, MaxVec, MinVec );
if( iPrimitiveParams == NULL )
{
std::vector< SMAXVertex > vecPoint;
Point3 Edge;
if( GetTriangleList( pNode, vecPoint ) <= 0 )
{
return 0;
}
Type = CT_TRIANGLES;
fwrite( &Type, sizeof( CollisionType ), 1, fp );
if( pNode->GetParentNode()->GetParentNode() )
{
strcpy( szParentName, pNode->GetParentNode()->GetName() );
nCount = strlen( szParentName ) + 1;
}
else
{
nCount = 0;
}
fwrite( &nCount, sizeof( int ), 1, fp );
if( nCount > 1 )
{
fwrite( szParentName, nCount, 1, fp );
}
int i;
nCount = ( int )vecPoint.size() / 3;
fwrite( &nCount, sizeof( int ), 1, fp );
for( i = 0; i < nCount; i++ )
{
fwrite( &vecPoint[ i * 3 ], sizeof( Point3 ), 1, fp );
Edge = vecPoint[ i * 3 + 1 ].Vertex - vecPoint[ i * 3 ].Vertex;
fwrite( &Edge, sizeof( Point3 ), 1, fp );
Edge = vecPoint[ i * 3 + 2 ].Vertex - vecPoint[ i * 3 ].Vertex;
fwrite( &Edge, sizeof( Point3 ), 1, fp );
}
return 1;
}
else if( pObject->ClassID() == Class_ID( BOXOBJ_CLASS_ID, 0 ) )
{
SOBB Box;
float fXSize, fYSize, fZSize;
nParamIndex = pObject->GetParamBlockIndex( BOXOBJ_WIDTH );
iPrimitiveParams->GetValue( nParamIndex, TimeValue( 0 ), fXSize, Inter );
Box.Extent[ 0 ] = fXSize / 2;
nParamIndex = pObject->GetParamBlockIndex( BOXOBJ_HEIGHT );
iPrimitiveParams->GetValue( nParamIndex, TimeValue( 0 ), fYSize, Inter );
Box.Extent[ 1 ] = fYSize / 2;
nParamIndex = pObject->GetParamBlockIndex( BOXOBJ_LENGTH );
iPrimitiveParams->GetValue( nParamIndex, TimeValue( 0 ), fZSize, Inter );
Box.Extent[ 2 ] = fZSize / 2;
Type = CT_BOX;
Box.Center = Point3( 0.0f, 0.0f, fYSize / 2 ) * NormalTM;
NormalTM.SetRow( 3, Point3( 0.0f, 0.0f, 0.0f ) );
Box.Axis[ 0 ] = Point3( 1.0f, 0.0f, 0.0f );
Box.Axis[ 0 ] = Normalize( NormalTM * Box.Axis[ 0 ] );
Box.Axis[ 1 ] = Point3( 0.0f, 0.0f, 1.0f );
Box.Axis[ 1 ] = Normalize( NormalTM * Box.Axis[ 1 ] );
Box.Axis[ 2 ] = Point3( 0.0f, 1.0f, 0.0f );
Box.Axis[ 2 ] = Normalize( NormalTM * Box.Axis[ 2 ] );
fwrite( &Type, sizeof( CollisionType ), 1, fp );
strcpy( szParentName, pNode->GetParentNode()->GetName() );
nCount = strlen( szParentName ) + 1;
fwrite( &nCount, sizeof( int ), 1, fp );
if( nCount > 1 )
{
fwrite( szParentName, nCount, 1, fp );
}
DumpPoint3( fp, Box.Center );
DumpPoint3( fp, Box.Axis[ 0 ] );
DumpPoint3( fp, Box.Axis[ 1 ] );
DumpPoint3( fp, Box.Axis[ 2 ] );
fwrite( Box.Extent, sizeof( float ), 3, fp );
return 1;
}
else if( pObject->ClassID() == Class_ID( SPHERE_CLASS_ID, 0 ) )
{
float fRadius;
SSphere Sphere;
nParamIndex = pObject->GetParamBlockIndex( CIRCLE_RADIUS );
iPrimitiveParams->GetValue( nParamIndex, TimeValue( 0 ), fRadius, Inter );
Type = CT_SPHERE;
Sphere.Center = Point3( 0.0f, 0.0f, 0.0f ) * NormalTM;
fwrite( &Type, sizeof( CollisionType ), 1, fp );
if( pNode->GetParentNode()->GetParentNode() )
{
strcpy( szParentName, pNode->GetParentNode()->GetName() );
nCount = strlen( szParentName ) + 1;
}
else
{
nCount = 0;
}
fwrite( &nCount, sizeof( int ), 1, fp );
if( nCount > 1 )
{
fwrite( szParentName, nCount, 1, fp );
}
DumpPoint3( fp, Sphere.Center );
fwrite( &fRadius, sizeof( float ), 1, fp );
return 1;
}
else if( pObject->ClassID() == Class_ID( CYLINDER_CLASS_ID, 0 ) )
{
float fRadius, fHeight;
SCylinder Cylinder;
nParamIndex = pObject->GetParamBlockIndex( CYLINDER_RADIUS );
iPrimitiveParams->GetValue( nParamIndex, TimeValue( 0 ), fRadius, Inter );
nParamIndex = pObject->GetParamBlockIndex( CYLINDER_HEIGHT );
iPrimitiveParams->GetValue( nParamIndex, TimeValue( 0 ), fHeight, Inter );
Type = CT_CYLINDER;
Cylinder.Origin = Point3( 0.0f, 0.0f, 0.0f ) * NormalTM;
NormalTM.SetRow( 3, Point3( 0.0f, 0.0f, 0.0f ) );
Cylinder.Direction = Point3( 0.0f, 0.0f, fHeight ) * NormalTM;
fwrite( &Type, sizeof( CollisionType ), 1, fp );
if( pNode->GetParentNode()->GetParentNode() )
{
strcpy( szParentName, pNode->GetParentNode()->GetName() );
nCount = strlen( szParentName ) + 1;
}
else
{
nCount = 0;
}
fwrite( &nCount, sizeof( int ), 1, fp );
if( nCount > 1 )
{
fwrite( szParentName, nCount, 1, fp );
}
DumpPoint3( fp, Cylinder.Origin );
DumpPoint3( fp, Cylinder.Direction );
fwrite( &fRadius, sizeof( float ), 1, fp );
return 1;
}
else if( pObject->ClassID() == CAPS_CLASS_ID )
{
float fRadius, fHeight;
SCylinder Cylinder;
Point3 NormalDir;
nParamIndex = pObject->GetParamBlockIndex( CAPS_RADIUS );
iPrimitiveParams->GetValue( nParamIndex, TimeValue( 0 ), fRadius, Inter );
nParamIndex = pObject->GetParamBlockIndex( CAPS_HEIGHT );
iPrimitiveParams->GetValue( nParamIndex, TimeValue( 0 ), fHeight, Inter );
fHeight -= fRadius * 2;
if( fHeight < 0.0f )
{
fHeight = 0.0f;
}
Type = CT_CYLINDER;
Cylinder.Origin = Point3( 0.0f, 0.0f, 0.0f ) * NormalTM;
NormalTM.SetRow( 3, Point3( 0.0f, 0.0f, 0.0f ) );
Cylinder.Direction = Point3( 0.0f, 0.0f, fHeight ) * NormalTM;
NormalDir = Normalize( Cylinder.Direction );
Cylinder.Origin = Cylinder.Origin + NormalDir * fRadius;
fwrite( &Type, sizeof( CollisionType ), 1, fp );
if( pNode->GetParentNode()->GetParentNode() )
{
strcpy( szParentName, pNode->GetParentNode()->GetName() );
nCount = strlen( szParentName ) + 1;
}
else
{
nCount = 0;
}
fwrite( &nCount, sizeof( int ), 1, fp );
if( nCount > 1 )
{
fwrite( szParentName, nCount, 1, fp );
}
DumpPoint3( fp, Cylinder.Origin );
DumpPoint3( fp, Cylinder.Direction );
fwrite( &fRadius, sizeof( float ), 1, fp );
return 1;
}
return 0;
}
void ActorEt::WriteCamera( const char *pFileName )
{
FILE *fp;
CSaveCamera SaveCamera;
fp = fopen( pFileName, "wb" );
if( fp == NULL )
{
char str[255];
sprintf(str, "[%s] <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>б<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>̶<EFBFBD>\n <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ʾҽ<CABE><D2BD>ϴ<EFBFBD>.", pFileName);
MessageBox(0, str, "Error Message", MB_OK );
return;
}
INode *pFindNode;
pFindNode = FindNode( 0, NODE_FLAG_CAMERA );
if( pFindNode )
{
SaveCamera.ProcessCamera( fp, pFindNode, m_pMaxInterface, ( bool )(m_nExportTargetCamera != 0) );
}
fclose( fp );
}
Value *save_ani_cf( Value** arg_list, int count )
{
theActorEt.m_pMaxInterface = MAXScript_interface;
theActorEt.SaveAni( NULL, arg_list[ 0 ]->to_string() );
return &true_value;
}