aboutsummaryrefslogtreecommitdiff
path: root/mayaPlug/shaveGeometryOverride.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'mayaPlug/shaveGeometryOverride.cpp')
-rw-r--r--mayaPlug/shaveGeometryOverride.cpp3840
1 files changed, 3840 insertions, 0 deletions
diff --git a/mayaPlug/shaveGeometryOverride.cpp b/mayaPlug/shaveGeometryOverride.cpp
new file mode 100644
index 0000000..fb29392
--- /dev/null
+++ b/mayaPlug/shaveGeometryOverride.cpp
@@ -0,0 +1,3840 @@
+// Shave and a Haircut
+// (c) 2019 Epic Games
+// US Patent 6720962
+
+#include <maya/M3dView.h>
+#include <maya/MBoundingBox.h>
+#include <maya/MDagPath.h>
+#include <maya/MDrawContext.h>
+#include <maya/MDrawRegistry.h>
+#include <maya/MFloatVector.h>
+#include <maya/MFnCamera.h>
+#include <maya/MFnDagNode.h>
+#include <maya/MFnDependencyNode.h>
+#include <maya/MFnDoubleIndexedComponent.h>
+#include <maya/MFnSingleIndexedComponent.h>
+#include <maya/MGlobal.h>
+#include <maya/MHWGeometry.h>
+#include <maya/MHWGeometryUtilities.h>
+#include <maya/MObject.h>
+#include <maya/MPlug.h>
+#if MAYA_API_VERSION >= 201600
+#include <maya/MPxComponentConverter.h>
+#include <maya/MSelectionContext.h>
+#endif
+#include <maya/MVector.h>
+#include <maya/MViewport2Renderer.h>
+
+#include "shaveGeometryOverride.h"
+#include "shaveGlobals.h"
+
+
+// Names of render items.
+//
+const MString shaveGeometryOverride::kHairShadedItemName = "shaveShaded";
+const MString shaveGeometryOverride::kHairShadedSelectedItemName = "shaveShadedSelection";
+const MString shaveGeometryOverride::kHairWireItemName = "shaveWire";
+const MString shaveGeometryOverride::kHairWireSelectedItemName = "shaveWireSelection";
+const MString shaveGeometryOverride::kInstanceShadedItemName = "shaveInstSolid";
+const MString shaveGeometryOverride::kInstanceWireItemName = "shaveInstWire";
+const MString shaveGeometryOverride::kInstanceWireSelectedItemName = "shaveInstWireSelection";
+const MString shaveGeometryOverride::kGuidesItemName = "shaveGuides";
+const MString shaveGeometryOverride::kKnotsItemName = "shaveKnots";
+
+// pre-draw callback
+//MHWRender::MShaderInstance* gShader = NULL;
+#if 0
+static void shavePreDrawCallback(
+ MHWRender::MDrawContext& context,
+ const MHWRender::MRenderItemList& renderItemList,
+ MHWRender::MShaderInstance *shaderInstance
+ )
+{
+ //printf("Pre-draw callback triggered for render item with name '%s'\n", renderItem->name().asChar());
+}
+// post-draw callback
+static void shavePostDrawCallback(
+ MHWRender::MDrawContext& context,
+ const MHWRender::MRenderItemList& renderItemList,
+ MHWRender::MShaderInstance *shaderInstance
+ )
+{
+ //printf("Post-draw callback triggered for render item with name '%s'\n", renderItem->name().asChar());
+}
+#endif
+
+
+#if MAYA_API_VERSION >= 201600
+// Custom component converter for selecting guide vertices.
+//
+class guideVertComponentConverter : public MHWRender::MPxComponentConverter
+{
+public:
+ guideVertComponentConverter() : MHWRender::MPxComponentConverter() {}
+ virtual ~guideVertComponentConverter() {}
+
+ virtual void initialize(const MHWRender::MRenderItem& renderItem)
+ {
+ mComponent = MObject::kNullObj;
+ mPrimIdxToVertIdx = NULL;
+ mSelectType = "";
+
+ shaveGeometryOverride::SelectionData* itemData = dynamic_cast<shaveGeometryOverride::SelectionData*>(renderItem.customData());
+
+ if (itemData)
+ {
+ mSelectType = itemData->mShaveSelectType;
+ mPrimIdxToVertIdx = &itemData->mPrimIdxToVertIdx;
+
+ // If the selection type is anything other than 'vert' or 'tip'
+ // then we are not selecting verts, we're using verts to select
+ // guides.
+ //
+ if ((mSelectType == "vert") || (mSelectType == "tip"))
+ {
+ mComponent = mVertComponentFn.create(shaveHairShape::kShaveGuideVertComponent);
+ }
+ else
+ {
+ mComponent = mGuideComponentFn.create(shaveHairShape::kShaveGuideComponent);
+ }
+ }
+ }
+
+ virtual void addIntersection(MHWRender::MIntersection& intersection)
+ {
+ int primIdx = intersection.index();
+
+ if (mPrimIdxToVertIdx != NULL)
+ {
+ if ((primIdx >= 0) && (primIdx < mPrimIdxToVertIdx->size()))
+ {
+ int vertIdx = mPrimIdxToVertIdx->at(primIdx);
+ int guideIdx = vertIdx / SHAVE_VERTS_PER_GUIDE;
+
+ if ((mSelectType == "vert") || (mSelectType == "tip"))
+ {
+ vertIdx = vertIdx % SHAVE_VERTS_PER_GUIDE;
+ mVertComponentFn.addElement(guideIdx, vertIdx);
+ }
+ else
+ {
+ mGuideComponentFn.addElement(guideIdx);
+ }
+ }
+ }
+ }
+
+ virtual MObject component()
+ {
+ return mComponent;
+ }
+
+ virtual MSelectionMask selectionMask() const
+ {
+ MSelectionMask mask;
+
+ if ((mSelectType == "vert") || (mSelectType == "tip"))
+ {
+ mask.addMask(MSelectionMask::kSelectCVs);
+
+ // Allow the converter to be used for snapping as well.
+ //
+ mask.addMask(MSelectionMask::kSelectPointsForGravity);
+ }
+ else
+ {
+ mask.addMask(MSelectionMask::kSelectMeshEdges);
+ }
+
+ return mask;
+ }
+
+ static MPxComponentConverter* create()
+ {
+ return new guideVertComponentConverter();
+ }
+
+private:
+ MObject mComponent;
+ MFnSingleIndexedComponent mGuideComponentFn;
+ MFnDoubleIndexedComponent mVertComponentFn;
+ const std::vector<unsigned int>* mPrimIdxToVertIdx;
+ MString mSelectType;
+};
+
+
+// Custom component converter for selecting guides.
+//
+class guideComponentConverter : public MHWRender::MPxComponentConverter
+{
+public:
+ guideComponentConverter() : MHWRender::MPxComponentConverter() {}
+ virtual ~guideComponentConverter() {}
+
+ virtual void initialize(const MHWRender::MRenderItem& renderItem)
+ {
+ mComponent = MObject::kNullObj;
+ mPrimIdxToGuideIdx = NULL;
+ mSelectType = "";
+
+ shaveGeometryOverride::SelectionData* itemData = dynamic_cast<shaveGeometryOverride::SelectionData*>(renderItem.customData());
+
+ if (itemData)
+ {
+ mSelectType = itemData->mShaveSelectType;
+
+ // Only use guides for selection if we're in 'guide' mode.
+ //
+ if (mSelectType == "guide")
+ {
+ mComponent = mComponentFn.create(shaveHairShape::kShaveGuideComponent);
+ mPrimIdxToGuideIdx = &itemData->mPrimIdxToGuideIdx;
+ }
+ }
+ }
+
+ virtual void addIntersection(MHWRender::MIntersection& intersection)
+ {
+ int primIdx = intersection.index();
+ if (mPrimIdxToGuideIdx != NULL)
+ {
+ if ((primIdx >= 0) && (primIdx < mPrimIdxToGuideIdx->size()))
+ {
+ int guideIdx = mPrimIdxToGuideIdx->at(primIdx);
+
+ mComponentFn.addElement(guideIdx);
+ }
+ }
+ }
+
+ virtual MObject component()
+ {
+ return mComponent;
+ }
+
+ virtual MSelectionMask selectionMask() const
+ {
+ MSelectionMask mask;
+
+ if (mSelectType == "guide")
+ {
+ mask.addMask(MSelectionMask::kSelectMeshEdges);
+ }
+
+ return mask;
+ }
+
+ static MPxComponentConverter* create()
+ {
+ return new guideComponentConverter();
+ }
+
+private:
+ MObject mComponent;
+ MFnSingleIndexedComponent mComponentFn;
+ const std::vector<unsigned int>* mPrimIdxToGuideIdx;
+ MString mSelectType;
+};
+#endif
+
+
+shaveGeometryOverride::shaveGeometryOverride(const MObject& obj)
+: MPxGeometryOverride(obj)
+, shave(NULL)
+, instex (NULL)
+{
+ MStatus status;
+ shobj = obj;
+ MFnDependencyNode node(obj, &status);
+ if (status)
+ {
+ shave = dynamic_cast<shaveHairShape*>(node.userNode());
+ }
+ else
+ {
+ MGlobal::displayError("can not attach MFnDependencyNode function set to the shave node");
+ }
+
+ MFnDagNode dag(obj,&status);
+ if (status)
+ {
+ MObject tm = dag.parent(0,&status);
+ if(!tm.isNull() && status == MStatus::kSuccess)
+ {
+ MFnDependencyNode tmfn(tm, &status);
+ //if(!tmfn.isLocked())
+ {
+ //does not have any effect
+ //status = tmfn.setLocked(true);
+ //if(status != MStatus::kSuccess)
+ // MGlobal::displayError("can not lock transfrom");
+
+ MPlug plug = tmfn.findPlug("translate", &status);
+ status = plug.setLocked(true); // lock the attribute
+
+ plug = tmfn.findPlug("rotate", &status);
+ status = plug.setLocked(true); // lock the attribute
+
+ plug = tmfn.findPlug("scale", &status);
+ status = plug.setLocked(true); // lock the attribute
+ }
+ }
+ else
+ MGlobal::displayError("can not get parent for shave node");
+ }
+ else
+ MGlobal::displayError("can not attach MFnDagNode function set to the shave node");
+}
+
+shaveGeometryOverride::~shaveGeometryOverride()
+{
+}
+
+MHWRender::DrawAPI shaveGeometryOverride::supportedDrawAPIs() const
+{
+ //return MHWRender::kAllDevices;
+ //return (MHWRender::kOpenGL | MHWRender::kDirectX11);
+ return MHWRender::kOpenGL;
+}
+
+#define POLY_HAIR
+
+static const bool debugShader = false;
+
+void shaveGeometryOverride::updateDG()
+{
+ MStatus st;
+
+ if (shave)
+ {
+ mNumHairsToDraw = shave->getNumDisplayHairs(false);
+
+ // TODO:
+ //
+ // We assume that the "active" 3d view (i.e. the one the mouse is in)
+ // is also the one currently being drawn. That is not necessarily
+ // true, especially when there are multiple views.
+ //
+ // We can determine the camera being rendered from the MFrameContext
+ // passed to addUIDrawables() (which we don't currently implement) but
+ // that won't be called until *after* updateDG() when it will be too
+ // late to pull data from the shaveHairShape's attrs.
+ //
+ // addUIDrawables() is called *before* populateGeometry(), so one
+ // workaround would be to cache data for *all* available views here,
+ // then select the appropriate set of data in populateGeometry(), based
+ // on the camera determined in addUIDrawables(). However, it would make
+ // sense to first check with ADesk to see if there is a way to get the
+ // necessary cam info (viewport, matrix, etc) here in updateDG().
+ //
+ M3dView view = M3dView::active3dView();
+
+ mLightMode = M3dView::kLightDefault;
+ view.getLightingMode(mLightMode);
+
+ MDagPath camPath;
+ st = view.getCamera(camPath);
+
+ if (st)
+ {
+ MFnCamera camFn(camPath);
+
+ mViewDir = camFn.viewDirection(MSpace::kWorld);
+ mViewDir.normalize();
+
+ mUpDir = camFn.upDirection(MSpace::kWorld);
+ mUpDir.normalize();
+
+ mRightDir = camFn.rightDirection(MSpace::kWorld);
+ mRightDir.normalize();
+
+ mWorldToCam = camPath.inclusiveMatrixInverse();
+ }
+ else
+ {
+ mViewDir = MVector::zAxis;
+ mUpDir = MVector::xAxis;
+ mRightDir = MVector::yAxis;
+ }
+
+#if 1
+ mHairCache = &shave->getDisplayHairs(view, true);
+
+ while (mNumHairsToDraw != mHairCache->displayHair.size())
+ {
+#ifdef GLOBAL_FALLBACK
+ if((IsMouseDown() || GetEventsHappen()) && !liveModeGlob && fallback)
+ {
+ shave->invalidateDisplayHairs();
+ break;
+ }
+#endif
+ mHairCache = &shave->getDisplayHairs(view, false);
+ }
+#ifdef GLOBAL_FALLBACK
+ ClearEvents();
+#endif
+#else
+ mHairCache = &shave->getDisplayHairs();
+#endif
+
+ if (debugShader)
+ {
+ printf("cache size: %zi\n", mHairCache->displayHair.size());
+ }
+
+ if (mNumHairsToDraw > mHairCache->displayHair.size())
+ {
+ mNumHairsToDraw = (unsigned int)mHairCache->displayHair.size();
+ }
+
+ mHairDisplayMode = shave->getDisplayMode();
+ mSpecularTint = shave->getSpecularTint();
+ mSpecularTint2 = shave->getSpecularTint2();
+ mGloss = shave->getGloss();
+ mSpecular = shave->getSpecular();
+ mTransparency = shave->getHairXparency();
+ mDoTipFade = shave->getDoTipfade();
+ mPasses = shave->getNumPasses();
+
+ mInstanceCache = &shave->getInstanceDisplay();
+ mGuideCache = &shave->getGuides().guides;
+
+ mGuideExtent = shave->getGuideExt();
+
+ // If the guide extent is zero then it hasn't yet been calculated, so do it now.
+ //
+ if (mGuideExtent == 0.0f) //compute once
+ {
+ MBoundingBox bbox;
+ bbox.clear();
+
+ shaveHairShape::Guides::const_iterator iter;
+
+ for (iter = mGuideCache->begin(); iter != mGuideCache->end(); iter++)
+ {
+ const shaveHairShape::Guide& guide = *iter;
+ if (!guide.hidden)
+ {
+ MPoint v = guide.verts[SHAVE_VERTS_PER_GUIDE-1];//tip only
+ bbox.expand(v);
+ }
+ }
+
+ mGuideExtent = (float)(bbox.max() - bbox.min()).length();
+ shave->setGuideExt(mGuideExtent);
+ }
+
+ if (!glisntGlob)
+ {
+ shave->updateTexLookups();
+ }
+ }
+}
+#if 0
+///////////////////////////////////////////////////////////////////////////////////
+#ifdef _WIN32
+#else
+# include <string.h>
+# define MAX_PATH 1024
+#endif
+#ifndef _CGFX_PLUGIN_MAX_COMPILER_ARGS_
+#define _CGFX_PLUGIN_MAX_COMPILER_ARGS_ 20
+#endif
+
+MString cgfxFindFile(const MString& name, const MString &searchpath)
+{
+ MString file = name;
+ struct stat statBuf;
+ char path[MAX_PATH];
+
+ const char * psearchpath = searchpath.asChar();
+
+ OutputDebugString("File = ");
+ OutputDebugString(file.asChar());
+ OutputDebugString("\n");
+
+ // First we check if it is a fully qualified path...
+ if (stat(file.asChar(), &statBuf) == -1)
+ {
+ bool found = false;
+
+ while (found == false && psearchpath < searchpath.asChar() + searchpath.length())
+ {
+ const char * endpath = strchr(psearchpath,';');
+ if (endpath)
+ {
+ strncpy(path,psearchpath, endpath - psearchpath);
+ path[endpath - psearchpath] = '\0';
+ }
+ else
+ {
+ strcpy(path,psearchpath);
+ }
+
+ psearchpath += strlen(path)+1;
+
+ bool fullPath = (path[0] == '/' ||
+ path[0] == '\\');
+
+ if (strlen(path) > 2)
+ {
+ fullPath = fullPath ||
+ (path[1] == ':' &&
+ (path[2] == '/' ||
+ path[2] == '\\'));
+ }
+
+ // Add the path and the filename together to get the full path
+ file = MString(path) + "/" + name;
+
+ OutputDebugString("Try File = ");
+ OutputDebugString(file.asChar());
+ OutputDebugString("\n");
+
+ if (stat(file.asChar(), &statBuf) != -1)
+ found = true;
+ else
+ file = "";
+ }
+ }
+
+ OutputDebugString("Returning: ");
+ OutputDebugString(file.asChar());
+ OutputDebugString("\n");
+
+
+ return file;
+}
+
+MString cgfxFindFile(const MString& name, bool projectRelative) {
+ // Our result
+ MString fileName;
+
+ // Do we have an image to look for?
+ if (name.asChar() != NULL && strcmp(name.asChar(), ""))
+ {
+ // Build a list of places we'll look for textures
+ // Start with the current working directory
+ static MString texturePath( ".");
+
+ // Add the standard Maya project paths
+ MString workspace;
+ MStatus status = MGlobal::executeCommand(MString("workspace -q -rd;"),
+ workspace);
+ if ( status == MS::kSuccess)
+ {
+ texturePath += ";";
+ texturePath += workspace;
+ texturePath += ";";
+ texturePath += workspace;
+ texturePath += "/textures;";
+ texturePath += workspace;
+ texturePath += "/images;";
+ texturePath += workspace;
+ }
+
+ // Finally, see if any CgFX environment variable paths are set
+ char * cgfxPath = getenv("CGFX_TEXTURE_PATH");
+ if (cgfxPath)
+ {
+ texturePath += ";";
+ texturePath += cgfxPath;
+ }
+ else
+ {
+ char * cgfxRoot = getenv("CGFX_ROOT");
+ if (cgfxRoot)
+ {
+ texturePath += ";";
+ texturePath += cgfxRoot;
+ texturePath += "/textures/2D;";
+ texturePath += cgfxRoot;
+ texturePath += "/textures/cubemaps;";
+ texturePath += cgfxRoot;
+ texturePath += "/textures/3D;";
+ texturePath += cgfxRoot;
+ texturePath += "/textures/rectangles;";
+ texturePath += cgfxRoot;
+ texturePath += "/CgFX_Textures;";
+ texturePath += cgfxRoot;
+ texturePath += "/CgFX";
+ }
+ }
+
+ OutputDebugString("CgFX texture path is: ");
+ OutputDebugString(texturePath.asChar());
+ OutputDebugString("\n");
+
+ fileName = cgfxFindFile(name, texturePath);
+
+ int hasFile = fileName.asChar() != NULL && strcmp(fileName.asChar(), "");
+
+ if (hasFile == 0)
+ {
+ // lets extract the filename and try it again...
+ int idx = name.rindex('/');
+ if (idx == -1)
+ idx = name.rindex('\\');
+ if (idx != -1)
+ {
+ MString filename = name.substring(idx+1,name.length()-1);
+ fileName = cgfxFindFile(filename, texturePath);
+ hasFile = fileName.asChar() != NULL && strcmp(fileName.asChar(), "");
+ }
+ }
+
+ // If we found the file and the user wants project relative, try
+ // to strip the project directory off the front of our result
+ if( hasFile && projectRelative)
+ {
+ if( fileName.length() > workspace.length() &&
+ workspace.length() > 0 &&
+ fileName.substring( 0, workspace.length() - 1) == workspace)
+ // Strip the project path off the front INCLUDING the
+ // separating '/' (otherwise we'd create an absolute path)
+ fileName = fileName.substring( workspace.length() + 1, fileName.length() - 1);
+ }
+
+ if (hasFile == 0)
+ OutputDebugString("Error: file not found.\n");
+ }
+ return fileName;
+}
+
+void cgfxGetFxIncludePath( const MString &fxFile, MStringArray &pathOptions )
+{
+ // Append the path of the cgfx file as a possible include search path
+ //
+ MString option;
+ if (fxFile.length())
+ {
+ MFileObject fobject;
+ fobject.setRawFullName( fxFile );
+ option = MString("-I") + fobject.resolvedPath();
+ pathOptions.append( option );
+ }
+
+ // Add in "standard" cgfx search for cgfx files as a possible include
+ // search path
+ //
+ char * cgfxRoot = getenv("CGFX_ROOT");
+ if (cgfxRoot)
+ {
+ option = MString("-I") + MString(cgfxRoot);
+ pathOptions.append( option );
+ option = MString("-I") + MString(cgfxRoot) + MString("/CgFX");
+ pathOptions.append( option );
+ }
+
+ // Add in Maya's Cg directory
+ char * mayaLocation = getenv("MAYA_LOCATION");
+ if (mayaLocation)
+ {
+ MString mayaCgLocation(MString(mayaLocation) + MString("/bin/Cg/"));
+ option = MString("-I") + mayaCgLocation;
+ pathOptions.append( option );
+ }
+}
+///////////////////////////////////////////////////////////////////////////////////
+#endif
+
+static bool vp20dlgFired = false;
+
+void shaveGeometryOverride::updateRenderItems(const MDagPath& path,
+ MHWRender::MRenderItemList& list)
+{
+ if (mLightMode == M3dView::kLightActive ||
+ mLightMode == M3dView::kLightAll)
+ {
+ if(!vp20dlgFired)
+ {
+ vp20dlgFired = true;
+ MGlobal::executeCommand("shave_showVP2lightWarning");
+ }
+ }
+ else
+ vp20dlgFired = false;
+
+ if(debugShader) printf("updateRenderItems\n");
+
+ if(!shave)
+ return;
+
+ MHWRender::MRenderer* renderer = MHWRender::MRenderer::theRenderer();
+ if (!renderer) return;
+
+ const MHWRender::MShaderManager* shaderMgr = renderer->getShaderManager();
+ if (!shaderMgr) return;
+
+ MHWRender::MTextureManager* textureMgr = renderer->getTextureManager();
+ if(!textureMgr) return;
+
+ if(debugShader)
+ {
+ MStringArray paths;
+ shaderMgr->shaderPaths(paths);
+ printf("Cgfx shader paths:\n");
+ for(unsigned int i = 0; i < paths.length(); i++)
+ printf("%s\n",paths[i].asChar());
+ }
+
+ // This is the type of primitive we use for drawing anything
+ // which isn't an instance.
+ //
+#ifdef POLY_HAIR
+ MHWRender::MGeometry::Primitive nonInstPrim = MHWRender::MGeometry::kTriangles;
+#else
+ MHWRender::MGeometry::Primitive nonInstPrim = MHWRender::MGeometry::kLines;
+#endif
+
+ if (mHairDisplayMode == shaveHairShape::kHairDisplayNone)
+ {
+ // Disable all render items.
+ //
+ disableRenderItem(list, kInstanceWireItemName, MHWRender::MGeometry::kLines, MHWRender::MGeometry::kWireframe);
+ disableRenderItem(list, kInstanceWireSelectedItemName, MHWRender::MGeometry::kLines, MHWRender::MGeometry::kWireframe);
+ disableRenderItem(list, kHairWireItemName, nonInstPrim, MHWRender::MGeometry::kWireframe);
+ disableRenderItem(list, kHairWireSelectedItemName, nonInstPrim, MHWRender::MGeometry::kWireframe/*::kAll*/);
+
+ disableRenderItem(
+ list,
+ kInstanceShadedItemName,
+ MHWRender::MGeometry::kTriangles,
+ (MHWRender::MGeometry::DrawMode) (MHWRender::MGeometry::kShaded|MHWRender::MGeometry::kTextured)
+ );
+
+ disableRenderItem(
+ list,
+ kHairShadedItemName,
+ nonInstPrim,
+ (MHWRender::MGeometry::DrawMode) (MHWRender::MGeometry::kShaded|MHWRender::MGeometry::kTextured)
+ );
+
+ disableRenderItem(
+ list,
+ kHairShadedSelectedItemName,
+ nonInstPrim,
+ (MHWRender::MGeometry::DrawMode) (MHWRender::MGeometry::kShaded|MHWRender::MGeometry::kTextured)
+ );
+ }
+ else if (mHairDisplayMode == shaveHairShape::kHairDisplayHair)
+ {
+ // disable instances
+ disableRenderItem(
+ list,
+ kInstanceWireItemName,
+ MHWRender::MGeometry::kLines,
+ MHWRender::MGeometry::kWireframe
+ );
+
+ disableRenderItem(
+ list,
+ kInstanceWireSelectedItemName,
+ MHWRender::MGeometry::kLines,
+ MHWRender::MGeometry::kWireframe
+ );
+
+ disableRenderItem(
+ list,
+ kInstanceShadedItemName,
+ MHWRender::MGeometry::kTriangles,
+ (MHWRender::MGeometry::DrawMode) (MHWRender::MGeometry::kShaded|MHWRender::MGeometry::kTextured)
+ );
+
+ ///////////// wirewrame not selected /////////
+ //
+ int index ;
+ // add wire frame item if it's not there
+ MHWRender::MRenderItem* wireItem = NULL;
+ index = list.indexOf(kHairWireItemName, nonInstPrim, MHWRender::MGeometry::kWireframe);
+
+ if (index < 0)
+ {
+ wireItem = MHWRender::MRenderItem::Create
+ (kHairWireItemName,
+ nonInstPrim,
+ MHWRender::MGeometry::kWireframe,
+ false);
+
+ //wireItem->castsShadows(true);
+
+ MHWRender::MShaderInstance* shader = shaderMgr->getEffectsFileShader("shaveHair.cgfx",
+ "StrandLines"/*,
+ 0,0,true,
+ debugShader ? shavePreDrawCallback : NULL,
+ debugShader ? shavePostDrawCallback : NULL*/);
+ if (shader)
+ {
+ list.append(wireItem);
+
+ static const float theColor[] = {0.0f, 0.01f, 0.27f, 1.0f};
+ shader->setParameter("gUseColor", true);
+ shader->setParameter("gColor", theColor);
+
+ // assign shader
+ wireItem->setShader(shader);
+
+ // sample debug code
+ if (debugShader)
+ {
+ MStringArray params;
+ shader->parameterList(params);
+ unsigned int numParams = params.length();
+ printf("DEBUGGING SHADER, BEGIN PARAM LIST OF LENGTH %d\n", numParams);
+ for (unsigned int i=0; i<numParams; i++)
+ {
+ printf("ParamName='%s', ParamType=", params[i].asChar());
+ switch (shader->parameterType(params[i]))
+ {
+ case MHWRender::MShaderInstance::kInvalid:
+ printf("'Invalid', ");
+ break;
+ case MHWRender::MShaderInstance::kBoolean:
+ printf("'Boolean', ");
+ break;
+ case MHWRender::MShaderInstance::kInteger:
+ printf("'Integer', ");
+ break;
+ case MHWRender::MShaderInstance::kFloat:
+ printf("'Float', ");
+ break;
+ case MHWRender::MShaderInstance::kFloat2:
+ printf("'Float2', ");
+ break;
+ case MHWRender::MShaderInstance::kFloat3:
+ printf("'Float3', ");
+ break;
+ case MHWRender::MShaderInstance::kFloat4:
+ printf("'Float4', ");
+ break;
+ case MHWRender::MShaderInstance::kFloat4x4Row:
+ printf("'Float4x4Row', ");
+ break;
+ case MHWRender::MShaderInstance::kFloat4x4Col:
+ printf("'Float4x4Col', ");
+ break;
+ case MHWRender::MShaderInstance::kTexture1:
+ printf("'1D Texture', ");
+ break;
+ case MHWRender::MShaderInstance::kTexture2:
+ printf("'2D Texture', ");
+ break;
+ case MHWRender::MShaderInstance::kTexture3:
+ printf("'3D Texture', ");
+ break;
+ case MHWRender::MShaderInstance::kTextureCube:
+ printf("'Cube Texture', ");
+ break;
+ case MHWRender::MShaderInstance::kSampler:
+ printf("'Sampler', ");
+ break;
+ default:
+ printf("'Unknown', ");
+ break;
+ }
+ printf("IsArrayParameter='%s'\n", shader->isArrayParameter(params[i]) ? "YES" : "NO");
+ }
+ printf("END PARAM LIST\n");
+ fflush(stdout);
+ }
+ }
+ else //let's try to get debug info
+ {
+#if 0
+ //////////////////////////////////////////////////////
+ MString fileName = cgfxFindFile("shaveHair.cgfx",false);
+
+ if(fileName.asChar() != NULL && strcmp(fileName.asChar(), ""))
+ {
+ // Compile and create the effect.
+ MStringArray fileOptions;
+ cgfxGetFxIncludePath( fileName, fileOptions );
+ const char *opts[_CGFX_PLUGIN_MAX_COMPILER_ARGS_];
+ unsigned int numOpts = fileOptions.length();
+ if (numOpts)
+ {
+ numOpts = (numOpts > _CGFX_PLUGIN_MAX_COMPILER_ARGS_) ? _CGFX_PLUGIN_MAX_COMPILER_ARGS_ : numOpts;
+ for (unsigned int i=0; i<numOpts; i++)
+ opts[i] = fileOptions[i].asChar();
+ opts[numOpts] = NULL;
+ }
+ CGeffect cgEffect = cgCreateEffectFromFile(sCgContext, fileName.asChar(), opts);
+
+ if (cgEffect)
+ {
+ }
+ }
+
+ //////////////////////////////////////////////////////
+#endif
+ }
+ }
+ else
+ {
+ wireItem = list.itemAt(index);
+ }
+ ///////////// wirewrame selected /////////
+ //
+ MHWRender::MRenderItem* selectItem = NULL;
+ index = list.indexOf(kHairWireSelectedItemName, nonInstPrim, MHWRender::MGeometry::kWireframe/*::kAll*/);
+ if (index < 0)
+ {
+ selectItem = MHWRender::MRenderItem::Create
+ (kHairWireSelectedItemName,
+ nonInstPrim,
+ MHWRender::MGeometry::kWireframe/*::kAll*/,
+ true);
+
+ //selectItem->castsShadows(true);
+
+ MHWRender::MShaderInstance* shader = shaderMgr->getEffectsFileShader("shaveHair.cgfx",
+ "StrandLines" /*,
+ 0,0,true,
+ debugShader ? shavePreDrawCallback : NULL,
+ debugShader ? shavePostDrawCallback : NULL*/ );
+
+ if (shader)
+ {
+ list.append(selectItem);
+
+ static const float selColor[] = {0.0f, 0.6f, 0.32f, 1.0f};
+ shader->setParameter("gUseColor", true);
+ shader->setParameter("gColor", selColor);
+
+ //shader->setIsTransparent(true);//crap, why it does not change anything?
+
+ selectItem->setShader(shader);
+
+ ///////////////////
+ //printf("transparent %s\n", shader->isTransparent()?"yes":"no");fflush(stdout);
+ ///////////////////
+ }
+ }
+ else
+ {
+ selectItem = list.itemAt(index);
+ }
+
+ // Update selection item, disable by default
+ bool brushDown = shave->getBrushDown();
+ selectItem->enable(false && !brushDown /*&& !hideHairGlob*/);
+ wireItem->enable(true && !brushDown /*&& !hideHairGlob*/);
+ {
+ MStatus status;
+ MSelectionList selectedList;
+ status = MGlobal::getActiveSelectionList(selectedList);
+ if (status)
+ {
+ MDagPath pathCopy = path;
+ do
+ {
+ if (selectedList.hasItem(pathCopy))
+ {
+ selectItem->enable(true && !brushDown/* && !hideHairGlob*/);
+ wireItem->enable(false && !brushDown /*&& !hideHairGlob*/);
+ break;
+ }
+ status = pathCopy.pop();
+ } while(status);
+ }
+ }
+
+ ///////////// solid not selected /////////
+ //
+ MHWRender::MShaderInstance* shader = NULL;
+ MHWRender::MRenderItem* shadedItem = NULL;
+ index = list.indexOf(
+ kHairShadedItemName,
+ nonInstPrim,
+ (MHWRender::MGeometry::DrawMode) (MHWRender::MGeometry::kShaded|MHWRender::MGeometry::kTextured));
+ if (index < 0)
+ {
+ shadedItem = MHWRender::MRenderItem::Create
+ (kHairShadedItemName,
+ nonInstPrim,
+ (MHWRender::MGeometry::DrawMode) (MHWRender::MGeometry::kShaded|MHWRender::MGeometry::kTextured),
+ false);
+ /*MHWRender::MShaderInstance* */ shader = shaderMgr->getEffectsFileShader("shaveHair.cgfx",
+ "StrandLines" /*,
+ 0,0,true,
+ debugShader ? shavePreDrawCallback : NULL,
+ debugShader ? shavePostDrawCallback : NULL*/);
+
+ //shadedItem->castsShadows(true);
+
+ if (shader)
+ {
+ list.append(shadedItem);
+
+ // assign shader
+ shader->setParameter("gUseColor", false);
+ shader->setParameter("gDimmed", true);
+
+ shadedItem->setShader(shader);
+ }
+ else
+ MGlobal::displayError("Can't load 'shaveHair.cgfx' shader");
+ }
+ else
+ {
+ shadedItem = list.itemAt(index);
+ shader = shadedItem->getShader();
+ }
+
+ if(shader)
+ {
+ shader->setParameter("gSpecular", mGloss);
+ shader->setParameter("gSpecularAmt", mSpecular);
+
+ float tint[3];
+ mSpecularTint.get(tint);
+ shader->setParameter("gSpecularTint", tint);
+
+ mSpecularTint2.get(tint);
+ shader->setParameter("gSpecularTint2", tint);
+ }
+
+
+ ///////////// solid selected /////////
+ //
+ MHWRender::MShaderInstance* shader2 = NULL;
+ MHWRender::MRenderItem* shadedItemSel = NULL;
+ index = list.indexOf(
+ kHairShadedSelectedItemName,
+ nonInstPrim,
+ (MHWRender::MGeometry::DrawMode) (MHWRender::MGeometry::kShaded|MHWRender::MGeometry::kTextured));
+ if (index < 0)
+ {
+// shadedItemSel = MHWRender::MRenderItem::Create
+// (kHairShadedSelectedItemName,
+// MHWRender::MGeometry::kLines,
+// MHWRender::MGeometry::kShaded, /*false*/ true);
+
+//#if MAYA_API_VERSION >= 201500
+// shadedItemSel = MHWRender::MRenderItem::Create
+// (kHairShadedSelectedItemName,
+// MHWRender::MRenderItem::MaterialSceneItem,
+// MHWRender::MGeometry::kLines);
+// shadedItemSel->setDrawMode(MHWRender::MGeometry::kShaded);
+//#else
+// shadedItemSel = MHWRender::MRenderItem::Create
+// (kHairShadedSelectedItemName,
+// MHWRender::MGeometry::kLines,
+// MHWRender::MGeometry::kShaded, /*false*/ true);
+//#endif
+ shadedItemSel = MHWRender::MRenderItem::Create
+ (kHairShadedSelectedItemName,
+ nonInstPrim,
+ (MHWRender::MGeometry::DrawMode) (MHWRender::MGeometry::kShaded|MHWRender::MGeometry::kTextured),
+ false);
+
+ //shadedItemSel->castsShadows(true);
+
+ /*MHWRender::MShaderInstance* */ shader2 = shaderMgr->getEffectsFileShader("shaveHair.cgfx",
+ "StrandLines"/*,
+ 0,0,true,
+ debugShader ? shavePreDrawCallback : NULL,
+ debugShader ? shavePostDrawCallback : NULL*/);
+
+ if (shader2)
+ {
+ list.append(shadedItemSel);
+
+ // assign shader
+ shader2->setParameter("gUseColor", false);
+ shader2->setParameter("gDimmed", false);
+ shader2->setParameter("gSpecular", mGloss);
+ shader2->setParameter("gSpecularAmt", mSpecular);
+
+ float tint[3];
+ mSpecularTint.get(tint);
+ shader2->setParameter("gSpecularTint", tint);
+
+ mSpecularTint2.get(tint);
+ shader2->setParameter("gSpecularTint2", tint);
+
+ shadedItemSel->setShader(shader2);
+
+ // once assigned, no need to hold on to shader instance
+ //shaderMgr->releaseShader(shader);
+ }
+ else
+ MGlobal::displayError("Can't load 'shaveHair.cgfx' shader");
+
+
+ /*
+ //let's try stock shader - its ok
+ MHWRender::MShaderInstance* shader = shaderMgr->getStockShader(
+ MHWRender::MShaderManager::k3dSolidShader, NULL, NULL);
+ if (shader)
+ {
+ // assign shader
+ list.append(shadedItemSel);
+ shadedItemSel->setShader(shader);
+
+ // once assigned, no need to hold on to shader instance
+ shaderMgr->releaseShader(shader);
+ }
+ */
+
+ }
+ else
+ {
+ shadedItemSel = list.itemAt(index);
+ shader2 = shadedItemSel->getShader();
+ }
+ if(shader2)
+ {
+ shader2->setParameter("gSpecular", mGloss);
+ shader2->setParameter("gSpecularAmt", mSpecular);
+
+ float tint[3];
+ mSpecularTint.get(tint);
+ shader2->setParameter("gSpecularTint", tint);
+
+ mSpecularTint2.get(tint);
+ shader2->setParameter("gSpecularTint2", tint);
+ }
+
+ // Update selection item, disable by default
+ shadedItemSel->enable(false && !brushDown /*&& !hideHairGlob*/);
+ shadedItem->enable(true && !brushDown /*&& !hideHairGlob*/);
+ {
+ MStatus status;
+ MSelectionList selectedList;
+ status = MGlobal::getActiveSelectionList(selectedList);
+ if (status)
+ {
+ MDagPath pathCopy = path;
+ do
+ {
+ if (selectedList.hasItem(pathCopy))
+ {
+ shadedItemSel->enable(true && !brushDown /*&& !hideHairGlob*/);
+ shadedItem->enable(false && !brushDown/* && !hideHairGlob*/);
+ break;
+ }
+ status = pathCopy.pop();
+ } while(status);
+ }
+ }
+
+ if (mNumHairsToDraw == 0)
+ {
+ shadedItemSel->enable(false);
+ shadedItem->enable(false);
+ selectItem->enable(false);
+ wireItem->enable(false);
+ }
+ else if(!doFallbackGlob)
+ {
+ shadedItemSel->enable(true);
+ shadedItem->enable(false);
+ }
+ }
+ else if(mHairDisplayMode == shaveHairShape::kHairDisplayGeom && glisntGlob /*false*/)
+ {
+ // disable regular hair items
+ disableRenderItem(list, kHairWireItemName, nonInstPrim, MHWRender::MGeometry::kWireframe);
+ disableRenderItem(list, kHairWireSelectedItemName, nonInstPrim, MHWRender::MGeometry::kWireframe/*::kAll*/);
+
+ disableRenderItem(
+ list,
+ kHairShadedItemName,
+ nonInstPrim,
+ (MHWRender::MGeometry::DrawMode) (MHWRender::MGeometry::kShaded|MHWRender::MGeometry::kTextured)
+ );
+
+ disableRenderItem(
+ list,
+ kHairShadedSelectedItemName,
+ nonInstPrim,
+ (MHWRender::MGeometry::DrawMode) (MHWRender::MGeometry::kShaded|MHWRender::MGeometry::kTextured)
+ );
+
+ ///////////// wirewrame not selected /////////
+ //
+ MHWRender::MRenderItem* wireItem = NULL;
+ {
+ int index = list.indexOf(
+ kInstanceWireItemName,
+ MHWRender::MGeometry::kLines,
+ MHWRender::MGeometry::kWireframe);
+
+ if (index < 0)
+ {
+ wireItem = MHWRender::MRenderItem::Create
+ (kInstanceWireItemName,
+ MHWRender::MGeometry::kLines,
+ MHWRender::MGeometry::kWireframe,
+ false);
+
+ MHWRender::MShaderInstance* shader = shaderMgr->getEffectsFileShader("shaveHair.cgfx","InstanceWire"/*,
+ 0,0,true,
+ debugShader ? shavePreDrawCallback : NULL,
+ debugShader ? shavePostDrawCallback : NULL*/);
+
+ //wireItem->castsShadows(true);
+
+ if (shader)
+ {
+ list.append(wireItem);
+
+ static const float theColor[] = {0.0f, 0.01f, 0.27f, 1.0f};
+ shader->setParameter("gColor", theColor);
+
+
+ // assign shader
+ wireItem->setShader(shader);
+
+ // sample debug code
+ if (debugShader)
+ {
+ MStringArray params;
+ shader->parameterList(params);
+ unsigned int numParams = params.length();
+ printf("DEBUGGING SHADER, BEGIN PARAM LIST OF LENGTH %d\n", numParams);
+ for (unsigned int i=0; i<numParams; i++)
+ {
+ printf("ParamName='%s', ParamType=", params[i].asChar());
+ switch (shader->parameterType(params[i]))
+ {
+ case MHWRender::MShaderInstance::kInvalid:
+ printf("'Invalid', ");
+ break;
+ case MHWRender::MShaderInstance::kBoolean:
+ printf("'Boolean', ");
+ break;
+ case MHWRender::MShaderInstance::kInteger:
+ printf("'Integer', ");
+ break;
+ case MHWRender::MShaderInstance::kFloat:
+ printf("'Float', ");
+ break;
+ case MHWRender::MShaderInstance::kFloat2:
+ printf("'Float2', ");
+ break;
+ case MHWRender::MShaderInstance::kFloat3:
+ printf("'Float3', ");
+ break;
+ case MHWRender::MShaderInstance::kFloat4:
+ printf("'Float4', ");
+ break;
+ case MHWRender::MShaderInstance::kFloat4x4Row:
+ printf("'Float4x4Row', ");
+ break;
+ case MHWRender::MShaderInstance::kFloat4x4Col:
+ printf("'Float4x4Col', ");
+ break;
+ case MHWRender::MShaderInstance::kTexture1:
+ printf("'1D Texture', ");
+ break;
+ case MHWRender::MShaderInstance::kTexture2:
+ printf("'2D Texture', ");
+ break;
+ case MHWRender::MShaderInstance::kTexture3:
+ printf("'3D Texture', ");
+ break;
+ case MHWRender::MShaderInstance::kTextureCube:
+ printf("'Cube Texture', ");
+ break;
+ case MHWRender::MShaderInstance::kSampler:
+ printf("'Sampler', ");
+ break;
+ default:
+ printf("'Unknown', ");
+ break;
+ }
+ printf("IsArrayParameter='%s'\n", shader->isArrayParameter(params[i]) ? "YES" : "NO");
+ }
+ printf("END PARAM LIST\n");
+ fflush(stdout);
+ }
+ }
+ }
+ else
+ {
+ wireItem = list.itemAt(index);
+ }
+ }
+ ///////////// wirewrame selected /////////
+ //
+ MHWRender::MRenderItem* wireItemSel = NULL;
+ {
+ int index = list.indexOf(
+ kInstanceWireSelectedItemName,
+ MHWRender::MGeometry::kLines,
+ MHWRender::MGeometry::kWireframe);
+
+ if (index < 0)
+ {
+ wireItemSel = MHWRender::MRenderItem::Create
+ (kInstanceWireSelectedItemName,
+ MHWRender::MGeometry::kLines,
+ MHWRender::MGeometry::kWireframe,
+ false);
+
+ MHWRender::MShaderInstance* shader = shaderMgr->getEffectsFileShader("shaveHair.cgfx","InstanceWire"/*, 0,0,true,
+ debugShader ? shavePreDrawCallback : NULL,
+ debugShader ? shavePostDrawCallback : NULL*/);
+
+ //wireItemSel->castsShadows(true);
+
+ if (shader)
+ {
+ list.append(wireItemSel);
+
+ static const float selColor[] = {0.0f, 0.6f, 0.32f, 1.0f};
+ shader->setParameter("gColor", selColor);
+
+ // assign shader
+ wireItemSel->setShader(shader);
+ }
+ }
+ else
+ {
+ wireItemSel = list.itemAt(index);
+ }
+ }
+
+
+ // Update selection item, disable by default
+ bool brushDown = shave->getBrushDown();
+ wireItemSel->enable(false && !brushDown /*&& !hideHairGlob*/);
+ wireItem->enable(true && !brushDown /*&& !hideHairGlob*/);
+ {
+ MStatus status;
+ MSelectionList selectedList;
+ status = MGlobal::getActiveSelectionList(selectedList);
+ if (status)
+ {
+ MDagPath pathCopy = path;
+ do
+ {
+ if (selectedList.hasItem(pathCopy))
+ {
+ wireItemSel->enable(true && !brushDown /*&& !hideHairGlob*/);
+ wireItem->enable(false && !brushDown /*&& !hideHairGlob*/);
+ break;
+ }
+ status = pathCopy.pop();
+ } while(status);
+ }
+ }
+
+ MHWRender::MRenderItem* solidItem = NULL;
+ MHWRender::MShaderInstance* shader = NULL;
+ {
+ int index = list.indexOf(
+ kInstanceShadedItemName,
+ MHWRender::MGeometry::kTriangles,
+ (MHWRender::MGeometry::DrawMode) (MHWRender::MGeometry::kShaded|MHWRender::MGeometry::kTextured));
+
+ if (index < 0)
+ {
+ solidItem = MHWRender::MRenderItem::Create
+ (kInstanceShadedItemName,
+ MHWRender::MGeometry::kTriangles,
+ (MHWRender::MGeometry::DrawMode) (MHWRender::MGeometry::kShaded|MHWRender::MGeometry::kTextured),
+ false);
+
+ shader = shaderMgr->getEffectsFileShader("shaveHair.cgfx","InstanceSolid" /*, 0,0,true,
+ debugShader ? shavePreDrawCallback : NULL,
+ debugShader ? shavePostDrawCallback : NULL*/);
+
+ //solidItem->castsShadows(true);
+
+ if (shader)
+ {
+ list.append(solidItem);
+ solidItem->setShader(shader);
+ }
+ }
+ else
+ {
+ solidItem = list.itemAt(index);
+ shader = solidItem->getShader();
+ }
+ if(shader)
+ {
+ static const float theColor[] = {0.0f, 0.01f, 0.27f, 1.0f};
+ shader->setParameter("gColor", theColor);
+
+ if (mInstanceCache->diffuse != 0)
+ {
+ shader->setParameter("gUseTexture", true);
+ if(!instex)
+ {
+ MHWRender::MTextureDescription desc;
+ {
+ desc.setToDefault2DTexture();
+ desc.fWidth = mInstanceCache->eTexW;
+ desc.fHeight = mInstanceCache->eTexH;
+ desc.fDepth = 1;
+ desc.fBytesPerRow = 4*mInstanceCache->eTexW;
+ desc.fBytesPerSlice = 4*mInstanceCache->eTexW*mInstanceCache->eTexH;
+ desc.fMipmaps = 0;
+ desc.fArraySlices = 0;
+ desc.fFormat = MHWRender::kR8G8B8A8_UNORM;
+ desc.fTextureType = MHWRender::kImage2D;
+ }
+
+ MString texName("Diffuse");
+ instex = textureMgr->acquireTexture(texName, desc, mInstanceCache->img.pixels());
+ }
+
+ MHWRender::MTextureAssignment tas;
+ tas.texture = instex;
+ shader->setParameter("gTexture",tas);
+ }
+ else
+ {
+ shader->setParameter("gUseTexture", false);
+ }
+ }
+ }
+ solidItem->enable(true);
+
+ if (mNumHairsToDraw == 0)
+ {
+ //solidItemSel->enable(false);
+ solidItem->enable(false);
+ wireItemSel->enable(false);
+ wireItem->enable(false);
+ }
+
+ if (!shave->getInstancingStatus() /*|| hideHairGlob*/)
+ {
+ solidItem->enable(false);
+ wireItemSel->enable(false);
+ wireItem->enable(false);
+ }
+
+ }
+ else if (!glisntGlob)
+ {
+ // disable instances
+ disableRenderItem(list, kInstanceWireItemName, MHWRender::MGeometry::kLines, MHWRender::MGeometry::kWireframe);
+ disableRenderItem(list, kInstanceWireSelectedItemName, MHWRender::MGeometry::kLines, MHWRender::MGeometry::kWireframe);
+
+ disableRenderItem(
+ list,
+ kInstanceShadedItemName,
+ MHWRender::MGeometry::kTriangles,
+ (MHWRender::MGeometry::DrawMode) (MHWRender::MGeometry::kShaded|MHWRender::MGeometry::kTextured)
+ );
+ }
+ //end of hair
+
+ ///////////////////////////////
+ MHWRender::DisplayStatus displayStatus = MHWRender::MGeometryUtilities::displayStatus(path);
+ bool componentSelectionMode = (displayStatus == MHWRender::kHilite );
+
+ MString selectType;
+ MGlobal::executeCommand(
+ "optionVar -q shaveBrushSelectMode", selectType
+ );
+
+ mSelectionData.mShaveSelectType = selectType;
+
+ ///// guides display
+ MHWRender::MRenderItem* guidesItem = NULL;
+ {
+ int index = list.indexOf(kGuidesItemName, nonInstPrim, MHWRender::MGeometry::kAll);
+
+ if (index < 0)
+ {
+ guidesItem = MHWRender::MRenderItem::Create
+ (kGuidesItemName,
+ nonInstPrim,
+ MHWRender::MGeometry::kAll,
+ false);
+ guidesItem->setCustomData(&mSelectionData);
+
+ MHWRender::MShaderInstance* shader = shaderMgr->getEffectsFileShader("shaveHair.cgfx","Guides");
+ if (shader)
+ {
+ list.append(guidesItem);
+
+ //static const float selColor[] = {0.0f, 0.6f, 0.32f, 1.0f};
+ //shader->setParameter("gColor", selColor);
+
+ // assign shader
+ guidesItem->setShader(shader);
+ }
+ }
+ else
+ {
+ guidesItem = list.itemAt(index);
+ }
+
+ bool displayGuides = shave->getDisplayGuides();
+ bool brushActive = shave->getBrushActive();
+ if (displayGuides || brushActive ||
+ (componentSelectionMode && (selectType == "root" || selectType == "tip" || selectType == "vert" || selectType == "guide" ))
+ )
+ guidesItem->enable(true);
+ else
+ guidesItem->enable(false);
+
+ {
+ MHWRender::MShaderInstance* shader = NULL;
+ shader = guidesItem->getShader();
+ //assert(shader);
+ if(shader)
+ {
+ float w = shave->getGuideThinkness();
+ if(w < 0.01f) w=0.01f;
+ shader->setParameter("gGuideWidth",w);
+ }
+ }
+ }
+ //vertices display
+ MHWRender::MRenderItem* knotsItem = NULL;
+ {
+ int index = list.indexOf(kKnotsItemName, nonInstPrim, MHWRender::MGeometry::kAll);
+
+ if (index < 0)
+ {
+ knotsItem = MHWRender::MRenderItem::Create
+ (kKnotsItemName,
+ nonInstPrim,
+ MHWRender::MGeometry::kAll,
+ false);
+ knotsItem->setCustomData(&mSelectionData);
+
+ MHWRender::MShaderInstance* shader = shaderMgr->getEffectsFileShader("shaveHair.cgfx","Knots");
+ //assert(shader);
+ if (shader)
+ {
+ list.append(knotsItem);
+
+ //static const float selColor[] = {0.0f, 0.6f, 0.32f, 1.0f};
+ //shader->setParameter("gColor", selColor);
+ knotsItem->depthPriority( MHWRender::MRenderItem::sActiveWireDepthPriority /*sDormantWireDepthPriority*/ );
+
+ // assign shader
+ knotsItem->setShader(shader);
+ }
+ }
+ else
+ {
+ knotsItem = list.itemAt(index);
+ }
+
+ bool displayGuides = shave->getDisplayGuides();
+ bool brushActive = shave->getBrushActive();
+
+ //can not access it here its a part of getDrawRequests
+ //bool componentSelectionMode = (!noActiveComponents && (dStatus == M3dView::kHilite));
+
+ if (/*displayGuides || brushActive*/
+ componentSelectionMode &&
+ (selectType == "root" || selectType == "tip" || selectType == "vert" ))
+ {
+ knotsItem->enable(true);
+ }
+ else
+ {
+ knotsItem->enable(false);
+ }
+
+ {
+ MHWRender::MShaderInstance* shader = NULL;
+ shader = knotsItem->getShader();
+
+ //assert(shader);
+ if(shader)
+ {
+ float w = shave->getGuideThinkness();
+ if(w < 0.01f) w=0.01f;
+ shader->setParameter("gGuideWidth",w);
+ }
+ }
+
+ }
+}
+
+
+
+void shaveGeometryOverride::populateGeometry(
+ const MHWRender::MGeometryRequirements& requirements,
+ const MHWRender::MRenderItemList& itemList,
+ MHWRender::MGeometry& data
+ )
+
+{
+ if (mHairDisplayMode == shaveHairShape::kHairDisplayHair)
+ {
+#ifdef POLY_HAIR
+ populateHairPolys(requirements, itemList, data);
+#else
+ populateHairLines(requirements, itemList, data);
+#endif
+ }
+ else if (mHairDisplayMode == shaveHairShape::kHairDisplayGeom)
+ {
+ populateHairInstances(requirements, itemList, data);
+ }
+#if 0
+ bool displayGuides = shave->getDisplayGuides();
+ if (/*displayGuides || mBrushIsActive*/ true)
+ {
+ populateHairGuides(
+ requirements,itemList,data
+ );
+ }
+#endif
+}
+
+void shaveGeometryOverride::populateHairInstances(
+ const MHWRender::MGeometryRequirements& requirements,
+ const MHWRender::MRenderItemList& itemList,
+ MHWRender::MGeometry& data
+)
+{
+ cacheGuidePolys();
+ cacheKnotPolys();
+
+ unsigned int guideTriangles = (unsigned int)guidePolys.size();
+ unsigned int knotTriangles = (unsigned int)knotPolys.size();
+ unsigned int instTriangles = mInstanceCache->faceCounts.length();
+ unsigned int totalTriangles = guideTriangles+ instTriangles + knotTriangles;
+
+ unsigned int totalLines = instTriangles*3;
+ unsigned int instVerts = instTriangles*3;
+ unsigned int guideVerts = guideTriangles*3;
+ unsigned int knotVerts = knotTriangles*3;
+ unsigned int totalVerts = totalTriangles*3;
+
+ if(debugShader)
+ {
+ printf("triangles: %i verts: %i\n",totalTriangles, totalVerts);
+ }
+
+ MHWRender::MVertexBuffer* positionBuffer = NULL;
+ float* positions = NULL;
+
+ MHWRender::MVertexBuffer* colorBuffer = NULL;
+ float* colors = NULL;
+
+ MHWRender::MVertexBuffer* normalBuffer = NULL;
+ float* normals = NULL;
+
+ MHWRender::MVertexBuffer* uvBuffer = NULL;
+ float* uvs = NULL;
+
+ const MHWRender::MVertexBufferDescriptorList& descList = requirements.vertexRequirements();
+
+ int numVertexReqs = descList.length();
+ MHWRender::MVertexBufferDescriptor desc;
+
+ for (int reqNum=0; reqNum<numVertexReqs; reqNum++)
+ {
+ if (!descList.getDescriptor(reqNum, desc))
+ {
+ continue;
+ }
+
+ switch (desc.semantic())
+ {
+ case MHWRender::MGeometry::kPosition:
+ {
+ positionBuffer = data.createVertexBuffer(desc);
+ if (positionBuffer)
+ positions = (float*)positionBuffer->acquire(totalVerts);
+ }
+ break;
+
+ case MHWRender::MGeometry::kColor:
+ {
+ colorBuffer = data.createVertexBuffer(desc);
+ if (colorBuffer)
+ colors = (float*)colorBuffer->acquire(totalVerts, true);
+ }
+ break;
+
+
+ //let's use texture to pass radius as uv.x
+ case MHWRender::MGeometry::kTexture:
+ {
+ uvBuffer = data.createVertexBuffer(desc);
+ if (uvBuffer)
+ uvs = (float*)uvBuffer->acquire(totalVerts, true);
+
+ }
+ break;
+
+ case MHWRender::MGeometry::kNormal:
+ {
+ normalBuffer = data.createVertexBuffer(desc);
+ if (normalBuffer)
+ normals = (float*)normalBuffer->acquire(totalVerts, true);
+ }
+ break;
+
+
+ case MHWRender::MGeometry::kTangent:
+ case MHWRender::MGeometry::kBitangent:
+ break;
+
+ default:
+ // do nothing for stuff we don't understand
+ break;
+ }
+ }
+
+ if(positions)
+ {
+ int vid = 0;
+ int pid = 0;
+ unsigned int nf = mInstanceCache->faceCounts.length();
+ for(unsigned int i = 0; i < nf; i++)
+ {
+ int fc = mInstanceCache->faceCounts[i];
+ if(fc != 3)
+ continue; //trianglular faces expected
+
+ int fs = mInstanceCache->faceStart[i];
+ int fe = mInstanceCache->faceEnd[i];
+ for(int j = fs; j < fe; j++)
+ {
+ int k = mInstanceCache->faceVerts[j];
+ const MFloatPoint& p = mInstanceCache->points[k];
+ positions[pid] = p.x;
+ positions[pid+1] = p.y;
+ positions[pid+2] = p.z;
+
+ pid += 3;
+
+
+ }
+ }
+ ////////////////////////////
+ for (unsigned int i = 0; i < guidePolys.size(); i++)
+ {
+ const GuidePoly& p = guidePolys[i];
+ for(int j=0; j<3; j++)
+ {
+ positions[pid++] = (float)p.v[j].x;
+ positions[pid++] = (float)p.v[j].y;
+ positions[pid++] = (float)p.v[j].z;
+ }
+ }
+
+ ////////////////////////////
+
+ for (unsigned int i = 0; i < knotPolys.size(); i++)
+ {
+ const KnotPoly& p = knotPolys[i];
+ for(int j=0; j<3; j++)
+ {
+ positions[pid++] = (float)p.v[j].x;
+ positions[pid++] = (float)p.v[j].y;
+ positions[pid++] = (float)p.v[j].z;
+ }
+ }
+
+ positionBuffer->commit(positions);
+ }
+
+ if (colors)
+ {
+ unsigned int nf = mInstanceCache->faceCounts.length();
+ int cid = nf*3*4;
+ //int cid = 0;
+ //for(unsigned int i = 0; i < nf; i++)
+ //{
+ // int fc = mInstanceCache->faceCounts[i];
+ // if(fc != 3)
+ // continue; //trianglular faces expected
+
+ // int fs = mInstanceCache->faceStart[i];
+ // int fe = mInstanceCache->faceEnd[i];
+ // for(int j = fs; j < fe; j++)
+ // cid += 3;
+ //}
+
+ /////////////////////////////////////////////////
+
+ for (unsigned int i = 0; i < guidePolys.size(); i++)
+ {
+ const GuidePoly& p = guidePolys[i];
+ for(int j=0; j<3; j++)
+ {
+ colors[cid] = p.active?1.0f:0.0f;
+ colors[cid+1] = 0.0f;
+ colors[cid+2] = 0.0f;
+ colors[cid+3] = 0.0f;
+ cid+=4;
+ }
+ }
+
+ ////////////////////////////////////////////////
+
+ for (unsigned int i = 0; i < knotPolys.size(); i++)
+ {
+ const KnotPoly& p = knotPolys[i];
+ for(int j=0; j<3; j++)
+ {
+ colors[cid] = p.active?1.0f:0.0f;
+ colors[cid+1] = 0.0f;
+ colors[cid+2] = 0.0f;
+ colors[cid+3] = 0.0f;
+ cid+=4;
+ }
+ }
+
+ colorBuffer->commit(colors);
+ }
+
+ if(normals)
+ {
+ int nid = 0;
+ unsigned int nf = mInstanceCache->faceCounts.length();
+ for(unsigned int i = 0; i < nf; i++)
+ {
+ int fc = mInstanceCache->faceCounts[i];
+ if(fc != 3)
+ continue; //trianglular faces expected
+
+ int fs = mInstanceCache->faceStart[i];
+ int fe = mInstanceCache->faceEnd[i];
+ for(int j = fs; j < fe; j++)
+ {
+ int k = mInstanceCache->faceVerts[j];
+ //something is weird with this, normals are inverted...
+ const MFloatPoint& n = mInstanceCache->normals[k];
+ normals[nid] = n.x;
+ normals[nid+1] = n.y;
+ normals[nid+2] = n.z;
+ nid += 3;
+ }
+ }
+ normalBuffer->commit(normals);
+ }
+
+ if(uvs)
+ {
+
+ int uid = 0;
+ int oo = 0;
+ unsigned int nf =mInstanceCache->faceCounts.length();
+ for(unsigned int i = 0; i < nf; i++)
+ {
+ int fc = mInstanceCache->faceCounts[i];
+ if(fc != 3)
+ continue; //trianglular faces expected
+
+ int fs = mInstanceCache->faceStart[i];
+ int fe = mInstanceCache->faceEnd[i];
+ for(int j = fs; j < fe; j++)
+ {
+ int k = mInstanceCache->faceVerts[j];
+ const MFloatPoint& t = mInstanceCache->uvs[oo /*k*/];
+ uvs[uid] = t.x;
+ uvs[uid+1] = t.y;
+ uid += 2;
+ oo++;
+ }
+ }
+
+ uvBuffer->commit(uvs);
+ }
+
+ // index data
+ int numItems = itemList.length();
+ for (int i=0; i<numItems; i++)
+ {
+ const MHWRender::MRenderItem* item = itemList.itemAt(i);
+ if (!item) continue;
+
+ // Enable to debug vertex buffers that are associated with each render item.
+ // Can also use to generate indexing better, but we don't need that here.
+ // Also debugs custom data on the render item.
+ if (debugShader)
+ {
+ const MHWRender::MVertexBufferDescriptorList& itemBuffers =
+ item->requiredVertexBuffers();
+ int numBufs = itemBuffers.length();
+ MHWRender::MVertexBufferDescriptor desc;
+ for (int bufNum=0; bufNum<numBufs; bufNum++)
+ {
+ if (itemBuffers.getDescriptor(bufNum, desc))
+ {
+ printf("Buffer Required for Item #%d ('%s'):\n", i, item->name().asChar());
+ printf("\tBufferName: %s\n", desc.name().asChar());
+ printf("\tDataType: %s (dimension %d)\n", MHWRender::MGeometry::dataTypeString(desc.dataType()).asChar(), desc.dimension());
+ printf("\tSemantic: %s\n", MHWRender::MGeometry::semanticString(desc.semantic()).asChar());
+ printf("\n");
+ }
+ }
+ fflush(stdout);
+ }
+ //same indexing for all
+ if (item->name() == kInstanceWireItemName || item->name() == kInstanceWireSelectedItemName)
+ {
+ MHWRender::MIndexBuffer* indexBuffer = NULL;
+ if (!indexBuffer)
+ {
+ indexBuffer = data.createIndexBuffer(MHWRender::MGeometry::kUnsignedInt32);
+ if (indexBuffer)
+ {
+ unsigned int* buffer = (unsigned int*)indexBuffer->acquire(totalLines*2);
+ if (buffer)
+ {
+ int idx = 0;
+ int vid = 0;
+ unsigned int nf = mInstanceCache->faceCounts.length();
+ for(unsigned int i = 0; i < nf; i++)
+ {
+ int fc = mInstanceCache->faceCounts[i];
+ if(fc != 3)
+ continue; //trianglular faces expected
+
+ //buffer[idx] = idx;
+ //buffer[idx+1] = idx+1;
+ //buffer[idx+2] = idx+2;
+
+ ////printf("f %i [%i %i %i]\n",i, idx, idx+1, idx+2);fflush(stdout);
+
+ //idx += 3;
+
+ int fs = mInstanceCache->faceStart[i];
+ int fe = mInstanceCache->faceEnd[i];
+ int k=0;
+ for(int j = fs; j < fe; j++)
+ {
+ buffer[idx] = vid;
+ unsigned int vid2 = (k < 2) ? vid+1 : vid-2;
+ buffer[idx+1] = vid2;
+ idx += 2;
+ vid++;
+ k++;
+ }
+ }
+ indexBuffer->commit(buffer);
+ }
+ }
+ }
+
+ // Associate same index buffer with either render item
+ if (indexBuffer)
+ {
+ item->associateWithIndexBuffer(indexBuffer);
+ }
+ }
+
+ if (item->name() == kInstanceShadedItemName )
+ {
+ MHWRender::MIndexBuffer* indexBuffer = NULL;
+ if (!indexBuffer)
+ {
+ indexBuffer = data.createIndexBuffer(MHWRender::MGeometry::kUnsignedInt32);
+ if (indexBuffer)
+ {
+ unsigned int* buffer = (unsigned int*)indexBuffer->acquire(instTriangles*3);
+ if (buffer)
+ {
+ int idx = 0;
+ int vid = 0;
+ unsigned int nf = mInstanceCache->faceCounts.length();
+ for(unsigned int i = 0; i < nf; i++)
+ {
+ int fc = mInstanceCache->faceCounts[i];
+ if(fc != 3)
+ continue; //trianglular faces expected
+
+ buffer[idx] = idx;
+ buffer[idx+1] = idx+1;
+ buffer[idx+2] = idx+2;
+
+ //printf("f %i [%i %i %i]\n",i, idx, idx+1, idx+2);fflush(stdout);
+
+ idx += 3;
+
+ //int fs = mInstanceCache->faceStart[i];
+ //int fe = mInstanceCache->faceEnd[i];
+ //int k=0;
+ //for(int j = fs; j < fe; j++)
+ //{
+ // buffer[idx] = vid;
+ // unsigned int vid2 = (k < 2) ? vid+1 : vid-2;
+ // buffer[idx+1] = vid2;
+ // idx += 2;
+ // vid++;
+ // k++;
+ //}
+ }
+ indexBuffer->commit(buffer);
+ }
+ }
+ }
+
+ // Associate same index buffer with either render item
+ if (indexBuffer)
+ {
+ item->associateWithIndexBuffer(indexBuffer);
+ }
+ }
+
+ ////////////////////////////////////////
+ //// guide indexing
+ if (item->name() == kGuidesItemName)
+ {
+ MHWRender::MIndexBuffer* indexBuffer2 = NULL;
+ // Wireframe index buffer is same for both wireframe and selected render item
+ // so we only compute and allocate it once, but reuse it for both render items
+ if (!indexBuffer2)
+ {
+ indexBuffer2 = data.createIndexBuffer(MHWRender::MGeometry::kUnsignedInt32);
+ //indexBuffer2 = new MHWRender::MIndexBuffer(MHWRender::MGeometry::kUnsignedInt32);
+ if (indexBuffer2)
+ {
+ unsigned int* buffer = (unsigned int*)indexBuffer2->acquire(guideVerts);
+ if (buffer)
+ {
+ for (unsigned int i = 0; i < guideVerts; i++)
+ {
+ //simple indexing
+ buffer[i] = i+instVerts;
+ }
+
+ indexBuffer2->commit(buffer);
+ }
+ }
+ }
+ if(indexBuffer2)
+ item->associateWithIndexBuffer(indexBuffer2);
+ }
+
+ //////////////////////////////
+ // knot indexing
+ if (item->name() == kKnotsItemName)
+ {
+ MHWRender::MIndexBuffer* indexBuffer3 = NULL;
+ if (!indexBuffer3)
+ {
+ indexBuffer3 = data.createIndexBuffer(MHWRender::MGeometry::kUnsignedInt32);
+ if (indexBuffer3)
+ {
+ unsigned int* buffer = (unsigned int*)indexBuffer3->acquire(knotVerts);
+ if (buffer)
+ {
+ for (unsigned int i = 0; i < knotVerts; i++)
+ {
+ //simple indexing
+ buffer[i] = i+instVerts+guideVerts;
+ }
+ indexBuffer3->commit(buffer);
+ }
+ }
+ }
+ if(indexBuffer3)
+ item->associateWithIndexBuffer(indexBuffer3);
+ }
+ }
+
+}
+
+void shaveGeometryOverride::populateHairLines(
+ const MHWRender::MGeometryRequirements& requirements,
+ const MHWRender::MRenderItemList& itemList,
+ MHWRender::MGeometry& data
+)
+{
+ //
+ // Determine the number of hairs to be drawn.
+ //
+ bool doxpar = shave->getDoHairXparency();
+ bool fallback = shave->getDoFallback();
+ float ipasses = 1.0f/(float)mPasses;
+
+ if(debugShader)
+ {
+ printf("numHairsToDraw: %i\n",mNumHairsToDraw);
+ }
+
+ unsigned int numGuidesToDraw = (unsigned int)mGuideCache->size();
+ if(debugShader)
+ printf("numGuidesToDraw: %i\n",numGuidesToDraw);
+
+ //
+ // compute number of elements
+ //
+ unsigned int totalLines = 0;
+ unsigned int hairLines = 0;
+ unsigned int guideLines = 0;
+ for (unsigned int h = 0; h < mNumHairsToDraw; h++)
+ {
+ const shaveHairShape::DisplayHair& hair = mHairCache->displayHair[h];
+ for (unsigned int s = 0; s < hair.size(); s++)
+ {
+ const shaveHairShape::DisplayStrand& strand = hair[s];
+ unsigned int strandlen = strand.verts.length();
+ hairLines += (strandlen-1);
+ }
+ }
+
+#if 1
+ {
+ shaveHairShape::Guides::const_iterator iter;
+ for (iter = mGuideCache->begin(); iter != mGuideCache->end(); iter++)
+ {
+ const shaveHairShape::Guide& guide = *iter;
+
+ if (!guide.hidden)
+ guideLines += (SHAVE_VERTS_PER_GUIDE-1);
+
+ }
+ }
+#endif
+ totalLines = guideLines + hairLines;
+ unsigned int hairVerts = hairLines*2;
+ unsigned int guideVerts = guideLines*2;
+ unsigned int totalVerts = totalLines*2;
+
+
+ // vertex data
+ MHWRender::MVertexBuffer* positionBuffer = NULL;
+ float* positions = NULL;
+
+ MHWRender::MVertexBuffer* colorBuffer = NULL;
+ float* colors = NULL;
+
+ MHWRender::MVertexBuffer* uvBuffer = NULL;
+ float* uvs = NULL;
+
+ MHWRender::MVertexBuffer* tangBuffer = NULL;
+ float* tang = NULL;
+
+ MHWRender::MVertexBuffer* guidePositionBuffer = NULL;
+ float* guidepositions = NULL;
+
+ /////////////////////////////////////////////////////////////
+ //int numItems = itemList.length();
+ //for (int i=0; i<numItems; i++)
+ //{
+ // const MHWRender::MRenderItem* item = itemList.itemAt(i);
+ // if (!item) continue;
+ //
+ /////////////////////////////////////////////////////////////
+
+ const MHWRender::MVertexBufferDescriptorList& descList = requirements.vertexRequirements();
+// const MHWRender::MVertexBufferDescriptorList& descList = item->requiredVertexBuffers();
+ int numVertexReqs = descList.length();
+ MHWRender::MVertexBufferDescriptor desc;
+
+ if(debugShader)
+ {
+ printf("numVertexReqs: %i\n",numVertexReqs);
+ /*
+ const MHWRender::MVertexBufferDescriptorList& itemBuffers = item->requiredVertexBuffers();
+ int numBufs = itemBuffers.length();
+ MHWRender::MVertexBufferDescriptor desc;
+ for (int bufNum=0; bufNum<numBufs; bufNum++)
+ {
+ if (itemBuffers.getDescriptor(bufNum, desc))
+ {
+ printf("Buffer Required for Item #%d ('%s'):\n", i, item->name().asChar());
+ printf("\tBufferName: %s\n", desc.name().asChar());
+ printf("\tDataType: %s (dimension %d)\n", MHWRender::MGeometry::dataTypeString(desc.dataType()).asChar(), desc.dimension());
+ printf("\tSemantic: %s\n", MHWRender::MGeometry::semanticString(desc.semantic()).asChar());
+ printf("\n");
+ }
+ }
+ */
+ }
+
+ for (int reqNum=0; reqNum<numVertexReqs; reqNum++)
+ {
+ if (!descList.getDescriptor(reqNum, desc))
+ {
+ continue;
+ }
+
+ switch (desc.semantic())
+ {
+ case MHWRender::MGeometry::kPosition:
+ {
+ positionBuffer = data.createVertexBuffer(desc);
+ if (positionBuffer)
+ positions = (float*)positionBuffer->acquire(totalVerts, true);
+ }
+ break;
+
+ case MHWRender::MGeometry::kColor:
+ {
+ colorBuffer = data.createVertexBuffer(desc);
+ if (colorBuffer)
+ colors = (float*)colorBuffer->acquire(totalVerts, true);
+
+
+ }
+ break;
+
+ //let's use texture to pass radius as uv.x
+ case MHWRender::MGeometry::kTexture:
+ {
+ uvBuffer = data.createVertexBuffer(desc);
+ if (uvBuffer)
+ uvs = (float*)uvBuffer->acquire(totalVerts, true);
+
+ }
+ break;
+
+ //case MHWRender::MGeometry::kNormal:
+ // break;
+#if 0
+ case MHWRender::MGeometry::kNormal:
+ {
+ guidePositionBuffer = data.createVertexBuffer(desc);
+ if (guidePositionBuffer)
+ guidepositions = (float*)guidePositionBuffer->acquire(totalVerts,true);
+ }
+ break;
+#endif
+ case MHWRender::MGeometry::kTangent:
+ {
+ tangBuffer = data.createVertexBuffer(desc);
+ if (tangBuffer)
+ tang = (float*)tangBuffer->acquire(totalVerts, true);
+ }
+ break;
+ case MHWRender::MGeometry::kBitangent:
+ break;
+
+ default:
+ // do nothing for stuff we don't understand
+ break;
+ }
+ }
+ if(debugShader) fflush(stdout);
+
+ if (positions)
+ {
+ int pid = 0;
+ for (unsigned int h = 0; h < mNumHairsToDraw; h++)
+ {
+ const shaveHairShape::DisplayHair& hair = mHairCache->displayHair[h];
+ for (unsigned int s = 0; s < hair.size(); s++)
+ {
+ const shaveHairShape::DisplayStrand& strand = hair[s];
+
+ int numS = strand.verts.length()-1;
+
+ ////////////////////////
+ //printf("strand%i \n",s);
+ ////////////////////////
+
+ for (int v = 0; v < numS; v++)
+ {
+ int vv = v+1;
+ positions[pid++] = (float)strand.verts[v].x;
+ positions[pid++] = (float)strand.verts[v].y;
+ positions[pid++] = (float)strand.verts[v].z;
+
+ positions[pid++] = (float)strand.verts[vv].x;
+ positions[pid++] = (float)strand.verts[vv].y;
+ positions[pid++] = (float)strand.verts[vv].z;
+
+ ////////////////////////
+ //printf("v%i [%f %f %f] v%i [%f %f %f]\n",v,strand.verts[v].x,strand.verts[v].y,strand.verts[v].z,vv,strand.verts[vv].x,strand.verts[vv].y,strand.verts[vv].z);
+ ////////////////////////
+ }
+ }
+ }
+#if 1
+ /////////////////////////////////////////////////
+ shaveHairShape::Guides::const_iterator iter;
+ for (iter = mGuideCache->begin(); iter != mGuideCache->end(); iter++)
+ {
+ const shaveHairShape::Guide& guide = *iter;
+ if (!guide.hidden)
+ {
+ for (int v = 0; v < SHAVE_VERTS_PER_GUIDE-1; v++)
+ {
+ int vv = v+1;
+ positions[pid++] = guide.verts[v].x;
+ positions[pid++] = guide.verts[v].y;
+ positions[pid++] = guide.verts[v].z;
+
+ positions[pid++] = guide.verts[vv].x;
+ positions[pid++] = guide.verts[vv].y;
+ positions[pid++] = guide.verts[vv].z;
+
+ }
+ }
+ }
+#endif
+ positionBuffer->commit(positions);
+ }
+
+ if (colors)
+ {
+
+ int cid = 0;
+ for (unsigned int h = 0; h < mNumHairsToDraw; h++)
+ {
+ const shaveHairShape::DisplayHair& hair = mHairCache->displayHair[h];
+ for (unsigned int s = 0; s < hair.size(); s++)
+ {
+ const shaveHairShape::DisplayStrand& strand = hair[s];
+ int numS = strand.verts.length()-1;
+
+ for (int v = 0; v < numS; v++)
+ {
+ int vv = v+1;
+
+ MColor col0 = strand.colors[v];
+ MColor col1 = strand.colors[vv];
+ //we do get 1.0 in WFTYPE.alpha[] at the moment, lets fake it with tipfade
+ if(doxpar )
+ {
+ if(mDoTipFade)
+ {
+ col0.a = 1.0f - v/(float)numS;
+ col1.a = 1.0f - vv/(float)numS;
+ }
+ if(mPasses > 1)
+ {
+ col0.a *= ipasses;
+ col1.a *= ipasses;
+ }
+ if(mTransparency != 1.0f)
+ {
+ col0.a *= mTransparency;
+ col1.a *= mTransparency;
+ }
+ }
+ else
+ col1.a = col0.a = 1.0f;
+
+
+ colors[cid++] = col0.r;
+ colors[cid++] = col0.g;
+ colors[cid++] = col0.b;
+ colors[cid++] = col0.a;
+
+ colors[cid++] = col1.r;
+ colors[cid++] = col1.g;
+ colors[cid++] = col1.b;
+ colors[cid++] = col1.a;
+ }
+
+ }
+ }
+ colorBuffer->commit(colors);
+ }
+
+ if (uvs)
+ {
+ int uid = 0;
+ for (unsigned int h = 0; h < mNumHairsToDraw; h++)
+ {
+ const shaveHairShape::DisplayHair& hair = mHairCache->displayHair[h];
+ for (unsigned int s = 0; s < hair.size(); s++)
+ {
+ const shaveHairShape::DisplayStrand& strand = hair[s];
+
+ float r0, r1;
+ int numS = strand.verts.length()-1;
+ for (int v = 0; v < numS; v++)
+ {
+
+ int vv = v+1;
+ int vvv = v+2;
+ MVector dv = strand.verts[v]-strand.verts[vv];
+ float dvl = (float)dv.length();
+
+ float t1 = vv/(float)numS;
+ if(v == 0) //root
+ {
+ r0 = strand.rootrad;
+ r1 = strand.rootrad*(1.0f - t1) + strand.tiprad*t1;
+
+ }
+ else if(vv == numS) //tip
+ {
+ r0 = r1;
+ r1 = strand.tiprad;
+ }
+ else
+ {
+ r0 = r1;
+ r1 = strand.rootrad*(1.0f - t1) + strand.tiprad*t1;
+ }
+ uvs[uid++] = r0;
+ uvs[uid++] = dvl;
+
+ uvs[uid++] = r1;
+ uvs[uid++] = 0.0f;
+ }
+ }
+ }
+ uvBuffer->commit(uvs);
+ }
+
+ if (tang)
+ {
+ int pid = 0;
+ MVector tangent0;
+ MVector tangent1;
+ MVector p0;
+ MVector p1;
+ MVector p2;
+
+ for (unsigned int h = 0; h < mNumHairsToDraw; h++)
+ {
+ const shaveHairShape::DisplayHair& hair = mHairCache->displayHair[h];
+ for (unsigned int s = 0; s < hair.size(); s++)
+ {
+ const shaveHairShape::DisplayStrand& strand = hair[s];
+
+ int numS = strand.verts.length()-1;
+
+ ////////////////////////
+ //printf("strand%i \n",s);
+ ////////////////////////
+
+ for (int v = 0; v < numS; v++)
+ {
+ int vv = v+1;
+ int vvv = v+2;
+ if(v == 0) //root
+ {
+ p0.x = strand.verts[0].x;
+ p0.y = strand.verts[0].y;
+ p0.z = strand.verts[0].z;
+ p1.x = strand.verts[1].x;
+ p1.y = strand.verts[1].y;
+ p1.z = strand.verts[1].z;
+
+ tangent0 = p1 - p0;
+ tangent0.normalize();
+
+ tangent1 = tangent0;
+
+ }
+ else if(vv == numS) //tip
+ {
+ p0 = p1;
+ p1.x = strand.verts[vv].x;
+ p1.y = strand.verts[vv].y;
+ p1.z = strand.verts[vv].z;
+
+ tangent0 = tangent1;
+ tangent1 = p1 - p0;
+ tangent1.normalize();
+ }
+ else
+ {
+ p0 = p1;
+ p1.x = strand.verts[vv].x;
+ p1.y = strand.verts[vv].y;
+ p1.z = strand.verts[vv].z;
+
+ tangent0 = tangent1;
+ if(vvv < (int)strand.verts.length())
+ {
+ p2.x = strand.verts[vvv].x;
+ p2.y = strand.verts[vvv].y;
+ p2.z = strand.verts[vvv].z;
+ tangent1 = p2 - p0;
+ }
+ else
+ {
+ tangent1 = p1 - p0;
+ }
+ tangent1.normalize();
+ }
+ tang[pid++] = (float)tangent0.x;
+ tang[pid++] = (float)tangent0.y;
+ tang[pid++] = (float)tangent0.z;
+
+ tang[pid++] = (float)tangent1.x;
+ tang[pid++] = (float)tangent1.y;
+ tang[pid++] = (float)tangent1.z;
+
+ }
+ }
+ }
+ tangBuffer->commit(tang);
+ }
+
+
+ // index data
+ MHWRender::MIndexBuffer* indexBuffer = NULL;
+ MHWRender::MIndexBuffer* indexBuffer2 = NULL;
+ MHWRender::MIndexBuffer* indexBuffer3 = NULL;
+ int numItems = itemList.length();
+
+ for (int i=0; i<numItems; i++)
+ {
+ const MHWRender::MRenderItem* item = itemList.itemAt(i);
+ if (!item) continue;
+
+ // Enable to debug vertex buffers that are associated with each render item.
+ // Can also use to generate indexing better, but we don't need that here.
+ // Also debugs custom data on the render item.
+ static const bool debugStuff = false;
+ if (debugShader)
+ {
+ const MHWRender::MVertexBufferDescriptorList& itemBuffers =
+ item->requiredVertexBuffers();
+ int numBufs = itemBuffers.length();
+ MHWRender::MVertexBufferDescriptor desc;
+ for (int bufNum=0; bufNum<numBufs; bufNum++)
+ {
+ if (itemBuffers.getDescriptor(bufNum, desc))
+ {
+ printf("Buffer Required for Item #%d ('%s'):\n", i, item->name().asChar());
+ printf("\tBufferName: %s\n", desc.name().asChar());
+ printf("\tDataType: %s (dimension %d)\n", MHWRender::MGeometry::dataTypeString(desc.dataType()).asChar(), desc.dimension());
+ printf("\tSemantic: %s\n", MHWRender::MGeometry::semanticString(desc.semantic()).asChar());
+ printf("\n");
+ }
+ }
+ fflush(stdout);
+ }
+
+ //same indexing for all hair
+ if (item->name() == kHairWireItemName || item->name() == kHairWireSelectedItemName ||
+ item->name() == kHairShadedItemName || item->name() == kHairShadedSelectedItemName)
+ {
+ // Wireframe index buffer is same for both wireframe and selected render item
+ // so we only compute and allocate it once, but reuse it for both render items
+ if (!indexBuffer)
+ {
+ indexBuffer = data.createIndexBuffer(MHWRender::MGeometry::kUnsignedInt32);
+ if (indexBuffer)
+ {
+ unsigned int* buffer = (unsigned int*)indexBuffer->acquire(hairLines*2);
+ if (buffer)
+ {
+ int idx = 0;
+ for (unsigned int h = 0; h < mNumHairsToDraw; h++)
+ {
+ const shaveHairShape::DisplayHair& hair = mHairCache->displayHair[h];
+ for (unsigned int s = 0; s < hair.size(); s++)
+ {
+ const shaveHairShape::DisplayStrand& strand = hair[s];
+
+ int numS = strand.verts.length()-1;
+ for (int v = 0; v < numS; v++)
+ {
+ //simple indexing
+ buffer[idx] = idx;
+ buffer[idx+1] = idx+1;
+ idx += 2;
+ }
+ }
+ }
+ indexBuffer->commit(buffer);
+ }
+ }
+ }
+
+ // Associate same index buffer with either render item
+ if (indexBuffer)
+ {
+ item->associateWithIndexBuffer(indexBuffer);
+ }
+ }
+ //////////////////////////////////////////
+ // guide indexing
+ if (item->name() == kGuidesItemName)
+ {
+
+ // Wireframe index buffer is same for both wireframe and selected render item
+ // so we only compute and allocate it once, but reuse it for both render items
+ if (!indexBuffer2)
+ {
+ indexBuffer2 = data.createIndexBuffer(MHWRender::MGeometry::kUnsignedInt32);
+ //indexBuffer2 = new MHWRender::MIndexBuffer(MHWRender::MGeometry::kUnsignedInt32);
+ if (indexBuffer2)
+ {
+ unsigned int* buffer = (unsigned int*)indexBuffer2->acquire(guideLines*2);
+ if (buffer)
+ {
+ int idx0 = 0;
+ int idx1 = hairVerts;
+ shaveHairShape::Guides::const_iterator iter;
+ for (iter = mGuideCache->begin(); iter != mGuideCache->end(); iter++)
+ {
+ const shaveHairShape::Guide& guide = *iter;
+ if (!guide.hidden)
+ {
+ for (int v = 0; v < SHAVE_VERTS_PER_GUIDE-1; v++)
+ {
+ //simple indexing
+ buffer[idx0] = idx1;
+ buffer[idx0+1] = idx1+1;
+ idx0 += 2;
+ idx1 += 2;
+ }
+ }
+ }
+ indexBuffer2->commit(buffer);
+ //data.addIndexBuffer(indexBuffer2);
+
+ item->associateWithIndexBuffer(indexBuffer2);
+
+ }
+ }
+ }
+ }
+ //////////////////////////////
+ // guide indexing
+ if (item->name() == kKnotsItemName)
+ {
+ if (!indexBuffer3)
+ {
+ indexBuffer3 = data.createIndexBuffer(MHWRender::MGeometry::kUnsignedInt32);
+ if (indexBuffer3)
+ {
+ unsigned int* buffer = (unsigned int*)indexBuffer3->acquire(guideVerts/2);
+ if (buffer)
+ {
+ int idx0 = 0;
+ int idx1 = hairVerts;
+ shaveHairShape::Guides::const_iterator iter;
+ for (iter = mGuideCache->begin(); iter != mGuideCache->end(); iter++)
+ {
+ const shaveHairShape::Guide& guide = *iter;
+ if (!guide.hidden)
+ {
+ for (int v = 0; v < SHAVE_VERTS_PER_GUIDE-1; v++)
+ {
+ //simple indexing
+ buffer[idx0] = idx1;
+ idx0 += 1;
+ idx1 += 2;
+ }
+ }
+ }
+ indexBuffer3->commit(buffer);
+ item->associateWithIndexBuffer(indexBuffer3);
+ }
+ }
+ }
+ }
+ ///////////////////////////////
+ }
+
+ //////////////////////////////////////
+ //}
+ //////////////////////////////////////
+}
+
+///////////////// cache polys & z-sorty strands///////////////////////////////////
+
+void shaveGeometryOverride::cacheHairPolys()
+{
+ bool doxpar = shave->getDoHairXparency();
+ bool fallback = shave->getDoFallback();
+ float ipasses = 1.0f/(float)mPasses;
+
+ // far/near
+ MPoint centerPt(mHairCache->center);
+ MPoint nearPt = centerPt - mViewDir*mHairCache->radius;
+ MPoint farPt = centerPt + mViewDir*mHairCache->radius;
+
+ MPoint nearSc = nearPt*mWorldToCam;
+ MPoint farSc = farPt*mWorldToCam;
+
+ //sort to groups
+ ingroups = 0;
+ int numS = 1;
+
+ groups.resize(400);
+ for(int g = (int)groups.size()-1; g >= 0; g--)
+ {
+ groups[g].p.clear();
+ groups[g].p.reserve(300);
+ }
+
+ for (unsigned int h = 0; h < mNumHairsToDraw; h++)
+ {
+ const shaveHairShape::DisplayHair& hair = mHairCache->displayHair[h];
+ for (unsigned int s = 0; s < hair.size(); s++)
+ {
+ const shaveHairShape::DisplayStrand& strand = hair[s];
+
+ MVector tangent0;
+ MVector tangent1;
+ MVector p0;
+ MVector p1;
+ MVector p2;
+ float r0;
+ float r1;
+ numS = strand.verts.length()-1;
+ float inumS = 1.0f/(float)numS;
+
+ for (int v = 0; v < numS; v++)
+ {
+ int vv = v+1;
+ int vvv = v+2;
+ float t1 = vv*inumS;
+ if(v == 0) //root polygon
+ {
+ p0.x = strand.verts[0].x;
+ p0.y = strand.verts[0].y;
+ p0.z = strand.verts[0].z;
+ p1.x = strand.verts[1].x;
+ p1.y = strand.verts[1].y;
+ p1.z = strand.verts[1].z;
+
+ tangent0 = p1 - p0;
+ tangent0.normalize();
+
+ tangent1 = tangent0;
+
+ r0 = strand.rootrad;
+ r1 = strand.rootrad*(1.0f - t1) + strand.tiprad*t1;
+
+ }
+ else if(vv == numS) //tip poly
+ {
+ p0 = p1;
+ p1.x = strand.verts[vv].x;
+ p1.y = strand.verts[vv].y;
+ p1.z = strand.verts[vv].z;
+
+ tangent0 = tangent1;
+ tangent1 = p1 - p0;
+ tangent1.normalize();
+
+
+ r0 = r1;
+ r1 = strand.tiprad;
+ }
+ else
+ {
+ p0 = p1;
+ p1.x = strand.verts[vv].x;
+ p1.y = strand.verts[vv].y;
+ p1.z = strand.verts[vv].z;
+
+ tangent0 = tangent1;
+ if(vvv < (int)strand.verts.length())
+ {
+ p2.x = strand.verts[vvv].x;
+ p2.y = strand.verts[vvv].y;
+ p2.z = strand.verts[vvv].z;
+ tangent1 = p2 - p0;
+ }
+ else
+ {
+ tangent1 = p1 - p0;
+ }
+ tangent1.normalize();
+
+ r0 = r1;
+ r1 = strand.rootrad*(1.0f - t1) + strand.tiprad*t1;
+
+ }
+ if(p0 == p1)
+ continue;
+
+
+ MVector d0 = tangent0^mViewDir;
+ MVector d1 = tangent1^mViewDir;
+ d0.normalize();
+ d1.normalize();
+
+ MVector v0 = p0 + d0*r0;
+ MVector v1 = p0 - d0*r0;
+ MVector v2 = p1 - d1*r1;
+ MVector v3 = p1 + d1*r1;
+
+ MColor col0 = strand.colors[v];
+
+ //we do get 1.0 in WFTYPE.alpha[] at the moment, lets fake it with tipfade
+ //col.a = 1.0f - vv*inumS;
+ col0.a = 1.0f;
+ if(mDoTipFade)
+ col0.a -= v*inumS;
+ if(mPasses)
+ col0.a *= ipasses;
+
+ MColor col1 = strand.colors[vv];
+ col1.a = 1.0f;
+ if(mDoTipFade)
+ col1.a -= vv*inumS;
+ if(mPasses)
+ col1.a *= ipasses;
+
+
+ Poly P1;
+
+ P1.v[0] = v0;
+ P1.c[0] = col0;
+ P1.t[0] = tangent0;
+
+ P1.v[1] = v1;
+ P1.c[1] = col0;
+ P1.t[1] = tangent0;
+
+
+ P1.v[2] = v2;
+ P1.c[2] = col1;
+ P1.t[2] = tangent1;
+
+ Poly P2;
+
+ P2.v[0] = v2;
+ P2.c[0] = col1;
+ P2.t[0] = tangent1;
+
+ P2.v[1] = v3;
+ P2.c[1] = col1;
+ P2.t[1] = tangent1;
+
+ P2.v[2] = v0;
+ P2.c[2] = col0;
+ P2.t[2] = tangent0;
+
+ //for Joe: what I am doing wrong with z-sort?
+ MPoint V(0.5f*(p0.x+p1.x), 0.5f*(p0.y+p1.y), 0.5f*(p0.z+p1.z));//a middle of poly
+ MPoint S = V*mWorldToCam; //to camera space
+ float d = (float)((S.z-nearSc.z)/(farSc.z-nearSc.z));
+ //if(d > 1.0f) d = 1.0f;
+ //if(d < 0.0f) d = 0.0f;
+ int pos = (int)(d*(float)groups.size());
+ if(pos >= groups.size()) pos = (int)groups.size()-1;
+ if(pos < 0) pos = 0;
+
+ groups[pos].p.push_back(P1);
+ groups[pos].p.push_back(P2);
+
+ ingroups+=2;
+ }
+
+ }
+ }
+
+};
+
+void shaveGeometryOverride::cacheGuidePolys()
+{
+ int numS = SHAVE_VERTS_PER_GUIDE-1;
+ shaveHairShape::Guides::const_iterator iter;
+ float w = shave->getGuideThinkness();
+
+ w *= (4.0f*mGuideExtent)/1500.0f;
+
+ int nvisible = 0;
+ for (iter = mGuideCache->begin(); iter != mGuideCache->end(); iter++)
+ {
+ const shaveHairShape::Guide& guide = *iter;
+ if (!guide.hidden)
+ nvisible++;
+ }
+ guidePolys.clear();
+ guidePolys.reserve(numS*2*nvisible);
+
+ mSelectionData.mPrimIdxToGuideIdx.clear();
+ mSelectionData.mPrimIdxToGuideIdx.reserve(numS*2*nvisible);
+
+ int v;
+ for (iter = mGuideCache->begin(); iter != mGuideCache->end(); iter++)
+ {
+ const shaveHairShape::Guide& guide = *iter;
+ if (!guide.hidden)
+ {
+ unsigned int guideIdx = (unsigned int)(iter - mGuideCache->begin());
+ bool isActive = (guide.select != 0);
+
+ MVector tangent0;
+ MVector tangent1;
+ MVector p0;
+ MVector p1;
+ MVector p2;
+ int numS = SHAVE_VERTS_PER_GUIDE-1;
+
+ for (v = 0; v < numS; v++)
+ {
+ int vv = v+1;
+ int vvv = v+2;
+ if(v == 0) //root polygon
+ {
+ p0.x = guide.verts[0].x;
+ p0.y = guide.verts[0].y;
+ p0.z = guide.verts[0].z;
+ p1.x = guide.verts[1].x;
+ p1.y = guide.verts[1].y;
+ p1.z = guide.verts[1].z;
+
+ tangent0 = p1 - p0;
+ tangent0.normalize();
+ tangent1 = tangent0;
+ }
+ else if(vv == numS) //tip poly
+ {
+ p0 = p1;
+ p1.x = guide.verts[vv].x;
+ p1.y = guide.verts[vv].y;
+ p1.z = guide.verts[vv].z;
+
+ tangent0 = tangent1;
+ tangent1 = p1 - p0;
+ tangent1.normalize();
+ }
+ else
+ {
+ p0 = p1;
+ p1.x = guide.verts[vv].x;
+ p1.y = guide.verts[vv].y;
+ p1.z = guide.verts[vv].z;
+
+ tangent0 = tangent1;
+ if(vvv < SHAVE_VERTS_PER_GUIDE)
+ {
+ p2.x = guide.verts[vvv].x;
+ p2.y = guide.verts[vvv].y;
+ p2.z = guide.verts[vvv].z;
+ tangent1 = p2 - p0;
+ }
+ else
+ {
+ tangent1 = p1 - p0;
+ }
+ tangent1.normalize();
+ }
+ if(p0 == p1)
+ continue;
+
+
+ MVector d0 = tangent0^mViewDir;
+ MVector d1 = tangent1^mViewDir;
+ d0.normalize();
+ d1.normalize();
+
+ MVector v0 = p0 + d0*(float)w;
+ MVector v1 = p0 - d0*(float)w;
+ MVector v2 = p1 - d1*(float)w;
+ MVector v3 = p1 + d1*(float)w;
+
+
+ GuidePoly P1;
+ P1.v[0] = v0;
+ P1.v[1] = v1;
+ P1.v[2] = v2;
+ P1.active = isActive;
+
+ GuidePoly P2;
+ P2.v[0] = v2;
+ P2.v[1] = v3;
+ P2.v[2] = v0;
+ P2.active = isActive;
+
+ guidePolys.push_back(P1);
+ guidePolys.push_back(P2);
+
+ // Both polys are on the same guide so we store
+ // the same index in them.
+ //
+ mSelectionData.mPrimIdxToGuideIdx.push_back(guideIdx);
+ mSelectionData.mPrimIdxToGuideIdx.push_back(guideIdx);
+ }
+ }
+ }
+}
+
+void shaveGeometryOverride::cacheKnotPolys()
+{
+ int numS = SHAVE_VERTS_PER_GUIDE-1;
+ shaveHairShape::Guides::const_iterator iter;
+ float w = shave->getGuideThinkness();
+
+ w *= (4.0f*mGuideExtent)/1500.0f;
+ w *= 2.0f;
+
+ ///////////////////////////////////////
+ bool drawActive = false;
+ int startVert = 0;
+ int endVert = SHAVE_VERTS_PER_GUIDE - 1;
+
+ MString selectType;
+ MGlobal::executeCommand(
+ "optionVar -q shaveBrushSelectMode", selectType
+ );
+
+ if(selectType == "root")
+ {
+ startVert = endVert = 0;
+ }
+ else if(selectType == "tip")
+ {
+ startVert = endVert = SHAVE_VERTS_PER_GUIDE - 1;
+ }
+ else if(selectType == "vert")
+ {
+ startVert = 0;
+ endVert = SHAVE_VERTS_PER_GUIDE - 1;
+ }
+
+ const unsigned int numDrawnVertsPerGuide = endVert - startVert + 1;
+
+ ///////////////////////////////////////
+
+ int nvisible = 0;
+ for (iter = mGuideCache->begin(); iter != mGuideCache->end(); iter++)
+ {
+ const shaveHairShape::Guide& guide = *iter;
+ if (!guide.hidden)
+ nvisible++;
+ }
+ knotPolys.clear();
+ knotPolys.reserve(numDrawnVertsPerGuide*2*nvisible);
+
+ mSelectionData.mPrimIdxToVertIdx.clear();
+ mSelectionData.mPrimIdxToVertIdx.reserve(numDrawnVertsPerGuide*2*nvisible);
+
+ MVector p0;
+ for (iter = mGuideCache->begin(); iter != mGuideCache->end(); iter++)
+ {
+ const shaveHairShape::Guide& guide = *iter;
+ if (!guide.hidden)
+ {
+ unsigned int guideIdx = (unsigned int)(iter - mGuideCache->begin());
+
+ for (int i = startVert; i <= endVert ; i++)
+ {
+ //
+ // Is this vert active?
+ //
+ bool isActive = ((guide.select & (1 << i)) != 0);
+
+ p0.x = guide.verts[i].x;
+ p0.y = guide.verts[i].y;
+ p0.z = guide.verts[i].z;
+
+ MVector v0 = p0 + (mUpDir+mRightDir)*(float)w;
+ MVector v1 = p0 + (-mUpDir+mRightDir)*(float)w;
+ MVector v2 = p0 + (-mUpDir-mRightDir)*(float)w;
+ MVector v3 = p0 + (mUpDir-mRightDir)*(float)w;
+
+
+ KnotPoly P1;
+ P1.v[0] = v0;
+ P1.v[1] = v1;
+ P1.v[2] = v2;
+ P1.active = isActive;
+
+ KnotPoly P2;
+ P2.v[0] = v2;
+ P2.v[1] = v3;
+ P2.v[2] = v0;
+ P2.active = isActive;
+
+ knotPolys.push_back(P1);
+ knotPolys.push_back(P2);
+
+ // Both polys represent the same guide vert so we store the same
+ // index for each of them.
+ //
+ mSelectionData.mPrimIdxToVertIdx.push_back(guideIdx * SHAVE_VERTS_PER_GUIDE + i);
+ mSelectionData.mPrimIdxToVertIdx.push_back(guideIdx * SHAVE_VERTS_PER_GUIDE + i);
+ }
+ }
+ }
+}
+
+
+////////////////////// draw polyginal hair ///////////////////////////////////
+void shaveGeometryOverride::populateHairPolys(
+ const MHWRender::MGeometryRequirements& requirements,
+ const MHWRender::MRenderItemList& itemList,
+ MHWRender::MGeometry& data
+)
+{
+ bool doxpar = shave->getDoHairXparency();
+ bool fallback = shave->getDoFallback();
+ float ipasses = 1.0f/(float)mPasses;
+
+ cacheHairPolys();
+ cacheGuidePolys();
+ cacheKnotPolys();
+
+#if 0 //skip guides for now
+ unsigned int numGuidesToDraw = mGuideCache->size();
+#endif
+
+ //
+ // compute number of elements
+ //
+
+ unsigned int hairPolys = ingroups;
+ unsigned int nguidePolys = (unsigned int)guidePolys.size();
+ unsigned int nknotPolys = (unsigned int)knotPolys.size();
+ unsigned int totalPolys = nguidePolys + hairPolys + nknotPolys;
+
+ unsigned int hairVerts = hairPolys*3;
+ unsigned int guideVerts = nguidePolys*3;
+ unsigned int knotVerts = nknotPolys*3;
+ unsigned int totalVerts = totalPolys*3;
+
+ // vertex data
+ MHWRender::MVertexBuffer* positionBuffer = NULL;
+ float* positions = NULL;
+
+ MHWRender::MVertexBuffer* colorBuffer = NULL;
+ float* colors = NULL;
+
+ MHWRender::MVertexBuffer* uvBuffer = NULL;
+ float* uvs = NULL;
+
+ MHWRender::MVertexBuffer* tangBuffer = NULL;
+ float* tang = NULL;
+
+ MHWRender::MVertexBuffer* guidePositionBuffer = NULL;
+ float* guidepositions = NULL;
+
+ const MHWRender::MVertexBufferDescriptorList& descList = requirements.vertexRequirements();
+ int numVertexReqs = descList.length();
+ MHWRender::MVertexBufferDescriptor desc;
+
+ if(debugShader)
+ {
+ printf("numVertexReqs: %i\n",numVertexReqs);
+ /*
+ const MHWRender::MVertexBufferDescriptorList& itemBuffers = item->requiredVertexBuffers();
+ int numBufs = itemBuffers.length();
+ MHWRender::MVertexBufferDescriptor desc;
+ for (int bufNum=0; bufNum<numBufs; bufNum++)
+ {
+ if (itemBuffers.getDescriptor(bufNum, desc))
+ {
+ printf("Buffer Required for Item #%d ('%s'):\n", i, item->name().asChar());
+ printf("\tBufferName: %s\n", desc.name().asChar());
+ printf("\tDataType: %s (dimension %d)\n", MHWRender::MGeometry::dataTypeString(desc.dataType()).asChar(), desc.dimension());
+ printf("\tSemantic: %s\n", MHWRender::MGeometry::semanticString(desc.semantic()).asChar());
+ printf("\n");
+ }
+ }
+ */
+ }
+
+ for (int reqNum=0; reqNum<numVertexReqs; reqNum++)
+ {
+ if (!descList.getDescriptor(reqNum, desc))
+ {
+ continue;
+ }
+
+ switch (desc.semantic())
+ {
+ case MHWRender::MGeometry::kPosition:
+ {
+ if(debugShader) printf("POSITION BUFFER\n");
+ positionBuffer = data.createVertexBuffer(desc);
+ if (positionBuffer)
+ positions = (float*)positionBuffer->acquire(totalVerts,true);
+ }
+ break;
+
+ case MHWRender::MGeometry::kColor:
+ {
+ if(debugShader) printf("COLOR BUFFER\n");
+ colorBuffer = data.createVertexBuffer(desc);
+ if (colorBuffer)
+ colors = (float*)colorBuffer->acquire(totalVerts,true);
+ }
+ break;
+
+ //let's use texture to pass radius as uv.x
+ case MHWRender::MGeometry::kTexture:
+ {
+ if(debugShader) printf("TEXTURE BUFFER\n");
+ uvBuffer = data.createVertexBuffer(desc);
+ if (uvBuffer)
+ uvs = (float*)uvBuffer->acquire(totalVerts,true);
+ }
+ break;
+
+
+ //case MHWRender::MGeometry::kTangent:
+ case MHWRender::MGeometry::kNormal:
+ {
+ if(debugShader) printf("TANTGET/NORMAL BUFFER\n");
+ tangBuffer = data.createVertexBuffer(desc);
+ if (tangBuffer)
+ tang = (float*)tangBuffer->acquire(totalVerts,true);
+ }
+ break;
+ case MHWRender::MGeometry::kBitangent:
+ break;
+
+ default:
+ // do nothing for stuff we don't understand
+ break;
+ }
+ }
+ if(debugShader) fflush(stdout);
+
+ if (positions)
+ {
+ int pid = 0;
+ for(int g = (int)groups.size()-1; g >= 0; g--)
+ {
+ const PolyGroup& gr = groups[g];
+ unsigned int gs = (unsigned int)gr.p.size();
+ for(unsigned int i = 0; i < gs; i++)
+ {
+ const Poly& p = gr.p[i];
+
+ for(int j=0; j<3; j++)
+ {
+ positions[pid] = (float)p.v[j].x;
+ positions[pid+1] = (float)p.v[j].y;
+ positions[pid+2] = (float)p.v[j].z;
+ pid+=3;
+ }
+ }
+ }
+
+ /////////////////////////////////////////////////
+
+ for (unsigned int i = 0; i < guidePolys.size(); i++)
+ {
+ const GuidePoly& p = guidePolys[i];
+ for(int j=0; j<3; j++)
+ {
+ positions[pid++] = (float)p.v[j].x;
+ positions[pid++] = (float)p.v[j].y;
+ positions[pid++] = (float)p.v[j].z;
+ }
+ }
+
+ ////////////////////////////////////////////////
+
+ for (unsigned int i = 0; i < knotPolys.size(); i++)
+ {
+ const KnotPoly& p = knotPolys[i];
+
+ for(int j=0; j<3; j++)
+ {
+ positions[pid++] = (float)p.v[j].x;
+ positions[pid++] = (float)p.v[j].y;
+ positions[pid++] = (float)p.v[j].z;
+ }
+ }
+
+ positionBuffer->commit(positions);
+ }
+
+ if (colors)
+ {
+ int cid = 0;
+ for(int g = (int)groups.size()-1; g >= 0; g--)
+ {
+ const PolyGroup& gr = groups[g];
+ unsigned int gs = (unsigned int)gr.p.size();
+ for(unsigned int i = 0; i < gs; i++)
+ {
+ const Poly& p = gr.p[i];
+ for(int j=0; j<3; j++)
+ {
+ colors[cid] = p.c[j].r;
+ colors[cid+1] = p.c[j].g;
+ colors[cid+2] = p.c[j].b;
+ colors[cid+3] = p.c[j].a;
+ cid+=4;
+ }
+ }
+ }
+ /////////////////////////////////////////////////
+
+ for (unsigned int i = 0; i < guidePolys.size(); i++)
+ {
+ const GuidePoly& p = guidePolys[i];
+ for(int j=0; j<3; j++)
+ {
+ colors[cid] = p.active?1.0f:0.0f;
+ colors[cid+1] = 0.0f;
+ colors[cid+2] = 0.0f;
+ colors[cid+3] = 0.0f;
+ cid+=4;
+ }
+ }
+
+ ////////////////////////////////////////////////
+
+ for (unsigned int i = 0; i < knotPolys.size(); i++)
+ {
+ const KnotPoly& p = knotPolys[i];
+ for(int j=0; j<3; j++)
+ {
+ colors[cid] = p.active?1.0f:0.0f;
+ colors[cid+1] = 0.0f;
+ colors[cid+2] = 0.0f;
+ colors[cid+3] = 0.0f;
+ cid+=4;
+ }
+ }
+
+ colorBuffer->commit(colors);
+ }
+
+ if (uvs)
+ {
+ int uid = 0;
+ for(int g = (int)groups.size()-1; g >= 0; g--)
+ {
+ const PolyGroup& gr = groups[g];
+ unsigned int gs = (unsigned int)gr.p.size();
+ for(unsigned int i = 0; i < gs; i++)
+ {
+ const Poly& p = gr.p[i];
+ for(int j=0; j<3; j++)
+ {
+ uvs[uid] = (float)p.uv[j].x;
+ uvs[uid+1] = (float)p.uv[j].y;
+ uid+=2;
+ }
+ }
+ }
+ uvBuffer->commit(uvs);
+ }
+
+ if (tang)
+ {
+ int tid = 0;
+ for(int g = (int)groups.size()-1; g >= 0; g--)
+ {
+ const PolyGroup& gr = groups[g];
+ unsigned int gs = (unsigned int)gr.p.size();
+ for(unsigned int i = 0; i < gs; i++)
+ {
+ const Poly& p = gr.p[i];
+ for(int j=0; j<3; j++)
+ {
+ tang[tid] = (float)p.t[j].x;
+ tang[tid+1] = (float)p.t[j].y;
+ tang[tid+2] = (float)p.t[j].z;
+ tid+=3;
+ }
+ }
+ }
+ tangBuffer->commit(tang);
+ }
+
+
+ // index data
+ MHWRender::MIndexBuffer* indexBuffer = NULL;
+ MHWRender::MIndexBuffer* indexBuffer2 = NULL;
+ MHWRender::MIndexBuffer* indexBuffer3 = NULL;
+ int numItems = itemList.length();
+ for (int i=0; i<numItems; i++)
+ {
+ const MHWRender::MRenderItem* item = itemList.itemAt(i);
+ if (!item) continue;
+
+ // Enable to debug vertex buffers that are associated with each render item.
+ // Can also use to generate indexing better, but we don't need that here.
+ // Also debugs custom data on the render item.
+ static const bool debugStuff = false;
+ if (debugShader)
+ {
+ const MHWRender::MVertexBufferDescriptorList& itemBuffers =
+ item->requiredVertexBuffers();
+ int numBufs = itemBuffers.length();
+ MHWRender::MVertexBufferDescriptor desc;
+ for (int bufNum=0; bufNum<numBufs; bufNum++)
+ {
+ if (itemBuffers.getDescriptor(bufNum, desc))
+ {
+ printf("Buffer Required for Item #%d ('%s'):\n", i, item->name().asChar());
+ printf("\tBufferName: %s\n", desc.name().asChar());
+ printf("\tDataType: %s (dimension %d)\n", MHWRender::MGeometry::dataTypeString(desc.dataType()).asChar(), desc.dimension());
+ printf("\tSemantic: %s\n", MHWRender::MGeometry::semanticString(desc.semantic()).asChar());
+ printf("\n");
+ }
+ }
+ fflush(stdout);
+ }
+
+ //same indexing for all hair
+ if (item->name() == kHairWireItemName || item->name() == kHairWireSelectedItemName ||
+ item->name() == kHairShadedItemName || item->name() == kHairShadedSelectedItemName)
+ {
+ // Wireframe index buffer is same for both wireframe and selected render item
+ // so we only compute and allocate it once, but reuse it for both render items
+ if (!indexBuffer)
+ {
+ indexBuffer = data.createIndexBuffer(MHWRender::MGeometry::kUnsignedInt32);
+ if (indexBuffer)
+ {
+ unsigned int* buffer = (unsigned int*)indexBuffer->acquire(hairVerts);
+ if (buffer)
+ {
+ for(unsigned int k = 0; k < hairVerts; k++)
+ buffer[k] = k;
+
+ indexBuffer->commit(buffer);
+ }
+ }
+ }
+
+ // Associate same index buffer with either render item
+ if (indexBuffer)
+ {
+ item->associateWithIndexBuffer(indexBuffer);
+ }
+ }
+
+ //////////////////////////////////////////
+ // guide indexing
+ if (item->name() == kGuidesItemName)
+ {
+
+ // Wireframe index buffer is same for both wireframe and selected render item
+ // so we only compute and allocate it once, but reuse it for both render items
+ if (!indexBuffer2)
+ {
+ indexBuffer2 = data.createIndexBuffer(MHWRender::MGeometry::kUnsignedInt32);
+ //indexBuffer2 = new MHWRender::MIndexBuffer(MHWRender::MGeometry::kUnsignedInt32);
+ if (indexBuffer2)
+ {
+ unsigned int* buffer = (unsigned int*)indexBuffer2->acquire(guideVerts);
+ if (buffer)
+ {
+ for (unsigned int i = 0; i < guideVerts; i++)
+ {
+ //simple indexing
+ buffer[i] = i+hairVerts;
+ }
+
+ indexBuffer2->commit(buffer);
+ }
+ }
+ }
+ if(indexBuffer2)
+ item->associateWithIndexBuffer(indexBuffer2);
+ }
+ //////////////////////////////
+ // knot indexing
+ if (item->name() == kKnotsItemName)
+ {
+ if (!indexBuffer3)
+ {
+ indexBuffer3 = data.createIndexBuffer(MHWRender::MGeometry::kUnsignedInt32);
+ if (indexBuffer3)
+ {
+ unsigned int* buffer = (unsigned int*)indexBuffer3->acquire(knotVerts);
+ if (buffer)
+ {
+ for (unsigned int i = 0; i < knotVerts; i++)
+ {
+ //simple indexing
+ buffer[i] = i+hairVerts+guideVerts;
+ }
+ indexBuffer3->commit(buffer);
+ }
+ }
+ }
+ if(indexBuffer3)
+ {
+ item->associateWithIndexBuffer(indexBuffer3);
+ }
+ }
+ ///////////////////////////////
+ }
+
+ //////////////////////////////////////
+ //}
+ //////////////////////////////////////
+}
+
+/////////// not used /////////////////////
+void shaveGeometryOverride::populateHairGuides(
+ const MHWRender::MGeometryRequirements& requirements,
+ const MHWRender::MRenderItemList& itemList,
+ MHWRender::MGeometry& data
+ )
+{
+ float w = shave->getGuideThinkness();
+
+ unsigned int numGuidesToDraw = (unsigned int)mGuideCache->size();
+ if(debugShader)
+ printf("numGuidesToDraw: %i\n",numGuidesToDraw);
+
+ //
+ // compute number of elements
+ //
+ unsigned int totalLines = 0;
+ {
+ shaveHairShape::Guides::const_iterator iter;
+ for (iter = mGuideCache->begin(); iter != mGuideCache->end(); iter++)
+ {
+ const shaveHairShape::Guide& guide = *iter;
+
+ if (!guide.hidden)
+ totalLines += (SHAVE_VERTS_PER_GUIDE-1);
+
+ }
+ }
+ unsigned int totalVerts = totalLines*2;
+
+
+ // vertex data
+ int positionStart = 0;
+ MHWRender::MVertexBuffer* positionBuffer = NULL;
+ float* positions = NULL;
+
+ MHWRender::MVertexBuffer* tangBuffer = NULL;
+ float* tang = NULL;
+
+ const MHWRender::MVertexBufferDescriptorList& descList = requirements.vertexRequirements();
+ int numVertexReqs = descList.length();
+ MHWRender::MVertexBufferDescriptor desc;
+
+ if(debugShader)
+ printf("numVertexReqs: %i\n",numVertexReqs);
+
+
+ for (int reqNum=0; reqNum<numVertexReqs; reqNum++)
+ {
+ if (!descList.getDescriptor(reqNum, desc))
+ {
+ continue;
+ }
+#if 0
+ switch (desc.semantic())
+ {
+ case MHWRender::MGeometry::kPosition:
+ {
+ for (int k = 0; k < data.vertexBufferCount(); k++)
+ {
+ MHWRender::MVertexBuffer* vb = data.vertexBuffer(k);
+ if(vb)
+ {
+ if(vb->descriptor().semantic() == desc.semantic())
+ {
+ positionBuffer = vb;
+ positionStart = positionBuffer->vertexCount();
+ positions = (float*)malloc(totalVerts*3*sizeof(float));
+
+ if(debugShader)
+ printf("startPosVertex: %i\n",positionStart);
+ }
+ }
+
+ }
+
+ //positionBuffer = data.createVertexBuffer(desc);
+ //if (positionBuffer)
+ // positions = (float*)positionBuffer->acquire(totalVerts);
+ }
+ break;
+
+ case MHWRender::MGeometry::kTangent:
+ {
+ tangBuffer = data.createVertexBuffer(desc);
+ if (tangBuffer)
+ tang = (float*)tangBuffer->acquire(totalVerts);
+ }
+ break;
+
+ case MHWRender::MGeometry::kNormal:
+ {
+ positionBuffer = data.createVertexBuffer(desc);
+ if (positionBuffer)
+ positions = (float*)positionBuffer->acquire(totalVerts);
+ }
+ break;
+
+ default:
+ // do nothing for stuff we don't understand
+ break;
+ }
+#endif
+ }
+ if(debugShader) fflush(stdout);
+
+ if (positions )
+ {
+ int pid = 0;
+ int g = 0;
+ shaveHairShape::Guides::const_iterator iter;
+ for (iter = mGuideCache->begin(); iter != mGuideCache->end(); iter++)
+ {
+ const shaveHairShape::Guide& guide = *iter;
+ if (!guide.hidden)
+ {
+ for (int v = 0; v < SHAVE_VERTS_PER_GUIDE-1; v++)
+ {
+ int vv = v+1;
+ positions[pid++] = guide.verts[v].x;
+ positions[pid++] = guide.verts[v].y;
+ positions[pid++] = guide.verts[v].z;
+
+ positions[pid++] = guide.verts[vv].x;
+ positions[pid++] = guide.verts[vv].y;
+ positions[pid++] = guide.verts[vv].z;
+
+ }
+ }
+ }
+ positionBuffer->commit(positions);
+ //positionBuffer->update(positions,positionStart,totalVerts,false);
+ //free(positions);
+ }
+
+
+ if (tang)
+ {
+ int pid = 0;
+ MFloatVector tangent0;
+ MFloatVector tangent1;
+ MFloatVector p0;
+ MFloatVector p1;
+ MFloatVector p2;
+
+ shaveHairShape::Guides::const_iterator iter;
+ for (iter = mGuideCache->begin(); iter != mGuideCache->end(); iter++)
+ {
+ const shaveHairShape::Guide& guide = *iter;
+ if (!guide.hidden)
+ {
+ for (int v = 0; v < SHAVE_VERTS_PER_GUIDE-2; v++)
+ {
+ int vv = v+1;
+ int vvv = v+2;
+ if(v == 0) //root
+ {
+ p0.x = guide.verts[0].x;
+ p0.y = guide.verts[0].y;
+ p0.z = guide.verts[0].z;
+ p1.x = guide.verts[1].x;
+ p1.y = guide.verts[1].y;
+ p1.z = guide.verts[1].z;
+
+ tangent0 = p1 - p0;
+ tangent0.normalize();
+
+ tangent1 = tangent0;
+
+ }
+ else if(vv == (int)SHAVE_VERTS_PER_GUIDE-1) //tip
+ {
+ p0 = p1;
+ p1.x = guide.verts[vv].x;
+ p1.y = guide.verts[vv].y;
+ p1.z = guide.verts[vv].z;
+
+ tangent0 = tangent1;
+ tangent1 = p1 - p0;
+ tangent1.normalize();
+ }
+ else
+ {
+ p0 = p1;
+ p1.x = guide.verts[vv].x;
+ p1.y = guide.verts[vv].y;
+ p1.z = guide.verts[vv].z;
+
+ tangent0 = tangent1;
+ if(vvv < (int)SHAVE_VERTS_PER_GUIDE)
+ {
+ p2.x = guide.verts[vvv].x;
+ p2.y = guide.verts[vvv].y;
+ p2.z = guide.verts[vvv].z;
+ tangent1 = p2 - p0;
+ }
+ else
+ {
+ tangent1 = p1 - p0;
+ }
+ tangent1.normalize();
+ }
+ tang[pid++] = tangent0.x;
+ tang[pid++] = tangent0.y;
+ tang[pid++] = tangent0.z;
+
+ tang[pid++] = tangent1.x;
+ tang[pid++] = tangent1.y;
+ tang[pid++] = tangent1.z;
+
+ }
+ }
+ }
+ tangBuffer->commit(tang);
+ }
+
+
+ // index data
+ MHWRender::MIndexBuffer* indexBuffer = NULL;
+ int numItems = itemList.length();
+ for (int i=0; i<numItems; i++)
+ {
+ const MHWRender::MRenderItem* item = itemList.itemAt(i);
+ if (!item) continue;
+
+ // Enable to debug vertex buffers that are associated with each render item.
+ // Can also use to generate indexing better, but we don't need that here.
+ // Also debugs custom data on the render item.
+ static const bool debugStuff = false;
+ if (debugShader)
+ {
+ const MHWRender::MVertexBufferDescriptorList& itemBuffers =
+ item->requiredVertexBuffers();
+ int numBufs = itemBuffers.length();
+ MHWRender::MVertexBufferDescriptor desc;
+ for (int bufNum=0; bufNum<numBufs; bufNum++)
+ {
+ if (itemBuffers.getDescriptor(bufNum, desc))
+ {
+ printf("Buffer Required for Item #%d ('%s'):\n", i, item->name().asChar());
+ printf("\tBufferName: %s\n", desc.name().asChar());
+ printf("\tDataType: %s (dimension %d)\n", MHWRender::MGeometry::dataTypeString(desc.dataType()).asChar(), desc.dimension());
+ printf("\tSemantic: %s\n", MHWRender::MGeometry::semanticString(desc.semantic()).asChar());
+ printf("\n");
+ }
+ }
+ fflush(stdout);
+ }
+
+ //indexing
+ if (item->name() == kGuidesItemName)
+ {
+
+ // Wireframe index buffer is same for both wireframe and selected render item
+ // so we only compute and allocate it once, but reuse it for both render items
+ if (!indexBuffer)
+ {
+ indexBuffer = data.createIndexBuffer(MHWRender::MGeometry::kUnsignedInt32);
+ //indexBuffer = new MHWRender::MIndexBuffer(MHWRender::MGeometry::kUnsignedInt32);
+ if (indexBuffer)
+ {
+ unsigned int* buffer = (unsigned int*)indexBuffer->acquire(totalLines*2);
+ if (buffer)
+ {
+ int idx0 = 0;
+ int idx1 = 0;//positionStart; // 0;
+ shaveHairShape::Guides::const_iterator iter;
+ for (iter = mGuideCache->begin(); iter != mGuideCache->end(); iter++)
+ {
+ const shaveHairShape::Guide& guide = *iter;
+ if (!guide.hidden)
+ {
+ for (int v = 0; v < SHAVE_VERTS_PER_GUIDE-1; v++)
+ {
+ //simple indexing
+ buffer[idx0] = idx1;
+ buffer[idx0+1] = idx1+1;
+ idx0 += 2;
+ idx1 += 2;
+ }
+ }
+ }
+ indexBuffer->commit(buffer);
+ //data.addIndexBuffer(indexBuffer);
+
+ item->associateWithIndexBuffer(indexBuffer);
+
+ }
+ }
+ }
+ }
+ }
+}
+
+#if MAYA_API_VERSION >= 201600
+void shaveGeometryOverride::updateSelectionGranularity(
+ const MDagPath& path, MHWRender::MSelectionContext& selectCtx
+ )
+{
+ // The selection level defaults to object, so we only have to set
+ // it if we want to select components.
+ //
+ MHWRender::DisplayStatus displayStatus = MHWRender::MGeometryUtilities::displayStatus(path);
+
+ if (displayStatus == MHWRender::kHilite)
+ {
+ MSelectionMask mayaSelectionMask;
+
+ if (MGlobal::selectionMode() == MGlobal::kSelectComponentMode)
+ {
+ mayaSelectionMask = MGlobal::componentSelectionMask();
+ }
+ else
+ {
+ mayaSelectionMask = MGlobal::objectSelectionMask();
+ }
+
+ MSelectionMask supportedComponents(MSelectionMask::kSelectCVs);
+ supportedComponents.addMask(MSelectionMask::kSelectMeshEdges);
+
+ if (mayaSelectionMask.intersects(supportedComponents))
+ {
+ selectCtx.setSelectionLevel(MHWRender::MSelectionContext::kComponent);
+ }
+ }
+#if MAYA_API_VERSION >= 201650
+ // pointSnappingActive() actually became available in API version 201610
+ // (2016 Extension 1), but we don't want to force our 2016 users to update
+ // to the extension if they don't have to.
+ //
+ else if (pointSnappingActive())
+ {
+ selectCtx.setSelectionLevel(MHWRender::MSelectionContext::kComponent);
+ }
+#endif
+}
+#endif
+
+
+void shaveGeometryOverride::cleanUp()
+{
+
+}
+
+
+#if MAYA_API_VERSION >= 201600
+MStatus shaveGeometryOverride::registerComponentConverters()
+{
+ MStatus st = MHWRender::MDrawRegistry::registerComponentConverter(kKnotsItemName, guideVertComponentConverter::create);
+
+ if (st)
+ {
+ st = MHWRender::MDrawRegistry::registerComponentConverter(kGuidesItemName, guideComponentConverter::create);
+ }
+
+ return st;
+}
+
+MStatus shaveGeometryOverride::deregisterComponentConverters()
+{
+ MStatus st = MHWRender::MDrawRegistry::deregisterComponentConverter(kKnotsItemName);
+
+ if (st)
+ {
+ st = MHWRender::MDrawRegistry::deregisterComponentConverter(kGuidesItemName);
+ }
+
+ return st;
+}
+#endif
+
+
+bool shaveGeometryOverride::disableRenderItem(
+ MHWRender::MRenderItemList& list,
+ const MString& itemName,
+ MHWRender::MGeometry::Primitive primType,
+ MHWRender::MGeometry::DrawMode drawMode
+ )
+{
+ int index = list.indexOf(itemName, primType, drawMode);
+
+ if (index >= 0)
+ {
+ list.itemAt(index)->enable(false);
+ }
+
+ return (index >= 0);
+}