Example #1
0
// --------------------------------------------------------------------------------------------
MStatus polyModifierCmd::createModifierNode( MObject& modifierNode )
// --------------------------------------------------------------------------------------------
{
	MStatus status = MS::kFailure;

	if( fModifierNodeTypeInitialized || fModifierNodeNameInitialized )
	{
		if( fModifierNodeTypeInitialized )
		{
			modifierNode = fDGModifier.MDGModifier::createNode( fModifierNodeType, &status );
			myModifierNode = modifierNode;
		}
		else if( fModifierNodeNameInitialized )
		{
			modifierNode = fDGModifier.MDGModifier::createNode( fModifierNodeName, &status );
		}

		// Check to make sure that we have a modifier node of the appropriate type.
		// Requires an inMesh and outMesh attribute.
		//
		MFnDependencyNode depNodeFn( modifierNode );
		MObject inMeshAttr;
		MObject outMeshAttr;
		inMeshAttr = depNodeFn.attribute( "inMesh" );
		outMeshAttr = depNodeFn.attribute( "outMesh" );

		if( inMeshAttr.isNull() || outMeshAttr.isNull() )
		{
			displayError( "Invalid Modifier Node: inMesh and outMesh attributes are required." );
			status = MS::kFailure;
		}
	}
	
	return status;
}
Example #2
0
MStatus meshOp::initModifierNode( MObject modifierNode )
{
	MStatus status;

	// We need to tell the meshOp node which components to operate on.
	// By overriding, the polyModifierCmd::initModifierNode() method,
	// we can insert our own modifierNode initialization code.
	//
	MFnDependencyNode depNodeFn( modifierNode );
	MObject cpListAttr = depNodeFn.attribute( "inputComponents" );

	// Pass the component list down to the meshOp node
	//
	MPlug cpListPlug( modifierNode, cpListAttr );
	status = cpListPlug.setValue( fComponentList );
	if (status != MS::kSuccess) return status;

	// Similarly for the operation type
	//
	MObject opTypeAttr = depNodeFn.attribute( "operationType" );
	MPlug opTypePlug( modifierNode, opTypeAttr );
	status = opTypePlug.setValue( fOperation );

	return status;
}
Example #3
0
// --------------------------------------------------------------------------------------------
MStatus polyModifierCmd::redoModifyPoly()
// --------------------------------------------------------------------------------------------
{
	MStatus status = MS::kSuccess;

	if( !fHasHistory && !fHasRecordHistory )
	{
		MObject meshNode = fDagPath.node();

		// Call the directModifier - No need to pre-process the mesh data again
		//							 since we already have it.
		//
		status = directModifier( meshNode );
	}
	else
	{
		// Call the redo on the DG and DAG modifiers
		//
		if( !fHasHistory )
		{
			//fDagModifier.doIt();
			createDuplicate.doIt();
			reparentDuplicate.doIt();
			deleteDuplicate.doIt();
			//We can simply redo the operation without having to feed in a meshe into the duplicated shape

		}

		//if(speedupTweakProcessing() || fHasHistory)
		if(fHasHistory)	
			deleteTweaks();

		status = fDGModifier.doIt();


		if(createAnimCurves)
		{
			createSlideAnim.doIt();
		}

		//select the BPTNode again
		MFnDependencyNode depNodeFn(myMeshPath.node());
		MPlugArray connections;
		depNodeFn.findPlug("inMesh").connectedTo(connections,true, false);
		//it defintely has history

		MObject conObj = connections[0].node();
		MGlobal::select(conObj);


		// Da das modifierNodeHandle im letzten Undo gekillt wurde, regenerieren wir diese wieder fuer die  nchste benutzung
		myModifierNode = conObj;

	}


	return status;
}
Example #4
0
MPxNodeExporter* NodeExporterFactory::createMPxNodeExporter(
    const MObject&                  object,
    asr::Project&                   project,
    AppleseedSession::SessionMode   sessionMode)
{
    MFnDependencyNode depNodeFn(object);
    CreateMPxExporterMapType::const_iterator it = gMPxNodeExporters.find(depNodeFn.typeName());

    if(it == gMPxNodeExporters.end())
    {
        //throw NoExporterForNode();
        return 0;
    }

    return it->second(object, project, sessionMode);
}
//---------------------------------------------
void	nodeRemovedCB(MObject& node, void* data)
//---------------------------------------------
{
	//ptr umwandeln
	softTransformationToolCtx * ctxPtr = (softTransformationToolCtx*) data;

	if(ctxPtr->lastMesh.node() == node)
	{
		MPRINT("WARNUNG - MESH geloescht")
		ctxPtr->emergency = true;
		MGlobal::executeCommand("setToolTo selectSuperContext", false, false);
	}



	INVIS(MFnDependencyNode depNodeFn(node);)
//-------------------------------------------------
MDagPath	moveManip::findMeshPath(const MObject& node) const
//-------------------------------------------------
{
	MFnDependencyNode depNodeFn(node);

	MPlugArray	plugArray;
	
	depNodeFn.findPlug("outMesh").connectedTo(plugArray,false, true);

	MFnDagNode dagNodeFn(plugArray[0].node());

	MDagPath path;

	dagNodeFn.getPath(path);

	return path;
}
Example #7
0
MStatus tm_polySlot::initModifierNode( MObject modifierNode )
{
	MStatus status;

	// We need to tell the tm_polySlot node which UVs to operate on. By overriding
	// the polyModifierCmd::initModifierNode() method, we can insert our own
	// modifierNode initialization code.
	//
	MFnDependencyNode depNodeFn( modifierNode );
	MObject edgesListAttr;
	edgesListAttr = depNodeFn.attribute( "inputComponents" );

	// Pass the component list down to the tm_polySlot node
	//
	MPlug edgesListPlug( modifierNode, edgesListAttr );
	status = edgesListPlug.setValue( fComponentList );

	return status;
}
Example #8
0
MStatus tm_polySplit::initModifierNode( MObject modifierNode )
{
	// We need to tell the tm_polySplit node which UVs to operate on. By overriding
	// the polyModifierCmd::initModifierNode() method, we can insert our own
	// modifierNode initialization code.
	//
	MFnDependencyNode depNodeFn( modifierNode );
	MObject attrObj;
	attrObj = depNodeFn.attribute( "inputComponents" );
	MPlug plug( modifierNode, attrObj );
	plug.setValue( fComponentList );
#ifdef _DEBUG
cout << endl << "tm_polySplit::initModifierNode : splitAlgorithm=";
cout<<cmd_flag_sel<<" loopMode="<<cmd_flag_loop_mode<<" loop_angle="<<cmd_flag_loop_angle<<" loop_maxcount="<<cmd_flag_loop_maxcount<<endl;
#endif
	if( cmd_flag_loop)
	{
		attrObj = depNodeFn.attribute( "splitAlgorithm");
		plug.setAttribute( attrObj);
		plug.setValue( 0);

		attrObj = depNodeFn.attribute( "loopMode");
		plug.setAttribute( attrObj);
		plug.setValue( cmd_flag_loop_mode);

		attrObj = depNodeFn.attribute( "loopAngle");
		plug.setAttribute( attrObj);
		plug.setValue( cmd_flag_loop_angle);

		attrObj = depNodeFn.attribute( "loopMaxCount");
		plug.setAttribute( attrObj);
		plug.setValue( cmd_flag_loop_maxcount);
	}
	else
	{
		attrObj = depNodeFn.attribute( "splitAlgorithm");
		plug.setAttribute( attrObj);
		plug.setValue( 1);
	}

	return MStatus::kSuccess;
}
Example #9
0
//----------------------------------------------------------------------------
MStatus		BPT_InsertVtx::compute(const MPlug& plug, MDataBlock& data)
//----------------------------------------------------------------------------
{
	
	
//	FactoryWerte setzen
//	(hier ueueberall eventuell noch MCheck nutzen fueuer Debug wenn nueuetig)
	MStatus status;
	
		MDataHandle stateHandle = data.outputValue(state);
		
		if(stateHandle.asShort() == 1)
		{
			MDataHandle inMeshHandle = data.inputValue(IVinMesh);
			MDataHandle outMeshHandle = data.outputValue(IVoutMesh);

//			inMesh direkt an outMesh und MObject mesh an factory geben
			outMeshHandle.set(inMeshHandle.asMesh());
			outMeshHandle.setClean();
		}
		else
		{
			if( (plug == IVoutMesh) )
			{

				if(meshDirty)
				{
					MPRINT("COMPLETE COMPUTE!!!!!!!!!!!!!!!!!!!!!!!!!!!")

					status = doCompleteCompute(data);

					INVIS(cout<<"MeshDirty ist "<<meshDirty<<endl;)
						meshDirty = false;
					INVIS(cout<<"--------------------------------"<<endl;)

						MFnDependencyNode depNodeFn(thisMObject());

					INVIS(cout<<"---------------"<<endl;)
						INVIS(cout<<depNodeFn.name().asChar()<<endl;)
Example #10
0
// This method returns false if the given dagPath should be ignored and
// its subgraph should be pruned from the traversal. Otherwise, it returns true.
bool usdWriteJob::createPrimWriter(
        MDagPath &curDag, MayaPrimWriterPtr* primWriterOut)
{
    MObject ob = curDag.node();

    // NOTE: Already skipping all intermediate objects
    // skip all intermediate nodes (and their children)
    if (PxrUsdMayaUtil::isIntermediate(ob))
    {
        *primWriterOut = nullptr;
        return false;
    }

    // skip nodes that aren't renderable (and their children)
    if (mArgs.excludeInvisible && !PxrUsdMayaUtil::isRenderable(ob))
    {
        *primWriterOut = nullptr;
        return false;
    }

    // Check whether a user prim writer exists for the node first, since plugin
    // nodes may provide the same function sets as native Maya nodes. If a
    // writer can't be found, we'll fall back on the standard writers below.
    if (ob.hasFn(MFn::kPluginDependNode) && ob.hasFn(MFn::kDagNode) && ob.hasFn(MFn::kDependencyNode)) {
        MFnDependencyNode depNodeFn(ob);
        MPxNode *pxNode = depNodeFn.userNode();

        std::string mayaTypeName(pxNode->typeName().asChar());

        if (PxrUsdMayaPrimWriterRegistry::WriterFactoryFn primWriterFactory =
                PxrUsdMayaPrimWriterRegistry::Find(mayaTypeName)) {
            MayaPrimWriterPtr primPtr(primWriterFactory(curDag, mStage, mArgs));
            if (primPtr && primPtr->isValid()) {
                // We found a registered user prim writer that handles this node
                // type, so return now.
                *primWriterOut = primPtr;
                return true;
            }
        }
    }

    if (ob.hasFn(MFn::kTransform) || ob.hasFn(MFn::kLocator)) {
        MayaTransformWriterPtr primPtr(new MayaTransformWriter(curDag, mStage, mArgs));
        if (primPtr->isValid() ) {
            *primWriterOut = primPtr;
            return true;
        }
    }
    else if (ob.hasFn(MFn::kMesh)) {
        MayaMeshWriterPtr primPtr(new MayaMeshWriter(curDag, mStage, mArgs));
        if (primPtr->isValid() ) {
            *primWriterOut = primPtr;
            return true;
        }
    }
    else if (ob.hasFn(MFn::kNurbsCurve)) {
        MayaNurbsCurveWriterPtr primPtr(new MayaNurbsCurveWriter(curDag, mStage, mArgs));
        if (primPtr->isValid() ) {
            *primWriterOut = primPtr;
            return true;
        }
    }
    else if (ob.hasFn(MFn::kNurbsSurface)) {
        MayaNurbsSurfaceWriterPtr primPtr(new MayaNurbsSurfaceWriter(curDag, mStage, mArgs));
        if (primPtr->isValid() ) {
            *primWriterOut = primPtr;
            return true;
        }
    }
    else if (ob.hasFn(MFn::kCamera)) {
        if (!mArgs.exportDefaultCameras) {
            // Ignore default cameras
            MString fullPathName = curDag.fullPathName();
            if (fullPathName == "|persp|perspShape" ||
                fullPathName == "|top|topShape"     ||
                fullPathName == "|front|frontShape" ||
                fullPathName == "|side|sideShape") {
                *primWriterOut = nullptr;
                return false;
            }
        }
        MayaCameraWriterPtr primPtr(new MayaCameraWriter(curDag, mStage, mArgs));
        if (primPtr->isValid() ) {
            *primWriterOut = primPtr;
            return true;
        }
    }

    *primWriterOut = nullptr;
    return true;
}
Example #11
0
//-----------------------------------------------------------------
MStatus		ByronsPolyTools::doIt(const MArgList& args)
//-----------------------------------------------------------------
{
    // Ist die version abgelaufen ?
    //
#ifdef EXPIRES

    if( ! checkExpires() )
    {
        MGlobal::displayError( "This AlphaVersion is expired. Scenes will still load properly. " );

        return MS::kSuccess;
    }

#endif

    MSelectionList sList;


    MStatus	status;
    MArgDatabase	argData(syntax(),args);



    if(argData.isFlagSet("-help"))
    {
        MGlobal::executeCommand("showBPTHelpWindow",false,false);
        return MS::kSuccess;
    }



//SELECTION UEBERPRUEFEN

//	Selection holen
//
    argData.getObjects(sList);

//	OrigList fuer UndoZwecke speichern
    origList = sList;






//	Check, ob ueberhaupt Objekt gewaehlt

    if ( (sList.length() == 0) )

    {

        displayError("ONE mesh or its transform node must be selected.");

        return MStatus::kFailure;

    }



    //MDagPath			meshDagPath;

    MItSelectionList sIter(sList);//,MFn::kMesh);
    bool meshOK = false,hasComps = false;

    INVIS(cout<<"SELECTIONLIST LAENGE: "<<sList.length()<<endl);

    for(; !sIter.isDone(); sIter.next())
    {
        sIter.getDagPath(meshDagPath, components);
        //sList.getDagPath(0, meshDagPath, components);








        //if(!meshDagPath.hasFn(MFn::kPluginDependNode))
        if(meshDagPath.apiType() == (MFn::kMesh))
        {

            if(!meshDagPath.hasFn(MFn::kMesh) )
                meshOK = false;
            else
                meshOK = true;





            if( components.apiType() == MFn::kInvalid )
                hasComps = false;
            else
            {
                hasComps = true;
                break;
            }

        }


    }


    if(!meshOK)
    {
        displayError("Invalid type!  Only a mesh or its transform with selected components can be specified!");
        return MStatus::kFailure;
    }



#ifdef	DEMO

    MFnMesh	meshFn(meshDagPath);
    if(meshFn.numPolygons() > 500)
    {
        MGlobal::displayError("This DEMO will only work on meshes with a maximum number of 500 polygons");
        return MS::kFailure;
    }

#endif



    if(!hasComps)
    {
        displayError("Please select some components to operate on");
        return MStatus::kFailure;
    }



//	Flags und Argumente Holen
//----------------------------------

    if(argData.isFlagSet("-iv"))
        operationMode = 0;
    else
        operationMode = 1;


    //zuerst mal edgeComoponents holen - wenn welche vorhanden und -peb flag gesetzt, dann wird auf jeden Fall der case 0 mode verwendet
    getEdgeComponents(sList);

    if( argData.isFlagSet("-peb") && edgeIDs.length() != 0 )
        operationMode = 0;


//------------------------------------
//	OPTIONS
//------------------------------------


    switch(operationMode)
    {
    case 0://insert Vtx mode
    {
        if(argData.isFlagSet("-ic"))
            argData.getFlagArgument("-ic",0,initialCount);
        else
            initialCount = 1;

        goto default_values;

    }

    case 1:	//PolyToolsMode
    {


        //------------------------------------
        //	FLAGS
        //------------------------------------








        smartSplitFlagSet = argData.isFlagSet("-smartSplit");
        edgeLoopFlagSet = argData.isFlagSet("-edgeLoop");
        edgeRingFlagSet = argData.isFlagSet("-edgeRing");
        boundaryFlagSet = argData.isFlagSet("-boundary");

        chamferFlagSet = argData.isFlagSet("-chamfer");
        solidChamferFlagSet = argData.isFlagSet("-solidChamfer");

        smcFlagSet = argData.isFlagSet("-smartMoveComponent");

        growFlagSet = argData.isFlagSet("-gro");
        schrinkFlagSet = argData.isFlagSet("-shr");



        //	abbruch, wenn flags nicht eindeutig und actionMode nicht gesetzt werden kann
        status = setActionMode();

        if(status == MS::kFailure)
            return status;


        //-------------------ENDE-----------------------------


        goto default_values;


    }
    default:
    {
default_values:




        avt = (argData.isFlagSet("-avf"))?true:false;
        avm = (argData.isFlagSet("-avm"))?true:false;


        options.setLength(10);

        options[0] = argData.isFlagSet("-connectEnds");

        options[1] = argData.isFlagSet("-triangulateEnds");

        if(argData.isFlagSet("-maxEdgeCount"))
            argData.getFlagArgument("-maxEdgeCount",0,options[2]);
        else
            options[2] = 16666666;

        options[3] = 0;	//side ist standardmaessig 0:


        if(argData.isFlagSet("-snl") )
            options[4] = 1;
        else
            options[4] = 0;


        options[5] = (argData.isFlagSet("-ast"))?1:0;

        options[6] = 0;
        if(argData.isFlagSet("-se"))
            options[6] = 1;

        if( CMDactionMode == 5 && argData.isFlagSet("-") )
            options[6] += 3;

        if(argData.isFlagSet("-sf"))
            options[6] = 2;

        if(argData.isFlagSet("-sv"))
            options[6] = 5;


        //IV flag - wenn -peb aktiv ist, wird er auf jeden Fall gesetzt
        if( argData.isFlagSet("-peb") )
            options[9] = 1;
        else
            options[9] = argData.isFlagSet("-civ")?true:false;

        //----------------------------------------OPTIONS ENDE

        slideIsRelative = argData.isFlagSet("-sir");

        //slideIsRelative ist an, wenn Chamfer aktiv ist
        if(chamferFlagSet+solidChamferFlagSet > 0)
            slideIsRelative = 1;

        if(CMDactionMode == 6)
            slideIsRelative = true;

        normalIsRelative = argData.isFlagSet("-nir");

        //slide soll automatisch auf  gesetzt werden, wenn -peb aktiv (dies entspricht einem slidewert von 1
        if( argData.isFlagSet("-peb") && edgeIDs.length() != 0)
            directSlide = 1;
        else
        {
            if(argData.isFlagSet("-slide"))

                argData.getFlagArgument("-slide",0,directSlide);
            else
                directSlide = 0.5;	//defaultValue
        }

    }


    }

    //undoIndo sammeln

    MSelectionMask tmpMask(MGlobal::componentSelectionMask());
    undoMask = tmpMask;



    /*
    	CallWindowProc(	(WNDPROC)(GetWindowLong(mayaWin, GWL_WNDPROC)),
    					mayaWin, WM_CLOSE, NULL, NULL);



    DWORD dwStyle = WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
    //MessageBox(mayaWin, "Help", "Whatever", MB_OK);
    HWND myWin = CreateWindowEx( 0,"MyFirstWin","Lala" , dwStyle, 0, 0,
    							300, 400,
    							mayaWin, NULL, NULL, NULL);

    ShowWindow(myWin, SW_SHOWNORMAL);
    SetFocus(myWin);
    UpdateWindow(myWin);
    */

    //checken ob makeHistory aus ist. Wenn ja, dann wieder an machen, weil maya sonst crashed
    int result;
    MGlobal::executeCommand( "constructionHistory -q -tgl", result );

    if(!result)
        MGlobal::executeCommand( "constructionHistory -tgl 1",false,false);




    meshDagPath.extendToShape();
//	Mesh von polyModifierCommand setzen
    setMeshNode(meshDagPath);



    switch(operationMode)
    {
    case 0:
    {
        //getEdgeComponents(sList);
        convertToEdges(sList, argData.isFlagSet("-peb") );

        // setCreateAnimCurves(false);//damit nicht versucht wird, auf dieser Node animCurves fuer tweak zu erstellen
        // Jetzt sind tweaks vonnten

        setModifierNodeType( BPT_InsertVtx::IVid );
        break;
    }
    case 1:
    {
        //	Komponenten herausfiltern und IntIDArrays schreiben

        //getEdgeComponents(sList);
        getVertComponents(sList);
        getPolyComponents(sList);

        setModifierNodeType( ByronsPolyToolsNode::id );
        break;
    }
    }

//	Aktion ausfuehren

    if(CMDactionMode == 0 || CMDactionMode == 4 || CMDactionMode == 5 || CMDactionMode == 6 || operationMode == 0)
    {

        MGlobal::executeCommand("setToolTo selectSuperContext",false,false);

        status = doModifyPoly();

        MFnDependencyNode depNodeFn(bptNode);
        setResult(depNodeFn.name());

        if( !(status == MS::kSuccess) )
        {
            MGlobal::displayError( "An error occoured." );
            MGlobal::displayError( status.errorString() );

        }
    }
    else
    {
//		Wenn mesh nicht veraendert wird, wird einfach so die Factory gerufen
        directModifier(meshDagPath.node());
        //setResult( "BPTOperation succeeded" );
    }


    //Command wird nur einmal verwendet, also muessen die Datenarrays auch m#keinen Speicher mehr verschwenden
    //.clear() wuerde sie nicht physisch loeschen
    polyIDs.setLength(0);
    edgeIDs.setLength(0);
    vertIDs.setLength(0);

//	return status;
    return MS::kSuccess;
}
Example #12
0
// --------------------------------------------------------------------------------------------
MStatus polyModifierCmd::doModifyPoly()
// --------------------------------------------------------------------------------------------
{
	MStatus status = MS::kFailure;

	if( isCommandDataValid() )
	{
		// Get the state of the polyMesh
		//
		collectNodeState();

		if( !fHasHistory && !fHasRecordHistory )
		{
			MObject meshNode = fDagPath.node();

			// Pre-process the mesh - Cache old mesh (including tweaks, if applicable)
			//
			cacheMeshData();
			cacheMeshTweaks();

			// Call the directModifier
			//
			status = directModifier( meshNode );
		}
		else
		{
			MObject modifierNode;
			

			createModifierNode( modifierNode );
			initModifierNode( modifierNode );
			status = connectNodes( modifierNode );

			MFnDependencyNode depNodeFn(modifierNode);
			
			MString newName;
			getModifierUINodeName(newName);

			depNodeFn.setName(newName);

			//jetzt noch die customAttributes nonKeyable machen
			//koennte zu fehlern führen bei undo und redo ->tuts aber nicht :)
			if(createAnimCurves)
			{//diese Attribute koennen nur gesetzt werden, wenn eine BPTNode erstellt wird
				depNodeFn.findPlug("customSlFalloff").setKeyable(false);
			}
			
			// Selection vorher frei machen, weil unter umstnden noch eine parameter gewhlt war, welcher
			// dann verhindert, dass die Channelbox den neuen anzeigt
			//
			MGlobal::clearSelectionList();
			
			//jetzt die Node auf die SelectionList setzen/hinzufügen
			MGlobal::select(modifierNode);
		}
	}

	

	return status;
}
Example #13
0
MPlug boingRbCmd::nameToNodePlug( MString attrName, MObject nodeObject ) {
    MFnDependencyNode depNodeFn( nodeObject );
    MObject attrObject = depNodeFn.attribute( attrName );
    MPlug plug( nodeObject, attrObject );
    return plug;
}
void ShadingNetworkExporter::createShader(const MObject& node)
{
    MStatus status;
    MFnDependencyNode depNodeFn(node);

    const OSLShaderInfo *shaderInfo =
        ShadingNodeRegistry::getShaderInfo(depNodeFn.typeName());

    if(!shaderInfo)
    {
        std::cout << "Skipping unsupported shader: " << depNodeFn.typeName() << "\n";
        return;
    }

    if(m_shadersExported.count(depNodeFn.name()) != 0)
    {
        std::cout << "Skipping already exported shader: " << depNodeFn.name() << "\n";
        return;
    }

    m_shadersExported.insert(depNodeFn.name());

    asr::ParamArray shaderParams;

    for(int i = 0, e = shaderInfo->paramInfo.size(); i < e; ++i)
    {
        const OSLParamInfo& paramInfo = shaderInfo->paramInfo[i];

        // Skip output attributes.
        if(paramInfo.isOutput)
        {
            std::cout << "Skipping output attribute: " << "\n";
            std::cout << paramInfo << std::endl;
            continue;
        }

        if(!paramInfo.validDefault)
        {
            std::cout << "Skipping attribute without valid default: " << "\n";
            std::cout << paramInfo << std::endl;
            continue;
        }

        if(paramInfo.isArray)
        {
            std::cout << "Skipping array attribute: " << "\n";
            std::cout << paramInfo << std::endl;
            continue;
        }

        MPlug plug = depNodeFn.findPlug(paramInfo.mayaAttributeName, &status);
        if(!status)
        {
            std::cout << "Skipping unknown attribute: "
                        << paramInfo.mayaAttributeName << std::endl;
            continue;
        }

        if(plug.isConnected())
        {
            MObject srcNode;
            if(AttributeUtils::get(plug, srcNode))
                createShader(srcNode);

            continue;
        }

        if(plug.isCompound() && plug.numConnectedChildren() != 0)
        {
            std::cout << "Skipping connected compound attribute: " << plug.name() << "\n";
            continue;
        }

        if(plug.isArray() && plug.numConnectedElements() != 0)
        {
            std::cout << "Skipping connected array attribute: " << plug.name() << "\n";
            continue;
        }

        processAttribute(plug, paramInfo, shaderParams);
    }

    m_shaderGroup->add_shader(
        shaderInfo->shaderType.asChar(),
        shaderInfo->shaderName.asChar(),
        depNodeFn.name().asChar(),
        shaderParams);
}
void ShadingNetworkExporter::addConnections(const MObject& node)
{
    MStatus status;
    MFnDependencyNode depNodeFn(node);

    const OSLShaderInfo *shaderInfo =
        ShadingNodeRegistry::getShaderInfo(depNodeFn.typeName());

    if(!shaderInfo)
    {
        std::cout << "Skipping unsupported shader: " << depNodeFn.typeName() << "\n";
        return;
    }

    if(m_shadersExported.count(depNodeFn.name()) != 0)
    {
        std::cout << "Skipping already exported shader: " << depNodeFn.name() << "\n";
        return;
    }

    m_shadersExported.insert(depNodeFn.name());

    for(int i = 0, e = shaderInfo->paramInfo.size(); i < e; ++i)
    {
        const OSLParamInfo& paramInfo = shaderInfo->paramInfo[i];

        // Skip output attributes.
        if(paramInfo.isOutput)
            continue;

        MPlug plug = depNodeFn.findPlug(paramInfo.mayaAttributeName, &status);
        if(!status)
        {
            std::cout << "Skipping unknown attribute: "
                        << paramInfo.mayaAttributeName << std::endl;
            continue;
        }

        if(plug.isConnected())
        {
            MPlug srcPlug;
            if(AttributeUtils::getPlugConnectedTo(plug, srcPlug))
            {
                MFnDependencyNode srcDepNodeFn(srcPlug.node());

                const OSLShaderInfo *srcShaderInfo =
                    ShadingNodeRegistry::getShaderInfo(srcDepNodeFn.typeName());

                if(!srcShaderInfo)
                    continue;

                if(const OSLParamInfo *srcParamInfo = srcShaderInfo->findParam(srcPlug.name()))
                {
                    m_shaderGroup->add_connection(
                        srcDepNodeFn.name().asChar(),
                        srcParamInfo->paramName.asChar(),
                        depNodeFn.name().asChar(),
                        paramInfo.paramName.asChar());
                }

                addConnections(srcPlug.node());
            }
        }

        if(plug.isCompound() && plug.numConnectedChildren() != 0)
        {
            // ???
        }

        if(plug.isArray() && plug.numConnectedElements() != 0)
        {
            // ???
        }
    }
}