1983 lines
46 KiB
C++
1983 lines
46 KiB
C++
/**********************************************************************
|
||
*<
|
||
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;
|
||
}
|
||
|