//-
// ==========================================================================
// 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.
// ==========================================================================
//+

//
// Description: 
//  A simple locator node that demonstrates the transparency flag on
//  locator nodes. Transparent objects must be drawn in a special draw
//  pass by Maya because the rendered output is dependent on the draw
//  order of objects.  The isTransparent() method tells the API that
//  this locator should be placed in this special transparency queue 
//  for rendering.  
//
//  API programmers can see the effects of this draw operation by
//  toggling the 'transparencySort' attribute on this node.  When the
//  attribute is set to true the locator will be drawn in sorted order
//  with all transparent objects in the scene.  When it is set to
//  false it will be drawn with all opaque objects in the scene.
//  
//  This also demonstrates the related drawLast() flag.  This flag allows
//  a locator to be specified as the last object to be drawn in a given
//  refresh pass.  This flag a very specialized purpose, but it can be
//  important when using the isTransparent flag in crucial situations.
//

#include <maya/MPxLocatorNode.h> 
#include <maya/MString.h> 
#include <maya/MTypeId.h> 
#include <maya/MPlug.h>
#include <maya/MDataBlock.h>
#include <maya/MDataHandle.h>
#include <maya/MColor.h>
#include <maya/M3dView.h>
#include <maya/MFnPlugin.h>
#include <maya/MFnNumericAttribute.h>

#include <arrowData.h> 

class curvedArrows : public MPxLocatorNode
{
public:
	curvedArrows();
	virtual ~curvedArrows(); 

	virtual void			postConstructor(); 
	
    virtual MStatus   		compute( const MPlug& plug, MDataBlock& data );

	virtual void            draw( M3dView & view, const MDagPath & path, 
								  M3dView::DisplayStyle style,
								  M3dView::DisplayStatus status );

	virtual void			drawEdgeLoop( M3dView &, M3dView::DisplayStatus ); 
	
	virtual bool            isBounded() const;
	virtual MBoundingBox    boundingBox() const; 
	virtual bool			isTransparent() const; 
	virtual bool			drawLast() const; 

	static  void *          creator();
	static  MStatus         initialize();

	static  MObject			aEnableTransparencySort; 
	static  MObject			aEnableDrawLast; 
	static  MObject			aTheColor; 
	static  MObject			aTransparency; 
	
public: 
	static	MTypeId		id;
};

MTypeId curvedArrows::id( 0x08102B );
MObject curvedArrows::aEnableTransparencySort; 
MObject curvedArrows::aEnableDrawLast;
MObject curvedArrows::aTheColor; 
MObject curvedArrows::aTransparency; 

curvedArrows::curvedArrows() {}
curvedArrows::~curvedArrows() {}

void
curvedArrows::postConstructor() 
{
}

MStatus curvedArrows::compute( const MPlug& /*plug*/, MDataBlock& /*data*/ )
{ 
	return MS::kUnknownParameter;
}

void curvedArrows::drawEdgeLoop( M3dView &view, M3dView::DisplayStatus status )
{
	glPushAttrib( GL_CURRENT_BIT ); 
	if ( status == M3dView::kActive ) {
		view.setDrawColor( 13, M3dView::kActiveColors );
	} else {
		view.setDrawColor( 13, M3dView::kDormantColors );
	}  
	glBegin( GL_LINE_LOOP ); 
	
	unsigned int i; 
	for ( i = 0; i < fsEdgeLoopSize; i ++ ) { 
		glVertex3d( fsVertexList[fsEdgeLoop[i]][0], 
					fsVertexList[fsEdgeLoop[i]][1],
					fsVertexList[fsEdgeLoop[i]][2]);
	}
	glEnd(); 
	glPopAttrib();
}

void curvedArrows::draw( M3dView & view, const MDagPath & /*path*/, 
							 M3dView::DisplayStyle style,
							 M3dView::DisplayStatus status )
{ 
	// Get the size
	//
	MObject thisNode = thisMObject();
	MPlug tPlug = MPlug( thisNode, aTransparency ); 
	MPlug cPlug = MPlug( thisNode, aTheColor ); 

	float r, g, b, a; 
	MObject color; 

	cPlug.getValue( color ); 
	MFnNumericData data( color ); 
	data.getData( r, g, b ); 
	tPlug.getValue( a ); 

	view.beginGL(); 

	if( (style == M3dView::kFlatShaded) ||
	    (style == M3dView::kGouraudShaded) ) {
		// Push the color settings
		// 
		glPushAttrib( GL_COLOR_BUFFER_BIT | GL_CURRENT_BIT | GL_ENABLE_BIT | 
					  GL_PIXEL_MODE_BIT ); 
	
		if ( a < 1.0f ) { 
			glEnable( GL_BLEND );
			glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
		}
		
		glColor4f( r, g, b, a );			
	
		glBegin( GL_TRIANGLES ); 
		unsigned int i;
		for ( i = 0; i < fsFaceListSize; i ++ ) { 
			unsigned int *vid = fsFaceList[i];
			unsigned int *nid = fsFaceVertexNormalList[i]; 
			for ( unsigned int j = 0; j < 3; j ++ ) { 
				glNormal3d( fsNormalList[nid[j]-1][0], 
							fsNormalList[nid[j]-1][1], 
							fsNormalList[nid[j]-1][2] );
				glVertex3d( fsVertexList[vid[j]-1][0], 
							fsVertexList[vid[j]-1][1],
							fsVertexList[vid[j]-1][2] ); 
			}
		}
		glEnd(); 
	
		glPopAttrib(); 

		drawEdgeLoop( view, status ); 
	} else { 
		drawEdgeLoop( view, status ); 
	}

	view.endGL(); 
}

bool curvedArrows::isTransparent( ) const
{
	MObject thisNode = thisMObject(); 
	MPlug plug( thisNode, aEnableTransparencySort ); 
	bool value; 
	plug.getValue( value ); 
	return value; 
}

bool curvedArrows::drawLast() const
{
    MObject thisNode = thisMObject();
    MPlug plug( thisNode, aEnableDrawLast );
    bool value;
    plug.getValue( value );
    return value;
}

bool curvedArrows::isBounded() const
{ 
	return true;
}

MBoundingBox curvedArrows::boundingBox() const
{   
	MBoundingBox bbox; 
	
	unsigned int i;
	for ( i = 0; i < fsVertexListSize; i ++ ) { 
		double *pt = fsVertexList[i]; 
		bbox.expand( MPoint( pt[0], pt[1], pt[2] ) ); 
	}
	return bbox; 
}

void* curvedArrows::creator()
{
	return new curvedArrows();
}

MStatus curvedArrows::initialize()
{ 
	MFnNumericAttribute nAttr; 

	aTheColor = nAttr.createColor( "theColor", "tc" ); 
	nAttr.setDefault( 0.1, 0.1, 0.8 ); 
	nAttr.setKeyable( true ); 
	nAttr.setReadable( true ); 
	nAttr.setWritable( true ); 
	nAttr.setStorable( true ); 
	
	aTransparency = nAttr.create( "transparency", "t", MFnNumericData::kFloat );
	nAttr.setDefault( 0.5 ); 
	nAttr.setKeyable( true ); 
	nAttr.setReadable( true ); 
	nAttr.setWritable( true ); 
	nAttr.setStorable( true ); 

	aEnableTransparencySort = 
		nAttr.create( "transparencySort", "ts", MFnNumericData::kBoolean ); 
	nAttr.setDefault( true ); 
	nAttr.setKeyable( true ); 
	nAttr.setReadable( true ); 
	nAttr.setWritable( true ); 
	nAttr.setStorable( true ); 

    aEnableDrawLast =
        nAttr.create( "drawLast", "dL", MFnNumericData::kBoolean );
    nAttr.setDefault( false );
    nAttr.setKeyable( true );
    nAttr.setReadable( true );
    nAttr.setWritable( true );
    nAttr.setStorable( true );
                                                                                                                                                    
    MStatus stat1, stat2, stat3, stat4;
    stat1 = addAttribute( aTheColor );
    stat2 = addAttribute( aEnableTransparencySort );
    stat3 = addAttribute( aEnableDrawLast );
    stat4 = addAttribute( aTransparency );

    if ( !stat1 || !stat2 || !stat3  || !stat4) {
        stat1.perror("addAttribute");
        stat2.perror("addAttribute");
        stat3.perror("addAttribute");
        stat4.perror("addAttribute");
        return MS::kFailure;
    }

	return MS::kSuccess;
}

MStatus initializePlugin( MObject obj )
{ 
	MStatus   status;
	MFnPlugin plugin( obj, PLUGIN_COMPANY, "6.0", "Any");

	status = plugin.registerNode( "curvedArrows", curvedArrows::id, 
						 &curvedArrows::creator, &curvedArrows::initialize,
						 MPxNode::kLocatorNode );
	if (!status) {
		status.perror("registerNode");
		return status;
	}
	return status;
}

MStatus uninitializePlugin( MObject obj)
{
	MStatus   status;
	MFnPlugin plugin( obj );

	status = plugin.deregisterNode( curvedArrows::id );
	if (!status) {
		status.perror("deregisterNode");
		return status;
	}

	return status;
}
