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

// 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 heelCount = 17;
static int soleCount = 21;

//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// 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;
    bool fIsSelected;
};

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

    virtual ~FootPrintDrawOverride();

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

    virtual MUserData* prepareForDraw(
        const MDagPath& objPath,
        const MDagPath& cameraPath,
        MUserData* oldData);

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

private:
    FootPrintDrawOverride(const MObject& obj);

    float getMultiplier(const MDagPath& objPath) const;
    bool getSelectionStatus(const MDagPath& objPath) const;
};

FootPrintDrawOverride::FootPrintDrawOverride(const MObject& obj)
: MHWRender::MPxDrawOverride(obj, FootPrintDrawOverride::draw)
{
}

FootPrintDrawOverride::~FootPrintDrawOverride()
{
}

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::getSelectionStatus(const MDagPath& objPath) const
{
    // retrieve the selection status of the node
    MStatus status;
    MSelectionList selectedList;
    status = MGlobal::getActiveSelectionList(selectedList);
    if(!status)
        return false;

    MDagPath pathCopy = objPath;
    do
    {
        if(selectedList.hasItem(pathCopy))
            return true;

        status = pathCopy.pop();
    }while(status);

    return false;
}

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;

    return MBoundingBox(corner1, corner2);
}

MUserData* FootPrintDrawOverride::prepareForDraw(
    const MDagPath& objPath,
    const MDagPath& cameraPath,
    MUserData* oldData)
{
    // Cache multiplier attribute value for draw callback
    FootPrintData* data = dynamic_cast<FootPrintData*>(oldData);
    if (!data)
    {
        // data did not exist or was incorrect type, create new
        data = new FootPrintData();
    }
    data->fMultiplier = getMultiplier(objPath);
    data->fIsSelected = getSelectionStatus(objPath);

    return data;
}

void FootPrintDrawOverride::draw(const MHWRender::MDrawContext& context, const MUserData* data)
{
    // get cached data
    float multiplier = 1.0f;
    bool isSelected = false;
    const FootPrintData* footData = dynamic_cast<const FootPrintData*>(data);
    if (footData)
    {
        multiplier = footData->fMultiplier;
        isSelected = footData->fIsSelected;
    }

    // set colour
    static const float colorData[] = {1.0f, 0.0f, 0.0f};
    static const float selectedColorData[] = {0.0f, 1.0f, 0.0f};
    if(isSelected)
        glColor3fv(selectedColorData);
    else
        glColor3fv(colorData);


    MStatus status;

    // set world matrix
    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    MFloatMatrix transform =
        context.getMatrix(MHWRender::MDrawContext::kWorldViewMtx, &status);
    if (status)
    {
        glLoadMatrixf(transform.matrix[0]);
    }

    // set projection matrix
    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    MFloatMatrix projection =
        context.getMatrix(MHWRender::MDrawContext::kProjectionMtx, &status);
    if (status)
    {
        glLoadMatrixf(projection.matrix[0]);
    }

    const int displayStyle = context.getDisplayStyle();

    if(displayStyle & MHWRender::MDrawContext::kGouraudShaded)
    {
        // draw filled
        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();

}

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

    return status;
}