Exemple #1
0
MStatus setupRGBShaders::undoIt()
{
    for( int u = 0; u < undoLevels; u++ )
        dgMod.undoIt();

    return MS::kSuccess;
}
bool ToMayaSkinClusterConverter::doConversion( IECore::ConstObjectPtr from, MObject &to, IECore::ConstCompoundObjectPtr operands ) const
{
    MStatus s;

    IECore::ConstSmoothSkinningDataPtr skinningData = IECore::runTimeCast<const IECore::SmoothSkinningData>( from );
    assert( skinningData );

    const std::vector<std::string> &influenceNames = skinningData->influenceNames()->readable();
    const std::vector<Imath::M44f> &influencePoseData  = skinningData->influencePose()->readable();
    const std::vector<int> &pointIndexOffsets  = skinningData->pointIndexOffsets()->readable();
    const std::vector<int> &pointInfluenceCounts = skinningData->pointInfluenceCounts()->readable();
    const std::vector<int> &pointInfluenceIndices = skinningData->pointInfluenceIndices()->readable();
    const std::vector<float> &pointInfluenceWeights = skinningData->pointInfluenceWeights()->readable();

    MFnDependencyNode fnSkinClusterNode( to, &s );
    MFnSkinCluster fnSkinCluster( to, &s );
    if ( s != MS::kSuccess )
    {
        /// \todo: optional parameter to allow custom node types and checks for the necessary attributes
        /// \todo: create a new skinCluster if we want a kSkinClusterFilter and this isn't one
        throw IECore::Exception( ( boost::format( "ToMayaSkinClusterConverter: \"%s\" is not a valid skinCluster" ) % fnSkinClusterNode.name() ).str() );
    }

    const unsigned origNumInfluences = influenceNames.size();
    unsigned numInfluences = origNumInfluences;
    std::vector<bool> ignoreInfluence( origNumInfluences, false );
    std::vector<int> indexMap( origNumInfluences, -1 );
    const bool ignoreMissingInfluences = m_ignoreMissingInfluencesParameter->getTypedValue();
    const bool ignoreBindPose = m_ignoreBindPoseParameter->getTypedValue();

    // gather the influence objects
    MObject mObj;
    MDagPath path;
    MSelectionList influenceList;
    MDagPathArray influencePaths;
    for ( unsigned i=0, index=0; i < origNumInfluences; i++ )
    {
        MString influenceName( influenceNames[i].c_str() );
        s = influenceList.add( influenceName );
        if ( !s )
        {
            if ( ignoreMissingInfluences )
            {
                ignoreInfluence[i] = true;
                MGlobal::displayWarning( MString( "ToMayaSkinClusterConverter: \"" + influenceName + "\" is not a valid influence" ) );
                continue;
            }

            throw IECore::Exception( ( boost::format( "ToMayaSkinClusterConverter: \"%s\" is not a valid influence" ) % influenceName ).str() );
        }

        influenceList.getDependNode( index, mObj );
        MFnIkJoint fnInfluence( mObj, &s );
        if ( !s )
        {
            if ( ignoreMissingInfluences )
            {
                ignoreInfluence[i] = true;
                influenceList.remove( index );
                MGlobal::displayWarning( MString( "ToMayaSkinClusterConverter: \"" + influenceName + "\" is not a valid influence" ) );
                continue;
            }

            throw IECore::Exception( ( boost::format( "ToMayaSkinClusterConverter: \"%s\" is not a valid influence" ) % influenceName ).str() );
        }

        fnInfluence.getPath( path );
        influencePaths.append( path );
        indexMap[i] = index;
        index++;
    }

    MPlugArray connectedPlugs;

    bool existingBindPose = true;
    MPlug bindPlug = fnSkinClusterNode.findPlug( "bindPose", true, &s );
    if ( !bindPlug.connectedTo( connectedPlugs, true, false ) )
    {
        existingBindPose = false;
        if ( !ignoreBindPose )
        {
            throw IECore::Exception( ( boost::format( "ToMayaSkinClusterConverter: \"%s\" does not have a valid bindPose" ) % fnSkinClusterNode.name() ).str() );
        }
    }

    MPlug bindPoseMatrixArrayPlug;
    MPlug bindPoseMemberArrayPlug;
    if ( existingBindPose )
    {
        MFnDependencyNode fnBindPose( connectedPlugs[0].node() );
        if ( fnBindPose.typeName() != "dagPose" )
        {
            throw IECore::Exception( ( boost::format( "ToMayaSkinClusterConverter: \"%s\" is not a valid bindPose" ) % fnBindPose.name() ).str() );
        }

        bindPoseMatrixArrayPlug = fnBindPose.findPlug( "worldMatrix", true, &s );
        bindPoseMemberArrayPlug = fnBindPose.findPlug( "members", true, &s );
    }

    /// \todo: optional parameter to reset the skinCluster's geomMatrix plug

    // break existing influence connections to the skinCluster
    MDGModifier dgModifier;
    MMatrixArray ignoredPreMatrices;
    MPlug matrixArrayPlug = fnSkinClusterNode.findPlug( "matrix", true, &s );
    MPlug bindPreMatrixArrayPlug = fnSkinClusterNode.findPlug( "bindPreMatrix", true, &s );
    for ( unsigned i=0; i < matrixArrayPlug.numConnectedElements(); i++ )
    {
        MPlug matrixPlug = matrixArrayPlug.connectionByPhysicalIndex( i, &s );
        matrixPlug.connectedTo( connectedPlugs, true, false );
        if ( !connectedPlugs.length() )
        {
            continue;
        }

        MFnIkJoint fnInfluence( connectedPlugs[0].node() );
        fnInfluence.getPath( path );
        if ( ignoreMissingInfluences && !influenceList.hasItem( path ) )
        {
            MPlug preMatrixPlug = bindPreMatrixArrayPlug.elementByLogicalIndex( i );
            preMatrixPlug.getValue( mObj );
            MFnMatrixData matFn( mObj );
            ignoredPreMatrices.append( matFn.matrix() );
            ignoreInfluence.push_back( false );
            indexMap.push_back( influenceList.length() );
            influenceList.add( connectedPlugs[0].node() );
            numInfluences++;
        }
        dgModifier.disconnect( connectedPlugs[0], matrixPlug );
    }
    MPlug lockArrayPlug = fnSkinClusterNode.findPlug( "lockWeights", true, &s );
    for ( unsigned i=0; i < lockArrayPlug.numConnectedElements(); i++ )
    {
        MPlug lockPlug = lockArrayPlug.connectionByPhysicalIndex( i, &s );
        lockPlug.connectedTo( connectedPlugs, true, false );
        if ( connectedPlugs.length() )
        {
            dgModifier.disconnect( connectedPlugs[0], lockPlug );
        }
    }
    MPlug paintPlug = fnSkinClusterNode.findPlug( "paintTrans", true, &s );
    paintPlug.connectedTo( connectedPlugs, true, false );
    if ( connectedPlugs.length() )
    {
        dgModifier.disconnect( connectedPlugs[0], paintPlug );
    }

    // break existing influence connections to the bind pose
    if ( existingBindPose )
    {
        for ( unsigned i=0; i < bindPoseMatrixArrayPlug.numConnectedElements(); i++ )
        {
            MPlug matrixPlug = bindPoseMatrixArrayPlug.connectionByPhysicalIndex( i, &s );
            matrixPlug.connectedTo( connectedPlugs, true, false );
            if ( connectedPlugs.length() )
            {
                dgModifier.disconnect( connectedPlugs[0], matrixPlug );
            }
        }
        for ( unsigned i=0; i < bindPoseMemberArrayPlug.numConnectedElements(); i++ )
        {
            MPlug memberPlug = bindPoseMemberArrayPlug.connectionByPhysicalIndex( i, &s );
            memberPlug.connectedTo( connectedPlugs, true, false );
            if ( connectedPlugs.length() )
            {
                dgModifier.disconnect( connectedPlugs[0], memberPlug );
            }
        }
    }

    if ( !dgModifier.doIt() )
    {
        dgModifier.undoIt();
        throw IECore::Exception( "ToMayaSkinClusterConverter: Unable to break the influence connections" );
    }

    // make connections from influences to skinCluster and bindPose
    for ( unsigned i=0; i < numInfluences; i++ )
    {
        if ( ignoreInfluence[i] )
        {
            continue;
        }

        int index = indexMap[i];
        s = influenceList.getDependNode( index, mObj );
        MFnIkJoint fnInfluence( mObj, &s );
        MPlug influenceMatrixPlug = fnInfluence.findPlug( "worldMatrix", true, &s ).elementByLogicalIndex( 0, &s );
        MPlug influenceMessagePlug = fnInfluence.findPlug( "message", true, &s );
        MPlug influenceBindPosePlug = fnInfluence.findPlug( "bindPose", true, &s );
        MPlug influenceLockPlug = fnInfluence.findPlug( "lockInfluenceWeights", true, &s );
        if ( !s )
        {
            // add the lockInfluenceWeights attribute if it doesn't exist
            MFnNumericAttribute nAttr;
            MObject attribute = nAttr.create( "lockInfluenceWeights", "liw", MFnNumericData::kBoolean, false );
            fnInfluence.addAttribute( attribute );
            influenceLockPlug = fnInfluence.findPlug( "lockInfluenceWeights", true, &s );
        }

        // connect influence to the skinCluster
        MPlug matrixPlug = matrixArrayPlug.elementByLogicalIndex( index );
        MPlug lockPlug = lockArrayPlug.elementByLogicalIndex( index );
        dgModifier.connect( influenceMatrixPlug, matrixPlug );
        dgModifier.connect( influenceLockPlug, lockPlug );

        // connect influence to the bindPose
        if ( !ignoreBindPose )
        {
            MPlug bindPoseMatrixPlug = bindPoseMatrixArrayPlug.elementByLogicalIndex( index );
            MPlug memberPlug = bindPoseMemberArrayPlug.elementByLogicalIndex( index );
            dgModifier.connect( influenceMessagePlug, bindPoseMatrixPlug );
            dgModifier.connect( influenceBindPosePlug, memberPlug );
        }
    }
    unsigned firstIndex = find( ignoreInfluence.begin(), ignoreInfluence.end(), false ) - ignoreInfluence.begin();
    influenceList.getDependNode( firstIndex, mObj );
    MFnDependencyNode fnInfluence( mObj );
    MPlug influenceMessagePlug = fnInfluence.findPlug( "message", true, &s );
    dgModifier.connect( influenceMessagePlug, paintPlug );
    if ( !dgModifier.doIt() )
    {
        dgModifier.undoIt();
        throw IECore::Exception( "ToMayaSkinClusterConverter: Unable to create the influence connections" );
    }

    // use influencePoseData as bindPreMatrix
    for ( unsigned i=0; i < numInfluences; i++ )
    {
        if ( ignoreInfluence[i] )
        {
            continue;
        }

        MMatrix preMatrix = ( i < origNumInfluences ) ? IECore::convert<MMatrix>( influencePoseData[i] ) : ignoredPreMatrices[i-origNumInfluences];
        MPlug preMatrixPlug = bindPreMatrixArrayPlug.elementByLogicalIndex( indexMap[i], &s );
        s = preMatrixPlug.getValue( mObj );
        if ( s )
        {
            MFnMatrixData matFn( mObj );
            matFn.set( preMatrix );
            mObj = matFn.object();
        }
        else
        {
            MFnMatrixData matFn;
            mObj = matFn.create( preMatrix );
        }

        preMatrixPlug.setValue( mObj );
    }

    // remove unneeded bindPreMatrix children
    unsigned existingElements = bindPreMatrixArrayPlug.numElements();
    for ( unsigned i=influenceList.length(); i < existingElements; i++ )
    {
        MPlug preMatrixPlug = bindPreMatrixArrayPlug.elementByLogicalIndex( i, &s );
        /// \todo: surely there is a way to accomplish this in c++...
        MGlobal::executeCommand( ( boost::format( "removeMultiInstance %s" ) % preMatrixPlug.name() ).str().c_str() );
    }

    // get the geometry
    MObjectArray outputGeoObjs;
    if ( !fnSkinCluster.getOutputGeometry( outputGeoObjs ) )
    {
        throw IECore::Exception( ( boost::format( "ToMayaSkinClusterConverter: skinCluster \"%s\" does not have any output geometry!" ) % fnSkinCluster.name() ).str() );
    }
    MFnDagNode dagFn( outputGeoObjs[0] );
    MDagPath geoPath;
    dagFn.getPath( geoPath );

    // loop through all the points of the geometry and set the weights
    MItGeometry geoIt( outputGeoObjs[0] );
    MPlug weightListArrayPlug = fnSkinClusterNode.findPlug( "weightList", true, &s );
    for ( unsigned pIndex=0; !geoIt.isDone(); geoIt.next(), pIndex++ )
    {
        MPlug pointWeightsPlug = weightListArrayPlug.elementByLogicalIndex( pIndex, &s ).child( 0 );

        // remove existing influence weight plugs
        MIntArray existingInfluenceIndices;
        pointWeightsPlug.getExistingArrayAttributeIndices( existingInfluenceIndices );
        for( unsigned i=0; i < existingInfluenceIndices.length(); i++ )
        {
            MPlug influenceWeightPlug = pointWeightsPlug.elementByLogicalIndex( existingInfluenceIndices[i], &s );
            MGlobal::executeCommand( ( boost::format( "removeMultiInstance -break 1 %s" ) % influenceWeightPlug.name() ).str().c_str() );
        }

        // add new influence weight plugs
        int firstIndex = pointIndexOffsets[pIndex];
        for( int i=0; i < pointInfluenceCounts[pIndex]; i++ )
        {
            int influenceIndex = pointInfluenceIndices[ firstIndex + i ];
            if ( ignoreInfluence[ influenceIndex ] )
            {
                continue;
            }

            int skinClusterInfluenceIndex = fnSkinCluster.indexForInfluenceObject( influencePaths[ indexMap[ influenceIndex ] ] );
            MPlug influenceWeightPlug = pointWeightsPlug.elementByLogicalIndex( skinClusterInfluenceIndex, &s );
            influenceWeightPlug.setValue( pointInfluenceWeights[ firstIndex + i ] );
        }
    }

    return true;
}
Exemple #3
0
MStatus createClip::undoIt()
{
	MStatus status = fMod.undoIt();
    return status;
}
Exemple #4
0
// --------------------------------------------------------------------------------------------
MStatus polyModifierCmd::processUpstreamNode( modifyPolyData& data )
// --------------------------------------------------------------------------------------------
{
	MStatus status = MS::kSuccess;

	// Declare our function sets - Although dagNodeFn derives from depNodeFn, we need
	//							   both since dagNodeFn can only refer to DAG objects.
	//							   We will use depNodeFn for all times other when dealing
	//							   with the DAG.
	//
	MFnDependencyNode	depNodeFn;
	MFnDagNode			dagNodeFn;

	// Use the selected node's plug connections to find the upstream plug.
	// Since we are looking at the selected node's inMesh attribute, it will
	// always have only one connection coming in if it has history, and none
	// otherwise.
	//
	// If there is no history, copy the selected node and place it ahead of the
	// modifierNode as the new upstream node so that the modifierNode has an
	// input mesh to operate on.
	//

	//save the meshDagPath for later use
	MDagPath::getAPathTo(data.meshNodeShape,myMeshPath);

	MPlugArray tempPlugArray;

 	if( fHasHistory )
	{
		// Since we have history, look for what connections exist on the
		// meshNode "inMesh" plug. "inMesh" plugs should only ever have one
		// connection.
		//
		data.meshNodeDestPlug.connectedTo( tempPlugArray, true, false);
		

		// ASSERT: Only one connection should exist on meshNodeShape.inMesh!
		//
		MStatusAssert( (tempPlugArray.length() == 1),
					   "tempPlugArray.length() == 1 -- 0 or >1 connections on meshNodeShape.inMesh" );
		data.upstreamNodeSrcPlug = tempPlugArray[0];

		
		// Construction history only deals with shapes, so we can grab the
		// upstreamNodeShape off of the source plug.
		//
		// Dieser Bereich muss bleiben, weil diese Attribute noch bentigt werden
		data.upstreamNodeShape = data.upstreamNodeSrcPlug.node();
		depNodeFn.setObject( data.upstreamNodeShape );
		data.upstreamNodeSrcAttr = data.upstreamNodeSrcPlug.attribute();
		

		// Disconnect the upstream node and the selected node, so we can
		// replace them with our own connections below.
		//
		MPlug	nodePlug(data.meshNodeShape,data.meshNodeDestAttr ) ;
		INVIS(cout<<data.upstreamNodeSrcPlug.name().asChar()<<" --|-- "<<nodePlug.name().asChar()<<endl);
		status =	fDGModifier.disconnect( data.upstreamNodeSrcPlug,
											nodePlug );
											
		
		MCheckStatus( status, "Disconnect Upstream mit meshNode" );


	}
	else	// No History (!fHasHistory)
	{
		// Use the DAG node function set to duplicate the shape of the meshNode.
		// The duplicate method will return an MObject handle to the transform
		// of the duplicated shape, so traverse the dag to locate the shape. Store
		// this duplicate shape as our "upstream" node to drive the input for the 
		// modifierNode.
		//
		depNodeFn.setObject( data.meshNodeShape );
		data.upstreamNodeTransform = createDuplicate.createNode("mesh");
		createDuplicate.doIt();

		dagNodeFn.setObject( data.upstreamNodeTransform );
		

		// Ensure that our upstreamNode is pointing to a shape.
		//
		MStatusAssert( (0 < dagNodeFn.childCount()),
					   "0 < dagNodeFn.childCount() -- Duplicate meshNode transform has no shape." );
		data.upstreamNodeShape = dagNodeFn.child(0);

		MPlug outMeshPlug = depNodeFn.findPlug("outMesh");
		depNodeFn.setObject(data.upstreamNodeShape);

		//jetzt inMesh upstreamNodeShape mit outMesh meshShape füllen
		MDGModifier tempMod;
		tempMod.connect(outMeshPlug,depNodeFn.findPlug("inMesh"));
		tempMod.doIt();

		//force DGEVAL
		MString cmd = "dgeval -src ";
		cmd += depNodeFn.name();
		cmd += ".outMesh";
		MGlobal::executeCommand(cmd,false,false);

		tempMod.undoIt();

		
		// Re-parent the upstreamNodeShape under our original transform
		//
		reparentDuplicate.reparentNode( data.upstreamNodeShape, data.meshNodeTransform );
		reparentDuplicate.doIt();


		deleteDuplicate.deleteNode( data.upstreamNodeTransform );
		deleteDuplicate.doIt();
		/*
		status = fDagModifier.reparentNode( data.upstreamNodeShape, data.meshNodeTransform );
		MCheckStatus( status, "reparentNode" );

		// Perform the DAG re-parenting
		// 
		// Note: This reparent must be performed before the deleteNode() is called.
		//		 See polyModifierCmd.h (see definition of fDagModifier) for more details.
		//
		status = fDagModifier.doIt();
		MCheckStatus( status, "fDagModifier.doIt()" );
		*/
		// Mark the upstreamNodeShape (the original shape) as an intermediate object
		// (making it invisible to the user)
		//
		dagNodeFn.setObject( data.upstreamNodeShape );
		dagNodeFn.setIntermediateObject( true );

		// Get the upstream node source attribute
		//
		data.upstreamNodeSrcAttr = dagNodeFn.attribute( "outMesh" );
		data.upstreamNodeSrcPlug = MPlug(data.upstreamNodeShape, data.upstreamNodeSrcAttr);

		/*
		// Remove the duplicated transform node (clean up)
		//
		status = fDagModifier.deleteNode( data.upstreamNodeTransform );
		MCheckStatus( status, "deleteNode" );

		// Perform the DAG delete node
		//
		// Note: This deleteNode must be performed after the reparentNode() method is
		//		 completed. See polyModifierCmd.h (see definition of fDagModifier) for
		//		 details.
		//
		status = fDagModifier.doIt();
		MCheckStatus( status, "fDagModifier.doIt()" );
		*/

		// Cache the DAG path to the duplicate shape
		//
		dagNodeFn.getPath( fDuplicateDagPath );

		//finally delete the tweaks to avoid double transformation
		deleteTweaks();
	}

	return status;
}
Exemple #5
0
// --------------------------------------------------------------------------------------------
MStatus polyModifierCmd::undoDirectModifier()
// --------------------------------------------------------------------------------------------
{
	MStatus status;

	MFnDependencyNode depNodeFn;
	MFnDagNode dagNodeFn;

	MObject meshNode = fDagPath.node();
	depNodeFn.setObject( meshNode );
	
	// For the case with tweaks, we cannot write the mesh directly back onto
	// the cachedInMesh, since the shape can have out of date information from the
	// cachedInMesh. Thus we temporarily create an duplicate mesh, place our
	// old mesh on the outMesh attribute of our duplicate mesh, connect the
	// duplicate mesh shape to the mesh shape, and force a DG evaluation.
	//
	// For the case without tweaks, we can simply write onto the outMesh, since
	// the shape relies solely on an outMesh when there is no history nor tweaks.
	//
	if( fHasTweaks )
	{
		// Retrieve the inMesh and name of our mesh node (for the DG eval)
		//
		depNodeFn.setObject( meshNode );
		MPlug meshNodeInMeshPlug = depNodeFn.findPlug( "inMesh", &status );
		MCheckStatus( status, "Could not retrieve inMesh" );
		MString meshNodeName = depNodeFn.name();

		// Duplicate our current mesh
		//
		dagNodeFn.setObject( meshNode );
		MObject dupMeshNode = dagNodeFn.duplicate();

		// The dagNodeFn::duplicate() returns a transform, but we need a shape
		// so retrieve the DAG path and extend it to the shape.
		//
		MDagPath dupMeshDagPath;
		MDagPath::getAPathTo( dupMeshNode, dupMeshDagPath );
		dupMeshDagPath.extendToShape();

		// Retrieve the outMesh of the duplicate mesh and set our mesh data back
		// on it.
		//
		depNodeFn.setObject( dupMeshDagPath.node() );
		MPlug dupMeshNodeOutMeshPlug = depNodeFn.findPlug( "outMesh", &status );
		MCheckStatus( status, "Could not retrieve outMesh" );
		status = dupMeshNodeOutMeshPlug.setValue( fMeshData );

		// Temporarily connect the duplicate mesh node to our mesh node
		//
		MDGModifier dgModifier;
		dgModifier.connect( dupMeshNodeOutMeshPlug, meshNodeInMeshPlug );
		status = dgModifier.doIt();
		MCheckStatus( status, "Could not connect dupMeshNode -> meshNode" );

		// Need to force a DG evaluation now that the input has been changed.
		//
		MString cmd("dgeval -src ");
		cmd += meshNodeName;
		cmd += ".inMesh";
		status = MGlobal::executeCommand( cmd, false, false );
		MCheckStatus( status, "Could not force DG eval" );

		// Disconnect and delete the duplicate mesh node now
		//
		dgModifier.undoIt();
		MGlobal::deleteNode( dupMeshNode );

		// Restore the tweaks on the mesh
		//
		status = undoTweakProcessing();
	}
	else
	{
		// Restore the original mesh by writing the old mesh data (fMeshData) back
		// onto the outMesh of our meshNode
		//
		depNodeFn.setObject( meshNode );
		MPlug meshNodeOutMeshPlug = depNodeFn.findPlug( "outMesh", &status );
		MCheckStatus( status, "Could not retrieve outMesh" );
		status = meshNodeOutMeshPlug.setValue( fMeshData );
		MCheckStatus( status, "Could not set meshData" );
	}

	return status;
}
Exemple #6
0
// --------------------------------------------------------------------------------------------
MStatus polyModifierCmd::undoCachedMesh()
// --------------------------------------------------------------------------------------------
{
	MStatus status;

	// Only need to restore the cached mesh if there was no history. Also
	// check to make sure that we are in the record history state.
	//
	MStatusAssert( (fHasRecordHistory), "fHasRecordHistory == true" );

	if( !fHasHistory )
	{
		MFnDependencyNode depNodeFn;

		MString meshNodeName;
		MObject meshNodeShape;
		MPlug	meshNodeDestPlug;
		MPlug	meshNodeOutMeshPlug;
		MObject dupMeshNodeShape;
		MPlug	dupMeshNodeSrcPlug;

		meshNodeShape = fDagPath.node();
		dupMeshNodeShape = fDuplicateDagPath.node();

		depNodeFn.setObject( meshNodeShape );
		meshNodeName = depNodeFn.name();
		meshNodeDestPlug = depNodeFn.findPlug( "inMesh", &status );
		MCheckStatus( status, "Could not retrieve inMesh" );
		meshNodeOutMeshPlug = depNodeFn.findPlug( "outMesh", &status );
		MCheckStatus( status, "Could not retrieve outMesh" );

		depNodeFn.setObject( dupMeshNodeShape );
		dupMeshNodeSrcPlug = depNodeFn.findPlug( "outMesh", &status );
		MCheckStatus( status, "Could not retrieve outMesh" );

		// For the case with tweaks, we cannot write the mesh directly back onto
		// the cachedInMesh, since the shape can have out of date information from the
		// cachedInMesh, thus we temporarily connect the duplicate mesh shape to the
		// mesh shape and force a DG evaluation.
		//
		// For the case without tweaks, we can simply write onto the outMesh, since
		// the shape relies solely on an outMesh when there is no history nor tweaks.
		//
		if( fHasTweaks )
		{
			MDGModifier dgModifier;
			dgModifier.connect( dupMeshNodeSrcPlug, meshNodeDestPlug );
			status = dgModifier.doIt();
			MCheckStatus( status, "Could not connect dupMeshNode -> meshNode" );

			// Need to force a DG evaluation now that the input has been changed.
			//
			MString cmd( "dgeval -src " );
			cmd += meshNodeName;
			cmd += ".outMesh";	//outMesh statt inMesh, damit undo (ohne history) funzt
			status = MGlobal::executeCommand( cmd, false, false );
			MCheckStatus( status, "Could not force DG eval" );

			// Disconnect the duplicate meshNode now
			//
			dgModifier.undoIt();

			
		}
		else
		{
			MObject meshData;
			status = dupMeshNodeSrcPlug.getValue( meshData );
			MCheckStatus( status, "Could not retrieve meshData" );

			status = meshNodeOutMeshPlug.setValue( meshData );
			MCheckStatus( status, "Could not set outMesh" );

			
		}
	}

	return status;
}