// Shave and a Haircut // (c) 2019 Epic Games // US Patent 6720962 #include #include #include #include #include #include #include #include #include "shaveHairGeomIt.h" #include "shaveHairShape.h" #include "shaveSDKTYPES.h" static const int mid = SHAVE_VERTS_PER_GUIDE / 2; shaveHairGeomIt::shaveHairGeomIt(void* geom, MObjectArray& components) : MPxGeometryIterator(geom, components) , mComponents(components) , mHairShape((shaveHairShape*)geom) { mWholeGeom = (components.length() == 0); reset(); } shaveHairGeomIt::shaveHairGeomIt(void* geom, MObject& components) : MPxGeometryIterator(geom, components) , mHairShape((shaveHairShape*)geom) { mWholeGeom = components.isNull(); if (!mWholeGeom) mComponents.append(components); reset(); } void shaveHairGeomIt::component(MObject& comp) { if (mIsDone) comp = MObject::kNullObj; else { MFnDoubleIndexedComponent compFn; comp = compFn.create(shaveHairShape::kShaveGuideVertComponent); compFn.addElement(mCurGuide, mCurVert); } } int shaveHairGeomIt::index() const { return mIterationIndex; } int shaveHairGeomIt::indexUnsimplified() const { return mCurGuide * SHAVE_VERTS_PER_GUIDE + mCurVert; } int shaveHairGeomIt::iteratorCount() const { return mNumGuides * SHAVE_VERTS_PER_GUIDE; } void shaveHairGeomIt::next() { if (!mIsDone) { if (mWholeGeom) { if (++mCurVert >= SHAVE_VERTS_PER_GUIDE) { mCurVert = 0; mIsDone = (++mCurGuide >= mNumGuides); } } else { MFnComponent compFn(mComponents[mObjIndex]); if (++mElementIndex >= compFn.elementCount()) { mElementIndex = 0; // // I don't know if we need to worry about the // possibility of empty component objects, but if so, // this should take care of them. // while (++mObjIndex < mComponents.length()) { compFn.setObject(mComponents[mObjIndex]); if (compFn.elementCount() > 0) break; } mIsDone = (mObjIndex >= mComponents.length()); } if (!mIsDone) { if (mComponents[mObjIndex].hasFn(MFn::kSingleIndexedComponent)) { MFnSingleIndexedComponent guideComp(mComponents[mObjIndex]); mCurGuide = guideComp.element(mElementIndex); mCurVert = mid; } else { MFnDoubleIndexedComponent vertComp(mComponents[mObjIndex]); vertComp.getElement(mElementIndex, mCurGuide, mCurVert); } } } mIterationIndex++; } } MPoint shaveHairGeomIt::point() const { MPoint p; if (!mIsDone && mHairShape) { // // Load the hairShape into the Shave engine. // mHairShape->makeCurrent(); SOFTGUIDE guide; if (SHAVEfetch_guide(mCurGuide, &guide) != -1) { VERT& vert = guide.guide[mCurVert]; p.x = (double)vert.x; p.y = (double)vert.y; p.z = (double)vert.z; // // Transform the point into local space. // MDagPath shapePath; MDagPath::getAPathTo(mHairShape->thisMObject(), shapePath); p *= shapePath.inclusiveMatrixInverse(); } } return p; } void shaveHairGeomIt::reset() { MPxGeometryIterator::reset(); setCurrentPoint(0); mIterationIndex = 0; if (mHairShape) { mNumGuides = (int)mHairShape->getGuideCount(); setMaxPoints(mNumGuides * SHAVE_VERTS_PER_GUIDE); } else { setMaxPoints(0); mNumGuides = 0; } mCurGuide = 0; mCurVert = 0; if (mWholeGeom) { mIsDone = (mNumGuides == 0); } else { // // I don't know if we have to worry about getting empty component // objects, but let's check, just to be safe. // for (mObjIndex = 0; mObjIndex < mComponents.length(); mObjIndex++) { if (mComponents[mObjIndex].hasFn(MFn::kSingleIndexedComponent)) { MFnSingleIndexedComponent compFn(mComponents[mObjIndex]); if (compFn.elementCount() > 0) { mCurGuide = compFn.element(0); mCurVert = mid; break; } } else if (mComponents[mObjIndex].hasFn(MFn::kDoubleIndexedComponent)) { MFnDoubleIndexedComponent compFn(mComponents[mObjIndex]); if (compFn.elementCount() > 0) { compFn.getElement(0, mCurGuide, mCurVert); break; } } } mIsDone = (mObjIndex >= mComponents.length()); mElementIndex = 0; } } void shaveHairGeomIt::setPoint(const MPoint& newPoint) const { cout << "shaveHairGeomIt::setPoint" << endl; // %%% not yet implemented } int shaveHairGeomIt::setPointGetNext(MPoint& pointInOut) { // %%% 'set' portion not yet implemented cout << "shaveHairGeomIt::setPointGetNext" << endl; next(); pointInOut = point(); return index(); }