//-
// ==========================================================================
// Copyright 2012 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.
// ==========================================================================
//+

// Plugin: uiDrawManager.cpp

// This plugin demonstrates the use of MUIDrawManager.
//
// It provides the 'uiDrawManager' node which uses MUIDrawManager to display 3D (world coordinates) 
// or 2D (screen coordinates) primitives such as text, lines, spheres, etc, based on values set 
// on its attributes.
//
// For example, to draw a 2D, 15x30 pixel rectangle in the viewport, centered on pixel position 
// (50, 20) and tilted at a 45 degree angle, you would do the following:
// createNode -n testo uiDrawManager;
// setAttr testo.draw2D true;
// setAttr testo.rectScale -type double 2 15 30;
// setAttr testo.position -type double 3 50 20 0;
// setAttr testo.rectUp -type double3 1 1 0;

#include <maya/MPxLocatorNode.h>
#include <maya/MFnPlugin.h>
#include <maya/MFnEnumAttribute.h>
#include <maya/MFnNumericAttribute.h>
#include <maya/MFnTypedAttribute.h>
#include <maya/MFnStringData.h>
#include <maya/MFnPointArrayData.h>
#include <maya/MPointArray.h>
#include <maya/MUintArray.h>

// Viewport 2.0 includes
#include <maya/MDrawRegistry.h>
#include <maya/MPxDrawOverride.h>
#include <maya/MUserData.h>
#include <algorithm>

using namespace MHWRender;

class uiDrawManager : public MPxLocatorNode
{
public:
	enum EuiType {
		kText,
		kLine,
		kPoint,
		kRect,
		kQuad,
		kSphere,
		kCircle,		
		kArc,		
	};

public:
	uiDrawManager();
	virtual ~uiDrawManager();

	static void*			creator();
	static MStatus			initialize();

	// ui type attribute
	static MObject			aUIType;

	// color
	static MObject			aPrimitiveColor;
	static MObject			aPrimitiveTransparency;

	// line width and line style attributes	
	static MObject			aLineWidth;
	static MObject			aLineStyle;

	// fill attribute
	static MObject			aIsFilled;

	// radius attribute
	static MObject			aRadius;

	// 2D attributes
	static MObject			aDraw2D;
	static MObject			aPosition;

	// Text attributes
	static MObject			aTextAlignment;
	static MObject			aTextBoxSize;
	static MObject			aText;	
	static MObject			aTextBoxColor;
	static MObject			aTextBoxTransparency;
	static MObject			aTextFontSize;
	static MObject			aFontFaceName;

	// point attributes
	static MObject			aPointSize;

	// line attributes
	static MObject			aLineStartPoint;
	static MObject			aLineEndPoint;

	// rect attributes
	static MObject			aRectUp;
	static MObject			aRectNormal;
	static MObject			aRectScale;

	// quad attributes
	static MObject			aQuadVertex[4];

	// circle attributes
	static MObject			aCircleNormal;

	// arc attributes
	static MObject			aArcStart;
	static MObject			aArcEnd;
	static MObject			aArcNormal;
public:
	static	MTypeId		id;
	static	MString		drawDbClassification;
	static	MString		drawRegistrantId;
};

MObject uiDrawManager::aUIType;

MObject uiDrawManager::aPrimitiveColor;
MObject uiDrawManager::aPrimitiveTransparency;

MObject uiDrawManager::aLineWidth;
MObject uiDrawManager::aLineStyle;

MObject uiDrawManager::aIsFilled;

MObject uiDrawManager::aRadius;

MObject uiDrawManager::aDraw2D;
MObject uiDrawManager::aPosition;

MObject uiDrawManager::aTextAlignment;
MObject uiDrawManager::aTextBoxSize;
MObject uiDrawManager::aText;
MObject uiDrawManager::aTextBoxColor;
MObject uiDrawManager::aTextBoxTransparency;
MObject uiDrawManager::aTextFontSize;
MObject uiDrawManager::aFontFaceName;

MObject uiDrawManager::aPointSize;

MObject uiDrawManager::aLineStartPoint;
MObject uiDrawManager::aLineEndPoint;

MObject	uiDrawManager::aRectUp;
MObject	uiDrawManager::aRectNormal;
MObject	uiDrawManager::aRectScale;

MObject uiDrawManager::aQuadVertex[4];

MObject	uiDrawManager::aCircleNormal;

MObject	uiDrawManager::aArcStart;
MObject	uiDrawManager::aArcEnd;
MObject	uiDrawManager::aArcNormal;

MTypeId uiDrawManager::id(0x0008002A);
MString	uiDrawManager::drawDbClassification("drawdb/geometry/uiDrawManager");
MString	uiDrawManager::drawRegistrantId("uiDrawManagerPlugin");

uiDrawManager::uiDrawManager() {}

uiDrawManager::~uiDrawManager() {}

void* uiDrawManager::creator()
{
	return new uiDrawManager();
}


//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// Viewport 2.0 override implementation
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
class uiDrawManagerData : public MUserData 
{
public:
	uiDrawManagerData();
	virtual ~uiDrawManagerData() {};

	uiDrawManager::EuiType fUIType;

	MColor fColor;	

	float fLineWidth;
	MUIDrawManager::LineStyle fLineStyle;

	bool fIsFilled;

	double fRadius;

	bool fDraw2D;

	MPoint fPosition;

	// text
	MString fText;
	unsigned int fTextFontSize;
	unsigned int fFontFaceIndex;
	static MStringArray fFontList;

	MUIDrawManager::TextAlignment fTextAlignment;	
	int fTextBoxWidth;
	int fTextBoxHeight;	
	MColor fTextBoxColor;

	// point
	float fPointSize;

	// line
	MPoint fLineStartPoint;
	MPoint fLineEndPoint;

	// rect
	MVector fRectUp;
	MVector fRectNormal;
	double fRectScaleX;
	double fRectScaleY;

	// quad
	MPoint fQuadVertex[4];

	// circle
	MVector fCircleNormal;

	// arc
	MVector fArcStart;
	MVector fArcEnd;
	MVector fArcNormal;
};

MStringArray uiDrawManagerData::fFontList;

uiDrawManagerData::uiDrawManagerData() : MUserData(false) 
	, fUIType(uiDrawManager::kText)
	, fColor(1.0f, 0.0f, 0.0f, 1.0f)	
	, fLineWidth(2.0f)
	, fLineStyle(MUIDrawManager::kSolid)	
	, fIsFilled(false)
	, fRadius(1.0)
	, fDraw2D(false)
	, fPosition(0.0, 0.0, 0.001)
	// text
	, fText("uiDrawManager-Text")
	, fTextFontSize(MUIDrawManager::kDefaultFontSize)
	, fFontFaceIndex(0)
	, fTextAlignment(MUIDrawManager::kLeft)
	, fTextBoxWidth(0)
	, fTextBoxHeight(0)
	, fTextBoxColor(0.0f, 1.0f, 1.0f, 1.0f)	
	// point
	, fPointSize(2.0f)
	// line
	, fLineStartPoint(0.0, 0.0, 0.0)
	, fLineEndPoint(1.0, 1.0, 1.0)
	// rect
	, fRectUp(0.0, 1.0, 0.0)
	, fRectNormal(0.0, 0.0, 1.0)
	, fRectScaleX(1.0)
	, fRectScaleY(1.0)	
	// circle
	, fCircleNormal(0.0, 0.0, 1.0)
	// arc
	, fArcStart(1.0, 0.0, 0.0)
	, fArcEnd(0.0, 1.0, 0.0)
	, fArcNormal(0.0, 0.0, 1.0)
{
	// quad
	fQuadVertex[0] = MPoint(0.0, 0.0, 0.0);
	fQuadVertex[1] = MPoint(1.0, 0.0, 0.0);
	fQuadVertex[2] = MPoint(1.0, 1.0, 0.0);
	fQuadVertex[3] = MPoint(0.0, 1.0, 0.0);

}

class uiDrawManagerDrawOverride : public MPxDrawOverride
{
public:
	static MPxDrawOverride* Creator(const MObject& obj)
	{
		return new uiDrawManagerDrawOverride(obj);
	}

	virtual ~uiDrawManagerDrawOverride();

	virtual DrawAPI supportedDrawAPIs() const;

	virtual bool isBounded(
		const MDagPath& objPath,
		const MDagPath& cameraPath) const;

	virtual MBoundingBox boundingBox(
		const MDagPath& objPath,
		const MDagPath& cameraPath) const;

	virtual MUserData* prepareForDraw(
		const MDagPath& objPath,
		const MDagPath& cameraPath,
		const MFrameContext& frameContext,
		MUserData* oldData);

	virtual bool hasUIDrawables() const { return true; }

	virtual void addUIDrawables(
		const MDagPath& objPath,
		MHWRender::MUIDrawManager& drawManager,
		const MHWRender::MFrameContext& frameContext,
		const MUserData* data);

	static void draw(const MHWRender::MDrawContext& context, const MUserData* data);

protected:

private:
	uiDrawManagerDrawOverride(const MObject& obj);
};

uiDrawManagerDrawOverride::uiDrawManagerDrawOverride(const MObject& obj)
	: MPxDrawOverride(obj, uiDrawManagerDrawOverride::draw)
{
}

uiDrawManagerDrawOverride::~uiDrawManagerDrawOverride()
{
}

DrawAPI uiDrawManagerDrawOverride::supportedDrawAPIs() const
{
	// this plugin supports both GL and DX
	return (kOpenGL | kDirectX11);
}

bool uiDrawManagerDrawOverride::isBounded(const MDagPath& /*objPath*/,
	const MDagPath& /*cameraPath*/) const
{
	return false;
}

MBoundingBox uiDrawManagerDrawOverride::boundingBox(
	const MDagPath& objPath,
	const MDagPath& cameraPath) const
{
	return MBoundingBox();
}

MUserData* uiDrawManagerDrawOverride::prepareForDraw(
	const MDagPath& objPath,
	const MDagPath& cameraPath,
	const MHWRender::MFrameContext& frameContext,
	MUserData* oldData)
{
	uiDrawManagerData* data = dynamic_cast<uiDrawManagerData*>(oldData);
	if (!data) {
		data = new uiDrawManagerData();
	}

	MStatus status;
	MObject uiDrawManagerNode = objPath.node(&status);
	if (status) {
		// retrieve uiType
		{
			MPlug plug(uiDrawManagerNode, uiDrawManager::aUIType);
			data->fUIType = (uiDrawManager::EuiType)plug.asShort();
		}

		// common attributes
		// retrieve color
		{
			MPlug plug(uiDrawManagerNode, uiDrawManager::aPrimitiveColor);
			MObject o = plug.asMObject();
			MFnNumericData nData(o);
			nData.getData(data->fColor.r, data->fColor.g, data->fColor.b);			
		}

		// retrieve transparency
		{
			MPlug plug(uiDrawManagerNode, uiDrawManager::aPrimitiveTransparency);
			data->fColor.a = 1.0f - plug.asFloat();
		}
		
		// retrieve line width
		{
			MPlug plug(uiDrawManagerNode, uiDrawManager::aLineWidth);
			data->fLineWidth = plug.asFloat();
		}

		// retrieve line style
		{
			MPlug plug(uiDrawManagerNode, uiDrawManager::aLineStyle);
			data->fLineStyle = (MUIDrawManager::LineStyle)plug.asShort();
		}
		
		// retrieve filled flag		
		{
			MPlug plug(uiDrawManagerNode, uiDrawManager::aIsFilled);
			data->fIsFilled = plug.asBool();
		}

		// retrieve radius
		{
			MPlug plug(uiDrawManagerNode, uiDrawManager::aRadius);
			data->fRadius = plug.asDouble();
		}

		// retrieve 2D flag
		{
			MPlug plug(uiDrawManagerNode, uiDrawManager::aDraw2D);
			data->fDraw2D = plug.asBool();
		}

		// retrieve screen position
		{
			MPlug plug(uiDrawManagerNode, uiDrawManager::aPosition);
			MObject o = plug.asMObject();
			MFnNumericData nData(o);				
			nData.getData(data->fPosition.x, data->fPosition.y, data->fPosition.z);
			data->fPosition.w = 1.0f;
		}

		switch (data->fUIType) 
		{
		case uiDrawManager::kText:
			// retrieve text
			{		
				MPlug plug(uiDrawManagerNode, uiDrawManager::aText);
				data->fText = plug.asString();
			}	

			// retrieve text font size
			{
				MPlug plug(uiDrawManagerNode, uiDrawManager::aTextFontSize);
				data->fTextFontSize = std::max(plug.asInt(), 0);			
			}

			// retrieve font face index
			{
				MPlug plug(uiDrawManagerNode, uiDrawManager::aFontFaceName);
				data->fFontFaceIndex = (unsigned int)plug.asInt();
			}

			// retrieve text alignment
			{
				MPlug plug(uiDrawManagerNode, uiDrawManager::aTextAlignment);
				data->fTextAlignment = (MUIDrawManager::TextAlignment)plug.asShort();
			}		

			// retrieve text box size
			{
				MPlug plug(uiDrawManagerNode, uiDrawManager::aTextBoxSize);
				MObject o = plug.asMObject();
				MFnNumericData nData(o);			
				nData.getData(data->fTextBoxWidth, data->fTextBoxHeight);			
			}		

			// retrieve text box color
			{
				MPlug plug(uiDrawManagerNode, uiDrawManager::aTextBoxColor);
				MObject o = plug.asMObject();
				MFnNumericData nData(o);
				nData.getData(data->fTextBoxColor.r, data->fTextBoxColor.g, data->fTextBoxColor.b);				
			}

			// retrieve text box transparency
			{
				MPlug plug(uiDrawManagerNode, uiDrawManager::aTextBoxTransparency);
				data->fTextBoxColor.a = 1.0f - plug.asFloat();
			}
			break;			

		case uiDrawManager::kPoint:
			// retrieve point size
			{
				MPlug plug(uiDrawManagerNode, uiDrawManager::aPointSize);
				data->fPointSize = plug.asFloat();
			}

			break;

		case uiDrawManager::kLine:
			// retrieve line start point
			{
				MPlug plug(uiDrawManagerNode, uiDrawManager::aLineStartPoint);
				MObject o = plug.asMObject();
				MFnNumericData nData(o);				
				nData.getData(data->fLineStartPoint.x, data->fLineStartPoint.y, data->fLineStartPoint.z);
				data->fLineStartPoint.w = 1.0f;
			}

			// retrieve line end point
			{
				MPlug plug(uiDrawManagerNode, uiDrawManager::aLineEndPoint);
				MObject o = plug.asMObject();
				MFnNumericData nData(o);				
				nData.getData(data->fLineEndPoint.x, data->fLineEndPoint.y, data->fLineEndPoint.z);
				data->fLineEndPoint.w = 1.0f;
			}

			break;

		case uiDrawManager::kRect:
			// retrieve rect up vector
			{
				MPlug plug(uiDrawManagerNode, uiDrawManager::aRectUp);
				MObject o = plug.asMObject();
				MFnNumericData nData(o);				
				nData.getData(data->fRectUp.x, data->fRectUp.y, data->fRectUp.z);				
			}

			// retrieve rect normal vector
			{
				MPlug plug(uiDrawManagerNode, uiDrawManager::aRectNormal);
				MObject o = plug.asMObject();
				MFnNumericData nData(o);				
				nData.getData(data->fRectNormal.x, data->fRectNormal.y, data->fRectNormal.z);		
			}

			// retrieve rect scale
			{
				MPlug plug(uiDrawManagerNode, uiDrawManager::aRectScale);
				MObject o = plug.asMObject();
				MFnNumericData nData(o);				
				nData.getData(data->fRectScaleX, data->fRectScaleY);
			}

			break;

		case uiDrawManager::kQuad:
			// retrieve quad vertices
			{
				for (int i = 0; i < 4; ++i)
				{
					MPlug plug(uiDrawManagerNode, uiDrawManager::aQuadVertex[i]);
					MObject o = plug.asMObject();
					MFnNumericData nData(o);
					nData.getData(data->fQuadVertex[i].x, data->fQuadVertex[i].y, data->fQuadVertex[i].z);
				}
			}

			break;

		case uiDrawManager::kCircle:
			// retrieve circle normal
			{
				MPlug plug(uiDrawManagerNode, uiDrawManager::aCircleNormal);
				MObject o = plug.asMObject();
				MFnNumericData nData(o);				
				nData.getData(data->fCircleNormal.x, data->fCircleNormal.y, data->fCircleNormal.z);	
			}

			break;

		case uiDrawManager::kArc:
			// retrieve arc start vector
			{
				MPlug plug(uiDrawManagerNode, uiDrawManager::aArcStart);
				MObject o = plug.asMObject();
				MFnNumericData nData(o);				
				nData.getData(data->fArcStart.x, data->fArcStart.y, data->fArcStart.z);
			}

			// retrieve arc end vector
			{
				MPlug plug(uiDrawManagerNode, uiDrawManager::aArcEnd);
				MObject o = plug.asMObject();
				MFnNumericData nData(o);				
				nData.getData(data->fArcEnd.x, data->fArcEnd.y, data->fArcEnd.z);	
			}

			// retrieve arc normal
			{
				MPlug plug(uiDrawManagerNode, uiDrawManager::aArcNormal);
				MObject o = plug.asMObject();
				MFnNumericData nData(o);				
				nData.getData(data->fArcNormal.x, data->fArcNormal.y, data->fArcNormal.z);	
			}

			break;

		case uiDrawManager::kSphere:
			break;

		default:
			perror("unhandled ui type.");
			break;
		}			
	}

	return data;
}

void uiDrawManagerDrawOverride::addUIDrawables(
	const MDagPath& objPath,
	MHWRender::MUIDrawManager& drawManager,
	const MHWRender::MFrameContext& frameContext,
	const MUserData* data)
{
	const uiDrawManagerData* thisdata = dynamic_cast<const uiDrawManagerData*>(data);
	if (!thisdata) {
		return;
	}

	switch (thisdata->fUIType) 
	{
	case uiDrawManager::kText: 
		{
			// Draw a text "uiDrawManager"
			// All drawing operations must take place between calls to beginDrawable()
			// and endDrawable().
			drawManager.beginDrawable();

			drawManager.setColor(thisdata->fColor);
			drawManager.setFontSize(thisdata->fTextFontSize);

			MString faceName = uiDrawManagerData::fFontList[thisdata->fFontFaceIndex];
			drawManager.setFontName(faceName);
			int boxSize[] = { thisdata->fTextBoxWidth, thisdata->fTextBoxHeight };
			if (thisdata->fDraw2D) {
				// uiDrawManagerData::fPosition gives a screen space position 
				// where 2D UI item is located.				
				drawManager.text2d(thisdata->fPosition, thisdata->fText, thisdata->fTextAlignment, 
					boxSize[0]+boxSize[1] == 0 ? NULL : boxSize, &thisdata->fTextBoxColor, false);
			}
			else {
				// for 3D items, place it at the origin of the world space.
				drawManager.text(thisdata->fPosition, thisdata->fText, thisdata->fTextAlignment, 
					boxSize[0]+boxSize[1] == 0 ? NULL : boxSize, &thisdata->fTextBoxColor, false);
			}			

			drawManager.endDrawable();
		}
		break;

	case uiDrawManager::kLine:
		{
			drawManager.beginDrawable();

			drawManager.setColor(thisdata->fColor);
			drawManager.setLineWidth(thisdata->fLineWidth);
			drawManager.setLineStyle(thisdata->fLineStyle);
			if (thisdata->fDraw2D) {
				drawManager.line2d(thisdata->fLineStartPoint, thisdata->fLineEndPoint);
			}
			else {
				drawManager.line(thisdata->fLineStartPoint, thisdata->fLineEndPoint);
			}

			drawManager.endDrawable();
		}
		break;

	case uiDrawManager::kPoint:
		{
			drawManager.beginDrawable();

			drawManager.setColor(thisdata->fColor);
			drawManager.setPointSize(thisdata->fPointSize);
			if (thisdata->fDraw2D) {
				drawManager.point2d(thisdata->fPosition);
			}
			else {
				drawManager.point(thisdata->fPosition);
			}		

			drawManager.endDrawable();
		}
		break;

	case uiDrawManager::kRect:
		{
			drawManager.beginDrawable();

			drawManager.setColor(thisdata->fColor);
			drawManager.setLineWidth(thisdata->fLineWidth);
			drawManager.setLineStyle(thisdata->fLineStyle);
			if (thisdata->fDraw2D) {
				// For 2d rectangle, an up vector in screen space is used to determine its X 
				// and Y directions. In addition, "fRectScaleX" and "fRectScaleY"(in pixels)
				// specify the half-lengths of the 2d rectangle.
				drawManager.rect2d(thisdata->fPosition, thisdata->fRectUp,
					thisdata->fRectScaleX, thisdata->fRectScaleY, thisdata->fIsFilled);
			}
			else {
				// For 3d rectangle, the up vector should not be parallel with the normal vector.
				drawManager.rect(thisdata->fPosition, thisdata->fRectUp, thisdata->fRectNormal,
					thisdata->fRectScaleX, thisdata->fRectScaleY, thisdata->fIsFilled);
			}

			drawManager.endDrawable();
		}
		break;

	case uiDrawManager::kQuad:
		{
			drawManager.beginDrawable();

			drawManager.setColor(thisdata->fColor);
			drawManager.setLineWidth(thisdata->fLineWidth);
			drawManager.setLineStyle(thisdata->fLineStyle);

			// prepare primitive type
			MUIDrawManager::Primitive mode = 
				thisdata->fIsFilled ? MUIDrawManager::kTriStrip : MUIDrawManager::kClosedLine;
			// prepare position list
			MPointArray position;
			for (int i = 0; i < 4; ++i) {
				position.append(thisdata->fQuadVertex[i]);
			}
			// prepare index
			MUintArray index;
			index.append(0);
			index.append(1);
			index.append(3);
			index.append(2);			

			// draw mesh
			if (thisdata->fDraw2D) {
				drawManager.mesh2d(mode, position, NULL, thisdata->fIsFilled ? &index : NULL);
			}
			else {
				drawManager.mesh(mode, position, NULL, NULL, thisdata->fIsFilled ? &index : NULL);
			}

			drawManager.endDrawable();
		}
		break;

	case uiDrawManager::kSphere:
		{
			drawManager.beginDrawable();

			drawManager.setColor(thisdata->fColor);
			drawManager.setLineWidth(thisdata->fLineWidth);
			drawManager.setLineStyle(thisdata->fLineStyle);
			drawManager.sphere(thisdata->fPosition, thisdata->fRadius, thisdata->fIsFilled);

			drawManager.endDrawable();
		}
		break;

	case uiDrawManager::kCircle:
		{
			drawManager.beginDrawable();

			drawManager.setColor(thisdata->fColor);
			drawManager.setLineWidth(thisdata->fLineWidth);
			drawManager.setLineStyle(thisdata->fLineStyle);
			if (thisdata->fDraw2D) {
				// The radius in specified as pixel unit for 2d items.
				drawManager.circle2d(thisdata->fPosition, thisdata->fRadius, 
					thisdata->fIsFilled);
			}
			else {
				drawManager.circle(thisdata->fPosition, thisdata->fCircleNormal, thisdata->fRadius, 
					thisdata->fIsFilled);
			}

			drawManager.endDrawable();
		}
		break;

	case uiDrawManager::kArc:
		{
			drawManager.beginDrawable();

			drawManager.setColor(thisdata->fColor);
			drawManager.setLineWidth(thisdata->fLineWidth);
			drawManager.setLineStyle(thisdata->fLineStyle);
			if (thisdata->fDraw2D) {
				// If 2d, the range of the arc is defined by the start and end vectors 
				// specified in screen space.
				drawManager.arc2d(thisdata->fPosition, thisdata->fArcStart, thisdata->fArcEnd, 
					thisdata->fRadius, thisdata->fIsFilled);
			}
			else {
				// For 3d arc, the projections of the start and end vectors onto the arc plane(
				// determined by the normal vector) determine the range of the arc.
				drawManager.arc(thisdata->fPosition, thisdata->fArcStart, thisdata->fArcEnd, 
					thisdata->fArcNormal, thisdata->fRadius, thisdata->fIsFilled);
			}

			drawManager.endDrawable();
		}
		break;

	default:
		perror("unhandled ui types.");
		break;
	}
	
}

void uiDrawManagerDrawOverride::draw(const MHWRender::MDrawContext& context, const MUserData* data)
{

}

//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// Plugin Registration
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------

MStatus uiDrawManager::initialize()
{
	MStatus status;

	MFnNumericAttribute nAttr;
	MFnEnumAttribute eAttr;
	MFnTypedAttribute typedAttr;

	// Add ui type attribute
	aUIType = eAttr.create("uiType", "ut", uiDrawManager::kText);
	eAttr.addField("text", uiDrawManager::kText);
	eAttr.addField("line", uiDrawManager::kLine);
	eAttr.addField("point", uiDrawManager::kPoint);
	eAttr.addField("rect", uiDrawManager::kRect);	
	eAttr.addField("quad", uiDrawManager::kQuad);
	eAttr.addField("sphere", uiDrawManager::kSphere);
	eAttr.addField("circle", uiDrawManager::kCircle);	
	eAttr.addField("arc", uiDrawManager::kArc);	
	MPxNode::addAttribute(aUIType);
	
	// Add color attribute
	aPrimitiveColor = nAttr.create("primitiveColor", "pc", MFnNumericData::k3Float);
	nAttr.setDefault(1.0f, 0.0f, 0.0f);
	nAttr.setUsedAsColor(true);
	MPxNode::addAttribute(aPrimitiveColor);

	// Add transparency attribute
	aPrimitiveTransparency = nAttr.create("primitiveTransparency", "pt", MFnNumericData::kFloat, 0.0);
	nAttr.setSoftMin(0.0);
	nAttr.setSoftMax(1.0);	
	MPxNode::addAttribute(aPrimitiveTransparency);

	// add line width and line style attributes
	aLineWidth = nAttr.create("lineWidth", "lw", MFnNumericData::kFloat, 2.0);
	MPxNode::addAttribute(aLineWidth);

	aLineStyle = eAttr.create("lineStyle", "ls", MUIDrawManager::kSolid);
	eAttr.addField("solid", MUIDrawManager::kSolid);
	eAttr.addField("shortdotted", MUIDrawManager::kShortDotted);
	eAttr.addField("shortdashed", MUIDrawManager::kShortDashed);
	eAttr.addField("dashed", MUIDrawManager::kDashed);
	eAttr.addField("dotted", MUIDrawManager::kDotted);
	MPxNode::addAttribute(aLineStyle);

	// Add filled attribute
	aIsFilled = nAttr.create("isFilled", "if", MFnNumericData::kBoolean, 0);	
	MPxNode::addAttribute(aIsFilled);

	// Add radius attribute
	aRadius = nAttr.create("radius", "ra", MFnNumericData::kDouble, 1.0);
	MPxNode::addAttribute(aRadius);

	// add 2D attributes
	aDraw2D = nAttr.create("draw2D", "d2", MFnNumericData::kBoolean, 0);
	MPxNode::addAttribute(aDraw2D);

	aPosition = nAttr.create("position", "pos", MFnNumericData::k3Double);
	nAttr.setDefault(0.0, 0.0, 0.001);
	MPxNode::addAttribute(aPosition);
	
	// Add text attributes.
	MFnStringData stringFn;
	MObject defaultText = stringFn.create("uiDrawManager-Text");
	aText = typedAttr.create("text", "t", MFnData::kString, defaultText);
	MPxNode::addAttribute(aText);	

	aTextFontSize = nAttr.create("textFontSize", "tfs", MFnNumericData::kInt, MUIDrawManager::kDefaultFontSize);
	nAttr.setMin(-1);
	nAttr.setMax(99);	
	MPxNode::addAttribute(aTextFontSize);

	unsigned int nFont = MUIDrawManager::getFontList(uiDrawManagerData::fFontList);
	if (nFont == 0)
	{
		perror("No font available!");
	}
	aFontFaceName = eAttr.create("fontFaceName", "ffn", 0);
	for (unsigned int i = 0; i < nFont; i++)
	{
		MString str = uiDrawManagerData::fFontList[i];
		eAttr.addField(str, (short)i);
	}
	MPxNode::addAttribute(aFontFaceName);

	aTextAlignment = eAttr.create("textAlignment", "ta", MUIDrawManager::kLeft);
	eAttr.addField("left", MUIDrawManager::kLeft);
	eAttr.addField("center", MUIDrawManager::kCenter);
	eAttr.addField("right", MUIDrawManager::kRight);
	MPxNode::addAttribute(aTextAlignment);	

	aTextBoxSize = nAttr.create("textBoxSize", "tbs", MFnNumericData::k2Int);
	nAttr.setDefault(0, 0);
	MPxNode::addAttribute(aTextBoxSize);

	aTextBoxColor = nAttr.create("textBoxColor", "tbc", MFnNumericData::k3Float);
	nAttr.setDefault(0.0f, 1.0f, 1.0f);
	nAttr.setUsedAsColor(true);
	MPxNode::addAttribute(aTextBoxColor);

	aTextBoxTransparency = nAttr.create("textBoxTransparency", "tbt", MFnNumericData::kFloat, 0.0);
	nAttr.setSoftMin(0.0);
	nAttr.setSoftMax(1.0);	
	MPxNode::addAttribute(aTextBoxTransparency);
	
	// add point attributes
	aPointSize = nAttr.create("pointSize", "ps", MFnNumericData::kFloat, 2.0);
	MPxNode::addAttribute(aPointSize);

	// add line attributes
	aLineStartPoint = nAttr.create("lineStartPoint", "lsp", MFnNumericData::k3Double);
	nAttr.setDefault(0.0, 0.0, 0.0);
	MPxNode::addAttribute(aLineStartPoint);

	aLineEndPoint = nAttr.create("lineEndPoint", "lep", MFnNumericData::k3Double);
	nAttr.setDefault(1.0, 1.0, 1.0);
	MPxNode::addAttribute(aLineEndPoint);
	
	// add rect attributes
	aRectUp = nAttr.create("rectUp", "ru", MFnNumericData::k3Double);
	nAttr.setDefault(0.0, 1.0, 0.0);
	MPxNode::addAttribute(aRectUp);

	aRectNormal = nAttr.create("rectNormal", "rn", MFnNumericData::k3Double);
	nAttr.setDefault(0.0, 0.0, 1.0);
	MPxNode::addAttribute(aRectNormal);

	aRectScale = nAttr.create("rectScale", "rs", MFnNumericData::k2Double);
	nAttr.setDefault(1.0, 1.0);
	MPxNode::addAttribute(aRectScale);

	// add quad attributes
	double defaultPosition[4][3] = 
	{
		{0.0, 0.0, 0.0},
		{1.0, 0.0, 0.0},
		{1.0, 1.0, 0.0},
		{0.0, 1.0, 0.0}
	};
	for (int i = 0; i < 4;  ++i)
	{
		MString fullName = "quadVertex";
		MString shortName = "qv";
		aQuadVertex[i] = nAttr.create(fullName + i, shortName + i, MFnNumericData::k3Double);
		nAttr.setDefault(defaultPosition[i][0], defaultPosition[i][1], defaultPosition[i][2]);
		MPxNode::addAttribute(aQuadVertex[i]);
	}
	
	// add circle attributes
	aCircleNormal = nAttr.create("circleNormal", "cn", MFnNumericData::k3Double);
	nAttr.setDefault(0.0, 0.0, 1.0);
	MPxNode::addAttribute(aCircleNormal);

	// add arc attributes
	aArcStart = nAttr.create("arcStartVector", "asv", MFnNumericData::k3Double);
	nAttr.setDefault(1.0, 0.0, 0.0);
	MPxNode::addAttribute(aArcStart);

	aArcEnd = nAttr.create("arcEndVector", "aev", MFnNumericData::k3Double);
	nAttr.setDefault(0.0, 1.0, 0.0);
	MPxNode::addAttribute(aArcEnd);

	aArcNormal = nAttr.create("arcNormal", "an", MFnNumericData::k3Double);
	nAttr.setDefault(0.0, 0.0, 1.0);
	MPxNode::addAttribute(aArcNormal);

	return MS::kSuccess;
}

MStatus initializePlugin( MObject obj )
{
	MStatus   status;
	MFnPlugin plugin( obj, PLUGIN_COMPANY, "3.0", "Any");

	status = plugin.registerNode(
		"uiDrawManager",
		uiDrawManager::id,
		&uiDrawManager::creator,
		&uiDrawManager::initialize,
		MPxNode::kLocatorNode,
		&uiDrawManager::drawDbClassification);
	if (!status) {
		status.perror("registerNode");
		return status;
	}

	status = MHWRender::MDrawRegistry::registerDrawOverrideCreator(
		uiDrawManager::drawDbClassification,
		uiDrawManager::drawRegistrantId,
		uiDrawManagerDrawOverride::Creator);
	if (!status) {
		status.perror("registerDrawOverrideCreator");
		return status;
	}

	return status;
}

MStatus uninitializePlugin( MObject obj)
{
	MStatus   status;
	MFnPlugin plugin( obj );

	status = MDrawRegistry::deregisterGeometryOverrideCreator(
		uiDrawManager::drawDbClassification,
		uiDrawManager::drawRegistrantId);
	if (!status) {
		status.perror("deregisterGeometryOverrideCreator");
		return status;
	}

	status = plugin.deregisterNode( uiDrawManager::id );
	if (!status) {
		status.perror("deregisterNode");
		return status;
	}

	return status;
}
