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

# 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;
    }