OpenGLViewportRenderer.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 <stdio.h>

#include <OpenGLViewportRenderer.h>

#include <maya/MGlobal.h>
#include <maya/MString.h>
#include <maya/MRenderingInfo.h>
#include <maya/MFnCamera.h>
#include <maya/MAngle.h>
#include <maya/MPoint.h>
#include <maya/MVector.h>

#include <maya/MItDag.h>
#include <maya/MMatrix.h>
#include <maya/MDagPath.h>
#include <maya/MFnDagNode.h>
#include <maya/MFnMesh.h>
#include <maya/MBoundingBox.h>


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

#include <maya/MDrawTraversal.h>
#include <maya/MGeometryManager.h>
#include <maya/MGeometry.h>
#include <maya/MGeometryData.h>
#include <maya/MGeometryPrimitive.h>
#include <maya/MHwTextureManager.h>
#include <maya/MImageFileInfo.h>

#include <maya/MFnSingleIndexedComponent.h>


#if MAYA_API_VERSION > 800
    #define _USE_MGL_FT_
    #include <maya/MGLFunctionTable.h>
    static MGLFunctionTable *gGLFT = NULL;
#else
    #if defined(OSMac_MachO_)
        #include <OpenGL/gl.h>
    #else
        #include <GL/gl.h>
    #endif
#endif

OpenGLViewportRendererHUD::OpenGLViewportRendererHUD()
: OpenGLViewportRenderer( "OpenGLViewportRendererHUD" )
{
    fUIName.set( "Plugin OpenGL Renderer HUD");
    fRenderingOverride = MViewportRenderer::kOverrideThenStandard;
}

unsigned int    OpenGLViewportRendererHUD::overrideThenStandardExclusion() const
{
    // exclude everything apart from manipulators
    return ~(unsigned int)kExcludeManipulators;
}

OpenGLViewportRendererFullUI::OpenGLViewportRendererFullUI()
: OpenGLViewportRenderer( "OpenGLViewportRendererFullUI" )
{
    fUIName.set( "Plugin OpenGL Renderer Full UI");
    fRenderingOverride = MViewportRenderer::kOverrideThenUI;
}

OpenGLViewportRenderer::OpenGLViewportRenderer( const MString & name )
:   MViewportRenderer( name )
{
    // Set the ui name
    fUIName.set( "Plugin OpenGL Renderer");

    // This renderer overrides all drawing
    fRenderingOverride = MViewportRenderer::kOverrideAllDrawing;

    // Set API and version number
    m_API = MViewportRenderer::kOpenGL;
    m_Version = 2.0f;
}

/* virtual */
OpenGLViewportRenderer::~OpenGLViewportRenderer()
{
    uninitialize();
}

/* virtual */
MStatus
OpenGLViewportRenderer::initialize()
{
#if defined(_USE_MGL_FT)
    // Get a pointer to a GL function table
    Tboolean useMGLFT = false;
    MHardwareRenderer *rend = MHardwareRenderer::theRenderer();
    if (rend)
        gGLFT = rend->glFunctionTable();
    if (!gGLFT)
        return MStatus::kFailure;
#endif
    return MStatus::kSuccess;
}

/* virtual */
MStatus
OpenGLViewportRenderer::uninitialize()
{
    gGLFT = NULL;
    return MStatus::kSuccess;
}

/* virtual */
MStatus
OpenGLViewportRenderer::render(const MRenderingInfo &renderInfo)
{
    //printf("Render using (%s : %s) renderer\n", fName.asChar(), fUIName.asChar());

    // Support direct rendering to an OpenGL context only.
    //
    if (renderInfo.renderingAPI() == MViewportRenderer::kOpenGL)
    {
        // This is not required as the target has already been made current
        // before the render() call.
        // renderTarget.makeTargetCurrent();

        // Do some rendering...
        renderToTarget( renderInfo );
    }
    return MStatus::kSuccess;
}

/* virtual */
bool
OpenGLViewportRenderer::nativelySupports( MViewportRenderer::RenderingAPI api,
                                       float version )
{
    // Do API check
    return (api == m_API);
}

/* virtual */ bool
OpenGLViewportRenderer::override( MViewportRenderer::RenderingOverride override )
{
    // Check override
    return (override == fRenderingOverride);
}

// Rendering methods
bool
OpenGLViewportRenderer::drawSurface( const MDagPath &dagPath, bool active, bool templated )
{

    bool drewSurface = false;
    if ( dagPath.hasFn( MFn::kMesh ))
    {
        MObject object = dagPath.node();
        MFnMesh mesh(object);

        // Figure out texturing
        //
        bool haveTexture = false;
        int numUVsets = mesh.numUVSets();
        MString uvSetName;
        MObjectArray textures;
        if (numUVsets > 0)
        {
            mesh.getCurrentUVSetName( uvSetName );
            MStatus status = mesh.getAssociatedUVSetTextures(uvSetName, textures);
            if (status == MS::kSuccess && textures.length())
            {
                haveTexture = true;
            }
        }

        bool haveColors = false;
        int numColors = mesh.numColorSets();
        MString colorSetName;
        if (numColors > 0)
        {
            haveColors = true;
            mesh.getCurrentColorSetName(colorSetName);
        }

        bool useNormals = false;

        // Setup our requirements needs.
        MGeometryRequirements requirements;
        requirements.addPosition();
        if (useNormals)
            requirements.addNormal();
        if (haveTexture)
            requirements.addTexCoord( uvSetName );
        if (haveColors)
            requirements.addColor( colorSetName );

        // Test for tangents and binormals
        bool testBinormal = false;
        if (testBinormal)
            requirements.addBinormal( uvSetName );
        bool testTangent= false;
        if (testTangent)
            requirements.addTangent( uvSetName );

        // Cheesy test for filtering out 3 components for drawing.
#if defined(_TEST_OGL_RENDERER_COMPONENT_FILTER_)
        MFnSingleIndexedComponent components;
        MObject comp = components.create( MFn::kMeshPolygonComponent );
        components.addElement( 1 );
        components.addElement( 200 );
        components.addElement( 5000 );
        MGeometry geom = MGeometryManager::getGeometry( dagPath, requirements, &comp );
#else
        MGeometry geom = MGeometryManager::getGeometry( dagPath, requirements, NULL );
#endif
        unsigned int numPrims = geom.primitiveArrayCount();
        if (numPrims)
        {
            const MGeometryPrimitive prim = geom.primitiveArray(0);

            unsigned int numElem = prim.elementCount();
            if (numElem)
            {
                //MGeometryData::ElementType primType = prim.dataType();
                unsigned int *idx = (unsigned int *) prim.data();

                // Get the position data
                const MGeometryData pos = geom.position();
                float * posPtr = (float * )pos.data();

                bool haveData = idx && posPtr;

                // Get the normals data
                float * normPtr = NULL;
                if (useNormals)
                {
                    const MGeometryData norm = geom.normal();
                    normPtr = (float * )norm.data();
                }

                // Get the texture coordinate data
                float *uvPtr = NULL;
                if (haveTexture)
                {
                    const MGeometryData uvs = geom.texCoord( uvSetName );
                    uvPtr = (float *)uvs.data();
                }

                unsigned int numColorComponents = 4;
                float *clrPtr = NULL;
                if (haveColors)
                {
                    const MGeometryData clrs = geom.color( colorSetName );
                    clrPtr = (float *)clrs.data();
                }
                else if (testBinormal)
                {
                    const MGeometryData binorm = geom.binormal( uvSetName );
                    clrPtr = (float *)binorm.data();
                    numColorComponents = 3;
                }
                else if (testTangent)
                {
                    const MGeometryData tang = geom.tangent( uvSetName );
                    clrPtr = (float *)tang.data();
                    numColorComponents = 3;
                }


                if (haveData)
                {
                    drewSurface = true;

                    bool drawWire = false;

                    MMatrix  matrix = dagPath.inclusiveMatrix();
                    #if defined(_USE_MGL_FT_)
                        gGLFT->glMatrixMode( MGL_MODELVIEW );
                        gGLFT->glPushMatrix();
                        gGLFT->glMultMatrixd( &(matrix.matrix[0][0]) );
                    #else
                        ::glMatrixMode( GL_MODELVIEW );
                        ::glPushMatrix();
                        ::glMultMatrixd( &(matrix.matrix[0][0]) );
                    #endif

                    // Setup state, and routing.
                    //
                    bool boundTexture = false;
                    if (uvPtr)
                    {
                        MImageFileInfo::MHwTextureType hwType;
                        if (MS::kSuccess == MHwTextureManager::glBind( textures[0], hwType ))
                        {
                            boundTexture = true;

                            #if defined(_USE_MGL_FT_)
                            gGLFT->glTexParameteri(MGL_TEXTURE_2D, MGL_TEXTURE_WRAP_S, MGL_REPEAT);
                            gGLFT->glTexParameteri(MGL_TEXTURE_2D, MGL_TEXTURE_WRAP_T, MGL_REPEAT);
                            gGLFT->glTexParameteri(MGL_TEXTURE_2D, MGL_TEXTURE_MIN_FILTER, MGL_LINEAR);
                            gGLFT->glTexParameteri(MGL_TEXTURE_2D, MGL_TEXTURE_MAG_FILTER, MGL_LINEAR);

                            if (!clrPtr)
                                gGLFT->glColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
                            gGLFT->glEnableClientState( MGL_TEXTURE_COORD_ARRAY );
                            gGLFT->glTexCoordPointer( 2, MGL_FLOAT, 0, uvPtr );

                            #else
                            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
                            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
                            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
                            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

                            if (!clrPtr)
                                glColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
                            glEnableClientState( GL_TEXTURE_COORD_ARRAY );
                            glTexCoordPointer( 2, GL_FLOAT, 0, uvPtr );

                            #endif

                            drawWire = false;
                        }
                    }

                    if (clrPtr)
                    {
                        #if defined(_USE_MGL_FT_)
                        gGLFT->glEnableClientState(MGL_COLOR_ARRAY);
                        gGLFT->glColorPointer( numColorComponents, MGL_FLOAT, 0, clrPtr );
                        #else
                        glEnableClientState(GL_COLOR_ARRAY);
                        glColorPointer( numColorComponents, GL_FLOAT, 0, clrPtr );
                        #endif
                    }

                    #if defined(_USE_MGL_FT_)
                    gGLFT->glEnableClientState( MGL_VERTEX_ARRAY );
                    gGLFT->glVertexPointer ( 3, MGL_FLOAT, 0, posPtr );
                    #else
                    glEnableClientState( GL_VERTEX_ARRAY );
                    glVertexPointer ( 3, GL_FLOAT, 0, posPtr );
                    #endif

                    if (normPtr)
                    {
                        #if defined(_USE_MGL_FT_)
                        gGLFT->glEnableClientState( MGL_NORMAL_ARRAY );
                        gGLFT->glNormalPointer (    MGL_FLOAT, 0, normPtr );
                        #else
                        glEnableClientState( GL_NORMAL_ARRAY );
                        glNormalPointer (    GL_FLOAT, 0, normPtr );
                        #endif
                        drawWire = false;
                    }

                    // Draw
                    if (drawWire)
                    {
                        #if defined(_USE_MGL_FT_)
                        gGLFT->glPolygonMode(MGL_FRONT_AND_BACK, MGL_LINE);
                        gGLFT->glDrawElements ( MGL_TRIANGLES, numElem, MGL_UNSIGNED_INT, idx );
                        gGLFT->glPolygonMode(MGL_FRONT_AND_BACK, MGL_FILL);

                        if (clrPtr)
                        {
                            gGLFT->glDisableClientState(MGL_COLOR_ARRAY);
                        }
                        #else
                        glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
                        glDrawElements ( GL_TRIANGLES, numElem, GL_UNSIGNED_INT, idx );
                        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

                        if (clrPtr)
                        {
                            glDisableClientState(GL_COLOR_ARRAY);
                        }
                        #endif
                    }
                    else
                    {
                        #if defined(_USE_MGL_FT_)
                        if (active)
                        {
                            gGLFT->glEnable(MGL_POLYGON_OFFSET_FILL);
                            gGLFT->glPolygonOffset( 0.95f, 1.0f );
                        }
                        gGLFT->glDrawElements ( MGL_TRIANGLES, numElem, MGL_UNSIGNED_INT, idx );
                        if (active)
                            gGLFT->glDisable(MGL_POLYGON_OFFSET_FILL);

                        if (normPtr)
                            gGLFT->glDisableClientState( MGL_NORMAL_ARRAY );
                        if (boundTexture)
                        {
                            gGLFT->glDisableClientState( MGL_TEXTURE_COORD_ARRAY );
                            gGLFT->glDisable(MGL_TEXTURE_2D);
                            gGLFT->glBindTexture(MGL_TEXTURE_2D, 0);
                        }
                        if (clrPtr)
                        {
                            gGLFT->glDisableClientState(MGL_COLOR_ARRAY);
                        }

                        if (active)
                        {
                            gGLFT->glColor3f( 1.0f, 1.0f, 1.0f );
                            gGLFT->glPolygonMode(MGL_FRONT_AND_BACK, MGL_LINE);
                            gGLFT->glDrawElements ( MGL_TRIANGLES, numElem, MGL_UNSIGNED_INT, idx );
                            gGLFT->glPolygonMode(MGL_FRONT_AND_BACK, MGL_FILL);
                        }
                        #else
                        if (active)
                        {
                            glEnable(GL_POLYGON_OFFSET_FILL);
                            glPolygonOffset( 0.95f, 1.0f );
                        }
                        glDrawElements ( GL_TRIANGLES, numElem, GL_UNSIGNED_INT, idx );
                        if (active)
                            glDisable(GL_POLYGON_OFFSET_FILL);

                        if (normPtr)
                            glDisableClientState( GL_NORMAL_ARRAY );
                        if (boundTexture)
                        {
                            glDisableClientState( GL_TEXTURE_COORD_ARRAY );
                            glDisable(GL_TEXTURE_2D);
                            glBindTexture(GL_TEXTURE_2D, 0);
                        }
                        if (clrPtr)
                        {
                            glDisableClientState(GL_COLOR_ARRAY);
                        }

                        if (active)
                        {
                            ::glColor3f( 1.0f, 1.0f, 1.0f );
                            glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
                            glDrawElements ( GL_TRIANGLES, numElem, GL_UNSIGNED_INT, idx );
                            glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
                        }
                        #endif
                    }


                    // Reset state, and routing.
                    #if defined(_USE_MGL_FT_)
                    gGLFT->glDisableClientState( MGL_VERTEX_ARRAY );
                    gGLFT->glPopMatrix();
                    #else
                    glDisableClientState( GL_VERTEX_ARRAY );
                    ::glPopMatrix();
                    #endif
                }
            }
        }
    }
    return drewSurface;
}

bool
OpenGLViewportRenderer::drawBounds( const MDagPath &dagPath,
                                    const MBoundingBox &box)
{
    MMatrix  matrix = dagPath.inclusiveMatrix();
    {
        MPoint  minPt = box.min();
        MPoint  maxPt = box.max();

        double bottomLeftFront[3] =     { minPt.x, minPt.y, minPt.z };
        double topLeftFront[3] =        { minPt.x, maxPt.y, minPt.z };
        double bottomRightFront[3] =    { maxPt.x, minPt.y, minPt.z };
        double topRightFront[3] =       { maxPt.x, maxPt.y, minPt.z };
        double bottomLeftBack[3] =      { minPt.x, minPt.y, maxPt.z };
        double topLeftBack[3] =         { minPt.x, maxPt.y, maxPt.z };
        double bottomRightBack[3] =     { maxPt.x, minPt.y, maxPt.z };
        double topRightBack[3] =        { maxPt.x, maxPt.y, maxPt.z };

        #if defined(_USE_MGL_FT_)
        gGLFT->glMatrixMode( MGL_MODELVIEW );
        gGLFT->glPushMatrix();
        gGLFT->glMultMatrixd( &(matrix.matrix[0][0]) );

        gGLFT->glBegin(MGL_LINE_STRIP);
        gGLFT->glVertex3dv( bottomLeftFront );
        gGLFT->glVertex3dv( bottomLeftBack );
        gGLFT->glVertex3dv( topLeftBack );
        gGLFT->glVertex3dv( topLeftFront );
        gGLFT->glVertex3dv( bottomLeftFront );
        gGLFT->glVertex3dv( bottomRightFront );
        gGLFT->glVertex3dv( bottomRightBack);
        gGLFT->glVertex3dv( topRightBack );
        gGLFT->glVertex3dv( topRightFront );
        gGLFT->glVertex3dv( bottomRightFront );
        gGLFT->glEnd();

        gGLFT->glBegin(MGL_LINES);
        gGLFT->glVertex3dv(bottomLeftBack);
        gGLFT->glVertex3dv(bottomRightBack);

        gGLFT->glVertex3dv(topLeftBack);
        gGLFT->glVertex3dv(topRightBack);

        gGLFT->glVertex3dv(topLeftFront);
        gGLFT->glVertex3dv(topRightFront);
        gGLFT->glEnd();

        gGLFT->glPopMatrix();
        #else
        ::glMatrixMode( GL_MODELVIEW );
        ::glPushMatrix();
        ::glMultMatrixd( &(matrix.matrix[0][0]) );

        ::glBegin(GL_LINE_STRIP);
        ::glVertex3dv( bottomLeftFront );
        ::glVertex3dv( bottomLeftBack );
        ::glVertex3dv( topLeftBack );
        ::glVertex3dv( topLeftFront );
        ::glVertex3dv( bottomLeftFront );
        ::glVertex3dv( bottomRightFront );
        ::glVertex3dv( bottomRightBack);
        ::glVertex3dv( topRightBack );
        ::glVertex3dv( topRightFront );
        ::glVertex3dv( bottomRightFront );
        ::glEnd();

        ::glBegin(GL_LINES);
        ::glVertex3dv(bottomLeftBack);
        ::glVertex3dv(bottomRightBack);

        ::glVertex3dv(topLeftBack);
        ::glVertex3dv(topRightBack);

        ::glVertex3dv(topLeftFront);
        ::glVertex3dv(topRightFront);
        ::glEnd();

        ::glPopMatrix();
        #endif
    }
    return true;
}

bool
OpenGLViewportRenderer::setupLighting()
{
    //glEnable(GL_LIGHT0);
    //glEnable(GL_LIGHTING);
    return false;
}

// Comment out #define to see how pruning works in this example
//
// #define _DEBUG_TRAVERSAL_PRUNING

// Use a custom traverser class.
class MsurfaceDrawTraversal : public MDrawTraversal
{
    virtual bool        filterNode( const MDagPath &traversalItem )
    {
        bool prune = false;

        // Check to only prune shapes, not transforms.
        //
#if defined(_DEBUG_TRAVERSAL_PRUNING)
        MString pname = traversalItem.fullPathName() ;
#endif
        if ( traversalItem.childCount() == 0)
        {
            if ( !traversalItem.hasFn( MFn::kMesh) &&
                !traversalItem.hasFn( MFn::kNurbsSurface) &&
                !traversalItem.hasFn( MFn::kSubdiv) &&
                !traversalItem.hasFn( MFn::kSketchPlane ) &&
                !traversalItem.hasFn( MFn::kGroundPlane )
                )
            {
#if defined(_DEBUG_TRAVERSAL_PRUNING)
                printf("Prune path [ %s ]\n", pname.asChar());
#endif
                prune = true;
            }
        }
        else
        {
#if defined(_DEBUG_TRAVERSAL_PRUNING)
            printf("Don't prune path [ %s ]\n", pname.asChar());
#endif
        }
        return prune;
    }

};

bool OpenGLViewportRenderer::renderToTarget( const MRenderingInfo &renderInfo )
//
// Description:
//      Render directly to current OpenGL target.
//
{

    const MRenderTarget &renderTarget = renderInfo.renderTarget();

    // Draw the world space axis
    //
    #if defined(_USE_MGL_FT_)
    gGLFT->glDisable(MGL_LIGHTING);
    gGLFT->glBegin(MGL_LINES);
    gGLFT->glColor3f( 1.0f, 0.0f, 0.0f );
    gGLFT->glVertex3f( 0.0f, 0.0f, 0.0f );
    gGLFT->glVertex3f( 3.0f, 0.0f, 0.0f );

    gGLFT->glColor3f( 0.0f, 1.0f, 0.0f );
    gGLFT->glVertex3f( 0.0f, 0.0f, 0.0f );
    gGLFT->glVertex3f( 0.0f, 3.0f, 0.0f );

    gGLFT->glColor3f( 0.0f, 0.0f, 1.0f );
    gGLFT->glVertex3f( 0.0f, 0.0f, 0.0f );
    gGLFT->glVertex3f( 0.0f, 0.0f, 3.0f );
    gGLFT->glEnd();
    gGLFT->glEnable(MGL_DEPTH_TEST);
    #else
    ::glDisable(GL_LIGHTING);
    ::glBegin(GL_LINES);
    ::glColor3f( 1.0f, 0.0f, 0.0f );
    ::glVertex3f( 0.0f, 0.0f, 0.0f );
    ::glVertex3f( 3.0f, 0.0f, 0.0f );

    ::glColor3f( 0.0f, 1.0f, 0.0f );
    ::glVertex3f( 0.0f, 0.0f, 0.0f );
    ::glVertex3f( 0.0f, 3.0f, 0.0f );

    ::glColor3f( 0.0f, 0.0f, 1.0f );
    ::glVertex3f( 0.0f, 0.0f, 0.0f );
    ::glVertex3f( 0.0f, 0.0f, 3.0f );
    ::glEnd();
    glEnable(GL_DEPTH_TEST);
    #endif


    // Draw some surfaces...
    //
    bool useDrawTraversal = true;
    if (useDrawTraversal)
    {
#if defined(_DEBUG_TRAVERSAL_PRUNING)
        printf("==========================\n");
#endif
        const MDagPath &cameraPath = renderInfo.cameraPath();
        if (cameraPath.isValid())
        {
            bool pruneDuringTraversal = true;

            // You can actually keep the traverser classes around
            // if desired. Here we just create temporary traversers
            // on the fly.
            //
            MDrawTraversal *trav = NULL;
            if (pruneDuringTraversal)
            {
                trav = new MsurfaceDrawTraversal;
                trav->enableFiltering( true );
            }
            else
            {
                trav = new MDrawTraversal;
                trav->enableFiltering( false );
            }
            if (!trav)
            {
                printf("Warning: failed to create a traversal class !\n");
                return true;
            }

            trav->setFrustum( cameraPath, renderTarget.width(),
                renderTarget.height() );

            if (!trav->frustumValid())
                printf("Warning : Frustum is invalid !\n");

            trav->traverse();

            unsigned int numItems = trav->numberOfItems();
#if defined(_DEBUG_TRAVERSAL_PRUNING)
            printf("There are %d items on the traversal list\n", numItems );
#endif
            if (numItems)
            {
                setupLighting();
            }

            unsigned int i;
            for (i=0; i<numItems; i++)
            {
                MDagPath path;
                trav->itemPath(i, path);

                if (path.isValid())
                {
                    bool drawIt = false;

                    // Default traverer may have view manips showing up.
                    // This is currently a known Maya bug.
                    if (!pruneDuringTraversal)
                        if ( path.hasFn( MFn::kViewManip ))
                            continue;

#if defined(_DEBUG_TRAVERSAL_PRUNING)
                    MString pname = path.fullPathName() ;
                    printf("Draw path [%d][ %s ]\n", i, pname.asChar());
#endif

                    //
                    // Draw surfaces (polys, nurbs, subdivs)
                    //
                    bool active = false;
                    bool templated = false;
                    if ( path.hasFn( MFn::kMesh) ||
                         path.hasFn( MFn::kNurbsSurface) ||
                         path.hasFn( MFn::kSubdiv) )
                    {
                        drawIt = true;
                        if (trav->itemHasStatus( i, MDrawTraversal::kActiveItem ))
                        {
                            active = true;
                            #if defined(_USE_MGL_FT_)
                            gGLFT->glColor3f( 1.0f, 1.0f, 1.0f );
                            #else
                            ::glColor3f( 1.0f, 1.0f, 1.0f );
                            #endif
                        }
                        else if (trav->itemHasStatus( i, MDrawTraversal::kTemplateItem ))
                        {
                            #if defined(_USE_MGL_FT_)
                            gGLFT->glColor3f( 0.2f, 0.2f, 0.2f );
                            #else
                            ::glColor3f( 0.2f, 0.2f, 0.2f );
                            #endif
                            templated = true;
                        }
                        else
                        {
                            #if defined(_USE_MGL_FT_)
                            if (path.hasFn( MFn::kMesh ))
                                gGLFT->glColor3f( 0.286f, 0.706f, 1.0f );
                            else if (path.hasFn( MFn::kNurbsSurface))
                                gGLFT->glColor3f( 0.486f, 0.306f, 1.0f );
                            else
                                gGLFT->glColor3f( 0.886f, 0.206f, 1.0f );
                            #else
                            if (path.hasFn( MFn::kMesh ))
                                ::glColor3f( 0.286f, 0.706f, 1.0f );
                            else if (path.hasFn( MFn::kNurbsSurface))
                                ::glColor3f( 0.486f, 0.306f, 1.0f );
                            else
                                ::glColor3f( 0.886f, 0.206f, 1.0f );
                            #endif
                        }
                    }

                    //
                    // Draw the ground plane
                    //
                    else if (path.hasFn( MFn::kSketchPlane ) ||
                             path.hasFn( MFn::kGroundPlane ))
                    {
                        drawIt = true;
                        #if defined(_USE_MGL_FT_)
                        gGLFT->glColor3f( 0.0f, 1.0f, 0.0f );
                        #else
                        ::glColor3f( 0.0f, 1.0f, 0.0f );
                        #endif
                    }

                    if (drawIt)
                    {
                        MFnDagNode dagNode(path);
                        if (!drawSurface( path, active, templated ))
                        {
                            MBoundingBox box = dagNode.boundingBox();
                            drawBounds( path, box );
                        }
                    }
                }
            }

            if (trav)
                delete trav;
        }
    }
    // Draw everything in the scene, without any culling or visibility
    // testing. This is just comparison code, and should never be
    // enabled, unless you want to do post-filtering...
    else
    {
        MItDag::TraversalType traversalType = MItDag::kDepthFirst;
        MFn::Type filter = MFn::kMesh;
        MStatus status;

        MItDag dagIterator( traversalType, filter, &status);

        for ( ; !dagIterator.isDone(); dagIterator.next() )
        {

            MDagPath dagPath;

            status = dagIterator.getPath(dagPath);
            if ( !status ) {
                status.perror("MItDag::getPath");
                continue;
            }

            MFnDagNode dagNode(dagPath, &status);
            if ( !status ) {
                status.perror("MFnDagNode constructor");
                continue;
            }

            MBoundingBox box = dagNode.boundingBox();
            #if defined(_USE_MGL_FT_)
            gGLFT->glColor3f( 1.0f, 0.0f, 0.0f );
            #else
            ::glColor3f( 1.0f, 0.0f, 0.0f );
            #endif
            drawBounds( dagPath, box );
        }
    }

    return true;
}