solidCheckerShader.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 <math.h>

#include <maya/MGlobal.h>
#include <maya/MPxNode.h>
#include <maya/MString.h>
#include <maya/MTypeId.h>
#include <maya/MPlug.h>
#include <maya/MDataBlock.h>
#include <maya/MDataHandle.h> 
#include <maya/MFnNumericAttribute.h>
#include <maya/MFnMatrixAttribute.h>
#include <maya/MFloatVector.h>
#include <maya/MFloatPoint.h>
#include <maya/MFloatMatrix.h>
#include <maya/MFnPlugin.h>

class mySChecker : public MPxNode
{
    public:
    mySChecker();
    virtual ~mySChecker();

    virtual MStatus compute( const MPlug&, MDataBlock& );
    virtual void    postConstructor();

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

    //  Id tag for use with binary file format
    static const MTypeId id;

    private:

    // Input attributes
    static MObject aColor1;
    static MObject aColor2;
    static MObject aPlaceMat;
    static MObject aPointWorld;
    static MObject aBias;

    // Output attributes
    static MObject aOutColor;
    static MObject aOutAlpha;
};


// Static data
const MTypeId mySChecker::id( 0x8100b );

// Attributes
MObject        mySChecker::aColor1;
MObject        mySChecker::aColor2;
MObject        mySChecker::aPlaceMat;
MObject        mySChecker::aPointWorld;
MObject        mySChecker::aBias;
 
MObject        mySChecker::aOutColor;
MObject        mySChecker::aOutAlpha;

#define MAKE_INPUT(attr)                                \
    attr.setKeyable(true);  attr.setStorable(true);     \
    attr.setReadable(true); attr.setWritable(true);

#define MAKE_OUTPUT(attr)                               \
    attr.setKeyable(false); attr.setStorable(false);    \
    attr.setReadable(true); attr.setWritable(false);

void mySChecker::postConstructor( )
{
    setMPSafe(true);
}

mySChecker::mySChecker()
{
}

mySChecker::~mySChecker()
{
}

// creates an instance of the node
void * mySChecker::creator()
{
    return new mySChecker();
}

// initializes attribute information
MStatus mySChecker::initialize()
{
    MFnMatrixAttribute mAttr; 
    MFnNumericAttribute nAttr; 
    MObject x, y, z;

    aColor1 = nAttr.createColor("color1", "c1");
    MAKE_INPUT(nAttr);
    nAttr.setDefault(0., .58824, .644);     // Light blue

    aColor2 = nAttr.createColor("color2", "c2");
    MAKE_INPUT(nAttr);
    nAttr.setDefault(1., 1., 1.);           // White

    aBias = nAttr.create( "bias", "b", MFnNumericData::k3Float);
    MAKE_INPUT(nAttr);
    nAttr.setMin(0.0f);
    nAttr.setMax(1.0f);
    nAttr.setDefault(0.5f, 0.5f, 0.5f);

    aPlaceMat = mAttr.create("placementMatrix", "pm",
                             MFnMatrixAttribute::kFloat);
    MAKE_INPUT(mAttr);

    // Internal shading attribute, implicitely connected.
    aPointWorld = nAttr.createPoint("pointWorld", "pw");
    MAKE_INPUT(nAttr);
    nAttr.setHidden(true);

    // Create output attributes
    aOutColor = nAttr.createColor("outColor", "oc");
    MAKE_OUTPUT(nAttr);

    aOutAlpha = nAttr.create( "outAlpha", "oa", MFnNumericData::kFloat);
    MAKE_OUTPUT(nAttr);

    // Add the attributes here
    addAttribute(aColor1);
    addAttribute(aColor2);
    addAttribute(aPointWorld);
    addAttribute(aPlaceMat);
    addAttribute(aBias);

    addAttribute(aOutColor);
    addAttribute(aOutAlpha);

    // all input affect the output color and alpha
    attributeAffects (aColor1, aOutColor);
    attributeAffects (aColor1, aOutAlpha);

    attributeAffects (aColor2, aOutColor);
    attributeAffects (aColor2, aOutAlpha);

    attributeAffects (aPointWorld, aOutColor);
    attributeAffects (aPointWorld, aOutAlpha);

    attributeAffects (aPlaceMat, aOutColor);
    attributeAffects (aPlaceMat, aOutAlpha);

    attributeAffects (aBias, aOutColor);
    attributeAffects (aBias, aOutAlpha);

    return MS::kSuccess;
}


//
// This function gets called by Maya to evaluate the texture.
//
MStatus mySChecker::compute(const MPlug& plug, MDataBlock& block) 
{
    // outColor or individial R, G, B channel, or alpha
    if((plug != aOutColor) && (plug.parent() != aOutColor) && 
       (plug != aOutAlpha))
        return MS::kUnknownParameter;

    MFloatVector resultColor;
    float3 & worldPos = block.inputValue(aPointWorld).asFloat3();
    MFloatMatrix& mat = block.inputValue(aPlaceMat).asFloatMatrix();
    float3 & bias = block.inputValue(aBias).asFloat3();

    MFloatPoint pos(worldPos[0], worldPos[1], worldPos[2]);
    pos *= mat;                             // Convert into solid space

    // normalize the point
    int count = 0;
    if (pos.x - floor(pos.x) < bias[0]) count++;
    if (pos.y - floor(pos.y) < bias[1]) count++;
    if (pos.z - floor(pos.z) < bias[2]) count++;

    if (count & 1)
        resultColor = block.inputValue(aColor2).asFloatVector();
    else
        resultColor = block.inputValue(aColor1).asFloatVector();

    // Set ouput color attribute
    MDataHandle outColorHandle = block.outputValue( aOutColor );
    MFloatVector& outColor = outColorHandle.asFloatVector();
    outColor = resultColor;
    outColorHandle.setClean();

    // Set ouput alpha attribute
    MDataHandle outAlphaHandle = block.outputValue( aOutAlpha );
    float& outAlpha = outAlphaHandle.asFloat();
    outAlpha = ( count & 1) ? 1.0f : 0.0f;
    outAlphaHandle.setClean();

    return MS::kSuccess;
}


MStatus initializePlugin( MObject obj )
{
    const MString UserClassify( "texture/3d" );

    MFnPlugin plugin( obj, PLUGIN_COMPANY, "4.5", "Any");
    plugin.registerNode("solidChecker", mySChecker::id, 
                        &mySChecker::creator, &mySChecker::initialize,
                        MPxNode::kDependNode, &UserClassify );

    return MS::kSuccess;
}

MStatus uninitializePlugin( MObject obj )
{
    MFnPlugin plugin( obj );
    plugin.deregisterNode( mySChecker::id );

    return MS::kSuccess;
}