summaryrefslogtreecommitdiffstats
path: root/tools/globalcode/utility/MExt.cpp
diff options
context:
space:
mode:
authorSvxy <aidan61605@gmail.com>2023-05-31 23:31:32 +0200
committerSvxy <aidan61605@gmail.com>2023-05-31 23:31:32 +0200
commiteb4b3404aa00220d659e532151dab13d642c17a3 (patch)
tree7e1107c4995489a26c4007e41b53ea8d00ab2134 /tools/globalcode/utility/MExt.cpp
downloadThe-Simpsons-Hit-and-Run-TSH&R-PC.tar
The-Simpsons-Hit-and-Run-TSH&R-PC.tar.gz
The-Simpsons-Hit-and-Run-TSH&R-PC.tar.bz2
The-Simpsons-Hit-and-Run-TSH&R-PC.tar.lz
The-Simpsons-Hit-and-Run-TSH&R-PC.tar.xz
The-Simpsons-Hit-and-Run-TSH&R-PC.tar.zst
The-Simpsons-Hit-and-Run-TSH&R-PC.zip
Diffstat (limited to 'tools/globalcode/utility/MExt.cpp')
-rw-r--r--tools/globalcode/utility/MExt.cpp2030
1 files changed, 2030 insertions, 0 deletions
diff --git a/tools/globalcode/utility/MExt.cpp b/tools/globalcode/utility/MExt.cpp
new file mode 100644
index 0000000..6523859
--- /dev/null
+++ b/tools/globalcode/utility/MExt.cpp
@@ -0,0 +1,2030 @@
+//-----------------------------------------------------------------------------
+// Copyright (C) 2001 Radical Entertainment Ltd. All rights reserved.
+//
+// MExt.cpp
+//
+// Description: Functions that extend the Maya API to perform other common
+// tasks.
+//
+// Modification History:
+// + Created Aug 21, 2001 -- bkusy
+//-----------------------------------------------------------------------------
+#include "precompiled/PCH.h"
+
+//----------------------------------------
+// System Includes
+//----------------------------------------
+//#include <windows.h>
+
+#include <assert.h>
+#include <stdlib.h>
+#include <math.h>
+
+/* Using precompiled headers
+#include <maya/M3dView.h>
+#include <maya/MArgList.h>
+#include <maya/MDagPath.h>
+#include <maya/MDoubleArray.h>
+#include <maya/MDGModifier.h>
+#include <maya/MDoubleArray.h>
+#include <maya/MGlobal.h>
+#include <maya/MFnDagNode.h>
+#include <maya/MFnData.h>
+#include <maya/MFnDependencyNode.h>
+#include <maya/MFnDoubleArrayData.h>
+#include <maya/MFnMatrixData.h>
+#include <maya/MFnTransform.h>
+#include <maya/MFnTypedAttribute.h>
+#include <maya/MItDag.h>
+#include <maya/MItSelectionList.h>
+#include <maya/MMatrix.h>
+#include <maya/MObject.h>
+#include <maya/MPlug.h>
+#include <maya/MPlugArray.h>
+#include <maya/MPoint.h>
+#include <maya/MSelectionList.h>
+#include <maya/MStatus.h>
+#include <maya/MString.h>
+#include <maya/MTransformationMatrix.h>
+#include <maya/MTypeId.h>
+#include <maya/MVector.h>
+*/
+
+//----------------------------------------
+// Project Includes
+//----------------------------------------
+#include "MExt.h"
+#include "util.h"
+
+//----------------------------------------
+// Constants, Typedefs and Statics
+//----------------------------------------
+static const double EPSILON = 0.00001;
+static const int SCRATCHPAD_SIZE = 256;
+static char scratchpad[ SCRATCHPAD_SIZE + 1 ];
+
+
+//-----------------------------------------------------------------------------
+// G e t S c a l e d
+//
+// Synopsis: Retrieves an attribute that is first scaled by the scale in
+// the node's parenting transform.
+//
+// Parameters: vertex - reference parameter to receive scaled attribute.
+// node - the node the attribute is on.
+// attr - the attribute to retrieve.
+//
+// Returns: The status of the request, hopefully MS::kSuccess.
+//
+// Constraints: This method only applies the scale that is stored in the
+// immediate parent of the node. Prior parenting tranforms have
+// no effect.
+//-----------------------------------------------------------------------------
+void MExt::Attr::GetScaled( MPoint* vertex,
+ const MObject& node,
+ const MObject& attr
+ )
+{
+ MStatus status;
+
+ //
+ // Get the nodes parenting transform.
+ //
+ MFnDagNode fnNode( node, &status );
+ assert( status );
+
+ MObject transform = fnNode.parent( 0, &status );
+ assert( status );
+
+ MFnTransform fnTransform( transform, &status );
+ assert( status );
+
+ //
+ // Get the scale in the parenting transform.
+ //
+ double scale[3];
+ status = fnTransform.getScale( scale );
+ assert( status );
+
+ //
+ // Get the attribute.
+ //
+ Get( vertex, node, attr );
+
+ //
+ // Scale the attribute.
+ //
+ vertex->x *= scale[0];
+ vertex->y *= scale[1];
+ vertex->z *= scale[2];
+}
+
+//-----------------------------------------------------------------------------
+// S e t S c a l e d
+//
+// Synopsis: Sets the attribute after taking into account the scale set in
+// the immediate parenting transform. If the attribute initially
+// has a value of (10,10,10) and a scaling vector of
+// (0.5, 2.0, 0.5) is in the parenting transform. The attribute
+// will be stored as (20,5,20) so that it will reflect the
+// original value when the attribute is retrieved through the
+// transform at a later time.
+//
+// Parameters: vertex - the vertex values to set the attribute to.
+// node - the node to set the attribute on.
+// attr - the attribute to set.
+//
+// Returns: NOTHING
+//
+// Constraints: Only the scaling in the immediate parenting transform is taken
+// into account.
+//
+//-----------------------------------------------------------------------------
+void MExt::Attr::SetScaled( const MPoint& vertex,
+ MObject& node,
+ MObject& attr
+ )
+{
+ MStatus status;
+
+ //
+ // Get the nodes parenting transform.
+ //
+ MFnDagNode fnNode( node, &status );
+ assert( status );
+
+ MObject transform = fnNode.parent( 0, &status );
+ assert( status );
+
+ MFnTransform fnTransform( transform, &status );
+ assert( status );
+
+ //
+ // Get the scale in the parenting transform.
+ //
+ double scale[3];
+ status = fnTransform.getScale( scale );
+ assert( status );
+
+ //
+ // Create the "unscaled" vertex.
+ //
+ MPoint scaledVertex = vertex;
+ scaledVertex.x = scaledVertex.x / scale[0];
+ scaledVertex.y = scaledVertex.y / scale[1];
+ scaledVertex.z = scaledVertex.z / scale[2];
+
+ Set( scaledVertex, node, attr );
+}
+
+//-----------------------------------------------------------------------------
+// S e t S c a l e d
+//
+// Synopsis: Sets the attribute after taking into account the scale set in
+// the immediate parenting transform. If the attribute initially
+// has a value of (10,10,10) and a scaling vector of
+// (0.5, 2.0, 0.5) is in the parenting transform. The attribute
+// will be stored as (20,5,20) so that it will reflect the
+// original value when the attribute is retrieved through the
+// transform at a later time.
+//
+// Parameters: vertex - the vertex values to set the attribute to.
+// node - the node to set the attribute on.
+// attr - the name of the attribute.
+//
+// Returns: NOTHING
+//
+// Constraints: Only the scaling in the immediate parenting transform is taken
+// into account.
+//
+//-----------------------------------------------------------------------------
+void MExt::Attr::SetScaled( const MPoint& vertex,
+ MObject& node,
+ const MString& attr
+ )
+{
+ MStatus status;
+
+ //
+ // Get the attribute object that corresponds to the named attribute.
+ //
+ MFnDagNode fnNode( node, &status );
+ assert( status );
+
+ MPlug plug = fnNode.findPlug( attr, &status );
+ assert( status );
+
+ SetScaled( vertex, node, plug.attribute() );
+}
+
+//-----------------------------------------------------------------------------
+// O p t i o n P a r s e r : : O p t i o n P a r s e r
+//
+// Synopsis: Constructor
+//
+// Parameters: args - the MArgList passed into functions like doIt();
+//
+// Returns: NOTHING
+//
+// Constraints: NONE
+//
+//-----------------------------------------------------------------------------
+MExt::OptionParser::OptionParser( const char* command, const MArgList& args ) :
+ m_argc( 0 ),
+ m_argv( 0 ),
+ m_opt( 0 )
+{
+ assert( command );
+
+ typedef char* charPointer;
+
+ //
+ // Create our simultated argument environment. We add one to m_argc because
+ // we are inserting the command name as well.
+ //
+ m_argc = args.length() + 1;
+ m_argv = new charPointer[ m_argc ];
+ assert( m_argv );
+
+ //
+ // Copy in the command name.
+ //
+ m_argv[0] = new char[ strlen( command ) + 1 ];
+ assert( m_argv[0] );
+ strcpy( m_argv[0], command );
+
+ //
+ // Copy in the arguments from argList.
+ //
+ int i;
+ for ( i = 1; i < m_argc; i++ )
+ {
+ MString arg;
+ args.get( i - 1, arg );
+ m_argv[i] = new char[ strlen( arg.asChar() ) + 1 ];
+ assert( m_argv[i] );
+ strcpy( m_argv[i], arg.asChar() );
+ }
+
+ //
+ // Initialize the parser.
+ //
+ util_getopt_init();
+}
+
+//-----------------------------------------------------------------------------
+// O p t i o n P a r s e r : : ~ O p t i o n P a r s e r
+//
+// Synopsis: Destructor
+//
+// Parameters: NONE
+//
+// Returns: NOTHING
+//
+// Constraints: NONE
+//
+//-----------------------------------------------------------------------------
+MExt::OptionParser::~OptionParser()
+{
+ if ( m_argv )
+ {
+ int i;
+ for ( i = 0; i < m_argc; i++ )
+ {
+ if ( m_argv[i] )
+ {
+ delete m_argv[i];
+ }
+ }
+
+ delete m_argv;
+ }
+
+ m_argc = 0;
+
+ if ( m_opt )
+ {
+ delete m_opt;
+ m_opt = 0;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// O p t i o n P a r s e r : : s e t O p t i o n s
+//
+// Synopsis: Specify the options that will be parsed.
+//
+// Parameters: optionSpec - the specification string. eg. "hgu:t:" would
+// specify two boolean flags, "h" and "g" ( they
+// do not take arguments ), and two argument flags,
+// "u" and "t", that take arguments. Flags that
+// take arguments must be followed by a ":".
+//
+// Returns: NOTHING
+//
+// Constraints: NONE
+//
+//-----------------------------------------------------------------------------
+void MExt::OptionParser::setOptions( const char* optionSpec )
+{
+ int len = strlen( optionSpec ) + 1;
+ m_opt = new char[ len + 1 ];
+ assert( m_opt );
+
+ strncpy( m_opt, optionSpec, len );
+}
+
+//-----------------------------------------------------------------------------
+// O p t i o n P a r s e r : : n e x t O p t i o n
+//
+// Synopsis: Get the next option.
+//
+// Parameters: NONE
+//
+// Returns: The character flag for the next option or -1 if no more
+// options.
+//
+// Constraints: NONE
+//
+//-----------------------------------------------------------------------------
+int MExt::OptionParser::nextOption()
+{
+ int result = util_getopt( m_argc, m_argv, m_opt );
+ return result;
+}
+
+//-----------------------------------------------------------------------------
+// O p t i o n P a r s e r : : g e t A r g
+//
+// Synopsis:
+//
+// Parameters: NONE
+//
+// Returns: NOTHING
+//
+// Constraints: NONE
+//
+//-----------------------------------------------------------------------------
+MString MExt::OptionParser::getArg()
+{
+ MString result( util_optarg );
+ return result;
+}
+
+//-----------------------------------------------------------------------------
+// O p t i o n V a r : : G e t
+//
+// Synopsis:
+//
+// Parameters: NONE
+//
+// Returns: NOTHING
+//
+// Constraints: NONE
+//
+//-----------------------------------------------------------------------------
+bool MExt::OptionVar::Get( char* buffer, unsigned int buffer_size, const char* symbol )
+{
+ bool doesExist = false;
+
+ MString command = "optionVar -exists ";
+ command += symbol;
+
+ int exists;
+ MGlobal::executeCommand( command, exists );
+
+ if ( exists )
+ {
+ command = "optionVar -query ";
+ command += symbol;
+
+ MString result;
+ MGlobal::executeCommand( command, result );
+
+ assert( result.length() < buffer_size );
+ strncpy( buffer, result.asChar(), buffer_size );
+
+ doesExist = true;
+ }
+
+ return doesExist;
+}
+
+
+//-----------------------------------------------------------------------------
+// O p t i o n V a r : : S e t
+//
+// Synopsis:
+//
+// Parameters: NONE
+//
+// Returns: NOTHING
+//
+// Constraints: NONE
+//
+//-----------------------------------------------------------------------------
+void MExt::OptionVar::Set( const char* buffer, const char* symbol )
+{
+ MString command;
+ command = "optionVar -stringValue ";
+ command += symbol;
+ command += " \"";
+ command += buffer;
+ command += "\"";
+
+ MGlobal::executeCommand( command );
+}
+
+//-----------------------------------------------------------------------------
+// A d d C h i l d
+//
+// Synopsis: Make a locator node the child of another by parenting the transforms.
+//
+// Parameters: parentLocatorNode - locator node to be the parent
+// childLocatorNode - locator node to be the child
+//
+// Returns: NOTHING
+//
+// Constraints: Must both have transforms.
+//
+//-----------------------------------------------------------------------------
+void MExt::AddChild( MObject& parentLocatorNode, MObject& childLocatorNode )
+{
+// assert( parentLocatorNode.apiType() == MFn::kLocator );
+// assert( childLocatorNode.apiType() == MFn::kLocator );
+
+ //Get the transform of the parent node
+ MFnDagNode fnDag( parentLocatorNode );
+ MObject parentTransform = fnDag.parent( 0 );
+
+ //Get teh transform of the child node.
+ fnDag.setObject( childLocatorNode );
+ MObject childTransform = fnDag.parent( 0 );
+
+ //Parent the fence to the wall
+ fnDag.setObject( parentTransform );
+ fnDag.addChild( childTransform );
+}
+
+//-----------------------------------------------------------------------------
+// C o n n e c t
+//
+// Synopsis: Connect two nodes via the specified attributes.
+//
+// Parameters: node - the source node.
+// attr - the source attribute.
+// otherNode - the destination node.
+// otherAttr - the destination attribute.
+//
+// Returns: NOTHING
+//
+// Constraints: NONE
+//
+//-----------------------------------------------------------------------------
+void MExt::Connect( MObject& node,
+ MObject& attr,
+ MObject& otherNode,
+ MObject& otherAttr
+ )
+{
+ MStatus status;
+
+ MDGModifier modifier;
+ status = modifier.connect( node, attr, otherNode, otherAttr );
+ assert( status );
+
+ status = modifier.doIt();
+ if ( !status ) MGlobal::displayError( status.errorString() );
+ assert( status );
+}
+
+void MExt::Connect( MObject& node,
+ const char* attr,
+ MObject& otherNode,
+ const char* otherAttr
+ )
+{
+ MStatus status;
+
+ MFnDependencyNode fnNode;
+
+ fnNode.setObject( node );
+ MPlug nodePlug = fnNode.findPlug( MString( attr ), &status );
+ assert( status );
+
+
+ fnNode.setObject( otherNode );
+ MPlug otherNodePlug = fnNode.findPlug( MString( otherAttr ), &status );
+ assert( status );
+
+ MDGModifier modifier;
+ status = modifier.connect( node, nodePlug.attribute(), otherNode, otherNodePlug.attribute() );
+ assert( status );
+
+ status = modifier.doIt();
+ if ( !status ) MGlobal::displayError( status.errorString() );
+ assert( status );
+}
+
+//-----------------------------------------------------------------------------
+// C r e a t e N o d e
+//
+// Synopsis:
+//
+// Parameters: node - reference parameter to receive node MObject.
+// transform - reference parameter to receive the parenting
+// transform.
+// type - the type of node to create.
+// name - the name to assign to the node. If NULL default
+// name is used.
+// group - MObject representing the group under which to
+// attach the new node. If NULL then the new node
+// is attached at the DAG root.
+//
+// Returns: the status of the request -- hopefully MS::kSuccess.
+//
+// Constraints: NONE
+//
+//-----------------------------------------------------------------------------
+void MExt::CreateNode( MObject* node,
+ MObject* transform,
+ const MString& type,
+ const MString* name,
+ const MObject& group
+ )
+{
+ MStatus status;
+
+ //
+ // Determine names for the nodes. This must be done before the
+ // nodes are created so as to avoid conflicting with the default
+ // names that Maya will assign them prior to us renaming them.
+ //
+ MString nodeName = type;
+ if ( name ) nodeName = *name;
+ MString transformName = ( "TForm" + nodeName );
+
+ MakeNameUnique( &nodeName, nodeName, group );
+ MakeNameUnique( &transformName, transformName, group );
+
+ //
+ // Create the transform.
+ //
+ MFnTransform fnTransform;
+ fnTransform.create( MObject::kNullObj, &status );
+ assert( status );
+
+ //
+ // Create the node under the transform.
+ //
+ MFnDagNode fnNode;
+ fnNode.create( type, fnTransform.object(), &status );
+ assert( status );
+
+ if ( group != MObject::kNullObj )
+ {
+ //
+ // Place the new node under the group node.
+ //
+ MFnTransform fnGroup( group, &status );
+ assert( status );
+
+ status = fnGroup.addChild( fnTransform.object() );
+ assert( status );
+ }
+
+ //
+ // Name the nodes.
+ //
+ fnTransform.setName( transformName, &status );
+ assert( status );
+
+ fnNode.setName( nodeName, &status );
+ assert( status );
+
+ //
+ // Return the node and transform objects in the reference parameters.
+ //
+ if ( transform )
+ {
+ *transform = fnTransform.object();
+ }
+
+ if ( node )
+ {
+ *node = fnNode.object();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// C r e a t e N o d e
+//
+// Synopsis:
+//
+// Parameters: node - reference parameter to receive node MObject.
+// transform - reference parameter to receive the parenting
+// transform.
+// type - the type of node to create.
+// name - the name to assign to the node. If NULL default
+// name is used.
+// group - MObject representing the group under which to
+// attach the new node. If NULL then the new node
+// is attached at the DAG root.
+//
+// Returns: the status of the request -- hopefully MS::kSuccess.
+//
+// Constraints: NONE
+//
+//-----------------------------------------------------------------------------
+void MExt::CreateNode( MObject& node,
+ MObject& transform,
+ const MString& type,
+ const MString* name,
+ const MObject& group
+ )
+{
+ MStatus status;
+
+ //
+ // Determine names for the nodes. This must be done before the
+ // nodes are created so as to avoid conflicting with the default
+ // names that Maya will assign them prior to us renaming them.
+ //
+ MString nodeName = type;
+ if ( name ) nodeName = *name;
+ MString transformName = ( "TForm" + nodeName );
+
+ MakeNameUnique( &nodeName, nodeName, group );
+ MakeNameUnique( &transformName, transformName, group );
+
+ //
+ // Create the transform.
+ //
+ MFnTransform fnTransform;
+ fnTransform.create( MObject::kNullObj, &status );
+ assert( status );
+
+ //
+ // Create the node under the transform.
+ //
+ MFnDagNode fnNode;
+ fnNode.create( type, fnTransform.object(), &status );
+ assert( status );
+
+ if ( group != MObject::kNullObj )
+ {
+ //
+ // Place the new node under the group node.
+ //
+ MFnTransform fnGroup( group, &status );
+ assert( status );
+
+ status = fnGroup.addChild( fnTransform.object() );
+ assert( status );
+ }
+
+ //
+ // Name the nodes.
+ //
+ fnTransform.setName( transformName, &status );
+ assert( status );
+
+ fnNode.setName( nodeName, &status );
+ assert( status );
+
+ //
+ // Return the node and transform objects in the reference parameters.
+ //
+ transform = fnTransform.object();
+ node = fnNode.object();
+}
+
+//-----------------------------------------------------------------------------
+// C r e a t e V e r t e x A t t r i b u t e
+//
+// Synopsis: Intended for use within the initialize() method for a node
+// class. Creates a vertex attribute using a double array.
+//
+// Parameters: name - the name of the attribute.
+// breif_name - the brief name of the attribute.
+//
+// Returns: the attribute object.
+//
+// Constraints: NONE
+//
+//-----------------------------------------------------------------------------
+void MExt::CreateVertexAttribute( MObject* attr,
+ const char* name,
+ const char* briefName
+ )
+{
+ MStatus status;
+
+ MDoubleArray doubleArray;
+ MFnDoubleArrayData doubleArrayData;
+ MObject defaultVertex = doubleArrayData.create( doubleArray, &status );
+ assert( status );
+
+ MFnTypedAttribute fnAttribute;
+ *attr = fnAttribute.create( name,
+ briefName,
+ MFnData::kDoubleArray,
+ defaultVertex,
+ &status
+ );
+ assert( status );
+}
+
+//=============================================================================
+// MExt::DeleteNode
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( MObject& node, bool deleteParent )
+//
+// Return: void
+//
+//=============================================================================
+void MExt::DeleteNode( MObject& node, bool deleteParent )
+{
+ //Get the parent and delete it too if it's a transform and the bool says so.
+
+ MStatus status;
+ MObject parent;
+
+ if ( deleteParent )
+ {
+ //Get the parent please.
+ MFnDagNode fnDag( node );
+ parent = fnDag.parent( 0, &status );
+ assert( status );
+ }
+
+ //Delete this node
+ MGlobal::deleteNode( node );
+
+ if ( deleteParent )
+ {
+ //Delete the parent.
+ MGlobal::deleteNode( parent );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// D i s c o n n e c t A l l
+//
+// Synopsis:
+//
+// Parameters: NONE
+//
+// Returns: NOTHING
+//
+// Constraints: NONE
+//
+//-----------------------------------------------------------------------------
+void MExt::DisconnectAll( MObject& node, MObject& attr )
+{
+ MStatus status;
+
+ MFnDependencyNode fnNode( node, &status );
+ assert( status );
+
+ //
+ // Get the plug for the attribute to be disconnected.
+ //
+ MPlug plug = fnNode.findPlug( attr, &status );
+ assert( status );
+
+ //
+ // Find all connections and disconnect them.
+ //
+ MDGModifier modifier;
+ MPlugArray sources;
+ MPlugArray targets;
+ MExt::ResolveConnections( &sources, &targets, plug, true, true );
+
+ unsigned int count = sources.length();
+ unsigned int i;
+
+ for ( i = 0; i < count; i++ )
+ {
+ status = modifier.disconnect( sources[i], targets[i] );
+ assert( status );
+ }
+
+ status = modifier.doIt();
+ assert( status );
+}
+
+void MExt::DisconnectAll( MObject& node, const char* attrName )
+{
+ MStatus status;
+
+ MFnDependencyNode fnNode( node, &status );
+ assert( status );
+
+ //
+ // Get the plug for the attribute to be disconnected.
+ //
+ MPlug plug = fnNode.findPlug( MString( attrName ), &status );
+ assert( status );
+
+ //
+ // Find all connections and disconnect them.
+ //
+ MDGModifier modifier;
+ MPlugArray sources;
+ MPlugArray targets;
+ MExt::ResolveConnections( &sources, &targets, plug, true, true );
+
+ unsigned int count = sources.length();
+ unsigned int i;
+
+ for ( i = 0; i < count; i++ )
+ {
+ status = modifier.disconnect( sources[i], targets[i] );
+ assert( status );
+ }
+
+ status = modifier.doIt();
+ assert( status );
+}
+
+//-----------------------------------------------------------------------------
+// D i s p l a y E r r o r
+//
+// Synopsis:
+//
+// Parameters: NONE
+//
+// Returns: NOTHING
+//
+// Constraints: NONE
+//
+//-----------------------------------------------------------------------------
+int MExt::DisplayError( const char* fmt, ... )
+{
+ va_list argp;
+ va_start( argp, fmt );
+ int size = _vsnprintf( scratchpad, SCRATCHPAD_SIZE, fmt, argp );
+ MGlobal::displayError( scratchpad );
+ return size;
+}
+
+//-----------------------------------------------------------------------------
+// D i s p l a y W a r n i n g
+//
+// Synopsis:
+//
+// Parameters: NONE
+//
+// Returns: NOTHING
+//
+// Constraints: NONE
+//
+//-----------------------------------------------------------------------------
+int MExt::DisplayWarning( const char* fmt, ... )
+{
+ va_list argp;
+ va_start( argp, fmt );
+ int size = _vsnprintf( scratchpad, SCRATCHPAD_SIZE, fmt, argp );
+ MGlobal::displayWarning( scratchpad );
+ return size;
+}
+
+//-----------------------------------------------------------------------------
+// D i s p l a y I n f o
+//
+// Synopsis:
+//
+// Parameters: NONE
+//
+// Returns: NOTHING
+//
+// Constraints: NONE
+//
+//-----------------------------------------------------------------------------
+int MExt::DisplayInfo( const char* fmt, ... )
+{
+ va_list argp;
+ va_start( argp, fmt );
+ int size = _vsnprintf( scratchpad, SCRATCHPAD_SIZE, fmt, argp );
+ MGlobal::displayInfo( scratchpad );
+ return size;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// F i l t e r S e l e c t i o n L i s t
+//
+// Synopsis: Filters the given source list for nodes of "typeName" and
+// places them in the filtered list. If transforms are in the
+// source list all their children are filtered as well.
+//
+// Parameters: filteredList - reference paremeter to receive the filtered
+// list.
+// typeName - the type name to check for.
+// sourceList - the list to filter.
+//
+//
+// Returns: NOTHING
+//
+// Constraints: NONE
+//
+//-----------------------------------------------------------------------------
+void MExt::FilterSelectionList( MSelectionList* filteredList,
+ const MString& typeName,
+ const MSelectionList& sourceList
+ )
+{
+ assert( filteredList );
+
+ MItSelectionList it_source( sourceList );
+ while( ! it_source.isDone() )
+ {
+ MObject node;
+ it_source.getDependNode( node );
+
+ MFnDependencyNode fnNode;
+ fnNode.setObject( node );
+
+ if ( fnNode.typeName() == typeName )
+ {
+ filteredList->add( fnNode.object() );
+ }
+ else if ( strcmp( "transform" , fnNode.typeName().asChar() ) == 0 )
+ {
+ SelectNodesBelowRoot( filteredList, typeName, fnNode.object() );
+ }
+
+ it_source.next();
+ }
+}
+
+//=============================================================================
+// MExt::FindAllSkeletonRoots
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( MObjectArray* objects )
+//
+// Return: bool
+//
+//=============================================================================
+bool MExt::FindAllSkeletonRoots( MObjectArray* objects )
+{
+ MStatus status;
+ bool returnVal = false;
+
+ MItDag dagIt( MItDag::kDepthFirst, MFn::kTransform, &status );
+ assert( status );
+
+ while( !dagIt.isDone() )
+ {
+ MFnTransform fnTransform( dagIt.item() );
+
+ MPlug p3dBoolPlug = fnTransform.findPlug( MString("p3dBooleanAttributes"), &status );
+ if ( status )
+ {
+ //This has p3d info.
+ int value = 0;
+ p3dBoolPlug.getValue( value );
+
+ if ( value & 0x0002 ) //This is the skelton root bit... HACK
+ {
+ objects->append( fnTransform.object() );
+ returnVal = true;
+ }
+ }
+
+ dagIt.next();
+ }
+
+ return returnVal;
+}
+
+//=============================================================================
+// MExt::FindAllTransforms
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( MObjectArray* transforms, const MObject& root )
+//
+// Return: bool
+//
+//=============================================================================
+bool MExt::FindAllTransforms( MObjectArray* transforms, const MObject& root )
+{
+ bool returnVal = false;
+
+ MItDag dagIt( MItDag::kDepthFirst, MFn::kTransform );
+ MDagPath path;
+ MDagPath::getAPathTo( root, path );
+
+ dagIt.reset( path, MItDag::kDepthFirst, MFn::kTransform );
+
+ while ( !dagIt.isDone() )
+ {
+ transforms->append( dagIt.item() );
+ returnVal = true;
+
+ dagIt.next();
+ }
+
+ return returnVal;
+}
+
+//-----------------------------------------------------------------------------
+// F i n d D a g N o d e B y N a m e
+//
+// Synopsis: Find a node in the DAG using its name as the search key.
+//
+// Parameters: path - reference object to receive the path of the found
+// node.
+// name - the name to search for.
+// root - only search under this node.
+//
+// Returns: true if found, false otherwise.
+//
+// Constraints: NONE
+//
+//-----------------------------------------------------------------------------
+bool MExt::FindDagNodeByName( MDagPath* path,
+ const MString& name,
+ const MObject& root
+ )
+{
+ MStatus status;
+
+ MItDag it_dag;
+ if ( root != MObject::kNullObj )
+ {
+ status = it_dag.reset( root );
+ if ( MS::kSuccess != status ) return false;
+ }
+
+ bool found = false;
+ while ( !found && !it_dag.isDone() )
+ {
+ MFnDependencyNode node( it_dag.item(), &status );
+ assert( status );
+ if ( name == node.name() )
+ {
+ found = true;
+ if ( path )
+ {
+ it_dag.getPath( *path );
+ }
+ }
+ it_dag.next();
+ }
+
+ return found;
+}
+
+//-----------------------------------------------------------------------------
+// F i n d D a g N o d e B y N a m e
+//
+// Synopsis: Find a node in the DAG using its name as the search key.
+//
+// Parameters: path - reference object to receive the path of the found
+// node.
+// name - the name to search for.
+// root - only search under the node named root.
+//
+// Returns: true if found, false otherwise.
+//
+// Constraints: NONE
+//
+//-----------------------------------------------------------------------------
+bool MExt::FindDagNodeByName( MDagPath* path,
+ const MString& name,
+ const MString& root
+ )
+{
+ MDagPath myPath;
+ bool found = FindDagNodeByName( &myPath, root );
+ if ( found )
+ {
+ found = FindDagNodeByName( path, name, myPath.node() );
+ }
+
+ return found;
+}
+
+//-----------------------------------------------------------------------------
+// G e t W o r l d P o s i t i o n
+//
+// Synopsis: Retrieves the world position of the given node.
+//
+// Parameters: wp - reference parameter to receive the world positioin.
+// node - the node object to retrieve the world position of.
+//
+// Returns: NOTHING
+//
+// Constraints: NONE
+//
+//-----------------------------------------------------------------------------
+void MExt::GetWorldPosition( MPoint* wp, const MObject& node )
+{
+ MStatus status;
+
+ MFnDependencyNode fnNode( node );
+
+ //
+ // Attempt to get the world matrix attribute.
+ //
+ MObject attrObject = fnNode.attribute( "worldMatrix", &status );
+ assert( status );
+
+ //
+ // Build the world matrix plug. Use the first element on the plug.
+ //
+ MPlug plug( const_cast<MObject&>(node), attrObject );
+ plug = plug.elementByLogicalIndex( 0, &status );
+ assert( status );
+
+ //
+ // Get the world matrix. We have to go through a few Maya layers on this
+ // one.
+ //
+ MObject matrixObject;
+ status = plug.getValue( matrixObject );
+ assert( status );
+
+ MFnMatrixData matrixData( matrixObject, &status );
+ assert( status );
+
+ MMatrix matrix = matrixData.matrix( &status );
+ assert( status );
+
+ //
+ // The translation vector of the matrix is our position.
+ //
+ wp->x = matrix( 3, 0 );
+ wp->y = matrix( 3, 1 );
+ wp->z = matrix( 3, 2 );
+}
+
+
+//-----------------------------------------------------------------------------
+// G e t W o r l d P o s i t i o n B e t w e e n
+//
+// Synopsis: Retrieves the world position of a point between the the given nodes.
+//
+// Parameters: node1 - The first node
+// node1 - The second node
+// betweenPoint - receives the point between the two nodes
+//
+// Returns: NOTHING
+//
+// Constraints: NONE
+//
+//-----------------------------------------------------------------------------
+MPoint MExt::GetWorldPositionBetween( MObject& node1, MObject& node2 )
+{
+ MVector newWPVect;
+ MPoint node1WP;
+ MPoint node2WP;
+
+ MExt::GetWorldPosition( &node1WP, node1 );
+ MExt::GetWorldPosition( &node2WP, node2 );
+
+ newWPVect = node2WP - node1WP;
+ newWPVect /= 2.0f;
+ newWPVect += node1WP;
+
+ MPoint newPoint( newWPVect );
+ return newPoint;
+}
+
+//=============================================================================
+// MExt::GetWorldMatrix
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( MObject& node )
+//
+// Return: MMatrix
+//
+//=============================================================================
+MMatrix MExt::GetWorldMatrix( MObject& node )
+{
+ MStatus status;
+
+ MFnDependencyNode fnNode( node );
+
+ //
+ // Attempt to get the world matrix attribute.
+ //
+ MObject attrObject = fnNode.attribute( "worldMatrix", &status );
+ assert( status );
+
+ //
+ // Build the world matrix plug. Use the first element on the plug.
+ //
+ MPlug plug( const_cast<MObject&>(node), attrObject );
+ plug = plug.elementByLogicalIndex( 0, &status );
+ assert( status );
+
+ //
+ // Get the world matrix. We have to go through a few Maya layers on this
+ // one.
+ //
+ MObject matrixObject;
+ status = plug.getValue( matrixObject );
+ assert( status );
+
+ MFnMatrixData matrixData( matrixObject, &status );
+ assert( status );
+
+ MMatrix matrix = matrixData.matrix( &status );
+ assert( status );
+
+ return matrix;
+}
+
+//-----------------------------------------------------------------------------
+// MExt : : I s C o n n e c t e d
+//
+// Synopsis:
+//
+// Parameters: NONE
+//
+// Returns: NOTHING
+//
+// Constraints: NONE
+//
+//-----------------------------------------------------------------------------
+bool MExt::IsConnected( MObject& node, const char* attr )
+{
+ MStatus status;
+ MFnDependencyNode fnNode;
+
+
+ fnNode.setObject( node );
+
+ MPlug plug = fnNode.findPlug( MString( attr ), &status );
+ assert( status );
+
+ return plug.isConnected();
+}
+
+bool MExt::IsConnected( MObject& node, MObject& attr )
+{
+ MStatus status;
+ MFnDependencyNode fnNode;
+
+
+ fnNode.setObject( node );
+
+ MPlug plug = fnNode.findPlug( attr, &status );
+ assert( status );
+
+ return plug.isConnected();
+}
+
+bool MExt::IsConnected( MPlug& plug1, MPlug& plug2 )
+{
+ MPlugArray plugArray;
+
+ plug1.connectedTo( plugArray, true, true );
+
+ unsigned int i;
+ for ( i = 0; i < plugArray.length(); ++i )
+ {
+ if ( plugArray[i] == plug2 )
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// M a k e N a m e U n i q u e
+//
+// Synopsis: Append numerical suffixes to a name to make it unique under
+// a specified root node.
+//
+// Parameters: unique - a reference parameter to receive the new unique name.
+// name - the original name.
+// root - the node under which the name must be unique.
+//
+// Returns: NOTHING
+//
+// Constraints: NONE
+//
+//-----------------------------------------------------------------------------
+void MExt::MakeNameUnique( MString* unique,
+ const MString& name,
+ const MObject& root
+ )
+{
+ const int bufferSize = 256;
+
+ MString myName = name;
+ assert( myName.length() < bufferSize );
+
+ if ( FindDagNodeByName( 0, myName, root ) )
+ {
+ char buffer[ bufferSize ];
+ strncpy( buffer, myName.asChar(), bufferSize );
+
+ //
+ // Isolate the base name by removing any numerical suffixes.
+ //
+ char* suffix = const_cast<char*>(util_reverseSpan( buffer, "0123456789" ));
+ if ( suffix )
+ {
+ *suffix = '\0';
+ }
+
+ myName = buffer;
+ int isuffix = 0;
+ while( FindDagNodeByName( 0, myName, root ) )
+ {
+ isuffix++;
+ myName = buffer;
+ myName += isuffix;
+ }
+
+ }
+
+ *unique = myName;
+}
+
+//-----------------------------------------------------------------------------
+// M a k e N a m e U n i q u e
+//
+// Synopsis: Append numerical suffixes to a name to make it unique under
+// a specified root node.
+//
+// Parameters: unique - a reference parameter to receive the new unique name.
+// name - the original name.
+// root - name of the node under which the name must be unique.
+//
+// Returns: NOTHING
+//
+// Constraints: NONE
+//
+//-----------------------------------------------------------------------------
+void MExt::MakeNameUnique( MString* unique,
+ const MString& name,
+ const MString& root
+ )
+{
+ MObject rootObject = MObject::kNullObj;
+ MDagPath path;
+ if ( FindDagNodeByName( &path, root ) )
+ {
+ rootObject = path.node();
+ }
+
+ MakeNameUnique( unique, name, rootObject );
+}
+
+//=============================================================================
+// MExt::MeshClickIntersect
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( short xClick, short yClick, MPoint& intersect, bool closest = true )
+//
+// Return: bool
+//
+//=============================================================================
+bool MExt::MeshClickIntersect( short xClick,
+ short yClick,
+ MPoint& intersect,
+ bool closest )
+{
+ //Get the mesh below the clicked point and find it's y height.
+ short xStart, xEnd, yStart, yEnd;
+
+ xStart = 0;
+ xEnd = M3dView::active3dView().portWidth();
+ yStart = M3dView::active3dView().portHeight();
+ yEnd = 0;
+
+ MGlobal::selectFromScreen( xStart,
+ yStart,
+ xEnd,
+ yEnd,
+ MGlobal::kReplaceList );
+
+ MSelectionList selectionList;
+
+ MGlobal::getActiveSelectionList( selectionList );
+
+ if ( selectionList.length() > 0 )
+ {
+ //Go through each selected object and see if the ray intersects it.
+ MItSelectionList selectIt( selectionList, MFn::kMesh );
+
+ MPoint nearClick, farClick;
+ M3dView activeView = M3dView::active3dView();
+ activeView.viewToWorld( xClick, yClick, nearClick, farClick );
+ MVector rayDir( MVector( farClick ) - MVector( nearClick ) );
+ MPointArray intersectPoints;
+ MDagPath objDag;
+
+ bool found = false;
+
+ MPoint resultPoint;
+
+ if ( closest )
+ {
+ resultPoint.x = 100000.0;
+ resultPoint.y = 100000.0;
+ resultPoint.z = 100000.0;
+ }
+ else
+ {
+ resultPoint.x = 0;
+ resultPoint.y = 0;
+ resultPoint.z = 0;
+ }
+
+ while ( !selectIt.isDone() )
+ {
+ selectIt.getDagPath( objDag );
+
+ MFnMesh mesh( objDag );
+
+ mesh.intersect( nearClick, rayDir, intersectPoints, 0.001f, MSpace::kWorld );
+
+ unsigned int i;
+ for ( i = 0; i < intersectPoints.length(); ++i )
+ {
+ //test each point...
+ if ( closest )
+ {
+ if ( intersectPoints[i].distanceTo(nearClick) < (resultPoint.distanceTo(nearClick) ) )
+ {
+ resultPoint = intersectPoints[i];
+ found = true;
+ }
+ }
+ else
+ {
+ if ( intersectPoints[i].distanceTo(nearClick) > (resultPoint.distanceTo(nearClick) ) )
+ {
+ resultPoint = intersectPoints[i];
+ found = true;
+ }
+ }
+ }
+
+ selectIt.next();
+ }
+
+ if ( found )
+ {
+ intersect = resultPoint;
+ MGlobal::clearSelectionList();
+ return true;
+ }
+ }
+
+ MGlobal::clearSelectionList();
+ return false;
+}
+
+//=============================================================================
+// MExt::MeshIntersectAlongVector
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( MPoint from, MPoint direction, MPoint& intersect, bool closest = true )
+//
+// Return: bool
+//
+//=============================================================================
+bool MExt::MeshIntersectAlongVector( MPoint from,
+ MPoint direction,
+ MPoint& intersect,
+ bool closest )
+{
+ MSelectionList selectionList;
+ selectionList.clear();
+
+ MItDag itDag(MItDag::kDepthFirst, MFn::kMesh );
+
+ while ( !itDag.isDone() )
+ {
+ MDagPath dagPath;
+ itDag.getPath( dagPath );
+
+ selectionList.add( dagPath );
+
+ itDag.next();
+ }
+
+ if ( selectionList.length() > 0 )
+ {
+ //Go through each selected object and see if the ray intersects it.
+ MItSelectionList selectIt( selectionList, MFn::kMesh );
+
+ MPointArray intersectPoints;
+ MDagPath objDag;
+
+ bool found = false;
+
+ MPoint resultPoint;
+
+ if ( closest )
+ {
+ resultPoint.x = 100000.0;
+ resultPoint.y = 100000.0;
+ resultPoint.z = 100000.0;
+ }
+ else
+ {
+ resultPoint.x = 0;
+ resultPoint.y = 0;
+ resultPoint.z = 0;
+ }
+
+ while ( !selectIt.isDone() )
+ {
+ selectIt.getDagPath( objDag );
+
+ MStatus status;
+
+ MFnMesh mesh( objDag, &status );
+ assert( status );
+
+
+ const char* name = mesh.name().asChar();
+
+ mesh.intersect( from, direction, intersectPoints, 0.001f, MSpace::kWorld );
+
+ unsigned int i;
+ for ( i = 0; i < intersectPoints.length(); ++i )
+ {
+ //test each point...
+ if ( closest )
+ {
+ if ( intersectPoints[i].distanceTo(from) < (resultPoint.distanceTo(from) ) )
+ {
+ resultPoint = intersectPoints[i];
+ found = true;
+ }
+ }
+ else
+ {
+ if ( intersectPoints[i].distanceTo(from) > (resultPoint.distanceTo(from) ) )
+ {
+ resultPoint = intersectPoints[i];
+ found = true;
+ }
+ }
+ }
+
+ selectIt.next();
+ }
+
+ if ( found )
+ {
+ intersect = resultPoint;
+ MGlobal::clearSelectionList();
+ return true;
+ }
+ }
+
+ MGlobal::clearSelectionList();
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// P l u g H a s C o n n e c t i o n
+//
+// Synopsis: Determines if there are any connections on the specified plug.
+//
+// Parameters: connectedNode - reference parameter to receive the associated
+// node for the first connection found.
+// plug - the plug to get the connections for.
+// asSrc - if true, retrieve connections where "plug" is
+// the source of the connection.
+// asDst - if true, retrieve connections where "plug" is
+// the target of the connection.
+//
+// Returns: true, if the plug has connections; false, otherwise
+//
+// Constraints: NONE
+//
+//-----------------------------------------------------------------------------
+bool MExt::PlugHasConnection( MObject* connectedNode,
+ MPlug& plug,
+ bool asDst,
+ bool asSrc,
+ const char* type
+ )
+{
+ bool isOk = false;
+
+ MPlug myPlug;
+ isOk = PlugHasConnection( &myPlug, plug, asDst, asSrc, type );
+
+ if ( isOk )
+ {
+ if ( connectedNode ) *connectedNode = myPlug.node();
+ }
+
+ return isOk;
+}
+
+//-----------------------------------------------------------------------------
+// P l u g H a s C o n n e c t i o n
+//
+// Synopsis: Determines if there are any connections on the specified plug.
+//
+// Parameters: connectedPlug - reference parameter to receive the plug of
+// the first connection found.
+// plug - the plug to get the connections for.
+// asSrc - if true, retrieve connections where "plug" is
+// the source of the connection.
+// asDst - if true, retrieve connections where "plug" is
+// the target of the connection.
+//
+// Returns: true, if the plug has connections; false, otherwise
+//
+// Constraints: NONE
+//
+//-----------------------------------------------------------------------------
+bool MExt::PlugHasConnection( MPlug* connectedPlug,
+ MPlug& plug,
+ bool asDst,
+ bool asSrc,
+ const char* type
+ )
+{
+ MPlugArray buffer;
+
+ if ( asSrc )
+ {
+ MPlugArray destinations;
+ ResolveConnections( &buffer, &destinations, plug, false, true );
+
+ unsigned int i;
+ for( i = 0; i < destinations.length(); i++ )
+ {
+ bool isOk = true;
+ if ( type )
+ {
+ MFnDependencyNode fnNode( destinations[i].node() );
+ if ( fnNode.typeName() != type )
+ {
+ isOk = false;
+ }
+ }
+
+ if ( isOk )
+ {
+ if ( connectedPlug ) *connectedPlug = destinations[i];
+ return true;
+ }
+ }
+ }
+
+ if ( asDst )
+ {
+ MPlugArray sources;
+ ResolveConnections( &sources, &buffer, plug, true, false );
+
+ unsigned int i;
+ for( i = 0; i < sources.length(); i++ )
+ {
+ bool isOk = true;
+ if ( type )
+ {
+ MFnDependencyNode fnNode( sources[i].node() );
+ if ( fnNode.typeName() != type )
+ {
+ isOk = false;
+ }
+ }
+
+ if ( isOk )
+ {
+ if ( connectedPlug ) *connectedPlug = sources[i];
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// R e s o l v e C o n n e c t i o n s
+//
+// Synopsis: Retrieves the plugs that are connected to this plug. This
+// will work on plugs that are associated with array as well as
+// non-array attributes.
+//
+// Parameters: sources - reference parameter to recieve list of
+// connection sources.
+// targets - reference parameter to recieve list of
+// connection targets.
+// plug - the plug to get the connections for.
+// asSrc - if true, retrieve connections where "plug" is
+// the source of the connection.
+// asDst - if true, retrieve connections where "plug" is
+// the target of the connection.
+//
+// Returns: true, if the plug has connections; false, otherwise
+//
+// Constraints: NONE
+//
+//-----------------------------------------------------------------------------
+void MExt::ResolveConnections( MPlugArray* sources,
+ MPlugArray* targets,
+ MPlug& plug,
+ bool asDst,
+ bool asSrc
+ )
+{
+ assert( sources );
+ assert( targets );
+
+ MStatus status;
+ MPlugArray myPlugs;
+ unsigned int count = 0;
+ unsigned int i = 0;
+
+ if ( plug.isArray() )
+ {
+ count = plug.numElements( &status );
+ assert( status );
+
+ for ( i = 0; i < count; i++ )
+ {
+ MPlug element = plug.elementByPhysicalIndex( i, &status );
+ assert( status );
+
+ if ( element.isConnected() )
+ {
+
+ MString name = element.name();
+ const char* dbg_name = name.asChar();
+
+ myPlugs.append( element );
+ }
+ }
+ }
+ else
+ {
+ myPlugs.append( plug );
+ }
+
+ sources->clear();
+ targets->clear();
+ count = myPlugs.length();
+ for ( i = 0; i < count; i++ )
+ {
+ MPlugArray connectedPlugs;
+
+ if ( asDst )
+ {
+ myPlugs[i].connectedTo( connectedPlugs, true, false, &status );
+ assert( status );
+
+ if ( connectedPlugs.length() > 0 )
+ {
+ sources->append( connectedPlugs[0] );
+ targets->append( myPlugs[i] );
+ }
+ }
+
+ if ( asSrc )
+ {
+ myPlugs[i].connectedTo( connectedPlugs, false, true, &status );
+ assert( status );
+
+ if ( connectedPlugs.length() > 0 )
+ {
+ sources->append( myPlugs[i] );
+ targets->append( connectedPlugs[0] );
+ }
+ }
+ }
+
+ assert( sources->length() == targets->length() );
+}
+
+//-----------------------------------------------------------------------------
+// S e l e c t N o d e s B e l o w R o o t
+//
+// Synopsis: Select nodes meeting the specified criteria and place them
+// in the provided selection list.
+//
+// Parameters: list - the list to receive the nodes.
+// typeId - the typeId of the node type to select.
+// root - the root of the subsection of the DAG to search.
+//
+// Returns: NOTHING
+//
+// Constraints: NONE
+//
+//-----------------------------------------------------------------------------
+void MExt::SelectNodesBelowRoot( MSelectionList* list,
+ const MString& typeName,
+ const MObject& root,
+ MSelectionList* intersectionList
+ )
+{
+ assert( list );
+
+ MStatus status;
+
+ bool mergeWithExisting = true;
+
+ MItDag itor;
+
+ if ( root != MObject::kNullObj )
+ {
+ itor.reset( root );
+ }
+
+ while( ! itor.isDone() )
+ {
+ MFnDependencyNode fnNode;
+ fnNode.setObject( itor.item() );
+
+ if ( fnNode.typeName() == typeName )
+ {
+ bool doAdd = true;
+
+ if ( intersectionList )
+ {
+ MDagPath path;
+ status = MDagPath::getAPathTo( fnNode.object(), path );
+
+ //
+ // We only add the item if it is in the intersectionList.
+ //
+ if ( ! intersectionList->hasItem( path ) )
+ {
+ doAdd = false;
+ }
+ }
+
+ if ( doAdd )
+ {
+ list->add( fnNode.object(), mergeWithExisting );
+ }
+ }
+
+ itor.next();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// S e t W o r l d P o s i t i o n
+//
+// Synopsis: Sets the world position of the given node.
+//
+// Parameters: wp - the new world position.
+// node - the node for which to set the position.
+//
+// Returns: Hopefully MS::kSuccess, but other MS::????? errors will occur
+// if the object is not a suitable type of node.
+//
+// Constraints: NONE
+//
+//-----------------------------------------------------------------------------
+void MExt::SetWorldPosition( const MPoint& wp, const MObject& node )
+{
+ MStatus status;
+
+ MFnDependencyNode fnNode( node );
+
+ //
+ // Attempt to get the world matrix attribute.
+ //
+ MObject attrObject = fnNode.attribute( "worldMatrix", &status );
+ assert( status );
+
+ //
+ // Build the world matrix plug. Use the first element on the plug.
+ //
+ MPlug plug( const_cast<MObject&>(node), attrObject );
+ plug = plug.elementByLogicalIndex( 0, &status );
+ assert( status );
+
+ //
+ // Get the world matrix. We have to go through a few Maya layers on this
+ // one.
+ //
+ MObject matrixObject;
+ status = plug.getValue( matrixObject );
+ assert( status );
+
+ MFnMatrixData matrixData( matrixObject, &status );
+ assert( status );
+
+ //
+ // Create a world tranformation matrix.
+ //
+ MTransformationMatrix matrix( matrixData.matrix( &status ) );
+ assert( status );
+
+ //
+ // Get the world translation vector.
+ //
+ MVector worldTranslation = matrix.translation( MSpace::kWorld, &status );
+
+
+ //
+ // Get the nodes immediate transform and create a function wrapper for it.
+ //
+ MDagPath nodePath;
+ status = MDagPath::getAPathTo( node, nodePath );
+ assert( status );
+
+ MObject transformObject = nodePath.transform( &status );
+ assert( status );
+
+ MFnTransform fnTransform( transformObject, &status );
+ assert( status );
+
+ //
+ // Get the node translation vector.
+ //
+ MVector nodeTranslation = fnTransform.translation( MSpace::kTransform, &status );
+
+ //
+ // The exclusive translation vector is that vector which reflect the
+ // amount of translation the node undergoes as a result of transforms
+ // exclusive of its immediate parent.
+ //
+ MVector exclusiveTranslation = worldTranslation - nodeTranslation;
+
+ //
+ // Set the nodeTranslation to that or our desired world position less the
+ // exclusiveTranslation vector.
+ //
+ MVector position( wp );
+ nodeTranslation = position - exclusiveTranslation;
+
+ //
+ // Push the result back into the transform and we are done.
+ //
+ status = fnTransform.setTranslation( nodeTranslation, MSpace::kTransform );
+ assert( status );
+
+}
+
+//-----------------------------------------------------------------------------
+// v i e w T o W o r l d A t Y
+//
+// Synopsis: Convert the specified view coordinates to world coordinates on
+// the specified y plane.
+//
+// Parameters: world - reference parameter to recieve the world coordinates.
+// view - the view position to be converted.
+// y - the y plane to translate to.
+//
+// Returns: The status of the request. Will return failure if the the
+// view plane is perpendicular to the y-plane.
+//
+// Constraints: NONE
+//
+//-----------------------------------------------------------------------------
+void MExt::ViewToWorldAtY( MPoint* wc, MPoint& vc, double y )
+{
+ assert( wc );
+
+ MStatus status = MS::kFailure;
+
+ M3dView view = M3dView::active3dView();
+ MPoint rayOrigin;
+ MVector rayVector;
+ status = view.viewToWorld( static_cast<short>(vc.x),
+ static_cast<short>(vc.y),
+ rayOrigin,
+ rayVector
+ );
+ assert( status );
+
+ MPoint result;
+ if ( fabs(rayVector.y) > EPSILON )
+ {
+ //
+ // The following formulas for x and z use the point slope formula in
+ // the form
+ // x = ( y - y0 ) / M + x0
+ // = ( y - y0 ) / ( dy / dx ) + x0
+ // = ( ( y - y0 ) / dy ) * dx + x0
+ //
+ double coeff = ( y - rayOrigin.y ) / rayVector.y;
+ wc->x = ( coeff * rayVector.x ) + rayOrigin.x;
+ wc->y = y;
+ wc->z = ( coeff * rayVector.z ) + rayOrigin.z;
+ }
+}