⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 max2nmo.cpp

📁 3dmax导出3d模型二次开发插件
💻 CPP
📖 第 1 页 / 共 3 页
字号:
		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 + -