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

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

    //
    // apiSimpleShapeUI.cpp
    //

    #include <maya/MIOStream.h>

    #include <apiSimpleShapeUI.h>

    #include <maya/MMaterial.h>
    #include <maya/MSelectionList.h>
    #include <maya/MSelectionMask.h>
    #include <maya/MDrawData.h>
    #include <maya/MMatrix.h>
    #include <maya/MFnSingleIndexedComponent.h>
    #include <maya/MObjectArray.h>
    #include <maya/MDagPath.h>

    // Object and component color defines
    //
    #define LEAD_COLOR              18  // green
    #define ACTIVE_COLOR            15  // white
    #define ACTIVE_AFFECTED_COLOR   8   // purple
    #define DORMANT_COLOR           4   // blue
    #define HILITE_COLOR            17  // pale blue
    #define DORMANT_VERTEX_COLOR    8   // purple
    #define ACTIVE_VERTEX_COLOR     16  // yellow

    // Vertex point size
    //
    #define POINT_SIZE              2.0

    //
    // UI implementation
    //

    apiSimpleShapeUI::apiSimpleShapeUI() {}
    apiSimpleShapeUI::~apiSimpleShapeUI() {}

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

    //
    // Overrides
    //

    /* override */
    void apiSimpleShapeUI::getDrawRequests( const MDrawInfo & info,
                                 bool objectAndActiveOnly,
                                 MDrawRequestQueue & queue )
    //
    // Description:
    //
    //     Add draw requests to the draw queue
    //
    // Arguments:
    //
    //     info                 - current drawing state
    //     objectsAndActiveOnly - no components if true
    //     queue                - queue of draw requests to add to
    //
    {
        // Get the data necessary to draw the shape
        //
        MDrawData data;
        apiSimpleShape* shape = (apiSimpleShape*) surfaceShape();
        MVectorArray* geomPtr = shape->getControlPoints();

        // This call creates a prototype draw request that we can fill
        // in and then add to the draw queue.
        //
        MDrawRequest request = info.getPrototype( *this );

        // Stuff our data into the draw request, it'll be used when the drawing
        // actually happens
        getDrawData( geomPtr, data );

        request.setDrawData( data );

        // Decode the draw info and determine what needs to be drawn
        //

        M3dView::DisplayStyle  appearance    = info.displayStyle();
        M3dView::DisplayStatus displayStatus = info.displayStatus();

        switch ( appearance )
        {
            case M3dView::kWireFrame :
            {
                request.setToken( kDrawWireframe );

                M3dView::ColorTable activeColorTable = M3dView::kActiveColors;
                M3dView::ColorTable dormantColorTable = M3dView::kDormantColors;

                switch ( displayStatus )
                {
                    case M3dView::kLead :
                        request.setColor( LEAD_COLOR, activeColorTable );
                        break;
                    case M3dView::kActive :
                        request.setColor( ACTIVE_COLOR, activeColorTable );
                        break;
                    case M3dView::kActiveAffected :
                        request.setColor( ACTIVE_AFFECTED_COLOR, activeColorTable );
                        break;
                    case M3dView::kDormant :
                        request.setColor( DORMANT_COLOR, dormantColorTable );
                        break;
                    case M3dView::kHilite :
                        request.setColor( HILITE_COLOR, activeColorTable );
                        break;

                    default:
                            break;
                }

                queue.add( request );

                break;
            }

            case M3dView::kGouraudShaded :
            {
                // Create the smooth shaded draw request
                //
                request.setToken( kDrawSmoothShaded );

                // Need to get the material info
                //
                MDagPath path = info.multiPath();   // path to your dag object
                M3dView view = info.view();;        // view to draw to
                MMaterial material = MPxSurfaceShapeUI::material( path );

                // Evaluate the material and if necessary, the texture.
                //
                if ( ! material.evaluateMaterial( view, path ) ) {
                    cerr << "Couldnt evaluate\n";
                }

                bool drawTexture = true;
                if ( drawTexture && material.materialIsTextured() ) {
                    material.evaluateTexture( data );
                }

                request.setMaterial( material );

                // request.setDisplayStyle( appearance );

                bool materialTransparent = false;
                material.getHasTransparency( materialTransparent );
                if ( materialTransparent ) {
                    request.setIsTransparent( true );
                }

                queue.add( request );

                // create a draw request for wireframe on shaded if
                // necessary.
                //
                if ( (displayStatus == M3dView::kActive) ||
                     (displayStatus == M3dView::kLead) ||
                     (displayStatus == M3dView::kHilite) )
                {
                    MDrawRequest wireRequest = info.getPrototype( *this );
                    wireRequest.setDrawData( data );
                    wireRequest.setToken( kDrawWireframeOnShaded );
                    wireRequest.setDisplayStyle( M3dView::kWireFrame );

                    M3dView::ColorTable activeColorTable = M3dView::kActiveColors;

                    switch ( displayStatus )
                    {
                        case M3dView::kLead :
                            wireRequest.setColor( LEAD_COLOR, activeColorTable );
                            break;
                        case M3dView::kActive :
                            wireRequest.setColor( ACTIVE_COLOR, activeColorTable );
                            break;
                        case M3dView::kHilite :
                            wireRequest.setColor( HILITE_COLOR, activeColorTable );
                            break;

                        default :
                            break;
                    }

                    queue.add( wireRequest );
                }

                break;
            }

            case M3dView::kFlatShaded :
                request.setToken( kDrawFlatShaded );
                break;

            default:
                break;

        }

        // Add draw requests for components
        //
        if ( !objectAndActiveOnly ) {

            // Inactive components
            //
            if ( (appearance == M3dView::kPoints) ||
                 (displayStatus == M3dView::kHilite) )
            {
                MDrawRequest vertexRequest = info.getPrototype( *this );
                vertexRequest.setDrawData( data );
                vertexRequest.setToken( kDrawVertices );
                vertexRequest.setColor( DORMANT_VERTEX_COLOR,
                                        M3dView::kActiveColors );

                queue.add( vertexRequest );
            }

            // Active components
            //
            if ( surfaceShape()->hasActiveComponents() ) {

                MDrawRequest activeVertexRequest = info.getPrototype( *this );
                activeVertexRequest.setDrawData( data );
                activeVertexRequest.setToken( kDrawVertices );
                activeVertexRequest.setColor( ACTIVE_VERTEX_COLOR,
                                              M3dView::kActiveColors );

                MObjectArray clist = surfaceShape()->activeComponents();
                MObject vertexComponent = clist[0]; // Should filter list
                activeVertexRequest.setComponent( vertexComponent );

                queue.add( activeVertexRequest );
            }
        }
    }

    /* override */
    void apiSimpleShapeUI::draw( const MDrawRequest & request, M3dView & view ) const
    //
    // Description:
    //
    //     Main (OpenGL) draw routine
    //
    // Arguments:
    //
    //     request - request to be drawn
    //     view    - view to draw into
    //
    {
        // Get the token from the draw request.
        // The token specifies what needs to be drawn.
        //
        int token = request.token();
        switch( token )
        {
            case kDrawWireframe :
            case kDrawWireframeOnShaded :
            case kDrawVertices :
                drawVertices( request, view );
                break;

            case kDrawSmoothShaded :
                break;          // Not implemented, left as exercise

            case kDrawFlatShaded : // Not implemented, left as exercise
                break;
        }
    }

    /* override */
    bool apiSimpleShapeUI::select( MSelectInfo &selectInfo, MSelectionList &selectionList,
                        MPointArray &worldSpaceSelectPts ) const
    //
    // Description:
    //
    //     Main selection routine
    //
    // Arguments:
    //
    //     selectInfo           - the selection state information
    //     selectionList        - the list of selected items to add to
    //     worldSpaceSelectPts  -
    //
    {
        bool selected = false;
        bool componentSelected = false;
        bool hilited = false;

        hilited = (selectInfo.displayStatus() == M3dView::kHilite);
        if ( hilited ) {
            componentSelected = selectVertices( selectInfo, selectionList, worldSpaceSelectPts );
            selected = selected || componentSelected;
        }

        if ( !selected )
        {
            // NOTE: If the geometry has an intersect routine it should
            // be called here with the selection ray to determine if the
            // the object was selected.

            selected = true;
            MSelectionMask priorityMask( MSelectionMask::kSelectNurbsSurfaces );
            MSelectionList item;
            item.add( selectInfo.selectPath() );
            MPoint xformedPt;
            if ( selectInfo.singleSelection() ) {
                MPoint center = surfaceShape()->boundingBox().center();
                xformedPt = center;
                xformedPt *= selectInfo.selectPath().inclusiveMatrix();
            }

            selectInfo.addSelection( item, xformedPt, selectionList,
                                     worldSpaceSelectPts, priorityMask, false );
        }

        return selected;
    }

    //
    // Helper routines
    //

    void apiSimpleShapeUI::drawVertices( const MDrawRequest & request,
                                  M3dView & view ) const
    //
    // Description:
    //
    //     Component (vertex) drawing routine
    //
    // Arguments:
    //
    //     request - request to be drawn
    //     view    - view to draw into
    //
    {
        MDrawData data = request.drawData();
        MVectorArray * geom = (MVectorArray*)data.geometry();

        view.beginGL();

        // Query current state so it can be restored
        //
        bool lightingWasOn = glIsEnabled( GL_LIGHTING ) ? true : false;
        if ( lightingWasOn ) {
            glDisable( GL_LIGHTING );
        }
        float lastPointSize;
        glGetFloatv( GL_POINT_SIZE, &lastPointSize );

        // Set the point size of the vertices
        //
        glPointSize( POINT_SIZE );

        // If there is a component specified by the draw request
        // then loop over comp (using an MFnComponent class) and draw the
        // active vertices, otherwise draw all vertices.
        //
        MObject comp = request.component();
        if ( ! comp.isNull() ) {
            MFnSingleIndexedComponent fnComponent( comp );
            for ( int i=0; i<fnComponent.elementCount(); i++ )
            {
                int index = fnComponent.element( i );
                glBegin( GL_POINTS );
                MVector& point = (*geom)[index];
                glVertex3f( (float)point[0],
                            (float)point[1],
                            (float)point[2] );
                glEnd();

                char annotation[32];
                sprintf( annotation, "%d", index );
                view.drawText( annotation, point );
            }
        }
        else {
            for ( unsigned int i=0; i<geom->length(); i++ )
            {
                glBegin( GL_POINTS );
                MVector point = (*geom)[ i ];
                glVertex3f( (float)point[0], (float)point[1], (float)point[2] );
                glEnd();
            }
        }

        // Restore the state
        //
        if ( lightingWasOn ) {
            glEnable( GL_LIGHTING );
        }
        glPointSize( lastPointSize );

        view.endGL();
    }

    bool apiSimpleShapeUI::selectVertices( MSelectInfo &selectInfo,
                                 MSelectionList &selectionList,
                                 MPointArray &worldSpaceSelectPts ) const
    //
    // Description:
    //
    //     Vertex selection.
    //
    // Arguments:
    //
    //     selectInfo           - the selection state information
    //     selectionList        - the list of selected items to add to
    //     worldSpaceSelectPts  -
    //
    {
        bool selected = false;
        M3dView view = selectInfo.view();

        MPoint      xformedPoint;
        MPoint      currentPoint;
        MPoint      selectionPoint;
        double      z,previousZ = 0.0;
        int         closestPointVertexIndex = -1;

        const MDagPath & path = selectInfo.multiPath();

        // Create a component that will store the selected vertices
        //
        MFnSingleIndexedComponent fnComponent;
        MObject surfaceComponent = fnComponent.create( MFn::kMeshVertComponent );
        int vertexIndex;

        // if the user did a single mouse click and we find > 1 selection
        // we will use the alignmentMatrix to find out which is the closest
        //
        MMatrix alignmentMatrix;
        MPoint singlePoint;
        bool singleSelection = selectInfo.singleSelection();
        if( singleSelection ) {
            alignmentMatrix = selectInfo.getAlignmentMatrix();
        }

        // Get the geometry information
        //
        apiSimpleShape* shape = (apiSimpleShape*) surfaceShape();
        MVectorArray* geomPtr = shape->getControlPoints();
        MVectorArray& geom = *geomPtr;

        // Loop through all vertices of the mesh and
        // see if they lie withing the selection area
        //
        int numVertices = geom.length();
        for ( vertexIndex=0; vertexIndex<numVertices; vertexIndex++ )
        {
            const MVector& point = geom[ vertexIndex ];

            // Sets OpenGL's render mode to select and stores
            // selected items in a pick buffer
            //
            view.beginSelect();

            glBegin( GL_POINTS );
            glVertex3f( (float)point[0],
                        (float)point[1],
                        (float)point[2] );
            glEnd();

            if ( view.endSelect() > 0 ) // Hit count > 0
            {
                selected = true;

                if ( singleSelection ) {
                    xformedPoint = currentPoint;
                    xformedPoint.homogenize();
                    xformedPoint*= alignmentMatrix;
                    z = xformedPoint.z;
                    if ( closestPointVertexIndex < 0 || z > previousZ ) {
                        closestPointVertexIndex = vertexIndex;
                        singlePoint = currentPoint;
                        previousZ = z;
                    }
                } else {
                    // multiple selection, store all elements
                    //
                    fnComponent.addElement( vertexIndex );
                }
            }
        }

        // If single selection, insert the closest point into the array
        //
        if ( selected && selectInfo.singleSelection() ) {
            fnComponent.addElement(closestPointVertexIndex);

            // need to get world space position for this vertex
            //
            selectionPoint = singlePoint;
            selectionPoint *= path.inclusiveMatrix();
        }

        // Add the selected component to the selection list
        //
        if ( selected ) {
            MSelectionList selectionItem;
            selectionItem.add( path, surfaceComponent );

            MSelectionMask mask( MSelectionMask::kSelectComponentsMask );
            selectInfo.addSelection(
                selectionItem, selectionPoint,
                selectionList, worldSpaceSelectPts,
                mask, true );
        }

        return selected;
    }