- Main Page
- Related Pages
- Modules
- Classes
- Examples

# ShadingConnection.cpp

    //-
    // ==========================================================================
    // Copyright (C) 1995 - 2006 Autodesk, Inc. and/or its licensors.  All
    // rights reserved.
    //
    // The coded instructions, statements, computer programs, and/or related
    // material (collectively the "Data") in these files contain unpublished
    // information proprietary to Autodesk, Inc. ("Autodesk") and/or its
    // licensors, which is protected by U.S. and Canadian federal copyright
    // law and by international treaties.
    //
    // The Data is provided for use exclusively by You. You have the right
    // to use, modify, and incorporate this Data into other products for
    // purposes authorized by the Autodesk software license agreement,
    // without fee.
    //
    // The copyright notices in the Software and this entire statement,
    // including the above license grant, this restriction and the
    // following disclaimer, must be included in all copies of the
    // Software, in whole or in part, and all derivative works of
    // the Software, unless such copies or derivative works are solely
    // in the form of machine-executable object code generated by a
    // source language processor.
    //
    // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.
    // AUTODESK DOES NOT MAKE AND HEREBY DISCLAIMS ANY EXPRESS OR IMPLIED
    // WARRANTIES INCLUDING, BUT NOT LIMITED TO, THE WARRANTIES OF
    // NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR
    // PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE, OR
    // TRADE PRACTICE. IN NO EVENT WILL AUTODESK AND/OR ITS LICENSORS
    // BE LIABLE FOR ANY LOST REVENUES, DATA, OR PROFITS, OR SPECIAL,
    // DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES, EVEN IF AUTODESK
    // AND/OR ITS LICENSORS HAS BEEN ADVISED OF THE POSSIBILITY
    // OR PROBABILITY OF SUCH DAMAGES.
    //
    // ==========================================================================
    //+

    // ShadingConnection.cpp

    // DESCRIPTION:  This class stores useful information about
    //               a shader's attribute, including what's connected upstream of it.
    //               It also automatically passes through shader switches.
    //
    // AUTHOR: Christian Laforte
    //

    #include <maya/MObject.h>
    #include <maya/MColor.h>
    #include <maya/MString.h>
    #include <maya/MStringArray.h>
    #include <maya/MFnDependencyNode.h>
    #include <maya/MPlug.h>
    #include <maya/MPlugArray.h>

    #include <assert.h>

    #include "ShadingConnection.h"

    ShadingConnection::ShadingConnection(MObject shaderObj, MString shapeName, MString attribute /* = "" */)
    {
        // Store those input values for later use.
        this->m_shaderObj = shaderObj;
        this->m_shapeName = shapeName;

        // By default, the connection is direct until proven otherwise.
        this->m_directConnection = true;

        if (attribute != "")
            traverseAttribute(attribute);
    }

    ShadingConnection::TYPE ShadingConnection::traverseAttribute(MString attributeName)
    {
        // Get a plug to the attribute.
        MStatus status;
        MFnDependencyNode shaderNode(m_shaderObj);

        MPlug plug = shaderNode.findPlug( attributeName, &status );
        assert(status);

        this->m_attributeName = attributeName;

        return analyzePlug(plug);
    }

    ShadingConnection::TYPE ShadingConnection::analyzePlug(MPlug plug)
    {
        MStatus status;

        // Find all incoming connections.
        MPlugArray connectedElements;
        plug.connectedTo( connectedElements, true, false, &status );
        assert(status);

        if (connectedElements.length() == 0)
        {
            // It's a constant color... set it now and return.
            unsigned int numChildren = plug.numChildren();
            assert(numChildren == 3);

            float red, green, blue;
            plug.child(0).getValue(red);
            plug.child(1).getValue(green);
            plug.child(2).getValue(blue);

            return setConstantColor(MColor(red, green, blue, 1.0));
        }

        // The plug is actually connected on a different shading node.
        MObject connectedObject = connectedElements[0].node(&status);
        assert(status);

        // If this is a triple shading switch, go through it.
        if (connectedObject.hasFn(MFn::kTripleShadingSwitch))
        {
            return traverseTripleShadingSwitch(connectedObject);
        }

        // Set the object and return the appropriate type.
        return setTexture(connectedObject);
    }

    ShadingConnection::TYPE ShadingConnection::traverseTripleShadingSwitch(MObject connectedObject)
    {
        // The connection cannot be direct anymore.
        m_directConnection = false;

        MFnDependencyNode node(connectedObject);

        MStatus status;
        MPlug inputPlug = node.findPlug( "input" );

        unsigned int numElements = inputPlug.numElements();
        unsigned int numChildren = inputPlug.numChildren();

        // It is assumed that the first child of this input compound attribute is
        // a "inTexture" attribute and the the second child is the inShape attribute.
        // This assumption should always be safe, unless some drastic changes occured in the
        // implementation of the shading switches... in which case this code won't work, so
        // we would throw an exception.
        assert( numChildren >= 2); // "Abnormal hierarchy in switching node."

        // Go through each row of the switch table.
        for (unsigned int index = 0; index < numElements; index++)
        {
            MPlug inTexturePlug = inputPlug.elementByPhysicalIndex(index).child(0);
            MPlug inShapePlug = inputPlug.elementByPhysicalIndex(index).child(1);

            MPlugArray inShapeConnections;
            inShapePlug.connectedTo( inShapeConnections, true, false, &status );

            // Check if one of the corresponding shapes matches the given shape name.
            unsigned int numCorrespondingShapes = inShapeConnections.length();
            for (unsigned int shapeNum = 0; shapeNum < numCorrespondingShapes; shapeNum++)
            {
                MObject inShapeObj = inShapeConnections[0].node(&status);
                assert(status);

                MFnDependencyNode inShape(inShapeObj);
                MString inShapeName = inShape.name();

                if (inShapeName == m_shapeName)
                    return analyzePlug(inTexturePlug);
            }
        }

        // If there was no special case in the switch for our shape, check the default.
        MPlug defaultPlug = node.findPlug("default");
        return analyzePlug(defaultPlug);
    }

    ShadingConnection::TYPE ShadingConnection::type()
    {
        return m_type;
    }

    MColor ShadingConnection::constantColor()
    {
        assert(m_type == CONSTANT_COLOR);
        return m_constantColor;
    }

    MObject ShadingConnection::texture()
    {
        assert(m_type == TEXTURE);
        return m_texture;
    }

    MObject ShadingConnection::shaderObj()
    {
        return m_shaderObj;
    }

    MString ShadingConnection::shaderName()
    {
        MStatus stat;
        MFnDependencyNode shaderNode(m_shaderObj, &stat);
        assert(stat);
        return shaderNode.name();
    }

    MString ShadingConnection::attributeName()
    {
        return m_attributeName;
    }

    MString ShadingConnection::shapeName()
    {
        return m_shapeName;
    }

    ShadingConnection::TYPE ShadingConnection::setConstantColor(MColor col)
    {
        m_constantColor = col;
        m_type = CONSTANT_COLOR;

        // Reset m_texture to prevent misinterpretation.
        m_texture = MObject();

        return m_type;
    }

    ShadingConnection::TYPE ShadingConnection::setTexture(MObject texture)
    {
        m_texture = texture;
        m_type = TEXTURE;

        // Reset m_color to prevent misinterpretation.
        m_constantColor = MColor();

        return m_type;
    }

    bool ShadingConnection::isDirectConnection()
    {
        return m_directConnection;
    }