//- // ========================================================================== // Copyright (C) 1995 - 2005 Alias Systems Corp. and/or its licensors. All // rights reserved. // // The coded instructions, statements, computer programs, and/or related // material (collectively the "Data") in these files are provided by Alias // Systems Corp. ("Alias") and/or its licensors for the exclusive use of the // Customer (as defined in the Alias Software License Agreement that // accompanies this Alias software). Such Customer has the right to use, // modify, and incorporate the Data into other products and to distribute such // products for use by end-users. // // THE DATA IS PROVIDED "AS IS". ALIAS HEREBY DISCLAIMS ALL WARRANTIES // RELATING TO THE DATA, INCLUDING, WITHOUT LIMITATION, ANY AND ALL EXPRESS OR // IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND/OR FITNESS FOR A // PARTICULAR PURPOSE. IN NO EVENT SHALL ALIAS BE LIABLE FOR ANY DAMAGES // WHATSOEVER, WHETHER DIRECT, INDIRECT, SPECIAL, OR PUNITIVE, WHETHER IN AN // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, OR IN EQUITY, // ARISING OUT OF ACCESS TO, USE OF, OR RELIANCE UPON THE DATA. // ========================================================================== //+ // Example Plugin: circleNode.cpp // // This plug-in is an example of a user-defined dependency graph node. // It takes a number as input (such as time) and generates two output // numbers one which describes a sine curve as the input varies and // one that generates a cosine curve. If these two are hooked up to // the x and z translation attributes of an object the object will describe // move through a circle in the xz plane as time is changed. // // Executing the command "source circleNode" will run the MEL script which will // create a new "Circle" menu with a single item. Selecting this will build // a simple model (a sphere which follows a circular path) which can be played back, // by clicking on the "play" icon on the time slider. Note: the circleNode // plugin needs to be loaded before the "Circle" menu item can be executed // properly. // // The node has two additional attributes which can be changed to affect // the animation, "scale" which defines the size of the circular path, and // "frames" which defines the number of frames required for a complete circuit // of the path. Either of these can be hooked up to other nodes, or can // be simply set via the MEL command "setAttr" operating on the circle node // "circleNode1" created by the MEL script. For example, "setAttr circleNode1.scale #" // will change the size of the circle and "setAttr circleNode1.frames #" // will cause objects to complete a circle in indicated number of frames. // $RCSfile: circleNode.cpp $ $Revision: /main/20 $ #include #include #include #include #include #include #include #include #include #include #include #include // The circle class defines the attributes // and methods necessary for the circleNode plugin // class circle : public MPxNode { public: circle(); virtual ~circle(); virtual MStatus compute( const MPlug& plug, MDataBlock& data ); static void* creator(); static MStatus initialize(); public: static MObject input; // The input value. static MObject sOutput; // The sinusoidal output value. static MObject cOutput; // The cosinusoidal output value. static MObject frames; // Number of frames for one circle. static MObject scale; // Size of circle. static MTypeId id; }; MTypeId circle::id( 0x80005 ); MObject circle::input; MObject circle::sOutput; MObject circle::cOutput; MObject circle::frames; MObject circle::scale; // The creator method creates an instance of the circleNode class // and is the first method called by Maya // when a circleNode needs to be created. // void* circle::creator() { return new circle(); } // 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 values. // The inputs are: input, scale, frames // The outputs are: sineOutput, cosineOutput // MStatus circle::initialize() { MFnNumericAttribute nAttr; MStatus stat; // Setup the input attributes // input = nAttr.create( "input", "in", MFnNumericData::kFloat, 0.0, &stat ); CHECK_MSTATUS( stat ); CHECK_MSTATUS( nAttr.setStorable( true ) ); scale = nAttr.create( "scale", "sc", MFnNumericData::kFloat, 10.0, &stat ); CHECK_MSTATUS( stat ); CHECK_MSTATUS( nAttr.setStorable( true ) ); frames = nAttr.create( "frames", "fr", MFnNumericData::kFloat, 48.0, &stat ); CHECK_MSTATUS( stat ); CHECK_MSTATUS( nAttr.setStorable( true ) ); // Setup the output attributes // sOutput = nAttr.create( "sineOutput", "so", MFnNumericData::kFloat, 0.0, &stat ); CHECK_MSTATUS( stat ); CHECK_MSTATUS( nAttr.setWritable( false ) ); CHECK_MSTATUS( nAttr.setStorable( false ) ); cOutput = nAttr.create( "cosineOutput", "co", MFnNumericData::kFloat, 0.0, &stat ); CHECK_MSTATUS( stat ); CHECK_MSTATUS( nAttr.setWritable( false ) ); CHECK_MSTATUS( nAttr.setStorable( false ) ); // Add the attributes to the node // CHECK_MSTATUS( addAttribute( input ) ); CHECK_MSTATUS( addAttribute( scale ) ); CHECK_MSTATUS( addAttribute( frames ) ); CHECK_MSTATUS( addAttribute( sOutput ) ); CHECK_MSTATUS( addAttribute( cOutput ) ); // Set the attribute dependencies // CHECK_MSTATUS( attributeAffects( input, sOutput ) ); CHECK_MSTATUS( attributeAffects( input, cOutput ) ); CHECK_MSTATUS( attributeAffects( scale, sOutput ) ); CHECK_MSTATUS( attributeAffects( scale, cOutput ) ); CHECK_MSTATUS( attributeAffects( frames, sOutput ) ); CHECK_MSTATUS( attributeAffects( frames, cOutput ) ); return MS::kSuccess; } // The constructor does nothing // circle::circle() {} // The destructor does nothing // circle::~circle() {} // 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. // MStatus circle::compute (const MPlug& plug, MDataBlock& data) { MStatus returnStatus; // Check that the requested recompute is one of the output values // if (plug == sOutput || plug == cOutput) { // Read the input values // MDataHandle inputData = data.inputValue (input, &returnStatus); CHECK_MSTATUS( returnStatus ); MDataHandle scaleData = data.inputValue (scale, &returnStatus); CHECK_MSTATUS( returnStatus ); MDataHandle framesData = data.inputValue (frames, &returnStatus); CHECK_MSTATUS( returnStatus ); // Compute the output values // float currentFrame = inputData.asFloat(); float scaleFactor = scaleData.asFloat(); float framesPerCircle = framesData.asFloat(); float angle = 6.2831853f * (currentFrame/framesPerCircle); float sinResult = sinf (angle) * scaleFactor; float cosResult = cosf (angle) * scaleFactor; // Store them on the output plugs // MDataHandle sinHandle = data.outputValue( circle::sOutput, &returnStatus ); CHECK_MSTATUS( returnStatus ); MDataHandle cosHandle = data.outputValue( circle::cOutput, &returnStatus ); CHECK_MSTATUS( returnStatus ); sinHandle.set( sinResult ); cosHandle.set( cosResult ); CHECK_MSTATUS( data.setClean( plug ) ); } else { return MS::kUnknownParameter; } return MS::kSuccess; } // The initializePlugin method is called by Maya when the circleNode // plugin is loaded. It registers the circleNode which provides // Maya with the creator and initialize methods to be called when // a circleNode is created. // MStatus initializePlugin ( MObject obj ) { MStatus status; MFnPlugin plugin( obj, "Alias", "4.5", "Any"); status = plugin.registerNode( "circle", circle::id, circle::creator, circle::initialize ); if (!status) { status.perror("registerNode"); return status; } return status; } // The unitializePlugin is called when Maya needs to unload the plugin. // It basically does the opposite of initialize by calling // the deregisterCommand to remove it. // MStatus uninitializePlugin( MObject obj) { MStatus status; MFnPlugin plugin( obj ); status = plugin.deregisterNode( circle::id ); if (!status) { status.perror("deregisterNode"); return status; } return status; }