footPrintNode.cpp

//-
// ==========================================================================
// Copyright 1995,2006,2008 Autodesk, Inc. All rights reserved.
//
// Use of this software is subject to the terms of the Autodesk
// license agreement provided at the time of installation or download,
// or which otherwise accompanies this software in either electronic
// or hard copy form.
// ==========================================================================
//+

#include <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>

// 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>

static ID3D11Buffer* sSoleVertexBuffer = NULL;
static ID3D11Buffer* sHeelVertexBuffer = NULL;
static ID3D11Buffer* sSoleWireIndexBuffer = NULL;
static ID3D11Buffer* sSoleShadedIndexBuffer = NULL;
static ID3D11Buffer* sHeelWireIndexBuffer = NULL;
static ID3D11Buffer* sHeelShadedIndexBuffer = NULL;
static ID3D11Buffer* sConstantBuffer = NULL;
static ID3D11VertexShader* sVertexShader = NULL;
static ID3D11PixelShader* sPixelShader = NULL;
static ID3D11InputLayout* sVertexLayout = NULL;
#endif

// 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();
}

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

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,
        MUserData* oldData);

    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;

#ifdef _WIN32
    struct ConstantBufferDef
    {
        XMMATRIX fWVP;
        XMFLOAT4 fMatColor;
    };
    static bool initShadersDX(ID3D11Device* dxDevice);
    static bool initBuffersDX(ID3D11Device* dxDevice);
#endif
};

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

    return data;
}

void FootPrintDrawOverride::draw(const MHWRender::MDrawContext& context, const MUserData* data)
{
    // get renderer
    MHWRender::MRenderer* theRenderer = MHWRender::MRenderer::theRenderer();
    if (!theRenderer) return;

    // get state data
    MStatus status;
    const MMatrix transform =
        context.getMatrix(MHWRender::MDrawContext::kWorldViewMtx, &status);
    if (status != MStatus::kSuccess) return;
    const MMatrix projection =
        context.getMatrix(MHWRender::MDrawContext::kProjectionMtx, &status);
    if (status != MStatus::kSuccess) return;

    const int displayStyle = context.getDisplayStyle();
    const FootPrintData* footData = dynamic_cast<const FootPrintData*>(data);
    if (!footData)
        return;

    // If we don't want to draw the bounds within this plugin
    // manaully, 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 (displayStyle & MHWRender::MDrawContext::kBoundingBox)
    {
        if (!footData->fCustomBoxDraw)
            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::MDrawContext::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::MDrawContext::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::MDrawContext::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);
                }
            }
        }
    }

    // GL Draw
    if (theRenderer->drawAPIIsOpenGL())
    {
        // set colour
        glColor4fv(color);

        // set world matrix
        glMatrixMode(GL_MODELVIEW);
        glPushMatrix();
        glLoadMatrixd(transform.matrix[0]);

        // set projection matrix
        glMatrixMode(GL_PROJECTION);
        glPushMatrix();
        glLoadMatrixd(projection.matrix[0]);

        // Override drawing of bounding boxes. Simple sample
        // code to show drawing the bounding box filled versus
        // non-filled.
        //
        if (displayStyle & MHWRender::MDrawContext::kBoundingBox)
        {
            MPoint min = footData->fCurrentBoundingBox.min();
            MPoint max = footData->fCurrentBoundingBox.max();

            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_QUADS );

            // front
            //
            glVertex3fv( bottomLeftFront );
            glVertex3fv( topLeftFront  );
            glVertex3fv( topRightFront );
            glVertex3fv( bottomRightFront );
            // back
            //
            glVertex3fv( bottomLeftBack  );
            glVertex3fv( topLeftBack  );
            glVertex3fv( topRightBack );
            glVertex3fv( bottomRightBack );
            // left
            //
            glVertex3fv( topLeftFront  );
            glVertex3fv( topLeftBack);
            glVertex3fv( bottomLeftBack );
            glVertex3fv( bottomLeftFront );
            // right
            //
            glVertex3fv( topRightFront  );
            glVertex3fv( topRightBack);
            glVertex3fv( bottomRightBack );
            glVertex3fv( bottomRightFront );
            // top
            //
            glVertex3fv( topLeftFront  );
            glVertex3fv( topRightFront );
            glVertex3fv( topRightBack  );
            glVertex3fv( topLeftBack  );
            // bottom
            //
            glVertex3fv( bottomLeftFront  );
            glVertex3fv( bottomRightFront );
            glVertex3fv( bottomRightBack  );
            glVertex3fv( bottomLeftBack  );

            glEnd();
        }

        if(displayStyle & MHWRender::MDrawContext::kGouraudShaded)
        {
            glPushAttrib( GL_CURRENT_BIT );

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

        if(displayStyle & MHWRender::MDrawContext::kWireFrame)
        {
            // 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();
        }

        glPopMatrix();
        glMatrixMode(GL_MODELVIEW);
        glPopMatrix();
    }
#ifdef _WIN32
    // DX Draw
    else
    {
        // init device
        ID3D11Device* dxDevice = (ID3D11Device*)theRenderer->GPUDeviceHandle();
        if (!dxDevice) return;
        // get context
        ID3D11DeviceContext* dxContext = NULL;
        dxDevice->GetImmediateContext(&dxContext);
        if (!dxContext) return;
        // create shaders (if they don't exist)
        if (!initShadersDX(dxDevice)) return;
        // create buffers (if they don't exist)
        if (!initBuffersDX(dxDevice)) return;

        // Compute matrix
        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 );
        XMMATRIX dxTransform = XMMATRIX(
            (float)transform.matrix[0][0], (float)transform.matrix[0][1], (float)transform.matrix[0][2], (float)transform.matrix[0][3],
            (float)transform.matrix[1][0], (float)transform.matrix[1][1], (float)transform.matrix[1][2], (float)transform.matrix[1][3],
            (float)transform.matrix[2][0], (float)transform.matrix[2][1], (float)transform.matrix[2][2], (float)transform.matrix[2][3],
            (float)transform.matrix[3][0], (float)transform.matrix[3][1], (float)transform.matrix[3][2], (float)transform.matrix[3][3]);
        XMMATRIX dxProjection = XMMATRIX(
            (float)projection.matrix[0][0], (float)projection.matrix[0][1], (float)projection.matrix[0][2], (float)projection.matrix[0][3],
            (float)projection.matrix[1][0], (float)projection.matrix[1][1], (float)projection.matrix[1][2], (float)projection.matrix[1][3],
            (float)projection.matrix[2][0], (float)projection.matrix[2][1], (float)projection.matrix[2][2], (float)projection.matrix[2][3],
            (float)projection.matrix[3][0], (float)projection.matrix[3][1], (float)projection.matrix[3][2], (float)projection.matrix[3][3]);

        // Set up shader
        ConstantBufferDef cb;
        cb.fWVP = XMMatrixTranspose(scale * dxTransform * dxProjection);
        cb.fMatColor = XMFLOAT4(color[0], color[1], color[2], color[3]);
        dxContext->UpdateSubresource(sConstantBuffer, 0, NULL, &cb, 0, 0);
        dxContext->VSSetShader(sVertexShader, NULL, 0);
        dxContext->VSSetConstantBuffers(0, 1, &sConstantBuffer);
        dxContext->IASetInputLayout(sVertexLayout);
        dxContext->PSSetShader(sPixelShader, NULL, 0);
        dxContext->PSSetConstantBuffers(0, 1, &sConstantBuffer);

        // Do the actual drawing
        UINT stride = sizeof(float) * 3;
        UINT offset = 0;
        if(displayStyle & MHWRender::MDrawContext::kGouraudShaded)
        {
            // Draw the sole
            dxContext->IASetVertexBuffers(0, 1, &sSoleVertexBuffer, &stride, &offset);
            dxContext->IASetIndexBuffer(sSoleShadedIndexBuffer, DXGI_FORMAT_R16_UINT, 0);
            dxContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
            dxContext->DrawIndexed(3 * (soleCount-2), 0, 0);
            // Draw the heel
            dxContext->IASetVertexBuffers(0, 1, &sHeelVertexBuffer, &stride, &offset);
            dxContext->IASetIndexBuffer(sHeelShadedIndexBuffer, DXGI_FORMAT_R16_UINT, 0);
            dxContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
            dxContext->DrawIndexed(3 * (heelCount-2), 0, 0);
        }
        if(displayStyle & MHWRender::MDrawContext::kWireFrame)
        {
            // Draw the sole
            dxContext->IASetVertexBuffers(0, 1, &sSoleVertexBuffer, &stride, &offset);
            dxContext->IASetIndexBuffer(sSoleWireIndexBuffer, DXGI_FORMAT_R16_UINT, 0);
            dxContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST);
            dxContext->DrawIndexed(2 * (soleCount-1), 0, 0);
            // Draw the heel
            dxContext->IASetVertexBuffers(0, 1, &sHeelVertexBuffer, &stride, &offset);
            dxContext->IASetIndexBuffer(sHeelWireIndexBuffer, DXGI_FORMAT_R16_UINT, 0);
            dxContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST);
            dxContext->DrawIndexed(2 * (heelCount-1), 0, 0);
        }
    }
#endif

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

#ifdef _WIN32
bool FootPrintDrawOverride::initShadersDX(ID3D11Device* dxDevice)
{
    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 (!sVertexShader)
    {
        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 = dxDevice->CreateVertexShader(
            vsBlob->GetBufferPointer(), vsBlob->GetBufferSize(), NULL, &sVertexShader);
        if (FAILED(hr))
        {
            printf("Failed to create vertex shader\n");
            vsBlob->Release();
            return false;
        }
    }

    // Layout
    if (!sVertexLayout)
    {
        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 = dxDevice->CreateInputLayout(
            layout, numLayoutElements, vsBlob->GetBufferPointer(), vsBlob->GetBufferSize(), &sVertexLayout);
        vsBlob->Release();
        if (FAILED(hr))
        {
            printf("Failed to create input layout\n");
            return false;
        }
    }

    // PS
    if (!sPixelShader)
    {
        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");
            sVertexShader->Release();
            sVertexLayout->Release();
            if (pErrorBlob) pErrorBlob->Release();
            return false;
        }
        if (pErrorBlob) pErrorBlob->Release();
        hr = dxDevice->CreatePixelShader(
            psBlob->GetBufferPointer(), psBlob->GetBufferSize(), NULL, &sPixelShader);
        psBlob->Release();
        if (FAILED(hr))
        {
            printf("Failed to create pixel shader\n");
            sVertexShader->Release();
            sVertexLayout->Release();
            return false;
        }
    }

    return true;
}

bool FootPrintDrawOverride::initBuffersDX(ID3D11Device* dxDevice)
{
    HRESULT hr;
    D3D11_BUFFER_DESC bd;
    ZeroMemory(&bd, sizeof(bd));
    D3D11_SUBRESOURCE_DATA InitData;
    ZeroMemory(&InitData, sizeof(InitData));
    if (!sSoleVertexBuffer)
    {
        bd.Usage = D3D11_USAGE_IMMUTABLE;
        bd.ByteWidth = sizeof(float) * 3 * soleCount;
        bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
        bd.CPUAccessFlags = 0;
        InitData.pSysMem = sole;
        hr = dxDevice->CreateBuffer(&bd, &InitData, &sSoleVertexBuffer);
        if (FAILED(hr)) return false;
    }
    if (!sHeelVertexBuffer)
    {
        bd.Usage = D3D11_USAGE_IMMUTABLE;
        bd.ByteWidth = sizeof(float) * 3 * heelCount;
        bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
        bd.CPUAccessFlags = 0;
        InitData.pSysMem = heel;
        hr = dxDevice->CreateBuffer(&bd, &InitData, &sHeelVertexBuffer);
        if (FAILED(hr)) return false;
    }
    if (!sSoleWireIndexBuffer)
    {
        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 = dxDevice->CreateBuffer(&bd, &InitData, &sSoleWireIndexBuffer);
        if (FAILED(hr)) return false;
    }
    if (!sHeelWireIndexBuffer)
    {
        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 = dxDevice->CreateBuffer(&bd, &InitData, &sHeelWireIndexBuffer);
        if (FAILED(hr)) return false;
    }
    if (!sSoleShadedIndexBuffer)
    {
        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 = dxDevice->CreateBuffer(&bd, &InitData, &sSoleShadedIndexBuffer);
        if (FAILED(hr)) return false;
    }
    if (!sHeelShadedIndexBuffer)
    {
        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 = dxDevice->CreateBuffer(&bd, &InitData, &sHeelShadedIndexBuffer);
        if (FAILED(hr)) return false;
    }
    if (!sConstantBuffer)
    {
        bd.Usage = D3D11_USAGE_DEFAULT;
        bd.ByteWidth = sizeof(ConstantBufferDef);
        bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
        bd.CPUAccessFlags = 0;
        hr = dxDevice->CreateBuffer(&bd, NULL, &sConstantBuffer);
        if (FAILED(hr)) return false;
    }

    return true;
}
#endif

//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// 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 );

#ifdef _WIN32
    // DX cleanup
    if (sSoleVertexBuffer)
    {
        sSoleVertexBuffer->Release();
        sSoleVertexBuffer = NULL;
    }
    if (sHeelVertexBuffer)
    {
        sHeelVertexBuffer->Release();
        sHeelVertexBuffer = NULL;
    }
    if (sSoleWireIndexBuffer)
    {
        sSoleWireIndexBuffer->Release();
        sSoleWireIndexBuffer = NULL;
    }
    if (sSoleShadedIndexBuffer)
    {
        sSoleShadedIndexBuffer->Release();
        sSoleShadedIndexBuffer = NULL;
    }
    if (sHeelWireIndexBuffer)
    {
        sHeelWireIndexBuffer->Release();
        sHeelWireIndexBuffer = NULL;
    }
    if (sHeelShadedIndexBuffer)
    {
        sHeelShadedIndexBuffer->Release();
        sHeelShadedIndexBuffer = NULL;
    }
    if (sVertexShader)
    {
        sVertexShader->Release();
        sVertexShader = NULL;
    }
    if (sPixelShader)
    {
        sPixelShader->Release();
        sPixelShader = NULL;
    }
    if (sVertexLayout)
    {
        sVertexLayout->Release();
        sVertexLayout = NULL;
    }
    if (sConstantBuffer)
    {
        sConstantBuffer->Release();
        sConstantBuffer = NULL;
    }
#endif

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

    return status;
}