summaryrefslogtreecommitdiffstats
path: root/tools/trackeditor/code/contexts
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--tools/trackeditor/code/contexts/bvcontext.cpp721
-rw-r--r--tools/trackeditor/code/contexts/bvcontext.h98
-rw-r--r--tools/trackeditor/code/contexts/intersectioncontext.cpp478
-rw-r--r--tools/trackeditor/code/contexts/intersectioncontext.h82
-rw-r--r--tools/trackeditor/code/contexts/ppcontext.cpp717
-rw-r--r--tools/trackeditor/code/contexts/ppcontext.h97
-rw-r--r--tools/trackeditor/code/contexts/treelinecontext.cpp402
-rw-r--r--tools/trackeditor/code/contexts/treelinecontext.h139
8 files changed, 2734 insertions, 0 deletions
diff --git a/tools/trackeditor/code/contexts/bvcontext.cpp b/tools/trackeditor/code/contexts/bvcontext.cpp
new file mode 100644
index 0000000..1a4e0a0
--- /dev/null
+++ b/tools/trackeditor/code/contexts/bvcontext.cpp
@@ -0,0 +1,721 @@
+//----------------------------------------
+// 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 );
+}
+
diff --git a/tools/trackeditor/code/contexts/bvcontext.h b/tools/trackeditor/code/contexts/bvcontext.h
new file mode 100644
index 0000000..e444cd5
--- /dev/null
+++ b/tools/trackeditor/code/contexts/bvcontext.h
@@ -0,0 +1,98 @@
+#include "precompiled/PCH.h"
+
+#ifndef BVCONTEXT
+#define BVCONTEXT
+
+//----------------------------------------
+// System Includes
+//----------------------------------------
+
+
+//----------------------------------------
+// Forward References
+//----------------------------------------
+
+//-----------------------------------------------------------------------------
+//
+// B o u n d i n g v o l u m e C o n t e x t
+//
+//-----------------------------------------------------------------------------
+class BVContext : public MPxContext
+{
+ public:
+
+ enum Stimulus // Maskable values.
+ {
+ BUTTONDOWN = 0x0001,
+ BUTTONUP = 0x0002,
+ MOUSEDRAG = 0x0004,
+ COMPLETED = 0x0008,
+ DELETED = 0x0010,
+ ABORTED = 0x0020
+ };
+
+
+ BVContext();
+ virtual ~BVContext();
+
+ static const char* stringId;
+
+ virtual void toolOnSetup( MEvent& );
+ virtual void toolOffCleanup();
+ virtual MStatus doPress( MEvent& );
+ virtual MStatus doDrag( MEvent& );
+ virtual MStatus doRelease( MEvent& event );
+ virtual MStatus doHold( MEvent& event );
+ virtual MStatus doEnterRegion( MEvent& event );
+ virtual void deleteAction();
+ virtual void completeAction();
+ virtual void abortAction();
+
+ static int sLeftSide;
+ static const MString DEFAULT_GROUP_NAME;
+ static MObject sCurrentGroup;
+
+ private:
+ void ProcessState( Stimulus stimulus );
+ void AddPoint( MObject obj );
+ void DeleteLast();
+ void CloseLoop();
+ void SetHelpString();
+
+ MObjectArray mPoints;
+ MString mHelp;
+
+ short mXCurrent, mYCurrent;
+};
+
+//-----------------------------------------------------------------------------
+//
+// B o u n d i n g v o l u m e C o n t e x t C m d
+//
+//-----------------------------------------------------------------------------
+class BVContextCmd : public MPxContextCommand
+{
+ public:
+ BVContextCmd();
+ virtual ~BVContextCmd();
+
+ static void* creator();
+
+ virtual MPxContext* makeObj();
+
+ private:
+};
+
+class BVSplitCmd : public MPxCommand
+{
+public:
+ MStatus doIt( const MArgList& args );
+ static void* creator();
+
+ static const char* stringId;
+
+private:
+ void Split( MObject& node1, MObject& node2 );
+};
+
+#endif
diff --git a/tools/trackeditor/code/contexts/intersectioncontext.cpp b/tools/trackeditor/code/contexts/intersectioncontext.cpp
new file mode 100644
index 0000000..561d5bf
--- /dev/null
+++ b/tools/trackeditor/code/contexts/intersectioncontext.cpp
@@ -0,0 +1,478 @@
+//----------------------------------------
+// System Includes
+//----------------------------------------
+#include <math.h>
+
+//----------------------------------------
+// Project Includes
+//----------------------------------------
+
+#include "intersectioncontext.h"
+#include "nodes/intersection.h"
+#include "utility/mext.h"
+#include "main/trackeditor.h"
+
+//----------------------------------------
+// Constants, Typedefs and Statics
+//----------------------------------------
+
+const short OFFSET = 10;
+const double SCALE_FACTOR = 0.002;
+
+const char* IntersectionContext::stringId = "IntersectionContext";
+
+//==============================================================================
+// IntersectionContextCmd::IntersectionContextCmd
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: IntersectionContextCmd
+//
+//==============================================================================
+IntersectionContextCmd::IntersectionContextCmd()
+{
+}
+
+//==============================================================================
+// IntersectionContextCmd::~IntersectionContextCmd
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: IntersectionContextCmd
+//
+//==============================================================================
+IntersectionContextCmd::~IntersectionContextCmd()
+{
+}
+
+//-----------------------------------------------------------------------------
+// c r e a t o r
+//
+// Synopsis:
+//
+// Parameters: NONE
+//
+// Returns: NOTHING
+//
+// Constraints: NONE
+//
+//-----------------------------------------------------------------------------
+void* IntersectionContextCmd::creator()
+{
+ return new IntersectionContextCmd();
+}
+
+//-----------------------------------------------------------------------------
+// m a k e O b j
+//
+// Synopsis:
+//
+// Parameters: NONE
+//
+// Returns: NOTHING
+//
+// Constraints: NONE
+//
+//-----------------------------------------------------------------------------
+MPxContext* IntersectionContextCmd::makeObj()
+{
+ return new IntersectionContext();
+}
+
+//==============================================================================
+// IntersectionContext::IntersectionContext
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: IntersectionContext
+//
+//==============================================================================
+IntersectionContext::IntersectionContext() :
+ mXCurrent( 0 ),
+ mYCurrent( 0 ),
+ mIntersection( MObject::kNullObj ),
+ mIntersectionTransform( MObject::kNullObj )
+{
+ SetHelpString();
+
+ setTitleString( "Intersection Overlay Tool" );
+}
+
+//==============================================================================
+// IntersectionContext::~IntersectionContext
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: IntersectionContext
+//
+//==============================================================================
+IntersectionContext::~IntersectionContext()
+{
+}
+
+//==============================================================================
+// IntersectionContext::abortAction
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//==============================================================================
+void IntersectionContext::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 IntersectionContext::completeAction()
+{
+ ProcessState( COMPLETED );
+}
+
+//-----------------------------------------------------------------------------
+// d e l e t e A c t i o n
+//
+// Synopsis:
+//
+// Parameters: NONE
+//
+// Returns: NOTHING
+//
+// Constraints: NONE
+//
+//-----------------------------------------------------------------------------
+void IntersectionContext::deleteAction()
+{
+ ProcessState( DELETED );
+}
+
+//-----------------------------------------------------------------------------
+// d o D r a g
+//
+// Synopsis:
+//
+// Parameters: NONE
+//
+// Returns: NOTHING
+//
+// Constraints: NONE
+//
+//-----------------------------------------------------------------------------
+MStatus IntersectionContext::doDrag( MEvent& event )
+{
+
+ event.getPosition( mXDrag, mYDrag );
+ 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 IntersectionContext::doEnterRegion( MEvent& event )
+{
+ SetHelpString();
+
+ return MS::kSuccess;
+}
+
+//-----------------------------------------------------------------------------
+// d o H o l d
+//
+// Synopsis:
+//
+// Parameters: NONE
+//
+// Returns: NOTHING
+//
+// Constraints: NONE
+//
+//-----------------------------------------------------------------------------
+MStatus IntersectionContext::doHold( MEvent& event )
+{
+ MStatus status = MS::kSuccess;
+ return status;
+}
+
+//-----------------------------------------------------------------------------
+// d o P r e s s
+//
+// Synopsis:
+//
+// Parameters: NONE
+//
+// Returns: NOTHING
+//
+// Constraints: NONE
+//
+//-----------------------------------------------------------------------------
+MStatus IntersectionContext::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 IntersectionContext::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 IntersectionContext::toolOffCleanup()
+{
+ if ( mIntersectionTransform != MObject::kNullObj )
+ {
+ mIntersection = MObject::kNullObj;
+ mIntersectionTransform = MObject::kNullObj;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// t o o l O n S e t u p
+//
+// Synopsis:
+//
+// Parameters: NONE
+//
+// Returns: NOTHING
+//
+// Constraints: NONE
+//
+//-----------------------------------------------------------------------------
+void IntersectionContext::toolOnSetup( MEvent& event )
+{
+ setCursor( MCursor::crossHairCursor );
+}
+
+//-----------------------------------------------------------------------------
+//
+// 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 IntersectionContext::ProcessState( Stimulus stimulus )
+{
+ switch( stimulus )
+ {
+ case BUTTONDOWN:
+ {
+ InitIntersection();
+ }
+ break;
+ case MOUSEDRAG:
+ {
+ //Scale the intersection according to drag dist.
+ short diffX = mXCurrent - mXDrag;
+ short diffY = mYCurrent - mYDrag;
+
+ double dist = 25.0 + sqrt( ( diffX*diffX + diffY*diffY ) ) * SCALE_FACTOR;
+
+ double scaleFactor[3] = { dist, dist, dist };
+
+ MFnTransform fnTransform( mIntersectionTransform );
+
+ fnTransform.setScale( scaleFactor );
+ }
+ break;
+ case BUTTONUP:
+ case COMPLETED:
+ {
+ }
+ break;
+ case ABORTED:
+ {
+ if ( mIntersectionTransform != MObject::kNullObj )
+ {
+ mIntersection = MObject::kNullObj;
+ mIntersectionTransform = MObject::kNullObj;
+ }
+ }
+ break;
+ case DELETED:
+ {
+ if ( mIntersectionTransform != MObject::kNullObj )
+ {
+ MGlobal::deleteNode( mIntersection );
+ MGlobal::deleteNode( mIntersectionTransform );
+ mIntersection = MObject::kNullObj;
+ mIntersectionTransform = MObject::kNullObj;
+ }
+ }
+ break;
+ default:
+ {
+ }
+ break;
+ }
+
+ SetHelpString();
+}
+
+//==============================================================================
+// IntersectionContext::SetHelpString
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//==============================================================================
+void IntersectionContext::SetHelpString()
+{
+ mHelp = "Click and drag to create intersection.";
+
+ setHelpString( mHelp );
+}
+
+//==============================================================================
+// IntersectionContext::InitIntersection
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//==============================================================================
+void IntersectionContext::InitIntersection()
+{
+ //Get the mesh below the clicked point and find it's y height.
+ short xStart, xEnd, yStart, yEnd;
+
+ xStart = 0;
+ xEnd = M3dView::active3dView().portWidth();
+ yStart = M3dView::active3dView().portHeight();
+ yEnd = 0;
+
+ MGlobal::selectFromScreen( xStart,
+ yStart,
+ xEnd,
+ yEnd,
+ MGlobal::kReplaceList );
+
+ MSelectionList selectionList;
+
+ MGlobal::getActiveSelectionList( selectionList );
+
+ if ( selectionList.length() > 0 )
+ {
+ //Go through each selected object and see if the ray intersects it.
+ MItSelectionList selectIt( selectionList, MFn::kMesh );
+
+ MPoint nearClick, farClick;
+ M3dView activeView = M3dView::active3dView();
+ activeView.viewToWorld( mXCurrent, mYCurrent, nearClick, farClick );
+ MVector rayDir( MVector( farClick ) - MVector( nearClick ) );
+ MPointArray intersectPoints;
+ MDagPath objDag;
+
+ while ( !selectIt.isDone() )
+ {
+ selectIt.getDagPath( objDag );
+
+ MFnMesh mesh( objDag );
+
+ mesh.intersect( nearClick, rayDir, intersectPoints, 0.001f, MSpace::kWorld );
+
+ if ( intersectPoints.length() > 0 )
+ {
+ MObject transform;
+ MExt::CreateNode( mIntersection,
+ mIntersectionTransform,
+ MString( IntersectionLocatorNode::stringId ) );
+
+ assert( !mIntersection.isNull() );
+
+ MExt::SetWorldPosition( intersectPoints[0], mIntersection );
+
+ MFnTransform fnTransform( mIntersectionTransform );
+
+ const double scale[3] = { 25.0, 25.0, 25.0 };
+ fnTransform.setScale( scale );
+
+
+ TrackEditor::AddChild( mIntersection );
+
+ break;
+ }
+
+ selectIt.next();
+ }
+ }
+
+ MGlobal::clearSelectionList();
+}
diff --git a/tools/trackeditor/code/contexts/intersectioncontext.h b/tools/trackeditor/code/contexts/intersectioncontext.h
new file mode 100644
index 0000000..b54edd9
--- /dev/null
+++ b/tools/trackeditor/code/contexts/intersectioncontext.h
@@ -0,0 +1,82 @@
+#include "precompiled/PCH.h"
+
+#ifndef INTERSECTION_CONTEXT
+#define INTERSECTION_CONTEXT
+
+//----------------------------------------
+// System Includes
+//----------------------------------------
+
+
+//----------------------------------------
+// Forward References
+//----------------------------------------
+
+//-----------------------------------------------------------------------------
+//
+// I n t e r s e c t i o n C o n t e x t
+//
+//-----------------------------------------------------------------------------
+class IntersectionContext : public MPxContext
+{
+ public:
+
+ enum Stimulus // Maskable values.
+ {
+ BUTTONDOWN = 0x0001,
+ BUTTONUP = 0x0002,
+ MOUSEDRAG = 0x0004,
+ COMPLETED = 0x0008,
+ DELETED = 0x0010,
+ ABORTED = 0x0020
+ };
+
+
+ IntersectionContext();
+ virtual ~IntersectionContext();
+
+ static const char* stringId;
+
+ virtual void toolOnSetup( MEvent& );
+ virtual void toolOffCleanup();
+ virtual MStatus doPress( MEvent& );
+ virtual MStatus doDrag( MEvent& );
+ virtual MStatus doRelease( MEvent& event );
+ virtual MStatus doHold( MEvent& event );
+ virtual MStatus doEnterRegion( MEvent& event );
+ virtual void deleteAction();
+ virtual void completeAction();
+ virtual void abortAction();
+
+ private:
+ void ProcessState( Stimulus stimulus );
+ void SetHelpString();
+ void InitIntersection();
+
+ MString mHelp;
+
+ short mXCurrent, mYCurrent;
+ short mXDrag, mYDrag;
+ MObject mIntersection;
+ MObject mIntersectionTransform;
+};
+
+//-----------------------------------------------------------------------------
+//
+// I n t e r s e c t i o n C o n t e x t C m d
+//
+//-----------------------------------------------------------------------------
+class IntersectionContextCmd : public MPxContextCommand
+{
+ public:
+ IntersectionContextCmd();
+ virtual ~IntersectionContextCmd();
+
+ static void* creator();
+
+ virtual MPxContext* makeObj();
+
+ private:
+};
+
+#endif
diff --git a/tools/trackeditor/code/contexts/ppcontext.cpp b/tools/trackeditor/code/contexts/ppcontext.cpp
new file mode 100644
index 0000000..0a2a84b
--- /dev/null
+++ b/tools/trackeditor/code/contexts/ppcontext.cpp
@@ -0,0 +1,717 @@
+//----------------------------------------
+// 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 );
+}
+
diff --git a/tools/trackeditor/code/contexts/ppcontext.h b/tools/trackeditor/code/contexts/ppcontext.h
new file mode 100644
index 0000000..04e212d
--- /dev/null
+++ b/tools/trackeditor/code/contexts/ppcontext.h
@@ -0,0 +1,97 @@
+#include "precompiled/PCH.h"
+
+#ifndef PPCONTEXT
+#define PPCONTEXT
+
+//----------------------------------------
+// System Includes
+//----------------------------------------
+
+
+//----------------------------------------
+// Forward References
+//----------------------------------------
+
+//-----------------------------------------------------------------------------
+//
+// B o u n d i n g v o l u m e C o n t e x t
+//
+//-----------------------------------------------------------------------------
+class PPContext : public MPxContext
+{
+ public:
+
+ enum Stimulus // Maskable values.
+ {
+ BUTTONDOWN = 0x0001,
+ BUTTONUP = 0x0002,
+ MOUSEDRAG = 0x0004,
+ COMPLETED = 0x0008,
+ DELETED = 0x0010,
+ ABORTED = 0x0020
+ };
+
+
+ PPContext();
+ virtual ~PPContext();
+
+ static const char* stringId;
+
+ virtual void toolOnSetup( MEvent& );
+ virtual void toolOffCleanup();
+ virtual MStatus doPress( MEvent& );
+ virtual MStatus doDrag( MEvent& );
+ virtual MStatus doRelease( MEvent& event );
+ virtual MStatus doHold( MEvent& event );
+ virtual MStatus doEnterRegion( MEvent& event );
+ virtual void deleteAction();
+ virtual void completeAction();
+ virtual void abortAction();
+
+ static const MString DEFAULT_GROUP_NAME;
+ static MObject sCurrentGroup;
+
+ private:
+ void ProcessState( Stimulus stimulus );
+ void AddPoint( MObject obj );
+ void DeleteLast();
+ void CloseLoop();
+ void SetHelpString();
+
+ MObjectArray mPoints;
+ MString mHelp;
+
+ short mXCurrent, mYCurrent;
+};
+
+//-----------------------------------------------------------------------------
+//
+// B o u n d i n g v o l u m e C o n t e x t C m d
+//
+//-----------------------------------------------------------------------------
+class PPContextCmd : public MPxContextCommand
+{
+ public:
+ PPContextCmd();
+ virtual ~PPContextCmd();
+
+ static void* creator();
+
+ virtual MPxContext* makeObj();
+
+ private:
+};
+
+class PPSplitCmd : public MPxCommand
+{
+public:
+ MStatus doIt( const MArgList& args );
+ static void* creator();
+
+ static const char* stringId;
+
+private:
+ void Split( MObject& node1, MObject& node2 );
+};
+
+#endif
diff --git a/tools/trackeditor/code/contexts/treelinecontext.cpp b/tools/trackeditor/code/contexts/treelinecontext.cpp
new file mode 100644
index 0000000..5c5ba56
--- /dev/null
+++ b/tools/trackeditor/code/contexts/treelinecontext.cpp
@@ -0,0 +1,402 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: TreeLineContext.cpp
+//
+// Description: Implement TreeLineContext
+//
+// History: 27/05/2002 + Created -- Cary Brisebois
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+#include "precompiled/PCH.h"
+
+//========================================
+// Project Includes
+//========================================
+#include "contexts/TreeLineContext.h"
+#include "utility/mext.h"
+#include "main/constants.h"
+#include "main/trackeditor.h"
+#include "nodes/treelineshapenode.h"
+
+
+
+//******************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//******************************************************************************
+const char* TreeLineContext::stringId = "TreeLineContext";
+MObject TreeLineContext::mCurrentTreeLine;
+bool TreeLineContext::mWorking = false;
+
+
+//******************************************************************************
+//
+// Public Member Functions
+//
+//******************************************************************************
+
+//==============================================================================
+// TreeLineContext::TreeLineContext
+//==============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+TreeLineContext::TreeLineContext() :
+ mXCurrent( 0 ),
+ mYCurrent( 0 )
+{
+ SetHelpString();
+
+ setTitleString( "Ye Tree Line Tool" );
+
+}
+
+//==============================================================================
+// TreeLineContext::~TreeLineContext
+//==============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+TreeLineContext::~TreeLineContext()
+{
+}
+
+//=============================================================================
+// TreeLineContext::toolOnSetup
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( MEvent& )
+//
+// Return: void
+//
+//=============================================================================
+void TreeLineContext::toolOnSetup( MEvent& event )
+{
+ setCursor( MCursor::crossHairCursor );
+
+ mPoints.clear();
+ mWorking = false;
+ mCurrentTreeLine = MObject::kNullObj;
+}
+
+//=============================================================================
+// TreeLineContext::toolOffCleanup
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//=============================================================================
+void TreeLineContext::toolOffCleanup()
+{
+ mPoints.clear();
+ mCurrentTreeLine = MObject::kNullObj;
+}
+
+//=============================================================================
+// TreeLineContext::doPress
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( MEvent& event )
+//
+// Return: MStatus
+//
+//=============================================================================
+MStatus TreeLineContext::doPress( MEvent& event )
+{
+ event.getPosition( mXCurrent, mYCurrent );
+ ProcessState( BUTTONDOWN );
+ return MStatus::kSuccess;
+}
+
+//=============================================================================
+// TreeLineContext::doDrag
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( MEvent& event )
+//
+// Return: MStatus
+//
+//=============================================================================
+MStatus TreeLineContext::doDrag( MEvent& event )
+{
+ event.getPosition( mXCurrent, mYCurrent );
+ ProcessState( MOUSEDRAG );
+ return MStatus::kSuccess;
+}
+
+//=============================================================================
+// TreeLineContext::doRelease
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( MEvent& event )
+//
+// Return: MStatus
+//
+//=============================================================================
+MStatus TreeLineContext::doRelease( MEvent& event )
+{
+ if ( event.mouseButton() == MEvent::kLeftMouse )
+ {
+ event.getPosition( mXCurrent, mYCurrent );
+ ProcessState( BUTTONUP );
+ }
+
+ return MStatus::kSuccess;
+}
+
+//=============================================================================
+// TreeLineContext::doHold
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( MEvent& event )
+//
+// Return: MStatus
+//
+//=============================================================================
+MStatus TreeLineContext::doHold( MEvent& event )
+{
+ return MStatus::kSuccess;
+}
+
+//=============================================================================
+// TreeLineContext::doEnterRegion
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( MEvent& event )
+//
+// Return: MStatus
+//
+//=============================================================================
+MStatus TreeLineContext::doEnterRegion( MEvent& event )
+{
+ SetHelpString();
+
+ return MStatus::kSuccess;
+}
+
+//=============================================================================
+// TreeLineContext::deleteAction
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//=============================================================================
+void TreeLineContext::deleteAction()
+{
+ ProcessState( DELETED );
+}
+
+//=============================================================================
+// TreeLineContext::completeAction
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//=============================================================================
+void TreeLineContext::completeAction()
+{
+ ProcessState( COMPLETED );
+}
+
+//=============================================================================
+// TreeLineContext::abortAction
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//=============================================================================
+void TreeLineContext::abortAction()
+{
+ ProcessState( ABORTED );
+}
+
+//******************************************************************************
+//
+// Private Member Functions
+//
+//******************************************************************************
+
+//=============================================================================
+// TreeLineContext::ProcessState
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( Stimulus stimulus )
+//
+// Return: void
+//
+//=============================================================================
+void TreeLineContext::ProcessState( Stimulus stimulus )
+{
+ switch( stimulus )
+ {
+ case BUTTONDOWN:
+ {
+ }
+ break;
+
+ case BUTTONUP:
+ {
+ if ( !mWorking )
+ {
+ //Let's create our working Treeline!
+ MObject transform;
+ MString name( TETreeLine::TreelineShapeNode::stringId );
+ MExt::CreateNode( &mCurrentTreeLine,
+ &transform,
+ MString( TETreeLine::TreelineShapeNode::stringId ),
+ &name );
+ mWorking = true;
+
+ MFnTransform fnTransform( transform );
+ fnTransform.findPlug( MString("translate") ).setLocked( true );
+ fnTransform.findPlug( MString("rotate") ).setLocked( true );
+ fnTransform.findPlug( MString("scale") ).setLocked( true );
+
+ TrackEditor::AddChild( mCurrentTreeLine );
+ }
+
+ //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;
+
+ MStatus status;
+ MFnDependencyNode fnDepNode( mCurrentTreeLine );
+
+ MPlug verticesPlug = fnDepNode.findPlug( TETreeLine::TreelineShapeNode::mControlPoints, &status );
+ assert( status );
+
+ unsigned int elementCount = verticesPlug.numElements();
+ MPlug vertex = verticesPlug.elementByLogicalIndex( elementCount, &status );
+ assert( status );
+
+ MPlug x = vertex.child( TETreeLine::TreelineShapeNode::mControlValueX, &status );
+ assert( status );
+
+ x.setValue( intersectPoint.x * TEConstants::Scale );
+
+ MPlug y = vertex.child( TETreeLine::TreelineShapeNode::mControlValueY, &status );
+ assert( status );
+ y.setValue( intersectPoint.y * TEConstants::Scale );
+
+ MPlug z = vertex.child( TETreeLine::TreelineShapeNode::mControlValueZ, &status );
+ assert( status );
+ z.setValue( intersectPoint.z * TEConstants::Scale );
+
+ MGlobal::select( mCurrentTreeLine, MGlobal::kReplaceList );
+ }
+ break;
+ case DELETED:
+ {
+ DeleteLast();
+ }
+ break;
+ case ABORTED:
+ case COMPLETED:
+ {
+ //Start new treeline
+ mWorking = false;
+ mCurrentTreeLine = MObject::kNullObj;
+ }
+ break;
+ default:
+ {
+ }
+ break;
+ }
+
+ SetHelpString();
+}
+
+//=============================================================================
+// TreeLineContext::AddPoint
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( MPoint& point )
+//
+// Return: void
+//
+//=============================================================================
+void TreeLineContext::AddPoint( MPoint& point )
+{
+ mPoints.append( point );
+}
+
+//=============================================================================
+// TreeLineContext::DeleteLast
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//=============================================================================
+void TreeLineContext::DeleteLast()
+{
+ unsigned int size = mPoints.length();
+
+ if ( size )
+ {
+ MStatus status;
+
+ mPoints.remove( size - 1 );
+ }
+}
+
+//=============================================================================
+// TreeLineContext::SetHelpString
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//=============================================================================
+void TreeLineContext::SetHelpString()
+{
+ mHelp = "Click to place vertices in the line.";
+
+ setHelpString( mHelp );
+}
diff --git a/tools/trackeditor/code/contexts/treelinecontext.h b/tools/trackeditor/code/contexts/treelinecontext.h
new file mode 100644
index 0000000..a9833b7
--- /dev/null
+++ b/tools/trackeditor/code/contexts/treelinecontext.h
@@ -0,0 +1,139 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: treelinecontext.h
+//
+// Description: Blahblahblah
+//
+// History: 27/05/2002 + Created -- Cary Brisebois
+//
+//=============================================================================
+#include "precompiled/PCH.h"
+
+#ifndef TREELINECONTEXT_H
+#define TREELINECONTEXT_H
+
+//========================================
+// Nested Includes
+//========================================
+
+
+//========================================
+// Forward References
+//========================================
+
+//=============================================================================
+//
+// Synopsis: Blahblahblah
+//
+//=============================================================================
+
+class TreeLineContext : public MPxContext
+{
+public:
+
+ enum Stimulus // Maskable values.
+ {
+ BUTTONDOWN = 0x0001,
+ BUTTONUP = 0x0002,
+ MOUSEDRAG = 0x0004,
+ COMPLETED = 0x0008,
+ DELETED = 0x0010,
+ ABORTED = 0x0020
+ };
+
+ TreeLineContext();
+ virtual ~TreeLineContext();
+
+ static const char* stringId;
+
+ virtual void toolOnSetup( MEvent& event);
+ virtual void toolOffCleanup();
+ virtual MStatus doPress( MEvent& event);
+ virtual MStatus doDrag( MEvent& event );
+ virtual MStatus doRelease( MEvent& event );
+ virtual MStatus doHold( MEvent& event );
+ virtual MStatus doEnterRegion( MEvent& event );
+ virtual void deleteAction();
+ virtual void completeAction();
+ virtual void abortAction();
+
+private:
+ void ProcessState( Stimulus stimulus );
+ void AddPoint( MPoint& point );
+ void DeleteLast();
+ void SetHelpString();
+
+ MPointArray mPoints;
+ MString mHelp;
+
+ static MObject mCurrentTreeLine;
+ static bool mWorking;
+
+ short mXCurrent, mYCurrent;
+
+private:
+
+ //Prevent wasteful constructor creation.
+ TreeLineContext( const TreeLineContext& treelinecontext );
+ TreeLineContext& operator=( const TreeLineContext& treelinecontext );
+};
+
+//******************************************************************************
+//
+// TreeLineContextCmd
+//
+//******************************************************************************
+
+class TreeLineContextCmd : public MPxContextCommand
+{
+ public:
+ TreeLineContextCmd() {};
+ virtual ~TreeLineContextCmd() {};
+
+ static void* creator();
+
+ virtual MPxContext* makeObj();
+
+ private:
+};
+
+//******************************************************************************
+//
+// Inline Public Functions
+//
+//******************************************************************************
+
+//=============================================================================
+// TreeLineContextCmd::creator
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//=============================================================================
+inline void* TreeLineContextCmd::creator()
+{
+ return new TreeLineContextCmd();
+}
+
+//=============================================================================
+// TreeLineContextCmd::makeObj
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: MPxContext
+//
+//=============================================================================
+inline MPxContext* TreeLineContextCmd::makeObj()
+{
+ return new TreeLineContext();
+}
+
+
+#endif //TREELINECONTEXT_H
+