436 lines
13 KiB
C++
436 lines
13 KiB
C++
//=============================================================================
|
|
// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
|
|
//
|
|
// File:
|
|
//
|
|
// Description: Implement SnapSelectedCmd
|
|
//
|
|
// History: 18/03/2002 + Created -- Cary Brisebois
|
|
//
|
|
//=============================================================================
|
|
|
|
//========================================
|
|
// System Includes
|
|
//========================================
|
|
// Foundation Tech
|
|
|
|
//========================================
|
|
// Project Includes
|
|
//========================================
|
|
#include "snapselected.h"
|
|
#include "utility/MUI.h"
|
|
#include "utility/mext.h"
|
|
|
|
|
|
//******************************************************************************
|
|
//
|
|
// Global Data, Local Data, Local Classes
|
|
//
|
|
//******************************************************************************
|
|
|
|
const char* SnapSelectedCmd::stringId = "OS_SnapSelected";
|
|
const double OSScale = 100.0;
|
|
|
|
enum SnapType
|
|
{
|
|
ALL,
|
|
SINGLE,
|
|
TREELINE
|
|
};
|
|
|
|
//******************************************************************************
|
|
//
|
|
// Public Member Functions
|
|
//
|
|
//******************************************************************************
|
|
|
|
//==============================================================================
|
|
// SnapSelectedCmd::SnapSelectedCmd
|
|
//==============================================================================
|
|
// Description: Constructor.
|
|
//
|
|
// Parameters: None.
|
|
//
|
|
// Return: N/A.
|
|
//
|
|
//==============================================================================
|
|
SnapSelectedCmd::SnapSelectedCmd()
|
|
{
|
|
mObjDagPaths.clear();
|
|
mNewPositions.clear();
|
|
mOldPositions.clear();
|
|
}
|
|
|
|
//==============================================================================
|
|
// SnapSelectedCmd::~SnapSelectedCmd
|
|
//==============================================================================
|
|
// Description: Destructor.
|
|
//
|
|
// Parameters: None.
|
|
//
|
|
// Return: N/A.
|
|
//
|
|
//==============================================================================
|
|
SnapSelectedCmd::~SnapSelectedCmd()
|
|
{
|
|
}
|
|
|
|
//==============================================================================
|
|
// SnapSelectedCmd::creator
|
|
//==============================================================================
|
|
// Description: Comment
|
|
//
|
|
// Parameters: ()
|
|
//
|
|
// Return: void
|
|
//
|
|
//==============================================================================
|
|
void* SnapSelectedCmd::creator()
|
|
{
|
|
return new SnapSelectedCmd();
|
|
}
|
|
|
|
//==============================================================================
|
|
// SnapSelectedCmd::doit
|
|
//==============================================================================
|
|
// Description: Comment
|
|
//
|
|
// Parameters: ( const MArgList& args )
|
|
//
|
|
// Return: MStatus
|
|
//
|
|
//==============================================================================
|
|
MStatus SnapSelectedCmd::doIt( const MArgList& args )
|
|
{
|
|
if ( !MUI::ConfirmDialog( "Are you sure you want to snap these objects?\nYou can not UNDO this command." ) == MUI::YES )
|
|
{
|
|
//quit.
|
|
return MStatus::kSuccess;
|
|
}
|
|
|
|
assert( args.length() == 2 );
|
|
|
|
double OFFSET = 0;
|
|
int snapType = ALL;
|
|
|
|
args.get( 0, OFFSET );
|
|
args.get( 1, snapType );
|
|
|
|
OFFSET *= OSScale;
|
|
|
|
MSelectionList list;
|
|
MGlobal::getActiveSelectionList( list );
|
|
|
|
MItSelectionList i( list );
|
|
|
|
MFnDagNode fnDagNode;
|
|
MDagPath dagPath;
|
|
MItDag itDag;
|
|
MObject obj;
|
|
MDagPath objDagPath;
|
|
MObject childObj;
|
|
|
|
//For all selected objects.
|
|
for ( ; !i.isDone(); i.next() )
|
|
{
|
|
i.getDagPath( dagPath );
|
|
|
|
itDag.reset( dagPath, MItDag::kBreadthFirst, MFn::kTransform );
|
|
|
|
for ( ; !itDag.isDone() && itDag.depth() < 2; itDag.next() )
|
|
{
|
|
obj = itDag.item();
|
|
fnDagNode.setObject( obj );
|
|
|
|
const char* objName = fnDagNode.name().asChar();
|
|
const char* objTypeName = fnDagNode.typeName().asChar();
|
|
|
|
int childCount = fnDagNode.childCount();
|
|
|
|
int whichChild;
|
|
|
|
for ( whichChild = 0; whichChild < childCount; ++whichChild )
|
|
{
|
|
childObj = fnDagNode.child( whichChild );
|
|
fnDagNode.setObject( childObj );
|
|
|
|
const char* childObjName = fnDagNode.name().asChar();
|
|
const char* childObjTypeName = fnDagNode.typeName().asChar();
|
|
|
|
//Find a mesh below me and move my pivot to the intersection.
|
|
itDag.getPath( objDagPath );
|
|
MFnTransform fnTrans( objDagPath );
|
|
|
|
//Get all the child meshes of this obj node to prevent snapping to
|
|
//something that is part of me.
|
|
|
|
MStringArray meshNames;
|
|
|
|
GetChildMeshNames( objDagPath, meshNames );
|
|
|
|
|
|
MVector pos = fnTrans.translation( MSpace::kWorld );
|
|
MPoint rotate = fnTrans.rotatePivot( MSpace::kWorld );
|
|
MVector rayDir( 0, -1.0, 0 );
|
|
|
|
MItDag meshIt( MItDag::kDepthFirst, MFn::kMesh );
|
|
MDagPath meshDagPath;
|
|
MPointArray intersectPoints;
|
|
|
|
bool found = false;
|
|
|
|
for ( ; !meshIt.isDone(); meshIt.next() )
|
|
{
|
|
meshIt.getPath( meshDagPath );
|
|
MFnMesh mesh( meshDagPath );
|
|
|
|
const char* meshName = mesh.name().asChar();
|
|
|
|
unsigned int i;
|
|
bool nameFound = false;
|
|
for ( i = 0; i < meshNames.length(); ++i )
|
|
{
|
|
if ( meshNames[i] == mesh.name() )
|
|
{
|
|
nameFound = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( nameFound )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if ( snapType == TREELINE )
|
|
{
|
|
|
|
}
|
|
else
|
|
{
|
|
mesh.intersect( rotate, rayDir, intersectPoints, 0.001f, MSpace::kWorld );
|
|
|
|
if ( intersectPoints.length() > 0 )
|
|
{
|
|
MVector diff( intersectPoints[ 0 ] - rotate );
|
|
diff.y += OFFSET;
|
|
|
|
//Prepare the command for the redo it ( which does all the work )
|
|
mObjDagPaths.append( fnTrans.dagPath() );
|
|
mNewPositions.append( diff );
|
|
|
|
//Save the old position.
|
|
MVector vector = fnTrans.translation( MSpace::kObject );
|
|
mOldPositions.append( vector );
|
|
|
|
// //Move the transform.
|
|
// fnTrans.translateBy( diff, MSpace::kWorld );
|
|
|
|
found = true;
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( !found )
|
|
{
|
|
//Look up
|
|
MPoint rotate = fnTrans.rotatePivot( MSpace::kWorld );
|
|
MVector rayDir( 0, 1.0, 0 );
|
|
|
|
MItDag meshIt( MItDag::kDepthFirst, MFn::kMesh );
|
|
MDagPath meshDagPath;
|
|
MPointArray intersectPoints;
|
|
|
|
for ( ; !meshIt.isDone(); meshIt.next() )
|
|
{
|
|
meshIt.getPath( meshDagPath );
|
|
MFnMesh mesh( meshDagPath );
|
|
|
|
const char* meshName = mesh.name().asChar();
|
|
|
|
unsigned int i;
|
|
bool nameFound = false;
|
|
for ( i = 0; i < meshNames.length(); ++i )
|
|
{
|
|
if ( meshNames[i] == mesh.name() )
|
|
{
|
|
nameFound = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( nameFound )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if ( snapType == TREELINE )
|
|
{
|
|
|
|
}
|
|
else
|
|
{
|
|
mesh.intersect( rotate, rayDir, intersectPoints, 0.001f, MSpace::kWorld );
|
|
|
|
if ( intersectPoints.length() > 0 )
|
|
{
|
|
MVector diff( intersectPoints[ 0 ] - rotate );
|
|
diff.y -= OFFSET;
|
|
|
|
//Prepare the command for the redo it ( which does all the work )
|
|
mObjDagPaths.append( fnTrans.dagPath() );
|
|
mNewPositions.append( diff );
|
|
|
|
//Save the old position.
|
|
MVector vector = fnTrans.translation( MSpace::kObject );
|
|
mOldPositions.append( vector );
|
|
|
|
// //Move the transform.
|
|
// fnTrans.translateBy( diff, MSpace::kWorld );
|
|
|
|
found = true;
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( !found )
|
|
{
|
|
MString errorMsg( "The object: " );
|
|
errorMsg += fnTrans.name();
|
|
errorMsg += MString( " has no mesh below it.\nNo snapping done on it." );
|
|
|
|
MUI::InfoDialog( errorMsg.asChar() );
|
|
}
|
|
}
|
|
|
|
if ( snapType == SINGLE )
|
|
{
|
|
//No more iterations.
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
redoIt();
|
|
|
|
return MStatus::kSuccess;
|
|
}
|
|
|
|
//=============================================================================
|
|
// SnapSelectedCmd::undoIt
|
|
//=============================================================================
|
|
// Description: Comment
|
|
//
|
|
// Parameters: ()
|
|
//
|
|
// Return: MStatus
|
|
//
|
|
//=============================================================================
|
|
MStatus SnapSelectedCmd::undoIt()
|
|
{
|
|
unsigned int i;
|
|
for ( i = 0; i < mObjDagPaths.length(); ++i )
|
|
{
|
|
if ( mObjDagPaths[i].isValid() )
|
|
{
|
|
//Move this guy to the new position.
|
|
MFnTransform fnTransform( mObjDagPaths[i] );
|
|
|
|
fnTransform.setTranslation( mOldPositions[i], MSpace::kObject );
|
|
}
|
|
else
|
|
{
|
|
MExt::DisplayError( "Error performing snap due to invalid object or change in heirarchy" );
|
|
}
|
|
}
|
|
|
|
return MStatus::kSuccess;
|
|
}
|
|
|
|
//=============================================================================
|
|
// SnapSelectedCmd::redoIt
|
|
//=============================================================================
|
|
// Description: Comment
|
|
//
|
|
// Parameters: ()
|
|
//
|
|
// Return: MStatus
|
|
//
|
|
//=============================================================================
|
|
MStatus SnapSelectedCmd::redoIt()
|
|
{
|
|
unsigned int i;
|
|
for ( i = 0; i < mObjDagPaths.length(); ++i )
|
|
{
|
|
if ( mObjDagPaths[i].isValid() )
|
|
{
|
|
//Move this guy to the new position.
|
|
MFnTransform fnTransform( mObjDagPaths[i] );
|
|
|
|
fnTransform.translateBy( mNewPositions[i], MSpace::kWorld );
|
|
}
|
|
else
|
|
{
|
|
MExt::DisplayError( "Error performing snap due to invalid object or change in heirarchy" );
|
|
}
|
|
}
|
|
|
|
return MStatus::kSuccess;
|
|
}
|
|
|
|
//=============================================================================
|
|
// SnapSelectedCmd::isUndoable
|
|
//=============================================================================
|
|
// Description: Comment
|
|
//
|
|
// Parameters: ()
|
|
//
|
|
// Return: bool
|
|
//
|
|
//=============================================================================
|
|
bool SnapSelectedCmd::isUndoable() const
|
|
{
|
|
return true;
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// Private Member Functions
|
|
//
|
|
//******************************************************************************
|
|
|
|
//==============================================================================
|
|
// SnapSelectedCmd::GetChildMeshNames
|
|
//==============================================================================
|
|
// Description: Comment
|
|
//
|
|
// Parameters: ( MDagPath objDagPath, MStringArray& names )
|
|
//
|
|
// Return: void
|
|
//
|
|
//==============================================================================
|
|
void SnapSelectedCmd::GetChildMeshNames( MDagPath objDagPath, MStringArray& names )
|
|
{
|
|
names.clear();
|
|
|
|
MItDag itDag;
|
|
itDag.reset( objDagPath, MItDag::kDepthFirst, MFn::kMesh );
|
|
|
|
for ( ; !itDag.isDone(); itDag.next() )
|
|
{
|
|
MDagPath dagPath;
|
|
itDag.getPath( dagPath );
|
|
MFnMesh fnMesh( dagPath );
|
|
|
|
names.append( fnMesh.name() );
|
|
|
|
const char* meshName = fnMesh.name().asChar();
|
|
}
|
|
|
|
}
|