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

# pointOnSubdNode.cpp

    //-
    // ==========================================================================
    // Copyright 1995,2006,2008 Autodesk, Inc. All rights reserved.
    //
    // Use of this software is subject to the terms of the Autodesk
    // license agreement provided at the time of installation or download,
    // or which otherwise accompanies this software in either electronic
    // or hard copy form.
    // ==========================================================================
    //+

    //
    // File: pointOnSubdNode.cpp
    //
    // Dependency Graph Node: pointOnSubd
    //

    #include "pointOnSubdNode.h"

    #include <maya/MFnNumericAttribute.h>
    #include <maya/MFnTypedAttribute.h>
    #include <maya/MFnSubdNames.h>
    #include <maya/MFnSubdData.h>
    #include <maya/MDataHandle.h>
    #include <maya/MDataBlock.h>
    #include <maya/MFnPlugin.h>
    #include <maya/MFnSubd.h>
    #include <maya/MGlobal.h>
    #include <maya/MVector.h>
    #include <maya/MPoint.h>
    #include <maya/MPlug.h>

    MTypeId     pointOnSubd::id( 0x80019 );

    #include <maya/MIOStream.h>
    #define McheckErr(status,message)       \
        if( MStatus::kSuccess != stat ) {   \
            cerr << message << "\n";        \
            return stat;                    \
        }

    // attributes
    //
    MObject pointOnSubd::aSubd;
    MObject pointOnSubd::aFaceFirst;
    MObject pointOnSubd::aFaceSecond;
    MObject pointOnSubd::aRelativeUV;
    MObject pointOnSubd::aU;
    MObject pointOnSubd::aV;

    MObject pointOnSubd::aPoint;
    MObject pointOnSubd::aPointX;
    MObject pointOnSubd::aPointY;
    MObject pointOnSubd::aPointZ;
    MObject pointOnSubd::aNormal;
    MObject pointOnSubd::aNormalX;
    MObject pointOnSubd::aNormalY;
    MObject pointOnSubd::aNormalZ;

    pointOnSubd::pointOnSubd() {}
    pointOnSubd::~pointOnSubd() {}

    MStatus pointOnSubd::compute( const MPlug& plug, MDataBlock& data )
    //
    //  Description:
    //      This method computes the value of the given output plug based
    //      on the values of the input attributes.
    //
    //  Arguments:
    //      plug - the plug to compute
    //      data - object that provides access to the attributes for this node
    //
    {
        MStatus returnStatus;

        // Check which output attribute we have been asked to compute.  If this
        // node doesn't know how to compute it, we must return
        // MS::kUnknownParameter.
        //
        if( (plug == aPoint) || (plug == aNormal) ||
            (plug == aPointX) || (plug == aNormalX) ||
            (plug == aPointY) || (plug == aNormalY) ||
            (plug == aPointZ) || (plug == aNormalZ) ) {

            // Get a handle to the input attribute that we will need for the
            // computation.  If the value is being supplied via a connection
            // in the dependency graph, then this call will cause all upstream
            // connections to be evaluated so that the correct value is supplied.
            //
            do {
                MDataHandle subdHandle = data.inputValue( aSubd, &returnStatus );
                if( returnStatus != MS::kSuccess ) {
                    MGlobal::displayError( "ERROR: cannot get subd\n" );
                    break;
                }

                MDataHandle faceFirstHandle =
                    data.inputValue( aFaceFirst, &returnStatus );
                if( returnStatus != MS::kSuccess ) {
                    MGlobal::displayError( "ERROR: cannot get face first\n" );
                    break;
                }

                MDataHandle faceSecondHandle =
                    data.inputValue( aFaceSecond, &returnStatus );
                if( returnStatus != MS::kSuccess ) {
                    MGlobal::displayError( "ERROR: cannot get face2\n" );
                    break;
                }

                MDataHandle uHandle = data.inputValue( aU, &returnStatus );
                if( returnStatus != MS::kSuccess ) {
                    MGlobal::displayError( "ERROR: cannot get u\n" );
                    break;
                }

                MDataHandle vHandle = data.inputValue( aV, &returnStatus );
                if( returnStatus != MS::kSuccess ) {
                    MGlobal::displayError( "ERROR: cannot get v\n" );
                    break;
                }

                MDataHandle relHandle = data.inputValue( aRelativeUV, &returnStatus );
                if( returnStatus != MS::kSuccess ) {
                    MGlobal::displayError( "ERROR: cannot get relative UV\n" );
                    break;
                }

                // Read the input value from the handle.
                //
                MStatus stat;
                MObject subdValue = subdHandle.asSubdSurface();
                MFnSubd subdFn( subdValue, &stat );
                McheckErr(stat,"ERROR creating subd function set");

                int faceFirstValue = faceFirstHandle.asLong();
                int faceSecondValue = faceSecondHandle.asLong();
                double uValue = uHandle.asDouble();
                double vValue = vHandle.asDouble();
                bool relUV = relHandle.asBool();

                MPoint point;
                MVector normal;

                MUint64 polyId;
                stat = MFnSubdNames::fromSelectionIndices( polyId, faceFirstValue,
                                                           faceSecondValue );
                McheckErr(stat,"ERROR converting indices");

                stat = subdFn.evaluatePositionAndNormal( polyId, uValue, vValue,
                                                         relUV, point, normal );
                normal.normalize();
                McheckErr(stat,"ERROR evaluating the position and the normal");

                // Get handles to the output attributes.  This is similar to the
                // "inputValue" call above except that no dependency graph
                // computation will be done as a result of this call.
                //
                MDataHandle pointHandle = data.outputValue( aPoint );
                pointHandle.set( point.x, point.y, point.z );
                data.setClean(plug);

                MDataHandle normalHandle = data.outputValue( aNormal );
                normalHandle.set( normal.x, normal.y, normal.z );
                data.setClean(plug);

            } while( false );
        }
        else {
            return MS::kUnknownParameter;
        }

        return MS::kSuccess;
    }

    void* pointOnSubd::creator()
    //
    //  Description:
    //      this method exists to give Maya a way to create new objects
    //      of this type.
    //
    //  Return Value:
    //      a new object of this type
    //
    {
        return new pointOnSubd;
    }

    MStatus pointOnSubd::initialize()
    //
    //  Description:
    //      This method is called to create and initialize all of the attributes
    //      and attribute dependencies for this node type.  This is only called
    //      once when the node type is registered with Maya.
    //
    //  Return Values:
    //      MS::kSuccess
    //      MS::kFailure
    //
    {
        MStatus stat;

        MFnTypedAttribute subdAttr;
        aSubd = subdAttr.create( "subd", "s", MFnSubdData::kSubdSurface, &stat );
        McheckErr( stat, "cannot create pointOnSubd::aSubd" );
        subdAttr.setStorable(true);
        subdAttr.setKeyable(false);
        subdAttr.setReadable( true );
        subdAttr.setWritable( true );
        subdAttr.setCached( false );
        stat = addAttribute( pointOnSubd::aSubd );
        McheckErr( stat, "cannot add pointOnSubd::aSubd" );

        MFnNumericAttribute faceFirstAttr;
        aFaceFirst = faceFirstAttr.create( "faceFirst", "ff",
                                           MFnNumericData::kLong, 0, &stat );
        McheckErr( stat, "cannot create pointOnSubd::aFaceFirst" );
        faceFirstAttr.setStorable(true);
        faceFirstAttr.setKeyable(true);
        faceFirstAttr.setSoftMin( 0.0 );
        faceFirstAttr.setReadable( true );
        faceFirstAttr.setWritable( true );
        faceFirstAttr.setCached( false );
        stat = addAttribute( pointOnSubd::aFaceFirst );
        McheckErr( stat, "cannot add pointOnSubd::aFaceFirst" );

        MFnNumericAttribute faceSecondAttr;
        aFaceSecond = faceSecondAttr.create( "faceSecond", "fs",
                                             MFnNumericData::kLong, 0, &stat );
        McheckErr( stat, "cannot create pointOnSubd::aFaceSecond" );
        faceSecondAttr.setStorable(true);
        faceSecondAttr.setKeyable(true);
        faceSecondAttr.setSoftMin( 0.0 );
        faceSecondAttr.setReadable( true );
        faceSecondAttr.setWritable( true );
        faceSecondAttr.setCached( false );
        stat = addAttribute( pointOnSubd::aFaceSecond );
        McheckErr( stat, "cannot add pointOnSubd::aFaceSecond" );

        MFnNumericAttribute uAttr;
        aU = uAttr.create( "uValue", "u", MFnNumericData::kDouble,
                           0, &stat );
        McheckErr( stat, "cannot create pointOnSubd::aU" );
        uAttr.setStorable(true);
        uAttr.setKeyable(true);
        uAttr.setSoftMin( 0.0 );
        uAttr.setSoftMax( 1.0 );
        uAttr.setReadable( true );
        uAttr.setWritable( true );
        uAttr.setCached( false );
        stat = addAttribute( aU );
        McheckErr( stat, "cannot add pointOnSubd::aU" );

        MFnNumericAttribute vAttr;
        aV = vAttr.create( "vValue", "v", MFnNumericData::kDouble,
                           0, &stat );
        McheckErr( stat, "cannot create pointOnSubd::aV" );
        vAttr.setStorable(true);
        vAttr.setKeyable(true);
        vAttr.setSoftMin( 0.0 );
        vAttr.setSoftMax( 1.0 );
        vAttr.setReadable( true );
        vAttr.setWritable( true );
        vAttr.setCached( false );
        stat = addAttribute( aV );
        McheckErr( stat, "cannot add pointOnSubd::aV" );

        MFnNumericAttribute relAttr;
        aRelativeUV = relAttr.create( "relative", "rel", MFnNumericData::kBoolean,
                                      0, &stat );
        McheckErr( stat, "cannot create pointOnSubd::aRelativeUV" );
        relAttr.setStorable(true);
        relAttr.setKeyable(true);
        relAttr.setSoftMin( 0.0 );
        relAttr.setSoftMax( 1.0 );
        relAttr.setReadable( true );
        relAttr.setWritable( true );
        relAttr.setCached( false );
        stat = addAttribute( pointOnSubd::aRelativeUV );
        McheckErr( stat, "cannot add pointOnSubd::aRelativeUV" );

        MFnNumericAttribute pointXAttr;
        aPointX = pointXAttr.create( "pointX", "px", MFnNumericData::kDouble,
                                    0.0, &stat );
        McheckErr( stat, "cannot create pointOnSubd::aPointX" );
        pointXAttr.setWritable(false);
        pointXAttr.setStorable(false);
        pointXAttr.setReadable( true );
        pointXAttr.setCached( true );
        stat = addAttribute( aPointX );
        McheckErr( stat, "cannot add pointOnSubd::aPointX" );

        MFnNumericAttribute pointYAttr;
        aPointY = pointYAttr.create( "pointY", "py", MFnNumericData::kDouble,
                                    0.0, &stat );
        McheckErr( stat, "cannot create pointOnSubd::aPointY" );
        pointYAttr.setWritable(false);
        pointYAttr.setStorable(false);
        pointYAttr.setReadable( true );
        pointYAttr.setCached( true );
        stat = addAttribute( aPointY );
        McheckErr( stat, "cannot add pointOnSubd::aPointY" );

        MFnNumericAttribute pointZAttr;
        aPointZ = pointZAttr.create( "pointZ", "pz", MFnNumericData::kDouble,
                                    0.0, &stat );
        McheckErr( stat, "cannot create pointOnSubd::aPointZ" );
        pointZAttr.setWritable(false);
        pointZAttr.setStorable(false);
        pointZAttr.setReadable( true );
        pointZAttr.setCached( true );
        stat = addAttribute( aPointZ );
        McheckErr( stat, "cannot add pointOnSubd::aPointZ" );

        MFnNumericAttribute pointAttr;
        aPoint = pointAttr.create( "point", "p", aPointX, aPointY, aPointZ, &stat);
        McheckErr( stat, "cannot create pointOnSubd::aPoint" );
        pointAttr.setWritable(false);
        pointAttr.setStorable(false);
        pointAttr.setReadable( true );
        pointAttr.setCached( true );
        stat = addAttribute( aPoint );
        McheckErr( stat, "cannot add pointOnSubd::aPoint" );

        MFnNumericAttribute normalXAttr;
        aNormalX = normalXAttr.create( "normalX", "nx", MFnNumericData::kDouble,
                                       0.0, &stat );
        McheckErr( stat, "cannot create pointOnSubd::aNormal" );
        normalXAttr.setWritable(false);
        normalXAttr.setStorable(false);
        normalXAttr.setReadable( true );
        normalXAttr.setCached( true );
        stat = addAttribute( aNormalX );
        McheckErr( stat, "cannot add pointOnSubd::aNormalX" );

        MFnNumericAttribute normalYAttr;
        aNormalY = normalYAttr.create( "normalY", "ny", MFnNumericData::kDouble,
                                       0.0, &stat );
        McheckErr( stat, "cannot create pointOnSubd::aNormal" );
        normalYAttr.setWritable(false);
        normalYAttr.setStorable(false);
        normalYAttr.setReadable( true );
        normalYAttr.setCached( true );
        stat = addAttribute( aNormalY );
        McheckErr( stat, "cannot add pointOnSubd::aNormalY" );

        MFnNumericAttribute normalZAttr;
        aNormalZ = normalZAttr.create( "normalZ", "nz", MFnNumericData::kDouble,
                                       0.0, &stat );
        McheckErr( stat, "cannot create pointOnSubd::aNormal" );
        normalZAttr.setWritable(false);
        normalZAttr.setStorable(false);
        normalZAttr.setReadable( true );
        normalZAttr.setCached( true );
        stat = addAttribute( aNormalZ );
        McheckErr( stat, "cannot add pointOnSubd::aNormalZ" );

        MFnNumericAttribute normalAttr;
        aNormal = normalAttr.create("normal","n",aNormalX,aNormalY,aNormalZ,&stat);
        McheckErr( stat, "cannot create pointOnSubd::aNormal" );
        normalAttr.setWritable(false);
        normalAttr.setStorable(false);
        normalAttr.setReadable( true );
        normalAttr.setCached( true );
        stat = addAttribute( aNormal );
        McheckErr( stat, "cannot add pointOnSubd::aNormal" );

        // Set up a dependency between the input and the output.  This will cause
        // the output to be marked dirty when the input changes.  The output will
        // then be recomputed the next time the value of the output is requested.
        //
        stat = attributeAffects( aSubd, aPoint );
        stat = attributeAffects( aSubd, aPointX );
        stat = attributeAffects( aSubd, aPointY );
        stat = attributeAffects( aSubd, aPointZ );
        stat = attributeAffects( aSubd, aNormal );
        stat = attributeAffects( aSubd, aNormalX );
        stat = attributeAffects( aSubd, aNormalY );
        stat = attributeAffects( aSubd, aNormalZ );

        stat = attributeAffects( aFaceFirst, aPoint );
        stat = attributeAffects( aFaceFirst, aPointX );
        stat = attributeAffects( aFaceFirst, aPointY );
        stat = attributeAffects( aFaceFirst, aPointZ );
        stat = attributeAffects( aFaceFirst, aNormal );
        stat = attributeAffects( aFaceFirst, aNormalX );
        stat = attributeAffects( aFaceFirst, aNormalY );
        stat = attributeAffects( aFaceFirst, aNormalZ );

        stat = attributeAffects( aFaceSecond, aPoint );
        stat = attributeAffects( aFaceSecond, aPointX );
        stat = attributeAffects( aFaceSecond, aPointY );
        stat = attributeAffects( aFaceSecond, aPointZ );
        stat = attributeAffects( aFaceSecond, aNormal );
        stat = attributeAffects( aFaceSecond, aNormalX );
        stat = attributeAffects( aFaceSecond, aNormalY );
        stat = attributeAffects( aFaceSecond, aNormalZ );

        stat = attributeAffects( aU, aPoint );
        stat = attributeAffects( aU, aPointX );
        stat = attributeAffects( aU, aPointY );
        stat = attributeAffects( aU, aPointZ );
        stat = attributeAffects( aU, aNormal );
        stat = attributeAffects( aU, aNormalX );
        stat = attributeAffects( aU, aNormalY );
        stat = attributeAffects( aU, aNormalZ );

        stat = attributeAffects( aV, aPoint );
        stat = attributeAffects( aV, aPointX );
        stat = attributeAffects( aV, aPointY );
        stat = attributeAffects( aV, aPointZ );
        stat = attributeAffects( aV, aNormal );
        stat = attributeAffects( aV, aNormalX );
        stat = attributeAffects( aV, aNormalY );
        stat = attributeAffects( aV, aNormalZ );

        stat = attributeAffects( aRelativeUV, aPoint );
        stat = attributeAffects( aRelativeUV, aPointX );
        stat = attributeAffects( aRelativeUV, aPointY );
        stat = attributeAffects( aRelativeUV, aPointZ );
        stat = attributeAffects( aRelativeUV, aNormal );
        stat = attributeAffects( aRelativeUV, aNormalX );
        stat = attributeAffects( aRelativeUV, aNormalY );
        stat = attributeAffects( aRelativeUV, aNormalZ );

        return MS::kSuccess;

    }

    // ---------------------------------------------------------------

    MStatus initializePlugin( MObject obj )
    //
    //  Description:
    //      this method is called when the plug-in is loaded into Maya.  It
    //      registers all of the services that this plug-in provides with
    //      Maya.
    //
    //  Arguments:
    //      obj - a handle to the plug-in object (use MFnPlugin to access it)
    //
    {
        MStatus   status;
        MFnPlugin plugin( obj, PLUGIN_COMPANY, "3.0", "Any");

        status = plugin.registerNode( "pointOnSubd",
                                      pointOnSubd::id,
                                      pointOnSubd::creator,
                                      pointOnSubd::initialize );
        if (!status) {
            status.perror("registerNode");
            return status;
        }

        return status;
    }

    MStatus uninitializePlugin( MObject obj)
    //
    //  Description:
    //      this method is called when the plug-in is unloaded from Maya. It
    //      deregisters all of the services that it was providing.
    //
    //  Arguments:
    //      obj - a handle to the plug-in object (use MFnPlugin to access it)
    //
    {
        MStatus   status;
        MFnPlugin plugin( obj );

        status = plugin.deregisterNode( pointOnSubd::id );
        if (!status) {
            status.perror("deregisterNode");
            return status;
        }

        return status;
    }