std::auto_ptr< Accessor > AdskSceneMetadataCmd::getAccessorForScene( MString scenePath )
{
    // This string gets populated with errors by the Metadata library when they occur
    std::string errors;
    std::string stdScenePath( scenePath.asChar() );
    std::auto_ptr< Accessor > accessor( Accessor::accessorByExtension( stdScenePath ) );
    if ( NULL == accessor.get() ) 
    {
        MStatus resStatus;
        MString errorString = MStringResource::getString( rAccessorNotFoundError, resStatus );
        errorString.format( errorString, scenePath );
        displayError( errorString );
        
        return std::auto_ptr< Accessor >();
    }

    // Optimization: only read the scene associations.
    std::set< std::string > wantedAssociations;
    wantedAssociations.insert( AccessorMaya::getSceneAssociationsName() );

    if ( !accessor->read(   stdScenePath, 
                            NULL,                   // read all the structures
                            &wantedAssociations,    
                            errors ) ) 
    {
        MStatus resStatus;
        MString errorString = MStringResource::getString( rCannotReadFileError, resStatus );
        errorString.format( errorString, scenePath, errors.c_str() );
        displayError( errorString );

        return std::auto_ptr< Accessor >();
    }

    return accessor;
}
//======================================================================
//
// Do the command in query mode. It only does one thing, print the Stream,
// Channel, Associations, and Structure formats available.
//
MStatus exportMetadataCmd::doQuery()
{
	assert( fSerializer );
	MStatus status = MS::kSuccess;

	std::set<const adsk::Data::StreamSerializer*>::iterator sFmtIt;
	for( sFmtIt = adsk::Data::StreamSerializer::allFormats().begin();
		 sFmtIt != adsk::Data::StreamSerializer::allFormats().end(); sFmtIt++ )
	{
		const adsk::Data::StreamSerializer* fmt = *sFmtIt;
		MString fmtMsg( MStringResource::getString(kExportMetadataFormatType, status) );
		MString fmtType( "Stream" );
		MString fmtName( fmt->formatType() );
		MString msg;
		msg.format( fmtMsg, fmtType, fmtName );
		appendToResult( msg );
	}

	std::set<const adsk::Data::ChannelSerializer*>::iterator cFmtIt;
	for( cFmtIt = adsk::Data::ChannelSerializer::allFormats().begin();
		 cFmtIt != adsk::Data::ChannelSerializer::allFormats().end(); cFmtIt++ )
	{
		const adsk::Data::ChannelSerializer* fmt = *cFmtIt;
		MString fmtMsg( MStringResource::getString(kExportMetadataFormatType, status) );
		MString fmtType( "Channel" );
		MString fmtName( fmt->formatType() );
		MString msg;
		msg.format( fmtMsg, fmtType, fmtName );
		appendToResult( msg );
	}

	std::set<const adsk::Data::AssociationsSerializer*>::iterator aFmtIt;
	for( aFmtIt = adsk::Data::AssociationsSerializer::allFormats().begin();
		 aFmtIt != adsk::Data::AssociationsSerializer::allFormats().end(); aFmtIt++ )
	{
		const adsk::Data::AssociationsSerializer* fmt = *aFmtIt;
		MString fmtMsg( MStringResource::getString(kExportMetadataFormatType, status) );
		MString fmtType( "Associations" );
		MString fmtName( fmt->formatType() );
		MString msg;
		msg.format( fmtMsg, fmtType, fmtName );
		appendToResult( msg );
	}

	std::set<const adsk::Data::StructureSerializer*>::iterator fmtIt;
	for( fmtIt = adsk::Data::StructureSerializer::allFormats().begin();
		 fmtIt != adsk::Data::StructureSerializer::allFormats().end(); fmtIt++ )
	{
		const adsk::Data::StructureSerializer* fmt = *fmtIt;
		MString fmtMsg( MStringResource::getString(kExportMetadataFormatType, status) );
		MString fmtType( "Structure" );
		MString fmtName( fmt->formatType() );
		MString msg;
		msg.format( fmtMsg, fmtType, fmtName );
		appendToResult( msg );
	}

	return status;
}
//======================================================================
//
// Check the parsed arguments and do/undo/redo the command as appropriate
//
MStatus importMetadataCmd::checkArgs(MArgDatabase& argsDb)
{
	MStatus status = metadataBase::checkArgs( argsDb );
	if( status != MS::kSuccess ) return status;

	//----------------------------------------
	// -string flag
	//
	// If specified then the -file flag is not allowed.
	//
	fStringFlag.parse(argsDb, flagString);
	if( fStringFlag.isSet() )
	{
		if( fFile )
		{
			MString fmt = MStringResource::getString(kFileIgnored, status);
			MString msg;
			msg.format( fmt, flagString );
			displayWarning( msg );
		}

		if( !fStringFlag.isModeValid(fMode) )
		{
			MString fmt = MStringResource::getString(kOnlyCreateModeMsg, status);
			MString msg;
			msg.format( fmt, flagString );
			displayError(msg);
			return MS::kFailure;
		}
		if( ! fStringFlag.isArgValid() )
		{
			MString errMsg( MStringResource::getString(kInvalidString, status) );
			displayError( errMsg );
			return MS::kFailure;
		}
		fString = fStringFlag.arg();
	}
	else if( ! fFile )
	{
		MString fmt = MStringResource::getString(kFileOrStringNeeded, status);
		MString msg;
		msg.format( fmt, flagString );
		displayError( msg );
		return MS::kFailure;
	}
	else if( ! fFile->exists() )
	{
		MString fmt = MStringResource::getString(kFileNotFound, status);
		MString msg;
		msg.format( fmt, fFileFlag.arg().asChar() );
		displayError(msg);
		status = MS::kNotFound;
	}

	return status;
}
MString hwApiTextureTestStrings::getString(const MStringResourceId &stringId, float arg1, float arg2, float arg3, float arg4)
{
	MString string;
	MString arg1String; arg1String += arg1;
	MString arg2String; arg2String += arg2;
	MString arg3String; arg3String += arg3;
	MString arg4String; arg4String += arg4;
	string.format( hwApiTextureTestStrings::getString( stringId ), arg1String, arg2String, arg3String, arg4String );
	return string;
}
Beispiel #5
0
void MVGMesh::setIsActive(const bool isActive) const
{
    MStatus status;

    // Check is flag exists
    MFnMesh fn(_dagpath);
    MPlug mvgPlug = fn.findPlug(_MVG, false, &status);
    if(!status && !isActive)
        return;
    if(!status && isActive)
    {
        // Create MayaMVG attribute
        MDagModifier dagModifier;
        MFnNumericAttribute nAttr;
        MObject mvgAttr = nAttr.create(_MVG, "mvg", MFnNumericData::kBoolean);
        status = dagModifier.addAttribute(_object, mvgAttr);
        CHECK(status)
        dagModifier.doIt();
        mvgPlug = fn.findPlug(_MVG, false, &status);
    }
    status = mvgPlug.setValue(isActive);
    CHECK(status)
    if(isActive)
    {
        status = MGlobal::executePythonCommand("from mayaMVG import scale");
        CHECK(status)
        MString cmd;
        // Retrieve transform node
        cmd.format("scale.getParent(\"^1s\")", _dagpath.fullPathName());
        MString transform;
        status = MGlobal::executePythonCommand(cmd, transform);
        // Freeze transform mesh
        cmd.format("makeIdentity -apply true \"^1s\"", transform);
        status = MGlobal::executeCommand(cmd);
        CHECK(status)
        // Lock node
        cmd.format("scale.lockNode(\"^1s\", True)", transform);
        status = MGlobal::executePythonCommand(cmd);
        CHECK(status)
    }
    else
    {
Beispiel #6
0
MStatus AbcImport::doIt(const MArgList & args)
{
    MStatus status;

    MArgParser argData(syntax(), args, &status);

    MString filename("");
    MString connectRootNodes("");
    MString filterString("");
    MString excludeFilterString("");

    MObject reparentObj = MObject::kNullObj;

    bool    swap = false;
    bool    createIfNotFound = false;
    bool    removeIfNoUpdate = false;

    bool    debugOn = false;

    if (argData.isFlagSet("help"))
    {
        MGlobal::displayInfo(usage);
        return status;
    }

    if (argData.isFlagSet("debug"))
        debugOn = true;

    if (argData.isFlagSet("reparent"))
    {
        MString parent("");
        MDagPath reparentDagPath;
        status = argData.getFlagArgument("reparent", 0, parent);
        if (status == MS::kSuccess
            && getDagPathByName(parent, reparentDagPath) == MS::kSuccess)
        {
            reparentObj = reparentDagPath.node();
        }
        else
        {
            MString theWarning = parent;
            theWarning += MString(" is not a valid DagPath");
            printWarning(theWarning);
        }
    }

    if (!argData.isFlagSet("connect") && argData.isFlagSet("mode"))
    {
        MString modeStr;
        argData.getFlagArgument("mode", 0, modeStr);
        if (modeStr == "replace")
            deleteCurrentSelection();
        else if (modeStr == "open")
        {
            MFileIO fileIo;
            fileIo.newFile(true);
        }
    }
    else if (argData.isFlagSet("connect"))
    {
        swap = true;
        argData.getFlagArgument("connect", 0, connectRootNodes);

        if (argData.isFlagSet("createIfNotFound"))
        {
            createIfNotFound = true;
        }

        if (argData.isFlagSet("removeIfNoUpdate"))
            removeIfNoUpdate = true;
    }

    if (argData.isFlagSet("filterObjects"))
    {
        argData.getFlagArgument("filterObjects", 0, filterString);
    }

    if (argData.isFlagSet("excludeFilterObjects"))
    {
        argData.getFlagArgument("excludeFilterObjects", 0, excludeFilterString);
    }

    // if the flag isn't specified we'll only do stuff marked with the Maya
    // meta data
    bool recreateColorSets = false;
    if (argData.isFlagSet("recreateAllColorSets"))
    {
        recreateColorSets = true;
    }

    status = argData.getCommandArgument(0, filename);
    MString abcNodeName;
    if (status == MS::kSuccess)
    {
        {
            MString fileRule, expandName;
            MString alembicFileRule = "alembicCache";
            MString alembicFilePath = "cache/alembic";

            MString queryFileRuleCmd;
            queryFileRuleCmd.format("workspace -q -fre \"^1s\"",
                alembicFileRule);
            MString queryFolderCmd;
            queryFolderCmd.format("workspace -en `workspace -q -fre \"^1s\"`",
                alembicFileRule);

            // query the file rule for alembic cache
            MGlobal::executeCommand(queryFileRuleCmd, fileRule);
            if (fileRule.length() > 0)
            {
                // we have alembic file rule, query the folder
                MGlobal::executeCommand(queryFolderCmd, expandName);
            }

            // resolve the expanded file rule
            if (expandName.length() == 0)
            {
                expandName = alembicFilePath;
            }

            // get the path to the alembic file rule
            MFileObject directory;
            directory.setRawFullName(expandName);
            MString directoryName = directory.resolvedFullName();

            // resolve the relative path
            MFileObject absoluteFile;
            absoluteFile.setRawFullName(filename);
			absoluteFile.setResolveMethod(MFileObject::kInputFile);
#if MAYA_API_VERSION < 201300
            if (absoluteFile.resolvedFullName() !=
                absoluteFile.expandedFullName())
            {
#else
            if (!MFileObject::isAbsolutePath(filename)) {
#endif
                // this is a relative path
                MString absoluteFileName = directoryName + "/" + filename;
                absoluteFile.setRawFullName(absoluteFileName);
                filename = absoluteFile.resolvedFullName();
            }
            else
            {
                filename = absoluteFile.resolvedFullName();
            }
        }

        MFileObject fileObj;
        status = fileObj.setRawFullName(filename);
        if (status == MS::kSuccess && fileObj.exists())
        {
            ArgData inputData(filename, debugOn, reparentObj,
                swap, connectRootNodes, createIfNotFound, removeIfNoUpdate,
                recreateColorSets, filterString, excludeFilterString);
            abcNodeName = createScene(inputData);

            if (inputData.mSequenceStartTime != inputData.mSequenceEndTime &&
                inputData.mSequenceStartTime != -DBL_MAX &&
                inputData.mSequenceEndTime != DBL_MAX)
            {
                if (argData.isFlagSet("fitTimeRange"))
                {
                    MTime sec(1.0, MTime::kSeconds);
                    setPlayback(
                        inputData.mSequenceStartTime * sec.as(MTime::uiUnit()),
                        inputData.mSequenceEndTime * sec.as(MTime::uiUnit()) );
                }

                if (argData.isFlagSet("setToStartFrame"))
                {
                    MTime sec(1.0, MTime::kSeconds);
                    MGlobal::viewFrame( inputData.mSequenceStartTime *
                        sec.as(MTime::uiUnit()) );
                }
            }
        }
        else
        {
            MString theError("In AbcImport::doIt(), ");
            theError += filename;
            theError += MString(" doesn't exist");
            printError(theError);
        }
    }

    MPxCommand::setResult(abcNodeName);

    return status;
}
Beispiel #7
0
depthShaderOverride::depthShaderOverride(const MObject& obj)
: MPxSurfaceShadingNodeOverride(obj)
, fFragmentName("")
{
	// Define fragments needed for VP2 version of shader, this could also be
	// defined in a separate XML file
	//
	// Define the input and output parameter names to match the input and
	// output attribute names so that the values are automatically populated
	// on the shader.
	//
	// Define a separate fragment for computing the camera space position so
	// that the operation can be done in the vertex shader rather than the
	// pixel shader. Then connect the two fragments together in a graph.
	static const MString sFragmentName("depthShaderPluginFragment");
	static const char* sFragmentBody =
		"<fragment uiName=\"depthShaderPluginFragment\" name=\"depthShaderPluginFragment\" type=\"plumbing\" class=\"ShadeFragment\" version=\"1.0\">"
		"	<description><![CDATA[Depth shader fragment]]></description>"
		"	<properties>"
		"		<float name=\"depthValue\" />"
		"		<float3 name=\"color\" />"
		"		<float3 name=\"colorFar\" />"
		"		<float name=\"near\" />"
		"		<float name=\"far\" />"
		"	</properties>"
		"	<values>"
		"		<float name=\"depthValue\" value=\"0.0\" />"
		"		<float3 name=\"color\" value=\"0.0,1.0,0.0\" />"
		"		<float3 name=\"colorFar\" value=\"0.0,0.0,1.0\" />"
		"		<float name=\"near\" value=\"0.0\" />"
		"		<float name=\"far\" value=\"2.0\" />"
		"	</values>"
		"	<outputs>"
		"		<float3 name=\"outColor\" />"
		"	</outputs>"
		"	<implementation>"
		"	<implementation render=\"OGSRenderer\" language=\"Cg\" lang_version=\"2.1\">"
		"		<function_name val=\"depthShaderPluginFragment\" />"
		"		<source><![CDATA["
		"float3 depthShaderPluginFragment(float depthValue, float3 cNear, float3 cFar, float nearClip, float farClip) \n"
		"{ \n"
		"	float ratio = (farClip + depthValue)/(farClip - nearClip); \n"
		"	return cNear*ratio + cFar*(1.0f - ratio); \n"
		"} \n]]>"
		"		</source>"
		"	</implementation>"
		"	<implementation render=\"OGSRenderer\" language=\"HLSL\" lang_version=\"11.0\">"
		"		<function_name val=\"depthShaderPluginFragment\" />"
		"		<source><![CDATA["
		"float3 depthShaderPluginFragment(float depthValue, float3 cNear, float3 cFar, float nearClip, float farClip) \n"
		"{ \n"
		"	float ratio = (farClip + depthValue)/(farClip - nearClip); \n"
		"	return cNear*ratio + cFar*(1.0f - ratio); \n"
		"} \n]]>"
		"		</source>"
		"	</implementation>"
		"	<implementation render=\"OGSRenderer\" language=\"GLSL\" lang_version=\"3.0\">"
		"		<function_name val=\"depthShaderPluginFragment\" />"
		"		<source><![CDATA["
		"vec3 depthShaderPluginFragment(float depthValue, vec3 cNear, vec3 cFar, float nearClip, float farClip) \n"
		"{ \n"
		"	float ratio = (farClip + depthValue)/(farClip - nearClip); \n"
		"	return cNear*ratio + cFar*(1.0f - ratio); \n"
		"} \n]]>"
		"		</source>"
		"	</implementation>"
		"	</implementation>"
		"</fragment>";

	static const MString sVertexFragmentName("depthShaderPluginInterpolantFragment");
	static const char* sVertexFragmentBody =
		"<fragment uiName=\"depthShaderPluginInterpolantFragment\" name=\"depthShaderPluginInterpolantFragment\" type=\"interpolant\" class=\"ShadeFragment\" version=\"1.0\">"
		"	<description><![CDATA[Depth shader vertex fragment]]></description>"
		"	<properties>"
		"		<float3 name=\"Pm\" semantic=\"Pm\" flags=\"varyingInputParam\" />"
		"		<float4x4 name=\"worldViewProj\" semantic=\"worldviewprojection\" />"
		"	</properties>"
		"	<values>"
		"	</values>"
		"	<outputs>"
		"		<float name=\"outDepthValue\" ^1s/>"
		"	</outputs>"
		"	<implementation>"
		"	<implementation render=\"OGSRenderer\" language=\"Cg\" lang_version=\"2.1\">"
		"		<function_name val=\"depthShaderPluginInterpolantFragment\" />"
		"		<source><![CDATA["
		"float depthShaderPluginInterpolantFragment(float depthValue) \n"
		"{ \n"
		"	return depthValue; \n"
		"} \n]]>"
		"		</source>"
		"		<vertex_source><![CDATA["
		"float idepthShaderPluginInterpolantFragment(float3 Pm, float4x4 worldViewProj) \n"
		"{ \n"
		"	float4 pCamera = mul(worldViewProj, float4(Pm, 1.0f)); \n"
		"	return (pCamera.z - pCamera.w*2.0f); \n"
		"} \n]]>"
		"		</vertex_source>"
		"	</implementation>"
		"	<implementation render=\"OGSRenderer\" language=\"HLSL\" lang_version=\"11.0\">"
		"		<function_name val=\"depthShaderPluginInterpolantFragment\" />"
		"		<source><![CDATA["
		"float depthShaderPluginInterpolantFragment(float depthValue) \n"
		"{ \n"
		"	return depthValue; \n"
		"} \n]]>"
		"		</source>"
		"		<vertex_source><![CDATA["
		"float idepthShaderPluginInterpolantFragment(float3 Pm, float4x4 worldViewProj) \n"
		"{ \n"
		"	float4 pCamera = mul(float4(Pm, 1.0f), worldViewProj); \n"
		"	return (pCamera.z - pCamera.w*2.0f); \n"
		"} \n]]>"
		"		</vertex_source>"
		"	</implementation>"
		"	<implementation render=\"OGSRenderer\" language=\"GLSL\" lang_version=\"3.0\">"
		"		<function_name val=\"depthShaderPluginInterpolantFragment\" />"
		"		<source><![CDATA["
		"float depthShaderPluginInterpolantFragment(float depthValue) \n"
		"{ \n"
		"	return depthValue; \n"
		"} \n]]>"
		"		</source>"
		"		<vertex_source><![CDATA["
		"float idepthShaderPluginInterpolantFragment(vec3 Pm, mat4 worldViewProj) \n"
		"{ \n"
		"	vec4 pCamera = worldViewProj * vec4(Pm, 1.0f); \n"
		"	return (pCamera.z - pCamera.w*2.0f); \n"
		"} \n]]>"
		"		</vertex_source>"
		"	</implementation>"
		"	</implementation>"
		"</fragment>";

	static const MString sFragmentGraphName("depthShaderPluginGraph");
	static const char* sFragmentGraphBody =
		"<fragment_graph name=\"depthShaderPluginGraph\" ref=\"depthShaderPluginGraph\" class=\"FragmentGraph\" version=\"1.0\">"
		"	<fragments>"
		"			<fragment_ref name=\"depthShaderPluginFragment\" ref=\"depthShaderPluginFragment\" />"
		"			<fragment_ref name=\"depthShaderPluginInterpolantFragment\" ref=\"depthShaderPluginInterpolantFragment\" />"
		"	</fragments>"
		"	<connections>"
		"		<connect from=\"depthShaderPluginInterpolantFragment.outDepthValue\" to=\"depthShaderPluginFragment.depthValue\" />"
		"	</connections>"
		"	<properties>"
        "		<float3 name=\"Pm\" ref=\"depthShaderPluginInterpolantFragment.Pm\" semantic=\"Pm\" flags=\"varyingInputParam\" />"
        "		<float4x4 name=\"worldViewProj\" ref=\"depthShaderPluginInterpolantFragment.worldViewProj\" semantic=\"worldviewprojection\" />"
		"		<float3 name=\"color\" ref=\"depthShaderPluginFragment.color\" />"
		"		<float3 name=\"colorFar\" ref=\"depthShaderPluginFragment.colorFar\" />"
		"		<float name=\"near\" ref=\"depthShaderPluginFragment.near\" />"
		"		<float name=\"far\" ref=\"depthShaderPluginFragment.far\" />"
		"	</properties>"
		"	<values>"
		"		<float3 name=\"color\" value=\"0.0,1.0,0.0\" />"
		"		<float3 name=\"colorFar\" value=\"0.0,0.0,1.0\" />"
		"		<float name=\"near\" value=\"0.0\" />"
		"		<float name=\"far\" value=\"2.0\" />"
		"	</values>"
		"	<outputs>"
		"		<float3 name=\"outColor\" ref=\"depthShaderPluginFragment.outColor\" />"
		"	</outputs>"
		"</fragment_graph>";

	// Register fragments with the manager if needed
	MHWRender::MRenderer* theRenderer = MHWRender::MRenderer::theRenderer();
	if (theRenderer)
	{
		MHWRender::MFragmentManager* fragmentMgr =
			theRenderer->getFragmentManager();
		if (fragmentMgr)
		{
			// Add fragments if needed
			bool fragAdded = fragmentMgr->hasFragment(sFragmentName);
			bool vertFragAdded = fragmentMgr->hasFragment(sVertexFragmentName);
			bool graphAdded = fragmentMgr->hasFragment(sFragmentGraphName);
			if (!fragAdded)
			{
				fragAdded = (sFragmentName == fragmentMgr->addShadeFragmentFromBuffer(sFragmentBody, false));
			}
			if (!vertFragAdded)
			{
				// In DirectX, need to specify a semantic for the output of the vertex shader
				MString vertBody;
				if (theRenderer->drawAPI() == MHWRender::kDirectX11)
				{
					vertBody.format(MString(sVertexFragmentBody), MString("semantic=\"extraDepth\" "));
				}
				else
				{
					vertBody.format(MString(sVertexFragmentBody), MString(" "));
				}
				vertFragAdded = (sVertexFragmentName == fragmentMgr->addShadeFragmentFromBuffer(vertBody.asChar(), false));
			}
			if (!graphAdded)
			{
				graphAdded = (sFragmentGraphName == fragmentMgr->addFragmentGraphFromBuffer(sFragmentGraphBody));
			}

			// If we have them all, use the final graph for the override
			if (fragAdded && vertFragAdded && graphAdded)
			{
				fFragmentName = sFragmentGraphName;
			}
		}
	}
}
MString hwApiTextureTestStrings::getString(const MStringResourceId &stringId, const MString& arg1, const MString& arg2)
{
	MString string;
	string.format( hwApiTextureTestStrings::getString( stringId ), arg1, arg2 );
	return string;
}
//======================================================================
//
// Do the import in create mode. The metadata will be retrieved from the
// file or string and imported onto the selected object(s) presuming the
// specified format. Successful execution will see the imported metadata on
// the object(s), returning the names of the newly created or modified streams
// in the format OBJECT/CHANNEL_TYPE/STREAM
//
// The previously existing metadata is preserved for later undo.
//
MStatus importMetadataCmd::doCreate()
{
	assert( fSerializer );
	std::string errors;

	Associations* associationsRead = (Associations*)0;
	MStatus status;

	if( fString.length() > 0 )
	{
		std::stringstream inStream( fString.asChar() );
		associationsRead = fSerializer->read( inStream, errors );
		if( ! associationsRead )
		{
			MString fmt = MStringResource::getString(kImportMetadataStringReadFailed, status);
			MString msg;
			MString err( errors.c_str() );
			msg.format( fmt, err );
			displayError(msg);
			return MS::kFailure;
		}
	}
	else if( fFile )
	{
		std::ifstream inStream( fFile->resolvedFullName().asChar() );
		associationsRead = fSerializer->read( inStream, errors );
		inStream.close();
		if( ! associationsRead )
		{
			MString fmt = MStringResource::getString(kImportMetadataFileReadFailed, status);
			MString msg;
			MString err( errors.c_str() );
			msg.format( fmt, fFile->resolvedFullName(), err );
			displayError(msg);
			return MS::kFailure;
		}
	}
	else
	{
		// This isn't a recoverable error since this situation should have
		// been reported in the arg checking. Just assert and fail
		// immediately.
		assert( fFile );
		return MS::kFailure;
	}

	// Should have already handled this
	assert( associationsRead );

	MString resultFmt = MStringResource::getString(kImportMetadataResult, status);
	for( unsigned int i=0; i<fObjects.length(); ++i )
	{
		MFnDependencyNode node( fObjects[i], &status );
		// Should have filtered out non-objects already but check anyway
		if( MS::kSuccess != status ) continue;

		displayInfo( node.name(&status) );

		fDGModifier.setMetadata( fObjects[i], *associationsRead );

		if( MS::kSuccess == fDGModifier.doIt() )
		{
			for( unsigned int c=0; c<associationsRead->channelCount(); ++c )
			{
				adsk::Data::Channel channel = associationsRead->channelAt(c);
				MString cName( channel.name().c_str() );
				for( unsigned int s=0; s<channel.dataStreamCount(); ++s )
				{
					adsk::Data::Stream* cStream = channel.dataStream(s);
					if( cStream )
					{
						MString sName( cStream->name().c_str() );
						MString msg;
						msg.format( resultFmt, node.name(), cName, sName );
						appendToResult( msg );
					}
				}
			}
		}
		else
		{
			MString fmt = MStringResource::getString(kImportMetadataSetMetadataFailed, status);
			MString msg;
			msg.format( fmt, node.name() );
			displayError( msg );
			status = MS::kFailure;
		}
	}

    return status;
}
Beispiel #10
0
MStatus AbcExport::doIt(const MArgList & args)
{
try
{
    MStatus status;

    MTime oldCurTime = MAnimControl::currentTime();

    MArgParser argData(syntax(), args, &status);

    if (argData.isFlagSet("help"))
    {
        MGlobal::displayInfo(util::getHelpText());
        return MS::kSuccess;
    }

    bool verbose = argData.isFlagSet("verbose");

    // If skipFrame is true, when going through the playback range of the
    // scene, as much frames are skipped when possible.  This could cause
    // a problem for, time dependent solutions like
    // particle system / hair simulation
    bool skipFrame = true;
    if (argData.isFlagSet("dontSkipUnwrittenFrames"))
        skipFrame = false;

    double startEvaluationTime = DBL_MAX;
    if (argData.isFlagSet("preRollStartFrame"))
    {
        double startAt = 0.0;
        argData.getFlagArgument("preRollStartFrame", 0, startAt);
        startEvaluationTime = startAt;
    }

    unsigned int jobSize = argData.numberOfFlagUses("jobArg");

    if (jobSize == 0)
        return status;

    // the frame range we will be iterating over for all jobs,
    // includes frames which are not skipped and the startAt offset
    std::set<double> allFrameRange;

    // this will eventually hold only the animated jobs.
    // its a list because we will be removing jobs from it
    std::list < AbcWriteJobPtr > jobList;

    for (unsigned int jobIndex = 0; jobIndex < jobSize; jobIndex++)
    {
        JobArgs jobArgs;
        MArgList jobArgList;
        argData.getFlagArgumentList("jobArg", jobIndex, jobArgList);
        MString jobArgsStr = jobArgList.asString(0);
        MStringArray jobArgsArray;

        {
            // parse the job arguments
            // e.g. -perFrameCallbackMel "print \"something\"" will be splitted to
            //    [0] -perFrameCallbackMel
            //    [1] print "something"
            enum State {
                kArgument,               // parsing an argument (not quoted)
                kDoubleQuotedString,     // parsing a double quoted string
                kSingleQuotedString,     // parsing a single quoted string
            };

            State state = kArgument;
            MString stringBuffer;
            for (unsigned int charIdx = 0; charIdx < jobArgsStr.numChars();
                charIdx++)
            {
                MString ch = jobArgsStr.substringW(charIdx, charIdx);
                switch (state)
                {
                case kArgument:
                    if (ch == " ")
                    {
                        // space terminates the current argument
                        if (stringBuffer.length() > 0) {
                            jobArgsArray.append(stringBuffer);
                            stringBuffer.clear();
                        }
                        // goto another argument
                        state = kArgument;
                    }
                    else if (ch == "\"")
                    {
                        if (stringBuffer.length() > 0)
                        {
                            // double quote is part of the argument
                            stringBuffer += ch;
                        }
                        else
                        {
                            // goto double quoted string
                            state = kDoubleQuotedString;
                        }
                    }
                    else if (ch == "'")
                    {
                        if (stringBuffer.length() > 0)
                        {
                            // single quote is part of the argument
                            stringBuffer += ch;
                        }
                        else
                        {
                            // goto single quoted string
                            state = kSingleQuotedString;
                        }
                    }
                    else
                    {
                        stringBuffer += ch;
                    }
                break;

                case kDoubleQuotedString:
                    // double quote terminates the current string
                    if (ch == "\"")
                    {
                        jobArgsArray.append(stringBuffer);
                        stringBuffer.clear();
                        state = kArgument;
                    }
                    else if (ch == "\\")
                    {
                        // escaped character
                        MString nextCh = (++charIdx < jobArgsStr.numChars())
                            ? jobArgsStr.substringW(charIdx, charIdx) : "\\";
                        if (nextCh == "n")       stringBuffer += "\n";
                        else if (nextCh == "t")  stringBuffer += "\t";
                        else if (nextCh == "r")  stringBuffer += "\r";
                        else if (nextCh == "\\") stringBuffer += "\\";
                        else if (nextCh == "'")  stringBuffer += "'";
                        else if (nextCh == "\"") stringBuffer += "\"";
                        else                     stringBuffer += nextCh;
                    }
                    else
                    {
                        stringBuffer += ch;
                    }
                break;

                case kSingleQuotedString:
                    // single quote terminates the current string
                    if (ch == "'")
                    {
                        jobArgsArray.append(stringBuffer);
                        stringBuffer.clear();
                        state = kArgument;
                    }
                    else if (ch == "\\")
                    {
                        // escaped character
                        MString nextCh = (++charIdx < jobArgsStr.numChars())
                            ? jobArgsStr.substringW(charIdx, charIdx) : "\\";
                        if (nextCh == "n")       stringBuffer += "\n";
                        else if (nextCh == "t")  stringBuffer += "\t";
                        else if (nextCh == "r")  stringBuffer += "\r";
                        else if (nextCh == "\\") stringBuffer += "\\";
                        else if (nextCh == "'")  stringBuffer += "'";
                        else if (nextCh == "\"") stringBuffer += "\"";
                        else                     stringBuffer += nextCh;
                    }
                    else
                    {
                        stringBuffer += ch;
                    }
                break;
                }
            }

            // the rest of the argument
            if (stringBuffer.length() > 0)
            {
                jobArgsArray.append(stringBuffer);
            }
        }

        // the frame range within this job
        std::vector< FrameRangeArgs > frameRanges(1);
        frameRanges.back().startTime = oldCurTime.value();
        frameRanges.back().endTime = oldCurTime.value();
        frameRanges.back().strideTime = 1.0;

        bool hasRange = false;
        bool hasRoot = false;
        bool sampleGeo  = true; // whether or not to subsample geometry
        std::string fileName;
        bool asOgawa = true;

        unsigned int numJobArgs = jobArgsArray.length();
        for (unsigned int i = 0; i < numJobArgs; ++i)
        {
            MString arg = jobArgsArray[i];
            arg.toLowerCase();

            if (arg == "-f" || arg == "-file")
            {
                if (i+1 >= numJobArgs)
                {
                    MGlobal::displayError("File incorrectly specified.");
                    return MS::kFailure;
                }
                fileName = jobArgsArray[++i].asChar();
            }

            else if (arg == "-fr" || arg == "-framerange")
            {
                if (i+2 >= numJobArgs || !jobArgsArray[i+1].isDouble() ||
                    !jobArgsArray[i+2].isDouble())
                {
                    MGlobal::displayError("Frame Range incorrectly specified.");
                    return MS::kFailure;
                }

                // this is not the first -frameRange argument, we are going
                // to add one more frame range to the frame range array.
                if (hasRange)
                {
                    frameRanges.push_back(FrameRangeArgs());
                }

                hasRange = true;
                frameRanges.back().startTime = jobArgsArray[++i].asDouble();
                frameRanges.back().endTime = jobArgsArray[++i].asDouble();

                // make sure start frame is smaller or equal to endTime
                if (frameRanges.back().startTime > frameRanges.back().endTime)
                {
                    std::swap(frameRanges.back().startTime,
                        frameRanges.back().endTime);
                }
            }

            else if (arg == "-frs" || arg == "-framerelativesample")
            {
                if (i+1 >= numJobArgs || !jobArgsArray[i+1].isDouble())
                {
                    MGlobal::displayError(
                        "Frame Relative Sample incorrectly specified.");
                    return MS::kFailure;
                }
                frameRanges.back().shutterSamples.insert(
                    jobArgsArray[++i].asDouble());
            }

            else if (arg == "-nn" || arg == "-nonormals")
            {
                jobArgs.noNormals = true;
            }

            else if (arg == "-pr" || arg == "-preroll")
            {
                frameRanges.back().preRoll = true;
            }

            else if (arg == "-ro" || arg == "-renderableonly")
            {
                jobArgs.excludeInvisible = true;
            }

            else if (arg == "-s" || arg == "-step")
            {
                if (i+1 >= numJobArgs || !jobArgsArray[i+1].isDouble())
                {
                    MGlobal::displayError("Step incorrectly specified.");
                    return MS::kFailure;
                }
                frameRanges.back().strideTime = jobArgsArray[++i].asDouble();
            }

            else if (arg == "-sl" || arg == "-selection")
            {
                jobArgs.useSelectionList = true;
            }

            else if (arg == "-sn" || arg == "-stripnamespaces")
            {
                if (i+1 >= numJobArgs || !jobArgsArray[i+1].isUnsigned())
                {
                    // the strip all namespaces case
                    // so we pick a very LARGE number
                    jobArgs.stripNamespace = 0xffffffff;
                }
                else
                {
                    jobArgs.stripNamespace = jobArgsArray[++i].asUnsigned();
                }
            }

            else if (arg == "-uv" || arg == "-uvwrite")
            {
                jobArgs.writeUVs = true;
            }

            else if (arg == "-wcs" || arg == "-writecolorsets")
            {
                jobArgs.writeColorSets = true;
            }

            else if (arg == "-wfs" || arg == "-writefacesets")
            {
                jobArgs.writeFaceSets = true;
            }

            else if (arg == "-wfg" || arg == "-wholeframegeo")
            {
                sampleGeo = false;
            }

            else if (arg == "-ws" || arg == "-worldspace")
            {
                jobArgs.worldSpace = true;
            }

            else if (arg == "-wuvs" || arg == "-writeuvsets")
            {
                jobArgs.writeUVSets = true;
            }

            else if (arg == "-wv" || arg == "-writevisibility")
            {
                jobArgs.writeVisibility = true;
            }

            else if (arg == "-as" || arg == "-autosubd")
            {
                jobArgs.autoSubd = true;
            }

            else if (arg == "-mfc" || arg == "-melperframecallback")
            {
                if (i+1 >= numJobArgs)
                {
                    MGlobal::displayError(
                        "melPerFrameCallback incorrectly specified.");
                    return MS::kFailure;
                }
                jobArgs.melPerFrameCallback = jobArgsArray[++i].asChar();
            }

            else if (arg == "-pfc" || arg == "-pythonperframecallback")
            {
                if (i+1 >= numJobArgs)
                {
                    MGlobal::displayError(
                        "pythonPerFrameCallback incorrectly specified.");
                    return MS::kFailure;
                }
                jobArgs.pythonPerFrameCallback = jobArgsArray[++i].asChar();
            }

            else if (arg == "-mpc" || arg == "-melpostjobcallback")
            {
                if (i+1 >= numJobArgs)
                {
                    MGlobal::displayError(
                        "melPostJobCallback incorrectly specified.");
                    return MS::kFailure;
                }
                jobArgs.melPostCallback = jobArgsArray[++i].asChar();
            }

            else if (arg == "-ppc" || arg == "-pythonpostjobcallback")
            {
                if (i+1 >= numJobArgs)
                {
                    MGlobal::displayError(
                        "pythonPostJobCallback incorrectly specified.");
                    return MS::kFailure;
                }
                jobArgs.pythonPostCallback = jobArgsArray[++i].asChar();
            }

            // geomArbParams - attribute filtering stuff
            else if (arg == "-atp" || arg == "-attrprefix")
            {
                if (i+1 >= numJobArgs)
                {
                    MGlobal::displayError(
                        "attrPrefix incorrectly specified.");
                    return MS::kFailure;
                }
                jobArgs.prefixFilters.push_back(jobArgsArray[++i].asChar());
            }

            else if (arg == "-a" || arg == "-attr")
            {
                if (i+1 >= numJobArgs)
                {
                    MGlobal::displayError(
                        "attr incorrectly specified.");
                    return MS::kFailure;
                }
                jobArgs.attribs.insert(jobArgsArray[++i].asChar());
            }

            // userProperties - attribute filtering stuff
            else if (arg == "-uatp" || arg == "-userattrprefix")
            {
                if (i+1 >= numJobArgs)
                {
                    MGlobal::displayError(
                        "userAttrPrefix incorrectly specified.");
                    return MS::kFailure;
                }
                jobArgs.userPrefixFilters.push_back(jobArgsArray[++i].asChar());
            }

            else if (arg == "-u" || arg == "-userattr")
            {
                if (i+1 >= numJobArgs)
                {
                    MGlobal::displayError(
                        "userAttr incorrectly specified.");
                    return MS::kFailure;
                }
                jobArgs.userAttribs.insert(jobArgsArray[++i].asChar());
            }

            else if (arg == "-rt" || arg == "-root")
            {
                if (i+1 >= numJobArgs)
                {
                    MGlobal::displayError(
                        "root incorrectly specified.");
                    return MS::kFailure;
                }
                hasRoot = true;
                MString root = jobArgsArray[++i];

                MSelectionList sel;
                if (sel.add(root) != MS::kSuccess)
                {
                    MString warn = root;
                    warn += " could not be select, skipping.";
                    MGlobal::displayWarning(warn);
                    continue;
                }

                unsigned int numRoots = sel.length();
                for (unsigned int j = 0; j < numRoots; ++j)
                {
                    MDagPath path;
                    if (sel.getDagPath(j, path) != MS::kSuccess)
                    {
                        MString warn = path.fullPathName();
                        warn += " (part of ";
                        warn += root;
                        warn += " ) not a DAG Node, skipping.";
                        MGlobal::displayWarning(warn);
                        continue;
                    }
                    jobArgs.dagPaths.insert(path);
                }
            }
            else if (arg == "-ef" || arg == "-eulerfilter")
            {
                jobArgs.filterEulerRotations = true;
            }
            else if (arg == "-df" || arg == "-dataformat")
            {
                if (i+1 >= numJobArgs)
                {
                    MGlobal::displayError(
                        "dataFormat incorrectly specified.");
                    return MS::kFailure;
                }
                MString dataFormat = jobArgsArray[++i];
                dataFormat.toLowerCase();
                if (dataFormat == "hdf")
                {
                    asOgawa = false;
                }
                else if (dataFormat == "ogawa")
                {
                    asOgawa = true;
                }
            }
            else
            {
                MString warn = "Ignoring unsupported flag: ";
                warn += jobArgsArray[i];
                MGlobal::displayWarning(warn);
            }
        } //  for i

        if (fileName == "")
        {
            MString error = "-file not specified.";
            MGlobal::displayError(error);
            return MS::kFailure;
        }

        {
            MString fileRule, expandName;
            MString alembicFileRule = "alembicCache";
            MString alembicFilePath = "cache/alembic";

            MString queryFileRuleCmd;
            queryFileRuleCmd.format("workspace -q -fre \"^1s\"",
                alembicFileRule);

            MString queryFolderCmd;
            queryFolderCmd.format("workspace -en `workspace -q -fre \"^1s\"`",
                alembicFileRule);

            // query the file rule for alembic cache
            MGlobal::executeCommand(queryFileRuleCmd, fileRule);
            if (fileRule.length() > 0)
            {
                // we have alembic file rule, query the folder
                MGlobal::executeCommand(queryFolderCmd, expandName);
            }
            else
            {
                // alembic file rule does not exist, create it
                MString addFileRuleCmd;
                addFileRuleCmd.format("workspace -fr \"^1s\" \"^2s\"",
                    alembicFileRule, alembicFilePath);
                MGlobal::executeCommand(addFileRuleCmd);

                // save the workspace. maya may discard file rules on exit
                MGlobal::executeCommand("workspace -s");

                // query the folder
                MGlobal::executeCommand(queryFolderCmd, expandName);
            }

            // resolve the expanded file rule
            if (expandName.length() == 0)
            {
                expandName = alembicFilePath;
            }

            // get the path to the alembic file rule
            MFileObject directory;
            directory.setRawFullName(expandName);
            MString directoryName = directory.resolvedFullName();

            // make sure the cache folder exists
            if (!directory.exists())
            {
                // create the cache folder
                MString createFolderCmd;
                createFolderCmd.format("sysFile -md \"^1s\"", directoryName);
                MGlobal::executeCommand(createFolderCmd);
            }

            // resolve the relative path
            MFileObject absoluteFile;
            absoluteFile.setRawFullName(fileName.c_str());
#if MAYA_API_VERSION < 201300
            if (absoluteFile.resolvedFullName() !=
                absoluteFile.expandedFullName())
            {
#else
            if (!MFileObject::isAbsolutePath(fileName.c_str())) {
#endif
                // this is a relative path
                MString absoluteFileName = directoryName + "/" +
                    fileName.c_str();
                absoluteFile.setRawFullName(absoluteFileName);
                fileName = absoluteFile.resolvedFullName().asChar();
            }
            else
            {
                fileName = absoluteFile.resolvedFullName().asChar();
            }

            // check the path must exist before writing
            MFileObject absoluteFilePath;
            absoluteFilePath.setRawFullName(absoluteFile.path());
            if (!absoluteFilePath.exists()) {
                MString error;
                error.format("Path ^1s does not exist!", absoluteFilePath.resolvedFullName());
                MGlobal::displayError(error);
                return MS::kFailure;
            }

            // check the file is used by any AlembicNode in the scene
            MItDependencyNodes dgIter(MFn::kPluginDependNode);
            for (; !dgIter.isDone(); dgIter.next()) {
                MFnDependencyNode alembicNode(dgIter.thisNode());
                if (alembicNode.typeName() != "AlembicNode") {
                    continue;
                }

                MPlug abcFilePlug = alembicNode.findPlug("abc_File");
                if (abcFilePlug.isNull()) {
                    continue;
                }

                MFileObject alembicFile;
                alembicFile.setRawFullName(abcFilePlug.asString());
                if (!alembicFile.exists()) {
                    continue;
                }

                if (alembicFile.resolvedFullName() == absoluteFile.resolvedFullName()) {
                    MString error = "Can't export to an Alembic file which is in use.";
                    MGlobal::displayError(error);
                    return MS::kFailure;
                }
            }

            std::ofstream ofs(fileName.c_str());
            if (!ofs.is_open()) {
                MString error = MString("Can't write to file: ") + fileName.c_str();
                MGlobal::displayError(error);
                return MS::kFailure;
            }
            ofs.close();
        }

        // if -frameRelativeSample argument is not specified for a frame range,
        // we are assuming a -frameRelativeSample 0.0
        for (std::vector<FrameRangeArgs>::iterator range =
            frameRanges.begin(); range != frameRanges.end(); ++range)
        {
            if (range->shutterSamples.empty())
                range->shutterSamples.insert(0.0);
        }

        if (jobArgs.prefixFilters.empty())
        {
            jobArgs.prefixFilters.push_back("ABC_");
        }

        // the list of frame ranges for sampling
        std::vector<FrameRangeArgs> sampleRanges;
        std::vector<FrameRangeArgs> preRollRanges;
        for (std::vector<FrameRangeArgs>::const_iterator range =
            frameRanges.begin(); range != frameRanges.end(); ++range)
        {
            if (range->preRoll)
                preRollRanges.push_back(*range);
            else
                sampleRanges.push_back(*range);
        }

        // the list of frames written into the abc file
        std::set<double> geoSamples;
        std::set<double> transSamples;
        for (std::vector<FrameRangeArgs>::const_iterator range =
            sampleRanges.begin(); range != sampleRanges.end(); ++range)
        {
            for (double frame = range->startTime;
                frame <= range->endTime;
                frame += range->strideTime)
            {
                for (std::set<double>::const_iterator shutter =
                    range->shutterSamples.begin();
                    shutter != range->shutterSamples.end(); ++shutter)
                {
                    double curFrame = *shutter + frame;
                    if (!sampleGeo)
                    {
                        double intFrame = (double)(int)(
                            curFrame >= 0 ? curFrame + .5 : curFrame - .5);

                        // only insert samples that are close to being an integer
                        if (fabs(curFrame - intFrame) < 1e-4)
                        {
                            geoSamples.insert(curFrame);
                        }
                    }
                    else
                    {
                        geoSamples.insert(curFrame);
                    }
                    transSamples.insert(curFrame);
                }
            }

            if (geoSamples.empty())
            {
                geoSamples.insert(range->startTime);
            }

            if (transSamples.empty())
            {
                transSamples.insert(range->startTime);
            }
        }

        bool isAcyclic = false;
        if (sampleRanges.empty())
        {
            // no frame ranges or all frame ranges are pre-roll ranges
            hasRange = false;
            geoSamples.insert(frameRanges.back().startTime);
            transSamples.insert(frameRanges.back().startTime);
        }
        else
        {
            // check if the time range is even (cyclic)
            // otherwise, we will use acyclic
            // sub frames pattern
            std::vector<double> pattern(
                sampleRanges.begin()->shutterSamples.begin(),
                sampleRanges.begin()->shutterSamples.end());
            std::transform(pattern.begin(), pattern.end(), pattern.begin(),
                std::bind2nd(std::plus<double>(),
                    sampleRanges.begin()->startTime));

            // check the frames against the pattern
            std::vector<double> timeSamples(
                transSamples.begin(), transSamples.end());
            for (size_t i = 0; i < timeSamples.size(); i++)
            {
                // next pattern
                if (i % pattern.size() == 0 && i / pattern.size() > 0)
                {
                    std::transform(pattern.begin(), pattern.end(),
                        pattern.begin(), std::bind2nd(std::plus<double>(),
                            sampleRanges.begin()->strideTime));
                }

                // pattern mismatch, we use acyclic time sampling type
                if (timeSamples[i] != pattern[i % pattern.size()])
                {
                    isAcyclic = true;
                    break;
                }
            }
        }

        // the list of frames to pre-roll
        std::set<double> preRollSamples;
        for (std::vector<FrameRangeArgs>::const_iterator range =
            preRollRanges.begin(); range != preRollRanges.end(); ++range)
        {
            for (double frame = range->startTime;
                frame <= range->endTime;
                frame += range->strideTime)
            {
                for (std::set<double>::const_iterator shutter =
                    range->shutterSamples.begin();
                    shutter != range->shutterSamples.end(); ++shutter)
                {
                    double curFrame = *shutter + frame;
                    preRollSamples.insert(curFrame);
                }
            }

            if (preRollSamples.empty())
            {
                preRollSamples.insert(range->startTime);
            }
        }

        if (jobArgs.dagPaths.size() > 1)
        {
            // check for validity of the DagPath relationships complexity : n^2

            util::ShapeSet::const_iterator m, n;
            util::ShapeSet::const_iterator end = jobArgs.dagPaths.end();
            for (m = jobArgs.dagPaths.begin(); m != end; )
            {
                MDagPath path1 = *m;
                m++;
                for (n = m; n != end; n++)
                {
                    MDagPath path2 = *n;
                    if (util::isAncestorDescendentRelationship(path1,path2))
                    {
                        MString errorMsg = path1.fullPathName();
                        errorMsg += " and ";
                        errorMsg += path2.fullPathName();
                        errorMsg += " have an ancestor relationship.";
                        MGlobal::displayError(errorMsg);
                        return MS::kFailure;
                    }
                }  // for n
            }  // for m
        }
        // no root is specified, and we aren't using a selection
        // so we'll try to translate the whole Maya scene by using all
        // children of the world as roots.
        else if (!hasRoot && !jobArgs.useSelectionList)
        {
            MSelectionList sel;
#if MAYA_API_VERSION >= 201100
            sel.add("|*", true);
#else
            // older versions of Maya will not be able to find top level nodes
            // within namespaces
            sel.add("|*");
#endif
            unsigned int numRoots = sel.length();
            for (unsigned int i = 0; i < numRoots; ++i)
            {
                MDagPath path;
                sel.getDagPath(i, path);
                jobArgs.dagPaths.insert(path);
            }
        }
        else if (hasRoot && jobArgs.dagPaths.empty())
        {
            MString errorMsg = "No valid root nodes were specified.";
            MGlobal::displayError(errorMsg);
            return MS::kFailure;
        }
        else if (jobArgs.useSelectionList)
        {
            MSelectionList activeList;
            MGlobal::getActiveSelectionList(activeList);
            if (activeList.length() == 0)
            {
                MString errorMsg =
                    "-selection specified but nothing is actively selected.";
                MGlobal::displayError(errorMsg);
                return MS::kFailure;
            }
        }

        AbcA::TimeSamplingPtr transTime, geoTime;

        if (hasRange)
        {
            if (isAcyclic)
            {
                // acyclic, uneven time sampling
                // e.g. [0.8, 1, 1.2], [2.8, 3, 3.2], .. not continuous
                //      [0.8, 1, 1.2], [1.7, 2, 2.3], .. shutter different
                std::vector<double> samples(
                    transSamples.begin(), transSamples.end());
                std::transform(samples.begin(), samples.end(), samples.begin(),
                    std::bind2nd(std::multiplies<double>(), util::spf()));
                transTime.reset(new AbcA::TimeSampling(AbcA::TimeSamplingType(
                    AbcA::TimeSamplingType::kAcyclic), samples));
            }
            else
            {
                // cyclic, even time sampling between time periods
                // e.g. [0.8, 1, 1.2], [1.8, 2, 2.2], ...
                std::vector<double> samples;
                double startTime = sampleRanges[0].startTime;
                double strideTime = sampleRanges[0].strideTime;
                for (std::set<double>::const_iterator shutter =
                    sampleRanges[0].shutterSamples.begin();
                    shutter != sampleRanges[0].shutterSamples.end();
                    ++shutter)
                {
                    samples.push_back((startTime + *shutter) * util::spf());
                }

                if (samples.size() > 1)
                {
                    Alembic::Util::uint32_t numSamples =
                        static_cast<Alembic::Util::uint32_t>(samples.size());
                    transTime.reset(
                        new AbcA::TimeSampling(AbcA::TimeSamplingType(
                            numSamples, strideTime * util::spf()), samples));
                }
                // uniform sampling
                else
                {
                    transTime.reset(new AbcA::TimeSampling(
                        strideTime * util::spf(), samples[0]));
                }
            }
        }
        else
        {
            // time ranges are not specified
            transTime.reset(new AbcA::TimeSampling());
        }

        if (sampleGeo || !hasRange)
        {
            geoTime = transTime;
        }
        else
        {
            // sampling geo on whole frames
            if (isAcyclic)
            {
                // acyclic, uneven time sampling
                std::vector<double> samples(
                    geoSamples.begin(), geoSamples.end());
                // one more sample for setup()
                if (*transSamples.begin() != *geoSamples.begin())
                    samples.insert(samples.begin(), *transSamples.begin());
                std::transform(samples.begin(), samples.end(), samples.begin(),
                    std::bind2nd(std::multiplies<double>(), util::spf()));
                geoTime.reset(new AbcA::TimeSampling(AbcA::TimeSamplingType(
                    AbcA::TimeSamplingType::kAcyclic), samples));
            }
            else
            {
                double geoStride = sampleRanges[0].strideTime;
                if (geoStride < 1.0)
                    geoStride = 1.0;

                double geoStart = *geoSamples.begin() * util::spf();
                geoTime.reset(new AbcA::TimeSampling(
                    geoStride * util::spf(), geoStart));
            }
        }

        AbcWriteJobPtr job(new AbcWriteJob(fileName.c_str(), asOgawa,
            transSamples, transTime, geoSamples, geoTime, jobArgs));

       jobList.push_front(job);

        // make sure we add additional whole frames, if we arent skipping
        // the inbetween ones
        if (!skipFrame && !allFrameRange.empty())
        {
            double localMin = *(transSamples.begin());
            std::set<double>::iterator last = transSamples.end();
            last--;
            double localMax = *last;

            double globalMin = *(allFrameRange.begin());
            last = allFrameRange.end();
            last--;
            double globalMax = *last;

            // if the min of our current frame range is beyond
            // what we know about, pad a few more frames
            if (localMin > globalMax)
            {
                for (double f = globalMax; f < localMin; f++)
                {
                    allFrameRange.insert(f);
                }
            }

            // if the max of our current frame range is beyond
            // what we know about, pad a few more frames
            if (localMax < globalMin)
            {
                for (double f = localMax; f < globalMin; f++)
                {
                    allFrameRange.insert(f);
                }
            }
        }

        // right now we just copy over the translation samples since
        // they are guaranteed to contain all the geometry samples
        allFrameRange.insert(transSamples.begin(), transSamples.end());

        // copy over the pre-roll samples
        allFrameRange.insert(preRollSamples.begin(), preRollSamples.end());
    }

    // add extra evaluation run up, if necessary
    if (startEvaluationTime != DBL_MAX && !allFrameRange.empty())
    {
        double firstFrame = *allFrameRange.begin();
        for (double f = startEvaluationTime; f < firstFrame; ++f)
        {
            allFrameRange.insert(f);
        }
    }

    std::set<double>::iterator it = allFrameRange.begin();
    std::set<double>::iterator itEnd = allFrameRange.end();

    MComputation computation;
    computation.beginComputation();

    // loop through every frame in the list, if a job has that frame in it's
    // list of transform or shape frames, then it will write out data and
    // call the perFrameCallback, if that frame is also the last one it has
    // to work on then it will also call the postCallback.
    // If it doesn't have this frame, then it does nothing
    for (; it != itEnd; it++)
    {
        if (verbose)
        {
            double frame = *it;
            MString info;
            info = frame;
            MGlobal::displayInfo(info);
        }

        MGlobal::viewFrame(*it);
        std::list< AbcWriteJobPtr >::iterator j = jobList.begin();
        std::list< AbcWriteJobPtr >::iterator jend = jobList.end();
        while (j != jend)
        {
            if (computation.isInterruptRequested())
                return MS::kFailure;

            bool lastFrame = (*j)->eval(*it);

            if (lastFrame)
            {
                j = jobList.erase(j);
            }
            else
                j++;
        }
    }
    computation.endComputation();

    // set the time back
    MGlobal::viewFrame(oldCurTime);

    return MS::kSuccess;
}
catch (Alembic::Util::Exception & e)
{
    MString theError("Alembic Exception encountered: ");
    theError += e.what();
    MGlobal::displayError(theError);
    return MS::kFailure;
}
catch (std::exception & e)
{
    MString theError("std::exception encountered: ");
    theError += e.what();
    MGlobal::displayError(theError);
    return MS::kFailure;
}

}
Beispiel #11
0
MStatus initializePlugin(
    MObject obj) {

    MStatus status;
    MFnPlugin plugin(obj, "Pixar", "1.0", "Any");


    // we use lambdas to pass in MCreatorFunctions into the various Maya registration
    // functions so that we can specify the static data that the registered
    // shape/data/node should be using.

    status = plugin.registerData(
            _data.stageData.typeName,
            _data.stageData.typeId,
            []() { 
                return UsdMayaStageData::creator(_data.stageData);
            });
    CHECK_MSTATUS(status);

    status = plugin.registerShape(
            _data.proxyShape.typeName,
            _data.proxyShape.typeId,
            []() {
                return UsdMayaProxyShape::creator(_data.proxyShape);  
            },
            []() {
                return UsdMayaProxyShape::initialize(
                    &(_data.proxyShape));
            },
            UsdMayaProxyShapeUI::creator,
            &UsdMayaProxyDrawOverride::sm_drawDbClassification);

    CHECK_MSTATUS(status);

    status = plugin.registerNode(
            _data.referenceAssembly.typeName,
            _data.referenceAssembly.typeId,
            []() {
                return UsdMayaReferenceAssembly::creator(
                    _data.referenceAssembly);
            },
            []() {
                return UsdMayaReferenceAssembly::initialize(
                    &(_data.referenceAssembly));
            },
        MPxNode::kAssembly,
        &UsdMayaReferenceAssembly::_classification);
    CHECK_MSTATUS(status);

    status =
	MHWRender::MDrawRegistry::registerDrawOverrideCreator(
	    UsdMayaProxyDrawOverride::sm_drawDbClassification,
            UsdMayaProxyDrawOverride::sm_drawRegistrantId,
            UsdMayaProxyDrawOverride::Creator);
    CHECK_MSTATUS(status);

    status = MGlobal::sourceFile("usdMaya.mel");
    CHECK_MSTATUS(status);

    // Set the label for the assembly node type so that it appears correctly
    // in the 'Create -> Scene Assembly' menu.
    const MString assemblyTypeLabel("UsdReferenceAssembly");
    MString setLabelCmd;
    status = setLabelCmd.format("assembly -e -type ^1s -label ^2s",
                                _data.referenceAssembly.typeName,
                                assemblyTypeLabel);
    CHECK_MSTATUS(status);
    status = MGlobal::executeCommand(setLabelCmd);
    CHECK_MSTATUS(status);

    // Procs stored in usdMaya.mel
    // Add assembly callbacks for accessing data without creating an MPxAssembly instance
    status = MGlobal::executeCommand("assembly -e -repTypeLabelProc usdMaya_UsdMayaReferenceAssembly_repTypeLabel -type " + _data.referenceAssembly.typeName);
    CHECK_MSTATUS(status);
    status = MGlobal::executeCommand("assembly -e -listRepTypesProc usdMaya_UsdMayaReferenceAssembly_listRepTypes -type " + _data.referenceAssembly.typeName);
    CHECK_MSTATUS(status);

    // Attribute Editor Templates
    // XXX: The try/except here is temporary until we change the Pixar-internal
    // package name to match the external package name.
    MString attribEditorCmd(
        "try:\n"
        "    from pxr.UsdMaya import AEpxrUsdReferenceAssemblyTemplate\n"
        "except ImportError:\n"
        "    from pixar.UsdMaya import AEpxrUsdReferenceAssemblyTemplate\n"
        "AEpxrUsdReferenceAssemblyTemplate.addMelFunctionStubs()");
    status = MGlobal::executePythonCommand(attribEditorCmd);
    CHECK_MSTATUS(status);

    status = plugin.registerCommand("usdExport", 
            usdExport::creator,
            usdExport::createSyntax );
    if (!status) {
        status.perror("registerCommand usdExport");
    }

    status = plugin.registerCommand("usdImport",
            []() { 
                return usdImport::creator(_data.referenceAssembly.typeName.asChar(),
                                          _data.proxyShape.typeName.asChar());
            }, 
            usdImport::createSyntax );

    if (!status) {
        status.perror("registerCommand usdImport");
    }

    status = plugin.registerCommand("usdListShadingModes",
                                    usdListShadingModes::creator,
                                    usdListShadingModes::createSyntax);

    if (!status) {
        status.perror("registerCommand usdListShadingModes");
    }
    
    status = plugin.registerFileTranslator("pxrUsdImport", 
                                    "", 
                                    []() { 
                                        return usdTranslatorImport::creator(
                                            _data.referenceAssembly.typeName.asChar(),
                                            _data.proxyShape.typeName.asChar());
                                    }, 
                                    "usdTranslatorImport", // options script name
                                    const_cast<char*>(usdTranslatorImportDefaults), 
                                    false);

    if (!status) {
        status.perror("pxrUsd: unable to register USD Import translator.");
    }
    
    status = plugin.registerFileTranslator("pxrUsdExport", 
                                    "", 
                                    usdTranslatorExport::creator,
                                    "usdTranslatorExport", // options script name
                                    const_cast<char*>(usdTranslatorExportDefaults), 
                                    true);

    if (!status) {
        status.perror("pxrUsd: unable to register USD Export translator.");
    }

    return status;
}
void MayaTransformWriter::write()
{
	size_t numSamples = mAnimChanList.size();
	if (numSamples > 0)
	{
		std::vector < AnimChan >::iterator it, itEnd;

		for (it = mAnimChanList.begin(), itEnd = mAnimChanList.end();
			it != itEnd; ++it)
		{
			double val = it->asDouble();

			if (it->scale == -std::numeric_limits<double>::infinity())
				val = util::inverseScale(val);
			else if (it->scale != 1.0)
				val *= it->scale;

			mSample[it->opNum].setChannelValue(it->channelNum, val);
		}

		if (!mInheritsPlug.isNull())
		{
			mSample.setInheritsXforms(mInheritsPlug.asBool());
		}

		if (mFilterEulerRotations)
		{
			double xx(0), yy(0), zz(0);

			if (getSampledRotation(mSample, mJointOrientOpIndex, xx, yy, zz))
			{
				MEulerRotation filteredEuler(xx, yy, zz, mPrevJointOrientSolution.order);
				filteredEuler.setToClosestSolution(mPrevJointOrientSolution);

				// update sample with new solution
				setSampledRotation(mSample, mJointOrientOpIndex, filteredEuler.x, filteredEuler.y, filteredEuler.z);
				mPrevJointOrientSolution = filteredEuler;
			}

			if (getSampledRotation(mSample, mRotateOpIndex, xx, yy, zz))
			{
				MEulerRotation filteredEuler(xx, yy, zz, mPrevRotateSolution.order);
				filteredEuler.setToClosestSolution(mPrevRotateSolution);

#ifdef _DEBUG
				if (mVerbose)
				{
					MString str;
					MStringArray args(7,"");

					unsigned int i = 0;

					i=0;
					args[i++] = mName;
					args[i++].set(mPrevRotateSolution[0]);
					args[i++].set(mPrevRotateSolution[1]);
					args[i++].set(mPrevRotateSolution[2]);

					args[i++].set(Alembic::AbcGeom::RadiansToDegrees(mPrevRotateSolution[0]));
					args[i++].set(Alembic::AbcGeom::RadiansToDegrees(mPrevRotateSolution[1]));
					args[i++].set(Alembic::AbcGeom::RadiansToDegrees(mPrevRotateSolution[2]));

					str.format("^1s: previous rotation radians(^2s, ^3s, ^4s) degrees(^5s, ^6s, ^7s)",args);
					MGlobal::displayInfo( str );

					MEulerRotation currentEuler(xx, yy, zz, mPrevRotateSolution.order);

					i=0;
					args[i++] = mName;
					args[i++].set(currentEuler[0]);
					args[i++].set(currentEuler[1]);
					args[i++].set(currentEuler[2]);

					args[i++].set(Alembic::AbcGeom::RadiansToDegrees(currentEuler[0]));
					args[i++].set(Alembic::AbcGeom::RadiansToDegrees(currentEuler[1]));
					args[i++].set(Alembic::AbcGeom::RadiansToDegrees(currentEuler[2]));

					str.format("^1s: current rotation radians(^2s, ^3s, ^4s) degrees(^5s, ^6s, ^7s)",args);
					MGlobal::displayInfo( str );

					i=0;
					args[i++] = mName;
					args[i++].set(filteredEuler[0]);
					args[i++].set(filteredEuler[1]);
					args[i++].set(filteredEuler[2]);

					args[i++].set(Alembic::AbcGeom::RadiansToDegrees(filteredEuler[0]));
					args[i++].set(Alembic::AbcGeom::RadiansToDegrees(filteredEuler[1]));
					args[i++].set(Alembic::AbcGeom::RadiansToDegrees(filteredEuler[2]));

					str.format("^1s: filtered rotation radians(^2s, ^3s, ^4s) degrees(^5s, ^6s, ^7s)",args);
					MGlobal::displayInfo( str );

				}
#endif
				// update sample with new solution
				setSampledRotation(mSample, mRotateOpIndex, filteredEuler.x, filteredEuler.y, filteredEuler.z);
				mPrevRotateSolution = filteredEuler;
			}

			if (getSampledRotation(mSample, mRotateAxisOpIndex, xx, yy, zz))
			{
				MEulerRotation filteredEuler(xx, yy, zz, mPrevRotateAxisSolution.order);
				filteredEuler.setToClosestSolution(mPrevRotateAxisSolution);

				// update sample with new solution
				setSampledRotation(mSample, mRotateAxisOpIndex, filteredEuler.x, filteredEuler.y, filteredEuler.z);
				mPrevRotateAxisSolution = filteredEuler;
			}
		}

		mSchema.set(mSample);
	}
}
MStatus AdskSceneMetadataCmd::setMetadata( MString scenePath )
{
    // This string gets populated with errors by the Metadata library when they occur
    std::string errors;

    // Retrieve the accessor
    std::auto_ptr< Accessor > accessor( getAccessorForScene( scenePath ) );
    if ( NULL == accessor.get() )
    {
        setResult( false );
        return MS::kFailure;
    }

    // Retrieve the accessor
    Associations associations;
    if ( MS::kSuccess != getSceneAssociations(*(accessor.get()), associations) )
    {
        setResult( false );
        return MS::kFailure;
    }

    // Is our structure registered yet?
    Structure *structure = NULL;
    for ( Structure::ListIterator itrStructList = Structure::allStructures().begin(); itrStructList != Structure::allStructures().end(); ++itrStructList )
    {
        if ( std::string((*itrStructList)->name()) == std::string(gStructureName) )
        {
            structure = *itrStructList;
            break;
        }
    }

    if ( NULL == structure )
    {
        // Register our structure since it is not registered yet.
        structure = Structure::create();
        structure->setName( gStructureName );
        structure->addMember( Member::kString, 1, gMemberName );

        Structure::registerStructure( *structure );
    }

    // Make sure our structure is known by the accessor
    const Accessor::StructureSet &accessorStructures = accessor->structures();
    if ( accessorStructures.find( structure ) == accessorStructures.end() )
    {
        // Build a new structure set from the existing one
        Accessor::StructureSet updatedStructures = accessorStructures;

        // Add our structure to it
        updatedStructures.insert( structure );

        // Assign the new structure set
        accessor->setStructures( updatedStructures );
    }

    // Retrieve or create the specified channel
    std::string channelName( fChannelName.arg().asChar() );
    Channel channel = associations.channel( channelName );

    // Create the stream
    Stream stream( *structure, std::string( gStreamName ) );

    // Set the stream in the channel
    channel.setDataStream( stream );

    // Create an handle to the data itself
    Handle handle( *structure );

    // Set our string
    std::string dataString( fData.arg().asChar() );
    if ( 0 != handle.fromStr( dataString, 0, errors ) )
    {
        MStatus resStatus;
        MString errorString = MStringResource::getString( rSetDataOnChannelError, resStatus );
        errorString.format( errorString, fChannelName.arg(), errors.c_str() );
        displayError( errorString );

        setResult( false );
        return MS::kFailure;
    }

    // Set the handle in the stream
    stream.setElement( 0, handle );

    // Write the new scene file metadata
    if ( !accessor->write( errors ) )
    {
        MStatus resStatus;
        MString errorString = MStringResource::getString( rWriteMetadataError, resStatus );
        displayError( errorString );

        setResult( false );
        return MS::kFailure;
    }

    // true is success;
    setResult( true );
    return MS::kSuccess;
}
MStatus AdskSceneMetadataCmd::getMetadata( MString scenePath )
{
    // This string gets populated with errors by the Metadata library when they occur
    std::string errors;

    // Retrieve the accessor
    std::auto_ptr< Accessor > accessor( getAccessorForScene( scenePath ) );
    if ( NULL == accessor.get() )
    {
        return MS::kFailure;
    }

    // Retrieve the scene associations
    Associations associations;
    if ( MS::kSuccess != getSceneAssociations(*(accessor.get()), associations) )
    {
        return MS::kFailure;
    }

    // Look for the specified channel
    std::string channelName( fChannelName.arg().asChar() );
    Channel *channel = associations.findChannel( channelName );
    if ( NULL == channel )
    {
        // The specified channel was not found in the metadata. 
        // There is simply no metadata of interest in that scene file
        setResult( "" );
        return MS::kSuccess;
    }

    // There should only be one stream in our metadata. Make sure there is at least one
    if ( 0 == channel->dataStreamCount() )
    {
        MStatus resStatus;
        MString errorString = MStringResource::getString( rMissingStreamInChannelError, resStatus );
        errorString.format( errorString, fChannelName.arg() );
        displayError( errorString );
        return MS::kFailure;
    }

    Stream *stream = channel->dataStream( 0 );

    // There should only be one element in the stream. Make sure there is at least one
    if ( 0 == stream->elementCount() )
    {
        MStatus resStatus;
        MString errorString = MStringResource::getString( rMissingElementInStreamError, resStatus );
        errorString.format( errorString, fChannelName.arg() );
        displayError( errorString );
        return MS::kFailure;
    }

    Handle handle = stream->element( 0 );

    // Position the handle on our data of interest
    if ( false == handle.setPositionByMemberName( gMemberName ) )
    {
        MStatus resStatus;
        MString errorString = MStringResource::getString( rMissingMemberInElementError, resStatus );
        errorString.format( errorString, gMemberName, fChannelName.arg() );
        displayError( errorString );
        return MS::kFailure;
    }

    if ( Member::kString != handle.dataType() )
    {
        MStatus resStatus;
        MString errorString = MStringResource::getString( rInvalidMemberDataTypeError, resStatus );
        errorString.format( errorString, fChannelName.arg() );
        displayError( errorString );
        return MS::kFailure;
    }

    char **strings = handle.asString();

    setResult( strings[0] );
    return MS::kSuccess;
}
MayaMeshWriter::MayaMeshWriter(MDagPath & iDag,
    Alembic::Abc::OObject & iParent, Alembic::Util::uint32_t iTimeIndex,
    const JobArgs & iArgs, GetMembersMap& gmMap, util::InstanceRecorder& instanceRecorder)
  : mNoNormals(iArgs.noNormals),
    mWriteUVs(iArgs.writeUVs),
    mWriteColorSets(iArgs.writeColorSets),
    mIsGeometryAnimated(false),
    mDagPath(iDag)
{
    MStatus status = MS::kSuccess;
    MFnMesh lMesh( mDagPath, &status );
    if ( !status )
    {
        MGlobal::displayError( "MFnMesh() failed for MayaMeshWriter" );
    }

    // intermediate objects aren't translated
    MObject surface = iDag.node();

    if (iTimeIndex != 0 && util::isAnimated(surface))
        mIsGeometryAnimated = true;

    std::vector<float> uvs;
    std::vector<Alembic::Util::uint32_t> indices;

    MString name = lMesh.name();
    name = util::stripNamespaces(name, iArgs.stripNamespace);

    // check to see if this poly has been tagged as a SubD
    MPlug plug = lMesh.findPlug("SubDivisionMesh");
    if ( !plug.isNull() && plug.asBool() )
    {
        Alembic::AbcGeom::OSubD obj(iParent, name.asChar(), iTimeIndex);

        instanceRecorder.recordMaster(iDag,obj);

        mSubDSchema = obj.getSchema();

        Alembic::AbcGeom::OV2fGeomParam::Sample uvSamp;
        if ( mWriteUVs )
        {
            getUVs(uvs, indices);

            if (!uvs.empty())
            {
                uvSamp.setScope( Alembic::AbcGeom::kFacevaryingScope );
                uvSamp.setVals(Alembic::AbcGeom::V2fArraySample(
                    (const Imath::V2f *) &uvs.front(), uvs.size() / 2));
                if (!indices.empty())
                {
                    uvSamp.setIndices(Alembic::Abc::UInt32ArraySample(
                        &indices.front(), indices.size()));
                }
            }
        }

        Alembic::Abc::OCompoundProperty cp;
        Alembic::Abc::OCompoundProperty up;
        if (AttributesWriter::hasAnyAttr(lMesh, iArgs))
        {
            cp = mSubDSchema.getArbGeomParams();
            up = mSubDSchema.getUserProperties();
        }
        mAttrs = AttributesWriterPtr(new AttributesWriter(cp, up, obj, lMesh,
            iTimeIndex, iArgs));

        writeSubD(uvSamp);
    }
    else
    {
        Alembic::AbcGeom::OPolyMesh obj(iParent, name.asChar(), iTimeIndex);
        instanceRecorder.recordMaster(iDag,obj);

        mPolySchema = obj.getSchema();

        Alembic::AbcGeom::OV2fGeomParam::Sample uvSamp;

        if ( mWriteUVs )
        {
            getUVs(uvs, indices);

            if (!uvs.empty())
            {

                uvSamp.setScope( Alembic::AbcGeom::kFacevaryingScope );
                uvSamp.setVals(Alembic::AbcGeom::V2fArraySample(
                    (const Imath::V2f *) &uvs.front(), uvs.size() / 2));
                if (!indices.empty())
                {
                    uvSamp.setIndices(Alembic::Abc::UInt32ArraySample(
                        &indices.front(), indices.size()));
                }
            }
        }

        Alembic::Abc::OCompoundProperty cp;
        Alembic::Abc::OCompoundProperty up;
        if (AttributesWriter::hasAnyAttr(lMesh, iArgs))
        {
            cp = mPolySchema.getArbGeomParams();
            up = mPolySchema.getUserProperties();
        }

        // set the rest of the props and write to the writer node
        mAttrs = AttributesWriterPtr(new AttributesWriter(cp, up, obj, lMesh,
            iTimeIndex, iArgs));

        writePoly(uvSamp);
    }

    if (mWriteColorSets)
    {
        MStringArray colorSetNames;
        lMesh.getColorSetNames(colorSetNames);

        if (colorSetNames.length() > 0)
        {

            // Create the color sets compound prop
            Alembic::Abc::OCompoundProperty arbParams;
            if (mPolySchema)
            {
                arbParams =  mPolySchema.getArbGeomParams();
            }
            else
            {
                arbParams =  mSubDSchema.getArbGeomParams();
            }

            std::string currentColorSet = lMesh.currentColorSetName().asChar();
            for (unsigned int i=0; i < colorSetNames.length(); ++i)
            {
                // Create an array property for each color set
                std::string colorSetPropName = colorSetNames[i].asChar();

                Alembic::AbcCoreAbstract::MetaData md;
                if (currentColorSet == colorSetPropName)
                {
                    md.set("mayaColorSet", "1");
                }
                else
                {
                    md.set("mayaColorSet", "0");
                }

                if (lMesh.getColorRepresentation(colorSetNames[i]) ==
                    MFnMesh::kRGB)
                {
                    Alembic::AbcGeom::OC3fGeomParam colorProp(arbParams,
                        colorSetPropName, true,
                        Alembic::AbcGeom::kFacevaryingScope, 1, iTimeIndex, md);
                    mRGBParams.push_back(colorProp);
                }
                else
                {
                    Alembic::AbcGeom::OC4fGeomParam colorProp(arbParams,
                        colorSetPropName, true,
                        Alembic::AbcGeom::kFacevaryingScope, 1, iTimeIndex, md);
                    mRGBAParams.push_back(colorProp);
                }
            }
            writeColor();
        }
    }

    // write out facesets
    if(!iArgs.writeFaceSets)
        return;

    // get the connected shading engines
    MObjectArray connSGObjs (getOutConnectedSG(mDagPath));
    const unsigned int sgCount = connSGObjs.length();

    for (unsigned int i = 0; i < sgCount; ++i)
    {
        MObject connSGObj, compObj;

        connSGObj = connSGObjs[i];

        MFnDependencyNode fnDepNode(connSGObj);
        MString connSgObjName = fnDepNode.name();

        // retrive the component MObject
        status = getSetComponents(mDagPath, connSGObj, gmMap, compObj);

        if (status != MS::kSuccess)
        {
            MFnDependencyNode fnDepNode(connSGObj);
            MString message;
            message.format("Could not retrive face indices from set ^1s.",  connSgObjName);
            MGlobal::displayError(message);
            continue;
        }

        // retrieve the face indices
        MIntArray indices;
        MFnSingleIndexedComponent compFn;
        compFn.setObject(compObj);
        compFn.getElements(indices);
        const unsigned int numData = indices.length();

        // encountered the whole object mapping. skip it.
        if (numData == 0)
            continue;

        std::vector<Alembic::Util::int32_t> faceIndices(numData);
        for (unsigned int j = 0; j < numData; ++j)
        {
            faceIndices[j] = indices[j];
        }

        connSgObjName = util::stripNamespaces(connSgObjName,
                                              iArgs.stripNamespace);

        Alembic::AbcGeom::OFaceSet faceSet;
        std::string faceSetName(connSgObjName.asChar());

        if (mPolySchema)
        {
            if (mPolySchema.hasFaceSet(faceSetName))
            {
                faceSet = mPolySchema.getFaceSet(faceSetName);
            }
            else
            {
                faceSet = mPolySchema.createFaceSet(faceSetName);
            }
        }
        else
        {
            if (mSubDSchema.hasFaceSet(faceSetName))
            {
                faceSet = mSubDSchema.getFaceSet(faceSetName);
            }
            else
            {
                faceSet = mSubDSchema.createFaceSet(faceSetName);
            }
        }
        Alembic::AbcGeom::OFaceSetSchema::Sample samp;
        samp.setFaces(Alembic::Abc::Int32ArraySample(faceIndices));

        Alembic::AbcGeom::OFaceSetSchema faceSetSchema = faceSet.getSchema();

        faceSetSchema.set(samp);
        faceSetSchema.setFaceExclusivity(Alembic::AbcGeom::kFaceSetExclusive);

        MFnDependencyNode iNode(connSGObj);

        Alembic::Abc::OCompoundProperty cp;
        Alembic::Abc::OCompoundProperty up;
        if (AttributesWriter::hasAnyAttr(iNode, iArgs))
        {
            cp = faceSetSchema.getArbGeomParams();
            up = faceSetSchema.getUserProperties();
        }

        AttributesWriter attrWriter(cp, up, faceSet, iNode, iTimeIndex, iArgs);
        attrWriter.write();
    }
}
MStatus closestPointOnCurveCommand::redoIt()

{

   // DOUBLE-CHECK TO MAKE SURE THERE'S A SPECIFIED OBJECT TO EVALUATE ON:

   if (sList.length() == 0)

   {
	   MStatus stat;
	   MString msg = MStringResource::getString(kNoValidObject, stat);
       displayError(msg);
       return MStatus::kFailure;
   }



   // RETRIEVE THE SPECIFIED OBJECT AS A DAGPATH:

   MDagPath curveDagPath;
   sList.getDagPath(0, curveDagPath);


   // CHECK FOR INVALID NODE-TYPE INPUT WHEN SPECIFIED/SELECTED NODE IS *NOT* A "CURVE" NOR "CURVE TRANSFORM":

   if (!curveDagPath.node().hasFn(MFn::kNurbsCurve) && !(curveDagPath.node().hasFn(MFn::kTransform) && curveDagPath.hasFn(MFn::kNurbsCurve)))

   {
	   MStatus stat;
	   MString msg; 
	   // Use format to place variable string into message
	   MString msgFmt = MStringResource::getString(kInvalidType, stat);
	   MStringArray selectionStrings;
	   sList.getSelectionStrings(0, selectionStrings);
	   msg.format(msgFmt, selectionStrings[0]);
	   displayError(msg);
       return MStatus::kFailure;
   }



   // WHEN COMMAND *NOT* IN "QUERY MODE" (I.E. "CREATION MODE"), CREATE AND CONNECT A "closestPointOnCurve" NODE AND RETURN ITS NODE NAME:

   if (!queryFlagSet)

   {

      // CREATE THE NODE:

      MFnDependencyNode depNodeFn;

      if (closestPointOnCurveNodeName == "")

         depNodeFn.create("closestPointOnCurve");

      else

         depNodeFn.create("closestPointOnCurve", closestPointOnCurveNodeName);

      closestPointOnCurveNodeName = depNodeFn.name();



      // SET THE ".inPosition" ATTRIBUTE, IF SPECIFIED IN THE COMMAND:

      if (inPositionFlagSet)

      {

         MPlug inPositionXPlug = depNodeFn.findPlug("inPositionX");

         inPositionXPlug.setValue(inPosition.x);

         MPlug inPositionYPlug = depNodeFn.findPlug("inPositionY");

         inPositionYPlug.setValue(inPosition.y);

         MPlug inPositionZPlug = depNodeFn.findPlug("inPositionZ");

         inPositionZPlug.setValue(inPosition.z);

      }



      // MAKE SOME ADJUSTMENTS WHEN THE SPECIFIED NODE IS A "TRANSFORM" OF A CURVE SHAPE:

      unsigned instanceNumber=0;

      if (curveDagPath.node().hasFn(MFn::kTransform))

      {

         // EXTEND THE DAGPATH TO ITS CURVE "SHAPE" NODE:

         curveDagPath.extendToShape();



         // TRANSFORMS ARE *NOT* NECESSARILY THE "FIRST" INSTANCE TRANSFORM OF A CURVE SHAPE:

         instanceNumber = curveDagPath.instanceNumber();

      }



      // CONNECT THE NODES:

      MPlug worldCurvePlug, inCurvePlug;

      inCurvePlug = depNodeFn.findPlug("inCurve");

      depNodeFn.setObject(curveDagPath.node());

      worldCurvePlug = depNodeFn.findPlug("worldSpace");

      worldCurvePlug = worldCurvePlug.elementByLogicalIndex(instanceNumber);

      MDGModifier dgModifier;

      dgModifier.connect(worldCurvePlug, inCurvePlug);

      dgModifier.doIt();



      // SET COMMAND RESULT TO BE NEW NODE'S NAME, AND RETURN:

      setResult(closestPointOnCurveNodeName);

      return MStatus::kSuccess;

   }

   // OTHERWISE, WE'RE IN THE COMMAND'S "QUERY MODE":

   else

   {

      // COMPUTE THE CLOSEST POSITION, NORMAL, TANGENT, PARAMETER-U AND DISTANCE, USING THE *FIRST* INSTANCE TRANSFORM WHEN CURVE IS SPECIFIED AS A "SHAPE":

      MPoint position;

      MVector normal, tangent;

      double paramU, distance;

      closestTangentUAndDistance(curveDagPath, inPosition, position, normal, tangent, paramU, distance);



      // WHEN NO QUERYABLE FLAG IS SPECIFIED, INDICATE AN ERROR:

      if (!positionFlagSet && !normalFlagSet && !tangentFlagSet && !paramUFlagSet && !distanceFlagSet)

      {
		  MStatus stat;
		  MString msg = MStringResource::getString(kNoQueryFlag, stat);
		  displayError(msg);
          return MStatus::kFailure;
     }

      // WHEN JUST THE "DISTANCE" IS QUERIED, RETURN A SINGLE "FLOAT" INSTEAD OF AN ENTIRE FLOAT ARRAY FROM THE COMMAND:

      else if (distanceFlagSet && !(positionFlagSet || normalFlagSet || tangentFlagSet || paramUFlagSet))

         setResult(distance);

      // WHEN JUST THE "PARAMETER-U" IS QUERIED, RETURN A SINGLE "FLOAT" INSTEAD OF AN ENTIRE FLOAT ARRAY FROM THE COMMAND:

      else if (paramUFlagSet && !(positionFlagSet || normalFlagSet || tangentFlagSet || distanceFlagSet))

         setResult(paramU);

      // OTHERWISE, SET THE RETURN VALUE OF THE COMMAND'S RESULT TO A "COMPOSITE ARRAY OF FLOATS":

      else

      {

         // HOLDS FLOAT ARRAY RESULT:

         MDoubleArray floatArrayResult;



         // APPEND THE RESULTS OF THE CLOSEST POSITION, NORMAL, TANGENT, PARAMETER-U AND DISTANCE VALUES TO THE FLOAT ARRAY RESULT:

         if (positionFlagSet)

         {

            floatArrayResult.append(position.x);

            floatArrayResult.append(position.y);

            floatArrayResult.append(position.z);

         }

         if (normalFlagSet)

         {

            floatArrayResult.append(normal.x);

            floatArrayResult.append(normal.y);

            floatArrayResult.append(normal.z);

         }

         if (tangentFlagSet)

         {

            floatArrayResult.append(tangent.x);

            floatArrayResult.append(tangent.y);

            floatArrayResult.append(tangent.z);

         }

         if (paramUFlagSet)

            floatArrayResult.append(paramU);

         if (distanceFlagSet)

            floatArrayResult.append(distance);



         // FINALLY, SET THE COMMAND'S RESULT:

         setResult(floatArrayResult);

      }



      return MStatus::kSuccess;

   }

}