//----------------------------------------
// System Includes
//----------------------------------------
//----------------------------------------
// Project Includes
//----------------------------------------
#include "bvcontext.h"
#include "utility/Mext.h"
#include "nodes/walllocator.h"
#include "nodes/fenceline.h"
#include "nodes/nu.h"
#include "main/trackeditor.h"
//----------------------------------------
// Constants, Typedefs and Statics
//----------------------------------------
const char* BVContext::stringId = "BVContext";
int BVContext::sLeftSide = WallLocatorNode::LEFT;
const MString BVContext::DEFAULT_GROUP_NAME = "FenceLine";
MObject BVContext::sCurrentGroup;
const char* BVSplitCmd::stringId = "BVSplitSelected";
//==============================================================================
// BVContextCmd::BVContextCmd
//==============================================================================
// Description: Comment
//
// Parameters: ()
//
// Return: BVContextCmd
//
//==============================================================================
BVContextCmd::BVContextCmd()
{
}
//==============================================================================
// BVContextCmd::~BVContextCmd
//==============================================================================
// Description: Comment
//
// Parameters: ()
//
// Return: BVContextCmd
//
//==============================================================================
BVContextCmd::~BVContextCmd()
{
}
//-----------------------------------------------------------------------------
// c r e a t o r
//
// Synopsis:
//
// Parameters: NONE
//
// Returns: NOTHING
//
// Constraints: NONE
//
//-----------------------------------------------------------------------------
void* BVContextCmd::creator()
{
return new BVContextCmd();
}
//-----------------------------------------------------------------------------
// m a k e O b j
//
// Synopsis:
//
// Parameters: NONE
//
// Returns: NOTHING
//
// Constraints: NONE
//
//-----------------------------------------------------------------------------
MPxContext* BVContextCmd::makeObj()
{
return new BVContext();
}
//==============================================================================
// BVContext::BVContext
//==============================================================================
// Description: Comment
//
// Parameters: ()
//
// Return: BVContext
//
//==============================================================================
BVContext::BVContext() :
mXCurrent( 0 ),
mYCurrent( 0 )
{
SetHelpString();
setTitleString( "Bounding Volume Path Tool" );
}
//==============================================================================
// BVContext::~BVContext
//==============================================================================
// Description: Comment
//
// Parameters: ()
//
// Return: BVContext
//
//==============================================================================
BVContext::~BVContext()
{
}
//==============================================================================
// BVContext::abortAction
//==============================================================================
// Description: Comment
//
// Parameters: ()
//
// Return: void
//
//==============================================================================
void BVContext::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 BVContext::completeAction()
{
ProcessState( COMPLETED );
}
//-----------------------------------------------------------------------------
// d e l e t e A c t i o n
//
// Synopsis:
//
// Parameters: NONE
//
// Returns: NOTHING
//
// Constraints: NONE
//
//-----------------------------------------------------------------------------
void BVContext::deleteAction()
{
ProcessState( DELETED );
}
//-----------------------------------------------------------------------------
// d o D r a g
//
// Synopsis:
//
// Parameters: NONE
//
// Returns: NOTHING
//
// Constraints: NONE
//
//-----------------------------------------------------------------------------
MStatus BVContext::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 BVContext::doEnterRegion( MEvent& event )
{
SetHelpString();
return MS::kSuccess;
}
//-----------------------------------------------------------------------------
// d o H o l d
//
// Synopsis:
//
// Parameters: NONE
//
// Returns: NOTHING
//
// Constraints: NONE
//
//-----------------------------------------------------------------------------
MStatus BVContext::doHold( MEvent& event )
{
MStatus status = MS::kSuccess;
return status;
}
//-----------------------------------------------------------------------------
// d o P r e s s
//
// Synopsis:
//
// Parameters: NONE
//
// Returns: NOTHING
//
// Constraints: NONE
//
//-----------------------------------------------------------------------------
MStatus BVContext::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 BVContext::doRelease( MEvent& event )
{
if ( event.mouseButton() == MEvent::kLeftMouse )
{
event.getPosition( mXCurrent, mYCurrent );
ProcessState( BUTTONUP );
}
else if ( event.mouseButton() == MEvent::kMiddleMouse )
{
//Toggle the leftness...
sLeftSide = sLeftSide == WallLocatorNode::LEFT ? WallLocatorNode::RIGHT : WallLocatorNode::LEFT;
SetHelpString();
}
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 BVContext::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 BVContext::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 BVContext::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 );
MExt::Attr::Set( sLeftSide,
newNode,
WallLocatorNode::LEFTRIGHT_NAME_LONG );
//Set the position
MPoint vp( mXCurrent, mYCurrent, 0 );
MPoint wp;
MExt::ViewToWorldAtY( &wp, vp, 0 );
MExt::SetWorldPosition( wp, newNode );
AddPoint( newNode );
}
break;
case DELETED:
{
DeleteLast();
}
break;
case COMPLETED:
{
//Complete the loop and start a new one.
CloseLoop();
}
break;
default:
{
}
break;
}
SetHelpString();
}
//==============================================================================
// BVContext::AddPoint
//==============================================================================
// Description: Comment
//
// Parameters: ( MObject obj )
//
// Return: void
//
//==============================================================================
void BVContext::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( FenceLineNode::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
FenceLineNode::AddWall( sCurrentGroup, obj );
}
//==============================================================================
// BVContext::DeleteLast
//==============================================================================
// Description: Comment
//
// Parameters: ()
//
// Return: void
//
//==============================================================================
void BVContext::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 );
}
}
//==============================================================================
// BVContext::CloseLoop
//==============================================================================
// Description: Comment
//
// Parameters: ()
//
// Return: void
//
//==============================================================================
void BVContext::CloseLoop()
{
unsigned int size = mPoints.length();
if ( size == 1 )
{
MExt::DisplayWarning( "There was only one point in the BV loop. It will be deleted." );
DeleteLast();
}
else if ( size == 2 )
{
MExt::DisplayWarning( "There were only two points in the BV 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;
}
}
//==============================================================================
// BVContext::SetHelpString
//==============================================================================
// Description: Comment
//
// Parameters: ()
//
// Return: void
//
//==============================================================================
void BVContext::SetHelpString()
{
mHelp = "Click to place nodes in the path.";
if ( sLeftSide )
{
mHelp += "LEFT-SIDED";
}
else
{
mHelp += "RIGHT-SIDED";
}
setHelpString( mHelp );
}
//SPLIT COMMAND
//==============================================================================
// BVSplitCmd::creator
//==============================================================================
// Description: Comment
//
// Parameters: ()
//
// Return: void
//
//==============================================================================
void* BVSplitCmd::creator()
{
return new BVSplitCmd();
}
//==============================================================================
// BVSplitCmd::doIt
//==============================================================================
// Description: Comment
//
// Parameters: ( const MArgList &args )
//
// Return: MStatus
//
//==============================================================================
MStatus BVSplitCmd::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;
}
//==============================================================================
// BVSplitCmd::Split
//==============================================================================
// Description: Comment
//
// Parameters: ( MObject& node1, MObject& node2 )
//
// Return: void
//
//==============================================================================
void BVSplitCmd::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.
int isLeft;
MExt::Attr::Get( &isLeft, node1, WallLocatorNode::LEFTRIGHT_NAME_LONG );
MExt::Attr::Set( !isLeft == WallLocatorNode::LEFT ? WallLocatorNode::RIGHT : WallLocatorNode::LEFT,
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 );
FenceLineNode::AddWall( groupT, newNode );
}