aboutsummaryrefslogtreecommitdiff
path: root/mayaPlug/shaveNodeCmd.cpp
diff options
context:
space:
mode:
authorBen Marsh <[email protected]>2019-10-22 09:07:59 -0400
committerBen Marsh <[email protected]>2019-10-22 09:07:59 -0400
commitbd0027e737c6512397f841c22786274ed74b927f (patch)
treef7ffbdb8f3741bb7f24635616cc189cba5cb865c /mayaPlug/shaveNodeCmd.cpp
downloadshave-and-a-haircut-bd0027e737c6512397f841c22786274ed74b927f.tar.xz
shave-and-a-haircut-bd0027e737c6512397f841c22786274ed74b927f.zip
Adding Shave-and-a-Haircut 9.6
Diffstat (limited to 'mayaPlug/shaveNodeCmd.cpp')
-rw-r--r--mayaPlug/shaveNodeCmd.cpp1003
1 files changed, 1003 insertions, 0 deletions
diff --git a/mayaPlug/shaveNodeCmd.cpp b/mayaPlug/shaveNodeCmd.cpp
new file mode 100644
index 0000000..d124507
--- /dev/null
+++ b/mayaPlug/shaveNodeCmd.cpp
@@ -0,0 +1,1003 @@
+// Shave and a Haircut
+// (c) 2019 Epic Games
+// US Patent 6720962
+
+#include "shaveIO.h"
+
+#include <maya/MArgDatabase.h>
+#include <maya/MArgList.h>
+#include <maya/MDagModifier.h>
+#include <maya/MDGModifier.h>
+#include <maya/MDoubleArray.h>
+#include <maya/MFnAttribute.h>
+#include <maya/MFnDependencyNode.h>
+#include <maya/MFnNurbsCurve.h>
+#include <maya/MGlobal.h>
+#include <maya/MObjectArray.h>
+#include <maya/MPlugArray.h>
+#include <maya/MPoint.h>
+#include <maya/MPointArray.h>
+#include <maya/MPxCommand.h>
+#include <maya/MSelectionList.h>
+#include <maya/MSyntax.h>
+#include <maya/MString.h>
+#include <maya/MTime.h>
+#include <maya/MVector.h>
+#include <maya/MVectorArray.h>
+
+#include "shaveGlobals.h"
+#include "shaveHairShape.h"
+#include "shaveNodeCmd.h"
+#include "shaveSDK.h"
+#include "shaveUtil.h"
+
+
+static const char* flCollisionList = "-collisionList";
+static const char* fsCollisionList = "-cl";
+static const char* flCopyHair = "-copyHair";
+static const char* fsCopyHair = "-cph";
+static const char* flCurve = "-curve";
+static const char* fsCurve = "-crv";
+static const char* flDump = "-dump";
+static const char* fsDump = "-d";
+static const char* flGrowthList = "-growthList";
+static const char* fsGrowthList = "-gl";
+static const char* flGuidesToCurves = "-guidesToCurves";
+static const char* fsGuidesToCurves = "-gtc";
+static const char* flHairsToCurves = "-hairsToCurves";
+static const char* fsHairsToCurves = "-htc";
+static const char* flHairsToPolygons = "-hairsToPolygons";
+static const char* fsHairsToPolygons = "-htp";
+static const char* flParent = "-parent";
+static const char* fsParent = "-p";
+static const char* flRecomb = "-recomb";
+static const char* fsRecomb = "-rc";
+static const char* flRepair = "-repair";
+static const char* fsRepair = "-rep";
+static const char* flSplineLock = "-splineLock";
+static const char* fsSplineLock = "-slk";
+
+
+const MString shaveNodeCmd::commandName("shaveNode");
+
+
+shaveNodeCmd::shaveNodeCmd() {}
+shaveNodeCmd::~shaveNodeCmd() {}
+
+
+void* shaveNodeCmd::createCmd()
+{
+ return new shaveNodeCmd();
+}
+
+
+MSyntax shaveNodeCmd::createSyntax()
+{
+ MSyntax syntax;
+
+ syntax.enableEdit(true);
+ syntax.enableQuery(true);
+
+ syntax.addFlag(fsCollisionList, flCollisionList);
+ syntax.addFlag(fsCopyHair, flCopyHair, MSyntax::kSelectionItem);
+
+ syntax.addFlag(fsCurve, flCurve, MSyntax::kSelectionItem);
+ syntax.makeFlagMultiUse(fsCurve);
+
+ syntax.addFlag(fsDump, flDump);
+ syntax.addFlag(fsGrowthList, flGrowthList);
+ syntax.addFlag(fsGuidesToCurves, flGuidesToCurves);
+ syntax.addFlag(fsHairsToCurves, flHairsToCurves);
+ syntax.addFlag(fsHairsToPolygons, flHairsToPolygons);
+ syntax.addFlag(fsParent, flParent, MSyntax::kSelectionItem);
+ syntax.addFlag(fsRecomb, flRecomb);
+ syntax.addFlag(fsRepair, flRepair);
+ syntax.addFlag(fsSplineLock, flSplineLock);
+
+ syntax.setObjectType(MSyntax::kSelectionList, 1, 1);
+ syntax.useSelectionAsDefault(false);
+
+ return syntax;
+}
+
+
+MStatus shaveNodeCmd::copyInputConnections(
+ MDGModifier& dgMod, MObject srcNode, MObject destNode, MObject attr
+)
+{
+ MPlugArray conns;
+ MPlug destPlug(destNode, attr);
+ unsigned int i;
+ MPlug srcPlug(srcNode, attr);
+
+ srcPlug.connectedTo(conns, true, false);
+
+ if (conns.length() > 0)
+ dgMod.connect(conns[0], destPlug);
+
+ //
+ // If this is a compound attribute, do its children recursively.
+ //
+ if (srcPlug.numChildren() > 0)
+ {
+ unsigned int i;
+
+ for (i = 0; i < srcPlug.numChildren(); i++)
+ {
+ copyInputConnections(
+ dgMod, srcNode, destNode, destPlug.child(i).attribute()
+ );
+ }
+ }
+
+ //
+ // If this is an array attribute, then do its elements as well.
+ // Note that we don't do them recursively because this method does not
+ // properly handle the children of an array element. At the time that
+ // this was written, the shaveHairShape didn't have any such
+ // attributes, so it wasn't necessary to support them.
+ //
+ // Maya Bug: I used to just get numConnectedElements() then step
+ // through them using connectionByPhysicalIndex(). But
+ // the latter continues to report connections after
+ // they've been broken, which puts it out of synch with
+ // numConnectedElements(). So I now run through every
+ // element and check for connections.
+ //
+ unsigned int numElements = srcPlug.evaluateNumElements();
+
+ for (i = 0; i < numElements; i++)
+ {
+ MPlug element = srcPlug.elementByPhysicalIndex(i);
+
+ element.connectedTo(conns, true, false);
+
+ if (conns.length() > 0)
+ {
+ unsigned int logicalIndex = element.logicalIndex();
+
+ dgMod.connect(
+ conns[0], destPlug.elementByLogicalIndex(logicalIndex)
+ );
+ }
+ }
+
+ return MS::kSuccess;
+}
+
+
+MStatus shaveNodeCmd::doEditFlags(
+ const MArgDatabase& args, shaveHairShape* nodePtr
+)
+{
+ MStatus st;
+
+ if (args.isFlagSet(fsCopyHair))
+ {
+ MSelectionList list;
+ MObject srcNode;
+
+ args.getFlagArgument(fsCopyHair, 0, list);
+ list.getDependNode(0, srcNode);
+
+ MFnDependencyNode srcFn(srcNode, &st);
+
+ if (srcNode.isNull()
+ || !st
+ || (srcFn.typeId() != shaveHairShape::id))
+ {
+ displayError(
+ "-cp/-copyParams flag requires a shaveHairShape as"
+ " its argument."
+ );
+
+ return MS::kInvalidParameter;
+ }
+
+ // If any of the source node's params are being supplied by
+ // connections, then make the same connections to the destination
+ // node's params.
+ MDGModifier dgMod;
+ MObject node = nodePtr->thisMObject();
+
+ copyInputConnections(
+ dgMod, srcNode, node, shaveHairShape::hairColorTexture
+ );
+
+ copyInputConnections(
+ dgMod, srcNode, node, shaveHairShape::mutantHairColorTexture
+ );
+
+ copyInputConnections(
+ dgMod, srcNode, node, shaveHairShape::rootHairColorTexture
+ );
+
+ copyInputConnections(
+ dgMod, srcNode, node, shaveHairShape::shaveTextureAttr
+ );
+
+ dgMod.doIt();
+
+ // Get a pointer to the source node's instance.
+ shaveHairShape* srcNodePtr = (shaveHairShape*)srcFn.userNode();
+
+ // Copy the internal hairnode.
+ SHAVEcopy_node(
+ &(nodePtr->hairnode), &(srcNodePtr->hairnode), nodePtr->getShaveID()
+ );
+
+ // Copy the param values.
+ SHAVEset_parms(&(srcNodePtr->hairnode.shavep));
+ SHAVEfetch_parms(&(nodePtr->hairnode.shavep));
+
+ // Update the destination's node's plugs to reflect its new
+ // parameter values.
+ nodePtr->updatePlugsFromParams();
+ }
+ else if (args.isFlagSet(fsRepair)
+ && !args.isFlagSet(fsCollisionList)
+ && !args.isFlagSet(fsGrowthList))
+ {
+ displayError(
+ "-rep/-repair must be used with either -cl/-collisionList or "
+ "-gl/-growthList."
+ );
+
+ return MS::kInvalidParameter;
+ }
+ else if (args.isFlagSet(fsCollisionList))
+ {
+ if (args.isFlagSet(fsRepair))
+ {
+ st = nodePtr->repairGeomList(
+ shaveHairShape::aCollisionSet,
+ shaveHairShape::collisionObjectsGroupIDAttr
+ );
+
+ if (!st)
+ {
+ displayWarning(
+ MString("Shave: could not repair collision list for ") +
+ nodePtr->name() + "."
+ );
+
+ st = MS::kSuccess;
+ }
+ }
+ else
+ {
+ MSelectionList list;
+
+ MGlobal::getActiveSelectionList(list);
+ nodePtr->setCollisionList(list);
+ }
+ }
+ else if (args.isFlagSet(fsGrowthList))
+ {
+ if (args.isFlagSet(fsRepair))
+ {
+ st = nodePtr->repairGeomList(
+ shaveHairShape::aGrowthSet,
+ shaveHairShape::growthObjectsGroupIDAttr
+ );
+
+ if (!st)
+ {
+ displayWarning(
+ MString("Shave: could not repair growth list for ") +
+ nodePtr->name() + "."
+ );
+
+ st = MS::kSuccess;
+ }
+ }
+ else
+ {
+ MSelectionList list;
+
+ MGlobal::getActiveSelectionList(list);
+ nodePtr->setGrowthList(list);
+ }
+ }
+ else if (args.isFlagSet(fsGuidesToCurves))
+ {
+ MDagModifier dm;
+ MDagPath group = getParentTransform(args, dm, st);
+
+ if (!st) return st;
+
+ MObject curve;
+ MFnNurbsCurve curveFn;
+ SOFTGUIDE guide;
+
+ int guideIndex;
+ int hairGroup = nodePtr->getHairGroup();
+ int numCurveSegs = nodePtr->hairnode.shavep.segs[hairGroup];
+ int numCurveVerts = numCurveSegs + 1;
+ int numGuideSegs = SHAVE_VERTS_PER_GUIDE - 1;
+
+ numCurveSegs = numCurveSegs > numGuideSegs ? numGuideSegs : numCurveSegs;
+ numCurveVerts = numCurveVerts > SHAVE_VERTS_PER_GUIDE ? SHAVE_VERTS_PER_GUIDE : numCurveVerts;
+
+ double guideSegsPerHairSeg = (float)numGuideSegs/(float)(numCurveSegs);
+
+ //printf("numCurveSegs %i numCurveVerts %i numGuideSets %i \n",numCurveSegs,numCurveVerts,numGuideSegs);fflush(stdout);
+
+ int guideVertIndex;
+ int i;
+ MDoubleArray knots(numCurveVerts);
+ MPointArray points(numCurveVerts);
+ MVector p1, p2, p3, p4;
+ double u;
+ MVector vert;
+
+ for (guideIndex = 0;
+ SHAVEfetch_guide(guideIndex, &guide) != -1;
+ guideIndex++)
+ {
+ MVectorArray guideVerts(SHAVE_VERTS_PER_GUIDE);
+
+ for (i = 0; i < SHAVE_VERTS_PER_GUIDE; i++)
+ {
+ guideVerts.set(
+ MVector(
+ guide.guide[i].x,
+ guide.guide[i].y,
+ guide.guide[i].z
+ ),
+ i
+ );
+ }
+
+ // Make sure that the first curve vert lies precisely on
+ // the first guide vert.
+ points.set(0, guideVerts[0].x, guideVerts[0].y, guideVerts[0].z);
+ knots.set(0.0, 0);
+
+ for (i = 1; i < numCurveVerts - 1; i++)
+ {
+ // Interpolate the curve point along the guide.
+ u = guideSegsPerHairSeg * (double)i;
+ guideVertIndex = (int)u;
+ u -= (double)guideVertIndex;
+
+ p2 = guideVerts[guideVertIndex];
+ p3 = guideVerts[guideVertIndex+1];
+
+ if (guideVertIndex > 0)
+ p1 = guideVerts[guideVertIndex-1];
+ else
+ p1 = p2;
+
+ if (guideVertIndex < numGuideSegs)
+ p4 = guideVerts[guideVertIndex+2];
+ else
+ p4 = p3;
+
+ vert = interpolate(p1, p2, p3, p4, u);
+
+ points.set(i, vert.x, vert.y, vert.z);
+ knots.set((double)i, i);
+ }
+
+ // Make sure that the last curve vert lies precisely on
+ // the last guide vert.
+ points.set(
+ numCurveSegs,
+ guideVerts[numGuideSegs].x,
+ guideVerts[numGuideSegs].y,
+ guideVerts[numGuideSegs].z
+ );
+ knots.set((double)numCurveSegs, numCurveSegs);
+
+ curve = curveFn.create(
+ points,
+ knots,
+ 1,
+ MFnNurbsCurve::kOpen,
+ false,
+ true,
+ MObject::kNullObj,
+ &st
+ );
+
+ if (!st)
+ {
+ displayError(
+ commandName + ": error creating curve: " + st.errorString()
+ );
+ return st;
+ }
+
+ st = dm.reparentNode(curve, group.node());
+
+ if (!st)
+ {
+ displayError(
+ commandName
+ + ": error reparenting curve under group transform: "
+ + st.errorString()
+ );
+ return st;
+ }
+ }
+
+ if (guideIndex == 0)
+ {
+ displayError(
+ commandName + ": shave node contains no guides."
+ );
+
+ return MS::kFailure;
+ }
+
+ st = dm.doIt();
+
+ if (!st)
+ {
+ displayError(
+ commandName + ": error committing changes to DAG: "
+ + st.errorString()
+ );
+ return st;
+ }
+
+ MSelectionList list;
+
+ list.add(group);
+ MGlobal::setActiveSelectionList(list);
+
+ setResult(group.partialPathName());
+ }
+ else if (args.isFlagSet(fsHairsToCurves))
+ {
+ MDagModifier dm;
+ MDagPath group = getParentTransform(args, dm, st);
+
+ if (!st) return st;
+
+ CURVEINFO ci;
+ MObject curve;
+ MFnNurbsCurve curveFn;
+ bool gotACurve = false;
+ int hairNum;
+ int hairGroup = nodePtr->getHairGroup();
+ SHAVENODE* hairnode = nodePtr->getHairNode();
+ int numHairs = hairnode->shavep.haircount[hairGroup];
+ int numSegs = hairnode->shavep.segs[hairGroup];
+ WFTYPE wf;
+
+ init_geomWF(&wf);
+
+ for (hairNum = 0; hairNum < numHairs; hairNum++)
+ {
+ SHAVEmake_a_curve(0, hairGroup, hairNum, numSegs, &wf, &ci);
+
+ if (wf.totalverts > 0)
+ {
+ int face;
+
+ for (face = 0; face < wf.totalfaces; face++)
+ {
+ MDoubleArray knots;
+ MPointArray points;
+
+ int vert;
+
+ for (vert = wf.face_start[face]; vert < wf.face_end[face]; vert++)
+ {
+ points.append(
+ wf.v[wf.facelist[vert]].x,
+ wf.v[wf.facelist[vert]].y,
+ wf.v[wf.facelist[vert]].z
+ );
+ knots.append((double)(vert - wf.face_start[face]));
+ }
+
+ gotACurve = true;
+
+ curve = curveFn.create(
+ points,
+ knots,
+ 1,
+ MFnNurbsCurve::kOpen,
+ false,
+ true,
+ MObject::kNullObj,
+ &st
+ );
+
+ if (!st)
+ {
+ displayError(
+ commandName + ": error creating curve: "
+ + st.errorString()
+ );
+ return st;
+ }
+
+ st = dm.reparentNode(curve, group.node());
+
+ if (!st)
+ {
+ displayError(
+ commandName
+ + ": error reparenting curve under group transform: "
+ + st.errorString()
+ );
+ return st;
+ }
+ }
+ }
+ }
+
+ free_geomWF(&wf);
+
+ if (!gotACurve)
+ {
+ displayError(
+ commandName + ": shave node contains no hairs."
+ );
+
+ return MS::kFailure;
+ }
+
+ st = dm.doIt();
+
+ if (!st)
+ {
+ displayError(
+ commandName + ": error committing changes to DAG: "
+ + st.errorString()
+ );
+ return st;
+ }
+
+ MSelectionList list;
+
+ list.add(group);
+ MGlobal::setActiveSelectionList(list);
+
+ setResult(group.partialPathName());
+ }
+ else if (args.isFlagSet(fsHairsToPolygons))
+ {
+ MDagModifier dm;
+ MDagPath parent = getParentTransform(args, dm, st);
+
+ if (!st) return st;
+
+ MObject meshNode = nodePtr->createExternalMesh(parent.node(), &st);
+
+ if (!st)
+ {
+ displayError(
+ commandName + ": could not create hair mesh: " + st.errorString()
+ );
+ return st;
+ }
+
+ st = dm.doIt();
+
+ if (!st)
+ {
+ displayError(
+ commandName + ": error committing changes to DAG: "
+ + st.errorString()
+ );
+ return st;
+ }
+
+ MSelectionList list;
+
+ list.add(parent);
+ MGlobal::setActiveSelectionList(list);
+
+ setResult(parent.partialPathName());
+ }
+ else if (args.isFlagSet(fsRecomb))
+ {
+ MDagPathArray curves;
+ st = getCurves(args, curves);
+
+ if (st)
+ {
+ if (curves.length() == 0)
+ {
+ displayError(
+ MString("The ") + flRecomb + " flag requires that you "
+ + "specify one or more curves using the " + flCurve
+ + " flag."
+ );
+ st = MS::kInvalidParameter;
+ }
+ else
+ {
+ // Copy the curves into an object array.
+ MObjectArray curveObjs;
+
+ for (unsigned int i = 0; i < curves.length(); ++i)
+ {
+ MFnNurbsCurve curveFn(curves[i]);
+ curveObjs.append(curveFn.object());
+ }
+
+ // Shave wants points on the curve, not cvs. Since
+ // Shave reparameterizes all curves to
+ // SHAVE_VERTS_PER_GUIDE points, we might as well just
+ // give it that many points per curve in the first
+ // place.
+ WFTYPE curveData;
+
+ shaveUtil::sampleCurves(
+ curveObjs, SHAVE_VERTS_PER_GUIDE, curveData
+ );
+
+ nodePtr->recomb(curveData);
+ free_geomWF(&curveData);
+ }
+ }
+ }
+ else if (args.isFlagSet(fsSplineLock))
+ {
+ MDagPathArray curves;
+ st = getCurves(args, curves);
+
+ if (st)
+ {
+ if (curves.length() == 0)
+ nodePtr->clearSplineLocks();
+ else
+ nodePtr->setSplineLocks(curves);
+ }
+ }
+ else
+ {
+ displayError("No editable flags specified.");
+ st = MS::kInvalidParameter;
+ }
+
+ return st;
+}
+
+
+MStatus shaveNodeCmd::doIt(const MArgList& argList)
+{
+ MStatus st;
+ MArgDatabase args(syntax(), argList, &st);
+
+ if (!st) return st;
+
+ shaveHairShape* nodePtr = getShaveNode(args);
+ if (nodePtr == NULL) return MS::kInvalidParameter;
+
+ if (args.isQuery())
+ {
+ st = doQueryFlags(args, nodePtr);
+ }
+ else if (args.isEdit())
+ {
+ st = doEditFlags(args, nodePtr);
+ }
+ else
+ {
+ displayError(commandName + ": must specify one of -edit or -query.");
+ st = MS::kInvalidParameter;
+ }
+
+ return st;
+}
+
+
+MStatus shaveNodeCmd::doQueryFlags(
+ const MArgDatabase& args, shaveHairShape* nodePtr
+)
+{
+ MStatus st;
+
+ MObject node = nodePtr->thisMObject();
+
+ if (args.isFlagSet(fsDump))
+ {
+ MPlugArray connections;
+ MTime timeVal;
+ MFnAttribute attrFn;
+ MString indent(" ");
+
+ cout << "Warning: The -dump flag is not yet fully implemented."
+ << endl
+ << " Here's what we have so far..."
+ << endl;
+
+#if defined(OSMac_) && (MAYA_API_VERSION >= 201600) && (MAYA_API_VERSION < 201700)
+ cout << "Attribute values for '" << nodePtr->name().asChar() << "':" << endl;
+#else
+ cout << "Attribute values for '" << nodePtr->name() << "':" << endl;
+#endif
+
+ //
+ // time
+ //
+ MPlug plug(node, shaveHairShape::timeAttr);
+ plug.getValue(timeVal);
+
+ attrFn.setObject(shaveHairShape::timeAttr);
+
+#if defined(OSMac_) && (MAYA_API_VERSION >= 201600) && (MAYA_API_VERSION < 201700)
+ cout << indent.asChar() << attrFn.name().asChar() << ": " << timeVal.value()
+ << endl;
+#else
+ cout << indent << attrFn.name() << ": " << timeVal.value()
+ << endl;
+#endif
+
+ displayInputConnection(node, shaveHairShape::inputCurve, indent);
+ displayInputConnection(node, shaveHairShape::inputMesh, indent);
+ displayInputConnection(node, shaveHairShape::inputSurf, indent);
+ displayInputConnection(node, shaveHairShape::collisionObjectsAttr, indent);
+ }
+ else if (args.isFlagSet(fsCollisionList))
+ {
+ MSelectionList collisionList;
+ nodePtr->getCollisionList(collisionList);
+
+ MStringArray collisionObjectNames;
+ collisionList.getSelectionStrings(collisionObjectNames);
+ setResult(collisionObjectNames);
+ }
+ else if (args.isFlagSet(fsGrowthList))
+ {
+ MSelectionList growthList;
+ nodePtr->getGrowthList(growthList);
+
+ MStringArray growthObjectNames;
+ growthList.getSelectionStrings(growthObjectNames);
+ setResult(growthObjectNames);
+ }
+ else
+ {
+ displayError("No queryable flags specified.");
+ st = MS::kInvalidParameter;
+ }
+
+ return st;
+}
+
+
+void shaveNodeCmd::displayInputConnection(
+ MObject node, MObject attr, MString indent
+)
+{
+ MPlug plug(node, attr);
+ MFnAttribute attrFn(attr);
+ MPlugArray connections;
+ MString otherPlugName;
+
+ if (plug.isArray())
+ {
+ //
+ // Maya Bug: I used to just get numConnectedElements() then step
+ // through them using connectionByPhysicalIndex(). But
+ // the latter continues to report connections after
+ // they've been broken, which puts it out of synch with
+ // numConnectedElements(). So I now run through every
+ // element and check for connections.
+ //
+ unsigned int numElements = plug.evaluateNumElements();
+ unsigned int i;
+ bool foundConnections = false;
+
+ for (i = 0; i < numElements; i++)
+ {
+ MPlug element = plug.elementByPhysicalIndex(i);
+
+ element.connectedTo(connections, true, false);
+
+ if (connections.length() > 0)
+ {
+ MString elementName = element.name();
+
+ //
+ // Strip the node name from the start of the element name.
+ //
+#if defined(OSMac_) && (MAYA_API_VERSION >= 201600) && (MAYA_API_VERSION < 201700)
+ cout << indent.asChar() << stripNode(element.name()).asChar() << ": "
+ << connections[0].name().asChar() << endl;
+#else
+ cout << indent << stripNode(element.name()) << ": "
+ << connections[0].name() << endl;
+#endif
+
+ foundConnections = true;
+ }
+ }
+
+ if (!foundConnections)
+ {
+#if defined(OSMac_) && (MAYA_API_VERSION >= 201600) && (MAYA_API_VERSION < 201700)
+ cout << indent.asChar() << stripNode(plug.name()).asChar() << ": No Connections"
+ << endl;
+#else
+ cout << indent << stripNode(plug.name()) << ": No Connections"
+ << endl;
+#endif
+ }
+ }
+ else
+ {
+ plug.connectedTo(connections, true, false);
+
+ if (connections.length() > 0)
+ otherPlugName = connections[0].name();
+ else
+ otherPlugName = "Not Connected";
+
+#if defined(OSMac_) && (MAYA_API_VERSION >= 201600) && (MAYA_API_VERSION < 201700)
+ cout << indent.asChar() << stripNode(plug.name()).asChar() << ": "
+ << otherPlugName.asChar() << endl;
+#else
+ cout << indent << stripNode(plug.name()) << ": " << otherPlugName
+ << endl;
+#endif
+ }
+}
+
+
+MStatus shaveNodeCmd::getCurves(const MArgDatabase& args, MDagPathArray& curves)
+{
+ MDagPath curve;
+ MArgList flagArgs;
+ MSelectionList list;
+ unsigned int numCurves = args.numberOfFlagUses(flCurve);
+
+ for (unsigned int i = 0; i < numCurves; i++)
+ {
+ list.clear();
+
+ //
+ // Get a DAG path to this flag's curve.
+ //
+ args.getFlagArgumentList(fsCurve, i, flagArgs);
+ list.add(flagArgs.asString(0));
+ list.getDagPath(0, curve);
+ curve.extendToShape();
+
+ if (!curve.isValid() || !curve.hasFn(MFn::kNurbsCurve))
+ {
+ displayError(
+ MString("'") + flagArgs.asString(0) + "' is not a NURBS curve."
+ );
+ curves.clear();
+ return MS::kInvalidParameter;
+ }
+
+ curves.append(curve);
+ }
+
+ return MS::kSuccess;
+}
+
+
+MDagPath shaveNodeCmd::getParentTransform(
+ const MArgDatabase& args, MDagModifier& dm, MStatus& st
+)
+{
+ MDagPath parent;
+
+ if (args.isFlagSet(fsParent))
+ {
+ MSelectionList list;
+
+ args.getFlagArgument(fsParent, 0, list);
+
+ list.getDagPath(0, parent);
+
+ if (!parent.isValid())
+ {
+ displayError(
+ commandName + ": argument of '" + flParent
+ + "' flag is not a transform."
+ );
+ st = MS::kInvalidParameter;
+ }
+ }
+ else
+ {
+ MObject node = dm.createNode("transform", MObject::kNullObj, &st);
+
+ if (!st)
+ {
+ displayError(
+ commandName + ": could not create group transform: "
+ + st.errorString()
+ );
+ }
+ else
+ {
+ if (args.isFlagSet(flHairsToPolygons))
+ dm.renameNode(node, "shaveHairMesh#");
+ else
+ dm.renameNode(node, "shaveCurveGroup#");
+
+ st = MDagPath::getAPathTo(node, parent);
+
+ if (!st)
+ {
+ displayError(
+ commandName + ": error getting path to group transform: "
+ + st.errorString()
+ );
+ }
+ }
+ }
+
+ return parent;
+}
+
+
+shaveHairShape* shaveNodeCmd::getShaveNode(const MArgDatabase& args)
+{
+ MStatus st;
+ shaveHairShape* nodePtr = NULL;
+
+ //
+ // Get the shaveHairShape to be operated on.
+ //
+ MSelectionList selection;
+ args.getObjects(selection);
+
+ MObject node(MObject::kNullObj);
+ selection.getDependNode(0, node);
+
+ MFnDependencyNode nodeFn(node, &st);
+
+ if (node.isNull() || !st || (nodeFn.typeId() != shaveHairShape::id))
+ {
+ st = MS::kInvalidParameter;
+
+ displayError("No shaveHairShape specified.");
+ }
+ else
+ {
+ nodePtr = (shaveHairShape*)nodeFn.userNode();
+
+ // Make sure that this is the shaveHairShape which is loaded into the
+ // engine.
+ if (nodePtr)
+ {
+ nodePtr->makeCurrent();
+ nodePtr->getHairNode();
+ }
+ }
+
+ return nodePtr;
+}
+
+
+MVector shaveNodeCmd::interpolate(
+ const MVector& p1,
+ const MVector& p2,
+ const MVector& p3,
+ const MVector& p4,
+ double u
+)
+{
+ double u3, u2;
+
+ if (u >= 1.0) return p3;
+ if (u <= 0.0) return p2;
+
+ u3 = u * u * u;
+ u2 = u * u;
+
+ return ((-u3 + (2.0 * u2) - u) * p1 +
+ (3.0 * u3 - 5.0 * u2 + 2.0) * p2 +
+ (-3.0 * u3 + (4.0 * u2) + u) * p3 +
+ (u3 + -u2) * p4) / 2.0;
+}
+
+
+MString shaveNodeCmd::stripNode(MString plugName)
+{
+ return plugName.substring(plugName.index('.')+1, plugName.length()-1);
+}