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

# footPrintNode.cpp

    //-
    // ==========================================================================
    // Copyright 2012 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 <maya/MPxLocatorNode.h>
    #include <maya/MString.h>
    #include <maya/MDagPath.h>
    #include <maya/MTypeId.h>
    #include <maya/MPlug.h>
    #include <maya/MVector.h>
    #include <maya/MDataBlock.h>
    #include <maya/MDataHandle.h>
    #include <maya/MColor.h>
    #include <maya/M3dView.h>
    #include <maya/MFnPlugin.h>
    #include <maya/MDistance.h>
    #include <maya/MMatrix.h>
    #include <maya/MFnUnitAttribute.h>

    // Viewport 2.0 includes
    #include <maya/MDrawRegistry.h>
    #include <maya/MPxDrawOverride.h>
    #include <maya/MUserData.h>
    #include <maya/MDrawContext.h>
    #include <maya/MGlobal.h>
    #include <maya/MSelectionList.h>
    #include <maya/MViewport2Renderer.h>
    #include <maya/MHWGeometryUtilities.h>
    #include <maya/MStateManager.h>
    #include <maya/MShaderManager.h>

    #include <assert.h>

    // DX stuff
    #ifdef _WIN32

    #define WIN32_LEAN_AND_MEAN
    #include <d3d11.h>
    #include <d3dx11.h>
    #include <d3dcompiler.h>

    #ifndef D3DCOMPILE_ENABLE_STRICTNESS
        #define D3DCOMPILE_ENABLE_STRICTNESS D3D10_SHADER_ENABLE_STRICTNESS
        #define D3DCOMPILE_DEBUG D3D10_SHADER_DEBUG
    #endif

    #include <xnamath.h>

    #endif //_WIN32

    // Foot Data
    //
    static float sole[][3] = { {  0.00f, 0.0f, -0.70f },
                               {  0.04f, 0.0f, -0.69f },
                               {  0.09f, 0.0f, -0.65f },
                               {  0.13f, 0.0f, -0.61f },
                               {  0.16f, 0.0f, -0.54f },
                               {  0.17f, 0.0f, -0.46f },
                               {  0.17f, 0.0f, -0.35f },
                               {  0.16f, 0.0f, -0.25f },
                               {  0.15f, 0.0f, -0.14f },
                               {  0.13f, 0.0f,  0.00f },
                               {  0.00f, 0.0f,  0.00f },
                               { -0.13f, 0.0f,  0.00f },
                               { -0.15f, 0.0f, -0.14f },
                               { -0.16f, 0.0f, -0.25f },
                               { -0.17f, 0.0f, -0.35f },
                               { -0.17f, 0.0f, -0.46f },
                               { -0.16f, 0.0f, -0.54f },
                               { -0.13f, 0.0f, -0.61f },
                               { -0.09f, 0.0f, -0.65f },
                               { -0.04f, 0.0f, -0.69f },
                               { -0.00f, 0.0f, -0.70f } };
    static float heel[][3] = { {  0.00f, 0.0f,  0.06f },
                               {  0.13f, 0.0f,  0.06f },
                               {  0.14f, 0.0f,  0.15f },
                               {  0.14f, 0.0f,  0.21f },
                               {  0.13f, 0.0f,  0.25f },
                               {  0.11f, 0.0f,  0.28f },
                               {  0.09f, 0.0f,  0.29f },
                               {  0.04f, 0.0f,  0.30f },
                               {  0.00f, 0.0f,  0.30f },
                               { -0.04f, 0.0f,  0.30f },
                               { -0.09f, 0.0f,  0.29f },
                               { -0.11f, 0.0f,  0.28f },
                               { -0.13f, 0.0f,  0.25f },
                               { -0.14f, 0.0f,  0.21f },
                               { -0.14f, 0.0f,  0.15f },
                               { -0.13f, 0.0f,  0.06f },
                               { -0.00f, 0.0f,  0.06f } };
    static int soleCount = 21;
    static int heelCount = 17;

    //---------------------------------------------------------------------------
    //---------------------------------------------------------------------------
    // Node implementation with standard viewport draw
    //---------------------------------------------------------------------------
    //---------------------------------------------------------------------------

    class footPrint : public MPxLocatorNode
    {
    public:
        footPrint();
        virtual ~footPrint();

        virtual MStatus         compute( const MPlug& plug, MDataBlock& data );

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

        virtual bool            isBounded() const;
        virtual MBoundingBox    boundingBox() const;

        static  void *          creator();
        static  MStatus         initialize();

        static  MObject         size;         // The size of the foot

    public:
        static  MTypeId     id;
        static  MString     drawDbClassification;
        static  MString     drawRegistrantId;
    };

    MObject footPrint::size;
    MTypeId footPrint::id( 0x80007 );
    MString footPrint::drawDbClassification("drawdb/geometry/footPrint");
    MString footPrint::drawRegistrantId("FootprintNodePlugin");

    footPrint::footPrint() {}
    footPrint::~footPrint() {}

    MStatus footPrint::compute( const MPlug& /*plug*/, MDataBlock& /*data*/ )
    {
        return MS::kUnknownParameter;
    }

    void footPrint::draw( M3dView & view, const MDagPath & /*path*/,
                                 M3dView::DisplayStyle style,
                                 M3dView::DisplayStatus status )
    {
        // Get the size
        //
        MObject thisNode = thisMObject();
        MPlug plug( thisNode, size );
        MDistance sizeVal;
        plug.getValue( sizeVal );

        float multiplier = (float) sizeVal.asCentimeters();

        view.beginGL();

        if ( ( style == M3dView::kFlatShaded ) ||
             ( style == M3dView::kGouraudShaded ) )
        {
            // Push the color settings
            //
            glPushAttrib( GL_CURRENT_BIT );

            if ( status == M3dView::kActive ) {
                view.setDrawColor( 13, M3dView::kActiveColors );
            } else {
                view.setDrawColor( 13, M3dView::kDormantColors );
            }

            glBegin( GL_TRIANGLE_FAN );
                int i;
                int last = soleCount - 1;
                for ( i = 0; i < last; ++i ) {
                    glVertex3f( sole[i][0] * multiplier,
                                sole[i][1] * multiplier,
                                sole[i][2] * multiplier );
                }
            glEnd();
            glBegin( GL_TRIANGLE_FAN );
                last = heelCount - 1;
                for ( i = 0; i < last; ++i ) {
                    glVertex3f( heel[i][0] * multiplier,
                                heel[i][1] * multiplier,
                                heel[i][2] * multiplier );
                }
            glEnd();

            glPopAttrib();
        }

        // Draw the outline of the foot
        //
        glBegin( GL_LINES );
            int i;
            int last = soleCount - 1;
            for ( i = 0; i < last; ++i ) {
                glVertex3f( sole[i][0] * multiplier,
                            sole[i][1] * multiplier,
                            sole[i][2] * multiplier );
                glVertex3f( sole[i+1][0] * multiplier,
                            sole[i+1][1] * multiplier,
                            sole[i+1][2] * multiplier );
            }
            last = heelCount - 1;
            for ( i = 0; i < last; ++i ) {
                glVertex3f( heel[i][0] * multiplier,
                            heel[i][1] * multiplier,
                            heel[i][2] * multiplier );
                glVertex3f( heel[i+1][0] * multiplier,
                            heel[i+1][1] * multiplier,
                            heel[i+1][2] * multiplier );
            }
        glEnd();

        view.endGL();

        // Draw the name of the footPrint
        view.setDrawColor( MColor( 0.1f, 0.8f, 0.8f, 1.0f ) );
        view.drawText( MString("Footprint"), MPoint( 0.0, 0.0, 0.0 ), M3dView::kCenter );
    }

    bool footPrint::isBounded() const
    {
        return true;
    }

    MBoundingBox footPrint::boundingBox() const
    {
        // Get the size
        //
        MObject thisNode = thisMObject();
        MPlug plug( thisNode, size );
        MDistance sizeVal;
        plug.getValue( sizeVal );

        double multiplier = sizeVal.asCentimeters();

        MPoint corner1( -0.17, 0.0, -0.7 );
        MPoint corner2( 0.17, 0.0, 0.3 );

        corner1 = corner1 * multiplier;
        corner2 = corner2 * multiplier;

        return MBoundingBox( corner1, corner2 );
    }

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

    //---------------------------------------------------------------------------
    //---------------------------------------------------------------------------
    // Viewport 2.0 override implementation
    //---------------------------------------------------------------------------
    //---------------------------------------------------------------------------

    class FootPrintData : public MUserData
    {
    public:
        FootPrintData() : MUserData(false) {} // don't delete after draw
        virtual ~FootPrintData() {}

        float fMultiplier;
        float fColor[3];
        bool  fCustomBoxDraw;
        MBoundingBox fCurrentBoundingBox;
        MDAGDrawOverrideInfo fDrawOV;
    };

    // Helper class declaration for the object drawing
    class FootPrintDrawAgent
    {
    public:
        FootPrintDrawAgent(){}
        virtual ~FootPrintDrawAgent(){}

        virtual void drawShaded( float multiplier ) = 0;
        virtual void drawBoundingBox( const MPoint&, const MPoint&) = 0;
        virtual void drawWireframe( float multiplier ) = 0;
        virtual void beginDraw() = 0;
        virtual void endDraw() = 0;

        void setMatrix( const MMatrix& wvMatrix, const MMatrix& projMatrix ){
            mWorldViewMatrix = wvMatrix;
            mProjectionMatrix = projMatrix;
        }

        void setColor( const MColor& color){
            mColor = color;
        }

    protected:
        MMatrix mWorldViewMatrix;
        MMatrix mProjectionMatrix;
        MColor  mColor;
    };

    // GL draw agent declaration
    class FootPrintDrawAgentGL : public FootPrintDrawAgent
    {
    public:
        static FootPrintDrawAgentGL& getDrawAgent(){
            static FootPrintDrawAgentGL obj;
            return obj;
        }

        virtual void drawShaded( float multiplier );
        virtual void drawBoundingBox( const MPoint& min, const MPoint& max );
        virtual void drawWireframe( float multiplier );
        virtual void beginDraw();
        virtual void endDraw();
    private:
        FootPrintDrawAgentGL(){}
        ~FootPrintDrawAgentGL(){}
        FootPrintDrawAgentGL( const FootPrintDrawAgentGL& v ){}
        FootPrintDrawAgentGL operator = (const FootPrintDrawAgentGL& v){ return *this; }
    };

    // DX stuff
    #ifdef _WIN32

    // DX draw agent declaration
    class FootPrintDrawAgentDX : public FootPrintDrawAgent
    {
    public:
        static FootPrintDrawAgentDX& getDrawAgent(){
            static FootPrintDrawAgentDX obj;
            return obj;
        }

        virtual void drawShaded( float multiplier );
        virtual void drawBoundingBox( const MPoint& min, const MPoint& max );
        virtual void drawWireframe( float multiplier );
        virtual void beginDraw();
        virtual void endDraw();

        bool releaseDXResources();
    private:
        ID3D11Device* mDevicePtr;
        ID3D11DeviceContext* mDeviceContextPtr;

        ID3D11Buffer* mBoundingboxVertexBufferPtr;
        ID3D11Buffer* mBoundingboxIndexBufferPtr;
        ID3D11Buffer* mSoleVertexBufferPtr;
        ID3D11Buffer* mHeelVertexBufferPtr;
        ID3D11Buffer* mSoleWireIndexBufferPtr;
        ID3D11Buffer* mSoleShadedIndexBufferPtr;
        ID3D11Buffer* mHeelWireIndexBufferPtr;
        ID3D11Buffer* mHeelShadedIndexBufferPtr;
        ID3D11Buffer* mConstantBufferPtr;
        ID3D11VertexShader* mVertexShaderPtr;
        ID3D11PixelShader* mPixelShaderPtr;
        ID3D11InputLayout* mVertexLayoutPtr;

        unsigned int mStride;
        unsigned int mOffset;
        struct ConstantBufferDef
        {
            XMMATRIX fWVP;
            XMFLOAT4 fMatColor;
        };
        bool initShadersDX();
        bool initBuffersDX();
        void setupConstantBuffer( const XMMATRIX& scale );
    private:
        FootPrintDrawAgentDX():
            mDevicePtr(NULL), mDeviceContextPtr(NULL), mStride(sizeof(float)*3), mOffset(0),
            mBoundingboxVertexBufferPtr(NULL),
            mBoundingboxIndexBufferPtr(NULL),
            mSoleVertexBufferPtr(NULL),
            mHeelVertexBufferPtr(NULL),
            mSoleWireIndexBufferPtr(NULL),
            mSoleShadedIndexBufferPtr(NULL),
            mHeelWireIndexBufferPtr(NULL),
            mHeelShadedIndexBufferPtr(NULL),
            mConstantBufferPtr(NULL),
            mVertexShaderPtr(NULL),
            mPixelShaderPtr(NULL),
            mVertexLayoutPtr(NULL)
            {}
        ~FootPrintDrawAgentDX(){}
        FootPrintDrawAgentDX( const FootPrintDrawAgentDX& v ){}
        FootPrintDrawAgentDX operator = (const FootPrintDrawAgentDX& v){ return *this; }
    };

    #endif // _WIN32

    // GL draw agent definition
    //
    void FootPrintDrawAgentGL::beginDraw()
    {
        // set world view matrix
        glMatrixMode(GL_MODELVIEW);
        glPushMatrix();
        glLoadMatrixd(mWorldViewMatrix.matrix[0]);
        // set projection matrix
        glMatrixMode(GL_PROJECTION);
        glPushMatrix();
        glLoadMatrixd(mProjectionMatrix.matrix[0]);
        glPushAttrib( GL_CURRENT_BIT );
    }

    void FootPrintDrawAgentGL::endDraw()
    {
        glPopAttrib();
        glPopMatrix();
        glMatrixMode(GL_MODELVIEW);
        glPopMatrix();
    }

    void FootPrintDrawAgentGL::drawShaded( float multiplier )
    {
        // set color
        glColor4fv( &(mColor.r) );

        glBegin( GL_TRIANGLE_FAN );
        int i;
        int last = soleCount - 1;
        for ( i = 0; i < last; ++i ) {
            glVertex3f( sole[i][0] * multiplier,
                sole[i][1] * multiplier,
                sole[i][2] * multiplier );
        }
        glEnd();
        glBegin( GL_TRIANGLE_FAN );
        last = heelCount - 1;
        for ( i = 0; i < last; ++i ) {
            glVertex3f( heel[i][0] * multiplier,
                heel[i][1] * multiplier,
                heel[i][2] * multiplier );
        }
        glEnd();
    }

    void FootPrintDrawAgentGL::drawBoundingBox( const MPoint& min, const MPoint& max )
    {
        // set color
        glColor4fv( &(mColor.r) );

        float bottomLeftFront[3] = { (float)min[0], (float)min[1], (float)min[2] };
        float topLeftFront[3] = { (float)min[0], (float)max[1], (float)min[2] }; //1
        float bottomRightFront[3] = { (float)max[0], (float)min[1], (float)min[2] }; //2
        float topRightFront[3] = { (float)max[0], (float)max[1], (float)min[2] }; //3
        float bottomLeftBack[3] = { (float)min[0], (float)min[1], (float)max[2] }; //4
        float topLeftBack[3] = { (float)min[0], (float)max[1], (float)max[2] }; //5
        float bottomRightBack[3] = { (float)max[0], (float)min[1], (float)max[2] }; //6
        float topRightBack[3] = { (float)max[0], (float)max[1], (float)max[2] }; //7

        glBegin( GL_LINES );

        // 4 Bottom lines
        //
        glVertex3fv( bottomLeftFront );
        glVertex3fv( bottomRightFront );
        glVertex3fv( bottomRightFront );
        glVertex3fv( bottomRightBack );
        glVertex3fv( bottomRightBack );
        glVertex3fv( bottomLeftBack );
        glVertex3fv( bottomLeftBack );
        glVertex3fv( bottomLeftFront );

        // 4 Top lines
        //
        glVertex3fv( topLeftFront );
        glVertex3fv( topRightFront );
        glVertex3fv( topRightFront );
        glVertex3fv( topRightBack );
        glVertex3fv( topRightBack );
        glVertex3fv( topLeftBack );
        glVertex3fv( topLeftBack );
        glVertex3fv( topLeftFront );

        // 4 Side lines
        //
        glVertex3fv( bottomLeftFront );
        glVertex3fv( topLeftFront );
        glVertex3fv( bottomRightFront );
        glVertex3fv( topRightFront );
        glVertex3fv( bottomRightBack );
        glVertex3fv( topRightBack );
        glVertex3fv( bottomLeftBack );
        glVertex3fv( topLeftBack );

        glEnd();
    }

    void FootPrintDrawAgentGL::drawWireframe( float multiplier )
    {
        // set color
        glColor4fv( &(mColor.r) );

        // draw wire
        glBegin( GL_LINES );
        int i;
        int last = soleCount - 1;
        for ( i = 0; i < last; ++i ) {
            glVertex3f( sole[i][0] * multiplier,
                sole[i][1] * multiplier,
                sole[i][2] * multiplier );
            glVertex3f( sole[i+1][0] * multiplier,
                sole[i+1][1] * multiplier,
                sole[i+1][2] * multiplier );
        }
        last = heelCount - 1;
        for ( i = 0; i < last; ++i ) {
            glVertex3f( heel[i][0] * multiplier,
                heel[i][1] * multiplier,
                heel[i][2] * multiplier );
            glVertex3f( heel[i+1][0] * multiplier,
                heel[i+1][1] * multiplier,
                heel[i+1][2] * multiplier );
        }
        glEnd();
    }

    // DX stuff
    #ifdef _WIN32
    // DX draw agent definition
    //
    void FootPrintDrawAgentDX::beginDraw()
    {
        // Initial device
        if( !mDevicePtr || !mDeviceContextPtr ){
            // get renderer
            MHWRender::MRenderer* theRenderer = MHWRender::MRenderer::theRenderer();
            if ( theRenderer ){
                mDevicePtr = (ID3D11Device*)theRenderer->GPUDeviceHandle();
                if ( mDevicePtr ){
                    mDevicePtr->GetImmediateContext( &mDeviceContextPtr );
                }
            }
        }
        assert( mDevicePtr );
        assert( mDeviceContextPtr );

        if ( mDevicePtr && mDeviceContextPtr ){

            // Init shaders
            if ( initShadersDX() ){
                // Set up shader
                mDeviceContextPtr->VSSetShader(mVertexShaderPtr, NULL, 0);
                mDeviceContextPtr->IASetInputLayout(mVertexLayoutPtr);
                mDeviceContextPtr->PSSetShader(mPixelShaderPtr, NULL, 0);
            }

            // Init buffers
            initBuffersDX();
        }
    }

    void FootPrintDrawAgentDX::endDraw()
    {}

    void FootPrintDrawAgentDX::setupConstantBuffer( const XMMATRIX& scale )
    {
        assert( mDeviceContextPtr );
        if ( !mDeviceContextPtr )
            return;

        // Compute matrix
        XMMATRIX dxTransform = XMMATRIX(
            (float)mWorldViewMatrix.matrix[0][0], (float)mWorldViewMatrix.matrix[0][1], (float)mWorldViewMatrix.matrix[0][2], (float)mWorldViewMatrix.matrix[0][3],
            (float)mWorldViewMatrix.matrix[1][0], (float)mWorldViewMatrix.matrix[1][1], (float)mWorldViewMatrix.matrix[1][2], (float)mWorldViewMatrix.matrix[1][3],
            (float)mWorldViewMatrix.matrix[2][0], (float)mWorldViewMatrix.matrix[2][1], (float)mWorldViewMatrix.matrix[2][2], (float)mWorldViewMatrix.matrix[2][3],
            (float)mWorldViewMatrix.matrix[3][0], (float)mWorldViewMatrix.matrix[3][1], (float)mWorldViewMatrix.matrix[3][2], (float)mWorldViewMatrix.matrix[3][3]);
        XMMATRIX dxProjection = XMMATRIX(
            (float)mProjectionMatrix.matrix[0][0], (float)mProjectionMatrix.matrix[0][1], (float)mProjectionMatrix.matrix[0][2], (float)mProjectionMatrix.matrix[0][3],
            (float)mProjectionMatrix.matrix[1][0], (float)mProjectionMatrix.matrix[1][1], (float)mProjectionMatrix.matrix[1][2], (float)mProjectionMatrix.matrix[1][3],
            (float)mProjectionMatrix.matrix[2][0], (float)mProjectionMatrix.matrix[2][1], (float)mProjectionMatrix.matrix[2][2], (float)mProjectionMatrix.matrix[2][3],
            (float)mProjectionMatrix.matrix[3][0], (float)mProjectionMatrix.matrix[3][1], (float)mProjectionMatrix.matrix[3][2], (float)mProjectionMatrix.matrix[3][3]);

        // Set constant buffer
        ConstantBufferDef cb;
        cb.fWVP = XMMatrixTranspose(scale * dxTransform * dxProjection);
        cb.fMatColor = XMFLOAT4( mColor.r, mColor.g, mColor.b, mColor.a);
        mDeviceContextPtr->UpdateSubresource(mConstantBufferPtr, 0, NULL, &cb, 0, 0);
        mDeviceContextPtr->VSSetConstantBuffers(0, 1, &mConstantBufferPtr);
        mDeviceContextPtr->PSSetConstantBuffers(0, 1, &mConstantBufferPtr);
    }

    void FootPrintDrawAgentDX::drawShaded( float multiplier )
    {
        assert( mDeviceContextPtr );
        if ( !mDeviceContextPtr )
            return;

        // Set constant buffer
        XMMATRIX scale(
            multiplier, 0.0f, 0.0f, 0.0f,
            0.0f, multiplier, 0.0f, 0.0f,
            0.0f, 0.0f, multiplier, 0.0f,
            0.0f, 0.0f, 0.0f, 1.0f );
        setupConstantBuffer( scale );

        // Draw the sole
        mDeviceContextPtr->IASetVertexBuffers(0, 1, &mSoleVertexBufferPtr, &mStride, &mOffset);
        mDeviceContextPtr->IASetIndexBuffer(mSoleShadedIndexBufferPtr, DXGI_FORMAT_R16_UINT, 0);
        mDeviceContextPtr->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
        mDeviceContextPtr->DrawIndexed(3 * (soleCount-2), 0, 0);
        // Draw the heel
        mDeviceContextPtr->IASetVertexBuffers(0, 1, &mHeelVertexBufferPtr, &mStride, &mOffset);
        mDeviceContextPtr->IASetIndexBuffer(mHeelShadedIndexBufferPtr, DXGI_FORMAT_R16_UINT, 0);
        mDeviceContextPtr->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
        mDeviceContextPtr->DrawIndexed(3 * (heelCount-2), 0, 0);
    }

    void FootPrintDrawAgentDX::drawBoundingBox( const MPoint& min, const MPoint& max )
    {
        assert( mDeviceContextPtr );
        if ( !mDeviceContextPtr )
            return;

        // Set constant buffer
        XMMATRIX scale(
            static_cast<float>(max[0]- min[0]), 0.0f, 0.0f, 0.0f,
            0.0f, static_cast<float>(max[1]-min[1]), 0.0f, 0.0f,
            0.0f, 0.0f, static_cast<float>(max[2]-min[2]), 0.0f,
            0.0f, 0.0f, 0.0f, 1.0f );
        setupConstantBuffer( scale );

        mDeviceContextPtr->IASetVertexBuffers(0, 1, &mBoundingboxVertexBufferPtr, &mStride, &mOffset);
        mDeviceContextPtr->IASetIndexBuffer(mBoundingboxIndexBufferPtr, DXGI_FORMAT_R16_UINT, 0);
        mDeviceContextPtr->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST);
        mDeviceContextPtr->DrawIndexed(2 * 12, 0, 0);
    }

    void FootPrintDrawAgentDX::drawWireframe( float multiplier )
    {
        assert( mDeviceContextPtr );
        if ( !mDeviceContextPtr )
            return;

        // Set constant buffer
        XMMATRIX scale(
            multiplier, 0.0f, 0.0f, 0.0f,
            0.0f, multiplier, 0.0f, 0.0f,
            0.0f, 0.0f, multiplier, 0.0f,
            0.0f, 0.0f, 0.0f, 1.0f );
        setupConstantBuffer( scale );

        // Draw the sole
        mDeviceContextPtr->IASetVertexBuffers(0, 1, &mSoleVertexBufferPtr, &mStride, &mOffset);
        mDeviceContextPtr->IASetIndexBuffer(mSoleWireIndexBufferPtr, DXGI_FORMAT_R16_UINT, 0);
        mDeviceContextPtr->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST);
        mDeviceContextPtr->DrawIndexed(2 * (soleCount-1), 0, 0);
        // Draw the heel
        mDeviceContextPtr->IASetVertexBuffers(0, 1, &mHeelVertexBufferPtr, &mStride, &mOffset);
        mDeviceContextPtr->IASetIndexBuffer(mHeelWireIndexBufferPtr, DXGI_FORMAT_R16_UINT, 0);
        mDeviceContextPtr->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST);
        mDeviceContextPtr->DrawIndexed(2 * (heelCount-1), 0, 0);
    }

    #endif // _WIN32

    class FootPrintDrawOverride : public MHWRender::MPxDrawOverride
    {
    public:
        static MHWRender::MPxDrawOverride* Creator(const MObject& obj)
        {
            return new FootPrintDrawOverride(obj);
        }

        virtual ~FootPrintDrawOverride();

        virtual MHWRender::DrawAPI supportedDrawAPIs() const;

        virtual bool isBounded(
            const MDagPath& objPath,
            const MDagPath& cameraPath) const;

        virtual MBoundingBox boundingBox(
            const MDagPath& objPath,
            const MDagPath& cameraPath) const;

        virtual bool disableInternalBoundingBoxDraw() const;

        virtual MUserData* prepareForDraw(
            const MDagPath& objPath,
            const MDagPath& cameraPath,
            const MHWRender::MFrameContext& frameContext,
            MUserData* oldData);

        virtual bool hasUIDrawables() const { return true; }

        virtual void addUIDrawables(
            const MDagPath& objPath,
            MHWRender::MUIDrawManager& drawManager,
            const MHWRender::MFrameContext& frameContext,
            const MUserData* data);

        static void draw(const MHWRender::MDrawContext& context, const MUserData* data);

    protected:
        MBoundingBox mCurrentBoundingBox;
        bool         mCustomBoxDraw;
    private:
        FootPrintDrawOverride(const MObject& obj);
        float getMultiplier(const MDagPath& objPath) const;
    };

    FootPrintDrawOverride::FootPrintDrawOverride(const MObject& obj)
    : MHWRender::MPxDrawOverride(obj, FootPrintDrawOverride::draw)
    // We want to perform custom bounding box drawing
    // so return true so that the internal rendering code
    // will not draw it for us.
    , mCustomBoxDraw(true)
    {
    }

    FootPrintDrawOverride::~FootPrintDrawOverride()
    {
    }

    MHWRender::DrawAPI FootPrintDrawOverride::supportedDrawAPIs() const
    {
        // this plugin supports both GL and DX
        return (MHWRender::kOpenGL | MHWRender::kDirectX11);
    }

    float FootPrintDrawOverride::getMultiplier(const MDagPath& objPath) const
    {
        // Retrieve value of the size attribute from the node
        MStatus status;
        MObject footprintNode = objPath.node(&status);
        if (status)
        {
            MPlug plug(footprintNode, footPrint::size);
            if (!plug.isNull())
            {
                MDistance sizeVal;
                if (plug.getValue(sizeVal))
                {
                    return (float)sizeVal.asCentimeters();
                }
            }
        }

        return 1.0f;
    }

    bool FootPrintDrawOverride::isBounded(const MDagPath& /*objPath*/,
                                          const MDagPath& /*cameraPath*/) const
    {
        return true;
    }

    MBoundingBox FootPrintDrawOverride::boundingBox(
        const MDagPath& objPath,
        const MDagPath& cameraPath) const
    {
        MPoint corner1( -0.17, 0.0, -0.7 );
        MPoint corner2( 0.17, 0.0, 0.3 );

        float multiplier = getMultiplier(objPath);
        corner1 = corner1 * multiplier;
        corner2 = corner2 * multiplier;

        FootPrintDrawOverride *nonConstThis = (FootPrintDrawOverride *)this;
        nonConstThis->mCurrentBoundingBox.clear();
        nonConstThis->mCurrentBoundingBox.expand( corner1 );
        nonConstThis->mCurrentBoundingBox.expand( corner2 );

        return mCurrentBoundingBox;
    }

    bool FootPrintDrawOverride::disableInternalBoundingBoxDraw() const
    {
        return mCustomBoxDraw;
    }

    MUserData* FootPrintDrawOverride::prepareForDraw(
        const MDagPath& objPath,
        const MDagPath& cameraPath,
        const MHWRender::MFrameContext& frameContext,
        MUserData* oldData)
    {
        // Retrieve data cache (create if does not exist)
        FootPrintData* data = dynamic_cast<FootPrintData*>(oldData);
        if (!data)
        {
            data = new FootPrintData();
        }

        // compute data and cache it
        data->fMultiplier = getMultiplier(objPath);
        MColor color = MHWRender::MGeometryUtilities::wireframeColor(objPath);
        data->fColor[0] = color.r;
        data->fColor[1] = color.g;
        data->fColor[2] = color.b;
        data->fCustomBoxDraw = mCustomBoxDraw;
        data->fCurrentBoundingBox = mCurrentBoundingBox;

        // Get the draw override information
        data->fDrawOV = objPath.getDrawOverrideInfo();

        return data;
    }

    void FootPrintDrawOverride::addUIDrawables(
            const MDagPath& objPath,
            MHWRender::MUIDrawManager& drawManager,
            const MHWRender::MFrameContext& frameContext,
            const MUserData* data)
    {
        // Draw a text "Foot"
        MPoint pos( 0.0, 0.0, 0.0 ); // Position of the text
        MColor textColor( 0.1f, 0.8f, 0.8f, 1.0f ); // Text color

        drawManager.beginDrawable();

        drawManager.setColor( textColor );
        drawManager.setFontSize( MHWRender::MUIDrawManager::kSmallFontSize );
        drawManager.text( pos,  MString("Footprint"), MHWRender::MUIDrawManager::kCenter );

        drawManager.endDrawable();
    }

    void FootPrintDrawOverride::draw(const MHWRender::MDrawContext& context, const MUserData* data)
    {
        // Get user draw data
        const FootPrintData* footData = dynamic_cast<const FootPrintData*>(data);
        if (!footData)
            return;

        // Get DAG object draw override
        const MDAGDrawOverrideInfo& objectOverrideInfo = footData->fDrawOV;

        // Just return and draw nothing, if it is overridden invisible
        if ( objectOverrideInfo.fOverrideEnabled && !objectOverrideInfo.fEnableVisible )
            return;

        // Get display status
        const unsigned int displayStyle = context.getDisplayStyle();
        const bool drawAsBoundingbox =
            (displayStyle & MHWRender::MFrameContext::kBoundingBox) ||
            (footData->fDrawOV.fLOD == MDAGDrawOverrideInfo::kLODBoundingBox);
        // If we don't want to draw the bounds within this plugin
        // manually, then skip drawing altogether in bounding box mode
        // since the bounds draw is handled by the renderer and
        // doesn't need to be drawn here.
        //
        if ( drawAsBoundingbox && !footData->fCustomBoxDraw )
        {
            return;
        }

        // Now, something gonna draw...

        // Get renderer
        MHWRender::MRenderer* theRenderer = MHWRender::MRenderer::theRenderer();
        if (!theRenderer)
            return;

        // Get  world view matrix
        MStatus status;
        const MMatrix transform =
            context.getMatrix(MHWRender::MFrameContext::kWorldViewMtx, &status);
        if (status != MStatus::kSuccess) return;
        // Get projection matrix
        const MMatrix projection =
            context.getMatrix(MHWRender::MFrameContext::kProjectionMtx, &status);
        if (status != MStatus::kSuccess) return;

        // Check to see if we are drawing in a shadow pass.
        // If so then we keep the shading simple which in this
        // example means to disable any extra blending state changes
        //
        const MHWRender::MPassContext & passCtx = context.getPassContext();
        const MStringArray & passSem = passCtx.passSemantics();
        bool castingShadows = false;
        for (unsigned int i=0; i<passSem.length(); i++)
        {
            if (passSem[i] == MHWRender::MPassContext::kShadowPassSemantic)
                castingShadows = true;
        }
        bool debugPassInformation = false;
        if (debugPassInformation)
        {
            const MString & passId = passCtx.passIdentifier();
            printf("footprint node drawing in pass[%s], semantic[", passId.asChar());
            for (unsigned int i=0; i<passSem.length(); i++)
                printf(" %s", passSem[i].asChar());
            printf("\n");
        }

        // get cached data
        float multiplier = footData->fMultiplier;
        float color[4] = {
                footData->fColor[0],
                footData->fColor[1],
                footData->fColor[2],
                1.0f
        };

        bool requireBlending = false;

        // If we're not casting shadows then do extra work
        // for display styles
        if (!castingShadows)
        {

            // Use some monotone version of color to show "default material mode"
            //
            if (displayStyle & MHWRender::MFrameContext::kDefaultMaterial)
            {
                color[0] = color[1] = color[2] = (color[0] + color[1] + color[2]) / 3.0f;
            }
            // Do some alpha blending if in x-ray mode
            //
            else if (displayStyle & MHWRender::MFrameContext::kXray)
            {
                requireBlending = true;
                color[3] = 0.3f;
            }
        }

        // Set blend and raster state
        //
        MHWRender::MStateManager* stateMgr = context.getStateManager();
        const MHWRender::MBlendState* pOldBlendState = NULL;
        const MHWRender::MRasterizerState* pOldRasterState = NULL;
        bool rasterStateModified = false;

        if(stateMgr && (displayStyle & MHWRender::MFrameContext::kGouraudShaded))
        {
            // draw filled, and with blending if required
            if (stateMgr && requireBlending)
            {
                static const MHWRender::MBlendState* blendState = NULL;
                if (!blendState)
                {
                    MHWRender::MBlendStateDesc desc;
                    desc.targetBlends[0].blendEnable = true;
                    desc.targetBlends[0].destinationBlend = MHWRender::MBlendState::kInvSourceAlpha;
                    desc.targetBlends[0].alphaDestinationBlend = MHWRender::MBlendState::kInvSourceAlpha;
                    blendState = stateMgr->acquireBlendState(desc);
                }

                if (blendState)
                {
                    pOldBlendState = stateMgr->getBlendState();
                    stateMgr->setBlendState(blendState);
                }
            }

            // Override culling mode since we always want double-sided
            //
            pOldRasterState = stateMgr ? stateMgr->getRasterizerState() : NULL;
            if (pOldRasterState)
            {
                MHWRender::MRasterizerStateDesc desc( pOldRasterState->desc() );
                // It's also possible to change this to kCullFront or kCullBack if we
                // wanted to set it to that.
                MHWRender::MRasterizerState::CullMode cullMode = MHWRender::MRasterizerState::kCullNone;
                if (desc.cullMode != cullMode)
                {
                    static const MHWRender::MRasterizerState *rasterState = NULL;
                    if (!rasterState)
                    {
                        // Just override the cullmode
                        desc.cullMode = cullMode;
                        rasterState = stateMgr->acquireRasterizerState(desc);
                    }
                    if (rasterState)
                    {
                        rasterStateModified = true;
                        stateMgr->setRasterizerState(rasterState);
                    }
                }
            }
        }

        //========================
        // Start the draw work
        //========================

        // Prepare draw agent, default using OpenGL
        FootPrintDrawAgentGL& drawAgentRef = FootPrintDrawAgentGL::getDrawAgent();
        FootPrintDrawAgent* drawAgentPtr = &drawAgentRef;
    #ifdef _WIN32
        // DX Draw
        if ( !theRenderer->drawAPIIsOpenGL() )
        {
            FootPrintDrawAgentDX& drawAgentRef = FootPrintDrawAgentDX::getDrawAgent();
            drawAgentPtr = &drawAgentRef;
        }
    #endif
        assert( drawAgentPtr );

        if ( drawAgentPtr ){

            // Set color
            drawAgentPtr->setColor( MColor(color[0],color[1],color[2],color[3]) );
            // Set matrix
            drawAgentPtr->setMatrix( transform, projection );

            drawAgentPtr->beginDraw();

            if ( drawAsBoundingbox )
            {
                // If it is in bounding bode, draw only bounding box wireframe, nothing else
                MPoint min = footData->fCurrentBoundingBox.min();
                MPoint max = footData->fCurrentBoundingBox.max();

                drawAgentPtr->drawBoundingBox( min, max );
            } else {
                // Templated, only draw wirefame and it is not selectale
                const bool overideTemplated = objectOverrideInfo.fOverrideEnabled &&
                    (objectOverrideInfo.fDisplayType == MDAGDrawOverrideInfo::kDisplayTypeTemplate);
                // Override no shaded, only show wireframe
                const bool overrideNoShaded = objectOverrideInfo.fOverrideEnabled && !objectOverrideInfo.fEnableShading;

                if ( overideTemplated || overrideNoShaded ){
                    drawAgentPtr->drawWireframe( multiplier );
                } else {
                    if( (displayStyle & MHWRender::MFrameContext::kGouraudShaded) ||
                        (displayStyle & MHWRender::MFrameContext::kTextured))
                    {
                        drawAgentPtr->drawShaded( multiplier );
                    }

                    if(displayStyle & MHWRender::MFrameContext::kWireFrame)
                    {
                        drawAgentPtr->drawWireframe( multiplier );
                    }
                }
            }

            drawAgentPtr->endDraw();
        }

        //========================
        // End the draw work
        //========================

        // Restore old blend state and old raster state
        if(stateMgr && (displayStyle & MHWRender::MFrameContext::kGouraudShaded))
        {
            if (stateMgr && pOldBlendState)
            {
                stateMgr->setBlendState(pOldBlendState);
            }
            if (rasterStateModified && pOldRasterState)
            {
                stateMgr->setRasterizerState(pOldRasterState);
            }
        }
    }

    // DX stuff
    #ifdef _WIN32

    bool FootPrintDrawAgentDX::initShadersDX()
    {
        assert( mDevicePtr );
        if ( !mDevicePtr )
            return false;

        HRESULT hr;
        DWORD dwShaderFlags = D3DCOMPILE_ENABLE_STRICTNESS;
        ID3DBlob* vsBlob = NULL;
        ID3DBlob* psBlob = NULL;
        ID3DBlob* pErrorBlob;
        MString effectLocation(
            MString(getenv("MAYA_LOCATION")) +
            MString("\\devkit\\plug-ins") +
            MString("\\footprint.hlsl"));

        // VS
        if (!mVertexShaderPtr)
        {
            hr = D3DX11CompileFromFile(
                effectLocation.asChar(),
                NULL,
                NULL,
                "mainVS",
                "vs_5_0",
                dwShaderFlags,
                0,
                NULL,
                &vsBlob,
                &pErrorBlob,
                NULL);
            if (FAILED(hr))
            {
                printf("Failed to compile vertex shader\n");
                if (pErrorBlob) pErrorBlob->Release();
                return false;
            }
            if (pErrorBlob) pErrorBlob->Release();
            hr = mDevicePtr->CreateVertexShader(
                vsBlob->GetBufferPointer(), vsBlob->GetBufferSize(), NULL, &mVertexShaderPtr);
            if (FAILED(hr))
            {
                printf("Failed to create vertex shader\n");
                vsBlob->Release();
                return false;
            }
        }

        // Layout
        if (!mVertexLayoutPtr)
        {
            D3D11_INPUT_ELEMENT_DESC layout[] =
            {
                { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
            };
            int numLayoutElements = sizeof layout/sizeof layout[0];
            hr = mDevicePtr->CreateInputLayout(
                layout, numLayoutElements, vsBlob->GetBufferPointer(), vsBlob->GetBufferSize(), &mVertexLayoutPtr);
            vsBlob->Release();
            if (FAILED(hr))
            {
                printf("Failed to create input layout\n");
                return false;
            }
        }

        // PS
        if (!mPixelShaderPtr)
        {
            hr = D3DX11CompileFromFile(
                effectLocation.asChar(),
                NULL,
                NULL,
                "mainPS",
                "ps_5_0",
                dwShaderFlags,
                0,
                NULL,
                &psBlob,
                &pErrorBlob,
                NULL);
            if (FAILED(hr))
            {
                printf("Failed to compile vertex shader\n");
                mVertexShaderPtr->Release();
                mVertexLayoutPtr->Release();
                if (pErrorBlob) pErrorBlob->Release();
                return false;
            }
            if (pErrorBlob) pErrorBlob->Release();
            hr = mDevicePtr->CreatePixelShader(
                psBlob->GetBufferPointer(), psBlob->GetBufferSize(), NULL, &mPixelShaderPtr);
            psBlob->Release();
            if (FAILED(hr))
            {
                printf("Failed to create pixel shader\n");
                mVertexShaderPtr->Release();
                mVertexLayoutPtr->Release();
                return false;
            }
        }

        return true;
    }

    bool FootPrintDrawAgentDX::initBuffersDX()
    {
        assert( mDevicePtr );
        if ( !mDevicePtr )
            return false;

        HRESULT hr;
        D3D11_BUFFER_DESC bd;
        ZeroMemory(&bd, sizeof(bd));
        D3D11_SUBRESOURCE_DATA InitData;
        ZeroMemory(&InitData, sizeof(InitData));

        if (!mBoundingboxVertexBufferPtr)
        {
            // 8 Vertices for drawing the bounding box in DX mode
            float bbData[][3] = {
                { -0.5, -0.5f, -0.5f},
                {  0.5, -0.5f, -0.5f},
                {  0.5, -0.5f,  0.5f},
                { -0.5, -0.5f,  0.5f},
                { -0.5,  0.5f, -0.5f},
                {  0.5,  0.5f, -0.5f},
                {  0.5,  0.5f,  0.5f},
                { -0.5,  0.5f,  0.5f}};

            bd.Usage = D3D11_USAGE_IMMUTABLE;
            bd.ByteWidth = sizeof(float) * 3 * 8;
            bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
            bd.CPUAccessFlags = 0;
            InitData.pSysMem = bbData;
            hr = mDevicePtr->CreateBuffer(&bd, &InitData, &mBoundingboxVertexBufferPtr);
            if (FAILED(hr)) return false;
        }
        if( !mBoundingboxIndexBufferPtr ){
            unsigned short bbWireIndices[] =
            {
                0,1,
                1,2,
                2,3,
                3,0,
                4,5,
                5,6,
                6,7,
                7,4,
                0,4,
                1,5,
                2,6,
                3,7
            };
            bd.Usage = D3D11_USAGE_IMMUTABLE;
            bd.ByteWidth = sizeof(unsigned short) * 2 * 12;
            bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
            bd.CPUAccessFlags = 0;
            InitData.pSysMem = bbWireIndices;
            hr = mDevicePtr->CreateBuffer(&bd, &InitData, &mBoundingboxIndexBufferPtr);
            if (FAILED(hr)) return false;
        }

        if (!mSoleVertexBufferPtr)
        {
            bd.Usage = D3D11_USAGE_IMMUTABLE;
            bd.ByteWidth = sizeof(float) * 3 * soleCount;
            bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
            bd.CPUAccessFlags = 0;
            InitData.pSysMem = sole;
            hr = mDevicePtr->CreateBuffer(&bd, &InitData, &mSoleVertexBufferPtr);
            if (FAILED(hr)) return false;
        }
        if (!mHeelVertexBufferPtr)
        {
            bd.Usage = D3D11_USAGE_IMMUTABLE;
            bd.ByteWidth = sizeof(float) * 3 * heelCount;
            bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
            bd.CPUAccessFlags = 0;
            InitData.pSysMem = heel;
            hr = mDevicePtr->CreateBuffer(&bd, &InitData, &mHeelVertexBufferPtr);
            if (FAILED(hr)) return false;
        }
        if (!mSoleWireIndexBufferPtr)
        {
            unsigned short soleWireIndices[] =
            {
                0, 1,
                1, 2,
                2, 3,
                3, 4,
                4, 5,
                5, 6,
                6, 7,
                7, 8,
                8, 9,
                9, 10,
                10, 11,
                11, 12,
                12, 13,
                13, 14,
                14, 15,
                15, 16,
                16, 17,
                17, 18,
                18, 19,
                19, 20
            };
            bd.Usage = D3D11_USAGE_IMMUTABLE;
            bd.ByteWidth = sizeof(unsigned short) * 2 * (soleCount-1);
            bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
            bd.CPUAccessFlags = 0;
            InitData.pSysMem = soleWireIndices;
            hr = mDevicePtr->CreateBuffer(&bd, &InitData, &mSoleWireIndexBufferPtr);
            if (FAILED(hr)) return false;
        }
        if (!mHeelWireIndexBufferPtr)
        {
            unsigned short heelWireIndices[] =
            {
                0, 1,
                1, 2,
                2, 3,
                3, 4,
                4, 5,
                5, 6,
                6, 7,
                7, 8,
                8, 9,
                9, 10,
                10, 11,
                11, 12,
                12, 13,
                13, 14,
                14, 15,
                15, 16
            };
            bd.Usage = D3D11_USAGE_IMMUTABLE;
            bd.ByteWidth = sizeof(unsigned short) * 2 * (heelCount-1);
            bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
            bd.CPUAccessFlags = 0;
            InitData.pSysMem = heelWireIndices;
            hr = mDevicePtr->CreateBuffer(&bd, &InitData, &mHeelWireIndexBufferPtr);
            if (FAILED(hr)) return false;
        }
        if (!mSoleShadedIndexBufferPtr)
        {
            unsigned short soleShadedIndices[] =
            {
                0, 1, 2,
                0, 2, 3,
                0, 3, 4,
                0, 4, 5,
                0, 5, 6,
                0, 6, 7,
                0, 7, 8,
                0, 8, 9,
                0, 9, 10,
                0, 10, 11,
                0, 11, 12,
                0, 12, 13,
                0, 13, 14,
                0, 14, 15,
                0, 15, 16,
                0, 16, 17,
                0, 17, 18,
                0, 18, 19,
                0, 19, 20
            };
            bd.Usage = D3D11_USAGE_IMMUTABLE;
            bd.ByteWidth = sizeof(unsigned short) * 3 * (soleCount-2);
            bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
            bd.CPUAccessFlags = 0;
            InitData.pSysMem = soleShadedIndices;
            hr = mDevicePtr->CreateBuffer(&bd, &InitData, &mSoleShadedIndexBufferPtr);
            if (FAILED(hr)) return false;
        }
        if (!mHeelShadedIndexBufferPtr)
        {
            unsigned short heelShadedIndices[] =
            {
                0, 1, 2,
                0, 2, 3,
                0, 3, 4,
                0, 4, 5,
                0, 5, 6,
                0, 6, 7,
                0, 7, 8,
                0, 8, 9,
                0, 9, 10,
                0, 10, 11,
                0, 11, 12,
                0, 12, 13,
                0, 13, 14,
                0, 14, 15,
                0, 15, 16
            };
            bd.Usage = D3D11_USAGE_IMMUTABLE;
            bd.ByteWidth = sizeof(unsigned short) * 3 * (heelCount-2);
            bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
            bd.CPUAccessFlags = 0;
            InitData.pSysMem = heelShadedIndices;
            hr = mDevicePtr->CreateBuffer(&bd, &InitData, &mHeelShadedIndexBufferPtr);
            if (FAILED(hr)) return false;
        }
        if (!mConstantBufferPtr)
        {
            bd.Usage = D3D11_USAGE_DEFAULT;
            bd.ByteWidth = sizeof(ConstantBufferDef);
            bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
            bd.CPUAccessFlags = 0;
            hr = mDevicePtr->CreateBuffer(&bd, NULL, &mConstantBufferPtr);
            if (FAILED(hr)) return false;
        }

        return true;
    }

    bool FootPrintDrawAgentDX::releaseDXResources()
    {
        if (mBoundingboxVertexBufferPtr)
        {
            mBoundingboxVertexBufferPtr->Release();
            mBoundingboxVertexBufferPtr = NULL;
        }
        if (mBoundingboxIndexBufferPtr)
        {
            mBoundingboxIndexBufferPtr->Release();
            mBoundingboxIndexBufferPtr = NULL;
        }

        if (mSoleVertexBufferPtr)
        {
            mSoleVertexBufferPtr->Release();
            mSoleVertexBufferPtr = NULL;
        }
        if (mHeelVertexBufferPtr)
        {
            mHeelVertexBufferPtr->Release();
            mHeelVertexBufferPtr = NULL;
        }
        if (mSoleWireIndexBufferPtr)
        {
            mSoleWireIndexBufferPtr->Release();
            mSoleWireIndexBufferPtr = NULL;
        }
        if (mSoleShadedIndexBufferPtr)
        {
            mSoleShadedIndexBufferPtr->Release();
            mSoleShadedIndexBufferPtr = NULL;
        }
        if (mHeelWireIndexBufferPtr)
        {
            mHeelWireIndexBufferPtr->Release();
            mHeelWireIndexBufferPtr = NULL;
        }
        if (mHeelShadedIndexBufferPtr)
        {
            mHeelShadedIndexBufferPtr->Release();
            mHeelShadedIndexBufferPtr = NULL;
        }
        if (mVertexShaderPtr)
        {
            mVertexShaderPtr->Release();
            mVertexShaderPtr = NULL;
        }
        if (mPixelShaderPtr)
        {
            mPixelShaderPtr->Release();
            mPixelShaderPtr = NULL;
        }
        if (mVertexLayoutPtr)
        {
            mVertexLayoutPtr->Release();
            mVertexLayoutPtr = NULL;
        }
        if (mConstantBufferPtr)
        {
            mConstantBufferPtr->Release();
            mConstantBufferPtr = NULL;
        }

        return true;
    }

    #endif // _WIN32

    //---------------------------------------------------------------------------
    //---------------------------------------------------------------------------
    // Plugin Registration
    //---------------------------------------------------------------------------
    //---------------------------------------------------------------------------

    MStatus footPrint::initialize()
    {
        MFnUnitAttribute unitFn;
        MStatus          stat;

        size = unitFn.create( "size", "sz", MFnUnitAttribute::kDistance );
        unitFn.setDefault( 1.0 );

        stat = addAttribute( size );
        if (!stat) {
            stat.perror("addAttribute");
            return stat;
        }

        return MS::kSuccess;
    }

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

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

        status = MHWRender::MDrawRegistry::registerDrawOverrideCreator(
            footPrint::drawDbClassification,
            footPrint::drawRegistrantId,
            FootPrintDrawOverride::Creator);
        if (!status) {
            status.perror("registerDrawOverrideCreator");
            return status;
        }

        return status;
    }

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

        status = MHWRender::MDrawRegistry::deregisterDrawOverrideCreator(
            footPrint::drawDbClassification,
            footPrint::drawRegistrantId);
        if (!status) {
            status.perror("deregisterDrawOverrideCreator");
            return status;
        }

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

        // Release DX resource
    #ifdef _WIN32
        FootPrintDrawAgentDX& drawAgentRef = FootPrintDrawAgentDX::getDrawAgent();
        drawAgentRef.releaseDXResources();
    #endif

        return status;
    }