footPrintNode/footPrintNode.cpp
 
 
 
footPrintNode/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;
}