simpleLoftNode.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/MItCurveCV.h>
#include <maya/MDagPath.h>

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

    virtual MStatus     compute( const MPlug& plug, MDataBlock& data );
    MObject             loft( MObject &curve, MObject &surfFn, MStatus &stat );

    static  void*       creator();
    static  MStatus     initialize();

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

MTypeId     simpleLoft::id( 0x80011 );
MObject     simpleLoft::inputCurve;
MObject     simpleLoft::outputSurface;

simpleLoft::~simpleLoft() {}

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

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

    inputCurve = typedAttr.create( "inputCurve", "in",
                 MFnNurbsCurveData::kNurbsCurve, &stat );

    if ( !stat ) {
        stat.perror("ERROR creating simpleLoft curve attribute");
        return stat;
    }

    outputSurface = typedAttr.create( "outputSurface", "out",
                MFnNurbsSurfaceData::kNurbsSurface, &stat );

    if ( !stat ) {
        stat.perror("ERROR creating simpleLoft surface attribute");
        return stat;
    }
    typedAttr.setStorable( false );

    stat = addAttribute( inputCurve );
        if (!stat) { stat.perror("addAttribute"); return stat;}
    stat = addAttribute( outputSurface );
        if (!stat) { stat.perror("addAttribute"); return stat;}

    stat = attributeAffects( inputCurve, outputSurface );
        if (!stat) { stat.perror("attributeAffects"); return stat;}

    return MS::kSuccess;
}

MObject simpleLoft::loft( MObject &curve, MObject &newSurfData, MStatus &stat )
{
    MFnNurbsSurface surfFn;

    MPointArray cvs;
    MDoubleArray ku, kv;
    MFnNurbsCurve curveFn (curve);

    stat = curveFn.getCVs (cvs, MSpace::kWorld);
    if ( stat != MS::kSuccess )
    {
        cerr << "Error in getting CVs: " << stat << endl;
        return MObject::kNullObj;
    }


    int i, j, k = cvs.length();

    // create knot vectors for U and V

    ku.append( 0.0 );
    ku.append( 0.0 );
    ku.append( 0.0 );

    ku.append( 1.0 );
    ku.append( 1.0 );
    ku.append( 1.0 );

    kv.append( 0.0 );
    kv.append( 0.0 );
    kv.append( 0.0 );

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

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

    // create cvs for the surface

    for ( i = 1; i < 4; i++ )
    {
        for ( j = 0; j < k; j++ )
        {
            MPoint point = cvs[j];
            point.z += (double) i;  // loft in Z by 1
            cvs.append( point );
        }
    }


    MObject surf = surfFn.create(
        cvs, ku, kv, 3, 3,
        MFnNurbsSurface::kOpen, MFnNurbsSurface::kOpen,
        false, newSurfData, &stat );

    if ( stat != MS::kSuccess )
    {
        cerr << "Error in creating surface: " << stat << endl;
        return MObject::kNullObj;
    }

    // stat = MGlobal::addToModel( surf );
    return surf;

}

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

    if ( plug == outputSurface )    // loft inputCurve into surface
    {
        MDataHandle inputData = data.inputValue( inputCurve, &stat );
        if( stat != MS::kSuccess )
        {
            cerr << "ERROR getting data: " << stat << endl;
            return stat;
        }

        MObject curve = inputData.asNurbsCurve();
        MFnNurbsCurve curveFn( curve, &stat );
        if( stat != MS::kSuccess )
        {
          cerr << "ERROR creating curve function set:" << stat << endl;
          return stat;
        }

        MDataHandle surfHandle = data.outputValue( simpleLoft::outputSurface );
        if( stat != MS::kSuccess )
        {
          cerr << "Error in getting data handle: " << stat << endl;
          return stat;
        }
        
        MFnNurbsSurfaceData dataCreator;
        MObject newSurfData = dataCreator.create( &stat );
        if ( stat != MS::kSuccess ) {
          cerr << "Error creating new nurbs surface data block: "
               << stat << endl;
          return stat;
        }
        
        /* MObject newSurf = */ loft( curve, newSurfData,  stat );
        if( stat != MS::kSuccess )
        {
          cerr << "Error in creating surface: " << stat << endl;
          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.
        surfHandle.set( newSurfData );
        
        stat = data.setClean( plug );
        if( stat != MS::kSuccess )
        {
          cerr << "Error in cleaning outputSurface plug: "
               << stat << endl;
          return stat;
        }
    }
    else
    {
        return MS::kUnknownParameter;
    }

    return MS::kSuccess;
}

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

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

    return status;
}

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

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

    return status;
}