#include <math.h>
#include <maya/MPxNode.h>
#include <maya/MIOStream.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/MFnLightDataAttribute.h>
#include <maya/MFloatVector.h>
#include <maya/MFnPlugin.h>
class LightNode : public MPxNode
{
        public:
                      LightNode();
    virtual           ~LightNode();
    virtual MStatus   compute( const MPlug&, MDataBlock& );
        virtual void      postConstructor();
    static void *     creator();
    static MStatus    initialize();
    static MTypeId    id;
        private
:
        
        static MObject  aColor;
        static MObject  aPosition;
        static MObject  aInputDirection;
    static MObject  aInputAmbient;
    static MObject  aInputDiffuse;
    static MObject  aInputSpecular;
    static MObject  aIntensity;
        static MObject  aLightDirection;
        static MObject  aLightIntensity;
    static MObject  aLightAmbient;
    static MObject  aLightDiffuse;
    static MObject  aLightSpecular;
    static MObject  aLightShadowFraction;
    static MObject  aPreShadowIntensity;
    static MObject  aLightBlindData;
    static MObject  aLightData;
};
MTypeId LightNode::id( 0x81010 );
MObject  LightNode::aColor;
MObject  LightNode::aPosition;
MObject  LightNode::aInputDirection;
MObject  LightNode::aInputAmbient;
MObject  LightNode::aInputDiffuse;
MObject  LightNode::aInputSpecular;
MObject  LightNode::aIntensity; 
MObject  LightNode::aLightData;
MObject  LightNode::aLightDirection;
MObject  LightNode::aLightIntensity;
MObject  LightNode::aLightAmbient;
MObject  LightNode::aLightDiffuse;
MObject  LightNode::aLightSpecular;
MObject  LightNode::aLightShadowFraction;
MObject  LightNode::aPreShadowIntensity;
MObject  LightNode::aLightBlindData;
void LightNode::postConstructor( )
{
        setMPSafe(true);
}
LightNode::LightNode()
{
}
LightNode::~LightNode()
{
}
void * LightNode::creator()
{
    return new LightNode();
}
MStatus LightNode::initialize()
{
    MFnNumericAttribute nAttr; 
    MFnLightDataAttribute lAttr;
    aColor = nAttr.createColor( "color", "c" );
    CHECK_MSTATUS ( nAttr.setKeyable(true) );
    CHECK_MSTATUS ( nAttr.setStorable(true) );
    CHECK_MSTATUS ( nAttr.setDefault(0.0f, 0.58824f, 0.644f) );
    aPosition = nAttr.createPoint( "position", "pos" );
    CHECK_MSTATUS ( nAttr.setKeyable(true) );
    CHECK_MSTATUS ( nAttr.setStorable(true) );
    aInputDirection = nAttr.createPoint( "inputDirection", "id" );
    CHECK_MSTATUS ( nAttr.setKeyable(true) );
    CHECK_MSTATUS ( nAttr.setStorable(true) );
    CHECK_MSTATUS ( nAttr.setDefault(-1.0f, 0.0f, 0.0f) );
    aInputAmbient = nAttr.create( "ambientOn", "an", MFnNumericData::kBoolean);
    CHECK_MSTATUS ( nAttr.setKeyable(true) );
    CHECK_MSTATUS ( nAttr.setStorable(true) );
    CHECK_MSTATUS ( nAttr.setHidden(false) );
    CHECK_MSTATUS ( nAttr.setDefault(true) );
    aInputDiffuse = nAttr.create( "diffuseOn", "dn", MFnNumericData::kBoolean);
    CHECK_MSTATUS ( nAttr.setKeyable(true) );
    CHECK_MSTATUS ( nAttr.setStorable(true) );
    CHECK_MSTATUS ( nAttr.setHidden(false) );
    CHECK_MSTATUS ( nAttr.setDefault(true) );
    aInputSpecular = nAttr.create( "specularOn", "sn", MFnNumericData::kBoolean);
    CHECK_MSTATUS ( nAttr.setKeyable(true) );
    CHECK_MSTATUS ( nAttr.setStorable(true) );
    CHECK_MSTATUS ( nAttr.setHidden(false) );
    CHECK_MSTATUS ( nAttr.setDefault(true) );
    aIntensity = nAttr.create( "intensity", "i", MFnNumericData::kFloat);
    CHECK_MSTATUS ( nAttr.setKeyable(true) );
    CHECK_MSTATUS ( nAttr.setStorable(true) );
    CHECK_MSTATUS ( nAttr.setHidden(false) );
    CHECK_MSTATUS ( nAttr.setDefault(1.0f) );
    aLightDirection = nAttr.createPoint( "lightDirection", "ld" );
    CHECK_MSTATUS ( nAttr.setStorable(false) );
    CHECK_MSTATUS ( nAttr.setHidden(true) );
    CHECK_MSTATUS ( nAttr.setReadable(true) );
    CHECK_MSTATUS ( nAttr.setWritable(false) );
    CHECK_MSTATUS ( nAttr.setDefault(-1.0f, 0.0f, 0.0f) );
    aLightIntensity = nAttr.createColor( "lightIntensity", "li" );
    CHECK_MSTATUS ( nAttr.setStorable(false) );
    CHECK_MSTATUS ( nAttr.setHidden(true) );
    CHECK_MSTATUS ( nAttr.setReadable(true) );
    CHECK_MSTATUS ( nAttr.setWritable(false) );
    CHECK_MSTATUS ( nAttr.setDefault(1.0f, 0.5f, 0.2f) );
    aLightAmbient = nAttr.create( "lightAmbient", "la", 
                                                                  MFnNumericData::kBoolean);
    CHECK_MSTATUS ( nAttr.setStorable(false) );
    CHECK_MSTATUS ( nAttr.setHidden(true) );
    CHECK_MSTATUS ( nAttr.setReadable(true) );
    CHECK_MSTATUS ( nAttr.setWritable(false) );
    nAttr.setDefault(true);
    aLightDiffuse = nAttr.create( "lightDiffuse", "ldf",
                                                                  MFnNumericData::kBoolean);
    CHECK_MSTATUS ( nAttr.setStorable(false) );
    CHECK_MSTATUS ( nAttr.setHidden(true) );
    CHECK_MSTATUS ( nAttr.setReadable(true) );
    CHECK_MSTATUS ( nAttr.setWritable(false) );
    CHECK_MSTATUS ( nAttr.setDefault(true) );
    aLightSpecular = nAttr.create( "lightSpecular", "ls", 
                                                                   MFnNumericData::kBoolean);
    CHECK_MSTATUS ( nAttr.setStorable(false) );
    CHECK_MSTATUS ( nAttr.setHidden(true) );
    CHECK_MSTATUS ( nAttr.setReadable(true) );
    CHECK_MSTATUS ( nAttr.setWritable(false) );
    CHECK_MSTATUS ( nAttr.setDefault(true) );
    aLightShadowFraction = nAttr.create("lightShadowFraction","lsf",
                                                                                MFnNumericData::kFloat);
    CHECK_MSTATUS ( nAttr.setStorable(false) );
    CHECK_MSTATUS ( nAttr.setHidden(true) );
    CHECK_MSTATUS ( nAttr.setReadable(true) );
    CHECK_MSTATUS ( nAttr.setWritable(false) );
    CHECK_MSTATUS ( nAttr.setDefault(0.0f) );
    aPreShadowIntensity = nAttr.create("preShadowIntensity","psi",
                                                                           MFnNumericData::kFloat);
    CHECK_MSTATUS ( nAttr.setStorable(false) );
    CHECK_MSTATUS ( nAttr.setHidden(true) );
    CHECK_MSTATUS ( nAttr.setReadable(true) );
    CHECK_MSTATUS ( nAttr.setWritable(false) );
    CHECK_MSTATUS ( nAttr.setDefault(0.0f) );
    aLightBlindData = nAttr.createAddr("lightBlindData","lbld");
    CHECK_MSTATUS ( nAttr.setStorable(false) );
    CHECK_MSTATUS ( nAttr.setHidden(true) );
    CHECK_MSTATUS ( nAttr.setReadable(true) );
    CHECK_MSTATUS ( nAttr.setWritable(false) );
    aLightData = lAttr.create( "lightData", "ltd", 
                               aLightDirection, aLightIntensity, 
                                                           aLightAmbient, 
                               aLightDiffuse, aLightSpecular, 
                                                           aLightShadowFraction,
                               aPreShadowIntensity, aLightBlindData);
    CHECK_MSTATUS ( nAttr.setReadable(true) );
    CHECK_MSTATUS ( nAttr.setWritable(false) );
    CHECK_MSTATUS ( lAttr.setStorable(false) );
    CHECK_MSTATUS ( lAttr.setHidden(true) );
    lAttr.setDefault(-1.0f, 0.0f, 0.0f, 1.0f, 0.5f, 0.2f, true, true,
                                         true, 0.0f, 1.0f, NULL);
    CHECK_MSTATUS ( addAttribute(aColor) );
    CHECK_MSTATUS ( addAttribute(aPosition) );
    CHECK_MSTATUS ( addAttribute(aInputDirection) );
    CHECK_MSTATUS ( addAttribute(aInputAmbient) );
    CHECK_MSTATUS ( addAttribute(aInputDiffuse) );
    CHECK_MSTATUS ( addAttribute(aInputSpecular) );
    CHECK_MSTATUS ( addAttribute(aIntensity) );
        
    CHECK_MSTATUS ( addAttribute(aLightData) );
    CHECK_MSTATUS ( attributeAffects (aLightIntensity, aLightData) );
    CHECK_MSTATUS ( attributeAffects (aLightDirection, aLightData) );
    CHECK_MSTATUS ( attributeAffects (aLightAmbient, aLightData) );
    CHECK_MSTATUS ( attributeAffects (aLightDiffuse, aLightData) );
    CHECK_MSTATUS ( attributeAffects (aLightSpecular, aLightData) );
    CHECK_MSTATUS ( attributeAffects (aLightShadowFraction, aLightData) );
    CHECK_MSTATUS ( attributeAffects (aPreShadowIntensity, aLightData) );
    CHECK_MSTATUS ( attributeAffects (aLightBlindData, aLightData) );
    CHECK_MSTATUS ( attributeAffects (aLightData, aLightData) );
    CHECK_MSTATUS ( attributeAffects (aColor, aLightData) );
    CHECK_MSTATUS ( attributeAffects (aPosition, aLightData) );
    CHECK_MSTATUS ( attributeAffects (aInputDirection, aLightData) );
    CHECK_MSTATUS ( attributeAffects (aInputAmbient, aLightData) );
    CHECK_MSTATUS ( attributeAffects (aInputDiffuse, aLightData) );
    CHECK_MSTATUS ( attributeAffects (aInputSpecular, aLightData) );
    CHECK_MSTATUS ( attributeAffects (aIntensity, aLightData) );
    return MS::kSuccess;
}
MStatus LightNode::compute(
const MPlug&      plug,
      MDataBlock& block ) 
{ 
    if ((plug != aLightData) && (plug.parent() != aLightData))
                return MS::kUnknownParameter;
    MFloatVector resultColor;
        
    MFloatVector& LColor  = block.inputValue( aColor ).asFloatVector();
    
    float LIntensity  = block.inputValue( aIntensity ).asFloat();
        
    MFloatVector& LDirection  = block.inputValue( aInputDirection ).asFloatVector();
    bool  LAmbient  = block.inputValue( aInputAmbient ).asBool();
    bool  LDiffuse  = block.inputValue( aInputDiffuse ).asBool();
    bool  LSpecular = block.inputValue( aInputSpecular ).asBool();
    resultColor = LColor * LIntensity;
  
    
    MDataHandle outLightDataHandle = block.outputValue( aLightData );
    MFloatVector& outIntensity = outLightDataHandle.child(aLightIntensity).asFloatVector();
    outIntensity = resultColor;
    MFloatVector& outDirection = outLightDataHandle.child(aLightDirection).asFloatVector();
    outDirection = LDirection;
    bool& outAmbient = outLightDataHandle.child(aLightAmbient).asBool();
    outAmbient = LAmbient;
    bool& outDiffuse = outLightDataHandle.child(aLightDiffuse).asBool();
    outDiffuse = LDiffuse;
    bool& outSpecular = outLightDataHandle.child(aLightSpecular).asBool();
    outSpecular = LSpecular;
    float& outSFraction = outLightDataHandle.child(aLightShadowFraction).asFloat();
    outSFraction = 1.0f;
    float& outPSIntensity = outLightDataHandle.child(aPreShadowIntensity).asFloat();
    outPSIntensity = (resultColor[0] + resultColor[1] + resultColor[2]) / 3.0f;
        void*& outBlindData = outLightDataHandle.child(aLightBlindData).asAddr();
        outBlindData = NULL;
    outLightDataHandle.setClean();
    return MS::kSuccess;
}
MStatus initializePlugin( MObject obj )
{ 
   const MString UserClassify( "light" );
   MFnPlugin plugin( obj, PLUGIN_COMPANY, "4.5", "Any");
   CHECK_MSTATUS ( plugin.registerNode( "directLight", LightNode::id, 
                         LightNode::creator, LightNode::initialize,
                         MPxNode::kDependNode, &UserClassify ) );
   return MS::kSuccess;
}
MStatus uninitializePlugin( MObject obj )
{
   MFnPlugin plugin( obj );
   CHECK_MSTATUS ( plugin.deregisterNode( LightNode::id ) );
   return MS::kSuccess;
}