#include <maya/MIOStream.h>
#include <stdio.h>
#include <stdlib.h>
#include <maya/MFn.h>
#include <maya/MPxNode.h>
#include <maya/MPxManipContainer.h>
#include <maya/MPxSelectionContext.h>
#include <maya/MPxContextCommand.h>
#include <maya/MModelMessage.h>
#include <maya/MFnPlugin.h>
#include <maya/MGlobal.h>
#include <maya/MItSelectionList.h>
#include <maya/MPoint.h>
#include <maya/MVector.h>
#include <maya/MDagPath.h>
#include <maya/MManipData.h>
#include <maya/MSelectionList.h>
#include <maya/MItSurfaceCV.h>
#include <maya/MFnComponent.h>
#include <maya/MFnScaleManip.h>
MVector vectorPlugValue(const MPlug& plug) {
if (plug.numChildren() == 3)
{
double x,y,z;
MPlug rx = plug.child(0);
MPlug ry = plug.child(1);
MPlug rz = plug.child(2);
rx.getValue(x);
ry.getValue(y);
rz.getValue(z);
MVector result(x,y,z);
return result;
}
else {
MGlobal::displayError("Expected 3 children for plug "+MString(plug.name()));
MVector result(0,0,0);
return result;
}
}
class componentScaleManip : public MPxManipContainer
{
public:
componentScaleManip();
virtual ~componentScaleManip();
static void * creator();
static MStatus initialize();
virtual MStatus createChildren();
virtual MStatus connectToDependNode(const MObject &node);
virtual void draw(M3dView &view,
const MDagPath &path,
M3dView::DisplayStyle style,
M3dView::DisplayStatus status);
void setSurfaceDagPath(const MDagPath& dagPath) {
surfaceDagPath = dagPath;
}
void setComponentObject(const MObject& obj) {
component = obj;
}
virtual MManipData manipToPlugConversion(unsigned index);
virtual MManipData plugToManipConversion(unsigned index);
MDagPath fScaleManip;
public:
static MTypeId id;
private:
MDagPath surfaceDagPath;
MObject component;
MPoint centroid;
int numComponents;
MPoint* initialPositions;
MPoint* initialControlPoint;
unsigned dummyPlugIndex;
};
MTypeId componentScaleManip::id( 0x80021 );
componentScaleManip::componentScaleManip() : numComponents(0)
, initialPositions(NULL)
, initialControlPoint(NULL)
{
}
componentScaleManip::~componentScaleManip()
{
delete [] initialPositions;
delete [] initialControlPoint;
}
void *componentScaleManip::creator()
{
return new componentScaleManip();
}
MStatus componentScaleManip::initialize()
{
MStatus stat;
stat = MPxManipContainer::initialize();
return stat;
}
MStatus componentScaleManip::createChildren()
{
MStatus stat = MStatus::kSuccess;
fScaleManip = addScaleManip("scaleManip", "scale");
return stat;
}
MStatus componentScaleManip::connectToDependNode(const MObject &node)
{
MStatus stat;
MFnComponent componentFn(component);
if (componentFn.elementCount() > numComponents)
{
delete [] initialPositions;
delete [] initialControlPoint;
numComponents = componentFn.elementCount();
initialPositions = new MPoint[numComponents];
initialControlPoint = new MPoint[numComponents];
}
int i = 0;
for (MItSurfaceCV iter(surfaceDagPath, component); !iter.isDone(); iter.next(), i++)
{
if (i >= numComponents)
{
MGlobal::displayWarning("More components found than expected.");
break;
}
initialPositions[i] = iter.position(MSpace::kWorld);
centroid += initialPositions[i];
MFnDependencyNode nodeFn(node);
MPlug controlPointArrayPlug = nodeFn.findPlug("controlPoints", &stat);
if (controlPointArrayPlug.isNull())
{
MGlobal::displayError("Control point plug not found on node.");
return MS::kFailure;
}
MPlug controlPointPlug =
controlPointArrayPlug.elementByLogicalIndex(iter.index(), &stat);
if (controlPointPlug.isNull())
{
MGlobal::displayError("Control point element not found.");
return MS::kFailure;
}
initialControlPoint[i] = vectorPlugValue(controlPointPlug);
unsigned plugIndex = addManipToPlugConversion(controlPointPlug);
if (plugIndex != (unsigned)i)
{
MGlobal::displayError("Unexpected plug index returned.");
return MS::kFailure;
}
}
centroid = centroid / numComponents;
MFnScaleManip scaleManip(fScaleManip);
addPlugToManipConversion(scaleManip.scaleCenterIndex());
finishAddingManips();
MPxManipContainer::connectToDependNode(node);
return stat;
}
void componentScaleManip::draw(M3dView & view,
const MDagPath & path,
M3dView::DisplayStyle style,
M3dView::DisplayStatus status)
{
MPxManipContainer::draw(view, path, style, status);
}
MManipData componentScaleManip::plugToManipConversion(unsigned index) {
MObject obj = MObject::kNullObj;
MFnScaleManip scaleManip(fScaleManip);
if (index == scaleManip.scaleCenterIndex())
{
MFnNumericData numericData;
obj = numericData.create( MFnNumericData::k3Double );
numericData.setData(centroid.x,centroid.y,centroid.z);
return MManipData(obj);
}
MGlobal::displayError("Invalid index in plugToManipConversion()!");
MFnNumericData numericData;
obj = numericData.create( MFnNumericData::k3Double );
numericData.setData(0.0,0.0,0.0);
return obj;
}
MManipData componentScaleManip::manipToPlugConversion(unsigned index) {
MObject obj = MObject::kNullObj;
MFnScaleManip scaleManip(fScaleManip);
if (index < (unsigned)numComponents)
{
MVector scaleVal;
getConverterManipValue(scaleManip.scaleIndex(), scaleVal);
MVector positionVec = initialPositions[index] - centroid;
MVector newPosition(positionVec.x*scaleVal.x,
positionVec.y*scaleVal.y, positionVec.z*scaleVal.z);
newPosition = newPosition - positionVec;
newPosition += initialControlPoint[index];
MFnNumericData numericData;
obj = numericData.create( MFnNumericData::k3Double );
numericData.setData(newPosition.x,newPosition.y,newPosition.z);
return MManipData(obj);
}
MGlobal::displayError("Invalid index in scale changed callback!");
MFnNumericData numericData;
obj = numericData.create( MFnNumericData::k3Double );
numericData.setData(0.0,0.0,0.0);
return obj;
}
class ComponentScaleContext : public MPxSelectionContext
{
public:
ComponentScaleContext();
virtual void toolOnSetup(MEvent &event);
virtual void toolOffCleanup();
static void updateManipulators(void * data);
private:
MCallbackId id1;
};
ComponentScaleContext::ComponentScaleContext()
{
MString str("Plugin component scaling manipulator");
setTitleString(str);
}
void ComponentScaleContext::toolOnSetup(MEvent &)
{
MString str("Scale the selected components");
setHelpString(str);
updateManipulators(this);
MStatus status;
id1 = MModelMessage::addCallback(MModelMessage::kActiveListModified,
updateManipulators,
this, &status);
if (!status) {
MGlobal::displayError("Model addCallback failed");
}
}
void ComponentScaleContext::toolOffCleanup()
{
MStatus status;
status = MModelMessage::removeCallback(id1);
if (!status) {
MGlobal::displayError("Model remove callback failed");
}
MPxContext::toolOffCleanup();
}
void ComponentScaleContext::updateManipulators(void * data)
{
MStatus stat = MStatus::kSuccess;
ComponentScaleContext * ctxPtr = (ComponentScaleContext *) data;
ctxPtr->deleteManipulators();
MSelectionList list;
stat = MGlobal::getActiveSelectionList(list);
MItSelectionList iter(list, MFn::kInvalid, &stat);
if (MS::kSuccess == stat) {
for (; !iter.isDone(); iter.next()) {
MDagPath dagPath;
MObject components;
iter.getDagPath(dagPath, components);
if (components.isNull() || !components.hasFn(MFn::kComponent))
{
MGlobal::displayWarning("Object in selection list is not "
"a component.");
continue;
}
MString manipName ("componentScaleManip");
MObject manipObject;
componentScaleManip* manipulator =
(componentScaleManip *) componentScaleManip::newManipulator(manipName, manipObject);
if (NULL != manipulator) {
ctxPtr->addManipulator(manipObject);
manipulator->setSurfaceDagPath(dagPath);
manipulator->setComponentObject(components);
if (!manipulator->connectToDependNode(dagPath.node()))
{
MGlobal::displayWarning("Error connecting manipulator to"
" object");
}
}
}
}
}
class componentScaleContext : public MPxContextCommand
{
public:
componentScaleContext() {};
virtual MPxContext * makeObj();
public:
static void* creator();
};
MPxContext *componentScaleContext::makeObj()
{
return new ComponentScaleContext();
}
void *componentScaleContext::creator()
{
return new componentScaleContext;
}
MStatus initializePlugin(MObject obj)
{
MStatus status;
MFnPlugin plugin(obj, PLUGIN_COMPANY, "6.0", "Any");
status = plugin.registerContextCommand("componentScaleContext",
&componentScaleContext::creator);
if (!status) {
MGlobal::displayError("Error registering componentScaleContext command");
return status;
}
status = plugin.registerNode("componentScaleManip", componentScaleManip::id,
&componentScaleManip::creator, &componentScaleManip::initialize,
MPxNode::kManipContainer);
if (!status) {
MGlobal::displayError("Error registering componentScaleManip node");
return status;
}
return status;
}
MStatus uninitializePlugin(MObject obj)
{
MStatus status;
MFnPlugin plugin(obj);
status = plugin.deregisterContextCommand("componentScaleContext");
if (!status) {
MGlobal::displayError("Error deregistering componentScaleContext command");
return status;
}
status = plugin.deregisterNode(componentScaleManip::id);
if (!status) {
MGlobal::displayError("Error deregistering componentScaleManip node");
return status;
}
return status;
}