// Copyright (C) 1997-2000 Alias|Wavefront, a division of Silicon Graphics Limited.
// 
// The information in this file is provided for the exclusive use of the
// licensees of Alias|Wavefront.  Such users have the right to use, modify,
// and incorporate this code into other products for purposes authorized
// by the Alias|Wavefront license agreement, without fee.
// 
// ALIAS|WAVEFRONT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
// INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
// EVENT SHALL ALIAS|WAVEFRONT BE LIABLE FOR ANY SPECIAL, INDIRECT OR
// CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
// DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.

// $RCSfile: wtBSNode.cpp $     $Revision: /main/6 $

//
//  File: wtBS.cc
//
//  Description:
// 		Example implementation of a deformer. This node
//		wtBSs vertices according to the CV's weights.
//		The weights are set using the set editor or the
//		percent command.
//

#include <string.h>
#include <iostream.h>
#include <math.h>

#include <maya/MPxDeformerNode.h> 
#include <maya/MItGeometry.h>
#include <maya/MPxLocatorNode.h> 
#include <maya/MItMeshVertex.h>

#include <maya/MFnNumericAttribute.h>
#include <maya/MFnMatrixAttribute.h>
#include <maya/MFnTypedAttribute.h>
#include <maya/MFnMatrixData.h>

#include <maya/MFnPlugin.h>
#include <maya/MFnDependencyNode.h>

#include <maya/MTypeId.h> 
#include <maya/MPlug.h>

#include <maya/MDataBlock.h>
#include <maya/MDataHandle.h>
#include <maya/MArrayDataHandle.h>

#include <maya/MPoint.h>
#include <maya/MVector.h>
#include <maya/MMatrix.h>

#include <maya/MDagModifier.h>


class wtBS : public MPxDeformerNode
{
public:
						wtBS();
	virtual				~wtBS();

	static  void*		creator();
	static  MStatus		initialize();

	// deformation function
	//
    virtual MStatus      		deform(MDataBlock& 		block,
									   MItGeometry& 	iter,
									   const MMatrix& 	mat,
									   unsigned int		multiIndex);

	// when the accessory is deleted, this node will clean itself up
	//
	virtual MObject&			accessoryAttribute() const;

	// create accessory nodes when the node is created
	//
	virtual MStatus				accessoryNodeSetup(MDagModifier& cmd);

public:
	// local node attributes

	static  MObject     wtBSMatrix; 	// wtBS center and axis
	static  MObject     defObject;      // def object
	
	static  MTypeId		id;

private:

	//MFnMesh def;

};

MTypeId     wtBS::id( 0x8000c );

// local attributes
//
MObject		wtBS::wtBSMatrix;
MObject     wtBS::defObject;      // def object


wtBS::wtBS() {}
wtBS::~wtBS() {}

void* wtBS::creator()
{
	return new wtBS();
}

MStatus wtBS::initialize()
{
	// local attribute initialization

	MFnMatrixAttribute  mAttr;
	wtBSMatrix=mAttr.create( "locateMatrix", "lm");
	    mAttr.setStorable(false);
		mAttr.setConnectable(true);


	MFnTypedAttribute  tAttr;
	defObject=tAttr.create( "targetMesh", "tm",MFnData::kMesh);
	tAttr.setStorable(false);
	tAttr.setConnectable(true);



	//  deformation attributes
	addAttribute( wtBSMatrix);

	attributeAffects( wtBS::wtBSMatrix, wtBS::outputGeom );

	addAttribute( defObject);

	attributeAffects( wtBS::defObject, wtBS::outputGeom );

	return MStatus::kSuccess;
}


MStatus
wtBS::deform( MDataBlock& block,
				MItGeometry& iter,
				const MMatrix& m,
				unsigned int multiIndex)
//
// Method: deform
//
// Description:   Deform the point with a squash algorithm
//
// Arguments:
//   block		: the datablock of the node
//	 iter		: an iterator for the geometry to be deformed
//   m    		: matrix to transform the point into world space
//	 multiIndex : the index of the geometry that we are deforming
//
//
{
	MStatus returnStatus;
	
	// Envelope data from the base class.
	// The envelope is simply a scale factor.
	//
	MDataHandle envData = block.inputValue(envelope, &returnStatus);
	if (MS::kSuccess != returnStatus) return returnStatus;
	float env = envData.asFloat();	

	// Get the matrix which is used to define the direction and scale
	// of the wtBS.
	//
	MDataHandle matData = block.inputValue(wtBSMatrix, &returnStatus );
	if (MS::kSuccess != returnStatus) return returnStatus;
	MMatrix omat = matData.asMatrix();
	MMatrix omatinv = omat.inverse();

	MDataHandle handle = block.inputValue(defObject, &returnStatus );   		
	MObject	mns=handle.asMesh();
	//def.setObject(mns);
 
	MItMeshVertex tgtIter(mns);
 

	// iterate through each point in the geometry
	//
	for ( ; !iter.isDone() && !tgtIter.isDone(); 
	iter.next(),tgtIter.next() ) {

		MPoint pt = iter.position();
		pt *= omatinv;
		
		MPoint tpt = tgtIter.position();

		float weight = weightValue(block,multiIndex,iter.index());
		
		// wtBS algorithm
		//
		float ww=weight*env;
		pt += (tpt-pt)*ww;
		//
		// end of wtBS algorithm

		pt *= omat;
		iter.setPosition(pt);
	}
	return returnStatus;
}


/* override */
MObject&
wtBS::accessoryAttribute() const
//
//	Description:
//	  This method returns a the attribute to which an accessory	
//    shape is connected. If the accessory shape is deleted, the deformer
//	  node will automatically be deleted.
//
//    This method is optional.
//
{
	return wtBS::wtBSMatrix;
}

/* override */
MStatus
wtBS::accessoryNodeSetup(MDagModifier& cmd)
//
//	Description:
//		This method is called when the deformer is created by the
//		"deformer" command. You can add to the cmds in the MDagModifier
//		cmd in order to hook up any additional nodes that your node needs
//		to operate.
//
//		In this example, we create a locator and attach its matrix attribute
//		to the matrix input on the wtBS node. The locator is used to
//		set the direction and scale of the random field.
//
//	Description:
//		This method is optional.
//
{
	MStatus result;

	// hook up the accessory node
	//
	MObject objLoc = cmd.createNode(MString("locator"),
									MObject::kNullObj,
									&result);

	if (MS::kSuccess == result) {
		MFnDependencyNode fnLoc(objLoc);
		MString attrName;
		attrName.set("matrix");
		MObject attrMat = fnLoc.attribute(attrName);

		result = cmd.connect(objLoc,attrMat,this->thisMObject(),wtBS::wtBSMatrix);
	}
	return result;
}


// standard initialization procedures
//

MStatus initializePlugin( MObject obj )
{
	MStatus result;
	MFnPlugin plugin( obj, "Alias|Wavefront - Example", "3.0", "Any");
	result = plugin.registerNode( "wtBS", wtBS::id, wtBS::creator, 
								  wtBS::initialize, MPxNode::kDeformerNode );

	return result;
}

MStatus uninitializePlugin( MObject obj)
{
	MStatus result;
	MFnPlugin plugin( obj );
	result = plugin.deregisterNode( wtBS::id );
	return result;
}
