📄 max2nmo.cpp
字号:
char *fileNameExtension = splitter.GetExtension();
if( strcmp(fileNameExtension, ".nmo") ){ // save the level only for ".cmo" and ".vmo"
m_VirtoolsObjects->InsertFront( level );
}
}
#endif
// Set Compression Level
if( GetCompressionLevel() ){
VirtoolsContext->SetFileWriteMode( CKFILE_WHOLECOMPRESSED );
VirtoolsContext->SetCompressionLevel( GetCompressionLevel() );
} else {
VirtoolsContext->SetFileWriteMode( CKFILE_UNCOMPRESSED );
}
//Normalizing root anim Y orientation aligning it with the Z world
if ((GetExportAsCharacter() || GetExportAsAnimationOnly()) && GetAlignAnimOnZ()) {
CK_ID* pid = VirtoolsContext->GetObjectsListByClassID(CKCID_KEYEDANIMATION);
CKKeyedAnimation* ka = (CKKeyedAnimation*) VirtoolsContext->GetObject(*pid);
if (ka) {
CKObjectAnimation* oa = ka->GetAnimation(ka->GetRootEntity()) ;
if (oa) {
CKAnimController* rctrl = oa->GetRotationController();
int rkeycount=0;
if (rctrl && (rkeycount=rctrl->GetKeyCount())) {
VxQuaternion diffy,first,dest;
CKRotationKey* rotkey = NULL;
VxMatrix or0;
rotkey = (CKRotationKey*) rctrl->GetKey(0);
first = rotkey->GetRotation();
first.ToMatrix(or0);
VxVector dir0(or0[0][2],or0[1][2],or0[2][2]);
dir0.y = 0.0f;
dir0.Normalize();
float angle = acosf(DotProduct(dir0,VxVector::axisZ()));
diffy.FromRotation(VxVector(0.0f,1.0f,0.0f),-(PI/2 - angle));
for (int ki = 0; ki<rkeycount;ki++) {
rotkey = (CKRotationKey*) rctrl->GetKey(ki);
dest = rotkey->GetRotation();
dest.Multiply(diffy);
dest.Normalize();
rotkey->SetRotation(dest);
}
}
}
}
}
// Write the file to hard drive
CKERROR err = VirtoolsFile->StartSave((char *)name);
if (err==CK_OK) {
VirtoolsFile->SaveObjects(m_VirtoolsObjects);
err = VirtoolsFile->EndSave();
}
if (err==CK_OK) {
Report(REPORT_HLEVEL,"\r\n");
Report(REPORT_HLEVEL,"File saved succesfully\r\n");
} else {
Report(REPORT_HLEVEL,"\r\n");
Report(REPORT_HLEVEL,"Error while saving file: %s\r\n",CKErrorToString(err));
}
if (GetReportLevel())
if (!DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_REPORT),
ip->GetMAXHWnd(), ReportDlgProc, (LPARAM)this)) {
return 1;
}
// Clean Up
DeleteCKObjectArray(m_VirtoolsObjects);
m_VirtoolsObjects = NULL;
VirtoolsContext->DeleteCKFile(VirtoolsFile);
delete VirtoolsExporter;
VirtoolsExporter = NULL;
VirtoolsContext->ClearAll();
return 1;
}
////////////////////////////////////
// Register All Special Parameters
////////////////////////////////////
BOOL Max2Nmo::RegisterAllSpecialParameters() {
CKParameterManager* pm = VirtoolsContext->GetParameterManager();
#ifdef _USESCRIPTS_
RegisterSpecialParameters( pm );
RegisterSpecialParameters2( pm );
#endif
return TRUE;
}
BOOL Max2Nmo::SupportsOptions(int ext, DWORD options) {
//assert(ext == 0);
return(options == SCENE_EXPORT_SELECTED) ? TRUE : FALSE;
}
#ifdef _USESCRIPTS_
// This methode parse all the nodes (recursivly), and evaluates
// the user defined properties buffer to execute some function
// like: attaching a script, setting an attribute, setting a local parameter
BOOL Max2Nmo::evaluateNodeUserDefinedProperties( INode* node ){
// Only export if exporting everything or it's selected
if(!exportSelected || node->Selected()) {
// Stop recursing if the user pressed Cancel
if (ip->GetCancel())
return FALSE;
// The ObjectState is a 'thing' that flows down the pipeline containing
// all information about the object. By calling EvalWorldState() we tell
// max to eveluate the object at end of the pipeline.
ObjectState os = node->EvalWorldState(0);
// The obj member of ObjectState is the actual object we will export.
if (os.obj) {
// We look at the super class ID to determine the type of the object.
switch(os.obj->SuperClassID()) {
case GEOMOBJECT_CLASS_ID:
case CAMERA_CLASS_ID:
case LIGHT_CLASS_ID:
case SHAPE_CLASS_ID:
case HELPER_CLASS_ID:
{
PropertiesEvaluator pe( VirtoolsExporter, node, this, m_VirtoolsObjects );
} break;
}
}
// For each child of this node, we recurse into ourselves
// until no more children are found.
for (int c = 0; c < node->NumberOfChildren(); c++) {
if (!evaluateNodeUserDefinedProperties(node->GetChildNode(c)))
return FALSE;
}
} else {
// node is not selected but one of its child may
// For each child of this node, we recurse into ourselves
// until no more children are found.
for (int c = 0; c < node->NumberOfChildren(); c++) {
if (!evaluateNodeUserDefinedProperties(node->GetChildNode(c)))
return FALSE;
}
}
return TRUE;
}
#endif
// This method is the main object exporter.
// It is called once of every node in the scene. The objects are
// exported as they are encoutered.
// Before recursing into the children of a node, we will export it.
// The benefit of this is that a nodes parent is always before the
// children in the resulting file. This is desired since a child's
// transformation matrix is optionally relative to the parent.
BOOL Max2Nmo::nodeEnum(INode* node)
{
// Only export if exporting everything or it's selected
if(!exportSelected || node->Selected()) {
nCurNode++;
if( GetShowProgressionBar() ){
ip->ProgressUpdate((int)((float)nCurNode/nTotalNodeCount*100.0f));
}
// Stop recursing if the user pressed Cancel
if (ip->GetCancel())
return FALSE;
// If this node is a group head, all children are
// members of this group. The node will be a dummy node and the node name
// is the actualy group name.
if (node->IsGroupHead()) {
// TODO
if (!GetGroupAsPlace()) {
CKGroup* group = VirtoolsExporter->AddGroup(node->GetName(),node);
// If there was a group being parsed : Add the newly created group
CKGroup* PrevGroup = CKGroups.Size() ? CKGroups.Back() : NULL;
if (PrevGroup) {
PrevGroup->AddObject(group);
}
CKGroups.PushBack(group);
}
}
// The ObjectState is a 'thing' that flows down the pipeline containing
// all information about the object. By calling EvalWorldState() we tell
// max to eveluate the object at end of the pipeline.
ObjectState os = node->EvalWorldState(0);
// The obj member of ObjectState is the actual object we will export.
if (os.obj) {
// We look at the super class ID to determine the type of the object.
switch(os.obj->SuperClassID()) {
case GEOMOBJECT_CLASS_ID:
ExportGeomObject(node);
break;
case CAMERA_CLASS_ID:
ExportCameraObject(node);
break;
case LIGHT_CLASS_ID:
ExportLightObject(node);
break;
case SHAPE_CLASS_ID:
ExportShapeObject(node);
break;
case HELPER_CLASS_ID:
ExportHelperObject(node);
break;
}
}
// For each child of this node, we recurse into ourselves
// until no more children are found.
for (int c = 0; c < node->NumberOfChildren(); c++) {
if (!nodeEnum(node->GetChildNode(c)))
return FALSE;
}
// If this is true here, it is the end of the group we started above.
if (node->IsGroupHead()) {
if (!GetGroupAsPlace()) {
CKGroups.PopBack();
}
GroupIndent-=2;
}
} else {
// node is not selected but one of its child may
// For each child of this node, we recurse into ourselves
// until no more children are found.
for (int c = 0; c < node->NumberOfChildren(); c++) {
if (!nodeEnum(node->GetChildNode(c)))
return FALSE;
}
}
return TRUE;
}
XString Max2Nmo::StrGroupIndent()
{
XString str = "";
for (int i=0;i<GroupIndent;++i)
str << " ";
return str;
}
void Max2Nmo::PreProcess(INode* node, int& nodeCount)
{
nodeCount++;
// Add the nodes material to out material list
// Null entries are ignored when added...
if (!exportSelected || (node->Selected() == TRUE))
mtlList.AddMtl(node->GetMtl());
// For each child of this node, we recurse into ourselves
// and increment the counter until no more children are found.
for (int c = 0; c < node->NumberOfChildren(); c++) {
PreProcess(node->GetChildNode(c), nodeCount);
}
}
void Max2Nmo::PostProcess(INode* node)
{
if(!exportSelected || node->Selected()) {
ExportAnimMesh(node);
}
// For each child of this node, we recurse into ourselves
for (int c = 0; c < node->NumberOfChildren(); c++) {
PostProcess(node->GetChildNode(c));
}
}
/****************************************************************************
Configuration.
To make all options "sticky" across sessions, the options are read and
written to a configuration file every time the exporter is executed.
****************************************************************************/
TSTR Max2Nmo::GetCfgFilename()
{
TSTR filename;
filename += ip->GetDir(APP_PLUGCFG_DIR);
filename += "\\";
filename += CFGFILENAME;
return filename;
}
// NOTE: Update anytime the CFG file changes
#define CFG_BEFORECOMPRESSVERSION 0x02
#define CFG_VERSION 0x02
BOOL Max2Nmo::ReadConfig()
{
TSTR filename = GetCfgFilename();
FILE* cfgStream;
cfgStream = fopen(filename, "rt");
if (!cfgStream)
return FALSE;
int version;
char CharacterName[256];
char AnimationName[256];
//---- read Version
fscanf(cfgStream,"%d",&version);
//---- read settings
if (version < CFG_BEFORECOMPRESSVERSION) {
nCompressionLevel = 0;
fscanf(cfgStream,"%d %d %d %d %d %d %d %d %d %s %s %d %d\n",
&bExportAsObjects,
&bExportAsCharacter,
&bExportAsAnimationOnly,
&bConvertPhysiqueToSkin,
&bStoreOnlyTextureFilenames,
&bRescaleScene,
&nReportLevel,
&nMeshFrameStep,
&nKeyFrameStep,
CharacterName,
AnimationName,
&bGroupAsPlace,
&bSaveBipedGeom);
} else {
fscanf(cfgStream,"%d %d %d %d %d %d %d %d %d %s %s %d %d %d %d\n",
&bExportAsObjects,
&bExportAsCharacter,
&bExportAsAnimationOnly,
&bConvertPhysiqueToSkin,
&bStoreOnlyTextureFilenames,
&bRescaleScene,
&nReportLevel,
&nMeshFrameStep,
&nKeyFrameStep,
CharacterName,
AnimationName,
&bGroupAsPlace,
&bSaveBipedGeom,
&nCompressionLevel,
&bAlignAnimOnZ);
}
fclose(cfgStream);
SetCharacterName(CharacterName);
SetAnimationName(AnimationName);
return TRUE;
}
void Max2Nmo::WriteConfig()
{
TSTR filename = GetCfgFilename();
FILE* cfgStream;
cfgStream = fopen(filename, "wt");
if (!cfgStream)
return;
fprintf(cfgStream,"%d %d %d %d %d %d %d %d %d %d %s %s %d %d %d %d\n",
CFG_VERSION,
GetExportAsObjects(),
GetExportAsCharacter(),
GetExportAsAnimationOnly(),
GetConvertPhysiqueToSkin(),
GetStoreOnlyFilenames(),
GetRescaleScene(),
GetReportLevel(),
GetMeshFrameStep(),
GetKeyFrameStep(),
(char *)GetCharacterName(),
(char *)GetAnimationName(),
bGroupAsPlace,
bSaveBipedGeom,
GetCompressionLevel(),
bAlignAnimOnZ);
fclose(cfgStream);
}
void Max2Nmo::RescaleScene()
{
int type;
float scale;
float convertFactor=1.0f;
if (UNITDISP_GENERIC != GetUnitDisplayType()) {
GetMasterUnitInfo(&type, &scale);
convertFactor=scale;
switch(type) {
case UNITS_INCHES: convertFactor*=0.0254f; break;
case UNITS_FEET: convertFactor*=0.3048f; break;
case UNITS_MILES: convertFactor*=1609.344f; break;
case UNITS_MILLIMETERS: convertFactor*=0.001f; break;
case UNITS_CENTIMETERS: convertFactor*=0.01f; break;
case UNITS_METERS: convertFactor*=1.0f; break;
case UNITS_KILOMETERS: convertFactor*=1000; break;
}
}
if(convertFactor!=1.0f)
{
ip->RescaleWorldUnits(convertFactor, FALSE);
SetMasterUnitInfo(UNITS_METERS,1.0f);
ip->ForceCompleteRedraw();
}
}
BOOL MtlKeeper::AddMtl(Mtl* mtl)
{
if (!mtl) {
return FALSE;
}
int numMtls = mtlTab.Count();
for (int i=0; i<numMtls; i++) {
if (mtlTab[i] == mtl) {
return FALSE;
}
}
mtlTab.Append(1, &mtl, 25);
return TRUE;
}
int MtlKeeper::GetMtlID(Mtl* mtl)
{
int numMtls = mtlTab.Count();
for (int i=0; i<numMtls; i++) {
if (mtlTab[i] == mtl) {
return i;
}
}
return -1;
}
int MtlKeeper::Count()
{
return mtlTab.Count();
}
Mtl* MtlKeeper::GetMtl(int id)
{
return mtlTab[id];
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -