2024-12-21 10:04:04 +08:00
|
|
|
|
/**********************************************************************
|
|
|
|
|
|
*<
|
|
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
|