The-Simpsons-Hit-and-Run/tools/objectsnapper/code/commands/snapselected.cpp

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();
}
}