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

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

    //
    // This example is based on the lineManip.cpp example but
    // incorporates a manip container so that two lines can
    // be created as children.  The left line will change
    // translateX of the selected nodes.  The right line
    // will change scaleX of the selected node.

    /*
        // To show this example using MEL, run the following:

        loadPlugin lineManipContainer;
        lineManipContainerContext lineManipContainerContext1;
        setParent Shelf1;
        toolButton -cl toolCluster
                    -i1 "moveManip.xpm"
                    -t lineManipContainerContext1
                    lineManipContainer1;

        If the preceding commands were used to create the manipulator context,
        the following commands can destroy it:

            deleteUI lineManipContainerContext1;
            deleteUI lineManipContainer1;

    */

    #include "lineManipContainer.h"

    #include <maya/MHardwareRenderer.h>
    #include <maya/MIOStream.h>
    #include <maya/MMatrix.h>
    #include <maya/MPoint.h>
    #include <maya/MVector.h>
    #include <maya/MSelectionList.h>
    #include <maya/MItSelectionList.h>
    #include <maya/MFnTransform.h>
    #include <maya/MGlobal.h>
    #include <maya/MFnCamera.h>
    #include <maya/MTemplateManipulator.h>

    // Statics
    MTypeId lineManip::id( 0x81049 );
    MTypeId lineManipContainer::id( 0x8104A );

    // Utility class for returning line points
    class lineGeometry
    {
    public:
        static MPoint topPoint( bool rightLine = true ) {
            if ( rightLine )
                return MPoint( 1.0f, 1.0f, 0.0f );
            return MPoint( -1.0f, 1.0f, 0.0f );
        }
        static MPoint bottomPoint( bool rightLine = true ) {
            if ( rightLine )
                return MPoint( 1.0f, -1.0f, 0.0f );
            return MPoint( -1.0f, -1.0f, 0.0f );
        }
        static MPoint otherPoint() {
            return MPoint( 2.0f, -1.0f, 0.0f );
        }
    };

    //
    // class implementation
    //
    lineManip::lineManip()
    {
        // Setup the plane with a point on the
        // plane along with a normal
        MPoint pointOnPlane(lineGeometry::topPoint());
        // Normal = cross product of two vectors on the plane
        MVector normalToPlane = (MVector(lineGeometry::topPoint()) - MVector(lineGeometry::otherPoint())) ^
                        (MVector(lineGeometry::otherPoint()) - MVector(lineGeometry::bottomPoint()));
        // Necessary to normalize
        normalToPlane.normalize();
        plane.setPlane( pointOnPlane, normalToPlane );

        // default case
        affectScale = affectTranslate = false;
    }

    lineManip::~lineManip()
    {
        // No-op
    }

    // virtual
    void lineManip::draw(M3dView &view, const MDagPath &path,
                    M3dView::DisplayStyle style, M3dView::DisplayStatus status)
    {
        static MGLFunctionTable *gGLFT = 0;
        if ( 0 == gGLFT )
            gGLFT = MHardwareRenderer::theRenderer()->glFunctionTable();

        // Are we in the right view
        MDagPath dpath;
        view.getCamera(dpath);
        MFnCamera viewCamera(dpath);
        const char *nameBuffer = viewCamera.name().asChar();
        if ( 0 == nameBuffer )
            return;
        if ( ( 0 == strstr(nameBuffer,"persp") ) && ( 0 == strstr(nameBuffer,"front") ) )
            return;

        //
        bool rightLine = true;
        if ( affectTranslate )
                rightLine = false;

        // Populate the point arrays which are in local space
        // Return values change with setting of rightLine
        // boolean
        float top[4],bottom[4];
        lineGeometry::topPoint(rightLine).get(top);
        lineGeometry::bottomPoint(rightLine).get(bottom);

        // Depending on what's active, we modify the
        // end points with mouse deltas in local
        // space
        MGLuint active = 0;
        if ( glActiveName( active ) )
        {
            float *a = 0,*b = 0;
            if ( active == lineName )
            {
                a = &top[0]; b = &bottom[0];
            }

            if ( active != 0 )
            {
                a[0] += (float) mousePointGlName.x; a[1] += (float) mousePointGlName.y; a[2] += (float) mousePointGlName.z;
                b[0] += (float) mousePointGlName.x; b[1] += (float) mousePointGlName.y; b[2] += (float) mousePointGlName.z;
            }
        }

        // Begin the drawing
        view.beginGL();

        // Get the starting value of the pickable items
        MGLuint glPickableItem;
        glFirstHandle( glPickableItem );

        // Top
        lineName = glPickableItem;
        // Place before you draw the manipulator component that can
        // be pickable.
        colorAndName( view, glPickableItem, true, mainColor() );
        gGLFT->glBegin( MGL_LINES );
            gGLFT->glVertex3fv( top );
            gGLFT->glVertex3fv( bottom );
        gGLFT->glEnd();

        // End the drawing
        view.endGL();
    }

    // virtual
    MStatus lineManip::doPress( M3dView& view )
    {
        // Reset the mousePoint information on
        // a new press
        mousePointGlName = MPoint::origin;
        updateDragInformation();
        return MS::kSuccess;
    }

    // virtual
    MStatus lineManip::doDrag( M3dView& view )
    {
        updateDragInformation();
        return MS::kSuccess;
    }

    // virtual
     MStatus lineManip::doRelease( M3dView& view )
    {
        // Scale nodes on the selection list
        // No undo supported
        MSelectionList list;
        MGlobal::getActiveSelectionList( list );
        for ( MItSelectionList iter( list ); !iter.isDone(); iter.next() )
        {
            MObject node;
            MStatus status;
                iter.getDependNode( node );
            MFnTransform xform( node, &status );
            if ( MS::kSuccess == status )
            {
                if ( affectScale )
                {
                    double newScale[3];
                    newScale[0] = mousePointGlName.x + 1;
                    newScale[1] = mousePointGlName.y + 1;
                    newScale[2] = mousePointGlName.z + 1;
                    xform.setScale( newScale );
                }
                if ( affectTranslate )
                {
                    double newTranslate[3];
                    newTranslate[0] = mousePointGlName.x;
                    newTranslate[1] = mousePointGlName.y;
                    newTranslate[2] = mousePointGlName.z;
                    xform.setTranslation( newTranslate, MSpace::kObject );
                }
            }
        }
        return MS::kSuccess;
    }

     // Utility method for finding the mouse delta
    MStatus lineManip::updateDragInformation()
    {
        // Find the mouse point in local space
        MPoint localMousePoint;
        MVector localMouseDirection;
        if ( MS::kFailure == mouseRay( localMousePoint, localMouseDirection) )
            return MS::kFailure;

        // Find the intersection of the mouse point with the
        // manip plane
        MPoint mouseIntersectionWithManipPlane;
        if ( ! plane.intersect( localMousePoint, localMouseDirection,   mouseIntersectionWithManipPlane ) )
            return MS::kFailure;

        mousePointGlName = mouseIntersectionWithManipPlane;

        MGLuint active = 0;
        if ( glActiveName( active ) )
        {
            float start[4] = {0,0,0,0},end[4] = {0,0,0,0};
            if ( active == lineName )
            {
                //
                bool rightLine = true;
                if ( affectTranslate )
                        rightLine = false;

                lineGeometry::topPoint(rightLine).get(start);
                lineGeometry::bottomPoint(rightLine).get(end);
            }

            if ( active != 0 )
            {
                lineMath line;
                // Find a vector on the plane
                MPoint a( start[0], start[1], start[2] );
                MPoint b( end[0], end[1], end[2] );
                MPoint vab = a - b;
                // Define line with a point and a vector on the plane
                line.setLine( start, vab );
                MPoint cpt;
                // Find the closest point so that we can get the
                // delta change of the mouse in local space
                if ( line.closestPoint( mousePointGlName, cpt ) )
                {
                    mousePointGlName.x -= cpt.x;
                    mousePointGlName.y -= cpt.y;
                    mousePointGlName.z -= cpt.z;
                }
            }
        }
        return MS::kFailure;
    }

    //
    // Manip container
    //

    lineManipContainer::lineManipContainer()
    {
        // No-op
    }

    lineManipContainer::~lineManipContainer()
    {
        // No-op
    }

    // Make the children manipulators: left and
    // right lines
    MStatus lineManipContainer::createChildren()
    {
        MStatus status;

        MPxManipulatorNode *proxyManip = 0;

        MString manipTypeName("singleLineManip");
        MString manipName("rightLineManip");
        status = addMPxManipulatorNode( manipTypeName, manipName, proxyManip );
        if ( !status )
        {
            return MS::kFailure;
        }

        lineManip *rightManipPtr = (lineManip *) proxyManip;
        if ( rightManipPtr )
        {
            rightManipPtr->affectScale = true;
        }

        proxyManip = 0;
        manipTypeName = "singleLineManip";
        manipName = "leftLineManip";
        status = addMPxManipulatorNode( manipTypeName, manipName, proxyManip );
        if ( !status )
        {
            return MS::kFailure;
        }

        lineManip *leftManipPtr = (lineManip *) proxyManip;
        if ( leftManipPtr )
        {
            leftManipPtr->affectTranslate = true;
        }

        return status;
    }

    MStatus lineManipContainer::connectToDependNode(const MObject &node)
    {
        // No-op
        return MS::kSuccess;
    }

    // Drw the children and then draw our text info
    void lineManipContainer::draw(M3dView & view,
                                     const MDagPath &path,
                                     M3dView::DisplayStyle style,
                                     M3dView::DisplayStatus status)
    {
        MPxManipContainer::draw(view, path, style, status);

        //
        view.beginGL();

        MPoint textPos = nodeTranslation();
        MString str( "Two custom line manipulators");
        MString distanceText(str.asChar());
        view.drawText(distanceText, textPos, M3dView::kLeft);

        //
        view.endGL();
    }
    // Return the node translation
    MVector lineManipContainer::nodeTranslation() const
    {
        MFnDagNode dagFn(fNodePath);
        MDagPath path;
        dagFn.getPath(path);
        path.pop();  // pop from the shape to the transform
        MFnTransform transformFn(path);
        return transformFn.translation(MSpace::kWorld);
    }

    //
    // lineManipContainerContext: implemented as a template
    //

    class lineManipContainerContext;
    char contextName[] = "lineManipContainerContext";
    char manipulatorContainerNodeName[] = "lineManipContainer";

    class lineManipContainerContext :
        public MTemplateSelectionContext<contextName, lineManipContainerContext,
            MFn::kTransform, lineManipContainer, manipulatorContainerNodeName >
    {
    public:
        lineManipContainerContext() {}
        virtual ~lineManipContainerContext() {}

        virtual void namesOfAttributes(MStringArray& namesOfAttributes)
        {
            namesOfAttributes.append("scaleX");
            namesOfAttributes.append("translateX");
        }
    };

    //
    //  lineManipContainerContextCommand: implemented as a template
    //

    class lineManipContainerContextCommand;
    char contextCommandName[] = "lineManipContainerContext";

    class lineManipContainerContextCommand :
        public MTemplateContextCommand<contextCommandName, lineManipContainerContextCommand, lineManipContainerContext >
    {
    public:
        lineManipContainerContextCommand() {}
        virtual ~lineManipContainerContextCommand() {}
    };

    static lineManipContainerContextCommand _lineManipContainerContextCommand;

    //
    // Static methods
    //

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

    MStatus lineManip::initialize()
    {
        return MS::kSuccess;
    }

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

    MStatus lineManipContainer::initialize()
    {
        MStatus status;
        status = MPxManipContainer::initialize();
        return status;
    }

    //
    //  Entry points
    //

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

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

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

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

        return status;
    }

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

        status = plugin.deregisterNode( lineManip::id );
        if (!status)
        {
            status.perror("deregisterNode");
            return status;
        }
        status = plugin.deregisterNode(lineManipContainer::id);;
        if (!status)
        {
            status.perror("deregisterNode");
            return status;
        }
        status = _lineManipContainerContextCommand.deregisterContextCommand( obj );
        if (!status)
        {
            status.perror("deregisterContextCommand");
            return status;
        }

        return status;
    }