#ifndef shaveHairShape_h #define shaveHairShape_h // Shave and a Haircut // (c) 2019 Epic Games // US Patent 6720962 #include #include #include #include #include #include #include #include #include #include #include #include #include "shaveSDK.h" #include "shaveObjExporter.h" #include "ShavePerVertTexInfo.h" #include "shaveTextureStore.h" #ifdef OSMac_MachO_ # include # include #else # include # include #endif #define kStringLength 512 #if MAYA_API_VERSION < 20180000 class M3dView; class MDataHandle; class MDGContext; class MDGModifier; class MObjectArray; class MPlug; class MPlugArray; class MPxGeometryIterator; #endif ////////////////////// threads //////////////////////////////// #define REUSABLE_THREADS #ifdef REUSABLE_THREADS #ifndef APIENTRY #ifdef _WIN32 #define APIENTRY WINAPI #else #define APIENTRY #endif #endif #ifdef _WIN32 typedef DWORD/* unsigned int*/ (APIENTRY THPROC)(void* param); #else typedef void* (APIENTRY THPROC)( void* param); #endif class LEvent { public: #ifdef _WIN32 LEvent( bool signalled = false, LPSECURITY_ATTRIBUTES sa = NULL); #else LEvent( bool signalled = false); #endif virtual ~LEvent(); void Set(); void Reset(); void Wait(); #ifdef _WIN32 HANDLE handle; #else pthread_mutex_t mutex; pthread_cond_t cond; bool triggered; #endif }; class LThread { public: LThread( THPROC* pThreadFunc, // address of thread callback void* pThreadData = NULL, // address of callback's parameter, unsigned int exeFlags = 0, // creation flag unsigned int sSize = 0, // stack size bool inheritable = false // inheritable ); virtual ~LThread(); enum ThState { eWaiting, eAvilable, eRunning, eExit }; virtual void Create(); virtual void Execute(THPROC* pThreadFunc = NULL, void* pThreadData = NULL); virtual void WaitToFinish(); #ifdef _WIN32 DWORD GetThreadId() const {return thId(); } HANDLE GetHandle() const {return th();} #else int GetThreadId() const {return thId(); } pthread_t* GetHandle() {return &_th();} #endif int GetState() const {return state(); } void* GetThreadArgument() const {return thArg(); } LEvent* GetFinish() const {return efinish();} LEvent* GetStart() const {return estart();} protected: static void getErrorDetail(int&,std::string&); //extended thread proc, will be used if mutex and doneEvent not NULL static THPROC thFnEx; void execute(); //const member access #ifdef _WIN32 inline HANDLE th() const {return m_th;} inline unsigned int thId() const {return m_thId;} inline DWORD exitCode() const {return m_exitCode;} inline LPSECURITY_ATTRIBUTES sa() const {return m_sa;} #else inline const pthread_t& th() const {return m_th;} inline int thId() const {return m_thId;} inline int exitCode() const {return m_exitCode;} #endif inline LEvent* estart() const {return m_estart;} inline LEvent* efinish()const {return m_efinish;} inline void* thArg() const {return m_thArg;} inline THPROC* thFn() const {return m_thFn;} inline unsigned int stackSize()const {return m_stackSize;} inline unsigned int exeFlags() const {return m_exeFlags;} inline ThState state() const {return m_state;} //member access #ifdef _WIN32 inline HANDLE& _th() {return m_th;} inline DWORD& _thId() {return m_thId;} inline DWORD& _exitCode(){return m_exitCode;} inline LPSECURITY_ATTRIBUTES& _sa() {return m_sa;} #else inline pthread_t& _th() {return m_th;} inline int& _thId() {return m_thId;} inline int& _exitCode(){return m_exitCode;} #endif inline LEvent*& _estart() {return m_estart;} inline LEvent*& _efinish() {return m_efinish;} inline void*& _thArg() {return m_thArg;} inline THPROC*& _thFn() {return m_thFn;} inline unsigned int& _stackSize(){return m_stackSize;} inline unsigned int& _exeFlags() {return m_exeFlags;} inline ThState& _state() {return m_state;} private: #ifdef _WIN32 HANDLE m_th; DWORD m_thId; DWORD m_exitCode; LPSECURITY_ATTRIBUTES m_sa; #else pthread_t m_th; int m_thId; int m_exitCode; #endif LEvent* m_estart; LEvent* m_efinish; void* m_thArg; THPROC* m_thFn; unsigned int m_stackSize; unsigned int m_exeFlags; ThState m_state; }; class LThreadGroup { public: LThreadGroup(THPROC* thFn = NULL); virtual ~LThreadGroup(); LThread* Get(unsigned int i) const {return th(i);} virtual bool Start(unsigned int i, THPROC* pThreadFunc, void* thData); virtual void WaitToFinish(int ms = -1); static unsigned int GetNumCPUs(); protected: //const memeber access inline const std::vector& ths() const {return m_ths;} inline LThread* th(unsigned int i) const {return m_ths[i];} //member access inline std::vector& _ths() {return m_ths;} inline LThread*& _th(unsigned int i) {return m_ths[i];} private: std::vector m_ths; }; #endif /////////////////////////////////////////////////////////////// class shaveDirties { public: shaveDirties() { last_haircout = 0; this_haircount = 0; last_passes = 0; this_passes = 0; last_display_count = 0; this_display_count = 0; last_display_segs = 0; this_display_segs = 0; last_guide_segs = 0; this_guide_segs = 0; // these are DIRTY FLAGS you need to set before each update DIRTY_HAIRCOUNT = 1; DIRTY_PASSES = 1; DIRTY_DISPLAY_COUNT = 1; DIRTY_DISPLAYSEGS = 1; DIRTY_GUIDE_SEGS = 1; DIRTY_TEXTURE = 1; DIRTY_TEXTURE_JOE = 1; DIRTY_TIME = 1; DIRTY_CLUMPS = 1; DIRTY_MULT = 1; BRUSH_MOUSE_DOWN = 0; // BRUSH_JUST_MOVED = 0; GLOBAL_MOUSE_DOWN = 0; } ~shaveDirties(){} int last_haircout; int this_haircount; int last_passes; int this_passes; int last_display_count; int this_display_count; int last_display_segs; int this_display_segs; int last_guide_segs; // these are new just declare them 15 int this_guide_segs; // these are DIRTY FLAGS you need to set before each update int DIRTY_HAIRCOUNT; int DIRTY_PASSES; int DIRTY_DISPLAY_COUNT; int DIRTY_DISPLAYSEGS; int DIRTY_GUIDE_SEGS; int DIRTY_TEXTURE; int DIRTY_TEXTURE_JOE; int DIRTY_TIME; int DIRTY_CLUMPS; int DIRTY_MULT; int BRUSH_JUST_MOVED; int BRUSH_MOUSE_DOWN; //only for styling int GLOBAL_MOUSE_DOWN; //does not depend where in MayaWindow }; class shaveInstanceDisplay { public: MFloatPoint center; float radius; MImage img; //result MFloatPointArray points; MFloatPointArray normals; MFloatPointArray uvs; MIntArray faceCounts; MIntArray faceStart; MIntArray faceEnd; MIntArray faceVerts; GLuint diffuse; //GLuint xparenc; bool hasXparency; enum { eTexW = 320, eTexH = 320 }; shaveInstanceDisplay() { diffuse = 0; hasXparency = false; /*xparenc = 0;*/ } virtual ~shaveInstanceDisplay() {}; void Reset(); void CreateMaps(MObject shader); void SampleMap(MObject map, MImage& img); }; class shaveHairShape : public MPxSurfaceShape { public: static MString drawDbClassification; static MString drawRegistrantId; typedef enum { kDynamicsInit = -1, kDynamicsOff = 0, kDynamicsCreate = 1, kDynamicsUse = 2 } DynamicsMode; typedef enum { kHairDisplayNone = 0, kHairDisplayHair = 1, kHairDisplayGeom = 2 } HairDisplayMode; typedef struct { MVectorArray verts; MColorArray colors; float tiprad; float rootrad; } DisplayStrand; typedef std::vector DisplayHair; struct DisplayHairCache{ enum { eBucnchSize = 3000 //5000 //how many hairs to fetch per iteration }; std::vector displayHair; MFloatPoint center; float radius; }; typedef struct { MFloatVectorArray verts; short select; bool hidden; } Guide; typedef std::vector Guides; typedef struct { float frame; Guides guides; } GuidesSnapshot; //******************************************************************* // // Methods // //******************************************************************* public: // // Standard methods. // shaveHairShape(); virtual ~shaveHairShape(); virtual bool acceptsGeometryIterator(bool writeable = true) { return !writeable; } virtual bool acceptsGeometryIterator( MObject&, bool writeable=true, bool forReadOnly = false ) { return !writeable && forReadOnly; } virtual MObjectArray activeComponents() const; virtual void componentToPlugs( MObject& component, MSelectionList& selectionList ) const; virtual MStatus compute(const MPlug& plug, MDataBlock& data); virtual MObject createFullVertexGroup() const; static void* creator(); virtual MPxGeometryIterator* geometryIteratorSetup( MObjectArray& components1, MObject& components2, bool forReadOnly = false ); #if MAYA_API_VERSION >= 20180000 virtual bool getInternalValue( const MPlug &plug, MDataHandle &hdl ); #else virtual bool getInternalValueInContext( const MPlug& plug, MDataHandle& hdl, MDGContext& context ); #endif virtual MSelectionMask getComponentSelectionMask() const; virtual MSelectionMask getShapeSelectionMask() const; virtual bool hasActiveComponents() const; static MStatus initialize(); virtual bool isBounded() const { return false; } virtual MStatus legalConnection( const MPlug& ourPlug, const MPlug& theirPlug, bool weAreSource, bool& isLegal ); virtual bool match( const MSelectionMask& mask, const MObjectArray& componentList ) const; virtual MatchResult matchComponent( const MSelectionList& item, const MAttributeSpecArray& spec, MSelectionList& list ); virtual void postConstructor(); #if MAYA_API_VERSION >= 201600 virtual SchedulingType schedulingType() const { return kUntrusted; } #endif #if MAYA_API_VERSION >= 20180000 virtual bool setInternalValue( const MPlug &plug, const MDataHandle &hdl ); #else virtual bool setInternalValueInContext( const MPlug& plug, const MDataHandle& hdl, MDGContext& context ); #endif virtual MStatus setDependentsDirty( const MPlug& dirty, MPlugArray& affected ); virtual MStatus connectionMade ( const MPlug& plug, const MPlug& otherPlug, bool asSrc ); virtual MStatus connectionBroken ( const MPlug & plug, const MPlug &otherPlug, bool asSrc ); virtual MStatus shouldSave(const MPlug& plug, bool& saveIt); virtual void transformUsing( const MMatrix& mat, const MObjectArray& components ); virtual void transformUsing( const MMatrix& mat, const MObjectArray& components, MVertexCachingMode cachingMode, MPointArray* pointCache ); // // Non-standard class methods. // static void doAffects(MObject targetAttr); static int getMaxShaveID(); static int getNumShaveNodes(); static int initNumShaveNodes(); static void nodeAdded(); static void nodeRemoved(); // // Non-standard instance methods. // int addShaveUVSets(); void applyEdits(bool resetRestPose); void applySelections(); void attrDebug(int); virtual MBoundingBox boundingBoxTemp() const; void clearBlindDataAttr(MObject& attr); void clearComponentSelections(); void clearHiddenGuides(); void clearSelections(); void clearSplineLocks(); MObject createExternalMesh(MObject parent, MStatus* st); void deleteMe(MDGModifier& dgMod); void enableHairDisplay(bool enable) { mHairDisplayEnabled = enable; } MStatus getCollisionGeom( MDataBlock& block, MObjectArray& geoms, MObjectArray& components ); MStatus getCollisionList(MSelectionList& list); unsigned getNumPasses() const; //const std::vector& getDisplayHairs(); void invalidateDisplayHairs(); void clearDisplayHairs(); const DisplayHairCache& getDisplayHairs(M3dView& view); const DisplayHairCache& getDisplayHairs(M3dView& view, bool cleanup); //iterative const DisplayHairCache& getDisplayHairs() const {return mDisplayHairCache;}// no compute #if 0 bool getDisplayHairs(unsigned int hairCount, DisplayHairCache& cache); #endif MObject getDisplayShape(); MObject getDisplayTransform(); MStatus getGeomFromArrayAttr( MDataBlock& block, MObject arrayAttr, MObject componentGroupIDAttr, MObjectArray& geoms, MObjectArray& components ); MStatus getGrowthGeom( MDataBlock& block, MObjectArray& geoms, MObjectArray& components ); /*const*/ shaveInstanceDisplay& getInstanceDisplay(); MStatus getGrowthList(MSelectionList& list); unsigned getGuideCount(); bool getGuideDisplayOverride() const { return mGuideDisplayOverride; } const GuidesSnapshot& getGuides(); const GuidesSnapshot& getDirtyGuides() { return mGuideCache; } const GuidesSnapshot& getPrevGuides() { return mPrevGuides; } int getHairGroup(MDataBlock* block=NULL) const; SHAVENODE* getHairNode(); int getDisplayMode() const; bool getDisplayGuides() const; bool getDoTipfade() const; float getAmbDiff() const; // // Draw opacity attributes // bool getDoHairXparency() const; float getHairXparency() const; MColor getSpecularTint() const; MColor getSpecularTint2() const; float getSpecular() const; float getGloss() const; void dirtyDisplay() {mDisplayHairCacheDirty=true;mDisplayInstCacheDirty = true;} void dirtyGuides() {mGuideCacheDirty = true;} bool getDoFallback() const; bool getInstancingStatus(); // // Return the number of hairs which should be displayed. // unsigned getNumDisplayHairs( bool forcefallback, MDataBlock* block=NULL ) const; // // Return the number of segments to use when displaying hair. // int getNumDisplaySegments() const; float getGuideThinkness() const; float getGuideExt() const; void setGuideExt(float e); MStatus getSelectionListFromArrayAttr( MSelectionList& list, MObject arrayAttr, MObject componentGroupIDAttr = MObject::kNullObj ); MObject getShader(); unsigned int numLayers(); MObject getLayer(unsigned int idx); int getShaveID() const; int getStackIndex() const; MString getUVSet(MObject growthObject, MObject texture); // // Let the node know that it's guides have been modified by an external // entity (e.g. the brush). // void guidesChanged(); void hideSelectedGuides(); MStatus initializeNode(); void initTextureLookup(); bool isCurrent() const; bool isHairDisplayEnabled() const { return mHairDisplayEnabled; } bool isInstanced() const; void makeCurrent(bool trigger=true); MString nodeName(); bool nodeIsInitialized() const; void recomb(WFTYPE& curves); void removeShaveUVSets(); MStatus repairGeomList( const MObject& setAttr, const MObject& groupIdAttr ); void setBlindDataAttr( MObject& attr, const void* data, long dataLen ); MStatus setCollisionList(const MSelectionList& list); MStatus setGrowthList(const MSelectionList& list); MStatus setSplineLocks(const MDagPathArray& curves); void setStackIndex(int index); void unhideGuides(); void updateNodeName(); void updateParams(); void updateDatablockFromParams(MDataBlock& block); void updatePlugsFromParams(); void updateSelections(const MSelectionList& selections); void updateMayaComponentSelections(); void doXform(); #ifdef PER_NODE_TEXLOOKUP void updateTexLookups(); #endif void setBrushActive(bool b) { mBrushIsActive=b; MHWRender::MRenderer::setGeometryDrawDirty(thisMObject()); } bool getBrushActive() { return mBrushIsActive;} void setBrushDown(bool b) { assert(false); //not hide but reduce display hair count. mBrushIsDown=b; MHWRender::MRenderer::setGeometryDrawDirty(thisMObject()); } bool getBrushDown() { return mBrushIsDown;} static void cacheOneHair(unsigned threadID, void* data); protected: // Callback called at the end of a 'duplicate' command. void afterDuplication(); static void afterDuplication(void* clientData); // Callback called at the start of a 'duplicate' command. void beforeDuplication(); static void beforeDuplication(void* clientData); // Delete all of the stat files associate with this node. void cleanStatFiles(MDataBlock& block); MStatus clearInstanceObject(MDataBlock& block); void computeBoundingBox(MBoundingBox& bbox, MDataBlock& block); MStatus computeOutputMesh( MDataBlock& datablock, bool nodeJustLoaded ); // Connect the geometry in 'set' to the appropriate inputs on the // shaveHairShape. 'setAttr' contains the shaveHairShape attribute to // which the set is connected. MStatus connectGeometry(MObject setAttr, MObject set); void createEmptyMesh(MObject& meshData); // Create a geometry set of the appropriate type (growth or collision) // as determined by 'setAttr'. MObject createGeomSet(const MObject& setAttr); void createMesh(MDataBlock& datablock, MObject& outData); void dirtyOutputMesh(); // Recursively disconnect all incoming connections to 'attr' and its // children/elements. void disconnectIncoming( const MObject& attr, MDGModifier* dgmod = NULL ); // Recursively disconnect all outgoing connections to 'attr' and its // children/elements. void disconnectOutgoing( const MObject& attr, MDGModifier* dgmod = NULL ); // Recursively disconnect all connections to 'attr' and its // children/elements. void disconnectAll( const MObject& attr, MDGModifier* dgmod = NULL ); // Recursively disconnect all incoming (if 'incoming' is true) or // outgoing (if 'incoming' is false) connections to 'plug' and its // children/elements. void disconnectPlugTree( MPlug& plug, bool incoming, MDGModifier* dgmod = NULL ); // Apply the display parameters to 'totalCount' and return the number // of them which should be displayed. // unsigned getDisplayCount( unsigned totalCount, bool forcefallback, MDataBlock* block=NULL ) const; // Retrieves the geometry set connected to 'setAttr'. Returns // MObject::kNullObj if there is no set connected. MObject getGeomSet(const MObject& setAttr); // Returns the attribute on 'shape' which contains its world geometry // array. 'growthTargetAttr' returns the input attribute on the // shaveHairShape node which receives the corresponding growth geometry. // There's no input attribute returned for collision geometry because // it is always 'collisionObjects'. static bool getWorldGeomAttrs( const MObject& shape, MObject& worldGeomAttr, MObject& growthTargetAttr ); bool isPermanentlyDisabled() const; void loadShaveEngine( float frame, bool doXplant, bool keepMaterials, bool preserveParams, MDataBlock& block ); MObject makePolyMeshData( MDataBlock& datablock, MObject parent, bool useDisplayLOD, bool forShadowsOnly ); void restoreGeomSet(const MObject& attr, MSelectionList& list); void saveGeomSet(const MObject& attr, MSelectionList& list); // Forces the node to do an xplant the next time it is evaluated. // void scheduleXplant(); // Replaces any existing growth or collision surfaces (as determined // by 'attr') with those specified in 'list', creating the external // objectSet if necessary. MStatus setGeomList(const MObject& attr, const MSelectionList& list); void setGuideDisplayOverride(bool enable); MStatus setInstanceObject( MObject instanceMesh, MObject shader, MDataBlock* block=NULL ); void setPermanentlyDisabled(bool disabled); void setShadowHaircount(int group); void updateBlindData(MDataBlock* block=NULL, bool updateParams=true); void updateParamsFromDatablock(MDataBlock&, int); void updateParamsFromPlugs(int); void updateSplines(); //******************************************************************* // // Member Variables // //******************************************************************* // // Global member variables. // public: static MTypeId id; static const int kNodeVersion; static int mNextShaveID; static const MString nodeTypeName; static const MFn::Type kShaveGuideComponent = MFn::kMeshEdgeComponent; static const MFn::Type kShaveGuideVertComponent = MFn::kSurfaceCVComponent; static const char* kShapeSelectionMaskName; static const char* kGuideSelectionMaskName; static const char* kStrandSelectionMaskName; static const char* kVertSelectionMaskName; protected: static int numShaveNodes; // // Local member variables. // public: DynamicsMode doDyn; // Local echo of runDynamics attr ShaveExportData exportData; MString growthType; SHAVENODE hairnode; // the data we pass to/from Shave bool isRibDumper; WFTYPE MAYAdata; WFTYPE memShaveObj; // In-memory OBJ used w. MAYAxform // 'memShaveObj' above contains the growth and collision geom. It also // contains per-vert UV info, but that turns out to not work well for // shared UVs. 'growthCollisionUVs' below is a workaround. It contains // per-face-vert UVs for the growth and collision geom. The only // reason that we include the collision geom UVs is that we were in // lockdown and that meant the minimal changes to existing code. Also, // it might feasibly prove useful at some future point. For that same // reason, we continue to set the per-vert UVs in 'memShaveObj', but // hopefully no one is looking at them. WFTYPE growthCollisionUVs; // Per-face-vert UV info. short shaveDspyMode; // 0: guides, 1: hairs MString shaveObjFile; // temp file, used for // interprocess communication #if defined(OSMac_) && !defined(OSMac_MachO_) MString shaveObjFileHFS;// HFS version of shaveObjFile, // for CFM version of Maya on OSX. #endif // Cached texture values for per-vertex parameters. ShavePerVertTexInfo vertTexInfo; shaveDirties dirties; protected: #ifdef REUSABLE_THREADS inline LThreadGroup* lthGrp() const {return m_lthGrp;} inline LThreadGroup*& _lthGrp() {return m_lthGrp;} #endif float availableMem; bool beenHereBefore; // Call MAYArefresh or xplant/xform? bool blindInit; // have we loaded blind data? bool doneSelections; MObject geomMesh; MFnMesh instanceRefMesh; MCallbackId mAfterDuplicateCB; MCallbackId mBeforeDuplicateCB; bool mBrushIsActive; bool mBrushIsDown; //std::vector mDisplayHairCache; DisplayHairCache mDisplayHairCache; shaveInstanceDisplay mDisplayInstCache; bool mDisplayHairCacheDirty; bool mDisplayInstCacheDirty; // bool mDirtyDisplaycount; // bool mDirtyTexture; // bool mDirtyHaircount; bool mFirstTime; // For debugging use only GuidesSnapshot mGuideCache; GuidesSnapshot mPrevGuides; bool mGuideCacheDirty; unsigned mGuideCount; bool mGuideCountDirty; bool mGuideDisplayOverride; bool mGuideSelectionsDirty; bool mHairDisplayEnabled; bool mHaveSelections; bool mIsInstanced; WFTYPE mLockSplines; bool mNodeInitialized; int mNodeVersion; MSelectionList mSavedCollisionList; MSelectionList mSavedGrowthList; float mShaveFrame; int mShaveID; // vlad|06Apr2010 -- replaced by 'stackIndex' attribute // int mStackIndex; std::vector mVertSelections; bool mXplantRequired; //******************************************************************* // // Attributes // //******************************************************************* public: // vlad|06Apr2010 -- attribute replacement of 'int mStackIndex' // so stack index can be retrieved from another module by // attribute name static MObject stackIndex; static MObject aCachedBBox; static MObject aCachedBBoxMin; static MObject aCachedBBoxMax; static MObject aCollisionSet; static MObject aDisplayGuides; //goes to globals static MObject aDisplaySegmentLimit; //goes to globals static MObject aDisplayGuideThick; //goes to globals static MObject aDisplayGuideExt; static MObject aEvalOption; static MObject aGrowthSet; static MObject aGuide; static MObject aGuideX; static MObject aGuideY; static MObject aGuideZ; static MObject aHairGroup; static MObject aNodeVersion; static MObject aShaveVersion; static MObject aSpecularTint; static MObject aSpecularTint2; static MObject aSplineLock; static MObject aSplineLockTrigger; static MObject aTipFade; static MObject aSquirrel; static MObject blockDynamics; static MObject collisionObjectsAttr; static MObject collisionObjectsGroupIDAttr; static MObject displayHiarDoXparency; //goes to shave globals static MObject displayHiarDoSsao; //goes to shave globals static MObject displayHiarXparency; static MObject displayNodeAttr; static MObject dspyMode; static MObject growthObjectsGroupIDAttr; static MObject hairColorTexture; static MObject hairColorTextureR; static MObject hairColorTextureG; static MObject hairColorTextureB; static MObject inputCurve; static MObject inputMesh; static MObject inputSurf; static MObject instanceMesh; static MObject instanceMeshChanged; static MObject instancingStatusChanged; static MObject isActive; static MObject mutantHairColorTexture; static MObject mutantHairColorTextureR; static MObject mutantHairColorTextureG; static MObject mutantHairColorTextureB; static MObject neverBeenInstanced; static MObject outputMesh; static MObject renderStateAttr; static MObject ribDumper; static MObject ribInsert; static MObject runDynamics; static MObject rootHairColorTexture; static MObject rootHairColorTextureR; static MObject rootHairColorTextureG; static MObject rootHairColorTextureB; static MObject shaveBlindHair; static MObject shaveBlindState; static MObject shaveInfo; static MObject shaveParamAmbDiff; // slider 6 static MObject shaveParamAnimSpeed; // slider 33 static MObject shaveParamCollide; static MObject shaveParamCollisionMethod; static MObject shaveParamDampening; // slider 40 static MObject shaveParamDensity; // slider 28 static MObject shaveParamDisplacement; // slider 43 static MObject shaveParamFrizzAnimDir; static MObject shaveParamFrizzAnimDirX; static MObject shaveParamFrizzAnimDirY; static MObject shaveParamFrizzAnimDirZ; static MObject shaveParamFrizzAnim; // slider 32 static MObject shaveParamFrizzFreqX; // slider 1 static MObject shaveParamFrizzFreqY; // slider 30 static MObject shaveParamFrizzFreqZ; // slider 31 static MObject shaveParamFrizzRoot; // slider 0 static MObject shaveParamFrizzTip; // slider 24 static MObject shaveParamGeomShadow; static MObject shaveParamGloss; // slider 5 static MObject shaveParamGravity; static MObject shaveParamHairColor; static MObject shaveParamHairRed; // slider 9 static MObject shaveParamHairGreen; // slider 10 static MObject shaveParamHairBlue; // slider 11 static MObject shaveParamHaircount; static MObject shaveParamHueVariation; // slider 12 static MObject shaveParamInstancingStatus; static MObject shaveParamKinkFreqX; // slider 3 static MObject shaveParamKinkFreqY; // slider 34 static MObject shaveParamKinkFreqZ; // slider 35 static MObject shaveParamKinkRoot; // slider 38 static MObject shaveParamKinkTip; // slider 2 static MObject shaveParamMultStrand; // slider 25 static MObject shaveParamMutantColor; static MObject shaveParamMutantRed; // slider 13 static MObject shaveParamMutantGreen; // slider 14 static MObject shaveParamMutantBlue; // slider 15 static MObject shaveParamMutantPercent; // slider 16 static MObject shaveParamNoInterp; static MObject shaveParamPainted; static MObject shaveParamPasses; static MObject shaveParamRandScale; // slider 36 static MObject shaveParamRandomizeMulti; // slider 42 static MObject shaveParamRootColor; static MObject shaveParamRootRed; // slider 17 static MObject shaveParamRootGreen; // slider 18 static MObject shaveParamRootBlue; // slider 19 static MObject shaveParamRootStiffness; // slider 21 static MObject shaveParamScale; // slider 41 static MObject shaveParamSegs; static MObject shaveParamSelfShadow; // slider 7 static MObject shaveParamSpecular; // slider 4 static MObject shaveParamSplayRoot; // slider 26 static MObject shaveParamSplayTip; // slider 27 static MObject shaveParamMultAsp; // slider 44 - vlad|05July2010 static MObject shaveParamOffset; // slider 45 - vlad|09July2010 static MObject shaveParamAspect; // slider 46 - vlad|09July2010 static MObject shaveParamStiffness; // slider 8 static MObject shaveParamThickRoot; // slider 20 static MObject shaveParamThickTip; // slider 37 static MObject shaveParamTotalGuides; static MObject shaveParamValueVariation; // slider 39 static MObject shaveTexMutantColor; static MObject shaveTextureAttr; static MObject surfTessU; static MObject surfTessV; static MObject subdTessDept; static MObject subdTessSamp; static MObject textureCacheUpdatedAttr; static MObject timeAttr; static MObject triggerAttr; static MObject overrideGeomShaderAttr; static MObject uvSetAssignmentsAttr; static MObject uvSetNameAttr; static MObject uvSetTexturesAttr; static MObject flyawayPerc; static MObject flyawayStren; static MObject messStren; static MObject clumps; static MObject clumpsStren; static MObject clumpsColStren; static MObject clumpsRotStren; static MObject clumpsRotOffset; static MObject clumpsRandomize; static MObject clumpsFlatness; static MObject clumpsScruffle; static MObject procedural; static MObject randomSeedOffset; static MObject versionLockAttr; // Deprecated Attributes static MObject displayHairMaxAttr; static MObject displayHairRatioAttr; // moved to shave globals static MObject shaveParamsDisplaceStren; private: #ifdef REUSABLE_THREADS LThreadGroup* m_lthGrp; #endif }; inline int shaveHairShape::getMaxShaveID() { return mNextShaveID - 1; } inline int shaveHairShape::getShaveID() const { return mShaveID; } //vlad|06Apr2010 -- replaced by 'stackIndex' attribute //inline int shaveHairShape::getStackIndex() const //{ return mStackIndex; } inline bool shaveHairShape::isCurrent() const { return ((int)SHAVEquery_shave_ID() == getShaveID()); } inline bool shaveHairShape::isInstanced() const { return mIsInstanced; } inline bool shaveHairShape::nodeIsInitialized() const { return mNodeInitialized; } inline MStatus shaveHairShape::setCollisionList(const MSelectionList& list) { return setGeomList(aCollisionSet, list); } inline MStatus shaveHairShape::setGrowthList(const MSelectionList& list) { return setGeomList(aGrowthSet, list); } //vlad|06Apr2010 -- replaced by 'stackIndex' attribute //inline void shaveHairShape::setStackIndex(int index) //{ mStackIndex = index; } // // plugin.cpp has callbacks which keep track of shaveHairShape additions & // deletions. The actual count is maintained by the following methods. // // Now you might wonder why this class doesn't keep track of the count // itself, using its constructor and destructor. Unfortunately that won't // work because if a node is deleted in Maya, it's constructor doesn't get // called until the undo queue is flushed. Similarly, if a deletion is // undone, it will not result in a new node being created, so the // constructor won't be called. // inline void shaveHairShape::nodeAdded() { numShaveNodes++; } inline void shaveHairShape::nodeRemoved() { numShaveNodes--; } inline int shaveHairShape::getNumShaveNodes() { return numShaveNodes; } #endif