diff options
Diffstat (limited to 'mayaPlug/shaveGeometryOverride.cpp')
| -rw-r--r-- | mayaPlug/shaveGeometryOverride.cpp | 3840 |
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); +} |