diff options
| author | Ben Marsh <[email protected]> | 2019-10-22 09:07:59 -0400 |
|---|---|---|
| committer | Ben Marsh <[email protected]> | 2019-10-22 09:07:59 -0400 |
| commit | bd0027e737c6512397f841c22786274ed74b927f (patch) | |
| tree | f7ffbdb8f3741bb7f24635616cc189cba5cb865c /mayaPlug/shaveNodeCmd.cpp | |
| download | shave-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.cpp | 1003 |
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); +} |