customAttrManip/customAttrManip.cpp
 
 
 
customAttrManip/customAttrManip.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.
// ==========================================================================
//+

// 
// customAttrManip.cpp
// 
// This plug-in demonstrates how to create user-defined manipulators
// from a user-defined context.
//
// This is the script for running this plug-in:
// 
// loadPlugin "customAttrManip.so";
// source "customAttrManip.mel";
// sphere;
// move 5 0 0;
// cone;
// move -5 0 0;
// select -cl;
// 
// Now click on the customAttrManip on Shelf1!
// 

#include <maya/MIOStream.h>
#include <stdio.h>
#include <stdlib.h>

#include <maya/MFn.h>
#include <maya/MPxNode.h>
#include <maya/MPxManipContainer.h> 
#include <maya/MFnDistanceManip.h> 
#include <maya/MFnFreePointTriadManip.h> 
#include <maya/MFnDiscManip.h> 
#include <maya/MPxContext.h>
#include <maya/MPxSelectionContext.h>
#include <maya/MModelMessage.h>

#include <maya/MPxToolCommand.h>
#include <maya/MFnPlugin.h>
#include <maya/MArgList.h>
#include <maya/MGlobal.h>
#include <maya/MItSelectionList.h>
#include <maya/MPoint.h>
#include <maya/MVector.h>
#include <maya/MDagPath.h>

#include <maya/MFnTransform.h>
#include <maya/MItCurveCV.h>
#include <maya/MItSurfaceCV.h>
#include <maya/MItMeshVertex.h>

#include <maya/MPxSelectionContext.h>
#include <maya/MPxContextCommand.h>
#include <maya/M3dView.h>
#include <maya/MFnCamera.h>

#include <maya/MFnUnitAttribute.h>
#include <maya/MDistance.h>

#include <maya/MManipData.h>
#include <maya/MEulerRotation.h>
#include <maya/MQuaternion.h>


#define         customAttribute1String  "customManip1"
#define         customAttribute2String  "customManip2"
#define         customAttribute3String  "customManip3"

#define         scaleAttributeString    "customScaleAttr"

#define CHECKRESULT(stat,msg)     \
    if (MS::kSuccess != stat) {   \
        cerr << msg << endl;      \
    }

#ifdef LATER
        #define ADDMANIPFUNC            addDiscManip
        #define CUSTOMMANIPTYPE         MFnDiscManip
        #define MANIPDIRECTIONFUNC              setNormal
        #define MANIPPLUGCONN           connectToAnglePlug
#else
        #define ADDMANIPFUNC            addDistanceManip
        #define CUSTOMMANIPTYPE         MFnDistanceManip
        #define MANIPDIRECTIONFUNC              setDirection
        #define MANIPPLUGCONN           connectToDistancePlug
#endif

class customAttrManip : public MPxManipContainer
{
public:
    customAttrManip();
    virtual ~customAttrManip();
    
    static void * creator();
    static MStatus initialize();
    virtual MStatus createChildren();
    virtual MStatus connectToDependNode(const MObject &node);

        virtual MStatus doPress();
        virtual MStatus doDrag();
        virtual MStatus doRelease();

        virtual void draw(M3dView &view, 
                                                  const MDagPath &path, 
                                          M3dView::DisplayStyle style,
                                          M3dView::DisplayStatus status);

        MVector         nodeTranslation() const;
        MQuaternion     nodeRotation() const;

        void updateManipLocations();

    MDagPath fManip1;
    MDagPath fManip2;
    MDagPath fManip3;

        MDagPath fNodePath;

public:
    static MTypeId id;
};


MTypeId customAttrManip::id( 0x80020 );

customAttrManip::customAttrManip() 
{ 
    // Do not call createChildren from here - 
    // MayaPtr has not been set up yet.
}


customAttrManip::~customAttrManip() 
{
}


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


MStatus customAttrManip::initialize()
{ 
    MStatus stat;
    stat = MPxManipContainer::initialize();
    return stat;
}

// Do nothing special for now
MStatus  customAttrManip::doPress()
{
        // This is the safe definition as the base class, so it could be removed
        // It's simply here to show what return value is needed to force Maya
        // to also handle the event
        return MS::kUnknownParameter;
}

// Do nothing special for now
MStatus  customAttrManip::doDrag()
{
        return MS::kUnknownParameter;
}

//
// Snap the manip to the object's new location, since the custom Attrs
// may have somehow moved it
//
MStatus  customAttrManip::doRelease()
{
        // Custom release handling
        updateManipLocations();

        // Let Maya do it's work too
        return MS::kUnknownParameter;
}

MStatus customAttrManip::createChildren()
{
    MStatus stat = MStatus::kSuccess;

    MString pointManipName1("customtManip1");
    MString pointName1("customPoint1");
    fManip1 = ADDMANIPFUNC(pointManipName1, pointName1);

    MString pointManipName2("customtManip2");
    MString pointName2("customPoint2");
    fManip2 = ADDMANIPFUNC(pointManipName2, pointName2);

    MString pointManipName3("customtManip3");
    MString pointName3("customPoint3");
    fManip3 = ADDMANIPFUNC(pointManipName3, pointName3);

    return stat;
}

MQuaternion customAttrManip::nodeRotation() const
{
        //
        //  Since this is a manip, we're working directly on the transform
        //  no need to move up the dag path, which is done for locators
        //
        
        MFnDagNode dagFn(fNodePath);
        MDagPath path;
        dagFn.getPath(path);
        MFnTransform transformFn(path);
        MQuaternion q;
        transformFn.getRotation( q, MSpace::kWorld );
        return q;
}

MVector customAttrManip::nodeTranslation() const
{
        //
        //  Since this is a manip, we're working directly on the transform
        //  no need to move up the dag path, which is done for locators
        //
        
        MFnDagNode dagFn(fNodePath);
        MDagPath path;
        dagFn.getPath(path);
        MFnTransform transformFn(path);
        return transformFn.translation(MSpace::kWorld);
}

void customAttrManip::updateManipLocations()
{
        MVector  trans = nodeTranslation();
        MQuaternion  q = nodeRotation();

        CUSTOMMANIPTYPE freePointManipFn1(fManip1);
        CUSTOMMANIPTYPE freePointManipFn2(fManip2);
        CUSTOMMANIPTYPE freePointManipFn3(fManip3);

        MVector vecX(1.0, 0.0, 0.0);
        MVector vecY(0.0, 1.0, 0.0);
        MVector vecZ(0.0, 0.0, 1.0);

        freePointManipFn1.MANIPDIRECTIONFUNC(vecX);
        freePointManipFn1.rotateBy(q);
        freePointManipFn1.setTranslation(trans, MSpace::kWorld);

        freePointManipFn2.MANIPDIRECTIONFUNC(vecY);
        freePointManipFn2.rotateBy(q);
        freePointManipFn2.setTranslation(trans, MSpace::kWorld);

        freePointManipFn3.MANIPDIRECTIONFUNC(vecZ);
        freePointManipFn3.rotateBy(q);
        freePointManipFn3.setTranslation(trans, MSpace::kWorld);
}

MStatus customAttrManip::connectToDependNode(const MObject &node)
{
    MStatus stat;

        // Get the DAG path
        //
        MFnDagNode dagNodeFn(node);
        dagNodeFn.getPath(fNodePath);

    // Connect the plugs
    //    

    MFnDependencyNode nodeFn(node);    

        CUSTOMMANIPTYPE freePointManipFn1(fManip1);
        CUSTOMMANIPTYPE freePointManipFn2(fManip2);
        CUSTOMMANIPTYPE freePointManipFn3(fManip3);

    MPlug cPlug1 = nodeFn.findPlug(customAttribute1String, &stat);
        if( stat != MStatus::kSuccess )
        {
                cerr << "Can't find dynamic attr -- " << customAttribute1String << endl;
        }
        else
        {
                freePointManipFn1.MANIPPLUGCONN(cPlug1);
        }

    MPlug cPlug2 = nodeFn.findPlug(customAttribute2String, &stat);
        if( stat != MStatus::kSuccess )
        {
                cerr << "Can't find dynamic attr -- " << customAttribute1String << endl;
        }
        else
        {
                freePointManipFn2.MANIPPLUGCONN(cPlug2);
        }

    MPlug cPlug3 = nodeFn.findPlug(customAttribute3String, &stat);
        if( stat != MStatus::kSuccess )
        {
                cerr << "Can't find dynamic attr -- " << customAttribute1String << endl;
        }
        else
        {
                freePointManipFn3.MANIPPLUGCONN(cPlug3);
        }
    finishAddingManips();


    MPlug cPlug4 = nodeFn.findPlug(scaleAttributeString, &stat);
        if( stat != MStatus::kSuccess )
        {
                cerr << "Can't find dynamic attr -- " << scaleAttributeString << endl;
        }
        else
        {
                double factor;
                cPlug4.getValue( factor );

                freePointManipFn1.setScalingFactor( factor );
                freePointManipFn2.setScalingFactor( factor );
                freePointManipFn3.setScalingFactor( factor );
        }

        updateManipLocations();

    MPxManipContainer::connectToDependNode(node);        

    return stat;
}


void customAttrManip::draw(M3dView & view, 
                                         const MDagPath & path, 
                                         M3dView::DisplayStyle style,
                                         M3dView::DisplayStatus status)
{ 
    MPxManipContainer::draw(view, path, style, status);
/*      
    view.beginGL(); 

    MPoint textPos(0, 0, 0);
    char str[100];
    sprintf(str, "Stretch Me!"); 
    MString distanceText(str);
    view.drawText(distanceText, textPos, M3dView::kLeft);

    view.endGL();
        */
}



//
// The customAttrManip Context
//
// - tool contexts are custom event handlers. The selection
//   context class defaults to maya's selection mode and
//   allows you to override press/drag/release events.
//
#define MOVEHELPSTR             "Drag rings to change values on custom attributes"
#define MOVETITLESTR    "customAttrManip"


class customAttrCtx : public MPxSelectionContext
{
public:
    customAttrCtx();

    virtual void    toolOnSetup(MEvent &event);
    virtual void    toolOffCleanup();
    virtual MStatus doEnterRegion(MEvent &event);

    customAttrManip * caManip;
};


void updateManipulators(void * data);
MCallbackId id1;


customAttrCtx::customAttrCtx()
{
    MString str(MOVETITLESTR);
    setTitleString(str);
}


void customAttrCtx::toolOnSetup(MEvent &)
{
    MString str(MOVEHELPSTR);
    setHelpString(str);

        updateManipulators(this);
        MStatus status;
        id1 = MModelMessage::addCallback(MModelMessage::kActiveListModified,
                                                                         updateManipulators, 
                                                                         this, &status);
        if (!status) {
                cerr << "Model addCallback failed\n";
        }
}


void customAttrCtx::toolOffCleanup()
{
    MStatus status;
        status = MModelMessage::removeCallback(id1);
        if (!status) {
                cerr << "Model remove callback failed\n";
        }
        MPxContext::toolOffCleanup();
}

void updateManipulators(void * data)
{
    //cerr << "\n\n -- Active List Changed callback -- " << endl;

    MStatus stat = MStatus::kSuccess;
        
        customAttrCtx * ctxPtr = (customAttrCtx *) data;
        ctxPtr->deleteManipulators(); 

    // iterate through the selected objects:
    // 
    MSelectionList list;
    stat = MGlobal::getActiveSelectionList(list);
    MItSelectionList iter(list, MFn::kInvalid, &stat);

    if (MS::kSuccess == stat) {
        for (; !iter.isDone(); iter.next()) {
            // create the customAttrManip for each object selected:
            //
            MString manipName ("customAttrManip");
            MObject manipObject;
            ctxPtr->caManip = (customAttrManip *) customAttrManip::newManipulator(manipName, manipObject);

            if (NULL != ctxPtr->caManip) {
                            ctxPtr->addManipulator(manipObject);

                MObject dependNode;
                iter.getDependNode(dependNode);
                MFnDependencyNode dependNodeFn(dependNode);

                                //cerr << "Iterating on node " << dependNodeFn.name().asChar() << endl;

                dependNodeFn.findPlug(customAttribute1String, &stat);
                if (MStatus::kSuccess != stat) {
                    cerr << "dependNodeFn.findPlug failed\n";
                                        ctxPtr->deleteManipulators(); 
                                        return;
                }
                dependNodeFn.findPlug(customAttribute2String, &stat);
                if (MStatus::kSuccess != stat) {
                    cerr << "dependNodeFn.findPlug failed\n";
                                        ctxPtr->deleteManipulators(); 
                                        return;
                }
                dependNodeFn.findPlug(customAttribute3String, &stat);
                if (MStatus::kSuccess != stat) {
                    cerr << "dependNodeFn.findPlug failed\n";
                                        ctxPtr->deleteManipulators(); 
                                        return;
                }
                else {
                    //cerr << "dependNodeFn.findPlug succeed\n";
                }
                ctxPtr->caManip->connectToDependNode(dependNode);
            } 
        }
    }
}


MStatus customAttrCtx::doEnterRegion(MEvent &event)
//
// Print the tool description in the help line.
//
{
    MString str(MOVEHELPSTR);
    return setHelpString(str);
}


//
// Context creation command
//
//  This is the command that will be used to create instances
//  of our context.
//
#define CREATE_CTX_NAME "customAttrManipContext"


class customAttrCtxCommand : public MPxContextCommand
{
public:
    customAttrCtxCommand() {};
    virtual MPxContext * makeObj();

public:
    static void* creator();
};


MPxContext *customAttrCtxCommand::makeObj()
{
    customAttrCtx *newC = new customAttrCtx();
        return newC;
}


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


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

    status = plugin.registerContextCommand(CREATE_CTX_NAME,
                                                                                   &customAttrCtxCommand::creator);

    if (!status) 
        {
        status.perror("registerContextCommand");
        return status;
    }

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


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

    status = plugin.deregisterContextCommand(CREATE_CTX_NAME);
    if (!status) {
        status.perror("deregisterContextCommand");
        return status;
    }

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