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;
}