//--------------------------------------------------- MPlug DagHelper::getChildPlug ( const MPlug& parent, const MString& name, MStatus* rc ) { MStatus st; uint childCount = parent.numChildren ( &st ); if ( st != MStatus::kSuccess ) { if ( rc != NULL ) *rc = st; return parent; } // Check shortNames first for ( uint i = 0; i < childCount; ++i ) { MPlug child = parent.child ( i, &st ); if ( st != MStatus::kSuccess ) { if ( rc != NULL ) *rc = st; return parent; } MFnAttribute attributeFn ( child.attribute() ); MString n = attributeFn.shortName(); if ( n == name ) { if ( rc != NULL ) *rc = MStatus::kSuccess; return child; } } // Check longNames second, use shortNames! for ( uint i = 0; i < childCount; ++i ) { MPlug child = parent.child ( i, &st ); if ( st != MStatus::kSuccess ) { if ( rc != NULL ) *rc = st; return parent; } MFnAttribute attributeFn ( child.attribute() ); MString n = attributeFn.name(); if ( n == name ) { if ( rc != NULL ) *rc = MStatus::kSuccess; return child; } } if ( rc != NULL ) *rc = MStatus::kNotFound; return parent; }
virtual void onString(MPlug & plug, const MString & name, const MString & value) override { MStatus status; MObject attr = plug.attribute(&status); if (!status) return; if (value.length() == 0) return; bool isUsedAsFilename = MFnAttribute(attr).isUsedAsFilename(&status); if (!status) return; // Filename are treated as texture filenames. if (isUsedAsFilename) { // Export texture mShaderFXExporter.exportTexture(value); } else { // Export string ScopedElement string(mShaderFXExporter.mStreamWriter, PARAM_TYPE_STRING); mShaderFXExporter.mStreamWriter.appendText(value.asChar()); } }
ATTR_TYPE getPlugAttrType(const char *plugName, MFnDependencyNode& dn) { MDGContext ctx = MDGContext::fsNormal; MStatus stat = MS::kSuccess; MPlug plug = dn.findPlug(plugName, &stat); if( !stat ) return ATTR_TYPE::ATTR_TYPE_NONE; MObject attObj = plug.attribute(&stat); MFnAttribute att(attObj); if( !stat ) return ATTR_TYPE::ATTR_TYPE_NONE; if(att.isUsedAsColor()) return ATTR_TYPE::ATTR_TYPE_COLOR; if( attObj.apiType() == MFn::kNumericAttribute) { MFnNumericAttribute na(attObj, &stat); if( !stat ) return ATTR_TYPE::ATTR_TYPE_NONE; if( na.unitType() == MFnNumericData::Type::kFloat ) return ATTR_TYPE::ATTR_TYPE_FLOAT; } return ATTR_TYPE::ATTR_TYPE_NONE; }
MStatus simpleFluidEmitter::compute(const MPlug& plug, MDataBlock& block) // // Description: // // Fluid emitters do not perform emission in their compute() method. // Instead, each fluid to which the emitter is connected will call the // fluidEmitter() method once per frame, to allow the emitter to emit // directly into the fluid. // // It is ESSENTIAL that the compute routine return MS::kUnknownParameter // when the "emissionFunction" attribute is being evaluated. Doing so // will trigger the base class default compute() method, which will // register this node's "fluidEmitter" function with the fluid. The // mechanisms for doing this are not exposed through the API, so it is // important to let the default code handle this case. // // For all other attributes, users can override the compute() method. // { if( plug.attribute() == mEmissionFunction ) { // ESSENTIAL! Let the base class default compute method handle this // return MS::kUnknownParameter; } else { // can add custom handling for other attributes here // return MS::kUnknownParameter; } }
virtual bool onBeforePlug(MPlug & plug) override { MStatus status; MObject attr = plug.attribute(&status); if (!status) return false; MFnAttribute fnAttr(attr, &status); if (!status) return false; MString attrName = fnAttr.name(&status); if (!status) return false; bool isDynamic = fnAttr.isDynamic(&status); if (!status) return false; if (!isDynamic) return false; bool isHidden = fnAttr.isHidden(&status); if (!status) return false; if (isHidden) return false; return true; }
void NuiMayaDeviceGrabber::attrChangedCB(MNodeMessage::AttributeMessage msg, MPlug & plug, MPlug & otherPlug, void* clientData) { NuiMayaDeviceGrabber *wrapper = static_cast<NuiMayaDeviceGrabber *>(clientData); if(!wrapper) return; MStatus stat; MObject attr = plug.attribute(&stat); MFnAttribute fnAttr(attr); if (fnAttr.name() == "deviceOn" || fnAttr.name() == "deviceMode" ) { wrapper->updateDevice(); } else if (fnAttr.name() == "nearMode") { wrapper->updateNearMode(); } else if (fnAttr.name() == "elevationAngle") { wrapper->updateaElevationAngle(); } else if (fnAttr.name() == "previewerOn") { wrapper->updatePreviewer(); } else if (fnAttr.name() == "fusionOn") { wrapper->updateKinfu(); } }
MStatus ColorSplineParameterHandler<S>::doUpdate( IECore::ConstParameterPtr parameter, MPlug &plug ) const { assert( parameter ); typename IECore::TypedParameter< S >::ConstPtr p = IECore::runTimeCast<const IECore::TypedParameter< S > >( parameter ); if( !p ) { return MS::kFailure; } MObject attribute = plug.attribute(); MFnCompoundAttribute fnCAttr( attribute ); if( !fnCAttr.hasObj( attribute ) ) { return MS::kFailure; } MRampAttribute fnRAttr( plug ); if( !fnRAttr.isColorRamp() ) { return MS::kFailure; } return finishUpdating( parameter, plug ); }
UsdAttribute PxrUsdMayaWriteUtil::GetOrCreateUsdAttr( const MPlug& plg, const UsdPrim& usdPrim, const std::string &attrName, bool custom) { MObject attrObj(plg.attribute()); TfToken usdAttrName(attrName); if (usdAttrName.IsEmpty()) { printf("Invalid attrName '%s' for %s\n", attrName.c_str(), plg.name().asChar()); return UsdAttribute(); } // See if usdAttr already exists. If so, return. UsdAttribute usdAttr = usdPrim.GetAttribute(usdAttrName); if (usdAttr) { return usdAttr; } SdfValueTypeName attrType = PxrUsdMayaWriteUtil::GetUsdTypeName(plg); // --------------------- // CreateAttribute on USD Prim if specified above if (attrType) { usdAttr = usdPrim.CreateAttribute(usdAttrName, attrType, custom); } else { // Skipping. Unsupported type. } return usdAttr; }
MStatus ClassParameterHandler::storeClass( IECore::ConstParameterPtr parameter, MPlug &plug ) { IECorePython::ScopedGILLock gilLock; try { boost::python::object pythonParameter( IECore::constPointerCast<IECore::Parameter>( parameter ) ); boost::python::object classInfo = pythonParameter.attr( "getClass" )( true ); std::string className = boost::python::extract<std::string>( classInfo[1] ); int classVersion = boost::python::extract<int>( classInfo[2] ); std::string searchPathEnvVar = boost::python::extract<std::string>( classInfo[3] ); MString storedClassName; int storedClassVersion; MString storedSearchPathEnvVar; currentClass( plug, storedClassName, storedClassVersion, storedSearchPathEnvVar ); // only set the plug values if the new value is genuinely different, as otherwise // we end up generating unwanted reference edits. if ( storedClassName != className.c_str() || storedClassVersion != classVersion || storedSearchPathEnvVar != searchPathEnvVar.c_str() ) { MStringArray updatedClassInfo; updatedClassInfo.append( className.c_str() ); MString classVersionStr; classVersionStr.set( classVersion, 0 ); updatedClassInfo.append( classVersionStr ); updatedClassInfo.append( searchPathEnvVar.c_str() ); MObject attribute = plug.attribute(); MFnTypedAttribute fnTAttr( attribute ); if ( fnTAttr.attrType() == MFnData::kStringArray ) { MObject data = MFnStringArrayData().create( updatedClassInfo ); plug.setValue( data ); } else { // compatibility for the deprecated compound plug behaviour. keeping this code // so we can still read old scenes. creation of these plugs has been removed. /// \todo: find all such notes and remove the unnecessary code for Cortex 9. plug.child( 0 ).setString( className.c_str() ); plug.child( 1 ).setInt( classVersion ); plug.child( 2 ).setString( searchPathEnvVar.c_str() ); } } } catch( boost::python::error_already_set ) { PyErr_Print(); return MS::kFailure; } catch( const std::exception &e ) { MGlobal::displayError( MString( "ClassParameterHandler::setClass : " ) + e.what() ); return MS::kFailure; } return MS::kSuccess; }
MStatus ObjectParameterHandler::doSetValue( const MPlug &plug, IECore::ParameterPtr parameter ) const { IECore::ObjectParameterPtr p = IECore::runTimeCast<IECore::ObjectParameter>( parameter ); if( !p ) { return MS::kFailure; } /// Keep trying all the available handlers until we find one that works for (IECore::ObjectParameter::TypeIdSet::const_iterator it = p->validTypes().begin(); it != p->validTypes().end(); ++it) { ConstParameterHandlerPtr h = ParameterHandler::create( *it ); if (h) { if ( h->doSetValue( plug, parameter ) ) { return MS::kSuccess; } } } MStatus s; MObject plugData; s = plug.getValue( plugData ); if (!s) { // We might be here as the attribute isn't storable, // in that case we set the parameter to its default value. // If it is storable, then something has gone awry. MFnAttribute fnA( plug.attribute() ); bool isStorable = fnA.isStorable( &s ); if( s && !isStorable ) { parameter->setValue( parameter->defaultValue()->copy() ); return MS::kSuccess; } else { return MS::kFailure; } } MFnPluginData fnData( plugData, &s ); if (!s) { return MS::kFailure; } ObjectData *data = dynamic_cast<ObjectData *>( fnData.data( &s ) ); if (!data || !s) { return MS::kFailure; } parameter->setValue( data->getObject() ); return MS::kSuccess; }
//--------------------------------------------------- int DagHelper::getChildPlugIndex ( const MPlug& parent, const MString& name, MStatus* rc ) { MStatus st; uint childCount = parent.numChildren ( &st ); CHECK_STATUS_AND_RETURN ( st, -1 ); // Check shortNames first for ( uint i = 0; i < childCount; ++i ) { MPlug child = parent.child ( i, &st ); CHECK_STATUS_AND_RETURN ( st, -1 ); MFnAttribute attributeFn ( child.attribute() ); MString n = attributeFn.shortName(); if ( n == name ) { if ( rc != NULL ) *rc = MStatus::kSuccess; return i; } } // Check longNames second, use shortNames! for ( uint i = 0; i < childCount; ++i ) { MPlug child = parent.child ( i, &st ); CHECK_STATUS_AND_RETURN ( st, -1 ); MFnAttribute attributeFn ( child.attribute() ); MString n = attributeFn.name(); if ( n == name ) { if ( rc != NULL ) *rc = MStatus::kSuccess; return i; } } if ( rc != NULL ) *rc = MStatus::kNotFound; return -1; }
/* static */ UsdAttribute PxrUsdMayaWriteUtil::GetOrCreateUsdRiAttribute( const MPlug& attrPlug, const UsdPrim& usdPrim, const std::string& attrName, const std::string& nameSpace, const bool translateMayaDoubleToUsdSinglePrecision) { UsdAttribute usdAttr; if (!usdPrim) { return usdAttr; } MObject attrObj(attrPlug.attribute()); TfToken riAttrNameToken(attrName); if (riAttrNameToken.IsEmpty()) { MGlobal::displayError( TfStringPrintf("Invalid UsdRi attribute name '%s' for Maya plug '%s'", attrName.c_str(), attrPlug.name().asChar()).c_str()); return usdAttr; } UsdRiStatements riStatements(usdPrim); if (!riStatements) { return usdAttr; } // See if a UsdRi attribute with this name already exists. If so, return it. // XXX: There isn't currently API for looking for a specific UsdRi attribute // by name, so we have to get them all and then see if one matches. const std::vector<UsdProperty>& riAttrs = riStatements.GetRiAttributes(nameSpace); TF_FOR_ALL(iter, riAttrs) { if (iter->GetBaseName() == riAttrNameToken) { // Re-get the attribute from the prim so we can return it as a // UsdAttribute rather than a UsdProperty. return usdPrim.GetAttribute(iter->GetName()); } } const SdfValueTypeName& typeName = PxrUsdMayaWriteUtil::GetUsdTypeName(attrPlug, translateMayaDoubleToUsdSinglePrecision); if (typeName) { usdAttr = riStatements.CreateRiAttribute(riAttrNameToken, typeName.GetType(), nameSpace); } return usdAttr; }
//********************************************************* // Name: isEnumDataType // Desc: //********************************************************* bool BreakdownCommand::isEnumDataType(const MPlug &connection) { MObject attrObj; bool isEnum = false; attrObj = connection.attribute( &status ); if( attrObj.apiType() == MFn::kEnumAttribute ) { isEnum = true; } return isEnum; }
MPlug FxInternal::GetValuePlug(MPlug& plug) { MFnDependencyNode depNode(GetSite()); MObject oAttribute = plug.attribute(); MFnAttribute fnAttribute(oAttribute); MString name = fnAttribute.name() + MString("Value"); oAttribute= depNode.attribute(name); return plug.child(oAttribute); }
MStatus ParameterisedHolder<B>::shouldSave( const MPlug &plug, bool &isSaving ) { ParameterPtr parameter = plugParameter( plug ); if( parameter ) { // For parameters we found in the parameter map, we always handle // them ourselves, setting isSaving to either true or false, // and returning kSuccess, which means "Ignore the default behaviour" // There is no particular reason not use the standard behaviour // of calling the parent shouldSave, but instead we set isSaving // to always true and store our parm_ attributes even when they // are at default values. This is because it used to work that way // for all parms, and Lucio is concerned that changing this // could break something isSaving = true; /// Maya 8.5 and 2009 crash when saving a GenericAttribute (such as that /// created by the MeshParameterHandler) containing an "empty" mesh. /// This only applies to ASCII files, saving to binary works. Here /// we prevent Maya saving the value. MFnGenericAttribute fnGA; if( fnGA.hasObj( plug.attribute() ) ) { MObject value = plug.asMObject(); MFnMesh fnMesh( value ); if( fnMesh.hasObj( value ) && fnMesh.numPolygons()==0 ) { isSaving = false; } } return MS::kSuccess; } else { // For parameters that aren't special, use the default behaviour of // the base class. // NOTE: This is not very clear in the documentation, but for most // parameters, the default behaviour is to not touch isSaving, // and return kUnknownParameter, which Maya interprets as meaning // that we're not doing anything special, so use the default // behaviour. Maya then checks whether the plug has changed from // default, and exports it if it has return B::shouldSave( plug, isSaving ); } }
//********************************************************* // Name: isBooleanDataType // Desc: //********************************************************* bool BreakdownCommand::isBooleanDataType( const MPlug &connection ) { MFnNumericAttribute fnNumAttr; MObject attrObj; bool isBool = false; attrObj = connection.attribute( &status ); if( attrObj.apiType() == MFn::kNumericAttribute ) { status = fnNumAttr.setObject( attrObj ); if( fnNumAttr.unitType() == MFnNumericData::kBoolean ) isBool = true; } return isBool; }
/* static */ UsdGeomPrimvar PxrUsdMayaWriteUtil::GetOrCreatePrimvar( const MPlug& attrPlug, UsdGeomImageable& imageable, const std::string& primvarName, const TfToken& interpolation, const int elementSize, const bool custom, const bool translateMayaDoubleToUsdSinglePrecision) { UsdGeomPrimvar primvar; if (!imageable) { return primvar; } MObject attrObj(attrPlug.attribute()); TfToken primvarNameToken(primvarName); if (primvarNameToken.IsEmpty()) { MGlobal::displayError( TfStringPrintf("Invalid primvar name '%s' for Maya plug '%s'", primvarName.c_str(), attrPlug.name().asChar()).c_str()); return primvar; } // See if the primvar already exists. If so, return it. primvar = imageable.GetPrimvar(primvarNameToken); if (primvar) { return primvar; } const SdfValueTypeName& typeName = PxrUsdMayaWriteUtil::GetUsdTypeName(attrPlug, translateMayaDoubleToUsdSinglePrecision); if (typeName) { primvar = imageable.CreatePrimvar(primvarNameToken, typeName, interpolation, elementSize, custom); } return primvar; }
PXR_NAMESPACE_OPEN_SCOPE static bool _GetMayaAttributeNumericTypedAndUnitDataTypes( const MPlug& attrPlug, MFnNumericData::Type& numericDataType, MFnData::Type& typedDataType, MFnUnitAttribute::Type& unitDataType) { numericDataType = MFnNumericData::kInvalid; typedDataType = MFnData::kInvalid; unitDataType = MFnUnitAttribute::kInvalid; MObject attrObj(attrPlug.attribute()); if (attrObj.isNull()) { return false; } if (attrObj.hasFn(MFn::kNumericAttribute)) { MFnNumericAttribute numericAttrFn(attrObj); numericDataType = numericAttrFn.unitType(); } else if (attrObj.hasFn(MFn::kTypedAttribute)) { MFnTypedAttribute typedAttrFn(attrObj); typedDataType = typedAttrFn.attrType(); if (typedDataType == MFnData::kNumeric) { // Inspect the type of the data itself to find the actual type. MObject plugObj = attrPlug.asMObject(); if (plugObj.hasFn(MFn::kNumericData)) { MFnNumericData numericDataFn(plugObj); numericDataType = numericDataFn.numericType(); } } } else if (attrObj.hasFn(MFn::kUnitAttribute)) { MFnUnitAttribute unitAttrFn(attrObj); unitDataType = unitAttrFn.unitType(); } return true; }
bool getEnum(MString& plugName, MFnDependencyNode& dn, int& id, MString& value) { MDGContext ctx = MDGContext::fsNormal; MStatus stat = MS::kSuccess; bool result = false; MPlug plug = dn.findPlug(plugName, &stat); if( !stat ) return false; id = plug.asShort(ctx, &stat); if(!stat) return false; MFnEnumAttribute eAttr(plug.attribute(&stat)); if(!stat) return false; value = eAttr.fieldName(id, &stat); if(!stat) return false; return true; }
MString getEnumString(MString plugName, MFnDependencyNode& dn) { MDGContext ctx = MDGContext::fsNormal; MStatus stat = MS::kSuccess; bool result = false; MPlug plug = dn.findPlug(plugName, &stat); if (!stat) return ""; int id = plug.asShort(ctx, &stat); if (!stat) return ""; MFnEnumAttribute eAttr(plug.attribute(&stat)); if (!stat) return ""; MString value = eAttr.fieldName(id, &stat); if (!stat) return ""; return value; }
virtual void onString(MPlug & plug, const MString & name, const MString & value) override { MStatus status; if (value.length() == 0) return; MObject attr = plug.attribute(&status); if (!status) return; bool isUsedAsFilename = MFnAttribute(attr).isUsedAsFilename(&status); if (!status) return; // Filename are treated as texture filenames. if (!isUsedAsFilename) return; mShaderFXExporter.exportSamplerAndSurfaceInner(value); }
//--------------------------------------------------- bool DagHelper::getPlugValue(const MPlug& plug, int& enumValue, MString& enumName) { MStatus status; MObject attr; attr = plug.attribute(&status); if (!status) return false; MFnEnumAttribute fnEnum(attr, &status); if (!status) return false; status = plug.getValue(enumValue); if (!status) return false; enumName = fnEnum.fieldName(enumValue, &status); if (!status) return status; return true; }
/* static */ UsdAttribute PxrUsdMayaWriteUtil::GetOrCreateUsdAttr( const MPlug& attrPlug, const UsdPrim& usdPrim, const std::string& attrName, const bool custom, const bool translateMayaDoubleToUsdSinglePrecision) { UsdAttribute usdAttr; if (!usdPrim) { return usdAttr; } MObject attrObj(attrPlug.attribute()); TfToken usdAttrNameToken(attrName); if (usdAttrNameToken.IsEmpty()) { MGlobal::displayError( TfStringPrintf("Invalid USD attribute name '%s' for Maya plug '%s'", attrName.c_str(), attrPlug.name().asChar()).c_str()); return usdAttr; } // See if the USD attribute already exists. If so, return it. usdAttr = usdPrim.GetAttribute(usdAttrNameToken); if (usdAttr) { return usdAttr; } const SdfValueTypeName& typeName = PxrUsdMayaWriteUtil::GetUsdTypeName(attrPlug, translateMayaDoubleToUsdSinglePrecision); if (typeName) { usdAttr = usdPrim.CreateAttribute(usdAttrNameToken, typeName, custom); } return usdAttr; }
MStatus DateTimeParameterHandler::doUpdate( IECore::ConstParameterPtr parameter, MPlug &plug ) const { IECore::ConstDateTimeParameterPtr p = IECore::runTimeCast<const IECore::DateTimeParameter>( parameter ); if( !p ) { return MS::kFailure; } MObject attribute = plug.attribute(); // we'd like to be setting the default value here, but as maya doesn't save the default value // for dynamic string attributes in scene files, it'll be lost when the scene is reloaded. it's // best therefore that we don't set the default at all, so that the default is "", which is what // it'll be when we reload the scene - this ensures that any values set in the attribute later // will be saved correctly (if we set the default to "X" and the value was "X", maya won't save the // default or the value at all, and we end up with a value of "" on scene reload). MFnTypedAttribute fnTAttr( attribute ); if( !fnTAttr.hasObj( attribute ) || fnTAttr.attrType() != MFnData::kString ) { return MS::kFailure; } // Should this fail if getPlugValue fails? MString v = ""; if( plug.getValue( v ) ) { try { boost::posix_time::from_iso_string( v.asChar() ); } catch ( boost::bad_lexical_cast ) { return MS::kFailure; } } return finishUpdating( parameter, plug ); }
void ClassParameterHandler::currentClass( const MPlug &plug, MString &className, int &classVersion, MString &searchPathEnvVar ) { MObject attribute = plug.attribute(); MFnTypedAttribute fnTAttr( attribute ); if ( !fnTAttr.hasObj( attribute ) || fnTAttr.attrType() != MFnData::kStringArray ) { // compatibility for the deprecated compound plug behaviour className = plug.child( 0 ).asString(); classVersion = plug.child( 1 ).asInt(); searchPathEnvVar = plug.child( 2 ).asString(); return; } MFnStringArrayData fnSAD( plug.asMObject() ); if ( fnSAD.length() == 0 ) { className = ""; classVersion = 0; searchPathEnvVar = ""; return; } if ( fnSAD.length() != 3 ) { throw( IECore::InvalidArgumentException( ( plug.name() + " has more than 3 values. Expected name, version, searchPath only." ).asChar() ) ); } MStringArray storedClassInfo = fnSAD.array(); if ( !storedClassInfo[1].isInt() ) { throw( IECore::InvalidArgumentException( ( "Second value of " + plug.name() + " must represent an integer" ).asChar() ) ); } className = storedClassInfo[0]; classVersion = storedClassInfo[1].asInt(); searchPathEnvVar = storedClassInfo[2]; }
MStatus ObjectParameterHandler::doUpdate( IECore::ConstParameterPtr parameter, MPlug &plug ) const { IECore::ConstObjectParameterPtr p = IECore::runTimeCast<const IECore::ObjectParameter>( parameter ); if( !p ) { return MS::kFailure; } MObject attribute = plug.attribute(); MFnGenericAttribute fnGAttr( attribute ); if( !fnGAttr.hasObj( attribute ) ) { return MS::kFailure; } fnGAttr.addAccept( ObjectData::id ); // maya has an odd behaviour whereby a generic attribute with only one accepted datatype will // transform itself into a typed attribute after file save and load. here we add an accept // for a second dummy datatype to ensure that the attribute will still be a generic attribute // when saved and loaded. fnGAttr.addAccept( DummyDataId ); for (IECore::ObjectParameter::TypeIdSet::const_iterator it = p->validTypes().begin(); it != p->validTypes().end(); ++it) { ConstParameterHandlerPtr h = ParameterHandler::create( *it ); if (h) { if ( !h->doUpdate( parameter, plug ) ) { return MS::kFailure; } } } return finishUpdating( parameter, plug ); }
MStatus MeshParameterHandler::doUpdate( IECore::ConstParameterPtr parameter, MPlug &plug ) const { IECore::ConstObjectParameterPtr p = IECore::runTimeCast<const IECore::ObjectParameter>( parameter ); if( !p ) { return MS::kFailure; } MObject attribute = plug.attribute(); MFnGenericAttribute fnGAttr( attribute ); if( !fnGAttr.hasObj( attribute ) ) { return MS::kFailure; } fnGAttr.addAccept( MFnData::kMesh ); // maya has an odd behaviour whereby a generic attribute with only one accepted datatype will // transform itself into a typed attribute after file save and load. here we add an accept // for a second dummy datatype to ensure that the attribute will still be a generic attribute // when saved and loaded. fnGAttr.addAccept( DummyDataId ); return finishUpdating( parameter, plug ); }
//for this attribute on this node add the following layer nodes and plugs it's associated with void atomNodeWithAnimLayers::addPlugWithLayer(MPlug &attrPlug, MObjectArray &layers, MPlugArray &plugs) { if(plugs.length() == layers.length()) { MObject attrObj = attrPlug.attribute(); MFnAttribute fnLeafAttr (attrObj); std::string attrStd(std::string(fnLeafAttr.name().asChar())); PlugsAndLayers plugsAndLayers; for(unsigned int i =0; i < layers.length(); ++i) { if(plugs[i].isNull()==false) //it's possible to not have a plug for the specified layer { if(layers[i].hasFn (MFn::kDependencyNode)) { MFnDependencyNode fnNode (layers[i]); MString layerName = fnNode.name(); plugsAndLayers.mLayerNames.append(layerName); plugsAndLayers.mPlugs.append(plugs[i]); fAttrLayers[attrStd] = plugsAndLayers; } } } } }
MStatus sseDeformer::compute(const MPlug& plug, MDataBlock& data) { MStatus status; if (plug.attribute() != outputGeom) { printf("Ignoring requested plug\n"); return status; } unsigned int index = plug.logicalIndex(); MObject thisNode = this->thisMObject(); // get input value MPlug inPlug(thisNode,input); inPlug.selectAncestorLogicalIndex(index,input); MDataHandle hInput = data.inputValue(inPlug, &status); MCheckStatus(status, "ERROR getting input mesh\n"); // get the input geometry MDataHandle inputData = hInput.child(inputGeom); if (inputData.type() != MFnData::kMesh) { printf("Incorrect input geometry type\n"); return MStatus::kFailure; } MObject iSurf = inputData.asMesh() ; MFnMesh inMesh; inMesh.setObject( iSurf ) ; MDataHandle outputData = data.outputValue(plug); outputData.copy(inputData); if (outputData.type() != MFnData::kMesh) { printf("Incorrect output mesh type\n"); return MStatus::kFailure; } MObject oSurf = outputData.asMesh() ; if(oSurf.isNull()) { printf("Output surface is NULL\n"); return MStatus::kFailure; } MFnMesh outMesh; outMesh.setObject( oSurf ) ; MCheckStatus(status, "ERROR setting points\n"); // get all points at once for demo purposes. Really should get points from the current group using iterator MFloatPointArray pts; outMesh.getPoints(pts); int nPoints = pts.length(); MDataHandle envData = data.inputValue(envelope, &status); float env = envData.asFloat(); MDataHandle sseData = data.inputValue(sseEnabled, &status); bool sseEnabled = (bool) sseData.asBool(); // NOTE: Using MTimer and possibly other classes disables // autovectorization with Intel <=10.1 compiler on OSX and Linux!! // Must compile this function with -fno-exceptions on OSX and // Linux to guarantee autovectorization is done. Use -fvec_report2 // to check for vectorization status messages with Intel compiler. MTimer timer; timer.beginTimer(); if(sseEnabled) { // Innter loop will autovectorize. Around 3x faster than the // loop below it. It would be faster if first element was // guaranteed to be aligned on 16 byte boundary. for(int i=0; i<nPoints; i++) { float* ptPtr = &pts[i].x; for(int j=0; j<4; j++) { ptPtr[j] = env * (cosf(ptPtr[j]) * sinf(ptPtr[j]) * tanf(ptPtr[j])); } } } else { // This inner loop will not autovectorize. for(int i=0; i<nPoints; i++) { MFloatPoint& pt = pts[i]; for(int j=0; j<3; j++) { pt[j] = env * (cosf(pt[j]) * sinf(pt[j]) * tanf(pt[j])); } } } timer.endTimer(); if(sseEnabled) { printf("SSE enabled, runtime %f\n", timer.elapsedTime()); } else { printf("SSE disabled, runtime %f\n", timer.elapsedTime()); } outMesh.setPoints(pts); return status; }
// does this cover all cases? bool util::isAnimated(MObject & object, bool checkParent) { MStatus stat; MItDependencyGraph iter(object, MFn::kInvalid, MItDependencyGraph::kUpstream, MItDependencyGraph::kDepthFirst, MItDependencyGraph::kPlugLevel, &stat); if (stat!= MS::kSuccess) { MGlobal::displayError("Unable to create DG iterator "); } // MAnimUtil::isAnimated(node) will search the history of the node // for any animation curve nodes. It will return true for those nodes // that have animation curve in their history. // The average time complexity is O(n^2) where n is the number of history // nodes. But we can improve the best case by split the loop into two. std::vector<NodesToCheckStruct> nodesToCheckAnimCurve; NodesToCheckStruct nodeStruct; for (; !iter.isDone(); iter.next()) { MObject node = iter.thisNode(); if (node.hasFn(MFn::kPluginDependNode) || node.hasFn( MFn::kConstraint ) || node.hasFn(MFn::kPointConstraint) || node.hasFn(MFn::kAimConstraint) || node.hasFn(MFn::kOrientConstraint) || node.hasFn(MFn::kScaleConstraint) || node.hasFn(MFn::kGeometryConstraint) || node.hasFn(MFn::kNormalConstraint) || node.hasFn(MFn::kTangentConstraint) || node.hasFn(MFn::kParentConstraint) || node.hasFn(MFn::kPoleVectorConstraint) || node.hasFn(MFn::kParentConstraint) || node.hasFn(MFn::kTime) || node.hasFn(MFn::kJoint) || node.hasFn(MFn::kGeometryFilt) || node.hasFn(MFn::kTweak) || node.hasFn(MFn::kPolyTweak) || node.hasFn(MFn::kSubdTweak) || node.hasFn(MFn::kCluster) || node.hasFn(MFn::kFluid) || node.hasFn(MFn::kPolyBoolOp)) { return true; } if (node.hasFn(MFn::kExpression)) { MFnExpression fn(node, &stat); if (stat == MS::kSuccess && fn.isAnimated()) { return true; } } MPlug plug = iter.thisPlug(); MFnAttribute attr(plug.attribute(), &stat); bool checkNodeParent = false; if (stat == MS::kSuccess && attr.isWorldSpace()) { checkNodeParent = true; } nodeStruct.node = node; nodeStruct.checkParent = checkNodeParent; nodesToCheckAnimCurve.push_back(nodeStruct); } for (size_t i = 0; i < nodesToCheckAnimCurve.size(); ++i) { if (MAnimUtil::isAnimated(nodesToCheckAnimCurve[i].node, nodesToCheckAnimCurve[i].checkParent)) { return true; } } return false; }