pointOnSubdNode/pointOnSubdNode.cpp
 
 
 
pointOnSubdNode/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;
}