//- // ========================================================================== // Copyright (C) 1995 - 2006 Autodesk, Inc. and/or its licensors. All // rights reserved. // // The coded instructions, statements, computer programs, and/or related // material (collectively the "Data") in these files contain unpublished // information proprietary to Autodesk, Inc. ("Autodesk") and/or its // licensors, which is protected by U.S. and Canadian federal copyright // law and by international treaties. // // The Data is provided for use exclusively by You. You have the right // to use, modify, and incorporate this Data into other products for // purposes authorized by the Autodesk software license agreement, // without fee. // // The copyright notices in the Software and this entire statement, // including the above license grant, this restriction and the // following disclaimer, must be included in all copies of the // Software, in whole or in part, and all derivative works of // the Software, unless such copies or derivative works are solely // in the form of machine-executable object code generated by a // source language processor. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. // AUTODESK DOES NOT MAKE AND HEREBY DISCLAIMS ANY EXPRESS OR IMPLIED // WARRANTIES INCLUDING, BUT NOT LIMITED TO, THE WARRANTIES OF // NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR // PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE, OR // TRADE PRACTICE. IN NO EVENT WILL AUTODESK AND/OR ITS LICENSORS // BE LIABLE FOR ANY LOST REVENUES, DATA, OR PROFITS, OR SPECIAL, // DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES, EVEN IF AUTODESK // AND/OR ITS LICENSORS HAS BEEN ADVISED OF THE POSSIBILITY // OR PROBABILITY OF SUCH DAMAGES. // // ========================================================================== //+ // Example Plugin: stringFormatNode.cpp // // This plug-in is an example of a user-defined dependency graph node. // It takes several numbers as input, as well as a format string. It // generates a formatted string as an output. // // All occurences of ^[0-9][dft] are replaced with the corresponding // input parameter using the specified format. // // d means output as an integer. // f means output as a floating point value. // t means output as a timecode. // // For example, the string "format ^1f ^2d ^0t end format", using the // array {2.3, 3.4, 4.5} as an input will generate the result // "format 3.4 4 00:00:02 end format" // #include #include #include #include #include #include #include // The stringFormat class defines the attributes and methods necessary // for the stringFormatNode plugin // class stringFormat : public MPxNode { public: stringFormat(); virtual ~stringFormat(); virtual MStatus compute( const MPlug& plug, MDataBlock& data ); static void* creator(); static MStatus initialize(); public: static MTypeId id; // Unique node Id static MObject attrFormat; // Formatting string static MObject attrValues; // Input values (array) static MObject attrOutput; // Result }; MTypeId stringFormat::id( 0x81034 ); MObject stringFormat::attrFormat; MObject stringFormat::attrValues; MObject stringFormat::attrOutput; // The creator method creates an instance of the stringFormat class // and is the first method called by Maya when a stringFormat node // needs to be created. // void* stringFormat::creator() { return new stringFormat(); } // The initialize routine is called after the node has been created. // It sets up the input and output attributes and adds them to the // node. Finally the dependencies are arranged so that when the // inputs change Maya knowns to call compute to recalculate the output // value. // MStatus stringFormat::initialize() { MFnNumericAttribute numAttr; MFnTypedAttribute typedAttr; MFnStringData stringData; MStatus stat; MStatus stat2; // Setup the input attributes // attrFormat = typedAttr.create("format", "f", MFnData::kString, stringData.create(&stat2), &stat); CHECK_MSTATUS( stat2 ); CHECK_MSTATUS( stat ); CHECK_MSTATUS( typedAttr.setStorable( true ) ); CHECK_MSTATUS( typedAttr.setKeyable( true ) ); attrValues = numAttr.create("values", "v", MFnNumericData::kDouble, 0, &stat); CHECK_MSTATUS( stat ); CHECK_MSTATUS( numAttr.setArray( true ) ); CHECK_MSTATUS( numAttr.setReadable( false ) ); CHECK_MSTATUS( numAttr.setIndexMatters( true ) ); CHECK_MSTATUS( numAttr.setStorable( true ) ); CHECK_MSTATUS( numAttr.setKeyable( true ) ); attrOutput = typedAttr.create( "output", "o", MFnData::kString, stringData.create(&stat2), &stat); CHECK_MSTATUS( stat2 ); CHECK_MSTATUS( stat ); CHECK_MSTATUS( typedAttr.setWritable( false ) ); CHECK_MSTATUS( typedAttr.setStorable( false ) ); // Add the attributes to the node // CHECK_MSTATUS( addAttribute( attrFormat ) ); CHECK_MSTATUS( addAttribute( attrValues ) ); CHECK_MSTATUS( addAttribute( attrOutput ) ); // Set the attribute dependencies // CHECK_MSTATUS( attributeAffects( attrFormat, attrOutput ) ); CHECK_MSTATUS( attributeAffects( attrValues, attrOutput ) ); return MS::kSuccess; } // The constructor does nothing // stringFormat::stringFormat() {} // The destructor does nothing // stringFormat::~stringFormat() {} // The compute method is called by Maya when the input values // change and the output values need to be recomputed. // The input values are read then using sinf() and cosf() // the output values are stored on the output plugs. // // Look for ^[0-9][a-z] after the given index. Returns the position of // the characted just after '^' int findNextMatch(MString & string, int indx, int & param, char & letter) { // Warning this is not I18N compliant const char * str = string.asChar(); while (str[indx]) { if ((str[indx] == '^') && (str[indx+1] >= '0') && (str[indx+1] <= '9') && (str[indx+2] >= 'a') && (str[indx+1] <= 'z')) { param = str[indx+1] - '0'; letter = str[indx+2]; return indx+1; } indx++; } return -1; } MStatus stringFormat::compute (const MPlug& plug, MDataBlock& data) { MStatus status; // Check that the requested recompute is one of the output values // if (plug == attrOutput) { // Read the input values // MDataHandle inputData = data.inputValue (attrFormat, &status); CHECK_MSTATUS( status ); MString format = inputData.asString(); // Get input data handle, use outputArrayValue since we do not // want to evaluate all inputs, only the ones related to the // requested multiIndex. This is for efficiency reasons. // MArrayDataHandle vals = data.outputArrayValue(attrValues, &status); CHECK_MSTATUS( status ); int indx = 0; int param; char letter; while ((indx = findNextMatch(format, indx, param, letter)) > 0) { double val = 0.; status = vals.jumpToElement(param); if (status == MStatus::kSuccess) { MDataHandle thisVal = vals.inputValue( &status ); if (status == MStatus::kSuccess) { val = thisVal.asDouble(); } } MString replace; bool valid = false; switch (letter) { case 'd': // Integer val = floor(val+.5); // No break here case 'f': // Float replace.set(val); valid = true; break; case 't': // Timecode { const char * sign = ""; if (val<0) { sign = "-"; val = -val; } int valInt = (int)(val+.5); int sec = valInt / 24; int frame = valInt - sec * 24; int min = sec / 60; sec -= min * 60; int hour = min / 60; min -= hour * 60; char buffer[90]; if (hour>0) sprintf(buffer, "%s%d:%02d:%02d.%02d", sign, hour, min, sec, frame); else sprintf(buffer, "%s%02d:%02d.%02d", sign, min, sec, frame); replace = buffer; } valid = true; break; } if (valid) { format = format.substring(0, indx-2) + replace + format.substring(indx+2, format.length()-1); indx += replace.length() - 3; } } // Store the result // MDataHandle output = data.outputValue(attrOutput, &status ); CHECK_MSTATUS( status ); output.set( format ); } else { return MS::kUnknownParameter; } return MS::kSuccess; } // The initializePlugin method is called by Maya when the plugin is // loaded. It registers the node and the UI. // MStatus initializePlugin ( MObject obj ) { MStatus status; MFnPlugin plugin( obj, PLUGIN_COMPANY, "8.0", "Any"); // Register the node CHECK_MSTATUS_AND_RETURN_IT( plugin.registerNode( "stringFormat", stringFormat::id, stringFormat::creator, stringFormat::initialize)); // Create the UI for the plugin. // Keep on going, do not fail the load because of this. CHECK_MSTATUS(plugin.registerUI("stringFormatCreateUI", "stringFormatDeleteUI", "", "")); return status; } // The unitializePlugin is called when Maya needs to unload the plugin. // It does the opposite of initialize. // MStatus uninitializePlugin( MObject obj) { MStatus status; MFnPlugin plugin( obj ); CHECK_MSTATUS_AND_RETURN_IT(plugin.deregisterNode( stringFormat::id )); return status; }