blindComplexDataCmd/blindComplexDataCmd.cpp
 
 
 
blindComplexDataCmd/blindComplexDataCmd.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 <maya/MIOStream.h>
#include <maya/MFnPlugin.h>
#include <maya/MString.h>
#include <maya/MArgList.h>

#include <maya/MPxCommand.h>

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

#include <maya/MFnDependencyNode.h>
#include <maya/MFnTypedAttribute.h>

#include <maya/MPxData.h>
#include <maya/MTypeId.h>
#include <maya/MPlug.h>  
#include <maya/MFnPluginData.h>
#include <maya/MFnNurbsCurve.h>

#include <assert.h>

struct CVData {

        MStatus readASCII( const MArgList&, unsigned& );
        MStatus writeASCII( ostream& );

        MStatus readBinary( istream& in );
        MStatus writeBinary( ostream& out );

        double  _doubleData;
        int             _intData;

        static CVData empty;
};

CVData CVData::empty;

//
// Proxy data class declaration
//

class blindComplexData : public MPxData
{
public:
    blindComplexData();
    blindComplexData( const unsigned int );
    virtual ~blindComplexData();

        //
        // Override methods in MPxData.
    virtual MStatus         readASCII( const MArgList&, unsigned& lastElement );
    virtual MStatus         readBinary( istream& in, unsigned length );
    virtual MStatus         writeASCII( ostream& out );
    virtual MStatus         writeBinary( ostream& out );

        //
        // Custom methods.
    virtual void                        copy( const MPxData& ); 

        MTypeId                 typeId() const; 
        MString                                 name() const;

        bool                            setLength( const unsigned int numCVs,
                                                                           const bool copyOldData = false );
        
        const CVData &operator [] ( const unsigned int index ) const;
        CVData &operator [] ( const unsigned int index );

        unsigned int                                    length() const;

        //
        // static methods and data.
        static const MString    typeName;
    static const MTypeId    id;
        static void*            creator();

private:

        bool indexOk( const unsigned int ) const;

        // 
        // any customized data can be declared here, in this case, an array of 
        // CVData that is associated with the CVs. 
        
        CVData*                                 _CVDataArrayPtr;        
        unsigned int                                    _length;
};

const MTypeId blindComplexData::id( 0x80002 );
const MString blindComplexData::typeName( "blindComplexData" );

class blindComplexDataCmd : public MPxCommand
{
public:
                                                blindComplexDataCmd();
        virtual                         ~blindComplexDataCmd(); 

        MStatus                         doIt( const MArgList& args );
        MStatus                         redoIt();
        MStatus                         undoIt();
        bool                            isUndoable() const;
        
public:
        static void*            creator();
        MItSelectionList*       iter;
};


//
// Proxy data class implementation
//

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

blindComplexData::blindComplexData()
    :_CVDataArrayPtr( NULL ),
         _length(0)
{
}

blindComplexData::~blindComplexData()
{
        delete [] _CVDataArrayPtr;
        _length = 0;
}

blindComplexData::blindComplexData( const unsigned int cvNum )
        : _length(0),
          _CVDataArrayPtr( NULL )
{
        setLength( cvNum );
}

//
// Set the length of the array  
bool blindComplexData::setLength ( const unsigned int cvNum, 
                                                                                 const bool copyOldData ) 
{
        bool ret = true;
        if ( _length != cvNum || _CVDataArrayPtr == NULL ) {
                CVData* ptr;
                if ( _length != 0 && ! copyOldData ) {
                        cerr << "warning: might be erasing previous data." << endl;
                }
                ptr = new CVData[cvNum];
                if ( ptr == NULL ) {
                        cerr << "out of memory, setLength() failed" << endl;
                        ret = false;
                } else {
                        if ( copyOldData ) {
                                if ( cvNum < _length ) {
                                        cerr << "warning: new size not big enough for old data." 
                                                 << endl;
                                }
                                for ( unsigned int i = 0; i < cvNum; i++ ) {
                                        ptr[i] = _CVDataArrayPtr[i];  
                                }
                        }
                        delete [] _CVDataArrayPtr;
                        _CVDataArrayPtr = ptr;
                        _length = cvNum;
                }
        } else {
                cerr << "warning: setLength() o.k., same length, no change." << endl;
        }
        return ret;
}

unsigned int blindComplexData::length ( ) const 
{
        return _length;
}

inline 
bool blindComplexData::indexOk( const unsigned int index ) const {
        return ( index < _length );
}

const CVData& blindComplexData::operator [] ( const unsigned int index ) const 
{
        if ( indexOk( index  ) ) {
                return _CVDataArrayPtr[index];
        } else {
                cerr << "indexing error.  operator [] failed, returning invalid object"
                         << endl;
                return CVData::empty;
        }
}

CVData &blindComplexData::operator [] ( const unsigned int index ) 
{
        if ( indexOk( index  ) ) {
                return _CVDataArrayPtr[index];
        } else {
                cerr << "indexing error.  operator [] failed, returning invalid object"
                         << endl;
                // 
                // to get away a compiler warning.
                return CVData::empty; 
        }
}

void blindComplexData::copy( const MPxData& other )
//
//  Deescription:
//      Perform a copy or a conversion
//
{ 
    if( other.typeId() == blindComplexData::id ) {
        const blindComplexData* otherData =
                                                                                (const blindComplexData*)&other;
                if ( _length != otherData->_length ) {
                        if ( ! setLength( otherData->_length ) ) {
                                return;
                        }
                } 
                for ( unsigned int i = 0; i < _length; i++ ) {
                        _CVDataArrayPtr[i] = (*otherData)[i];
                }

    } else {
        //  we need to convert to the other type based on its iff Tag
                cerr << "wrong data format!" << endl;
    }
    return;
}

MTypeId blindComplexData::typeId() const
{
        return blindComplexData::id;
}

MString blindComplexData::name() const
{ 
        return blindComplexData::typeName; 
}

MStatus blindComplexData::readASCII(  const MArgList& args,
                                                unsigned& lastParsedElement )
{
    MStatus status;
        int argLength = args.length();
    if( argLength > 0 ) {
                int numDataRecord = (argLength - lastParsedElement); 
                //
                // Note: a better solution to determine the number of records is to
                // write out the number of records in the writeASCII() routine.
                //
                if ( numDataRecord % 2 != 0 ) {
                        cerr << "warning: corrupted data for blindComplexData" << endl;
                }
                // 
                // 2 numbers per record.
                numDataRecord /= 2;
                setLength(numDataRecord); 
                for ( unsigned int i=0; i < _length; i++ ) {
                status = _CVDataArrayPtr[i].readASCII(args, lastParsedElement);
                        if ( status != MS::kSuccess ) {
                                return status;
                        }
                }
                return MS::kSuccess;
    } 
        return MS::kFailure;
}

MStatus CVData::readASCII ( const MArgList& args,
                                                        unsigned& lastParsedElement ) 
{
        MStatus status;
        _intData = args.asInt( lastParsedElement++, &status );
        if ( status == MS::kSuccess ) {
            _doubleData = args.asDouble( lastParsedElement++, &status );
        } 
        return status;
}
                                
MStatus CVData::writeASCII ( ostream& out )  
{
        out << _intData << " " << _doubleData << " ";
        return out.fail() ? MS::kFailure : MS::kSuccess;
}

MStatus blindComplexData::writeASCII( ostream& out )
{
        MStatus status;
        for ( unsigned int i=0; i < _length; i++ ) {
                status = _CVDataArrayPtr[i].writeASCII(out);
                if ( status != MS::kSuccess ) {
                        return MS::kFailure;
                }
        }
    return MS::kSuccess;
}

MStatus blindComplexData::readBinary( istream& in, unsigned length )
{
        MStatus status;
        if ( length > 0 ) {
                unsigned int recNum;
                in.read( (char*) &recNum, sizeof(recNum) );
                if ( ! in.fail() && recNum > 0 ) {
                        setLength(recNum); 
                        for ( unsigned int i=0; i < _length; i++ ) {
                                status = _CVDataArrayPtr[i].readBinary(in);
                                if ( status != MS::kSuccess ) {
                                        return status;
                                }
                        }
                }
        } else {
                return MS::kFailure;
        }
        return MS::kSuccess;
}

MStatus blindComplexData::writeBinary( ostream& out )
{
        MStatus status;
        out.write( (char*) &_length, sizeof(_length) );
        if ( ! out.fail() ) {
                for ( unsigned int i=0; i < _length; i++ ) {
                        status = _CVDataArrayPtr[i].writeBinary(out);
                        if ( status != MS::kSuccess ) {
                                return status; 
                        }
                }
        } else {
                return MS::kFailure;
        }
    return MS::kSuccess;
}

MStatus CVData::readBinary ( istream& in )
{
        in.read( (char*) &_intData, sizeof(_intData) );
        if ( !in.fail() ) {
                in.read( (char*) &_doubleData, sizeof(_doubleData) );
        } else {
                return MS::kFailure;
        }
        return in.fail() ? MS::kFailure : MS::kSuccess;
}
                                
MStatus CVData::writeBinary ( ostream& out )  
{
        out.write( (char*) &_intData, sizeof(_intData) );
        if ( !out.fail() ) {
                out.write( (char*) &_doubleData, sizeof(_doubleData) );
        } else {
                return MS::kFailure;
        }
        return out.fail() ? MS::kFailure : MS::kSuccess;
}


//
// Command class implementation
//

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

blindComplexDataCmd::~blindComplexDataCmd()
{
}

blindComplexDataCmd::blindComplexDataCmd()
        : MPxCommand()
{
}

MStatus blindComplexDataCmd::doIt( const MArgList& )
{
        MStatus stat;

        // Create a selection list iterator
        //
    MSelectionList list;
    MGlobal::getActiveSelectionList( list );
        iter = new MItSelectionList( list,      MFn::kInvalid, &stat    );
        if ( MS::kSuccess == stat )
                stat = redoIt();

        return stat;
}

MStatus blindComplexDataCmd::redoIt()
{
        MStatus     stat;                               // Status code
        MObject         dependNode;             // Selected dependency node

        // Iterate over all selected dependency nodes
        //
        for ( ; !iter->isDone(); iter->next() ) 
        {
                // Get the selected dependency node and create
                // a function set for it
                //
                if ( MS::kSuccess != iter->getDependNode( dependNode ) ) {
                        cerr << "Error getting the dependency node" << endl;
                        continue;
                }
                
                MFnDependencyNode fnDN( dependNode, &stat );
                if ( MS::kSuccess != stat ) {
                        cerr << "Error creating MFnDependencyNode" << endl;
                        continue;
                }

                // Create a new attribute for our blind data
                //
                // cout << "Creating attr..." << endl;
                
                MFnTypedAttribute fnAttr;
                const MString fullName( "blindComplexData" );
                const MString briefName( "BCD" );
                MObject newAttr = fnAttr.create( fullName, briefName,
                                                                                 blindComplexData::id );

                // Now add the new attribute to the current dependency node
                //
                // cout << "Adding attr..." << endl;
                fnDN.addAttribute( newAttr, MFnDependencyNode::kLocalDynamicAttr );
                
                //
                // now we will demonstrate setting the value by using a plug.
                MPlug plug( dependNode, newAttr );  

                //
                // create an instance of the blind data with an initial array size of
                // 5.
                blindComplexData * newData = new blindComplexData( 5 );

                //
                // initialized 
                // cout << "setting data values..." << endl;
                unsigned int i;
                for ( i= 0; i < newData->length(); i++ ) {
                        (*newData)[i]._intData = 10 + i;
                        (*newData)[i]._doubleData = 20.02 + i;
                }

                // 
                // setting the value for the plug.
                stat = plug.setValue( newData );

                //
                // The following code demonstrates the retrieving of data from the 
                // plug.
                MObject sData;
                stat = plug.getValue( sData );

                if ( stat != MS::kSuccess ) {
                        cerr << "error getting value off plug" << endl;
                        continue;
                }

                // 
                // Convert the data from an MObject back to a pointer to MPxData, then
                // cast it back to a pointer to blindComplexData.
                MFnPluginData pdFn( sData ); 
                blindComplexData* data =
                                                        ( blindComplexData* ) pdFn.constData( &stat );
                //
                // read the data, and set the result to the values set.
                
                clearResult();

                if ( NULL != data ) {
                        // cout << "retrieving data values..." << endl;
                        for ( i = 0; i < data->length(); i++ ) {
                                // cout << "rec #" << i << ": " << (*data)[i]._intData << ", "; 
                                // cout << (*data)[i]._doubleData << endl;
                                appendToResult((double) ((*data)[i]._intData));
                                appendToResult((*data)[i]._doubleData);
                        }
                } else {
                        // cout << "Null data" << endl;
                }

        }
        return MS::kSuccess;
}

MStatus blindComplexDataCmd::undoIt()
{
        return MS::kSuccess;
}

bool blindComplexDataCmd::isUndoable() const
{
        return true;
}


//
// The following routines are used to register/unregister
// the command we are creating within Maya
//
MStatus initializePlugin( MObject obj )
{ 
        MStatus   status;
        MFnPlugin plugin( obj, PLUGIN_COMPANY, "3.0", "Any" );

        status = plugin.registerData( "blindComplexData",
                                                  blindComplexData::id,
                                                  blindComplexData::creator );
        if (!status) {
                status.perror("registerData");
                return status;
        }

        status = plugin.registerCommand(  "blindComplexData",
                                                         blindComplexDataCmd::creator );
        if (!status) {
                plugin.deregisterData( blindComplexData::id );
                status.perror("registerCommand");
                return status;
        }

        return status;
}

MStatus uninitializePlugin( MObject obj)
{
        MStatus   status1, status2;
        MFnPlugin plugin( obj );

        status1 = plugin.deregisterCommand( "blindComplexData" );
        if (!status1) {
                status1.perror("deregisterCommand");
        }
        status2 = plugin.deregisterData( blindComplexData::id );
        if (!status2) {
                status2.perror("deregisterData");
        }

        if ( !status1 )
                return status1;
        return status2;
}