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