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

# fullLoftNode.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.
    // ==========================================================================
    //+

    #include <string.h>
    #include <maya/MIOStream.h>
    #include <math.h>

    #include <maya/MPxNode.h>
    #include <maya/MPxCommand.h>

    #include <maya/MFnNumericAttribute.h>
    #include <maya/MFnTypedAttribute.h>
    #include <maya/MFnPlugin.h>

    #include <maya/MFnNurbsCurve.h>
    #include <maya/MFnNurbsSurface.h>
    #include <maya/MFnNurbsCurveData.h>
    #include <maya/MFnNurbsSurfaceData.h>

    #include <maya/MPointArray.h>
    #include <maya/MDoubleArray.h>

    #include <maya/MString.h>
    #include <maya/MTypeId.h>
    #include <maya/MPlug.h>
    #include <maya/MDataBlock.h>
    #include <maya/MDataHandle.h>

    #include <maya/MGlobal.h>
    #include <maya/MDagPath.h>

    class fullLoft : public MPxNode
    {
    public:
                            fullLoft() {};
        virtual             ~fullLoft();

        virtual MStatus     compute( const MPlug& plug, MDataBlock& data );
        MObject             loft( MArrayDataHandle &inputArray, MObject &surfFn,
                                  MStatus &stat );
        static  void*       creator();
        static  MStatus     initialize();

    public:
        static  MObject     inputCurve;     // The input curve.
        static  MObject     outputSurface;  // The output surface
        static  MTypeId     id;             // The IFF type id
    };

    MTypeId     fullLoft::id( 0x80008 );
    MObject     fullLoft::inputCurve;
    MObject     fullLoft::outputSurface;

    // Error macro: if not successful, print error message and return failure.
    // Assumes that "stat" contains the error value
    // Note that if (!stat) is the most efficient way to test for failure
    #define PERRORfail(s) \
    if (!stat) { \
        stat.perror(s); \
        return stat; \
    }

    // Error macro: if not successful, print error message and return a NULL object
    // Assumes that "stat" contains the error value
    #define PERRORnull(s) \
    if (!stat) { \
        stat.perror(s); \
        return MObject::kNullObj; \
    }

    fullLoft::~fullLoft ()
    {
    }

    void* fullLoft::creator()
    {
        return new fullLoft();
    }

    MStatus fullLoft::initialize()
    {
        MStatus stat;
        MFnTypedAttribute typedAttr;

        inputCurve=typedAttr.create( "inputCurve", "in",
                                             MFnNurbsCurveData::kNurbsCurve,
                                             &stat );
        PERRORfail("initialize create input attribute");
        stat = typedAttr.setArray( true );
        PERRORfail("initialize set input attribute array");

        outputSurface=typedAttr.create( "outputSurface", "out",
                                                MFnNurbsSurfaceData::kNurbsSurface,
                                                &stat );
        PERRORfail("initialize create output attribute");
        stat = typedAttr.setStorable( false );
        PERRORfail("initialize set output attribute storable");

        stat = addAttribute( inputCurve );
        PERRORfail("addAttribute(inputCurve)");

        stat = addAttribute( outputSurface );
        PERRORfail("addAttribute(outputSurface)");

        stat = attributeAffects( inputCurve, outputSurface );
        PERRORfail("attributeAffects(inputCurve, outputSurface)");

        return MS::kSuccess;
    }

    MObject fullLoft::loft( MArrayDataHandle &inputArray, MObject &newSurfData,
                          MStatus &stat )
    {
        MFnNurbsSurface surfFn;
        MPointArray cvs;
        MDoubleArray ku, kv;
        int i, j;
        int numCVs;
        int numCurves = inputArray.elementCount ();

        // Ensure that we have at least 1 element in the input array
        // We must not do an inputValue on an element that does not
        // exist.
        if ( numCurves < 1 )
            return MObject::kNullObj;

        // Count the number of CVs
        inputArray.jumpToElement(0);
        MDataHandle elementHandle = inputArray.inputValue(&stat);
        if (!stat) {
            stat.perror("fullLoft::loft: inputValue");
            return MObject::kNullObj;
        }
        MObject countCurve (elementHandle.asNurbsCurve());
        MFnNurbsCurve countCurveFn (countCurve);
        numCVs = countCurveFn.numCVs (&stat);
        PERRORnull("fullLoft::loft counting CVs");

        // Create knot vectors for U and V
        // U dimension contains one CV from each curve, triple knotted
        for (i = 0; i < numCurves; i++)
        {
            ku.append (double (i));
            ku.append (double (i));
            ku.append (double (i));
        }

        // V dimension contains all of the CVs from one curve, triple knotted at
        // the ends
        kv.append( 0.0 );
        kv.append( 0.0 );
        kv.append( 0.0 );

        for ( i = 1; i < numCVs - 3; i ++ )
            kv.append( (double) i );

        kv.append( numCVs-3 );
        kv.append( numCVs-3 );
        kv.append( numCVs-3 );

        // Build the surface's CV array
        for (int curveNum = 0; curveNum < numCurves; curveNum++)
        {
            MObject curve (inputArray.inputValue ().asNurbsCurve ());
            MFnNurbsCurve curveFn (curve);
            MPointArray curveCVs;

            stat = curveFn.getCVs (curveCVs, MSpace::kWorld);
            PERRORnull("fullLoft::loft getting CVs");

            if (curveCVs.length() != (unsigned)numCVs)
                stat = MS::kFailure;
            PERRORnull("fullLoft::loft inconsistent number of CVs - rebuild curves");

            // Triple knot for every curve but the first
            int repeats = (curveNum == 0) ? 1 : 3;

            for (j = 0; j < repeats; j++)
                for ( i = 0; i < numCVs; i++ )
                    cvs.append (curveCVs [i]);

            stat = inputArray.next ();
        }
        MObject surf = surfFn.create(cvs, ku, kv, 3, 3,
                                     MFnNurbsSurface::kOpen,
                                     MFnNurbsSurface::kOpen,
                                     false, newSurfData, &stat );
        PERRORnull ("fullLoft::Loft create surface");

        return surf;
    }

    MStatus fullLoft::compute( const MPlug& plug, MDataBlock& data )
    {
        MStatus stat;

        if ( plug == outputSurface )    // loft inputCurves into surface
        {
            MArrayDataHandle inputArrayData = data.inputArrayValue( inputCurve,
                                                                    &stat );
            PERRORfail("fullLoft::compute getting input array data");
            MDataHandle surfHandle = data.outputValue( fullLoft::outputSurface );
            PERRORfail("fullLoft::compute getting output data handle");

            MFnNurbsSurfaceData dataCreator;
            MObject newSurfData = dataCreator.create( &stat );
            PERRORfail("fullLoft::compute creating new nurbs surface data block");

            /* MObject newSurf = */ loft(inputArrayData, newSurfData,  stat );
            // No error message is needed - fullLoft::loft will output one
            if (!stat)
                return stat;

            // newSurf is the new surface object, but it has been packed
            // into the datablock we created for it, and the data block
            // is what we must put onto the plug.
            stat = surfHandle.set( newSurfData );
            PERRORfail("fullLoft::compute setting surface handle");

            stat = data.setClean( plug );
            PERRORfail("fullLoft::compute cleaning outputSurface plug");
        }
        else
        {
            return MS::kUnknownParameter;
        }

        return MS::kSuccess;
    }

    MStatus initializePlugin( MObject obj )
    {
        MStatus   status;
        MFnPlugin plugin( obj, PLUGIN_COMPANY, "3.0", "Any");

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

        return status;
    }

    MStatus uninitializePlugin( MObject obj)
    {
        MStatus   status;
        MFnPlugin plugin( obj );

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

        return status;
    }