718 lines
18 KiB
C++
718 lines
18 KiB
C++
//----------------------------------------
|
|
// System Includes
|
|
//----------------------------------------
|
|
|
|
|
|
//----------------------------------------
|
|
// Project Includes
|
|
//----------------------------------------
|
|
|
|
#include "ppcontext.h"
|
|
#include "utility/Mext.h"
|
|
#include "nodes/pedpath.h"
|
|
#include "nodes/nu.h"
|
|
#include "nodes/walllocator.h"
|
|
#include "main/trackeditor.h"
|
|
|
|
//----------------------------------------
|
|
// Constants, Typedefs and Statics
|
|
//----------------------------------------
|
|
const char* PPContext::stringId = "PPContext";
|
|
const MString PPContext::DEFAULT_GROUP_NAME = "PedPath";
|
|
MObject PPContext::sCurrentGroup;
|
|
|
|
|
|
const char* PPSplitCmd::stringId = "PPSplitSelected";
|
|
|
|
//==============================================================================
|
|
// PPContextCmd::PPContextCmd
|
|
//==============================================================================
|
|
// Description: Comment
|
|
//
|
|
// Parameters: ()
|
|
//
|
|
// Return: PPContextCmd
|
|
//
|
|
//==============================================================================
|
|
PPContextCmd::PPContextCmd()
|
|
{
|
|
}
|
|
|
|
//==============================================================================
|
|
// PPContextCmd::~PPContextCmd
|
|
//==============================================================================
|
|
// Description: Comment
|
|
//
|
|
// Parameters: ()
|
|
//
|
|
// Return: PPContextCmd
|
|
//
|
|
//==============================================================================
|
|
PPContextCmd::~PPContextCmd()
|
|
{
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// c r e a t o r
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Parameters: NONE
|
|
//
|
|
// Returns: NOTHING
|
|
//
|
|
// Constraints: NONE
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void* PPContextCmd::creator()
|
|
{
|
|
return new PPContextCmd();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// m a k e O b j
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Parameters: NONE
|
|
//
|
|
// Returns: NOTHING
|
|
//
|
|
// Constraints: NONE
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
MPxContext* PPContextCmd::makeObj()
|
|
{
|
|
return new PPContext();
|
|
}
|
|
|
|
//==============================================================================
|
|
// PPContext::PPContext
|
|
//==============================================================================
|
|
// Description: Comment
|
|
//
|
|
// Parameters: ()
|
|
//
|
|
// Return: PPContext
|
|
//
|
|
//==============================================================================
|
|
PPContext::PPContext() :
|
|
mXCurrent( 0 ),
|
|
mYCurrent( 0 )
|
|
{
|
|
SetHelpString();
|
|
|
|
setTitleString( "Pedestrian Path Tool" );
|
|
}
|
|
|
|
//==============================================================================
|
|
// PPContext::~PPContext
|
|
//==============================================================================
|
|
// Description: Comment
|
|
//
|
|
// Parameters: ()
|
|
//
|
|
// Return: PPContext
|
|
//
|
|
//==============================================================================
|
|
PPContext::~PPContext()
|
|
{
|
|
}
|
|
|
|
//==============================================================================
|
|
// PPContext::abortAction
|
|
//==============================================================================
|
|
// Description: Comment
|
|
//
|
|
// Parameters: ()
|
|
//
|
|
// Return: void
|
|
//
|
|
//==============================================================================
|
|
void PPContext::abortAction()
|
|
{
|
|
ProcessState( ABORTED );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// c o m p l e t e A c t i o n
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Parameters: NONE
|
|
//
|
|
// Returns: NOTHING
|
|
//
|
|
// Constraints: NONE
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void PPContext::completeAction()
|
|
{
|
|
ProcessState( COMPLETED );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// d e l e t e A c t i o n
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Parameters: NONE
|
|
//
|
|
// Returns: NOTHING
|
|
//
|
|
// Constraints: NONE
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void PPContext::deleteAction()
|
|
{
|
|
ProcessState( DELETED );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// d o D r a g
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Parameters: NONE
|
|
//
|
|
// Returns: NOTHING
|
|
//
|
|
// Constraints: NONE
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
MStatus PPContext::doDrag( MEvent& event )
|
|
{
|
|
|
|
event.getPosition( mXCurrent, mYCurrent );
|
|
ProcessState( MOUSEDRAG );
|
|
return MS::kSuccess;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// d o E n t e r R e g i o n
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Parameters: NONE
|
|
//
|
|
// Returns: NOTHING
|
|
//
|
|
// Constraints: NONE
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
MStatus PPContext::doEnterRegion( MEvent& event )
|
|
{
|
|
SetHelpString();
|
|
|
|
return MS::kSuccess;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// d o H o l d
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Parameters: NONE
|
|
//
|
|
// Returns: NOTHING
|
|
//
|
|
// Constraints: NONE
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
MStatus PPContext::doHold( MEvent& event )
|
|
{
|
|
MStatus status = MS::kSuccess;
|
|
return status;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// d o P r e s s
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Parameters: NONE
|
|
//
|
|
// Returns: NOTHING
|
|
//
|
|
// Constraints: NONE
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
MStatus PPContext::doPress( MEvent& event )
|
|
{
|
|
event.getPosition( mXCurrent, mYCurrent );
|
|
ProcessState( BUTTONDOWN );
|
|
return MS::kSuccess;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// d o R e l e a s e
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Parameters: NONE
|
|
//
|
|
// Returns: NOTHING
|
|
//
|
|
// Constraints: NONE
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
MStatus PPContext::doRelease( MEvent& event )
|
|
{
|
|
if ( event.mouseButton() == MEvent::kLeftMouse )
|
|
{
|
|
event.getPosition( mXCurrent, mYCurrent );
|
|
ProcessState( BUTTONUP );
|
|
}
|
|
|
|
return MS::kSuccess;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// t o o l O f f C l e a n u p
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Parameters: NONE
|
|
//
|
|
// Returns: NOTHING
|
|
//
|
|
// Constraints: NONE
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void PPContext::toolOffCleanup()
|
|
{
|
|
CloseLoop();
|
|
mPoints.clear();
|
|
sCurrentGroup = MObject::kNullObj;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// t o o l O n S e t u p
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Parameters: NONE
|
|
//
|
|
// Returns: NOTHING
|
|
//
|
|
// Constraints: NONE
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void PPContext::toolOnSetup( MEvent& event )
|
|
{
|
|
setCursor( MCursor::crossHairCursor );
|
|
|
|
mPoints.clear();
|
|
sCurrentGroup = MObject::kNullObj;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// P R I V A T E M E M B E R S
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// p r o c e s s S t a t e
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Parameters: NONE
|
|
//
|
|
// Returns: NOTHING
|
|
//
|
|
// Constraints: NONE
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void PPContext::ProcessState( Stimulus stimulus )
|
|
{
|
|
switch( stimulus )
|
|
{
|
|
case BUTTONDOWN:
|
|
{
|
|
}
|
|
break;
|
|
|
|
case BUTTONUP:
|
|
{
|
|
MObject newNode;
|
|
MObject nodeTransform;
|
|
|
|
MExt::CreateNode( newNode, nodeTransform, MString( WallLocatorNode::stringId ) );
|
|
|
|
// NODE_UTIL::DisableAttributes( newNode, false );
|
|
MFnDagNode fnDagNode( newNode );
|
|
|
|
MObject parent = fnDagNode.parent( 0 );
|
|
MFnDependencyNode fnParent( parent );
|
|
MPlug spPlug = fnParent.findPlug( MString( "scale" ) );
|
|
spPlug.setLocked( true );
|
|
|
|
MPlug rpPlug = fnParent.findPlug( MString( "rotate" ) );
|
|
rpPlug.setLocked( true );
|
|
|
|
|
|
MExt::Attr::Set( WallLocatorNode::NONE,
|
|
newNode,
|
|
WallLocatorNode::LEFTRIGHT_NAME_LONG );
|
|
|
|
//Set the position
|
|
MPoint intersectPoint;
|
|
if ( !MExt::MeshClickIntersect( mXCurrent, mYCurrent, intersectPoint ) )
|
|
{
|
|
//Put it at 0.
|
|
MPoint vp( mXCurrent, mYCurrent, 0 );
|
|
MExt::ViewToWorldAtY( &intersectPoint, vp, 0 ); //This is to y = 0
|
|
}
|
|
|
|
// intersectPoint = intersectPoint / TEConstants::Scale;
|
|
|
|
MExt::SetWorldPosition( intersectPoint, newNode );
|
|
|
|
AddPoint( newNode );
|
|
}
|
|
break;
|
|
case DELETED:
|
|
{
|
|
DeleteLast();
|
|
}
|
|
break;
|
|
case COMPLETED:
|
|
{
|
|
//Complete the loop and start a new one.
|
|
CloseLoop();
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
}
|
|
break;
|
|
}
|
|
|
|
SetHelpString();
|
|
}
|
|
|
|
//==============================================================================
|
|
// PPContext::AddPoint
|
|
//==============================================================================
|
|
// Description: Comment
|
|
//
|
|
// Parameters: ( MObject obj )
|
|
//
|
|
// Return: void
|
|
//
|
|
//==============================================================================
|
|
void PPContext::AddPoint( MObject obj )
|
|
{
|
|
MStatus status;
|
|
unsigned int size = mPoints.length();
|
|
|
|
if ( size )
|
|
{
|
|
MObject lastNode;
|
|
|
|
lastNode = mPoints[ size - 1 ];
|
|
|
|
if ( lastNode.isNull() )
|
|
{
|
|
//Someone has been deleting nodes.
|
|
MExt::DisplayError( "Someone has deleted something..." );
|
|
return;
|
|
}
|
|
|
|
MExt::Connect( lastNode, WallLocatorNode::NEXTNODE_NAME_LONG, obj, WallLocatorNode::PREVNODE_NAME_LONG );
|
|
}
|
|
else
|
|
{
|
|
//Starting a new group
|
|
MObject flT;
|
|
MString name( DEFAULT_GROUP_NAME );
|
|
|
|
MExt::CreateNode( sCurrentGroup, flT, MString( PedPathNode::stringId ), &name );
|
|
|
|
//Parent this group to the main TrackEditor Node if it exists.
|
|
TrackEditor::AddChild( sCurrentGroup );
|
|
}
|
|
|
|
mPoints.append( obj );
|
|
|
|
//Add the point (wall) to the current fence
|
|
PedPathNode::AddWall( sCurrentGroup, obj );
|
|
}
|
|
|
|
//==============================================================================
|
|
// PPContext::DeleteLast
|
|
//==============================================================================
|
|
// Description: Comment
|
|
//
|
|
// Parameters: ()
|
|
//
|
|
// Return: void
|
|
//
|
|
//==============================================================================
|
|
void PPContext::DeleteLast()
|
|
{
|
|
unsigned int size = mPoints.length();
|
|
|
|
if ( size )
|
|
{
|
|
MStatus status;
|
|
|
|
MObject obj = mPoints[ size - 1 ];
|
|
mPoints.remove( size - 1 );
|
|
|
|
MExt::DeleteNode( obj, true );
|
|
}
|
|
|
|
if ( mPoints.length() == 0 && !sCurrentGroup.isNull() )
|
|
{
|
|
//we deleted the last one.
|
|
//Remove the group object.
|
|
MExt::DeleteNode( sCurrentGroup, true );
|
|
}
|
|
}
|
|
|
|
//==============================================================================
|
|
// PPContext::CloseLoop
|
|
//==============================================================================
|
|
// Description: Comment
|
|
//
|
|
// Parameters: ()
|
|
//
|
|
// Return: void
|
|
//
|
|
//==============================================================================
|
|
void PPContext::CloseLoop()
|
|
{
|
|
unsigned int size = mPoints.length();
|
|
|
|
if ( size == 1 )
|
|
{
|
|
MExt::DisplayWarning( "There was only one point in the PP loop. It will be deleted." );
|
|
|
|
DeleteLast();
|
|
}
|
|
else if ( size == 2 )
|
|
{
|
|
MExt::DisplayWarning( "There were only two points in the PP loop. They will be deleted." );
|
|
|
|
DeleteLast();
|
|
DeleteLast();
|
|
}
|
|
else if ( size > 2 )
|
|
{
|
|
MObject lastNode, firstNode;
|
|
MStatus status;
|
|
|
|
lastNode = mPoints[ size - 1 ];
|
|
firstNode = mPoints[ 0 ];
|
|
|
|
MExt::Connect( lastNode, WallLocatorNode::NEXTNODE_NAME_LONG, firstNode, WallLocatorNode::PREVNODE_NAME_LONG );
|
|
|
|
//Clear the points list to start a new loop.
|
|
mPoints.clear();
|
|
sCurrentGroup;
|
|
}
|
|
}
|
|
|
|
//==============================================================================
|
|
// PPContext::SetHelpString
|
|
//==============================================================================
|
|
// Description: Comment
|
|
//
|
|
// Parameters: ()
|
|
//
|
|
// Return: void
|
|
//
|
|
//==============================================================================
|
|
void PPContext::SetHelpString()
|
|
{
|
|
mHelp = "Click to place nodes in the path.";
|
|
|
|
setHelpString( mHelp );
|
|
|
|
}
|
|
|
|
//SPLIT COMMAND
|
|
//==============================================================================
|
|
// PPSplitCmd::creator
|
|
//==============================================================================
|
|
// Description: Comment
|
|
//
|
|
// Parameters: ()
|
|
//
|
|
// Return: void
|
|
//
|
|
//==============================================================================
|
|
void* PPSplitCmd::creator()
|
|
{
|
|
return new PPSplitCmd();
|
|
}
|
|
|
|
//==============================================================================
|
|
// PPSplitCmd::doIt
|
|
//==============================================================================
|
|
// Description: Comment
|
|
//
|
|
// Parameters: ( const MArgList &args )
|
|
//
|
|
// Return: MStatus
|
|
//
|
|
//==============================================================================
|
|
MStatus PPSplitCmd::doIt( const MArgList &args )
|
|
{
|
|
MSelectionList selectionList;
|
|
|
|
MGlobal::getActiveSelectionList( selectionList );
|
|
|
|
if ( selectionList.isEmpty() )
|
|
{
|
|
//Nothing to do.
|
|
return MS::kSuccess;
|
|
}
|
|
|
|
//Get the number of objects in the list.
|
|
unsigned int numObjs = selectionList.length();
|
|
|
|
MObject obj;
|
|
MFnDependencyNode fnNode;
|
|
MObjectArray objArray;
|
|
|
|
unsigned int i;
|
|
for ( i = 0; i < numObjs; ++i )
|
|
{
|
|
selectionList.getDependNode( i, obj );
|
|
fnNode.setObject( obj );
|
|
|
|
if ( fnNode.typeId() == WallLocatorNode::id )
|
|
{
|
|
//This is a wall locator, add it to the array.
|
|
objArray.append( obj );
|
|
}
|
|
else
|
|
{
|
|
//This could be a transform, let's test the child node.
|
|
MFnDagNode dagNode( obj );
|
|
if( dagNode.childCount() )
|
|
{
|
|
//Get the first child
|
|
MObject child = dagNode.child( 0 );
|
|
|
|
fnNode.setObject( child );
|
|
if ( fnNode.typeId() == WallLocatorNode::id )
|
|
{
|
|
//This is a wall locator, add it to the array.
|
|
objArray.append( child );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( objArray.length() <= 1 )
|
|
{
|
|
//Nothing to do.
|
|
return MS::kSuccess;
|
|
}
|
|
|
|
//For each object in the objArray that is connected to another, create a node in-between...
|
|
MStatus status;
|
|
MObject obj1, obj2;
|
|
MFnDependencyNode fnNode1, fnNode2;
|
|
MPlug nextPlug, prevPlug;
|
|
|
|
unsigned int j;
|
|
for ( i = 0; i < objArray.length() - 1; ++i )
|
|
{
|
|
for ( j = i + 1; j < objArray.length(); ++j )
|
|
{
|
|
//Check if i and j are connected.
|
|
obj1 = objArray[i];
|
|
obj2 = objArray[j];
|
|
|
|
fnNode1.setObject( obj1 );
|
|
fnNode2.setObject( obj2 );
|
|
|
|
//Compare obj1.next to obj2.prev
|
|
nextPlug = fnNode1.findPlug( WallLocatorNode::NEXTNODE_NAME_LONG, &status );
|
|
assert( status );
|
|
prevPlug = fnNode2.findPlug( WallLocatorNode::PREVNODE_NAME_LONG, &status );
|
|
assert( status );
|
|
|
|
if ( MExt::IsConnected( nextPlug, prevPlug ) )
|
|
{
|
|
//Split and connect these two objects.
|
|
Split( obj1, obj2 );
|
|
}
|
|
else
|
|
{
|
|
//Compare obj2.next to obj1.prev
|
|
nextPlug = fnNode2.findPlug( WallLocatorNode::NEXTNODE_NAME_LONG, &status );
|
|
assert( status );
|
|
prevPlug = fnNode1.findPlug( WallLocatorNode::PREVNODE_NAME_LONG, &status );
|
|
assert( status );
|
|
|
|
if ( MExt::IsConnected( nextPlug, prevPlug ) )
|
|
{
|
|
//Split and connect these two objects.
|
|
Split( obj2, obj1 );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return MS::kSuccess;
|
|
}
|
|
|
|
//==============================================================================
|
|
// PPSplitCmd::Split
|
|
//==============================================================================
|
|
// Description: Comment
|
|
//
|
|
// Parameters: ( MObject& node1, MObject& node2 )
|
|
//
|
|
// Return: void
|
|
//
|
|
//==============================================================================
|
|
void PPSplitCmd::Split( MObject& node1, MObject& node2 )
|
|
{
|
|
//Take node1 and node2, create a newNode between them and connect
|
|
/// node1.next -> newNode.prev and newNode.next -> node2.prev
|
|
|
|
//Disconnect the nodes.
|
|
MExt::DisconnectAll( node1, WallLocatorNode::NEXTNODE_NAME_LONG );
|
|
|
|
MObject newNode;
|
|
MObject nodeTransform;
|
|
|
|
MExt::CreateNode( newNode, nodeTransform, MString( WallLocatorNode::stringId ) );
|
|
|
|
///NODE_UTIL::DisableAttributes( newNode );
|
|
|
|
//This will split based on one of the others.
|
|
MExt::Attr::Set( WallLocatorNode::NONE,
|
|
newNode,
|
|
WallLocatorNode::LEFTRIGHT_NAME_LONG );
|
|
|
|
MPoint newWP = MExt::GetWorldPositionBetween( node1, node2 );
|
|
//Lock the y to 0;
|
|
newWP[1] = 0;
|
|
|
|
MExt::SetWorldPosition( newWP, newNode );
|
|
|
|
//Connect the nodes in their new order.
|
|
MExt::Connect( node1, WallLocatorNode::NEXTNODE_NAME_LONG, newNode, WallLocatorNode::PREVNODE_NAME_LONG );
|
|
MExt::Connect( newNode, WallLocatorNode::NEXTNODE_NAME_LONG, node2, WallLocatorNode::PREVNODE_NAME_LONG );
|
|
|
|
//Make sure the node is parented properly...
|
|
|
|
MFnDagNode fnDagNode( node1 );
|
|
MObject parentT = fnDagNode.parent( 0 );
|
|
|
|
fnDagNode.setObject( parentT );
|
|
MObject groupT = fnDagNode.parent( 0 );
|
|
|
|
PedPathNode::AddWall( groupT, newNode );
|
|
}
|
|
|