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

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

    //  File Name: narrowPolyViewer.cpp
    //
    //  Description:
    //      A simple test of the MPx3dModelView code.
    //      A view that allows multiple cameras to be added is made.
    //

    #include "narrowPolyViewer.h"

    #include <maya/MItDag.h>
    #include <maya/MStringArray.h>
    #include <maya/MGlobal.h>

    #include <maya/MPoint.h>
    #include <maya/MSelectionList.h>
    #include <maya/MItSelectionList.h>
    #include <maya/MFnMesh.h>
    #include <maya/MItMeshVertex.h>
    #include <maya/MItMeshPolygon.h>
    #include <maya/MPointArray.h>
    #include <maya/MIOStream.h>

    #if defined(OSMac_MachO_)
    #include <OpenGL/gl.h>
    #else
    #include <GL/gl.h>
    #endif

    #include <math.h>

    narrowPolyViewer::narrowPolyViewer()
    :   fDrawManips(true)
    ,   fLightTest(false)
    {
        setMultipleDrawEnable(true);
        tol = 10;
    }

    narrowPolyViewer::~narrowPolyViewer()
    {
    }

    MStatus narrowPolyViewer::setCameraList(const MDagPathArray &cameraList)
    //
    //  Description:
    //      Replace the contents of fCameraList with the passed list of cameras.
    //
    {
        setMultipleDrawEnable(true);
        fCameraList.clear();

        unsigned ii = 0;
        unsigned nCameras = cameraList.length();
        for (ii = 0; ii < nCameras; ++ii) {
            fCameraList.append(cameraList[ii]);
        }

        refresh();

        return MS::kSuccess;
    }

    MStatus narrowPolyViewer::getCameraList(MDagPathArray &cameraList) const
    //
    //  Description:
    //      Fills the passed camera list with the current camera list used by
    //      this view. The default camera is not added to the list. Also, the list
    //      is cleared of any previous values.
    //
    {
        cameraList.clear();

        unsigned ii = 0;
        unsigned nCameras = fCameraList.length();
        for (ii = 0; ii < nCameras; ++ii) {
            cameraList.append(fCameraList[ii]);
        }

        return MS::kSuccess;
    }

    MStatus narrowPolyViewer::getCameraList(MStringArray &cameraList) const
    //
    //  Description:
    //      Fills the passed camera list with the current camera list used by
    //      this view. The default camera is not added to the list. Also, the list
    //      is cleared of any previous values.
    //
    {
        cameraList.clear();

        unsigned ii = 0;
        unsigned nCameras = fCameraList.length();
        for (ii = 0; ii < nCameras; ++ii) {
            cameraList.append(fCameraList[ii].partialPathName());
        }

        return MS::kSuccess;
    }

    MStatus narrowPolyViewer::appendCamera(const MDagPath &camera)
    //
    //  Description:
    //      Append a camera to the list of cameras used by this view.
    //
    {
        MStatus ReturnStatus = fCameraList.append(camera);
        refresh(true);

        return ReturnStatus;
    }

    MStatus narrowPolyViewer::removeCamera(const MDagPath &camera)
    //
    //  Description:
    //      Removes the specified camera from the list of cameras. If the
    //      camera is not on the list, it is still considered removed.
    //
    {
        //  Loop backwards to avoid any array resize problems.
        //
        int ii = 0;
        bool cameraRemoved = false;
        int nCameras = (int)fCameraList.length();
        for (ii = nCameras - 1; ii >= 0; ii--) {
            if (camera == fCameraList[ii]) {
                fCameraList.remove(ii);
                cameraRemoved = true;
            }
        }

        if (cameraRemoved) {
            refresh();
        }
        return MS::kSuccess;
    }

    MStatus narrowPolyViewer::removeAllCameras()
    //
    //  Description:
    //      Remove all cameras from the list.
    //
    {
        MStatus ReturnStatus = fCameraList.clear();
        refresh();
        return ReturnStatus;
    }

    MString narrowPolyViewer::getCameraHUDName()
    {
        MString hudName("narrowPolyViewer: ");

        //  Oops, well this method should be non-const, or there
        //  should be a const version of get camera. For now, we will
        //  live with a cast.
        //
        MDagPath cameraPath;
        getCamera(cameraPath);

        cameraPath.pop();
        hudName += cameraPath.partialPathName();
        return hudName;
    }

    MStatus narrowPolyViewer::setIsolateSelect(MSelectionList &list)
    {
        setViewSelected(true);
        return setObjectsToView(list);
    }

    MStatus narrowPolyViewer::setIsolateSelectOff()
    {
        return setViewSelected(false);
    }

    MStatus narrowPolyViewer::setLightTest(MSelectionList &list)
    {
        MStatus ReturnStatus = MS::kSuccess;
        MItSelectionList it(list, MFn::kLight, &ReturnStatus);
        if (MS::kSuccess != ReturnStatus) {
            return ReturnStatus;
        }

        for (; !it.isDone(); it.next()) {
            MDagPath lightPath;
            if (MS::kSuccess != it.getDagPath(lightPath)) {
                continue;
            }

            fLightList.append(lightPath);
        }

        if (fLightList.length() > 0) {
            fLightTest = true;
        }

        return ReturnStatus;
    }

    void narrowPolyViewer::preMultipleDraw()
    {
        fCurrentPass = 0;
        fDrawManips = false;

        MDagPath oldCamera;
        MStatus status = getCamera(oldCamera);

        if (MS::kSuccess != status) {
            status.perror("M3dView::getCamera");
        }

        fOldCamera = oldCamera;

        displayHUD(false);

        //  Clear the test camera list
        //
        fTestCameraList.clear();

        // get the first item in the selection list
        MStatus stat;
        MSelectionList sList;
        MGlobal::getActiveSelectionList(sList);
        MDagPath dagPath;
        stat = sList.getDagPath(0, dagPath);
        if (stat != MS::kSuccess) return;
        MItMeshPolygon itMeshPolygon(dagPath, MObject::kNullObj, &stat);
        if (stat != MS::kSuccess) return;

        beginGL();

        // Iterate over all faces on the mesh
        for (; !itMeshPolygon.isDone(); itMeshPolygon.next())
        {
            MPointArray points;
            itMeshPolygon.getPoints(points, MSpace::kWorld, &stat);
            int length = points.length();

            // Only care about triangles
            if (length == 3)
            {
                // Iterate over all points on the triangle face and if the angle
                // between any 2 sides are less than the tolerance, then draw the
                // triangle white
                for (int i=0; i<length; i++)
                {
                    // get the points of the triangle
                    MPoint p = points[i];
                    MPoint p1 = points[(i+1)%length];
                    MPoint p2 = points[(i+2)%length];

                    // create the 2 adjacent vectors to the current point
                    MVector v1(p1 - p);
                    MVector v2(p2 - p);

                    // get the angle between the two vectors in degrees
                    double angle = v1.angle(v2) * 180 / 3.14159;

                    // Dump some data
                    #if 0
                    MString astr = "The angle is : ";
                    astr += angle;
                    astr += " tolerance : ";
                    astr += tol;
                    MGlobal::displayInfo( astr );
                    #endif

                    // if angle less than tolerance then draw the triangle white
                    if ( (fabs( angle - tol ) < .0001) || angle < tol )
                    {
                        glBegin(GL_POLYGON);
                            glVertex3f((float)points[0].x, (float)points[0].y, (float)points[0].z);
                            glVertex3f((float)points[1].x, (float)points[1].y, (float)points[1].z);
                            glVertex3f((float)points[2].x, (float)points[2].y, (float)points[2].z);
                        glEnd();
                        break;
                    }
                }
            }
        }

        endGL();
    }

    void narrowPolyViewer::postMultipleDraw()
    {
        MStatus status = setCamera(fOldCamera);
        fDrawManips = true;

        updateViewingParameters();
        if (MS::kSuccess != status) {
            status.perror("M3dView::setCamera");
        }
    }

    void narrowPolyViewer::preMultipleDrawPass(unsigned index)
    {
        fCurrentPass = index;
        MStatus status;

        if (MS::kSuccess != (status = setDisplayAxis(false))) {
            status.perror("M3dView::setDisplayAxis");
        }
        if (MS::kSuccess != (status = setDisplayAxisAtOrigin(false))) {
            status.perror("M3dView::setDisplayAxisAtOrigin");
        }
        if (MS::kSuccess != (status = setDisplayCameraAnnotation(false))) {
            status.perror("M3dView::setDisplayCameraAnnotation");
        }

        MDagPath dagPath;

        //  Draw the main camera first.
        //
        if (fCurrentPass == 0) {
            getCamera(dagPath);
        } else {
            unsigned nCameras = fCameraList.length();
            if (fCurrentPass <= nCameras) {
                dagPath = fCameraList[fCurrentPass-1];
            } else {
                cerr << "Error ... too many passes specified: "
                     << fCurrentPass << endl;
                return;
            }
        }

        if (MS::kSuccess != (status = setCameraInDraw(dagPath))) {
            status.perror("M3dView::setCamera");
            return;
        }

        //  Add the camera to the list of cameras used.
        //
        MString thisCameraPath = dagPath.partialPathName();
        fTestCameraList.append(thisCameraPath);

        //  Turn on the display of everything, then selectively disable
        //  things.
        //
        setObjectDisplay(M3dView::kDisplayEverything, true);

        //  Only draw manips and grids for the main cameras.
        //  Also do not draw lights, cameras, ikHandles, dimensions,
        //  and selection handles for non-main cameras.
        //
        if (dagPath == fOldCamera) {
            fDrawManips = true;
            setObjectDisplay(M3dView::kDisplayGrid, true);

            //  For testing purposes, verify that the display grid is
            //  properly set.
            //
            if (!objectDisplay(M3dView::kDisplayGrid)) {
                MGlobal::displayError("objectDisplay kDisplayGrid should be true!");
            }

            //  Add fog for the main camera
            //
            if (MS::kSuccess != (status = setFogEnabled(true))) {
                status.perror("M3dView::setFogEnabled");
            }

            if (!isFogEnabled()) {
                MGlobal::displayError("setFogEnabled did not work!");
            }

            //  Turn off background fog. If not set, background fog would be
            //  used.
            //
            setBackgroundFogEnabled(false);

            setObjectDisplay(M3dView::kDisplayLights, true);
            setObjectDisplay(M3dView::kDisplayCameras, true);
            setObjectDisplay(M3dView::kDisplayIkHandles, true);
            setObjectDisplay(M3dView::kDisplayDimensions, true);
            setObjectDisplay(M3dView::kDisplaySelectHandles, true);

            //  Draw some text in the main view.
            //
            MPoint textPos(0, 0, 0);
            MString str("Main View");
            drawText(str, textPos, M3dView::kLeft);
        } else {
            fDrawManips = false;
            setObjectDisplay(M3dView::kDisplayGrid, false);

            //  For testing purposes, verify that the display grid is
            //  properly set.
            //
            if (objectDisplay(M3dView::kDisplayGrid)) {
                MGlobal::displayError(
                    "objectDisplay kDisplayGrid should be false!");
            }

            if (MS::kSuccess != (status = setFogEnabled(false))) {
                status.perror("M3dView::setFogEnabled");
            }
            if (isFogEnabled()) {
                MGlobal::displayError("setFogEnabled did not work!");
            }

            setObjectDisplay(M3dView::kDisplayLights, false);
            setObjectDisplay(M3dView::kDisplayCameras, false);
            setObjectDisplay(M3dView::kDisplayIkHandles, false);
            setObjectDisplay(M3dView::kDisplayDimensions, false);
            setObjectDisplay(M3dView::kDisplaySelectHandles, false);
        }

        if (fLightTest) {
            unsigned step = 4;
            unsigned min = 0 + (fCurrentPass * step);
            unsigned max = (fCurrentPass * step);

            if (max > 0) {
                max--;
            }

            unsigned nLights = fLightList.length();
            if (nLights < min) {
                setLightingMode(kLightDefault);
            } else {
                if (nLights < max) {
                    max = nLights;
                }

                MSelectionList list;
                unsigned ii = 0;
                for (ii = min; ii < max; ii++) {
                list.add(fLightList[ii].node());
                }

                MGlobal::setActiveSelectionList(list);
                setLightingMode(kLightSelected);
            }
        } else {
            setLightingMode(kLightDefault);
        }

        //  Make every other pass alternate between shaded and wireframe.
        //
        if (fCurrentPass % 2 == 0) {
            setObjectDisplay(M3dView::kDisplayNurbsSurfaces, true);
            setObjectDisplay(M3dView::kDisplayNurbsCurves, true);
        }

        updateViewingParameters();
    }

    void narrowPolyViewer::postMultipleDrawPass(unsigned index)
    {
        //  Until better control over selection and picking is exposed,
        //  turn on the display of everything after drawing. The selection
        //  methods will not consider things that are not visible.
        //
        //  If picking masks are to be used for the view, set them
        //  here.
        //
        setObjectDisplay(M3dView::kDisplayEverything, true);
    }

    bool narrowPolyViewer::okForMultipleDraw(const MDagPath &dagPath)
    {
        // Don't draw manipulators unless the fDrawManips value is true.
        //
        if (!fDrawManips && dagPath.hasFn(MFn::kManipulator3D)) {
            return false;
        }

        return true;
    }

    unsigned narrowPolyViewer::multipleDrawPassCount()
    {
        //  The camera list plus the main camera.
        //
        return fCameraList.length() + 1;
    }

    void narrowPolyViewer::removingCamera(MDagPath &cameraPath)
    //
    //  Description:
    //      A method that is called when the passed camera path is
    //      being deleted. Be sure to reemove any call to this
    //      camera.
    //
    {
        int ii = 0;
        int nCameras = (int)fCameraList.length();
        for (ii = nCameras - 1; ii >= 0; ii--) {
            if (cameraPath == fCameraList[ii]) {
                fCameraList.remove(ii);
            }
        }
    }

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

    MStatus narrowPolyViewer::copy(MPx3dModelView &src)
    //
    //  Description:
    //      Copy the contents for the src and put them
    //      into this.
    //
    {
        return MS::kSuccess;
    }

    MStatus narrowPolyViewer::swap(MPx3dModelView &src)
    //
    //  Description:
    //      Swap out the contents for the src and put them
    //      into this.
    //
    {
        return MS::kSuccess;
    }

    MString narrowPolyViewer::viewType() const
    //
    //  Description:
    //      Returns a string with the type of the view.
    //
    {
        return MString("narrowPolyViewer");
    }