summaryrefslogtreecommitdiffstats
path: root/tools/trackeditor/code
diff options
context:
space:
mode:
Diffstat (limited to 'tools/trackeditor/code')
-rw-r--r--tools/trackeditor/code/AETemplates/AEIntersectionLocatorNodeTemplate.mel20
-rw-r--r--tools/trackeditor/code/AETemplates/AERoadNodeTemplate.mel29
-rw-r--r--tools/trackeditor/code/AETemplates/AETELocatorSuppress.mel37
-rw-r--r--tools/trackeditor/code/AETemplates/AETEShowRoadSegButton.mel29
-rw-r--r--tools/trackeditor/code/AETemplates/AETreelineShapeNodeTemplate.mel41
-rw-r--r--tools/trackeditor/code/commands/export.cpp193
-rw-r--r--tools/trackeditor/code/commands/export.h26
-rw-r--r--tools/trackeditor/code/commands/intersectioncommands.cpp449
-rw-r--r--tools/trackeditor/code/commands/intersectioncommands.h60
-rw-r--r--tools/trackeditor/code/commands/trackeditorcommands.cpp222
-rw-r--r--tools/trackeditor/code/commands/trackeditorcommands.h42
-rw-r--r--tools/trackeditor/code/commands/treelinecommand.cpp323
-rw-r--r--tools/trackeditor/code/commands/treelinecommand.h136
-rw-r--r--tools/trackeditor/code/constants/version.hpp16
-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
-rw-r--r--tools/trackeditor/code/main/constants.h21
-rw-r--r--tools/trackeditor/code/main/pluginMain.cpp164
-rw-r--r--tools/trackeditor/code/main/pluginMain.h47
-rw-r--r--tools/trackeditor/code/main/shapeconstants.h34
-rw-r--r--tools/trackeditor/code/main/trackeditor.cpp350
-rw-r--r--tools/trackeditor/code/main/trackeditor.h85
-rw-r--r--tools/trackeditor/code/nodes/NU.h34
-rw-r--r--tools/trackeditor/code/nodes/fenceline.cpp201
-rw-r--r--tools/trackeditor/code/nodes/fenceline.h30
-rw-r--r--tools/trackeditor/code/nodes/intersection.cpp213
-rw-r--r--tools/trackeditor/code/nodes/intersection.h48
-rw-r--r--tools/trackeditor/code/nodes/pedpath.cpp271
-rw-r--r--tools/trackeditor/code/nodes/pedpath.h30
-rw-r--r--tools/trackeditor/code/nodes/road.cpp409
-rw-r--r--tools/trackeditor/code/nodes/road.h56
-rw-r--r--tools/trackeditor/code/nodes/tiledisplay.cpp212
-rw-r--r--tools/trackeditor/code/nodes/tiledisplay.h35
-rw-r--r--tools/trackeditor/code/nodes/treelineshapenode.cpp1343
-rw-r--r--tools/trackeditor/code/nodes/treelineshapenode.h142
-rw-r--r--tools/trackeditor/code/nodes/walllocator.cpp551
-rw-r--r--tools/trackeditor/code/nodes/walllocator.h69
-rw-r--r--tools/trackeditor/code/precompiled/PCH.cpp1
-rw-r--r--tools/trackeditor/code/precompiled/PCH.h68
-rw-r--r--tools/trackeditor/code/scripts/te_BVContext.mel43
-rw-r--r--tools/trackeditor/code/scripts/te_IntersectionContext.mel212
-rw-r--r--tools/trackeditor/code/scripts/te_PPContext.mel43
-rw-r--r--tools/trackeditor/code/scripts/te_cleanup.mel12
-rw-r--r--tools/trackeditor/code/scripts/te_editorwindow.mel335
-rw-r--r--tools/trackeditor/code/scripts/te_globals.mel1
-rw-r--r--tools/trackeditor/code/scripts/te_main.mel195
-rw-r--r--tools/trackeditor/code/scripts/te_setup.mel15
-rw-r--r--tools/trackeditor/code/scripts/te_treelineContext.mel84
54 files changed, 9711 insertions, 0 deletions
diff --git a/tools/trackeditor/code/AETemplates/AEIntersectionLocatorNodeTemplate.mel b/tools/trackeditor/code/AETemplates/AEIntersectionLocatorNodeTemplate.mel
new file mode 100644
index 0000000..740b05f
--- /dev/null
+++ b/tools/trackeditor/code/AETemplates/AEIntersectionLocatorNodeTemplate.mel
@@ -0,0 +1,20 @@
+global proc AEIntersectionLocatorNodeTemplate( string $nodeName )
+{
+
+ editorTemplate -beginScrollLayout;
+
+ editorTemplate -beginLayout "Intersection Attributes" -collapse 0;
+
+ editorTemplate -addControl "IntersectionType";
+
+ editorTemplate -endLayout;
+
+ editorTemplate -addExtraControls;
+
+ editorTemplate -endScrollLayout;
+
+ AEWBLocatorSuppress( $nodeName );
+
+ editorTemplate -suppress "localPosition";
+}
+ \ No newline at end of file
diff --git a/tools/trackeditor/code/AETemplates/AERoadNodeTemplate.mel b/tools/trackeditor/code/AETemplates/AERoadNodeTemplate.mel
new file mode 100644
index 0000000..27c4431
--- /dev/null
+++ b/tools/trackeditor/code/AETemplates/AERoadNodeTemplate.mel
@@ -0,0 +1,29 @@
+global proc AERoadNodeTemplate( string $nodeName )
+{
+
+ editorTemplate -beginScrollLayout;
+
+ editorTemplate -beginLayout "Road Attributes" -collapse 0;
+
+ editorTemplate -addControl "IntersectionStart";
+ editorTemplate -addControl "IntersectionEnd";
+ editorTemplate -addControl "density";
+ editorTemplate -addControl "speed";
+ editorTemplate -addControl "difficulty";
+ editorTemplate -addControl "shortCut";
+
+ editorTemplate -callCustom "AETEShowRoadSegNew"
+ "AETEShowRoadSegReplace"
+ "message";
+
+ editorTemplate -endLayout;
+
+ editorTemplate -addExtraControls;
+
+ editorTemplate -endScrollLayout;
+
+ AEWBLocatorSuppress( $nodeName );
+
+ editorTemplate -suppress "localPosition";
+}
+ \ No newline at end of file
diff --git a/tools/trackeditor/code/AETemplates/AETELocatorSuppress.mel b/tools/trackeditor/code/AETemplates/AETELocatorSuppress.mel
new file mode 100644
index 0000000..13a6d00
--- /dev/null
+++ b/tools/trackeditor/code/AETemplates/AETELocatorSuppress.mel
@@ -0,0 +1,37 @@
+global proc AETELocatorSuppress( string $nodeName )
+{
+ editorTemplate -suppress "inputTranslate";
+ editorTemplate -suppress "input";
+ editorTemplate -suppress "caching";
+ editorTemplate -suppress "nodeState";
+ editorTemplate -suppress "visibility";
+ editorTemplate -suppress "intermediateObject";
+ editorTemplate -suppress "template";
+ editorTemplate -suppress "ghosting";
+ editorTemplate -suppress "instObjGroups";
+ editorTemplate -suppress "compInstObjGroups";
+ editorTemplate -suppress "castsShadows";
+ editorTemplate -suppress "receiveShadows";
+ editorTemplate -suppress "depthJitter";
+ editorTemplate -suppress "motionBlur";
+ editorTemplate -suppress "renderInfo";
+ editorTemplate -suppress "primaryVisibility";
+ editorTemplate -suppress "visibleInReflections";
+ editorTemplate -suppress "visibleInRefractions";
+ editorTemplate -suppress "geometryAntialiasingOverride";
+ editorTemplate -suppress "antialiasingLevel";
+ editorTemplate -suppress "shadingSamplesOverride";
+ editorTemplate -suppress "shadingSamples";
+ editorTemplate -suppress "maxShadingSamples";
+ editorTemplate -suppress "volumeSamplesOverride";
+ editorTemplate -suppress "volumeSamples";
+ editorTemplate -suppress "maxVisibilitySamplesOverride";
+ editorTemplate -suppress "maxVisibilitySamples";
+ editorTemplate -suppress "boundingBoxScale";
+ editorTemplate -suppress "drawOverride";
+ editorTemplate -suppress "useObjectColor";
+ editorTemplate -suppress "objectColor";
+ editorTemplate -suppress "intermediateObject";
+ editorTemplate -suppress "visibility";
+ editorTemplate -suppress "lodVisibility";
+} \ No newline at end of file
diff --git a/tools/trackeditor/code/AETemplates/AETEShowRoadSegButton.mel b/tools/trackeditor/code/AETemplates/AETEShowRoadSegButton.mel
new file mode 100644
index 0000000..3ffbeb5
--- /dev/null
+++ b/tools/trackeditor/code/AETemplates/AETEShowRoadSegButton.mel
@@ -0,0 +1,29 @@
+global proc AETEShowRoadSegNew( string $nodeName )
+{
+ columnLayout -adj true;
+
+ select $nodeName;
+ string $names[] = `ls -sl -o`;
+
+ string $command = "te_MCB_ShowRoadFromSelected()";
+
+ button -label "Show Road Segments" -command $command TEShowRoadSegsButton;
+
+ setParent ..;
+
+ select $names[0];
+}
+
+
+global proc AETEShowRoadSegReplace( string $nodeName )
+{
+
+ select $nodeName;
+ string $names[] = `ls -sl -o`;
+
+ string $command = "te_MCB_ShowRoadFromSelected";
+
+ button -e -command $command TEShowRoadSegsButton;
+
+ select $names[0];
+} \ No newline at end of file
diff --git a/tools/trackeditor/code/AETemplates/AETreelineShapeNodeTemplate.mel b/tools/trackeditor/code/AETemplates/AETreelineShapeNodeTemplate.mel
new file mode 100644
index 0000000..766ed13
--- /dev/null
+++ b/tools/trackeditor/code/AETemplates/AETreelineShapeNodeTemplate.mel
@@ -0,0 +1,41 @@
+global proc AETreelineShapeNodeTemplate( string $nodeName )
+{
+
+ editorTemplate -beginScrollLayout;
+
+ editorTemplate -beginLayout "Treeline Attributes" -collapse false;
+
+ editorTemplate -addControl "material";
+
+ editorTemplate -addControl "uscale";
+
+ editorTemplate -addControl "height";
+
+ editorTemplate -suppress "colour";
+
+ editorTemplate -suppress "alpha";
+
+ editorTemplate -endLayout;
+
+ editorTemplate -addExtraControls;
+
+ editorTemplate -endScrollLayout;
+
+ AETELocatorSuppress( $nodeName );
+
+ editorTemplate -suppress "controlPoints";
+ editorTemplate -suppress "weights";
+ editorTemplate -suppress "uvSet";
+ editorTemplate -suppress "tweak";
+ editorTemplate -suppress "relativeTweak";
+ editorTemplate -suppress "currentUVSet";
+ editorTemplate -suppress "doubleSided";
+ editorTemplate -suppress "opposite";
+ editorTemplate -suppress "smoothShading";
+ editorTemplate -suppress "featureDisplacement";
+ editorTemplate -suppress "initialSampleRate";
+ editorTemplate -suppress "textureThreshold";
+ editorTemplate -suppress "normalThreshold";
+ editorTemplate -suppress "extraSampleRate";
+}
+ \ No newline at end of file
diff --git a/tools/trackeditor/code/commands/export.cpp b/tools/trackeditor/code/commands/export.cpp
new file mode 100644
index 0000000..77b7328
--- /dev/null
+++ b/tools/trackeditor/code/commands/export.cpp
@@ -0,0 +1,193 @@
+#include "precompiled/PCH.h"
+
+#include "export.h"
+#include "main/constants.h"
+#include "nodes/walllocator.h"
+#include "nodes/fenceline.h"
+#include "nodes/intersection.h"
+#include "nodes/road.h"
+#include "nodes/pedpath.h"
+#include "utility/mui.h"
+#include "utility/mext.h"
+
+#include <toollib.hpp>
+
+const char* ExportCommand::stringId = "TE_Export";
+bool ExportCommand::sRegisteredChunks = false;
+
+
+ExportCommand::ExportCommand() {};
+ExportCommand::~ExportCommand() {};
+
+//==============================================================================
+// ExportCommand::creator
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//==============================================================================
+void* ExportCommand::creator()
+{
+ return new ExportCommand();
+}
+
+//==============================================================================
+// ExportCommand::doIt
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ( const MArgList& args )
+//
+// Return: MStatus
+//
+//==============================================================================
+MStatus ExportCommand::doIt( const MArgList& args )
+{
+ if ( !sRegisteredChunks )
+ {
+ tlDataChunk::RegisterDefaultChunks();
+ sRegisteredChunks = true;
+ }
+
+ //Go through all the chunks looking for the types we want and exporting them.
+ //Alternatively, we could go thtough all the chunks and attempt to access the
+ //IExportable interface and then export if the interface exists...
+
+ //Args are all, or selected.
+
+ const unsigned char FILE_NAME_SIZE = 255;
+ char filePath[FILE_NAME_SIZE];
+ filePath[0] = '\0';
+
+ if ( MUI::FileDialog( filePath,
+ FILE_NAME_SIZE,
+ "Track Editor Export",
+ "Pure3D(*.p3d)|*.p3d|All Files(*.*)|*.*||",
+ "p3d",
+ MUI::SAVE ) )
+ {
+ //TODO: add selected.
+ MItDag dagIt( MItDag::kBreadthFirst, MFn::kLocator );
+
+ tlDataChunk* outChunk = new tlDataChunk;
+
+ //Put in a history chunk.
+ tlHistory history;
+
+// char hist[256];
+// sprintf(hist, "Track Editor version: 2.0, toollib version: %s", tlversion);
+//
+// history.AddLine( hist );
+
+// outChunk->AppendSubChunk( history.Chunk(), 0 );
+
+ bool deleteLast = false;
+ MFnDependencyNode fnNode;
+ MObject lastObj;
+ MTypeId id;
+
+ while ( !dagIt.isDone() )
+ {
+ fnNode.setObject( dagIt.item() );
+ id = fnNode.typeId();
+
+ if ( id == FenceLineNode::id )
+ {
+ //Export a wall locator;
+ tlDataChunk* newChunk = FenceLineNode::Export( dagIt.item(), history );
+
+ if ( newChunk )
+ {
+ //Append this to the output file.
+ outChunk->AppendSubChunk( newChunk );
+ }
+ else
+ {
+ //Time to go away.
+ deleteLast = true;
+ }
+ }
+ else if ( id == IntersectionLocatorNode::id )
+ {
+ tlDataChunk* newChunk = IntersectionLocatorNode::Export( dagIt.item(), history );
+
+ if ( newChunk )
+ {
+ //Append this to the output file.
+ outChunk->AppendSubChunk( newChunk );
+ }
+ else
+ {
+ //Time to go away.
+ deleteLast = true;
+ }
+ }
+ else if ( id == RoadNode::id )
+ {
+ tlDataChunk* newChunk = RoadNode::Export( dagIt.item(), history, outChunk );
+
+ if ( newChunk )
+ {
+ //Append this to the output file.
+ outChunk->AppendSubChunk( newChunk );
+ }
+ else
+ {
+ //Time to go away.
+ deleteLast = true;
+ }
+ }
+ else if ( id == PedPathNode::id )
+ {
+ tlDataChunk* newChunk = PedPathNode::Export( dagIt.item(), history );
+
+ if ( newChunk )
+ {
+ //Append this to the output file.
+ outChunk->AppendSubChunk( newChunk );
+ }
+ else
+ {
+ //Time to go away.
+ deleteLast = true;
+ }
+ }
+
+ if ( deleteLast )
+ {
+ lastObj = dagIt.item();
+ }
+
+ dagIt.next();
+
+ if ( deleteLast )
+ {
+ MExt::DisplayWarning( "Deleting useless node: %s", fnNode.name().asChar() );
+ MExt::DeleteNode( lastObj, true );
+ deleteLast = false;
+ }
+ }
+
+ tlFile output(new tlFileByteStream(filePath, omWRITE), tlFile::CHUNK32);
+
+ if(!output.IsOpen())
+ {
+
+ MGlobal::displayError("Unable to write file!");
+
+ delete outChunk;
+ return MS::kFailure;
+ }
+
+ //Sort it out..
+ outChunk->SortSubChunks();
+ outChunk->Write(&output);
+
+ delete outChunk;
+ }
+
+ return MS::kSuccess;
+}
diff --git a/tools/trackeditor/code/commands/export.h b/tools/trackeditor/code/commands/export.h
new file mode 100644
index 0000000..f3c031c
--- /dev/null
+++ b/tools/trackeditor/code/commands/export.h
@@ -0,0 +1,26 @@
+#include "precompiled/PCH.h"
+
+#ifndef EXPORT_COMMAND_H
+#define EXPORT_COMMAND_H
+
+class ExportCommand : MPxCommand
+{
+public:
+ enum ExportArg
+ {
+ SELECTED,
+ ALL
+ };
+
+ ExportCommand();
+ ~ExportCommand();
+
+ static void* creator();
+ virtual MStatus doIt( const MArgList& args );
+
+ static const char* stringId;
+
+private:
+ static bool sRegisteredChunks;
+};
+#endif \ No newline at end of file
diff --git a/tools/trackeditor/code/commands/intersectioncommands.cpp b/tools/trackeditor/code/commands/intersectioncommands.cpp
new file mode 100644
index 0000000..4733762
--- /dev/null
+++ b/tools/trackeditor/code/commands/intersectioncommands.cpp
@@ -0,0 +1,449 @@
+#include "precompiled/PCH.h"
+
+#include "intersectioncommands.h"
+#include "utility/mext.h"
+#include "nodes/road.h"
+#include "main/trackeditor.h"
+#include "nodes/intersection.h"
+
+
+const char* CreateRoadCmd::stringId = "TE_CreateRoad";
+const char* AddIntersectionToRoadCmd::stringId = "TE_AddIntersectionToRoad";
+
+
+//==============================================================================
+// CreateRoadCmd::creator
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//==============================================================================
+void* CreateRoadCmd::creator()
+{
+ return new CreateRoadCmd();
+}
+
+//==============================================================================
+// CreateRoadCmd::doIt
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ( const MArgList& args )
+//
+// Return: MStatus
+//
+//==============================================================================
+MStatus CreateRoadCmd::doIt( const MArgList& args )
+{
+ //Take all the selected road segments and create a road from them.
+ //If there is a segment that has not been roadified, highlight that one and return an error message.
+
+ MSelectionList selectList;
+ MGlobal::getActiveSelectionList( selectList );
+ MItSelectionList itSelect( selectList, MFn::kMesh );
+
+ if ( selectList.length() <= 0 || itSelect.isDone() )
+ {
+ MExt::DisplayWarning( "Nothing to do, please select road segments!" );
+ return MStatus::kSuccess;
+ }
+
+ MObjectArray segArray;
+ MObject obj;
+ MFnMesh fnMesh;
+ MPlug whichRoadPlug;
+ MStatus status;
+
+ while ( !itSelect.isDone() )
+ {
+ //Gather all the road segments and add them to the new road.
+ itSelect.getDependNode( obj );
+
+ fnMesh.setObject( obj );
+
+ whichRoadPlug = fnMesh.findPlug( MString( "teWhichRoad" ), &status );
+
+ if ( status == MStatus::kSuccess )
+ {
+ //This is one of them.
+ segArray.append( obj );
+ }
+
+ itSelect.next();
+ }
+
+ if ( segArray.length() <= 0 )
+ {
+ //There were no appropriate segs in the selection.
+ MExt::DisplayWarning( "Nothing to do, please select road segments!" );
+ return MStatus::kSuccess;
+ }
+
+ MObject newRoad;
+ MObject newRoadT;
+
+ MExt::CreateNode( newRoad, newRoadT, MString( RoadNode::stringId ) );
+
+ assert( !newRoad.isNull() );
+
+ unsigned int i;
+ for ( i = 0; i < segArray.length(); ++i )
+ {
+ //Test to see if this road seg is already connected.
+ if ( MExt::IsConnected( segArray[ i ], "teWhichRoad" ) )
+ {
+ MExt::DisconnectAll( segArray[ i ], "teWhichRoad" );
+ }
+
+ MExt::Connect( segArray[ i ], "teWhichRoad", newRoad, RoadNode::ROAD_SEG_NAME_LONG );
+ }
+
+ TrackEditor::AddChild( newRoad );
+
+ return MStatus::kSuccess;
+}
+
+
+//==============================================================================
+// AddIntersectionToRoadCmd::creator
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//==============================================================================
+void* AddIntersectionToRoadCmd::creator()
+{
+ return new AddIntersectionToRoadCmd();
+}
+
+//==============================================================================
+// AddIntersectionToRoadCmd::doIt
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ( const MArgList& args )
+//
+// Return: MStatus
+//
+//==============================================================================
+MStatus AddIntersectionToRoadCmd::doIt( const MArgList& args )
+{
+ MStatus status;
+
+ //Arg 0 is the name of the intersection (the road is selected)
+ //Arg 1 is whether it is a start or end point on the road.
+
+ assert( args.length() == 2 );
+
+ MObjectArray roadArray;
+
+ if ( GetRoadsFromSelectionList( roadArray ) )
+ {
+ MString intersectionName;
+ args.get( 0, intersectionName );
+
+ if ( intersectionName == MString( "" ) )
+ {
+ MExt::DisplayWarning( "Must have an intersection selected in the editor." );
+ return MStatus::kSuccess;
+ }
+
+ bool isEnd;
+ args.get( 1, isEnd );
+
+ MDagPath dagPath;
+ if ( !MExt::FindDagNodeByName( &dagPath, intersectionName ) )
+ {
+ MExt::DisplayWarning( "The Intersection: %s does not exist!", intersectionName.asChar() );
+ return MStatus::kSuccess;
+ }
+
+ MFnDagNode fnIntersectionDagNode( dagPath );
+
+ unsigned int i;
+ for ( i = 0; i < roadArray.length(); ++i )
+ {
+ if ( isEnd )
+ {
+ MExt::DisconnectAll( roadArray[i], RoadNode::INTERSECTION_END_LONG );
+ MExt::Connect( roadArray[i], RoadNode::INTERSECTION_END_LONG, fnIntersectionDagNode.object(), IntersectionLocatorNode::ROAD_LONG );
+ }
+ else
+ {
+ MExt::DisconnectAll( roadArray[i], RoadNode::INTERSECTION_START_LONG );
+ MExt::Connect( roadArray[i], RoadNode::INTERSECTION_START_LONG, fnIntersectionDagNode.object(), IntersectionLocatorNode::ROAD_LONG );
+ }
+ }
+ }
+
+ return MStatus::kSuccess;
+}
+
+
+const char* ShowRoadCmd::stringId = "TE_ShowRoad";
+
+//==============================================================================
+// ShowRoadCmd::creator
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//==============================================================================
+void* ShowRoadCmd::creator()
+{
+ return new ShowRoadCmd();
+}
+
+//==============================================================================
+// ShowRoadCmd::doIt
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ( const MArgList& args )
+//
+// Return: MStatus
+//
+//==============================================================================
+MStatus ShowRoadCmd::doIt( const MArgList& args )
+{
+
+ MObject road;
+
+ if ( GetRoadFromSelectionList( road ) )
+ {
+ MString cmd;
+
+ MFnDependencyNode fnNode( road );
+ MPlug roadPlug = fnNode.findPlug( MString( RoadNode::ROAD_SEG_NAME_LONG ) );
+ assert( roadPlug.isArray() );
+
+ MGlobal::clearSelectionList();
+
+ MPlugArray source, dest;
+ MExt::ResolveConnections( &source, &dest, roadPlug, AS_DEST );
+
+ assert( source.length() );
+
+ unsigned int i;
+ for ( i = 0; i < source.length(); ++i )
+ {
+ fnNode.setObject( source[i].node() );
+ cmd = MString( "select -add " ) + fnNode.name();
+
+ MGlobal::executeCommand( cmd );
+ }
+
+ fnNode.setObject( road );
+ cmd = MString("select -add ") + fnNode.name();
+ MGlobal::executeCommand( cmd );
+ }
+
+ return MStatus::kSuccess;
+}
+
+
+const char* DestroyRoadCmd::stringId = "TE_DestroyRoad";
+
+//==============================================================================
+// DestroyRoadCmd::creator
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//==============================================================================
+void* DestroyRoadCmd::creator()
+{
+ return new DestroyRoadCmd();
+}
+
+//==============================================================================
+// DestroyRoadCmd::doIt
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ( const MArgList& args )
+//
+// Return: MStatus
+//
+//==============================================================================
+MStatus DestroyRoadCmd::doIt( const MArgList& args )
+{
+
+ MObject road;
+
+ if ( GetRoadFromSelectionList( road ) )
+ {
+ MExt::DeleteNode( road, true );
+ }
+
+ return MStatus::kSuccess;
+}
+
+
+
+//==============================================================================
+// GetRoadFromSelectionList
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ( MObject& road )
+//
+// Return: bool
+//
+//==============================================================================
+bool GetRoadFromSelectionList( MObject& road )
+{
+ MStatus status;
+
+ MSelectionList selectList;
+ MGlobal::getActiveSelectionList( selectList );
+
+ if ( selectList.length() <= 0 )
+ {
+ MExt::DisplayWarning( "A road segment must be selected!" );
+ return false;
+ }
+ else
+ {
+ MObject segment;
+ selectList.getDependNode( 0, segment );
+ MFnDagNode fnNode( segment );
+
+ if ( fnNode.typeName() == MString( RoadNode::stringId ) )
+ {
+ //this is a road segment
+ road = fnNode.object();
+ }
+ else
+ {
+ //Test to make sure the selected item is a road segment.
+ MFn::Type type = fnNode.type();
+
+ if ( fnNode.typeName() == MString( "transform" ) )
+ {
+ //We want the child of this, not the transform.
+ fnNode.setObject( fnNode.child( 0 ) );
+ }
+
+ MPlug whichRoadPlug = fnNode.findPlug( MString( "teWhichRoad" ), &status );
+
+ if ( status )
+ {
+ //Get the intersection connected to this road and select all the road segs
+ //attached to it.
+ if ( whichRoadPlug.isConnected() )
+ {
+ //Get the road Locator;
+ MPlugArray plugs;
+ whichRoadPlug.connectedTo( plugs, false, true );
+
+ assert( plugs.length() > 0 );
+
+ //Get to road attached to the segment.
+ road = plugs[ 0 ].node();
+ }
+ else
+ {
+ MExt::DisplayWarning( "This road segment is not part of a road!" );
+ return false;
+ }
+ }
+ else
+ {
+ MExt::DisplayWarning( "A road segment must be selected!" );
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+//==============================================================================
+// GetRoadsFromSelectionList
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ( MObject& road )
+//
+// Return: bool
+//
+//==============================================================================
+bool GetRoadsFromSelectionList( MObjectArray& roadArray )
+{
+ MStatus status;
+
+ MSelectionList selectList;
+ MGlobal::getActiveSelectionList( selectList );
+
+ if ( selectList.length() <= 0 )
+ {
+ MExt::DisplayWarning( "At least one road segment must be selected!" );
+ return false;
+ }
+ else
+ {
+ unsigned int i;
+ for ( i = 0; i < selectList.length(); ++i )
+ {
+ MObject node;
+ selectList.getDependNode( i, node );
+ MFnDagNode fnNode( node );
+
+ if ( fnNode.typeName() == MString( RoadNode::stringId ) )
+ {
+ //this is a road node
+ roadArray.append( fnNode.object() );
+ }
+ else
+ {
+ //Test to make sure the selected item is a road segment.
+ MFn::Type type = fnNode.type();
+
+ if ( fnNode.typeName() == MString( "transform" ) )
+ {
+ //We want the child of this, not the transform.
+ fnNode.setObject( fnNode.child( 0 ) );
+ }
+
+ MPlug whichRoadPlug = fnNode.findPlug( MString( "teWhichRoad" ), &status );
+
+ if ( status )
+ {
+ //Get the intersection connected to this road and select all the road segs
+ //attached to it.
+ if ( whichRoadPlug.isConnected() )
+ {
+ //Get the road Locator;
+ MPlugArray plugs;
+ whichRoadPlug.connectedTo( plugs, false, true );
+
+ assert( plugs.length() > 0 );
+
+ //Get to road attached to the segment.
+ roadArray.append( plugs[ 0 ].node() );
+ }
+ else
+ {
+ MExt::DisplayWarning( "This road segment: %s is not part of a road!", fnNode.name().asChar() );
+ return false;
+ }
+ }
+ }
+ }
+ }
+
+ return true;
+} \ No newline at end of file
diff --git a/tools/trackeditor/code/commands/intersectioncommands.h b/tools/trackeditor/code/commands/intersectioncommands.h
new file mode 100644
index 0000000..f2a261b
--- /dev/null
+++ b/tools/trackeditor/code/commands/intersectioncommands.h
@@ -0,0 +1,60 @@
+#include "precompiled/PCH.h"
+
+#ifndef INTERSECTION_COMMANDS
+#define INTERSECTION_COMMANDS
+
+class CreateRoadCmd : public MPxCommand
+{
+public:
+ CreateRoadCmd() {};
+ ~CreateRoadCmd() {};
+
+ static void* creator();
+ virtual MStatus doIt( const MArgList& args );
+
+ static const char* stringId;
+};
+
+class AddIntersectionToRoadCmd : public MPxCommand
+{
+public:
+ AddIntersectionToRoadCmd() {};
+ ~AddIntersectionToRoadCmd() {};
+
+ static void* creator();
+ virtual MStatus doIt( const MArgList& args );
+
+ static const char* stringId;
+};
+
+class ShowRoadCmd : public MPxCommand
+{
+public:
+ ShowRoadCmd() {};
+ ~ShowRoadCmd() {};
+
+ static void* creator();
+ virtual MStatus doIt( const MArgList& args );
+
+ static const char* stringId;
+};
+
+class DestroyRoadCmd : public MPxCommand
+{
+public:
+ DestroyRoadCmd() {};
+ ~DestroyRoadCmd() {};
+
+ static void* creator();
+ virtual MStatus doIt( const MArgList& args );
+
+ static const char* stringId;
+};
+
+
+
+//Global tool like thing.
+bool GetRoadFromSelectionList( MObject& road );
+bool GetRoadsFromSelectionList( MObjectArray& road );
+
+#endif \ No newline at end of file
diff --git a/tools/trackeditor/code/commands/trackeditorcommands.cpp b/tools/trackeditor/code/commands/trackeditorcommands.cpp
new file mode 100644
index 0000000..29aeb76
--- /dev/null
+++ b/tools/trackeditor/code/commands/trackeditorcommands.cpp
@@ -0,0 +1,222 @@
+#include "precompiled/PCH.h"
+
+#include "trackeditorcommands.h"
+#include "main/trackeditor.h"
+#include "utility/mext.h"
+#include "main/constants.h"
+
+//TEStateChange
+const char* TEStateChangeCommand::stringId = "TE_StateChange";
+
+//==============================================================================
+// TEStateChangeCommand::creator
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//==============================================================================
+void* TEStateChangeCommand::creator()
+{
+ return new TEStateChangeCommand();
+}
+
+//==============================================================================
+// TEStateChangeCommand::doIt
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ( const MArgList& args )
+//
+// Return: MStatus
+//
+//==============================================================================
+MStatus TEStateChangeCommand::doIt( const MArgList& args )
+{
+ assert( args.length() == 1 );
+
+ int arg;
+ args.get( 0, arg );
+
+ TrackEditor::SetEditMode( (TrackEditor::EditMode) arg );
+
+ return MStatus::kSuccess;
+}
+
+//TEGetSelectedVertexPosition
+
+const char* TEGetSelectedVertexPosition::stringId = "TE_GetSelectedVertexPosition";
+
+//==============================================================================
+// TEGetSelectedVertexPosition::creator
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//==============================================================================
+void* TEGetSelectedVertexPosition::creator()
+{
+ return new TEGetSelectedVertexPosition();
+}
+
+//==============================================================================
+// TEGetSelectedVertexPosition::doIt
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ( const MArgList& args )
+//
+// Return: MStatus
+//
+//==============================================================================
+MStatus TEGetSelectedVertexPosition::doIt( const MArgList& args )
+{
+ MStatus status;
+ MDoubleArray returnVal( 3, 0 );
+
+ assert( args.length() == 1 ); //Only one arg.
+
+ MString argString;
+ args.get( 0, argString );
+
+ MSelectionList activeList;
+ MGlobal::getActiveSelectionList(activeList);
+
+ MItSelectionList iter( activeList, MFn::kMeshVertComponent, &status);
+
+ //We're only going to deal with the first selected item. Don't select more
+ //Than one please.
+
+ if ( !iter.isDone() )
+ {
+ MDagPath item;
+ MObject component;
+ iter.getDagPath( item, component );
+ // do something with it
+
+ MStatus isMeshIT;
+ MItMeshVertex mITVert( item , component, &isMeshIT );
+
+ if(isMeshIT == MS::kSuccess)
+ {
+ MPoint vertPos;
+ double x, y, z;
+
+ if ( argString == MString( "local" ) )
+ {
+ vertPos = mITVert.position( MSpace::kObject, &status );
+ x = vertPos[0];
+ y = vertPos[1];
+ z = vertPos[2];
+ }
+ else //"world"
+ {
+ vertPos = mITVert.position( MSpace::kWorld, &status );
+ x = vertPos[0];
+ y = vertPos[1];
+ z = vertPos[2];
+ }
+
+ returnVal[0] = x / TEConstants::Scale;
+ returnVal[1] = y / TEConstants::Scale;
+ returnVal[2] = z / TEConstants::Scale;
+
+ }
+
+ iter.next(); //This is to test if there are more verts than needed.
+ }
+ else
+ {
+ MExt::DisplayWarning("No vertices selected!");
+ }
+
+ if ( !iter.isDone() )
+ {
+ MExt::DisplayWarning("Too many vertices selected!");
+ }
+
+
+ MPxCommand::setResult( returnVal );
+
+ return MStatus::kSuccess;
+}
+
+
+//TEGetSelectedVertexIndex
+
+const char* TEGetSelectedVertexIndex::stringId = "TE_GetSelectedVertexIndex";
+
+//==============================================================================
+// TEGetSelectedVertexIndex::creator
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//==============================================================================
+void* TEGetSelectedVertexIndex::creator()
+{
+ return new TEGetSelectedVertexIndex();
+}
+
+//==============================================================================
+// TEGetSelectedVertexIndex::doIt
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ( const MArgList& args )
+//
+// Return: MStatus
+//
+//==============================================================================
+MStatus TEGetSelectedVertexIndex::doIt( const MArgList& args )
+{
+ int returnVal = -1;
+
+ MStatus status;
+ MSelectionList activeList;
+ MGlobal::getActiveSelectionList(activeList);
+
+ MItSelectionList iter( activeList, MFn::kMeshVertComponent, &status);
+
+ //We're only going to deal with the first selected item. Don't select more
+ //Than one please.
+
+ if ( !iter.isDone() )
+ {
+ MDagPath item;
+ MObject component;
+ iter.getDagPath( item, component );
+ // do something with it
+
+ MStatus isMeshIT;
+ MItMeshVertex mITVert( item , component, &isMeshIT );
+
+ if(isMeshIT == MS::kSuccess)
+ {
+ returnVal = mITVert.index();
+ }
+
+ iter.next(); //This is to test if there are more verts than needed.
+ }
+ else
+ {
+ MExt::DisplayWarning("No vertices selected!");
+ }
+
+ if ( !iter.isDone() )
+ {
+ MExt::DisplayWarning("Too many vertices selected!");
+ }
+
+ MPxCommand::setResult( returnVal );
+
+ return MStatus::kSuccess;
+}
diff --git a/tools/trackeditor/code/commands/trackeditorcommands.h b/tools/trackeditor/code/commands/trackeditorcommands.h
new file mode 100644
index 0000000..990ffd7
--- /dev/null
+++ b/tools/trackeditor/code/commands/trackeditorcommands.h
@@ -0,0 +1,42 @@
+#include "precompiled/PCH.h"
+
+#ifndef TE_COMMANDS_H
+#define TE_COMMANDS_H
+
+class TEStateChangeCommand : public MPxCommand
+{
+public:
+ TEStateChangeCommand() {};
+ ~TEStateChangeCommand() {};
+
+ static void* creator();
+ virtual MStatus doIt( const MArgList& args );
+
+ static const char* stringId;
+};
+
+class TEGetSelectedVertexPosition : public MPxCommand
+{
+public:
+ TEGetSelectedVertexPosition() {};
+ ~TEGetSelectedVertexPosition() {};
+
+ static void* creator();
+ virtual MStatus doIt( const MArgList& args );
+
+ static const char* stringId;
+};
+
+class TEGetSelectedVertexIndex : public MPxCommand
+{
+public:
+ TEGetSelectedVertexIndex() {};
+ ~TEGetSelectedVertexIndex() {};
+
+ static void* creator();
+ virtual MStatus doIt( const MArgList& args );
+
+ static const char* stringId;
+};
+
+#endif \ No newline at end of file
diff --git a/tools/trackeditor/code/commands/treelinecommand.cpp b/tools/trackeditor/code/commands/treelinecommand.cpp
new file mode 100644
index 0000000..25f22de
--- /dev/null
+++ b/tools/trackeditor/code/commands/treelinecommand.cpp
@@ -0,0 +1,323 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: SnapSelectedTreelines.cpp
+//
+// Description: Implement SnapSelectedTreelines
+//
+// History: 27/05/2002 + Created -- Cary Brisebois
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+
+
+//========================================
+// Project Includes
+//========================================
+#include "commands/TreeLineCommand.h"
+#include "main/trackeditor.h"
+#include "nodes/treelineshapenode.h"
+
+//******************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//******************************************************************************
+const char* SnapSelectedTreelines::stringId = "TE_SnapSelectedTreelines";
+const char* ConvertTreelineToGeometry::stringId = "TE_ConvertTreelineToGeometry";
+const char* SetDeleteTreeline::stringId = "TE_SetDeleteTreeline";
+
+//******************************************************************************
+//
+// Public Member Functions
+//
+//******************************************************************************
+
+//==============================================================================
+// SnapSelectedTreelines::SnapSelectedTreelines
+//==============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+SnapSelectedTreelines::SnapSelectedTreelines()
+{
+}
+
+//==============================================================================
+// SnapSelectedTreelines::~SnapSelectedTreelines
+//==============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+SnapSelectedTreelines::~SnapSelectedTreelines()
+{
+}
+
+//=============================================================================
+// SnapSelectedTreelines::doIt
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( const MArgList& args )
+//
+// Return: MStatus
+//
+//=============================================================================
+MStatus SnapSelectedTreelines::doIt( const MArgList& args )
+{
+ //For each treeline in the selection list, call
+
+ MSelectionList selectionList;
+ MGlobal::getActiveSelectionList( selectionList );
+
+ MItSelectionList itSel( selectionList );
+
+ while ( !itSel.isDone() )
+ {
+ MObject obj;
+ itSel.getDependNode( obj );
+
+ Recurse( obj );
+
+ itSel.next();
+ }
+
+ return MStatus::kSuccess;
+}
+
+//=============================================================================
+// SnapSelectedTreelines::Recurse
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( MObject& obj )
+//
+// Return: void
+//
+//=============================================================================
+void SnapSelectedTreelines::Recurse( MObject& obj )
+{
+ MStatus status;
+
+ MFnTransform FnTransform( obj, &status );
+
+ if ( status )
+ {
+ //This is a transform...
+
+ MFnDagNode fnDagNode( obj );
+
+ unsigned int i;
+ for ( i = 0; i < fnDagNode.childCount(); ++i )
+ {
+ Recurse( fnDagNode.child( i ) );
+ }
+ }
+ else
+ {
+ MFnDependencyNode fnDepNode( obj );
+
+ if ( fnDepNode.typeId() == TETreeLine::TreelineShapeNode::id )
+ {
+ TETreeLine::TreelineShapeNode::SnapTreeline( obj );
+ }
+
+ }
+}
+
+//*****************************************************************************
+//
+// ConvertTreelineToGeometry
+//
+//*****************************************************************************
+
+//=============================================================================
+// ConvertTreelineToGeometry::ConvertTreelineToGeometry
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: ConvertTreelineToGeometry
+//
+//=============================================================================
+ConvertTreelineToGeometry::ConvertTreelineToGeometry()
+{
+}
+
+//=============================================================================
+// ConvertTreelineToGeometry::~ConvertTreelineToGeometry
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: ConvertTreelineToGeometry
+//
+//=============================================================================
+ConvertTreelineToGeometry::~ConvertTreelineToGeometry()
+{
+}
+
+//=============================================================================
+// ConvertTreelineToGeometry::doIt
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( const MArgList& args )
+//
+// Return: MStatus
+//
+//=============================================================================
+MStatus ConvertTreelineToGeometry::doIt( const MArgList& args )
+{
+ //For each treeline in the world, call
+
+ MSelectionList selectionList;
+ selectionList.clear();
+
+ MItDag itDag( MItDag::kDepthFirst );
+
+ while ( !itDag.isDone() )
+ {
+ MDagPath dagPath;
+ itDag.getPath( dagPath );
+
+ selectionList.add( dagPath );
+
+ itDag.next();
+ }
+
+ if ( selectionList.length() > 0 )
+ {
+
+ MItSelectionList itSel( selectionList );
+
+ while ( !itSel.isDone() )
+ {
+ MObject obj;
+ itSel.getDependNode( obj );
+
+ Recurse( obj );
+
+ itSel.next();
+ }
+ }
+
+ return MStatus::kSuccess;
+}
+
+//=============================================================================
+// ConvertTreelineToGeometry::Recurse
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( MObject& obj )
+//
+// Return: void
+//
+//=============================================================================
+void ConvertTreelineToGeometry::Recurse( MObject& obj )
+{
+ MStatus status;
+
+/*
+ MFnTransform FnTransform( obj, &status );
+
+ if ( status )
+ {
+ //This is a transform...
+
+ MFnDagNode fnDagNode( obj );
+
+ unsigned int i;
+ for ( i = 0; i < fnDagNode.childCount(); ++i )
+ {
+ Recurse( fnDagNode.child( i ) );
+ }
+ }
+ else
+ {
+*/
+ MFnDependencyNode fnDepNode( obj );
+
+ if ( fnDepNode.typeId() == TETreeLine::TreelineShapeNode::id )
+ {
+ TETreeLine::TreelineShapeNode::ConvertToGeometry( obj );
+ }
+
+// }
+}
+
+//*****************************************************************************
+//
+// SetDeleteTreeline
+//
+//*****************************************************************************
+
+//=============================================================================
+// SetDeleteTreeline::SetDeleteTreeline
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: SetDeleteTreeline
+//
+//=============================================================================
+SetDeleteTreeline::SetDeleteTreeline()
+{
+}
+
+//=============================================================================
+// SetDeleteTreeline::~SetDeleteTreeline
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: SetDeleteTreeline
+//
+//=============================================================================
+SetDeleteTreeline::~SetDeleteTreeline()
+{
+}
+
+//=============================================================================
+// SetDeleteTreeline::doIt
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( const MArgList& args )
+//
+// Return: MStatus
+//
+//=============================================================================
+MStatus SetDeleteTreeline::doIt( const MArgList& args )
+{
+ assert( args.length() == 1 );
+
+ bool del;
+ args.get( 0, del );
+
+ TrackEditor::SetDeleteTreelines( del );
+
+ return MStatus::kSuccess;
+}
+
+//******************************************************************************
+//
+// Private Member Functions
+//
+//******************************************************************************
diff --git a/tools/trackeditor/code/commands/treelinecommand.h b/tools/trackeditor/code/commands/treelinecommand.h
new file mode 100644
index 0000000..1e556b6
--- /dev/null
+++ b/tools/trackeditor/code/commands/treelinecommand.h
@@ -0,0 +1,136 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: tetreelinecommand.h
+//
+// Description: Blahblahblah
+//
+// History: 27/05/2002 + Created -- Cary Brisebois
+//
+//=============================================================================
+
+#ifndef TETREELINECOMMAND_H
+#define TETREELINECOMMAND_H
+
+//========================================
+// Nested Includes
+//========================================
+#include "precompiled/PCH.h"
+
+//========================================
+// Forward References
+//========================================
+
+//=============================================================================
+//
+// Synopsis: Blahblahblah
+//
+//=============================================================================
+
+class SnapSelectedTreelines : public MPxCommand
+{
+public:
+ SnapSelectedTreelines();
+ virtual ~SnapSelectedTreelines();
+
+ static void* creator();
+ virtual MStatus doIt( const MArgList& args );
+
+ static const char* stringId;
+
+private:
+
+ void Recurse( MObject& obj );
+
+ //Prevent wasteful constructor creation.
+ SnapSelectedTreelines( const SnapSelectedTreelines& tetreelinecommand );
+ SnapSelectedTreelines& operator=( const SnapSelectedTreelines& tetreelinecommand );
+};
+
+class ConvertTreelineToGeometry : public MPxCommand
+{
+public:
+ ConvertTreelineToGeometry();
+ ~ConvertTreelineToGeometry();
+
+ static void* creator();
+ virtual MStatus doIt( const MArgList& args );
+
+ static const char* stringId;
+
+private:
+ void Recurse( MObject& obj );
+
+ //Prevent wasteful constructor creation.
+ ConvertTreelineToGeometry( const ConvertTreelineToGeometry& tetreelinecommand );
+ ConvertTreelineToGeometry& operator=( const ConvertTreelineToGeometry& tetreelinecommand );
+};
+
+class SetDeleteTreeline : public MPxCommand
+{
+public:
+ SetDeleteTreeline();
+ ~SetDeleteTreeline();
+
+ static void* creator();
+ virtual MStatus doIt( const MArgList& args );
+
+ static const char* stringId;
+
+private:
+
+ //Prevent wasteful constructor creation.
+ SetDeleteTreeline( const SetDeleteTreeline& tetreelinecommand );
+ SetDeleteTreeline& operator=( const SetDeleteTreeline& tetreelinecommand );
+};
+//******************************************************************************
+//
+// Inline Public Functions
+//
+//******************************************************************************
+
+//=============================================================================
+// SnapSelectedTreelines::creator
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//=============================================================================
+inline void* SnapSelectedTreelines::creator()
+{
+ return new SnapSelectedTreelines();
+}
+
+//=============================================================================
+// ConvertTreelineToGeometry::creator
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//=============================================================================
+inline void* ConvertTreelineToGeometry::creator()
+{
+ return new ConvertTreelineToGeometry();
+}
+
+//=============================================================================
+// SetDeleteTreeline::creator
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//=============================================================================
+inline void* SetDeleteTreeline::creator()
+{
+ return new SetDeleteTreeline();
+}
+#endif //TETREELINECOMMAND_H
diff --git a/tools/trackeditor/code/constants/version.hpp b/tools/trackeditor/code/constants/version.hpp
new file mode 100644
index 0000000..bf88478
--- /dev/null
+++ b/tools/trackeditor/code/constants/version.hpp
@@ -0,0 +1,16 @@
+/*===========================================================================
+
+ File:: version.hpp
+
+ Copyright (c) %YEAR% Radical Entertainment, Inc. All rights reserved.
+
+===========================================================================*/
+
+#ifndef _VERSION_HPP
+#define _VERSION_HPP
+
+extern char* version;
+extern char* versioninfo[];
+
+#endif
+
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
+
diff --git a/tools/trackeditor/code/main/constants.h b/tools/trackeditor/code/main/constants.h
new file mode 100644
index 0000000..b9bcc25
--- /dev/null
+++ b/tools/trackeditor/code/main/constants.h
@@ -0,0 +1,21 @@
+#ifndef TE_CONSTANTS
+#define TE_CONSTANTS
+
+namespace TEConstants
+{
+ const unsigned int TypeIDPrefix = 0x00040200;
+ const float Scale = 100.0f;
+
+ namespace NodeIDs
+ {
+ const unsigned int WallLocator = 0xc0;
+ const unsigned int FenceLine = 0xc1;
+ const unsigned int TileDisplay = 0xc2;
+ const unsigned int Intersection = 0xc3;
+ const unsigned int Road = 0xc4;
+ const unsigned int TreeLine = 0xc5;
+ const unsigned int PedPath = 0xc6;
+ }
+}
+
+#endif \ No newline at end of file
diff --git a/tools/trackeditor/code/main/pluginMain.cpp b/tools/trackeditor/code/main/pluginMain.cpp
new file mode 100644
index 0000000..190ea4d
--- /dev/null
+++ b/tools/trackeditor/code/main/pluginMain.cpp
@@ -0,0 +1,164 @@
+//
+// Copyright (C) 2002 Radical Entertainment
+//
+// File: pluginMain.cpp
+//
+// Author: Maya SDK Wizard
+//
+#include "precompiled/PCH.h"
+
+#include <maya/MFnPlugin.h>
+
+//This is a warning provided by the STL... It seems that toollib gets whacky when there
+//is other templates made... Sigh...
+#pragma warning(disable:4786)
+
+#include "pluginmain.h"
+#include "trackeditor.h"
+
+#include "utility/mayahandles.h"
+#include "utility/mext.h"
+
+//Nodes
+#include "nodes/walllocator.h"
+#include "nodes/fenceline.h"
+#include "nodes/tiledisplay.h"
+#include "nodes/intersection.h"
+#include "nodes/road.h"
+#include "nodes/treelineshapenode.h"
+#include "nodes/pedpath.h"
+
+//Contexts
+#include "contexts/bvcontext.h"
+#include "contexts/intersectioncontext.h"
+#include "contexts/treelinecontext.h"
+#include "contexts/ppcontext.h"
+
+//Commands
+#include "commands/export.h"
+#include "commands/trackeditorcommands.h"
+#include "commands/intersectioncommands.h"
+#include "commands/treelinecommand.h"
+
+
+TrackEditor* gTE = 0;
+
+MStatus initializePlugin( MObject obj )
+//
+// Description:
+// this method is called when the plug-in is loaded into Maya. It
+// registers all of the services that this plug-in provides with
+// Maya.
+//
+// Arguments:
+// obj - a handle to the plug-in object (use MFnPlugin to access it)
+//
+{
+ MStatus status;
+
+
+ MayaHandles::SetHInstance( (void*)(MhInstPlugin) );
+
+ MFnPlugin plugin( obj, "Radical Entertainment", "4.0.1", "Any");
+
+ // Add plug-in feature registration here
+ //
+
+ //Register Nodes
+ REGISTER_LOCATOR( plugin, WallLocatorNode );
+ REGISTER_LOCATOR( plugin, FenceLineNode );
+ REGISTER_LOCATOR( plugin, TileDisplayNode );
+ REGISTER_LOCATOR( plugin, IntersectionLocatorNode );
+ REGISTER_LOCATOR( plugin, RoadNode );
+ REGISTER_LOCATOR( plugin, PedPathNode );
+
+ REGISTER_SHAPE( plugin, TETreeLine::TreelineShapeNode );
+
+ //Register Contexts
+ REGISTER_CONTEXT( plugin, BVContext );
+ REGISTER_CONTEXT( plugin, IntersectionContext );
+ REGISTER_CONTEXT( plugin, TreeLineContext );
+ REGISTER_CONTEXT( plugin, PPContext );
+
+ //Register Commands
+ REGISTER_COMMAND( plugin, PPSplitCmd );
+ REGISTER_COMMAND( plugin, BVSplitCmd );
+ REGISTER_COMMAND( plugin, ExportCommand );
+ REGISTER_COMMAND( plugin, TEStateChangeCommand );
+ REGISTER_COMMAND( plugin, TEGetSelectedVertexPosition );
+ REGISTER_COMMAND( plugin, TEGetSelectedVertexIndex );
+ REGISTER_COMMAND( plugin, CreateRoadCmd );
+ REGISTER_COMMAND( plugin, AddIntersectionToRoadCmd );
+ REGISTER_COMMAND( plugin, ShowRoadCmd );
+ REGISTER_COMMAND( plugin, DestroyRoadCmd );
+ REGISTER_COMMAND( plugin, SnapSelectedTreelines );
+ REGISTER_COMMAND( plugin, ConvertTreelineToGeometry );
+ REGISTER_COMMAND( plugin, SetDeleteTreeline );
+
+
+ //Create the TrackEditor.
+ gTE = new TrackEditor();
+
+ //Run any startup scripts.
+ MGlobal::sourceFile( MString( "te_main.mel" ) );
+
+ return status;
+}
+
+MStatus uninitializePlugin( MObject obj )
+//
+// Description:
+// this method is called when the plug-in is unloaded from Maya. It
+// deregisters all of the services that it was providing.
+//
+// Arguments:
+// obj - a handle to the plug-in object (use MFnPlugin to access it)
+//
+{
+ MStatus status;
+ MFnPlugin plugin( obj );
+
+ // Add plug-in feature deregistration here
+ //
+
+ //Run any cleanup scripts.
+ MGlobal::sourceFile( MString( "te_cleanup.mel" ) );
+
+ if ( gTE )
+ {
+ delete gTE;
+ }
+
+ //Unregister Commands
+ DEREGISTER_COMMAND( plugin, SetDeleteTreeline );
+ DEREGISTER_COMMAND( plugin, ConvertTreelineToGeometry );
+ DEREGISTER_COMMAND( plugin, SnapSelectedTreelines );
+ DEREGISTER_COMMAND( plugin, DestroyRoadCmd );
+ DEREGISTER_COMMAND( plugin, ShowRoadCmd );
+ DEREGISTER_COMMAND( plugin, AddIntersectionToRoadCmd );
+ DEREGISTER_COMMAND( plugin, CreateRoadCmd );
+ DEREGISTER_COMMAND( plugin, TEGetSelectedVertexIndex );
+ DEREGISTER_COMMAND( plugin, TEGetSelectedVertexPosition );
+ DEREGISTER_COMMAND( plugin, TEStateChangeCommand );
+ DEREGISTER_COMMAND( plugin, ExportCommand );
+ DEREGISTER_COMMAND( plugin, BVSplitCmd );
+
+ //Unregister Contexts
+ DEREGISTER_CONTEXT( plugin, PPContext );
+ DEREGISTER_CONTEXT( plugin, TreeLineContext );
+ DEREGISTER_CONTEXT( plugin, IntersectionContext );
+ DEREGISTER_CONTEXT( plugin, BVContext );
+ DEREGISTER_CONTEXT( plugin, PPContext );
+
+ //Unregister Nodes
+ DEREGISTER_NODE( plugin, PedPathNode );
+ DEREGISTER_NODE( plugin, TETreeLine::TreelineShapeNode );
+ DEREGISTER_NODE( plugin, RoadNode );
+ DEREGISTER_NODE( plugin, IntersectionLocatorNode );
+ DEREGISTER_NODE( plugin, TileDisplayNode );
+ DEREGISTER_NODE( plugin, FenceLineNode );
+ DEREGISTER_NODE( plugin, WallLocatorNode );
+
+ return status;
+}
+
diff --git a/tools/trackeditor/code/main/pluginMain.h b/tools/trackeditor/code/main/pluginMain.h
new file mode 100644
index 0000000..7ed6ee6
--- /dev/null
+++ b/tools/trackeditor/code/main/pluginMain.h
@@ -0,0 +1,47 @@
+#include "precompiled/PCH.h"
+
+//----------------------------------------
+// MACROS
+//----------------------------------------
+
+#define REGISTER_COMMAND( p, c ) if ( ! ( ( p ).registerCommand( c##::stringId, \
+ c##::creator ) \
+ ) \
+ ) return MS::kFailure
+
+#define REGISTER_CONTEXT( p, c ) if ( ! ( ( p ).registerContextCommand( c##::stringId, \
+ c##Cmd::creator ) \
+ ) \
+ ) return MS::kFailure
+
+
+#define REGISTER_LOCATOR( p, n ) if ( ! ( ( p ).registerNode( n##::stringId, \
+ n##::id, \
+ n##::creator, \
+ n##::initialize, \
+ MPxNode::kLocatorNode ) \
+ ) \
+ ) return MS::kFailure
+
+#define REGISTER_NODE( p, n ) if ( ! ( ( p ).registerNode( n##::stringId, \
+ n##::id, \
+ n##::creator, \
+ n##::initialize ) \
+ ) \
+ ) return MS::kFailure
+
+#define REGISTER_SHAPE( p, n ) if ( ! ( ( p ).registerShape( n##::stringId, \
+ n##::id, \
+ n##::creator, \
+ n##::initialize, \
+ n##UI::creator ) \
+ ) \
+ ) return MS::kFailure
+
+#define DEREGISTER_COMMAND( p, c ) ( p ).deregisterCommand( c##::stringId )
+
+#define DEREGISTER_CONTEXT( p, c ) ( p ).deregisterContextCommand( c##::stringId )
+
+
+#define DEREGISTER_NODE( p, n ) ( p ).deregisterNode( n##::id )
+
diff --git a/tools/trackeditor/code/main/shapeconstants.h b/tools/trackeditor/code/main/shapeconstants.h
new file mode 100644
index 0000000..c6c777d
--- /dev/null
+++ b/tools/trackeditor/code/main/shapeconstants.h
@@ -0,0 +1,34 @@
+#ifndef SHAPE_CONSTANTS_H
+#define SHAPE_CONSTANTS_H
+
+#define LEAD_COLOR 1 // green
+#define ACTIVE_COLOR 1 // white
+#define ACTIVE_AFFECTED_COLOR 1 // purple
+#define DORMANT_COLOR 1 // blue
+#define HILITE_COLOR 1 // pale blue
+
+#define P3D_BILLBOARD_QUAD_ID 0x040260
+#define P3D_BILLBOARD_QUAD_GROUP_ID 0x040261
+#define MAYA_LAMBERT_ID 1380729165
+#define MAYA_PHONG_ID 1380993103
+#define MAYA_LAYERED_SHADER_ID 1280922195
+
+namespace TETreeLine
+{
+
+const float MIN_DISPLAY_SIZE=0.001f;
+
+enum {
+ WIREFRAME,
+ WIREFRAME_SHADED,
+ SMOOTH_SHADED,
+ FLAT_SHADED,
+ VERTICES,
+ LAST_TOKEN
+};
+
+}; //namespace TETreeLine
+
+
+#endif //SHAPE_CONSTANTS_H
+
diff --git a/tools/trackeditor/code/main/trackeditor.cpp b/tools/trackeditor/code/main/trackeditor.cpp
new file mode 100644
index 0000000..0b0ccc2
--- /dev/null
+++ b/tools/trackeditor/code/main/trackeditor.cpp
@@ -0,0 +1,350 @@
+#include "precompiled/PCH.h"
+
+#include "trackeditor.h"
+#include "utility/mext.h"
+
+#include "nodes/tiledisplay.h"
+#include "nodes/fenceline.h"
+#include "nodes/intersection.h"
+#include "nodes/walllocator.h"
+#include "nodes/road.h"
+#include "nodes/treelineshapenode.h"
+#include "nodes/pedpath.h"
+
+const char* TrackEditor::Name = "TrackEditorNode";
+TrackEditor::EditMode TrackEditor::sEditMode = TrackEditor::OFF;
+unsigned int TrackEditor::sNodeAddedbackID = 0;
+unsigned int TrackEditor::sWindowClosedCallbackID = 0;
+bool TrackEditor::sDeleteTreelines = true;
+
+
+//==============================================================================
+// TrackEditor::TrackEditor
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: TrackEditor
+//
+//==============================================================================
+TrackEditor::TrackEditor()
+{
+// sNodeAddedbackID = MDGMessage::addNodeAddedCallback ( NodeAddedCB,
+// MString( "surfaceShape" ) );
+};
+
+//==============================================================================
+// TrackEditor::~TrackEditor
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: TrackEditor
+//
+//==============================================================================
+TrackEditor::~TrackEditor()
+{
+ if ( sNodeAddedbackID )
+ {
+ MDGMessage::removeCallback( sNodeAddedbackID );
+ }
+
+ if ( sWindowClosedCallbackID )
+ {
+ MUiMessage::removeCallback( sWindowClosedCallbackID );
+ }
+
+ RemoveTileDisplayNode();
+};
+
+//==============================================================================
+// TrackEditor::Exists
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: bool
+//
+//==============================================================================
+bool TrackEditor::Exists()
+{
+ MDagPath pathToTrackEditor;
+ return MExt::FindDagNodeByName( &pathToTrackEditor, MString( TrackEditor::Name ) );
+}
+
+//==============================================================================
+// TrackEditor::AddChild
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ( MObject& obj )
+//
+// Return: MStatus
+//
+//==============================================================================
+MStatus TrackEditor::AddChild( MObject& obj )
+{
+ //Make sure this exists.
+ CreateTrackEditorNode();
+
+ MDagPath pathToTrackEditor;
+
+ bool good = false;
+
+ if ( MExt::FindDagNodeByName( &pathToTrackEditor, MString( TrackEditor::Name ) ) )
+ {
+ good = true;
+ }
+ else
+ {
+ MGlobal::sourceFile( MString( "te_setup.mel" ) );
+
+ if ( MExt::FindDagNodeByName( &pathToTrackEditor, MString( TrackEditor::Name ) ) )
+ {
+ good = true;
+ }
+ }
+
+ if ( good )
+ {
+ MFnDagNode fnDagNodeTE;
+
+ //Which type?
+ MFnDagNode fnDagNodeObj( obj );
+
+ if ( fnDagNodeObj.typeId() == FenceLineNode::id )
+ {
+ //This is a fenceline, parent to the "Fences" node.
+ MDagPath dagPath;
+ if ( MExt::FindDagNodeByName( &dagPath, MString("Fences"), pathToTrackEditor.node() ) )
+ {
+ fnDagNodeTE.setObject( dagPath.node() );
+ }
+ else
+ {
+ MExt::DisplayError( "Someone has deleted Terrain Edit nodes!!" );
+ }
+ }
+ if ( fnDagNodeObj.typeId() == PedPathNode::id )
+ {
+ //This is a ped path, parent to the "PedPaths" node.
+ MDagPath dagPath;
+ if ( MExt::FindDagNodeByName( &dagPath, MString("PedPaths"), pathToTrackEditor.node() ) )
+ {
+ fnDagNodeTE.setObject( dagPath.node() );
+ }
+ else
+ {
+ MExt::DisplayError( "Someone has deleted Terrain Edit nodes!!" );
+ }
+ }
+ else if ( fnDagNodeObj.typeId() == IntersectionLocatorNode::id )
+ {
+ //This is a fenceline, parent to the "Intersections" node.
+ MDagPath dagPath;
+ if ( MExt::FindDagNodeByName( &dagPath, MString("Intersections"), pathToTrackEditor.node() ) )
+ {
+ fnDagNodeTE.setObject( dagPath.node() );
+ }
+ else
+ {
+ MExt::DisplayError( "Someone has deleted Terrain Edit nodes!!" );
+ }
+ }
+ else if ( fnDagNodeObj.typeId() == RoadNode::id )
+ {
+ //This is a fenceline, parent to the "Roads" node.
+ MDagPath dagPath;
+ if ( MExt::FindDagNodeByName( &dagPath, MString("Roads"), pathToTrackEditor.node() ) )
+ {
+ fnDagNodeTE.setObject( dagPath.node() );
+ }
+ else
+ {
+ MExt::DisplayError( "Someone has deleted Terrain Edit nodes!!" );
+ }
+ }
+ else if ( fnDagNodeObj.typeId() == TETreeLine::TreelineShapeNode::id )
+ {
+ //This is a tree line, add to the "Treelines" node
+ MDagPath dagPath;
+ if ( MExt::FindDagNodeByName( &dagPath, MString("Treelines"), pathToTrackEditor.node() ) )
+ {
+ fnDagNodeTE.setObject( dagPath.node() );
+ }
+ else
+ {
+ MExt::DisplayError( "Someone has deleted Terrain Edit nodes!!" );
+ }
+ }
+ else
+ {
+ fnDagNodeTE.setObject( pathToTrackEditor.node() );
+ }
+
+ MObject objT = fnDagNodeObj.parent( 0 );
+
+ return fnDagNodeTE.addChild( objT );
+ }
+
+ return MS::kFailure;
+}
+
+//Edit mode stuff.
+//==============================================================================
+// TrackEditor::GetEditMode
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: TrackEditor
+//
+//==============================================================================
+TrackEditor::EditMode TrackEditor::GetEditMode()
+{
+ //Test the track editor radio buttons for their state.
+
+ return sEditMode;
+};
+
+//==============================================================================
+// TrackEditor::SetEditMode
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ( TrackEditor::EditMode mode )
+//
+// Return: void
+//
+//==============================================================================
+void TrackEditor::SetEditMode( TrackEditor::EditMode mode )
+{
+ //Setup whatever needs setting up for the given mode.
+ switch( mode )
+ {
+ case OFF:
+ {
+ RemoveTileDisplayNode();
+
+ MGlobal::executeCommand( MString("teCloseEditorWindow()") );
+ }
+ break;
+ case EDIT:
+ {
+ //Make sure this exists;
+ CreateTileDisplayNode();
+
+ MGlobal::executeCommand( MString("teOpenEditorWindow()") );
+
+ //We should register a callback for when the window is closed.
+ sWindowClosedCallbackID = MUiMessage::addUiDeletedCallback( MString( "TE_TileEditor" ), WindowClosedCB );
+ }
+ break;
+ case DISPLAY:
+ {
+ //Make sure this exists;
+ CreateTileDisplayNode();
+
+ MGlobal::executeCommand( MString("teCloseEditorWindow()") );
+ }
+ break;
+ default:
+ {
+ break;
+ }
+ }
+
+ sEditMode = mode;
+}
+
+//==============================================================================
+// TrackEditor::NodeAddedCB
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ( MObject& node, void* data )
+//
+// Return: void
+//
+//==============================================================================
+void TrackEditor::NodeAddedCB( MObject& node, void* data )
+{
+// assert( false );
+}
+
+//==============================================================================
+// TrackEditor::WindowClosedCB
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ( void* data )
+//
+// Return: void
+//
+//==============================================================================
+void TrackEditor::WindowClosedCB( void* data )
+{
+ SetEditMode( OFF );
+
+ MUiMessage::removeCallback( sWindowClosedCallbackID );
+}
+
+//==============================================================================
+// TrackEditor::CreateTrackEditorNode
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//==============================================================================
+void TrackEditor::CreateTrackEditorNode()
+{
+ MGlobal::executeCommand( "te_Create_TrackEditorNode()" );
+}
+
+//==============================================================================
+// TrackEditor::CreateTileDisplayNode
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//==============================================================================
+void TrackEditor::CreateTileDisplayNode()
+{
+ if ( !MExt::FindDagNodeByName( NULL, MString( TileDisplayNode::stringId ) ) )
+ {
+ MExt::CreateNode( 0, 0, MString( TileDisplayNode::stringId ) );
+ }
+}
+
+//==============================================================================
+// TrackEditor::RemoveTileDisplayNode
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//==============================================================================
+void TrackEditor::RemoveTileDisplayNode()
+{
+ MDagPath dagPath;
+
+ if ( MExt::FindDagNodeByName( &dagPath, MString( TileDisplayNode::stringId ) ) )
+ {
+ MFnDagNode fnDagNode( dagPath );
+
+ MExt::DeleteNode( fnDagNode.object(), true );
+ }
+}
+
diff --git a/tools/trackeditor/code/main/trackeditor.h b/tools/trackeditor/code/main/trackeditor.h
new file mode 100644
index 0000000..d48cba1
--- /dev/null
+++ b/tools/trackeditor/code/main/trackeditor.h
@@ -0,0 +1,85 @@
+#include "precompiled/PCH.h"
+
+#ifndef TRACK_EDITOR
+#define TRACK_EDITOR
+
+//This node exists as the top node of all the other TrackEditor types.
+//See te_setup.mel for more details of how this is a node.
+//There should only ever be one of these in the Hypergraph.
+
+//This is the place where options will be stored also.
+
+class TrackEditor
+{
+public:
+ TrackEditor();
+ ~TrackEditor();
+
+ static const char* Name;
+
+ static bool Exists();
+ static MStatus AddChild( MObject& obj );
+
+ //These are the Track Editing functions and state.
+ enum EditMode
+ {
+ OFF,
+ EDIT,
+ DISPLAY
+ };
+
+ static EditMode GetEditMode();
+
+ static void SetDeleteTreelines( bool del );
+ static bool GetDeleteTreelines();
+
+protected:
+
+ friend class TEStateChangeCommand;
+ static EditMode sEditMode;
+ static void SetEditMode( EditMode mode );
+
+ static bool sDeleteTreelines;
+
+private:
+ static unsigned int sNodeAddedbackID;
+ static unsigned int sWindowClosedCallbackID;
+
+ static void NodeAddedCB( MObject& node, void* data );
+ static void WindowClosedCB( void* data );
+ static void CreateTrackEditorNode();
+ static void CreateTileDisplayNode();
+ static void RemoveTileDisplayNode();
+};
+
+//=============================================================================
+// TrackEditor::SetDeleteTreelines
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( bool del )
+//
+// Return: void
+//
+//=============================================================================
+inline void TrackEditor::SetDeleteTreelines( bool del )
+{
+ sDeleteTreelines = del;
+}
+
+//=============================================================================
+// TrackEditor::GetDeleteTreelines
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: bool
+//
+//=============================================================================
+inline bool TrackEditor::GetDeleteTreelines()
+{
+ return sDeleteTreelines;
+}
+
+#endif \ No newline at end of file
diff --git a/tools/trackeditor/code/nodes/NU.h b/tools/trackeditor/code/nodes/NU.h
new file mode 100644
index 0000000..d43db8f
--- /dev/null
+++ b/tools/trackeditor/code/nodes/NU.h
@@ -0,0 +1,34 @@
+#include "precompiled/PCH.h"
+
+#ifndef NODE_UTIL_H
+#define NODE_UTIL_H
+
+namespace NODE_UTIL
+{
+ inline void DisableAttributes( MObject& node, bool justY = true )
+ {
+ MFnDagNode fnDagNode( node );
+
+ MObject parent = fnDagNode.parent( 0 );
+ MFnDependencyNode fnParent( parent );
+
+ if ( justY )
+ {
+ MPlug ptyPlug = fnParent.findPlug( MString( "translateY" ) );
+ ptyPlug.setLocked( true );
+ }
+ else
+ {
+ MPlug ptPlug = fnParent.findPlug( MString( "translate" ) );
+ ptPlug.setLocked( true );
+ }
+
+ MPlug spPlug = fnParent.findPlug( MString( "scale" ) );
+ spPlug.setLocked( true );
+
+ MPlug rpPlug = fnParent.findPlug( MString( "rotate" ) );
+ rpPlug.setLocked( true );
+ }
+}
+
+#endif \ No newline at end of file
diff --git a/tools/trackeditor/code/nodes/fenceline.cpp b/tools/trackeditor/code/nodes/fenceline.cpp
new file mode 100644
index 0000000..87c8966
--- /dev/null
+++ b/tools/trackeditor/code/nodes/fenceline.cpp
@@ -0,0 +1,201 @@
+#include "fenceline.h"
+#include "walllocator.h"
+#include "utility/mext.h"
+
+#include <toollib.hpp>
+
+MTypeId FenceLineNode::id( TEConstants::TypeIDPrefix, TEConstants::NodeIDs::FenceLine );
+const char* FenceLineNode::stringId = "FenceLine";
+
+//==============================================================================
+// FenceLineNode::FenceLineNode
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: FenceLineNode
+//
+//==============================================================================
+FenceLineNode::FenceLineNode() {}
+
+//==============================================================================
+// FenceLineNode::~FenceLineNode
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: FenceLineNode
+//
+//==============================================================================
+FenceLineNode::~FenceLineNode() {}
+
+//==============================================================================
+// FenceLineNode::creator
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//==============================================================================
+void* FenceLineNode::creator()
+{
+ return new FenceLineNode();
+}
+
+//==============================================================================
+// FenceLineNode::initialize
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: MStatus
+//
+//==============================================================================
+MStatus FenceLineNode::initialize()
+{
+ return MS::kSuccess;
+}
+
+//==============================================================================
+// FenceLineNode::postConstructor
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//==============================================================================
+void FenceLineNode::postConstructor()
+{
+ //No moving the fenceline.
+ MPlug lPlug( thisMObject(), localPosition );
+ lPlug.setLocked( true );
+
+ MPlug wPlug( thisMObject(), worldPosition );
+ wPlug.setLocked( true );
+}
+
+//This is how you export one of these.
+//==============================================================================
+// FenceLineNode::Export
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ( MObject& fenceNode, tlHistory& history )
+//
+// Return: tlDataChunk
+//
+//==============================================================================
+tlDataChunk* FenceLineNode::Export( MObject& fenceNode, tlHistory& history )
+{
+ //This fenceline assumes that there are fences below it.
+ MFnDagNode fnNode( fenceNode );
+
+ if ( fnNode.typeId() == FenceLineNode::id )
+ {
+ //Create a tlDataChunk and return it filled with the appropriate data.
+ tlFenceLineChunk* fenceLine = new tlFenceLineChunk;
+
+ //Go through all it's children and add them to the chunk incrementing the
+ //count.
+
+ unsigned int childCount = 0;
+ MItDag dagIt( MItDag::kDepthFirst, MFn::kLocator );
+
+ MFnDagNode fnDag( fenceNode );
+ MObject fenceT = fnDag.parent( 0 );
+
+ dagIt.reset( fenceT );
+
+ while ( !dagIt.isDone() )
+ {
+ MFnDependencyNode fnNode( dagIt.item() );
+ MTypeId id = fnNode.typeId();
+
+ if ( id == WallLocatorNode::id )
+ {
+ //Export a wall locator;
+ tlDataChunk* newChunk = WallLocatorNode::Export( dagIt.item(), history );
+
+ //Append this to the fence line
+ fenceLine->AppendSubChunk( newChunk );
+
+ ++childCount;
+ }
+
+ dagIt.next();
+ }
+
+ if ( childCount )
+ {
+ fenceLine->SetNumWalls( childCount );
+ }
+ else
+ {
+ delete fenceLine;
+ return NULL;
+ }
+
+ return fenceLine;
+ }
+
+ assert( false );
+ return NULL;
+}
+
+//==============================================================================
+// FenceLineNode::AddWall
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ( MObject& fenceLine, MObject& wall )
+//
+// Return: void
+//
+//==============================================================================
+void FenceLineNode::AddWall( MObject& fenceLine, MObject& wall )
+{
+ //Test to make sure the fenceLine passed in is an obj, not a transform.
+ MFnDagNode fnDag( fenceLine );
+ if ( fnDag.typeId() == FenceLineNode::id )
+ {
+ MExt::AddChild( fenceLine, wall );
+ }
+ else
+ {
+ if ( fenceLine.apiType() == MFn::kTransform )
+ {
+ //We need to find the FenceLine node that is the child of this transform.
+ unsigned int childCount = fnDag.childCount();
+
+ unsigned int i;
+
+ MObject child;
+ MFnDagNode fnDagChild;
+
+ for ( i = 0; i < childCount; ++i )
+ {
+ child = fnDag.child( i );
+
+ fnDagChild.setObject( child );
+
+ if ( fnDagChild.typeId() == FenceLineNode::id )
+ {
+ //This is the child.
+ MExt::AddChild( child, wall );
+ return;
+ }
+ }
+
+ MExt::DisplayError( "Tried to parent something strange to fenceLine" );
+ assert(false);
+ }
+ }
+}
+
diff --git a/tools/trackeditor/code/nodes/fenceline.h b/tools/trackeditor/code/nodes/fenceline.h
new file mode 100644
index 0000000..d174f13
--- /dev/null
+++ b/tools/trackeditor/code/nodes/fenceline.h
@@ -0,0 +1,30 @@
+#include "precompiled/PCH.h"
+
+
+#ifndef FENCELINE
+#define FENCELINE
+
+#include "main/constants.h"
+
+class tlDataChunk;
+
+class FenceLineNode : public MPxLocatorNode
+{
+public:
+ FenceLineNode();
+ ~FenceLineNode();
+
+ static void* creator();
+ static MStatus initialize();
+ virtual void postConstructor();
+
+ static void AddWall( MObject& fenceLine, MObject& wall );
+
+ //This is how you export one of these.
+ static tlDataChunk* Export( MObject& fenceNode, tlHistory& history );
+
+ static MTypeId id;
+ static const char* stringId;
+};
+
+#endif \ No newline at end of file
diff --git a/tools/trackeditor/code/nodes/intersection.cpp b/tools/trackeditor/code/nodes/intersection.cpp
new file mode 100644
index 0000000..f3dce53
--- /dev/null
+++ b/tools/trackeditor/code/nodes/intersection.cpp
@@ -0,0 +1,213 @@
+#include "precompiled/PCH.h"
+
+#include "intersection.h"
+#include "main/constants.h"
+#include "utility/glext.h"
+#include "utility/mext.h"
+#include "utility/nodehelper.h"
+
+#include "utility/transformmatrix.h"
+#include <toollib.hpp>
+
+
+MTypeId IntersectionLocatorNode::id( TEConstants::TypeIDPrefix, TEConstants::NodeIDs::Intersection );
+const char* IntersectionLocatorNode::stringId = "IntersectionLocatorNode";
+
+//Attribute
+const char* IntersectionLocatorNode::TYPE_NAME_LONG = "IntersectionType";
+const char* IntersectionLocatorNode::TYPE_NAME_SHORT = "it";
+MObject IntersectionLocatorNode::mType;
+
+const char* IntersectionLocatorNode::ROAD_LONG = "Roads";
+const char* IntersectionLocatorNode::ROAD_SHORT = "R";
+MObject IntersectionLocatorNode::mRoads;
+
+
+const int IntersectionLocatorNode::ACTIVE_COLOUR = 13;
+const int IntersectionLocatorNode::INACTIVE_COLOUR = 22;
+const float IntersectionLocatorNode::SCALE = 1.0f * TEConstants::Scale;
+
+IntersectionLocatorNode::IntersectionLocatorNode() {};
+IntersectionLocatorNode::~IntersectionLocatorNode() {};
+
+//==============================================================================
+// IntersectionLocatorNode::creator
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//==============================================================================
+void* IntersectionLocatorNode::creator()
+{
+ return new IntersectionLocatorNode();
+}
+
+//==============================================================================
+// IntersectionLocatorNode::initialize
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: MStatus
+//
+//==============================================================================
+MStatus IntersectionLocatorNode::initialize()
+{
+ MStatus status;
+ MFnTypedAttribute fnTyped;
+ MFnMessageAttribute fnMessage;
+
+ mType = fnTyped.create( TYPE_NAME_LONG, TYPE_NAME_SHORT, MFnData::kString, MObject::kNullObj, &status );
+ RETURN_STATUS_ON_FAILURE( status );
+
+ RETURN_STATUS_ON_FAILURE( addAttribute( mType ) );
+
+ mRoads = fnMessage.create( ROAD_LONG, ROAD_SHORT, &status );
+ RETURN_STATUS_ON_FAILURE( status );
+ RETURN_STATUS_ON_FAILURE( fnMessage.setReadable( false ) );
+ RETURN_STATUS_ON_FAILURE( fnMessage.setWritable( true ) );
+ RETURN_STATUS_ON_FAILURE( fnMessage.setArray( true ) );
+ RETURN_STATUS_ON_FAILURE( fnMessage.setIndexMatters( false ) );
+
+ RETURN_STATUS_ON_FAILURE( addAttribute( mRoads ) );
+
+
+ return MS::kSuccess;
+}
+
+//==============================================================================
+// IntersectionLocatorNode::postConstructor
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//==============================================================================
+void IntersectionLocatorNode::postConstructor()
+{
+}
+
+
+//==============================================================================
+// IntersectionLocatorNode::draw
+//==============================================================================
+// Description: Comment
+//
+// Parameters: draw( M3dView & view,
+// const MDagPath & path,
+// M3dView::DisplayStyle style,
+// M3dView::DisplayStatus status )
+//
+// Return: void
+//
+//==============================================================================
+void IntersectionLocatorNode::draw( M3dView & view,
+ const MDagPath & path,
+ M3dView::DisplayStyle style,
+ M3dView::DisplayStatus status )
+{
+ view.beginGL();
+ glPushAttrib( GL_CURRENT_BIT | GL_LINE_BIT | GL_POLYGON_BIT );
+
+ if ( status == M3dView::kDormant )
+ {
+ int colour = NodeHelper::OverrideNodeColour( thisMObject(), INACTIVE_COLOUR );
+
+ view.setDrawColor( colour, M3dView::kDormantColors );
+ }
+ else
+ {
+ view.setDrawColor( ACTIVE_COLOUR, M3dView::kActiveColors );
+ }
+
+ //Draw a star to represent the locator.
+ GLExt::drawI( TEConstants::Scale );
+ GLExt::drawSphere( SCALE );
+
+ glPopAttrib();
+ view.endGL();
+}
+
+//==============================================================================
+// IntersectionLocatorNode::Export
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ( MObject& intersectionLocatorNode, tlHistory& history )
+//
+// Return: tlDataChunk
+//
+//==============================================================================
+tlDataChunk* IntersectionLocatorNode::Export( MObject& intersectionLocatorNode,
+ tlHistory& history )
+{
+ MFnDagNode fnNode( intersectionLocatorNode );
+
+ if ( fnNode.typeId() == IntersectionLocatorNode::id )
+ {
+ tlIntersectionChunk* intersectionChunk = new tlIntersectionChunk;
+
+ intersectionChunk->SetName( fnNode.name().asChar() );
+
+ MPoint thisPosition;
+ MExt::GetWorldPosition( &thisPosition, intersectionLocatorNode );
+
+ tlPoint point;
+ point[0] = thisPosition[0] / TEConstants::Scale;
+ point[1] = thisPosition[1] / TEConstants::Scale;
+ point[2] = -thisPosition[2] / TEConstants::Scale; //Maya vs. P3D...
+
+ intersectionChunk->SetCentre( rmt::Vector( point ) );
+
+ //GetScale...
+ MObject transform;
+ transform = fnNode.parent( 0 );
+ MFnTransform fnTransform( transform );
+
+ MDagPath dagPath;
+ MExt::FindDagNodeByName( &dagPath, fnTransform.name() );
+ TransformMatrix tm( dagPath );
+
+ double scaleX;
+ fnTransform.findPlug( MString( "sx" ) ).getValue( scaleX );
+
+ intersectionChunk->SetRadius( (float)scaleX );
+
+ MPlug typePlug = fnNode.findPlug( mType );
+ MString type;
+ typePlug.getValue( type );
+
+ if ( MString("NoStop") == type )
+ {
+ intersectionChunk->SetType( 0 );
+ }
+ else if ( MString("NWay") == type )
+ {
+ intersectionChunk->SetType( 1 );
+ }
+ else if ( MString("FourWay") == type )
+ {
+ intersectionChunk->SetType( 2 );
+ }
+ else if ( MString("NoStopN") == type )
+ {
+ intersectionChunk->SetType( 3 );
+ }
+ else //if ( MString("NWay") == type )
+ {
+ intersectionChunk->SetType( 4 );
+ }
+
+
+ return intersectionChunk;
+ }
+
+ assert( false );
+ return NULL;
+} \ No newline at end of file
diff --git a/tools/trackeditor/code/nodes/intersection.h b/tools/trackeditor/code/nodes/intersection.h
new file mode 100644
index 0000000..fade595
--- /dev/null
+++ b/tools/trackeditor/code/nodes/intersection.h
@@ -0,0 +1,48 @@
+#include "precompiled/PCH.h"
+
+#ifndef INTERSECTION_LOCATOR
+#define INTERSECTION_LOCATOR
+
+
+#include "main/constants.h"
+
+class tlDataChunk;
+
+class IntersectionLocatorNode : public MPxLocatorNode
+{
+public:
+ IntersectionLocatorNode();
+ ~IntersectionLocatorNode();
+
+ static void* creator();
+
+ virtual void draw( M3dView& view,
+ const MDagPath& path,
+ M3dView::DisplayStyle displayStyle,
+ M3dView::DisplayStatus displayStatus
+ );
+ static MStatus initialize();
+ virtual void postConstructor();
+
+ //This is how you export one of these.
+ static tlDataChunk* Export( MObject& intersectionLocatorNode, tlHistory& history );
+
+ static const char* TYPE_NAME_LONG;
+ static const char* TYPE_NAME_SHORT;
+ static MObject mType;
+
+ static const char* ROAD_LONG;
+ static const char* ROAD_SHORT;
+ static MObject mRoads; //This is an out message to all the roads this intersection connects.
+
+ static MTypeId id;
+ static const char* stringId;
+
+private:
+
+ static const int ACTIVE_COLOUR;
+ static const int INACTIVE_COLOUR;
+ static const float SCALE;
+};
+
+#endif \ No newline at end of file
diff --git a/tools/trackeditor/code/nodes/pedpath.cpp b/tools/trackeditor/code/nodes/pedpath.cpp
new file mode 100644
index 0000000..682f004
--- /dev/null
+++ b/tools/trackeditor/code/nodes/pedpath.cpp
@@ -0,0 +1,271 @@
+#include "pedpath.h"
+#include "walllocator.h"
+#include "utility/mext.h"
+
+#include <toollib.hpp>
+
+MTypeId PedPathNode::id( TEConstants::TypeIDPrefix, TEConstants::NodeIDs::PedPath );
+const char* PedPathNode::stringId = "PedPath";
+
+//==============================================================================
+// PedPathNode::PedPathNode
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: PedPathNode
+//
+//==============================================================================
+PedPathNode::PedPathNode() {}
+
+//==============================================================================
+// PedPathNode::~PedPathNode
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: PedPathNode
+//
+//==============================================================================
+PedPathNode::~PedPathNode() {}
+
+//==============================================================================
+// PedPathNode::creator
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//==============================================================================
+void* PedPathNode::creator()
+{
+ return new PedPathNode();
+}
+
+//==============================================================================
+// PedPathNode::initialize
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: MStatus
+//
+//==============================================================================
+MStatus PedPathNode::initialize()
+{
+ return MS::kSuccess;
+}
+
+//==============================================================================
+// PedPathNode::postConstructor
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//==============================================================================
+void PedPathNode::postConstructor()
+{
+ //No moving the pedpath.
+ MPlug lPlug( thisMObject(), localPosition );
+ lPlug.setLocked( true );
+
+ MPlug wPlug( thisMObject(), worldPosition );
+ wPlug.setLocked( true );
+}
+
+//This is how you export one of these.
+//==============================================================================
+// PedPathNode::Export
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ( MObject& pedNode, tlHistory& history )
+//
+// Return: tlDataChunk
+//
+//==============================================================================
+tlDataChunk* PedPathNode::Export( MObject& pedNode, tlHistory& history )
+{
+ //This fenceline assumes that there are fences below it.
+ MFnDagNode fnNode( pedNode );
+
+ if ( fnNode.typeId() == PedPathNode::id )
+ {
+ //Create a tlDataChunk and return it filled with the appropriate data.
+ tlPedpathChunk* pedPath = new tlPedpathChunk;
+
+ //Go through all it's children and add them to the chunk incrementing the
+ //count.
+
+ unsigned int childCount = 0;
+ MItDag dagIt( MItDag::kDepthFirst, MFn::kLocator );
+
+ MFnDagNode fnDag( pedNode );
+ MObject fenceT = fnDag.parent( 0 );
+
+ dagIt.reset( fenceT );
+
+ tlDataChunk tempChunk;
+
+ while ( !dagIt.isDone() )
+ {
+ MFnDependencyNode fnNode( dagIt.item() );
+ MTypeId id = fnNode.typeId();
+
+ if ( id == WallLocatorNode::id )
+ {
+ //Export a wall locator;
+ tlWallChunk* newChunk = reinterpret_cast<tlWallChunk*>(WallLocatorNode::Export( dagIt.item(), history ));
+
+ //Append this to the fence line
+ tempChunk.AppendSubChunk( newChunk );
+
+ ++childCount;
+ }
+
+ dagIt.next();
+ }
+
+ if ( childCount )
+ {
+ tlPoint* points = new tlPoint[childCount + 1];
+
+ unsigned int i;
+// for ( i = 0; i < tempChunk.SubChunkCount(); i++ )
+// {
+// points[i] = reinterpret_cast<tlWallChunk*>(tempChunk.GetSubChunk( i ))->GetStart();
+//
+// if ( i == tempChunk.SubChunkCount() - 1 )
+// {
+// points[childCount] = reinterpret_cast<tlWallChunk*>(tempChunk.GetSubChunk( i ))->GetEnd();
+// }
+// }
+
+ //Okay, we need to order the points... If there was a split, the points will
+ //be badly ordered.
+ points[0] = reinterpret_cast<tlWallChunk*>(tempChunk.GetSubChunk( 0 ))->GetStart(); //First point is always good.
+
+ //This is the testing point for the loop below.
+ tlPoint testPoint = reinterpret_cast<tlWallChunk*>(tempChunk.GetSubChunk( 0 ))->GetEnd();
+ tempChunk.RemoveSubChunk( 0 );
+
+ unsigned int remainingChunks = childCount - 1;
+ unsigned int foundCount = 1;
+
+
+ while ( foundCount < childCount )
+ {
+ bool found = false;
+ unsigned int chunkIndex = 0;
+ for ( i = 0; i < remainingChunks; ++i )
+ {
+ if ( !found && reinterpret_cast<tlWallChunk*>(tempChunk.GetSubChunk( i ))->GetStart() == testPoint )
+ {
+ points[foundCount] = reinterpret_cast<tlWallChunk*>(tempChunk.GetSubChunk( i ))->GetStart();
+ found = true;
+ foundCount++;
+
+ //heheh
+ if ( foundCount == childCount )
+ {
+ points[foundCount] = reinterpret_cast<tlWallChunk*>(tempChunk.GetSubChunk( i ))->GetEnd();
+ foundCount++;
+ }
+
+ chunkIndex = i;
+ }
+ }
+
+ if ( found )
+ {
+ testPoint = reinterpret_cast<tlWallChunk*>(tempChunk.GetSubChunk( chunkIndex ))->GetEnd();
+
+ tempChunk.RemoveSubChunk( chunkIndex );
+ remainingChunks--;
+ }
+ else
+ {
+ MExt::DisplayError("WHOA! Big error, get Cary!!!! Looks like ped paths are screwy..");
+ break;
+ }
+ }
+
+
+
+ pedPath->SetPoints( points, childCount + 1 );
+ pedPath->SetNumPoints( childCount + 1 );
+
+ delete[] points;
+ points = NULL;
+ }
+ else
+ {
+ delete pedPath;
+ return NULL;
+ }
+
+ return pedPath;
+ }
+
+ assert( false );
+ return NULL;
+}
+
+//==============================================================================
+// PedPathNode::AddWall
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ( MObject& pedPath, MObject& wall )
+//
+// Return: void
+//
+//==============================================================================
+void PedPathNode::AddWall( MObject& pedPath, MObject& wall )
+{
+ //Test to make sure the fenceLine passed in is an obj, not a transform.
+ MFnDagNode fnDag( pedPath );
+ if ( fnDag.typeId() == PedPathNode::id )
+ {
+ MExt::AddChild( pedPath, wall );
+ }
+ else
+ {
+ if ( pedPath.apiType() == MFn::kTransform )
+ {
+ //We need to find the FenceLine node that is the child of this transform.
+ unsigned int childCount = fnDag.childCount();
+
+ unsigned int i;
+
+ MObject child;
+ MFnDagNode fnDagChild;
+
+ for ( i = 0; i < childCount; ++i )
+ {
+ child = fnDag.child( i );
+
+ fnDagChild.setObject( child );
+
+ if ( fnDagChild.typeId() == PedPathNode::id )
+ {
+ //This is the child.
+ MExt::AddChild( child, wall );
+ return;
+ }
+ }
+
+ MExt::DisplayError( "Tried to parent something strange to pedPath" );
+ assert(false);
+ }
+ }
+}
+
diff --git a/tools/trackeditor/code/nodes/pedpath.h b/tools/trackeditor/code/nodes/pedpath.h
new file mode 100644
index 0000000..be8bf48
--- /dev/null
+++ b/tools/trackeditor/code/nodes/pedpath.h
@@ -0,0 +1,30 @@
+#include "precompiled/PCH.h"
+
+
+#ifndef PED_PATH
+#define PED_PATH
+
+#include "main/constants.h"
+
+class tlDataChunk;
+
+class PedPathNode : public MPxLocatorNode
+{
+public:
+ PedPathNode();
+ ~PedPathNode();
+
+ static void* creator();
+ static MStatus initialize();
+ virtual void postConstructor();
+
+ static void AddWall( MObject& fenceLine, MObject& wall );
+
+ //This is how you export one of these.
+ static tlDataChunk* Export( MObject& fenceNode, tlHistory& history );
+
+ static MTypeId id;
+ static const char* stringId;
+};
+
+#endif //PED_PATH \ No newline at end of file
diff --git a/tools/trackeditor/code/nodes/road.cpp b/tools/trackeditor/code/nodes/road.cpp
new file mode 100644
index 0000000..c414d84
--- /dev/null
+++ b/tools/trackeditor/code/nodes/road.cpp
@@ -0,0 +1,409 @@
+#include "road.h"
+#include "utility/mext.h"
+#include "utility/transformmatrix.h"
+#include <toollib.hpp>
+
+const tlPoint MVectorTotlPoint( const MVector& vector )
+{
+ tlPoint point;
+ point[0] = vector[0];
+ point[1] = vector[1];
+ point[2] = vector[2];
+
+ return point;
+}
+
+MTypeId RoadNode::id( TEConstants::TypeIDPrefix, TEConstants::NodeIDs::Road );
+const char* RoadNode::stringId = "RoadNode";
+
+const char* RoadNode::ROAD_SEG_NAME_SHORT = "RoadSegments";
+const char* RoadNode::ROAD_SEG_NAME_LONG = "rs";
+MObject RoadNode::mRoadSegments;
+
+const char* RoadNode::INTERSECTION_START_SHORT = "is";
+const char* RoadNode::INTERSECTION_START_LONG = "IntersectionStart";
+MObject RoadNode::mIntersectionStart;
+
+const char* RoadNode::INTERSECTION_END_SHORT = "ie";
+const char* RoadNode::INTERSECTION_END_LONG = "IntersectionEnd";
+MObject RoadNode::mIntersectionEnd;
+
+const char* RoadNode::DENSITY_SHORT = "den";
+const char* RoadNode::DENSITY_LONG = "density";
+MObject RoadNode::mDensity;
+
+const char* RoadNode::SPEED_SHORT = "spd";
+const char* RoadNode::SPEED_LONG = "speed";
+MObject RoadNode::mSpeed;
+
+const char* RoadNode::DIFF_SHORT = "diff";
+const char* RoadNode::DIFF_LONG = "difficulty";
+MObject RoadNode::mDiff;
+
+const char* RoadNode::SHORTCUT_SHORT = "shct";
+const char* RoadNode::SHORTCUT_LONG = "shortCut";
+MObject RoadNode::mShortcut;
+
+
+
+//==============================================================================
+// RoadNode::RoadNode
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: RoadNode
+//
+//==============================================================================
+RoadNode::RoadNode() {}
+
+//==============================================================================
+// RoadNode::~RoadNode
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: RoadNode
+//
+//==============================================================================
+RoadNode::~RoadNode() {}
+
+//==============================================================================
+// RoadNode::creator
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//==============================================================================
+void* RoadNode::creator()
+{
+ return new RoadNode();
+}
+
+//==============================================================================
+// RoadNode::initialize
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: MStatus
+//
+//==============================================================================
+MStatus RoadNode::initialize()
+{
+ MStatus status;
+ MFnMessageAttribute fnMessage;
+
+ mRoadSegments = fnMessage.create( ROAD_SEG_NAME_LONG, ROAD_SEG_NAME_SHORT, &status );
+ RETURN_STATUS_ON_FAILURE( status );
+ RETURN_STATUS_ON_FAILURE( fnMessage.setReadable( false ) );
+ RETURN_STATUS_ON_FAILURE( fnMessage.setWritable( true ) );
+ RETURN_STATUS_ON_FAILURE( fnMessage.setArray( true ) );
+ RETURN_STATUS_ON_FAILURE( fnMessage.setIndexMatters( false ) );
+
+ RETURN_STATUS_ON_FAILURE( addAttribute( mRoadSegments ) );
+
+ mIntersectionStart = fnMessage.create( INTERSECTION_START_LONG, INTERSECTION_START_SHORT, &status );
+ RETURN_STATUS_ON_FAILURE( status );
+
+ RETURN_STATUS_ON_FAILURE( addAttribute( mIntersectionStart ) );
+
+ mIntersectionEnd = fnMessage.create( INTERSECTION_END_LONG, INTERSECTION_END_SHORT, &status );
+ RETURN_STATUS_ON_FAILURE( status );
+
+ RETURN_STATUS_ON_FAILURE( addAttribute( mIntersectionEnd ) );
+
+ MFnNumericAttribute fnNumeric;
+ mDensity = fnNumeric.create( DENSITY_LONG, DENSITY_SHORT, MFnNumericData::kInt, 5, &status );
+ RETURN_STATUS_ON_FAILURE( status );
+ RETURN_STATUS_ON_FAILURE( fnNumeric.setReadable( true ) );
+ RETURN_STATUS_ON_FAILURE( fnNumeric.setWritable( true ) );
+
+ RETURN_STATUS_ON_FAILURE( addAttribute( mDensity ) );
+
+ mSpeed = fnNumeric.create( SPEED_LONG, SPEED_SHORT, MFnNumericData::kInt, 50, &status );
+ RETURN_STATUS_ON_FAILURE( status );
+ RETURN_STATUS_ON_FAILURE( fnNumeric.setReadable( true ) );
+ RETURN_STATUS_ON_FAILURE( fnNumeric.setWritable( true ) );
+
+ RETURN_STATUS_ON_FAILURE( addAttribute( mSpeed ) );
+
+ mShortcut = fnNumeric.create( SHORTCUT_LONG, SHORTCUT_SHORT, MFnNumericData::kBoolean, false, &status );
+ RETURN_STATUS_ON_FAILURE( status );
+ RETURN_STATUS_ON_FAILURE( fnNumeric.setReadable( true ) );
+ RETURN_STATUS_ON_FAILURE( fnNumeric.setWritable( true ) );
+
+ RETURN_STATUS_ON_FAILURE( addAttribute( mShortcut ) );
+
+ mDiff = fnNumeric.create( DIFF_LONG, DIFF_SHORT, MFnNumericData::kInt, 0, &status );
+ RETURN_STATUS_ON_FAILURE( status );
+ RETURN_STATUS_ON_FAILURE( fnNumeric.setReadable( true ) );
+ RETURN_STATUS_ON_FAILURE( fnNumeric.setWritable( true ) );
+
+ RETURN_STATUS_ON_FAILURE( addAttribute( mDiff ) );
+
+
+ return MS::kSuccess;
+}
+
+//==============================================================================
+// RoadNode::postConstructor
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//==============================================================================
+void RoadNode::postConstructor()
+{
+ //No moving the road.
+ MPlug lPlug( thisMObject(), localPosition );
+ lPlug.setLocked( true );
+
+ MPlug wPlug( thisMObject(), worldPosition );
+ wPlug.setLocked( true );
+}
+
+//This is how you export one of these.
+//=============================================================================
+// RoadNode::Export
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( MObject& roadNode, tlHistory& history, tlDataChunk* outChunk )
+//
+// Return: tlDataChunk
+//
+//=============================================================================
+tlDataChunk* RoadNode::Export( MObject& roadNode, tlHistory& history, tlDataChunk* outChunk ) //I think this is hackish.
+{
+ //This fenceline assumes that there are fences below it.
+ MFnDagNode fnNode( roadNode );
+
+ if ( fnNode.typeId() == RoadNode::id )
+ {
+ MFnDependencyNode fnTempNode;
+
+ tlRoadChunk* roadChunk = new tlRoadChunk;
+
+ roadChunk->SetName( fnNode.name().asChar() );
+ roadChunk->SetType( 0 );
+
+ //Get the intersections.
+
+ //START
+ MPlug intersectionPlug = fnNode.findPlug( mIntersectionStart );
+ MPlugArray source, dest;
+ MExt::ResolveConnections( &source, &dest, intersectionPlug, AS_SOURCE );
+
+ if ( dest.length() == 0 )
+ {
+ MExt::DisplayError( "ERROR: Road %s has no start intersection!", fnNode.name().asChar() );
+ delete roadChunk;
+ return NULL;
+ }
+
+ fnTempNode.setObject( dest[0].node() );
+ roadChunk->SetStartIntersection( fnTempNode.name().asChar() );
+
+ //END
+ intersectionPlug = fnNode.findPlug( mIntersectionEnd );
+ MExt::ResolveConnections( &source, &dest, intersectionPlug, AS_SOURCE );
+
+ if ( dest.length() == 0 )
+ {
+ MExt::DisplayError( "ERROR: Road %s has no end intersection!", fnNode.name().asChar() );
+ delete roadChunk;
+ return NULL;
+ }
+
+ fnTempNode.setObject( dest[0].node() );
+ roadChunk->SetEndIntersection( fnTempNode.name().asChar() );
+
+ int density;
+ fnNode.findPlug( mDensity ).getValue( density );
+ roadChunk->SetDensity( density );
+
+ int speed;
+ fnNode.findPlug( mSpeed ).getValue( speed );
+ if ( speed > 255 || speed < 0 )
+ {
+ speed = 255; //No need to mask, but what the hell.
+ }
+
+ int diff;
+ fnNode.findPlug( mDiff ).getValue( diff );
+ if ( diff > 255 || diff < 0 )
+ {
+ diff = 255;
+ }
+
+ bool sc;
+ fnNode.findPlug( mShortcut ).getValue( sc );
+
+
+ //This works differently now.
+ //8 bits - speed
+ //8 bits - difficulty level
+ //1 bit - id Short cut
+ //15 bits - saved for later
+ const int SPEED_MASK = 0x000000FF;
+ const int DIFFIC_MASK = 0x0000FF00;
+ const int SC_MASK = 0x00010000;
+
+ roadChunk->SetSpeed( speed | ( diff << 8 ) | ( sc ? SC_MASK : 0 ) );
+
+ //New set all the road segment chunks.
+ MPlug roadSegPlug = fnNode.findPlug( mRoadSegments );
+ MExt::ResolveConnections( &source, &dest, roadSegPlug, AS_DEST );
+
+ MDagPath dagPath;
+ MPlug tempPlug;
+ tlRoadSegmentChunk* roadSegChunk = NULL;
+ tlRoadSegmentDataChunk* roadSegDataChunk = NULL;
+ unsigned int i;
+ for ( i = 0; i < source.length(); ++i )
+ {
+ //Create new tlRoadSegmentChunks
+ roadSegChunk = new tlRoadSegmentChunk;
+ roadSegDataChunk = new tlRoadSegmentDataChunk;
+
+ fnTempNode.setObject( source[ i ].node() );
+ MExt::FindDagNodeByName( &dagPath, fnTempNode.name() );
+ MFnMesh fnMesh( dagPath );
+
+ roadSegChunk->SetName( fnMesh.name().asChar() );
+ roadSegChunk->SetRoadSegmentData( fnMesh.name().asChar() );
+ roadSegDataChunk->SetName( fnMesh.name().asChar() );
+
+ tempPlug = fnMesh.findPlug( MString( "teType" ) );
+ int type;
+ tempPlug.getValue( type );
+ roadSegDataChunk->SetType( type < 0 ? 0 : type );
+
+ tempPlug = fnMesh.findPlug( MString( "teLanes" ) );
+ int lanes;
+ tempPlug.getValue( lanes );
+ roadSegDataChunk->SetNumLanes( lanes );
+
+ tempPlug = fnMesh.findPlug( MString( "teShoulder" ) );
+ bool shoulder;
+ tempPlug.getValue( shoulder );
+ roadSegDataChunk->SetHasShoulder( shoulder ? 1 : 0 );
+
+ MPointArray points;
+ fnMesh.getPoints( points, MSpace::kWorld );
+
+ //ORIGIN
+ tempPlug = fnMesh.findPlug( MString( "teOrigin" ) );
+ int origin;
+ tempPlug.getValue( origin );
+ assert( origin >= 0 );
+ MPoint orig;
+ orig[ 0 ] = points[origin][0] / TEConstants::Scale;
+ orig[ 1 ] = points[origin][1] / TEConstants::Scale;
+ orig[ 2 ] = -points[origin][2] / TEConstants::Scale;
+
+ //DIRECTION
+ tempPlug = fnMesh.findPlug( MString( "teRoad" ) );
+ int direction;
+ tempPlug.getValue( direction );
+ assert( direction >= 0 );
+ MPoint dir;
+ dir[ 0 ] = points[direction][0] / TEConstants::Scale;
+ dir[ 1 ] = points[direction][1] / TEConstants::Scale;
+ dir[ 2 ] = -points[direction][2] / TEConstants::Scale;
+
+ MVector vDir = dir - orig;
+ roadSegDataChunk->SetDirection( MVectorTotlPoint( vDir ) );
+
+ //TOP
+ tempPlug = fnMesh.findPlug( MString( "teTop" ) );
+ int top;
+ tempPlug.getValue( top );
+ assert( top >= 0 );
+ MPoint topPoint;
+ topPoint[ 0 ] = points[top][0] / TEConstants::Scale;
+ topPoint[ 1 ] = points[top][1] / TEConstants::Scale;
+ topPoint[ 2 ] = -points[top][2] / TEConstants::Scale;
+
+ MVector vTop = topPoint - orig;
+ roadSegDataChunk->SetTop( MVectorTotlPoint( vTop ) );
+
+ //BOTTOM
+ tempPlug = fnMesh.findPlug( MString( "teBottom" ) );
+ int bottom;
+ tempPlug.getValue( bottom );
+ assert( bottom >= 0 );
+ MPoint bot;
+ bot[ 0 ] = points[bottom][0] / TEConstants::Scale;
+ bot[ 1 ] = points[bottom][1] / TEConstants::Scale;
+ bot[ 2 ] = -points[bottom][2] / TEConstants::Scale;
+
+ MVector vBottom = bot - orig;
+ roadSegDataChunk->SetBottom( MVectorTotlPoint( vBottom ) );
+
+
+ //Lets to the SCALE and ROTATION of the segment.
+ MPointArray worldPoints;
+ fnMesh.getPoints( worldPoints, MSpace::kWorld );
+
+ //WORLD ORIGIN
+ MPoint worldOrig;
+ worldOrig[ 0 ] = worldPoints[origin][0] / TEConstants::Scale;
+ worldOrig[ 1 ] = worldPoints[origin][1] / TEConstants::Scale;
+ worldOrig[ 2 ] = -worldPoints[origin][2] / TEConstants::Scale;
+
+ //Get the parent transform matrix for the mesh.
+ MObject meshTransformObj = fnMesh.parent( 0 );
+ MFnTransform fnTransform( meshTransformObj );
+ MExt::FindDagNodeByName( &dagPath, fnTransform.name() );
+ TransformMatrix tm( dagPath );
+
+ tlMatrix hmatrix;
+ tm.GetHierarchyMatrixLHS( hmatrix );
+ //Make this p3d friendly...
+ hmatrix.element[3][0] /= TEConstants::Scale;
+ hmatrix.element[3][1] /= TEConstants::Scale;
+ hmatrix.element[3][2] /= TEConstants::Scale;
+
+ if ( hmatrix.element[3][0] == 0.0f &&
+ hmatrix.element[3][1] == 0.0f &&
+ hmatrix.element[3][2] == 0.0f )
+ {
+ //This could be a frozen
+ MExt::DisplayWarning( "%s could have it's transforms frozen! NOT GOOD! Forced to assume object was built at origin.", fnMesh.name().asChar() );
+
+ hmatrix.element[3][0] = worldOrig.x;
+ hmatrix.element[3][1] = worldOrig.y;
+ hmatrix.element[3][2] = worldOrig.z;
+ }
+
+ tlMatrix smatrix;
+ tm.GetScaleMatrixLHS( smatrix );
+
+ //MATRICIES
+ roadSegChunk->SetHierarchyMatrix( hmatrix );
+ roadSegChunk->SetScaleMatrix( smatrix );
+
+ //DONE
+ roadChunk->AppendSubChunk( roadSegChunk );
+
+ outChunk->AppendSubChunk( roadSegDataChunk );
+ }
+
+ return roadChunk;
+ }
+
+ assert( false );
+ return NULL;
+}
+
diff --git a/tools/trackeditor/code/nodes/road.h b/tools/trackeditor/code/nodes/road.h
new file mode 100644
index 0000000..a601433
--- /dev/null
+++ b/tools/trackeditor/code/nodes/road.h
@@ -0,0 +1,56 @@
+#include "precompiled/PCH.h"
+
+
+#ifndef ROAD_H
+#define ROAD_H
+
+#include "main/constants.h"
+
+class tlDataChunk;
+
+class RoadNode : public MPxLocatorNode
+{
+public:
+ RoadNode();
+ ~RoadNode();
+
+ static void* creator();
+ static MStatus initialize();
+ virtual void postConstructor();
+
+ //This is how you export one of these.
+ static tlDataChunk* Export( MObject& roadNode, tlHistory& history, tlDataChunk* outChunk );
+
+ static MTypeId id;
+ static const char* stringId;
+
+ static const char* ROAD_SEG_NAME_SHORT;
+ static const char* ROAD_SEG_NAME_LONG;
+ static MObject mRoadSegments;
+
+ static const char* INTERSECTION_START_SHORT;
+ static const char* INTERSECTION_START_LONG;
+ static MObject mIntersectionStart;
+
+ static const char* INTERSECTION_END_SHORT;
+ static const char* INTERSECTION_END_LONG;
+ static MObject mIntersectionEnd;
+
+ static const char* DENSITY_SHORT;
+ static const char* DENSITY_LONG;
+ static MObject mDensity;
+
+ static const char* SPEED_SHORT;
+ static const char* SPEED_LONG;
+ static MObject mSpeed;
+
+ static const char* DIFF_SHORT;
+ static const char* DIFF_LONG;
+ static MObject mDiff;
+
+ static const char* SHORTCUT_SHORT;
+ static const char* SHORTCUT_LONG;
+ static MObject mShortcut;
+};
+
+#endif \ No newline at end of file
diff --git a/tools/trackeditor/code/nodes/tiledisplay.cpp b/tools/trackeditor/code/nodes/tiledisplay.cpp
new file mode 100644
index 0000000..e26f7f9
--- /dev/null
+++ b/tools/trackeditor/code/nodes/tiledisplay.cpp
@@ -0,0 +1,212 @@
+#include "tiledisplay.h"
+#include "main/constants.h"
+#include "main/trackeditor.h"
+#include "utility/glext.h"
+#include "utility/mext.h"
+
+MTypeId TileDisplayNode::id( TEConstants::TypeIDPrefix, TEConstants::NodeIDs::TileDisplay );
+const char* TileDisplayNode::stringId = "TileDisplayNode";
+
+const int TileDisplayNode::ORIGIN_COLOUR = 10;
+const int TileDisplayNode::ROAD_COLOUR = 11;
+const int TileDisplayNode::TOP_COLOUR = 12;
+const int TileDisplayNode::BOTTOM_COLOUR = 13;
+const int TileDisplayNode::LANE_COLOUR = 4;
+const float TileDisplayNode::SCALE = 1.0f * TEConstants::Scale;
+const float TileDisplayNode::LINE_WIDTH = 6.0f;
+const float TileDisplayNode::Y_OFFSET = 0.5f;
+
+TileDisplayNode::TileDisplayNode() {};
+
+TileDisplayNode::~TileDisplayNode() {};
+
+//==============================================================================
+// TileDisplayNode::creator
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//==============================================================================
+void* TileDisplayNode::creator()
+{
+ return new TileDisplayNode();
+}
+//==============================================================================
+// TileDisplayNode::draw
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ( M3dView& view,
+// const MDagPath& path,
+// M3dView::DisplayStyle displayStyle,
+// M3dView::DisplayStatus displayStatus )
+//
+//
+// Return: void
+//
+//==============================================================================
+void TileDisplayNode::draw( M3dView& view,
+ const MDagPath& path,
+ M3dView::DisplayStyle displayStyle,
+ M3dView::DisplayStatus displayStatus
+ )
+{
+ if ( TrackEditor::GetEditMode() != TrackEditor::OFF )
+ {
+ //Display the arrows for the selected mesh.
+ MStatus status;
+ MSelectionList activeList;
+ MGlobal::getActiveSelectionList(activeList);
+
+ MItSelectionList iter( activeList, MFn::kMesh, &status);
+
+ unsigned int count = activeList.length();
+
+ //Draw
+ view.beginGL();
+ glPushAttrib( GL_CURRENT_BIT | GL_LINE_BIT | GL_POLYGON_BIT );
+
+ while ( !iter.isDone() )
+ {
+ MDagPath meshDagPath;
+ iter.getDagPath( meshDagPath );
+
+ MFnMesh fnMesh( meshDagPath );
+
+ MPlug teOriginPlug = fnMesh.findPlug( MString("teOrigin"), &status );
+
+ if ( status == MStatus::kSuccess )
+ {
+ //This is a mesh of the appropriate type
+ //Get all the vertices that are set and display arrows for them.
+ int originVert;
+ teOriginPlug.getValue( originVert );
+
+ int roadVert;
+ MPlug teRoadPlug = fnMesh.findPlug( MString("teRoad"), &status );
+ assert( status );
+ teRoadPlug.getValue( roadVert );
+
+ int topVert;
+ MPlug teTopPlug = fnMesh.findPlug( MString("teTop"), &status );
+ assert( status );
+ teTopPlug.getValue( topVert );
+
+ int bottomVert;
+ MPlug teBottomPlug = fnMesh.findPlug( MString("teBottom"), &status );
+ assert( status );
+ teBottomPlug.getValue( bottomVert );
+
+ int numLanes;
+ MPlug teLanesPlug = fnMesh.findPlug( MString("teLanes"), &status );
+ assert( status );
+ teLanesPlug.getValue( numLanes );
+
+ if ( numLanes < 1 )
+ {
+ MExt::DisplayError( "The mesh %s has a road with no lanes!", fnMesh.name().asChar() );
+ }
+
+ MPoint teOriginPoint;
+ fnMesh.getPoint( originVert, teOriginPoint, MSpace::kWorld );
+ teOriginPoint[1] += Y_OFFSET;
+
+ MPoint teRoadPoint;
+ fnMesh.getPoint( roadVert, teRoadPoint, MSpace::kWorld );
+ teRoadPoint[1] += Y_OFFSET;
+
+ MPoint teTopPoint;
+ fnMesh.getPoint( topVert, teTopPoint, MSpace::kWorld );
+ teTopPoint[1] += Y_OFFSET;
+
+ MPoint teBottomPoint;
+ fnMesh.getPoint( bottomVert, teBottomPoint, MSpace::kWorld );
+ teBottomPoint[1] += Y_OFFSET;
+
+ //When we are in render mode, we draw the lines.
+ //If this was in GL_SELECTION_MODE, we would not draw the lines, so they won't interfere
+ //with selection.
+ GLint value;
+ glGetIntegerv( GL_RENDER_MODE, &value );
+
+ if ( (value == GL_RENDER) )
+ {
+ if ( originVert >= 0 )
+ {
+ view.setDrawColor( ORIGIN_COLOUR, M3dView::kActiveColors );
+ GLExt::drawSphere( 0.5f * SCALE, teOriginPoint );
+ }
+
+ if ( roadVert >= 0 )
+ {
+ view.setDrawColor( ROAD_COLOUR, M3dView::kActiveColors );
+ GLExt::drawSphere( 0.5f * SCALE, teRoadPoint );
+ GLExt::drawLine( teOriginPoint, teRoadPoint, LINE_WIDTH );
+ }
+
+ if ( topVert >= 0 )
+ {
+ view.setDrawColor( TOP_COLOUR, M3dView::kActiveColors );
+ GLExt::drawSphere( 0.5f * SCALE, teTopPoint );
+ GLExt::drawLine( teRoadPoint, teTopPoint, LINE_WIDTH );
+ }
+
+ if ( bottomVert >= 0 )
+ {
+ view.setDrawColor( BOTTOM_COLOUR, M3dView::kActiveColors );
+ GLExt::drawSphere( 0.5f * SCALE, teBottomPoint );
+ GLExt::drawLine( teOriginPoint, teBottomPoint, LINE_WIDTH );
+ }
+
+ if ( numLanes > 0 )
+ {
+ MVector scaledVector0, scaledVector1;
+ scaledVector0 = teBottomPoint - teOriginPoint;
+ scaledVector0 /= numLanes;
+ scaledVector0 /= 2;
+
+ scaledVector1 = teTopPoint - teRoadPoint;
+ scaledVector1 /= numLanes;
+ scaledVector1 /= 2;
+
+ unsigned int i;
+ for( i = 0; i < numLanes; ++i )
+ {
+ MPoint p0, p1;
+
+ p0 = teOriginPoint + scaledVector0 + (scaledVector0 * i * 2);
+ p1 = teRoadPoint + scaledVector1 + (scaledVector1 * i * 2);
+
+ view.setDrawColor( LANE_COLOUR, M3dView::kActiveColors );
+ GLExt::drawArrow( p0, p1, LINE_WIDTH );
+ }
+ }
+ }
+ }
+
+ iter.next();
+ }
+
+ glPopAttrib();
+ view.endGL();
+ }
+}
+
+//==============================================================================
+// TileDisplayNode::initialize
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: MStatus
+//
+//==============================================================================
+MStatus TileDisplayNode::initialize()
+{
+ return MStatus::kSuccess;
+}
+
diff --git a/tools/trackeditor/code/nodes/tiledisplay.h b/tools/trackeditor/code/nodes/tiledisplay.h
new file mode 100644
index 0000000..631778a
--- /dev/null
+++ b/tools/trackeditor/code/nodes/tiledisplay.h
@@ -0,0 +1,35 @@
+#include "precompiled/PCH.h"
+
+
+#ifndef TILE_DSIPLAY_H
+#define TILE_DSIPLAY_H
+
+class TileDisplayNode : public MPxLocatorNode
+{
+public:
+ TileDisplayNode();
+ ~TileDisplayNode();
+
+ static void* creator();
+ virtual void draw( M3dView& view,
+ const MDagPath& path,
+ M3dView::DisplayStyle displayStyle,
+ M3dView::DisplayStatus displayStatus
+ );
+ static MStatus initialize();
+
+ static MTypeId id;
+ static const char* stringId;
+
+private:
+ static const int ORIGIN_COLOUR;
+ static const int ROAD_COLOUR;
+ static const int TOP_COLOUR;
+ static const int BOTTOM_COLOUR;
+ static const int LANE_COLOUR;
+ static const float SCALE;
+ static const float LINE_WIDTH;
+ static const float Y_OFFSET;
+};
+
+#endif \ No newline at end of file
diff --git a/tools/trackeditor/code/nodes/treelineshapenode.cpp b/tools/trackeditor/code/nodes/treelineshapenode.cpp
new file mode 100644
index 0000000..701ab9c
--- /dev/null
+++ b/tools/trackeditor/code/nodes/treelineshapenode.cpp
@@ -0,0 +1,1343 @@
+#include <windows.h>
+#include <GL/glu.h>
+
+#include <math.h>
+
+#include <radmath/radmath.hpp>
+
+#include "nodes/treelineshapenode.h"
+#include "utility/mext.h"
+#include "utility/mui.h"
+#include "main/shapeconstants.h"
+#include "main/constants.h"
+#include "main/trackeditor.h"
+
+namespace TETreeLine
+{
+
+#define DORMANT_VERTEX_COLOR 8 // purple
+#define ACTIVE_VERTEX_COLOR 16 // yellow
+
+// Vertex point size
+//
+#define POINT_SIZE 2.0
+
+void SetQuadricDrawStyle (GLUquadricObj* qobj, int token)
+{
+ if ((token==SMOOTH_SHADED)||(token==FLAT_SHADED))
+ {
+ gluQuadricNormals( qobj, GLU_SMOOTH );
+ gluQuadricTexture( qobj, true );
+ gluQuadricDrawStyle( qobj, GLU_FILL );
+ }
+ else
+ {
+ gluQuadricDrawStyle( qobj, GLU_LINE );
+ }
+}
+
+void p3dBaseShapeUI::getDrawRequestsWireframe( MDrawRequest& request, const MDrawInfo& info )
+{
+ request.setToken( WIREFRAME );
+
+ M3dView::DisplayStatus displayStatus = info.displayStatus();
+ M3dView::ColorTable activeColorTable = M3dView::kActiveColors;
+ M3dView::ColorTable dormantColorTable = M3dView::kDormantColors;
+ switch ( displayStatus )
+ {
+ case M3dView::kLead :
+ request.setColor( lead_color, activeColorTable );
+ break;
+ case M3dView::kActive :
+ request.setColor( active_color, activeColorTable );
+ break;
+ case M3dView::kActiveAffected :
+ request.setColor( active_affected_color, activeColorTable );
+ break;
+ case M3dView::kDormant :
+ request.setColor( dormant_color, dormantColorTable );
+ break;
+ case M3dView::kHilite :
+ request.setColor( hilite_color, activeColorTable );
+ break;
+ }
+}
+
+void p3dBaseShapeUI::getDrawRequestsShaded( MDrawRequest& request, const MDrawInfo& info,
+ MDrawRequestQueue& queue, MDrawData& data )
+{
+ // Need to get the material info
+ //
+ MDagPath path = info.multiPath(); // path to your dag object
+ M3dView view = info.view();; // view to draw to
+ MMaterial material = MPxSurfaceShapeUI::material( path );
+ M3dView::DisplayStatus displayStatus = info.displayStatus();
+
+ // Evaluate the material and if necessary, the texture.
+ //
+ if ( ! material.evaluateMaterial( view, path ) )
+ {
+ MExt::DisplayError( "Could not evaluate\n" );
+ }
+
+ if ( material.materialIsTextured() )
+ {
+ material.evaluateTexture( data );
+ }
+
+ request.setMaterial( material );
+
+ bool materialTransparent = false;
+ material.getHasTransparency( materialTransparent );
+ if ( materialTransparent )
+ {
+ request.setIsTransparent( true );
+ }
+
+ // create a draw request for wireframe on shaded if
+ // necessary.
+ //
+ if ( (displayStatus == M3dView::kActive) ||
+ (displayStatus == M3dView::kLead) ||
+ (displayStatus == M3dView::kHilite) )
+ {
+ MDrawRequest wireRequest = info.getPrototype( *this );
+ wireRequest.setDrawData( data );
+ getDrawRequestsWireframe( wireRequest, info );
+ wireRequest.setToken( WIREFRAME_SHADED );
+ wireRequest.setDisplayStyle( M3dView::kWireFrame );
+ queue.add( wireRequest );
+ }
+}
+
+/////////////////////////////////////////////////////////////////////
+// SHAPE NODE IMPLEMENTATION
+/////////////////////////////////////////////////////////////////////
+MTypeId TreelineShapeNode::id(TEConstants::NodeIDs::TreeLine);
+const char* TreelineShapeNode::stringId = "TreelineShapeNode";
+
+const char* TreelineShapeNode::SHADER_NAME_LONG = "material";
+const char* TreelineShapeNode::SHADER_NAME_SHORT = "mt";
+MObject TreelineShapeNode::sShader;
+
+const char* TreelineShapeNode::USCALE_NAME_LONG = "uscale";
+const char* TreelineShapeNode::USCALE_NAME_SHORT = "us";
+MObject TreelineShapeNode::sUScale;
+
+const char* TreelineShapeNode::COLOUR_NAME_LONG = "colour";
+const char* TreelineShapeNode::COLOUR_NAME_SHORT = "clr";
+MObject TreelineShapeNode::sColour;
+
+const char* TreelineShapeNode::RED_NAME_LONG = "red";
+const char* TreelineShapeNode::RED_NAME_SHORT = "r";
+MObject TreelineShapeNode::sRed;
+
+const char* TreelineShapeNode::GREEN_NAME_LONG = "green";
+const char* TreelineShapeNode::GREEN_NAME_SHORT = "g";
+MObject TreelineShapeNode::sGreen;
+
+const char* TreelineShapeNode::BLUE_NAME_LONG = "blue";
+const char* TreelineShapeNode::BLUE_NAME_SHORT = "b";
+MObject TreelineShapeNode::sBlue;
+
+const char* TreelineShapeNode::ALPHA_NAME_LONG = "alpha";
+const char* TreelineShapeNode::ALPHA_NAME_SHORT = "a";
+MObject TreelineShapeNode::sAlpha;
+
+const char* TreelineShapeNode::HEIGHT_NAME_LONG = "height";
+const char* TreelineShapeNode::HEIGHT_NAME_SHORT = "h";
+MObject TreelineShapeNode::sHeight;
+
+TreelineShapeNode::TreelineShapeNode()
+{
+}
+
+TreelineShapeNode::~TreelineShapeNode()
+{
+}
+
+//********************************************************************************************
+// Description
+//
+// When instances of this node are created internally, the MObject associated
+// with the instance is not created until after the constructor of this class
+// is called. This means that no member functions of MPxSurfaceShape can
+// be called in the constructor.
+// The postConstructor solves this problem. Maya will call this function
+// after the internal object has been created.
+// As a general rule do all of your initialization in the postConstructor.
+//********************************************************************************************
+void TreelineShapeNode::postConstructor()
+{
+ // This call allows the shape to have shading groups assigned
+ setRenderable( true );
+}
+
+//********************************************************************************************
+// Compute attribute values of the node
+//********************************************************************************************
+MStatus TreelineShapeNode::compute( const MPlug& plug, MDataBlock& datablock )
+{
+ return MS::kSuccess;
+}
+
+//********************************************************************************************
+// Capture when connections are made to this shape
+//********************************************************************************************
+MStatus TreelineShapeNode::connectionMade ( const MPlug &plug, const MPlug &otherPlug, bool asSrc )
+{
+ MObject shaderObj = otherPlug.node();
+ if ( asSrc && shaderObj.hasFn(MFn::kShadingEngine) )
+ {
+ MFnDependencyNode parentFn( plug.node() );
+ MFnDependencyNode shaderFn( shaderObj );
+
+ // connect this material with the chosen object
+
+ MStatus status;
+ MPlug parentMaterialPlug = parentFn.findPlug( SHADER_NAME_LONG, &status );
+
+ if ( !status )
+ {
+ MExt::DisplayError( "Could not assign %s to %s", shaderFn.name(), parentFn.name() );
+ }
+ else
+ {
+ parentMaterialPlug.setLocked( false );
+ parentMaterialPlug.setValue( shaderFn.name() );
+ parentMaterialPlug.setLocked( true );
+ }
+ }
+
+ // let Maya process the connection too
+ return MS::kUnknownParameter;
+}
+
+//********************************************************************************************
+// Create instance of shape
+//********************************************************************************************
+void* TreelineShapeNode::creator()
+{
+ return new TreelineShapeNode();
+}
+
+//********************************************************************************************
+// Create and initialize all attributes in maya
+//********************************************************************************************
+MStatus TreelineShapeNode::initialize()
+{
+ MStatus status;
+ MFnTypedAttribute strAttr;
+ MFnNumericAttribute numAttr;
+ MFnCompoundAttribute compAttr;
+
+ sShader = strAttr.create( SHADER_NAME_LONG, SHADER_NAME_SHORT, MFnData::kString, &status );
+ RETURN_STATUS_ON_FAILURE( status );
+ RETURN_STATUS_ON_FAILURE( strAttr.setInternal( false ) );
+ RETURN_STATUS_ON_FAILURE( strAttr.setHidden( false ) );
+ RETURN_STATUS_ON_FAILURE( strAttr.setKeyable( false ) );
+ status = addAttribute( sShader );
+ RETURN_STATUS_ON_FAILURE( status );
+
+ sUScale = numAttr.create( USCALE_NAME_LONG, USCALE_NAME_SHORT, MFnNumericData::kDouble, 1.0, &status );
+ RETURN_STATUS_ON_FAILURE( status );
+ RETURN_STATUS_ON_FAILURE( numAttr.setMin(0.01) );
+ RETURN_STATUS_ON_FAILURE( numAttr.setMax(100.0) );
+ RETURN_STATUS_ON_FAILURE( strAttr.setInternal( false ) );
+ RETURN_STATUS_ON_FAILURE( strAttr.setHidden( false ) );
+ RETURN_STATUS_ON_FAILURE( strAttr.setKeyable( true ) );
+ status = addAttribute( sUScale );
+ RETURN_STATUS_ON_FAILURE( status );
+
+ // Compound colour attribute
+ sRed = numAttr.create ( RED_NAME_LONG, RED_NAME_SHORT, MFnNumericData::kFloat, 1.0, &status );
+ RETURN_STATUS_ON_FAILURE( status );
+ RETURN_STATUS_ON_FAILURE( numAttr.setMin(0.0) );
+ RETURN_STATUS_ON_FAILURE( numAttr.setMax(1.0) );
+ RETURN_STATUS_ON_FAILURE( numAttr.setHidden( false ) );
+ RETURN_STATUS_ON_FAILURE( numAttr.setKeyable( true ) );
+
+ sGreen = numAttr.create ( GREEN_NAME_LONG, GREEN_NAME_SHORT, MFnNumericData::kFloat, 1.0, &status );
+ RETURN_STATUS_ON_FAILURE( status );
+ RETURN_STATUS_ON_FAILURE( numAttr.setMin(0.0) );
+ RETURN_STATUS_ON_FAILURE( numAttr.setMax(1.0) );
+ RETURN_STATUS_ON_FAILURE( numAttr.setHidden( false ) );
+ RETURN_STATUS_ON_FAILURE( numAttr.setKeyable( true ) );
+
+ sBlue = numAttr.create ( BLUE_NAME_LONG, BLUE_NAME_SHORT, MFnNumericData::kFloat, 1.0, &status );
+ RETURN_STATUS_ON_FAILURE( status );
+ RETURN_STATUS_ON_FAILURE( numAttr.setMin(0.0) );
+ RETURN_STATUS_ON_FAILURE( numAttr.setMax(1.0) );
+ RETURN_STATUS_ON_FAILURE( numAttr.setHidden( false ) );
+ RETURN_STATUS_ON_FAILURE( numAttr.setKeyable( true ) );
+
+ sColour = numAttr.create( COLOUR_NAME_LONG, COLOUR_NAME_SHORT, sRed, sGreen, sBlue, &status );
+ RETURN_STATUS_ON_FAILURE( status );
+ RETURN_STATUS_ON_FAILURE( numAttr.setKeyable( true ) );
+ RETURN_STATUS_ON_FAILURE( numAttr.setUsedAsColor(true) );
+ status = addAttribute( sColour );
+ RETURN_STATUS_ON_FAILURE( status );
+
+ sAlpha = numAttr.create ( ALPHA_NAME_LONG, ALPHA_NAME_SHORT, MFnNumericData::kFloat, 1.0, &status );
+ RETURN_STATUS_ON_FAILURE( status );
+ RETURN_STATUS_ON_FAILURE( numAttr.setMin(0.0) );
+ RETURN_STATUS_ON_FAILURE( numAttr.setMax(1.0) );
+ RETURN_STATUS_ON_FAILURE( numAttr.setInternal( false ) );
+ RETURN_STATUS_ON_FAILURE( numAttr.setHidden( false ) );
+ RETURN_STATUS_ON_FAILURE( numAttr.setKeyable( true ) );
+ status = addAttribute( sAlpha );
+ RETURN_STATUS_ON_FAILURE( status );
+
+
+ sHeight = numAttr.create( HEIGHT_NAME_LONG, HEIGHT_NAME_SHORT, MFnNumericData::kFloat, 10.0, &status );
+ RETURN_STATUS_ON_FAILURE( status );
+ RETURN_STATUS_ON_FAILURE( numAttr.setMin(0.1) );
+ RETURN_STATUS_ON_FAILURE( numAttr.setMax(100.0) );
+ RETURN_STATUS_ON_FAILURE( numAttr.setInternal( false ) );
+ RETURN_STATUS_ON_FAILURE( numAttr.setHidden( false ) );
+ RETURN_STATUS_ON_FAILURE( numAttr.setKeyable( true ) );
+ status = addAttribute( sHeight );
+
+ return MS::kSuccess;
+}
+
+//********************************************************************************************
+// Returns the bounding box for the shape.
+// In this case just use the radius and height attributes
+// to determine the bounding box.
+//********************************************************************************************
+MBoundingBox TreelineShapeNode::boundingBox() const
+{
+ MBoundingBox result;
+
+ MStatus status;
+ MObject obj = thisMObject();
+
+ float height = 1.0f;
+
+ MFnDagNode dagNodeFn(obj);
+ MPlug plug;
+
+ plug = dagNodeFn.findPlug( sHeight, &status );
+ plug.getValue( height );
+
+ MPlug vertices = dagNodeFn.findPlug( mControlPoints, &status );
+ assert( status );
+
+ unsigned int i;
+ for ( i = 0; i < vertices.numElements(); ++i )
+ {
+ MPoint point;
+ MPlug vertex1 = vertices.elementByLogicalIndex( i, &status );
+ assert( status );
+
+ MPlug x1 = vertex1.child( mControlValueX, &status );
+ assert( status );
+ x1.getValue( point.x );
+
+ MPlug y1 = vertex1.child( mControlValueY, &status );
+ assert( status );
+ y1.getValue( point.y );
+
+ MPlug z1 = vertex1.child( mControlValueZ, &status );
+ assert( status );
+ z1.getValue( point.z );
+
+ result.expand( point );
+
+ point.y = point.y + ( height * TEConstants::Scale );
+
+ result.expand( point );
+ }
+
+ return result;
+}
+
+//=============================================================================
+// TreelineShapeNode::componentToPlugs
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( MObject& component, MSelectionList& selectionList )
+//
+// Return: void
+//
+//=============================================================================
+void TreelineShapeNode::componentToPlugs( MObject& component,
+ MSelectionList& selectionList ) const
+{
+ if ( component.hasFn(MFn::kMeshVertComponent) )
+ {
+ MFnSingleIndexedComponent fnVtxComp( component );
+ MObject thisNode = thisMObject();
+ MPlug plug( thisNode, mControlPoints );
+ int len = fnVtxComp.elementCount();
+ for ( int i = 0; i < len; i++ )
+ {
+ MPlug vtxPlug = plug.elementByLogicalIndex( fnVtxComp.element(i) );
+ selectionList.add( vtxPlug );
+ }
+ }
+}
+
+//=============================================================================
+// TreelineShapeNode::matchComponent
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( const MSelectionList& item, const MAttributeSpecArray& spec, MSelectionList& list )
+//
+// Return: MPxSurfaceShape
+//
+//=============================================================================
+MPxSurfaceShape::MatchResult
+TreelineShapeNode::matchComponent( const MSelectionList& item,
+ const MAttributeSpecArray& spec,
+ MSelectionList& list )
+//
+// Description:
+//
+// Component/attribute matching method.
+// This method validates component names and indices which are
+// specified as a string and adds the corresponding component
+// to the passed in selection list.
+//
+// For instance, select commands such as "select shape1.vtx[0:7]"
+// are validated with this method and the corresponding component
+// is added to the selection list.
+//
+// Arguments
+//
+// item - DAG selection item for the object being matched
+// spec - attribute specification object
+// list - list to add components to
+//
+// Returns
+//
+// the result of the match
+//
+{
+ MPxSurfaceShape::MatchResult result = MPxSurfaceShape::kMatchOk;
+ MAttributeSpec attrSpec = spec[0];
+ int dim = attrSpec.dimensions();
+
+ // Look for attributes specifications of the form :
+ // vtx[ index ]
+ // vtx[ lower:upper ]
+ //
+ if ( (1 == spec.length()) &&
+ (dim > 0) &&
+ (attrSpec.name() == "controlPoints" ) )
+ {
+ MObject node;
+ item.getDependNode( 0, node );
+ MFnDependencyNode fnDepNode( node );
+ int numVertices = fnDepNode.findPlug( mControlPoints ).numElements();
+ MAttributeIndex attrIndex = attrSpec[0];
+
+ int upper = 0;
+ int lower = 0;
+ if ( attrIndex.hasLowerBound() ) {
+ attrIndex.getLower( lower );
+ }
+ if ( attrIndex.hasUpperBound() ) {
+ attrIndex.getUpper( upper );
+ }
+
+ // Check the attribute index range is valid
+ //
+ if ( (lower > upper) || (upper >= numVertices) ) {
+ result = MPxSurfaceShape::kMatchInvalidAttributeRange;
+ }
+ else {
+ MDagPath path;
+ item.getDagPath( 0, path );
+ MFnSingleIndexedComponent fnVtxComp;
+ MObject vtxComp = fnVtxComp.create( MFn::kMeshVertComponent );
+
+ for ( int i=lower; i<=upper; i++ )
+ {
+ fnVtxComp.addElement( i );
+ }
+ list.add( path, vtxComp );
+ }
+ }
+ else {
+ // Pass this to the parent class
+ return MPxSurfaceShape::matchComponent( item, spec, list );
+ }
+
+ return result;
+}
+
+//=============================================================================
+// TreelineShapeNode::match
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( const MSelectionMask & mask, const MObjectArray& componentList )
+//
+// Return: bool
+//
+//=============================================================================
+bool TreelineShapeNode::match( const MSelectionMask & mask, const MObjectArray& componentList ) const
+//
+// Description:
+//
+// Check for matches between selection type / component list, and
+// the type of this shape / or it's components
+//
+// This is used by sets and deformers to make sure that the selected
+// components fall into the "vertex only" category.
+//
+// Arguments
+//
+// mask - selection type mask
+// componentList - possible component list
+//
+// Returns
+// true if matched any
+//
+{
+ bool result = false;
+
+ if( componentList.length() == 0 ) {
+ result = mask.intersects( MSelectionMask::kSelectMeshes );
+ }
+ else
+ {
+ for ( int i=0; i<(int)componentList.length(); i++ )
+ {
+ if ( (componentList[i].apiType() == MFn::kMeshVertComponent) &&
+ (mask.intersects(MSelectionMask::kSelectMeshVerts))
+ )
+ {
+ result = true;
+ break;
+ }
+ }
+ }
+
+ return result;
+}
+
+//=============================================================================
+// TreelineShapeNode::transformUsing
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( const MMatrix & mat, const MObjectArray & componentList )
+//
+// Return: void
+//
+//=============================================================================
+void TreelineShapeNode::transformUsing( const MMatrix & mat,
+ const MObjectArray & componentList )
+//
+// Description
+//
+// Transforms the given components. This method is used by
+// the move, rotate, and scale tools in component mode.
+// Bounding box has to be updated here, so do the normals and
+// any other attributes that depend on vertex positions.
+//
+// Arguments
+//
+// mat - matrix to tranform the components by
+// componentList - list of components to be transformed
+//
+{
+ MStatus stat;
+
+ MFnDependencyNode fnDepNode( thisMObject() );
+ MPlug vertices = fnDepNode.findPlug( mControlPoints );
+
+ int len = componentList.length();
+ int i;
+ for ( i=0; i<len; i++ )
+ {
+ MObject comp = componentList[i];
+ MFnSingleIndexedComponent fnComp( comp );
+ int elemCount = fnComp.elementCount();
+ for ( int idx=0; idx<elemCount; idx++ )
+ {
+ int elemIndex = fnComp.element( idx );
+ MPlug vertex = vertices.elementByLogicalIndex( elemIndex );
+
+ MPoint point;
+ vertex.child(0).getValue( point.x );
+ vertex.child(1).getValue( point.y );
+ vertex.child(2).getValue( point.z );
+
+ point *= mat;
+
+ vertex.child(0).setValue( point.x );
+ vertex.child(1).setValue( point.y );
+ vertex.child(2).setValue( point.z );
+ }
+ }
+
+ // Moving vertices will likely change the bounding box.
+ //
+
+ // Tell maya the bounding box for this object has changed
+ // and thus "boundingBox()" needs to be called.
+ //
+ childChanged( MPxSurfaceShape::kBoundingBoxChanged );
+}
+
+//=============================================================================
+// TreelineShapeNode::closestPoint
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( const MPoint & toThisPoint, MPoint & theClosestPoint, double tolerance )
+//
+// Return: void
+//
+//=============================================================================
+void TreelineShapeNode::closestPoint ( const MPoint& toThisPoint,
+ MPoint& theClosestPoint,
+ double tolerance )
+{
+ MStatus stat;
+
+ MFnDependencyNode fnDepNode( thisMObject() );
+ MPlug vertices = fnDepNode.findPlug( mControlPoints );
+
+ bool found = false;
+ double dist = 10000000.0;
+
+ unsigned int i;
+ for ( i = 0; i < vertices.numElements(); ++i )
+ {
+ MPlug vertex = vertices.elementByLogicalIndex( i );
+ MPoint point;
+
+ vertex.child( 0 ).getValue( point.x );
+ vertex.child( 1 ).getValue( point.y );
+ vertex.child( 2 ).getValue( point.z );
+
+ if ( point.distanceTo( toThisPoint ) < dist )
+ {
+ dist = point.distanceTo( toThisPoint );
+ theClosestPoint = point;
+ }
+ }
+}
+
+//=============================================================================
+// TreelineShapeNode::SnapTreeline
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( MObject& treeline )
+//
+// Return: void
+//
+//=============================================================================
+void TreelineShapeNode::SnapTreeline( MObject& treeline )
+{
+ MFnDependencyNode fnDepNode( treeline );
+
+ MPlug vertices = fnDepNode.findPlug( mControlPoints );
+
+ unsigned int i;
+
+ for ( i = 0; i < vertices.numElements(); ++i )
+ {
+ MPlug vertex = vertices.elementByLogicalIndex( i );
+
+ MPoint point;
+
+ vertex.child( 0 ).getValue( point.x );
+ vertex.child( 1 ).getValue( point.y );
+ vertex.child( 2 ).getValue( point.z );
+
+ MPoint intersectPoint;
+ //Look down...
+ if ( MExt::MeshIntersectAlongVector( point, MPoint(0, -100000.0, 0 ), intersectPoint ) )
+ {
+ vertex.child( 0 ).setValue( intersectPoint.x );
+ vertex.child( 1 ).setValue( intersectPoint.y );
+ vertex.child( 2 ).setValue( intersectPoint.z );
+ }
+ else
+ {
+ //Try looking up...
+ if ( MExt::MeshIntersectAlongVector( point, MPoint(0, 100000.0, 0 ), intersectPoint ) )
+ {
+ vertex.child( 0 ).setValue( intersectPoint.x );
+ vertex.child( 1 ).setValue( intersectPoint.y );
+ vertex.child( 2 ).setValue( intersectPoint.z );
+ }
+ }
+ }
+}
+
+void TreelineShapeNode::ConvertToGeometry( MObject& obj )
+{
+ MFnMesh newMesh;
+ MObject newMeshObj;
+
+ MFnDependencyNode fnDepNode( obj );
+ MPlug vertices = fnDepNode.findPlug( mControlPoints );
+
+ if ( vertices.numElements() >= 2 )
+ {
+ double height;
+ fnDepNode.findPlug( sHeight ).getValue( height );
+
+ double uScale;
+ fnDepNode.findPlug( sUScale).getValue( uScale );
+
+ MFloatArray uArray, vArray;
+ MIntArray uvCounts, uvIds;
+
+ unsigned int i = 0;
+ unsigned int j = 0;
+ do
+ {
+ //Create the new mesh...
+ MPointArray points;
+ MPoint point1, point2, point3, point4;
+
+ MPlug vertex1 = vertices.elementByLogicalIndex( i );
+ vertex1.child(0).getValue( point1.x );
+ vertex1.child(1).getValue( point1.y );
+ vertex1.child(2).getValue( point1.z );
+
+ point2 = point1;
+ point1.y += height * TEConstants::Scale;
+
+ points.append( point1 );
+ points.append( point2 );
+
+ MPlug vertex2 = vertices.elementByLogicalIndex( i + 1 );
+ vertex2.child(0).getValue( point3.x );
+ vertex2.child(1).getValue( point3.y );
+ vertex2.child(2).getValue( point3.z );
+
+ point4 = point3;
+ point4.y += height * TEConstants::Scale;
+
+ points.append( point3 );
+ points.append( point4 );
+
+ newMeshObj = newMesh.addPolygon( points );
+
+ double dist = point2.distanceTo( point3 );
+
+ float U = ceil( dist / (uScale * TEConstants::Scale ) );
+
+ uArray.append( 0 );
+ uArray.append( 0 );
+ uArray.append( U );
+ uArray.append( U );
+
+ vArray.append( 1 );
+ vArray.append( 0 );
+ vArray.append( 0 );
+ vArray.append( 1 );
+
+ uvCounts.append( 4 );
+
+ uvIds.append( 0 + j );
+ uvIds.append( 1 + j );
+ uvIds.append( 2 + j );
+ uvIds.append( 3 + j );
+
+ ++i;
+ j += 4;
+ }
+ while ( i < vertices.numElements() - 1 );
+
+ MString material;
+ fnDepNode.findPlug( sShader ).getValue( material );
+
+ if ( material.length() > 0 )
+ {
+ //Set the material to the new object.
+
+ newMesh.setUVs( uArray, vArray );
+ newMesh.assignUVs( uvCounts, uvIds );
+
+ //MEL command for assigning the texture.
+ //sets -e -forceElement pure3dSimpleShader1SG polySurface1;
+ MString meshName = newMesh.name();
+
+ MString cmd;
+
+ cmd += MString("sets -e -forceElement ") + material + MString(" ") + meshName;
+
+ MStatus status;
+ MGlobal::executeCommand( cmd, status );
+ }
+ }
+ else
+ {
+ assert(false);
+ MExt::DisplayError( "Treeline: %s is invalid for converting to geometry!", fnDepNode.name().asChar() );
+ }
+
+ if ( TrackEditor::GetDeleteTreelines() )
+ {
+ MExt::DeleteNode( obj, true );
+ }
+}
+
+
+/////////////////////////////////////////////////////////////////////
+// UI IMPLEMENTATION
+/////////////////////////////////////////////////////////////////////
+
+TreelineShapeNodeUI::TreelineShapeNodeUI()
+{
+}
+
+TreelineShapeNodeUI::~TreelineShapeNodeUI()
+{
+}
+
+void* TreelineShapeNodeUI::creator()
+{
+ return new TreelineShapeNodeUI();
+}
+
+//********************************************************************************************
+// The draw data is used to pass geometry through the
+// draw queue. The data should hold all the information
+// needed to draw the shape.
+//********************************************************************************************
+void TreelineShapeNodeUI::getDrawRequests( const MDrawInfo & info, bool objectAndActiveOnly, MDrawRequestQueue & queue )
+{
+ MDrawData data;
+ MDrawRequest request = info.getPrototype( *this );
+ TreelineShapeNode* shapeNode = (TreelineShapeNode*)surfaceShape();
+ getDrawData( NULL, data );
+ request.setDrawData( data );
+
+ // Use display status to determine what color to draw the object
+ switch ( info.displayStyle() )
+ {
+ case M3dView::kGouraudShaded :
+ request.setToken( SMOOTH_SHADED );
+ getDrawRequestsShaded( request, info, queue, data );
+ queue.add( request );
+ break;
+
+ case M3dView::kFlatShaded :
+ request.setToken( FLAT_SHADED );
+ getDrawRequestsShaded( request, info, queue, data );
+ queue.add( request );
+ break;
+
+ default :
+ request.setToken(WIREFRAME);
+ getDrawRequestsWireframe( request, info );
+ queue.add( request );
+ break;
+
+ }
+
+ // Add draw requests for components
+ //
+ if ( !objectAndActiveOnly )
+ {
+ // Inactive components
+ //
+ if ( (info.displayStyle() == M3dView::kPoints) ||
+ (info.displayStatus() == M3dView::kHilite) )
+ {
+ MDrawRequest vertexRequest = info.getPrototype( *this );
+ vertexRequest.setDrawData( data );
+ vertexRequest.setToken( VERTICES );
+ vertexRequest.setColor( DORMANT_VERTEX_COLOR, //TODO: PICK COLOURS
+ M3dView::kActiveColors );
+
+ queue.add( vertexRequest );
+ }
+
+ // Active components
+ //
+ if ( surfaceShape()->hasActiveComponents() ) {
+
+ MDrawRequest activeVertexRequest = info.getPrototype( *this );
+ activeVertexRequest.setDrawData( data );
+ activeVertexRequest.setToken( VERTICES );
+ activeVertexRequest.setColor( ACTIVE_VERTEX_COLOR, //TODO: PICK COLOURS
+ M3dView::kActiveColors );
+
+ MObjectArray clist = surfaceShape()->activeComponents();
+ MObject vertexComponent = clist[0]; // Should filter list
+ activeVertexRequest.setComponent( vertexComponent );
+
+ queue.add( activeVertexRequest );
+ }
+ }
+
+}
+
+//********************************************************************************************
+// Actual draw call
+//********************************************************************************************
+void TreelineShapeNodeUI::drawQuad(int drawMode) const
+{
+ glPushAttrib( GL_CURRENT_BIT | GL_LINE_BIT | GL_POLYGON_BIT );
+ TreelineShapeNode* shapeNode = (TreelineShapeNode*)surfaceShape();
+ MFnDagNode dagNodeFn(shapeNode->thisMObject());
+ MPlug plug;
+
+ MStatus status;
+ float height;
+ MPlug heightPlug = dagNodeFn.findPlug( TETreeLine::TreelineShapeNode::sHeight, &status );
+ assert( status );
+
+ heightPlug.getValue( height );
+
+ MPlug vertices = dagNodeFn.findPlug( TETreeLine::TreelineShapeNode::mControlPoints, &status );
+ assert( status );
+
+ if ( vertices.numElements() >= 2 )
+ {
+ double uScale;
+ MPlug uScalePlug = dagNodeFn.findPlug( TETreeLine::TreelineShapeNode::sUScale, &status );
+ assert( status );
+ uScalePlug.getValue( uScale );
+
+ int primType;
+ if ((drawMode==SMOOTH_SHADED)||(drawMode==FLAT_SHADED))
+ {
+ glPolygonMode ( GL_FRONT_AND_BACK, GL_FILL);
+ primType = GL_POLYGON;
+ }
+ else
+ {
+ glPolygonMode ( GL_FRONT_AND_BACK, GL_LINE);
+ primType = GL_LINE_LOOP;
+ }
+
+ glPushMatrix();
+
+ unsigned int i = 0;
+
+ do
+ {
+ MPoint point1, point2;
+ MPlug vertex1 = vertices.elementByLogicalIndex( i, &status );
+ assert( status );
+
+ MPlug vertex2 = vertices.elementByLogicalIndex( i + 1, &status );
+ assert( status );
+
+ MPlug x1 = vertex1.child( TETreeLine::TreelineShapeNode::mControlValueX, &status );
+ assert( status );
+ x1.getValue( point1.x );
+
+ MPlug y1 = vertex1.child( TETreeLine::TreelineShapeNode::mControlValueY, &status );
+ assert( status );
+ y1.getValue( point1.y );
+
+ MPlug z1 = vertex1.child( TETreeLine::TreelineShapeNode::mControlValueZ, &status );
+ assert( status );
+ z1.getValue( point1.z );
+
+ MPlug x2 = vertex2.child( TETreeLine::TreelineShapeNode::mControlValueX, &status );
+ assert( status );
+ x2.getValue( point2.x );
+
+ MPlug y2 = vertex2.child( TETreeLine::TreelineShapeNode::mControlValueY, &status );
+ assert( status );
+ y2.getValue( point2.y );
+
+ MPlug z2 = vertex2.child( TETreeLine::TreelineShapeNode::mControlValueZ, &status );
+ assert( status );
+ z2.getValue( point2.z );
+
+ MPoint normal, vect;
+ rmt::Vector normalVec;
+ rmt::Vector v;
+
+ double dist = point1.distanceTo( point2 );
+
+ double U = ceil( dist / (uScale * TEConstants::Scale ) );
+
+ vect = point2 - point1;
+ v.Set( vect.x, vect.y, vect.z );
+ normalVec.CrossProduct( v, rmt::Vector( 0.0f, 1.0f, 0.0f ) );
+
+ glBegin(primType);
+ glNormal3f( normalVec.x, normalVec.y, normalVec.z ); //TODO: CALCULATE THIS!
+ glTexCoord2f ( 0, 1 );
+ glVertex3f( point1.x,
+ (point1.y) + (height * TEConstants::Scale),
+ point1.z );
+ glTexCoord2f ( 0, 0 );
+ glVertex3f( point1.x,
+ point1.y,
+ point1.z );
+ glTexCoord2f ( U, 0 );
+ glVertex3f( point2.x,
+ point2.y,
+ point2.z );
+ glTexCoord2f ( U, 1 );
+ glVertex3f( point2.x,
+ (point2.y) + (height * TEConstants::Scale),
+ point2.z );
+ glEnd();
+
+ ++i;
+ }
+ while ( i < vertices.numElements() - 1 );
+
+ glPopMatrix();
+
+ glPolygonMode ( GL_FRONT_AND_BACK, GL_FILL);
+ }
+ glPopAttrib();
+}
+
+//********************************************************************************************
+// From the given draw request, get the draw data and display the quad
+//********************************************************************************************
+void TreelineShapeNodeUI::draw( const MDrawRequest & request, M3dView & view ) const
+{
+ glPushAttrib( GL_CURRENT_BIT | GL_LINE_BIT | GL_POLYGON_BIT );
+ MDagPath dagPath = request.multiPath();
+ MDrawData data = request.drawData();
+ short token = request.token();
+ bool drawTexture = false;
+
+ view.beginGL();
+
+ if ( (token == SMOOTH_SHADED) || (token == FLAT_SHADED) )
+ {
+ glEnable( GL_POLYGON_OFFSET_FILL );
+ // Set up the material
+ //
+ MMaterial material = request.material();
+ material.setMaterial(dagPath,false);
+
+ // Enable texturing
+ //
+ drawTexture = material.materialIsTextured();
+ if ( drawTexture ) glEnable(GL_TEXTURE_2D);
+
+ // Apply the texture to the current view
+ //
+ if ( drawTexture )
+ {
+ material.applyTexture( view, data );
+ }
+ }
+
+ if ( token == VERTICES )
+ {
+ drawVertices( request, view );
+ }
+ else
+ {
+ drawQuad(token);
+ }
+
+ // Turn off texture mode
+ //
+ if ( drawTexture ) glDisable(GL_TEXTURE_2D);
+
+ view.endGL();
+ glPopAttrib();
+}
+
+//********************************************************************************************
+// Select function. Gets called when the bbox for the object is selected.
+// This function just selects the object without doing any intersection tests.
+//********************************************************************************************
+bool TreelineShapeNodeUI::select( MSelectInfo &selectInfo, MSelectionList &selectionList, MPointArray &worldSpaceSelectPts ) const
+{
+ bool selected = false;
+
+ if ( selectInfo.displayStatus() == M3dView::kHilite ) {
+ selected = selectVertices( selectInfo, selectionList,worldSpaceSelectPts );
+ }
+
+ if ( !selected )
+ {
+ M3dView view = selectInfo.view();
+
+ //
+ // Re-Draw the object and see if they lie withing the selection area
+ // Sets OpenGL's render mode to select and stores
+ // selected items in a pick buffer
+ //
+ view.beginSelect();
+
+ switch ( selectInfo.displayStyle() )
+ {
+ case M3dView::kGouraudShaded :
+ drawQuad(SMOOTH_SHADED);
+ break;
+
+ case M3dView::kFlatShaded :
+ drawQuad(FLAT_SHADED);
+ break;
+
+ default :
+ drawQuad(WIREFRAME);
+ break;
+ }
+
+ if( view.endSelect() > 0 )
+ {
+ MSelectionMask priorityMask( MSelectionMask::kSelectObjectsMask );
+ MSelectionList item;
+ item.add( selectInfo.selectPath() );
+ MPoint xformedPt;
+ selectInfo.addSelection( item, xformedPt, selectionList, worldSpaceSelectPts, priorityMask, false );
+ return true;
+ }
+ }
+
+ return selected;
+}
+
+//=============================================================================
+// TreelineShapeNodeUI::drawVertices
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( const MDrawRequest & request, M3dView & view )
+//
+// Return: void
+//
+//=============================================================================
+void TreelineShapeNodeUI::drawVertices( const MDrawRequest & request, M3dView & view ) const
+//
+// Description:
+//
+// Component (vertex) drawing routine
+//
+// Arguments:
+//
+// request - request to be drawn
+// view - view to draw into
+//
+{
+ glPushAttrib( GL_CURRENT_BIT | GL_LINE_BIT | GL_POLYGON_BIT );
+ MDrawData data = request.drawData();
+ TreelineShapeNode* shapeNode = (TreelineShapeNode*)surfaceShape();
+ MFnDagNode dagNodeFn(shapeNode->thisMObject());
+
+ view.beginGL();
+
+ // Query current state so it can be restored
+ //
+ bool lightingWasOn = glIsEnabled( GL_LIGHTING ) ? true : false;
+ if ( lightingWasOn ) {
+ glDisable( GL_LIGHTING );
+ }
+ float lastPointSize;
+ glGetFloatv( GL_POINT_SIZE, &lastPointSize );
+
+ // Set the point size of the vertices
+ //
+ glPointSize( POINT_SIZE );
+
+ // If there is a component specified by the draw request
+ // then loop over comp (using an MFnComponent class) and draw the
+ // active vertices, otherwise draw all vertices.
+ //
+ MObject comp = request.component();
+ if ( ! comp.isNull() )
+ {
+ MPlug vertices = dagNodeFn.findPlug( TETreeLine::TreelineShapeNode::mControlPoints );
+
+ MFnSingleIndexedComponent fnComponent( comp );
+ for ( int i=0; i<fnComponent.elementCount(); i++ )
+ {
+ int index = fnComponent.element( i );
+ glBegin( GL_POINTS );
+ MPlug vertexPlug = vertices.elementByLogicalIndex( index );
+
+ MPoint vertex;
+ vertexPlug.child( 0 ).getValue( vertex.x );
+ vertexPlug.child( 1 ).getValue( vertex.y );
+ vertexPlug.child( 2 ).getValue( vertex.z );
+
+ glVertex3f( (float)vertex[0],
+ (float)vertex[1],
+ (float)vertex[2] );
+ glEnd();
+
+ char annotation[32];
+ sprintf( annotation, "%d", index );
+ view.drawText( annotation, vertex );
+ }
+ }
+ else
+ {
+ MPlug vertices = dagNodeFn.findPlug( TETreeLine::TreelineShapeNode::mControlPoints );
+
+ for ( int i=0; i<vertices.numElements(); i++ )
+ {
+ glBegin( GL_POINTS );
+ MPlug vertexPlug = vertices.elementByLogicalIndex( i );
+
+ MPoint vertex;
+ vertexPlug.child( 0 ).getValue( vertex.x );
+ vertexPlug.child( 1 ).getValue( vertex.y );
+ vertexPlug.child( 2 ).getValue( vertex.z );
+
+ glVertex3f( (float)vertex[0],
+ (float)vertex[1],
+ (float)vertex[2] );
+ glEnd();
+ }
+ }
+ // Restore the state
+ //
+ if ( lightingWasOn ) {
+ glEnable( GL_LIGHTING );
+ }
+ glPointSize( lastPointSize );
+
+ view.endGL();
+ glPopAttrib();
+}
+
+//=============================================================================
+// TreelineShapeNodeUI::selectVertices
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( MSelectInfo &selectInfo, MSelectionList &selectionList, MPointArray &worldSpaceSelectPts )
+//
+// Return: bool
+//
+//=============================================================================
+bool TreelineShapeNodeUI::selectVertices( MSelectInfo &selectInfo,
+ MSelectionList &selectionList,
+ MPointArray &worldSpaceSelectPts ) const
+//
+// Description:
+//
+// Vertex selection.
+//
+// Arguments:
+//
+// selectInfo - the selection state information
+// selectionList - the list of selected items to add to
+// worldSpaceSelectPts -
+//
+{
+ bool selected = false;
+ M3dView view = selectInfo.view();
+
+ MPoint xformedPoint;
+ MPoint currentPoint;
+ MPoint selectionPoint;
+ double z,previousZ = 0.0;
+ int closestPointVertexIndex = -1;
+
+ const MDagPath & path = selectInfo.multiPath();
+
+ // Create a component that will store the selected vertices
+ //
+ MFnSingleIndexedComponent fnComponent;
+ MObject surfaceComponent = fnComponent.create( MFn::kMeshVertComponent );
+ int vertexIndex;
+
+ // if the user did a single mouse click and we find > 1 selection
+ // we will use the alignmentMatrix to find out which is the closest
+ //
+ MMatrix alignmentMatrix;
+ MPoint singlePoint;
+ bool singleSelection = selectInfo.singleSelection();
+ if( singleSelection ) {
+ alignmentMatrix = selectInfo.getAlignmentMatrix();
+ }
+
+ // Get the geometry information
+ //
+ TreelineShapeNode* shapeNode = (TreelineShapeNode*)surfaceShape();
+ MFnDagNode dagNodeFn(shapeNode->thisMObject());
+
+ // Loop through all vertices of the mesh and
+ // see if they lie withing the selection area
+ //
+ MPlug vertices = dagNodeFn.findPlug( TETreeLine::TreelineShapeNode::mControlPoints );
+
+ int numVertices = vertices.numElements();
+
+ for ( vertexIndex=0; vertexIndex<numVertices; vertexIndex++ )
+ {
+ MPlug vertexPlug = vertices.elementByLogicalIndex( vertexIndex );
+
+ MPoint currentPoint;
+ vertexPlug.child( 0 ).getValue( currentPoint.x );
+ vertexPlug.child( 1 ).getValue( currentPoint.y );
+ vertexPlug.child( 2 ).getValue( currentPoint.z );
+
+ // Sets OpenGL's render mode to select and stores
+ // selected items in a pick buffer
+ //
+ view.beginSelect();
+
+ glBegin( GL_POINTS );
+
+ glVertex3f( (float)currentPoint[0],
+ (float)currentPoint[1],
+ (float)currentPoint[2] );
+ glEnd();
+
+ if ( view.endSelect() > 0 ) // Hit count > 0
+ {
+ selected = true;
+
+ if ( singleSelection ) {
+ xformedPoint = currentPoint;
+ xformedPoint.homogenize();
+ xformedPoint*= alignmentMatrix;
+ z = xformedPoint.z;
+ if ( closestPointVertexIndex < 0 || z > previousZ ) {
+ closestPointVertexIndex = vertexIndex;
+ singlePoint = currentPoint;
+ previousZ = z;
+ }
+ } else {
+ // multiple selection, store all elements
+ //
+ fnComponent.addElement( vertexIndex );
+ }
+ }
+ }
+
+ // If single selection, insert the closest point into the array
+ //
+ if ( selected && selectInfo.singleSelection() ) {
+ fnComponent.addElement(closestPointVertexIndex);
+
+ // need to get world space position for this vertex
+ //
+ selectionPoint = singlePoint;
+ selectionPoint *= path.inclusiveMatrix();
+ }
+
+ // Add the selected component to the selection list
+ //
+ if ( selected ) {
+ MSelectionList selectionItem;
+ selectionItem.add( path, surfaceComponent );
+
+ MSelectionMask mask( MSelectionMask::kSelectComponentsMask );
+ selectInfo.addSelection(
+ selectionItem, selectionPoint,
+ selectionList, worldSpaceSelectPts,
+ mask, true );
+ }
+
+ return selected;
+}
+
+} //namespace TETreeLine
+
+
diff --git a/tools/trackeditor/code/nodes/treelineshapenode.h b/tools/trackeditor/code/nodes/treelineshapenode.h
new file mode 100644
index 0000000..e1a25ac
--- /dev/null
+++ b/tools/trackeditor/code/nodes/treelineshapenode.h
@@ -0,0 +1,142 @@
+#ifndef TREELINE_SHAPE_NODE_H
+#define TREELINE_SHAPE_NODE_H
+
+#include "precompiled/PCH.h"
+
+class tlDataChunk;
+
+namespace TETreeLine
+{
+
+class p3dBaseShape : public MPxSurfaceShape
+{
+public:
+ p3dBaseShape() {}
+ virtual ~p3dBaseShape() {}
+};
+
+class p3dBaseShapeUI : public MPxSurfaceShapeUI
+{
+public:
+ p3dBaseShapeUI()
+ {
+ lead_color = 18; //green
+ active_color = 15; //white
+ active_affected_color = 8; //purple
+ dormant_color = 4; //blue
+ hilite_color = 17; //pale blue
+ }
+ virtual ~p3dBaseShapeUI() {}
+
+ virtual void getDrawRequestsWireframe( MDrawRequest&, const MDrawInfo& );
+ virtual void getDrawRequestsShaded( MDrawRequest&, const MDrawInfo&, MDrawRequestQueue&, MDrawData& data );
+
+protected:
+ int lead_color;
+ int active_color;
+ int active_affected_color;
+ int dormant_color;
+ int hilite_color;
+};
+
+/////////////////////////////////////////////////////////////////////
+//
+// Shape class - defines the non-UI part of a shape node
+//
+class TreelineShapeNode : public p3dBaseShape
+{
+public:
+ TreelineShapeNode();
+ virtual ~TreelineShapeNode();
+
+ virtual void postConstructor();
+ virtual MStatus compute( const MPlug& plug, MDataBlock& datablock );
+ virtual MStatus connectionMade ( const MPlug &plug, const MPlug &otherPlug, bool asSrc );
+ static void* creator();
+ static MStatus initialize();
+ virtual bool isBounded() const {return true;}
+ virtual MBoundingBox boundingBox() const;
+
+ virtual void componentToPlugs( MObject& component, MSelectionList& selectionList ) const;
+ virtual MPxSurfaceShape::MatchResult
+ matchComponent( const MSelectionList& item,
+ const MAttributeSpecArray& spec,
+ MSelectionList& list );
+ virtual bool match( const MSelectionMask& mask,
+ const MObjectArray& componentList ) const;
+ virtual void transformUsing( const MMatrix& mat, const MObjectArray& componentList );
+ virtual void closestPoint ( const MPoint & toThisPoint, MPoint & theClosestPoint, double tolerance );
+
+ static void SnapTreeline( MObject& treeline );
+
+ static void ConvertToGeometry( MObject& obj );
+
+ static MTypeId id;
+ static const char* stringId;
+
+private:
+ // Attributes
+ static const char* SHADER_NAME_LONG;
+ static const char* SHADER_NAME_SHORT;
+ static MObject sShader;
+
+ static const char* USCALE_NAME_LONG;
+ static const char* USCALE_NAME_SHORT;
+ static MObject sUScale;
+
+ static const char* COLOUR_NAME_LONG;
+ static const char* COLOUR_NAME_SHORT;
+ static MObject sColour;
+
+ static const char* RED_NAME_LONG;
+ static const char* RED_NAME_SHORT;
+ static MObject sRed;
+
+ static const char* GREEN_NAME_LONG;
+ static const char* GREEN_NAME_SHORT;
+ static MObject sGreen;
+
+ static const char* BLUE_NAME_LONG;
+ static const char* BLUE_NAME_SHORT;
+ static MObject sBlue;
+
+ static const char* ALPHA_NAME_LONG;
+ static const char* ALPHA_NAME_SHORT;
+ static MObject sAlpha;
+
+ static const char* HEIGHT_NAME_LONG;
+ static const char* HEIGHT_NAME_SHORT;
+ static MObject sHeight;
+};
+
+/////////////////////////////////////////////////////////////////////
+//
+// UI class - defines the UI part of a shape node
+//
+class TreelineShapeNodeUI : public p3dBaseShapeUI
+{
+public:
+ TreelineShapeNodeUI();
+ virtual ~TreelineShapeNodeUI();
+
+ virtual void getDrawRequests( const MDrawInfo & info, bool objectAndActiveOnly, MDrawRequestQueue & requests );
+ virtual void draw( const MDrawRequest & request, M3dView & view ) const;
+ virtual bool select( MSelectInfo &selectInfo, MSelectionList &selectionList, MPointArray &worldSpaceSelectPts ) const;
+ static void * creator();
+
+protected:
+ void drawQuad(int drawMode) const;
+ void drawVertices( const MDrawRequest & request, M3dView & view ) const;
+ bool selectVertices( MSelectInfo &selectInfo,
+ MSelectionList &selectionList,
+ MPointArray &worldSpaceSelectPts ) const;
+};
+
+
+} //namespace TETreeLine
+
+
+
+#endif //TREELINE_SHAPE_NODE_H
+
+
diff --git a/tools/trackeditor/code/nodes/walllocator.cpp b/tools/trackeditor/code/nodes/walllocator.cpp
new file mode 100644
index 0000000..e4d5c4f
--- /dev/null
+++ b/tools/trackeditor/code/nodes/walllocator.cpp
@@ -0,0 +1,551 @@
+#include "precompiled/PCH.h"
+
+#include "walllocator.h"
+#include "main/constants.h"
+#include "utility/glext.h"
+#include "utility/mext.h"
+#include "utility/nodehelper.h"
+
+#include <toollib.hpp>
+
+
+MTypeId WallLocatorNode::id( TEConstants::TypeIDPrefix, TEConstants::NodeIDs::WallLocator );
+const char* WallLocatorNode::stringId = "WallLocatorNode";
+
+const int WallLocatorNode::ACTIVE_COLOUR = 13;
+const int WallLocatorNode::INACTIVE_COLOUR = 22;
+const float WallLocatorNode::SCALE = 1.0f * TEConstants::Scale;
+
+//This is an attribute.
+
+const char* WallLocatorNode::LEFTRIGHT_NAME_LONG = "leftRight";
+const char* WallLocatorNode::LEFTRIGHT_NAME_SHORT = "lr";
+MObject WallLocatorNode::mLeftRight;
+
+const char* WallLocatorNode::PREVNODE_NAME_LONG = "prevNode";
+const char* WallLocatorNode::PREVNODE_NAME_SHORT = "pn";
+MObject WallLocatorNode::mPrevNode;
+
+const char* WallLocatorNode::NEXTNODE_NAME_LONG = "nextNode";
+const char* WallLocatorNode::NEXTNODE_NAME_SHORT = "nn";
+MObject WallLocatorNode::mNextNode;
+
+const char* WallLocatorNode::ID_NAME_LONG = "callbackID";
+const char* WallLocatorNode::ID_NAME_SHORT = "cb";
+MObject WallLocatorNode::mCallbackId;
+
+//==============================================================================
+// WallLocatorNode::WallLocatorNode
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: WallLocatorNode
+//
+//==============================================================================
+WallLocatorNode::WallLocatorNode() {};
+
+//==============================================================================
+// WallLocatorNode::~WallLocatorNode
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: WallLocatorNode
+//
+//==============================================================================
+WallLocatorNode::~WallLocatorNode() {};
+
+//==============================================================================
+// WallLocatorNode::creator
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//==============================================================================
+void* WallLocatorNode::creator()
+{
+ return new WallLocatorNode();
+}
+
+//==============================================================================
+// WallLocatorNode::initialize
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: MStatus
+//
+//==============================================================================
+MStatus WallLocatorNode::initialize()
+{
+ MFnMessageAttribute fnMessage;
+ MFnNumericAttribute fnNumeric;
+ MStatus status;
+
+ //Create the left/right attrib
+ mLeftRight = fnNumeric.create( LEFTRIGHT_NAME_LONG, LEFTRIGHT_NAME_SHORT, MFnNumericData::kInt, LEFT, &status );
+ RETURN_STATUS_ON_FAILURE( status );
+ fnNumeric.setDefault(LEFT);
+
+ RETURN_STATUS_ON_FAILURE( addAttribute( mLeftRight ) );
+
+
+ //Create the sttribute for the previous node.
+ mPrevNode = fnMessage.create( PREVNODE_NAME_LONG, PREVNODE_NAME_SHORT, &status );
+ RETURN_STATUS_ON_FAILURE( status );
+ RETURN_STATUS_ON_FAILURE( fnMessage.setReadable( false ) );
+ RETURN_STATUS_ON_FAILURE( fnMessage.setWritable( true ) );
+
+ RETURN_STATUS_ON_FAILURE( addAttribute( mPrevNode ) );
+
+ //Create the sttribute for the next node.
+ mNextNode = fnMessage.create( NEXTNODE_NAME_LONG, NEXTNODE_NAME_SHORT, &status );
+ RETURN_STATUS_ON_FAILURE( status );
+ RETURN_STATUS_ON_FAILURE( fnMessage.setReadable( true ) );
+ RETURN_STATUS_ON_FAILURE( fnMessage.setWritable( false ) );
+
+ RETURN_STATUS_ON_FAILURE( addAttribute( mNextNode ) );
+
+
+ mCallbackId = fnNumeric.create( ID_NAME_LONG, ID_NAME_SHORT, MFnNumericData::kLong, 0, &status );
+ RETURN_STATUS_ON_FAILURE( status );
+ fnNumeric.setDefault( 0 );
+
+ RETURN_STATUS_ON_FAILURE( addAttribute( mCallbackId ) );
+
+ return MS::kSuccess;
+}
+
+//==============================================================================
+// WallLocatorNode::legalConnection
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ( const MPlug & plug, const MPlug & otherPlug, bool asSrc, bool& result )
+//
+// Return: MStatus
+//
+//==============================================================================
+MStatus WallLocatorNode::legalConnection ( const MPlug & plug, const MPlug & otherPlug, bool asSrc, bool& result ) const
+{
+ if ( otherPlug.node() == thisMObject() )
+ {
+ result = false;
+ return MS::kSuccess;
+ }
+
+ if ( plug == mNextNode )
+ {
+ //This is the source of the connection.
+ //Therefore the connection is legal if I'm not already connected to the same node by the input.
+ MFnDependencyNode fnNode;
+ MStatus status;
+
+ fnNode.setObject( thisMObject() );
+ MPlug prevPlug = fnNode.findPlug( mPrevNode, &status );
+ assert( status );
+
+ if ( prevPlug.node() != otherPlug.node() )
+ {
+ //Go ahead and connect.
+ result = true;
+ }
+ else
+ {
+ //Already connected to this node. No 2-Node loops please.
+ result = false;
+ }
+
+ return MS::kSuccess;
+ }
+ else if ( plug == mPrevNode )
+ {
+ //This is the destination of the connection.
+ //Therefore the connection is legal if I'm not already connected to the same node by the output
+ MFnDependencyNode fnNode;
+ MStatus status;
+
+ fnNode.setObject( thisMObject() );
+ MPlug nextPlug = fnNode.findPlug( mNextNode, &status );
+ assert( status );
+
+ if ( nextPlug.node() != otherPlug.node() )
+ {
+ //Go ahead and connect.
+ result = true;
+ }
+ else
+ {
+ //Already connected to this node. No 2-Node loops please.
+ result = false;
+ }
+ return MS::kSuccess;
+ }
+
+ return MS::kUnknownParameter;
+}
+
+//==============================================================================
+// WallLocatorNode::postConstructor
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//==============================================================================
+void WallLocatorNode::postConstructor()
+{
+ //
+ // Register a callback that will notify us just prior to this node being
+ // deleted.
+ //
+ MStatus status;
+ MFnDependencyNode fnNode;
+
+ fnNode.setObject( thisMObject() );
+ MPlug plug = fnNode.findPlug( mCallbackId, &status );
+ assert( status );
+
+ int id = MNodeMessage::addNodeAboutToDeleteCallback(
+ thisMObject(),
+ NodeAboutToDeleteCallback,
+ (void*)(this),
+ &status
+ );
+
+ plug.setValue( id );
+
+ //Since this is a planar dealie, we want the Y to stay at 0...
+ MPlug lyPlug( thisMObject(), localPositionY );
+ lyPlug.setLocked( true );
+
+ MPlug wyPlug( thisMObject(), worldPositionY );
+ wyPlug.setLocked( true );
+
+ assert( status );
+}
+
+//==============================================================================
+// WallLocatorNode::draw
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ( M3dView & view,
+// const MDagPath & path,
+// M3dView::DisplayStyle style,
+// M3dView::DisplayStatus status )
+//
+// Return: void
+//
+//==============================================================================
+void WallLocatorNode::draw( M3dView & view,
+ const MDagPath & path,
+ M3dView::DisplayStyle style,
+ M3dView::DisplayStatus status )
+{
+ view.beginGL();
+ glPushAttrib( GL_CURRENT_BIT | GL_LINE_BIT | GL_POLYGON_BIT );
+
+ //If there is a connected wall locator node, draw a line to it. Then draw the arrow halfway between them.
+ if ( MExt::IsConnected( thisMObject(), mNextNode ) )
+ {
+ //Can we stop the GL system from adding this to it's selection mechanism?
+
+ //When we are in render mode, we draw the lines between the nodes.
+ //If this was in GL_SELECTION_MODE, we would not draw the lines, so they won't interfere
+ //with selection.
+ GLint value;
+ glGetIntegerv( GL_RENDER_MODE, &value );
+
+ if ( (value == GL_RENDER) )
+ {
+ //Get the world position of the next node
+ MStatus st;
+ MPlugArray pa;
+ MFnDependencyNode fnNode;
+
+ fnNode.setObject( thisMObject() );
+ MPlug plug = fnNode.findPlug( mNextNode, &st );
+ assert( st );
+
+ plug.connectedTo( pa, false, true, &st );
+ assert( st );
+
+ //There is only one thing plugged into this...
+ MPlug nextPlug = pa[0];
+
+ //Got the nextNode's plug, let's get the WorldPosition of the other node.
+ MPoint nnwp;
+ MExt::GetWorldPosition( &nnwp, nextPlug.node() );
+
+ //Get the world position of this node.
+ MPoint wp;
+ MExt::GetWorldPosition( &wp, thisMObject() );
+
+ MPoint localPosNN( nnwp - wp );
+ MPoint localOrigin; // (0,0,0)
+
+ int colour = NodeHelper::OverrideNodeColour( thisMObject(), INACTIVE_COLOUR );
+
+ view.setDrawColor( colour, M3dView::kDormantColors );
+
+ GLExt::drawLine( localOrigin, localPosNN );
+
+
+ //Draw the LEFT / RIGHT line
+ MPoint wpMiddleOfLine = MExt::GetWorldPositionBetween( thisMObject(), nextPlug.node() );
+
+ MVector arrow;
+ if ( CalculateNormal( nnwp, &arrow ) )
+ {
+ MPoint arrowFrom( wpMiddleOfLine - wp );
+ double scale = ( localPosNN.distanceTo(localOrigin) / 6 );
+ if ( scale > 5 * TEConstants::Scale )
+ {
+ scale = 5 * TEConstants::Scale;
+ }
+
+ MPoint arrowTo( ( arrow * scale ) + arrowFrom );
+
+ GLExt::drawLine( arrowFrom, arrowTo, 5.0f );
+ }
+ }
+ }
+
+ if ( status == M3dView::kDormant )
+ {
+ int colour = NodeHelper::OverrideNodeColour( thisMObject(), INACTIVE_COLOUR );
+
+ view.setDrawColor( colour, M3dView::kDormantColors );
+ }
+ else
+ {
+ view.setDrawColor( ACTIVE_COLOUR, M3dView::kDormantColors );
+ }
+
+ //Draw a star to represent the locator.
+ GLExt::drawCrossHair3D( SCALE );
+
+ glPopAttrib();
+ view.endGL();
+}
+
+//==============================================================================
+// WallLocatorNode::NodeAboutToDeleteCallback
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ( MDGModifier& modifier, void* data )
+//
+// Return: void
+//
+//==============================================================================
+void WallLocatorNode::NodeAboutToDeleteCallback( MDGModifier& modifier, void* data )
+{
+ //
+ // Get the this pointer for the node being deleted.
+ //
+ WallLocatorNode* thisNode = (WallLocatorNode*)(data);
+ assert( thisNode );
+
+ //
+ // Get the MObject corresponding to this node.
+ //
+ MObject node = thisNode->thisMObject();
+
+ //Attach the neighbour nodes to eachother.
+ MObject nextNode;
+ MObject prevNode;
+
+ if ( MExt::IsConnected( node, mNextNode ) && MExt::IsConnected( node, mPrevNode ))
+ {
+ MStatus status;
+ MFnDependencyNode fnNode;
+ fnNode.setObject( node );
+
+ MPlug plug = fnNode.findPlug( mNextNode, &status );
+
+ MPlugArray pa;
+ plug.connectedTo( pa, false, true, &status );
+ assert( status );
+
+ MPlug nextPlug = pa[0];
+
+ nextNode = nextPlug.node();
+
+
+ fnNode.setObject( node );
+
+ plug = fnNode.findPlug( mPrevNode, &status );
+
+ plug.connectedTo( pa, true, false, &status );
+ assert( status );
+
+ MPlug prevPlug = pa[0];
+
+ prevNode = prevPlug.node();
+
+ //Remove all connections to this node.
+ MExt::DisconnectAll( node, mNextNode );
+ MExt::DisconnectAll( node, mPrevNode );
+
+
+ //Connect the nodes together... THANKS!
+ if ( prevNode != nextNode )
+ {
+ MExt::Connect( prevNode, WallLocatorNode::NEXTNODE_NAME_LONG, nextNode, WallLocatorNode::PREVNODE_NAME_LONG );
+ }
+ }
+
+ //
+ // cancel callback.
+ //
+ MStatus status;
+ MFnDependencyNode fnNode;
+ fnNode.setObject( node );
+
+ int id;
+ MPlug plug = fnNode.findPlug( mCallbackId, &status );
+ plug.getValue( id );
+
+ MMessage::removeCallback( id );
+}
+
+//==============================================================================
+// WallLocatorNode::CalculateNormal
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ( MPoint& nextNodeWP, MVector* normal )
+//
+// Return: bool
+//
+//==============================================================================
+bool WallLocatorNode::CalculateNormal( MPoint& nextNodeWP, MVector* normal )
+{
+ return CalculateNormal( thisMObject(), nextNodeWP, normal );
+}
+
+//==============================================================================
+// WallLocatorNode::CalculateNormal
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ( MObject& thisNode, MPoint& nextNodeWP, MVector* normal )
+//
+// Return: bool
+//
+//==============================================================================
+bool WallLocatorNode::CalculateNormal( MObject& thisNode, MPoint& nextNodeWP, MVector* normal )
+{
+ //Get the world position of this node.
+ MPoint wp;
+ MExt::GetWorldPosition( &wp, thisNode );
+
+ MPoint localPosNN( nextNodeWP - wp );
+
+ MVector nextNode( localPosNN );
+
+ int isLeft = NONE;
+ MExt::Attr::Get( &isLeft, thisNode, mLeftRight );
+
+ if ( isLeft == LEFT )
+ {
+ MVector yUp( 0, -1.0f, 0 );
+ *normal = nextNode ^ yUp; //Cross product.
+ }
+ else if ( isLeft == RIGHT)
+ {
+ MVector yUp( 0, 1.0f, 0 );
+ *normal = nextNode ^ yUp; //Cross product.
+ }
+ else
+ {
+ return false;
+ }
+
+ normal->normalize();
+ return true;
+}
+
+//==============================================================================
+// WallLocatorNode::Export
+//==============================================================================
+// Description: Comment
+//
+// Parameters: ( MObject& wallLocatorNode, tlHistory& history )
+//
+// Return: tlDataChunk
+//
+//==============================================================================
+tlDataChunk* WallLocatorNode::Export( MObject& wallLocatorNode, tlHistory& history )
+{
+ MFnDagNode fnNode( wallLocatorNode );
+
+ if ( fnNode.typeId() == WallLocatorNode::id )
+ {
+ //Create a tlDataChunk and return it filled with the appropriate data.
+ tlWallChunk* wall = new tlWallChunk;
+
+ MStatus st;
+ MPlugArray pa;
+ MPlug nextPlug = fnNode.findPlug( mNextNode, &st );
+ nextPlug.connectedTo( pa, false, true, &st );
+ assert( st );
+
+ //There is only one thing plugged into this...
+ MPlug nextNodePlug = pa[0];
+ MObject nextNode = nextNodePlug.node();
+
+ MPoint thisPosition;
+ MExt::GetWorldPosition( &thisPosition, wallLocatorNode );
+
+ MPoint nextPosition;
+ MExt::GetWorldPosition( &nextPosition, nextNode );
+
+ MVector normal;
+ bool hasNormal = CalculateNormal( wallLocatorNode, nextPosition, &normal );
+
+ //Set the values.
+ tlPoint point;
+
+ point[0] = thisPosition[0] / TEConstants::Scale;
+ point[1] = thisPosition[1] / TEConstants::Scale;
+ point[2] = -thisPosition[2] / TEConstants::Scale; //Maya vs. P3D...
+ wall->SetStart( point );
+
+ point[0] = nextPosition[0] / TEConstants::Scale;
+ point[1] = nextPosition[1] / TEConstants::Scale;
+ point[2] = -nextPosition[2] / TEConstants::Scale; //Maya vs. P3D...
+ wall->SetEnd( point );
+
+ if ( hasNormal )
+ {
+ normal.normalize();
+ point[0] = normal[0];
+ point[1] = normal[1];
+ point[2] = -normal[2]; //Maya vs. P3D...
+ }
+ else
+ {
+ point[0] = 0;
+ point[1] = 0;
+ point[2] = 0;
+ }
+ wall->SetNormal( point );
+
+ return wall;
+ }
+
+ assert( false );
+ return NULL;
+} \ No newline at end of file
diff --git a/tools/trackeditor/code/nodes/walllocator.h b/tools/trackeditor/code/nodes/walllocator.h
new file mode 100644
index 0000000..31d114c
--- /dev/null
+++ b/tools/trackeditor/code/nodes/walllocator.h
@@ -0,0 +1,69 @@
+#include "precompiled/PCH.h"
+
+#ifndef WALL_LOCATOR
+#define WALL_LOCATOR
+
+
+#include "main/constants.h"
+
+class tlDataChunk;
+
+class WallLocatorNode : public MPxLocatorNode
+{
+public:
+ WallLocatorNode();
+ ~WallLocatorNode();
+
+ static void* creator();
+
+ virtual void draw( M3dView& view,
+ const MDagPath& path,
+ M3dView::DisplayStyle displayStyle,
+ M3dView::DisplayStatus displayStatus
+ );
+ static MStatus initialize();
+ virtual MStatus legalConnection ( const MPlug & plug, const MPlug & otherPlug, bool asSrc, bool& result ) const;
+ virtual void postConstructor();
+
+ //This is how you export one of these.
+ static tlDataChunk* Export( MObject& wallLocatorNode, tlHistory& history );
+ static bool CalculateNormal( MObject& thisNode, MPoint& nextNodeWP, MVector* normal );
+
+ static MTypeId id;
+ static const char* stringId;
+
+ //Custom to this object.
+ static const char* LEFTRIGHT_NAME_SHORT;
+ static const char* LEFTRIGHT_NAME_LONG;
+ static MObject mLeftRight;
+
+ enum
+ {
+ LEFT,
+ RIGHT,
+ NONE
+ };
+
+ static const char* PREVNODE_NAME_SHORT;
+ static const char* PREVNODE_NAME_LONG;
+ static MObject mPrevNode;
+
+ static const char* NEXTNODE_NAME_SHORT;
+ static const char* NEXTNODE_NAME_LONG;
+ static MObject mNextNode;
+
+ static const char* ID_NAME_SHORT;
+ static const char* ID_NAME_LONG;
+ static MObject mCallbackId;
+
+private:
+
+ static void NodeAboutToDeleteCallback( MDGModifier& modifier, void* data );
+ bool CalculateNormal( MPoint& nextNodeWP, MVector* normal );
+
+ static const int ACTIVE_COLOUR;
+ static const int INACTIVE_COLOUR;
+ static const float SCALE;
+};
+
+#endif \ No newline at end of file
diff --git a/tools/trackeditor/code/precompiled/PCH.cpp b/tools/trackeditor/code/precompiled/PCH.cpp
new file mode 100644
index 0000000..5f77b4a
--- /dev/null
+++ b/tools/trackeditor/code/precompiled/PCH.cpp
@@ -0,0 +1 @@
+#include "PCH.h" \ No newline at end of file
diff --git a/tools/trackeditor/code/precompiled/PCH.h b/tools/trackeditor/code/precompiled/PCH.h
new file mode 100644
index 0000000..f3cc7bf
--- /dev/null
+++ b/tools/trackeditor/code/precompiled/PCH.h
@@ -0,0 +1,68 @@
+#include <maya/M3dView.h>
+#include <maya/MAnimControl.h>
+#include <maya/MArgList.h>
+#include <maya/MAttributeIndex.h>
+#include <maya/MAttributeSpec.h>
+#include <maya/MAttributeSpecArray.h>
+#include <maya/MCursor.h>
+#include <maya/MDagPath.h>
+#include <maya/MDistance.h>
+#include <maya/MDGMessage.h>
+#include <maya/MDGModifier.h>
+#include <maya/MDoubleArray.h>
+#include <maya/MDrawData.h>
+#include <maya/MDrawRequest.h>
+#include <maya/MEulerRotation.h>
+#include <maya/MFnCompoundAttribute.h>
+#include <maya/MFnData.h>
+#include <maya/MFnDagNode.h>
+#include <maya/MFnDependencyNode.h>
+#include <maya/MFnDoubleArrayData.h>
+#include <maya/MFnEnumAttribute.h>
+#include <maya/MFnIkJoint.h>
+#include <maya/MFnIntArrayData.h>
+#include <maya/MFnMatrixData.h>
+#include <maya/MFnMesh.h>
+#include <maya/MFnMessageAttribute.h>
+#include <maya/MFnNumericAttribute.h>
+#include <maya/MFnSingleIndexedComponent.h>
+#include <maya/MFnStringArrayData.h>
+#include <maya/MFnTransform.h>
+#include <maya/MFnTypedAttribute.h>
+#include <maya/MGlobal.h>
+#include <maya/MIntArray.h>
+#include <maya/MItDag.h>
+#include <maya/MItDependencyNodes.h>
+#include <maya/MItMeshVertex.h>
+#include <maya/MItSelectionList.h>
+#include <maya/MMaterial.h>
+#include <maya/MMatrix.h>
+#include <maya/MNodeMessage.h>
+#include <maya/MObject.h>
+#include <maya/MObjectArray.h>
+#include <maya/MPlug.h>
+#include <maya/MPlugArray.h>
+#include <maya/MPoint.h>
+#include <maya/MPointArray.h>
+#include <maya/MPxCommand.h>
+#include <maya/MPxContext.h>
+#include <maya/MPxContextCommand.h>
+#include <maya/MPxGeometryIterator.h>
+#include <maya/MPxLocatorNode.h>
+#include <maya/MPxSurfaceShape.h>
+#include <maya/MPxSurfaceShapeUI.h>
+#include <maya/MQuaternion.h>
+#include <maya/MSelectionList.h>
+#include <maya/MSelectionMask.h>
+#include <maya/MStatus.h>
+#include <maya/MString.h>
+#include <maya/MStringArray.h>
+#include <maya/MTransformationMatrix.h>
+#include <maya/MTime.h>
+#include <maya/MTypeId.h>
+#include <maya/MUiMessage.h>
+#include <maya/MVector.h>
+
+#include "toollib.hpp"
+
+#include <assert.h> \ No newline at end of file
diff --git a/tools/trackeditor/code/scripts/te_BVContext.mel b/tools/trackeditor/code/scripts/te_BVContext.mel
new file mode 100644
index 0000000..e835468
--- /dev/null
+++ b/tools/trackeditor/code/scripts/te_BVContext.mel
@@ -0,0 +1,43 @@
+//-----------------------------------------------------------------------------
+// Copyright (C) 2001 Radical Entertainment Ltd. All rights reserved.
+//
+// te_BVContext.mel
+//
+// Description: Defines all the scripts required by the BVContext tool
+// As a convention all Terrain Editor global procedures
+// and global variables are prefixed with "te_". All commands
+// exposed through TE plugins are prefixed with "TE_".
+//
+// MCB = Menu Call Back
+// BCB = Button Call Back
+//
+// Modification History:
+// + Created -- CBrisebois
+//-----------------------------------------------------------------------------
+
+//This is the global instance of the bv context tool.
+
+global proc te_MCB_StartBVLoop()
+{
+ //Start the BV context...
+ if ( ! `contextInfo -exists BVCtx` )
+ {
+ BVContext BVCtx;
+ }
+
+ setToolTo BVCtx;
+}
+
+global proc te_MCB_SplitSelectedBV()
+{
+ //Call the API function.
+ BVSplitSelected();
+}
+
+global proc te_Delete_BVContext()
+{
+ if ( `contextInfo -exists BVCtx` )
+ {
+ deleteUI -toolContext BVCtx;
+ }
+} \ No newline at end of file
diff --git a/tools/trackeditor/code/scripts/te_IntersectionContext.mel b/tools/trackeditor/code/scripts/te_IntersectionContext.mel
new file mode 100644
index 0000000..54561ff
--- /dev/null
+++ b/tools/trackeditor/code/scripts/te_IntersectionContext.mel
@@ -0,0 +1,212 @@
+//-----------------------------------------------------------------------------
+// Copyright (C) 2001 Radical Entertainment Ltd. All rights reserved.
+//
+// te_IntersectionContext.mel
+//
+// Description: Defines all the scripts required by the IntersectionContext tool
+// As a convention all Terrain Editor global procedures
+// and global variables are prefixed with "te_". All commands
+// exposed through TE plugins are prefixed with "TE_".
+//
+// MCB = Menu Call Back
+// BCB = Button Call Back
+//
+// Modification History:
+// + Created -- CBrisebois
+//-----------------------------------------------------------------------------
+
+//This is the global instance of the bv context tool.
+
+global proc te_MCB_StartIntersection()
+{
+ //Start the Intersection context...
+ if ( ! `contextInfo -exists IntersectionCtx` )
+ {
+ IntersectionContext IntersectionCtx;
+ }
+
+ setToolTo IntersectionCtx;
+}
+
+global string $gSelectedIntersection = "";
+global int $gIntersectionSelectionCallbackID = 0;
+global string $gSelectedName;
+global string $gTypeField;
+global string $gIntersectionTypes[] = { "NoStop", "NWay", "FourWay", "NoStopN", "NWayN" };
+
+global proc te_MCB_EditIntersection()
+{
+ global string $gSelectedName;
+ global int $gIntersectionSelectionCallbackID;
+ global string $gIntersectionTypes[];
+ global string $gTypeField;
+
+ if ( `window -exists TE_InteresctionEditor` )
+ {
+ deleteUI -window TE_IntersectionEditor;
+ }
+
+ window -rtf true -title "TE Road / Intersection Editor" TE_IntersectionEditor;
+
+ columnLayout -adjustableColumn true;
+
+ $gSelectedName = `textField -editable false -text "" -width 170`;
+
+ $gTypeField = `optionMenu -label "Type" -width 170 -changeCommand ("te_MCB_IntersectionTypeChange( \"#1\" )")`;
+
+ int $index;
+ int $size = size($gIntersectionTypes);
+ for ( $index = 0; $index < $size; $index++ )
+ {
+ menuItem -label $gIntersectionTypes[ $index ];
+ }
+ setParent ..;
+
+ button -label "Create Road" -command ( "te_MCB_CreateRoadFromSelected()" );
+ button -label "Show Whole Road" -command ( "te_MCB_ShowRoadFromSelected()" );
+ button -label "Destroy Road" -command ( "te_MCB_DestroyRoadFromSelected()" );
+ button -label "Set Intersection Start" -command ( "te_MCB_AddSelectedIntersectionToRoad( 0 )" );
+ button -label "Set Intersection End" -command ( "te_MCB_AddSelectedIntersectionToRoad( 1 )" );
+ separator;
+ button -label "Create Intersections" -command "te_MCB_StartIntersection()";
+
+ setParent ..;
+
+ showWindow;
+
+ //Create the selection change callback.
+ $gIntersectionSelectionCallbackID = `scriptJob -parent "TE_IntersectionEditor" -event "SelectionChanged" "te_UpdateIntersectionEditor()"`;
+
+}
+
+global proc te_MCB_IntersectionTypeChange( string $value )
+{
+ global string $gSelectedIntersection;
+
+ if ( $gSelectedIntersection != "" )
+ {
+ setAttr ( $gSelectedIntersection + ".IntersectionType" ) -type "string" $value;
+ }
+}
+
+global proc te_CloseIntersectionEditorWindow()
+{
+ global int $gIntersectionSelectionCallbackID;
+
+ if ( `window -exists TE_InteresctionEditor` )
+ {
+ deleteUI -window TE_IntersectionEditor;
+ }
+
+ $gIntersectionSelectionCallbackID = 0;
+}
+
+global proc te_UpdateIntersectionEditor()
+{
+ global string $gSelectedIntersection;
+ global string $gSelectedName;
+ global string $gTypeField;
+ global string $gIntersectionTypes[];
+
+ string $selectedObjects[] = `ls -sl -dag`;
+ string $selectedObjectName = $selectedObjects[0];
+ string $selectedNodeType;
+
+ if ( $selectedObjectName != "" )
+ {
+ //There is something selected
+
+ $selectedNodeType = `nodeType $selectedObjectName `;
+
+ if ( $selectedNodeType == "transform" )
+ {
+ //We don't want the transform, we want the child node.
+ string $children[] = `listRelatives -c $selectedObjectName`;
+ $selectedObjectName = $children[0];
+ }
+
+ if ( $selectedObjectName != "" )
+ {
+ $selectedNodeType = `nodeType $selectedObjectName `;
+
+ if ( $selectedNodeType == "IntersectionLocatorNode" )
+ {
+ //We're in business
+ textField -edit -text $selectedObjectName $gSelectedName;
+
+ string $value = `getAttr ( $selectedObjectName + ".IntersectionType" )`;
+
+ //Which index is this string?
+ int $size = size( $gIntersectionTypes );
+ int $index;
+
+ for ( $index = 0; $index < $size; $index++ )
+ {
+ if ( $gIntersectionTypes[ $index ] == $value )
+ {
+ optionMenu -edit -sl ($index + 1) $gTypeField;
+ break;
+ }
+ }
+
+ if ( $index == $size )
+ {
+ //This node had no proper setting. Resetting it.
+ warning "Node had invalid type setting. Correcting to default type";
+
+ optionMenu -edit -sl 1 $gTypeField;
+ setAttr ( $selectedObjectName + ".IntersectionType" ) -type "string" $gIntersectionTypes[ 0 ];
+ }
+
+ $gSelectedIntersection = $selectedObjectName;
+ return;
+ }
+ else if ( $selectedNodeType == "mesh" )
+ {
+ //This is for adding road to the selected intersection. Do not unselect the intersection.
+ string $whichRoad[] = `listAttr -st teWhichRoad $selectedObjectName`;
+
+ if ( size( $whichRoad ) )
+ {
+ return;
+ }
+ }
+ }
+ }
+
+ textField -edit -text "" $gSelectedName;
+ $gSelectedIntersection = "";
+
+}
+
+
+
+global proc te_MCB_CreateRoadFromSelected()
+{
+ TE_CreateRoad();
+}
+
+global proc te_MCB_ShowRoadFromSelected()
+{
+ TE_ShowRoad();
+}
+
+global proc te_MCB_DestroyRoadFromSelected()
+{
+ TE_DestroyRoad();
+}
+
+global proc te_MCB_AddSelectedIntersectionToRoad( int $isEnd )
+{
+ global string $gSelectedIntersection;
+
+ TE_AddIntersectionToRoad( $gSelectedIntersection, $isEnd );
+}
+
+global proc te_Delete_IntersectionContext()
+{
+ if ( `contextInfo -exists IntersectionCtx` )
+ {
+ deleteUI -toolContext IntersectionCtx;
+ }
+} \ No newline at end of file
diff --git a/tools/trackeditor/code/scripts/te_PPContext.mel b/tools/trackeditor/code/scripts/te_PPContext.mel
new file mode 100644
index 0000000..a8cc63f
--- /dev/null
+++ b/tools/trackeditor/code/scripts/te_PPContext.mel
@@ -0,0 +1,43 @@
+//-----------------------------------------------------------------------------
+// Copyright (C) 2001 Radical Entertainment Ltd. All rights reserved.
+//
+// te_PPContext.mel
+//
+// Description: Defines all the scripts required by the PPContext tool
+// As a convention all Terrain Editor global procedures
+// and global variables are prefixed with "te_". All commands
+// exposed through TE plugins are prefixed with "TE_".
+//
+// MCB = Menu Call Back
+// BCB = Button Call Back
+//
+// Modification History:
+// + Created -- CBrisebois
+//-----------------------------------------------------------------------------
+
+//This is the global instance of the bv context tool.
+
+global proc te_MCB_StartPPLoop()
+{
+ //Start the PP context...
+ if ( ! `contextInfo -exists PPCtx` )
+ {
+ PPContext PPCtx;
+ }
+
+ setToolTo PPCtx;
+}
+
+global proc te_MCB_SplitSelectedPP()
+{
+ //Call the API function.
+ PPSplitSelected();
+}
+
+global proc te_Delete_PPContext()
+{
+ if ( `contextInfo -exists PPCtx` )
+ {
+ deleteUI -toolContext PPCtx;
+ }
+} \ No newline at end of file
diff --git a/tools/trackeditor/code/scripts/te_cleanup.mel b/tools/trackeditor/code/scripts/te_cleanup.mel
new file mode 100644
index 0000000..21f39d3
--- /dev/null
+++ b/tools/trackeditor/code/scripts/te_cleanup.mel
@@ -0,0 +1,12 @@
+te_Delete_TreeLineContext();
+te_Delete_BVContext();
+te_Delete_PPContext();
+te_Delete_IntersectionContext();
+te_CloseIntersectionEditorWindow();
+
+if ( `menu -exists te_MainMenu` )
+{
+ deleteUI te_MainMenu;
+
+ flushUndo;
+}
diff --git a/tools/trackeditor/code/scripts/te_editorwindow.mel b/tools/trackeditor/code/scripts/te_editorwindow.mel
new file mode 100644
index 0000000..1504a52
--- /dev/null
+++ b/tools/trackeditor/code/scripts/te_editorwindow.mel
@@ -0,0 +1,335 @@
+//Constant
+global int $gMAX_LANES = 4;
+
+global string $gSelectedName;
+global string $gOriginField;
+global string $gRoadField;
+global string $gTopField;
+global string $gBottomField;
+global string $gLanesField;
+global string $gShoulderField;
+
+global int $gSelectionScriptJob;
+
+global string $gSelectedObjectName;
+
+global proc teOpenEditorWindow()
+{
+ global string $gSelectedName;
+ global string $gOriginField;
+ global string $gRoadField;
+ global string $gTopField;
+ global string $gBottomField;
+ global string $gLanesField;
+ global string $gShoulderField;
+ global int $gMAX_LANES;
+
+
+ if ( `window -exists TE_TileEditor` )
+ {
+ deleteUI -window TE_TileEditor;
+ }
+
+ window -rtf true -title "TE Tile Editor" TE_TileEditor;
+
+ columnLayout -adjustableColumn true;
+
+ string $selectedRow = `rowLayout -numberOfColumns 3 -columnWidth 1 170`;
+ $gSelectedName = `textField -editable false -text "" -width 170`;
+ string $selectedButton = `button -label "Select Mesh" -command ("teSelectMesh()")`;
+ string $doneButton = `button -label "Done" -command ("teDoneEditingMesh()")`;
+
+ setParent ..;
+
+ string $originRow = `rowLayout -numberOfColumns 2`;
+ string $originButton = `button -label "Set Origin" -command ("teSelectOrigin()")`;
+ $gOriginField = `intField -value -1 -editable false`;
+ setParent ..;
+
+
+ string $roadRow = `rowLayout -numberOfColumns 2`;
+ string $roadButton = `button -label "Set Road Dir" -command ("teSelectRoadDir()")`;
+ $gRoadField = `intField -value -1 -editable false`;
+ setParent ..;
+
+
+ string $topRow = `rowLayout -numberOfColumns 2`;
+ string $topButton = `button -label "Set TOP" -command ("teSelectTOP()")`;
+ $gTopField = `intField -value -1 -editable false`;
+ setParent ..;
+
+
+ string $bottomRow = `rowLayout -numberOfColumns 2`;
+ string $bottomButton = `button -label "Set BOTTOM" -command ("teSelectBOTTOM()")`;
+ $gBottomField = `intField -value -1 -editable false`;
+ setParent ..;
+
+ //The following #1 is a trick that the scripting system converts into the value of the field/control...
+ string $laneRow = `rowLayout -numberOfColumns 2`;
+ string $laneLabel = `text -label "Num. Lanes" -align "center"`;
+ $gLanesField = `intField -value 1 -min 0 -max $gMAX_LANES -step 1 -editable true -changeCommand ("teSetNumLanes(#1)")`;
+ setParent ..;
+
+ $gShoulderField = `checkBox -label "Has Shoulder" -value true -changeCommand ("teSetShoulder(#1)")`;
+
+ setParent ..; //columnLayout
+
+ showWindow;
+}
+
+global proc teCloseEditorWindow()
+{
+ global string $gSelectedName;
+ global string $gOriginField;
+ global string $gRoadField;
+ global string $gTopField;
+ global string $gBottomField;
+ global string $gLanesField;
+ global string $gShoulderField;
+
+ global int $gSelectionScriptJob;
+
+ if ( `window -exists TE_TileEditor` )
+ {
+ deleteUI -window TE_TileEditor;
+ }
+
+ $gSelectedName = "";
+ $gOriginField = "";
+ $gRoadField = "";
+ $gTopField = "";
+ $gBottomField = "";
+ $gLanesField = "";
+ $gShoulderField = "";
+
+ $gSelectionScriptJob = 0;
+}
+
+global proc teSelectMesh()
+{
+ global string $gSelectedName;
+ global int $gSelectionScriptJob;
+ global string $gSelectedObjectName;
+
+ //May want to inform the TrackEditor of this selection if it is good.
+ string $selectedObjects[] = `ls -sl -dag`;
+ string $selectedObjectName = $selectedObjects[0];
+ string $selectedNodeType;
+
+ if ( $selectedObjectName != "" )
+ {
+ //There is something selected
+
+ $selectedNodeType = `nodeType $selectedObjectName `;
+
+ if ( $selectedNodeType == "transform" )
+ {
+ //We don't want the transform, we want the child node.
+ $selectedObjectName = $selectedObjects[1];
+ }
+
+ if ( $selectedObjectName != "" )
+ {
+ $selectedNodeType = `nodeType $selectedObjectName `;
+
+ if ( $selectedNodeType == "mesh" )
+ {
+ //We're in business
+ textField -edit -text $selectedObjectName $gSelectedName;
+
+ teSwitchToVertexSelection( 1 ); //Turn on vertex selection.
+
+ teAddSettingsToObject( $selectedObjectName );
+
+ $gSelectedObjectName = $selectedObjectName;
+
+ teUpdateEditorWindow();
+ }
+ }
+ }
+}
+
+global proc teUpdateEditorWindow()
+{
+ global string $gSelectedName;
+ global string $gOriginField;
+ global string $gRoadField;
+ global string $gTopField;
+ global string $gBottomField;
+ global string $gSelectedObjectName;
+ global string $gLanesField;
+ global string $gShoulderField;
+
+ //Update the fields according to the selected object.
+
+ int $valsSet = false;
+
+ if ( $gSelectedObjectName != "" )
+ {
+ string $attr[] = `listAttr -st teOrigin $gSelectedObjectName`;
+
+ if ( $attr[0] != "" )
+ {
+ textField -edit -text $gSelectedObjectName $gSelectedName;
+
+ float $origin = `getAttr ($gSelectedObjectName + ".teOrigin")`;
+ intField -edit -value $origin $gOriginField;
+
+ float $road = `getAttr ($gSelectedObjectName + ".teRoad")`;
+ intField -edit -value $road $gRoadField;
+
+ float $top = `getAttr ($gSelectedObjectName + ".teTop")`;
+ intField -edit -value $top $gTopField;
+
+ float $bottom = `getAttr ($gSelectedObjectName + ".teBottom")`;
+ intField -edit -value $bottom $gBottomField;
+
+ int $lanes = `getAttr ($gSelectedObjectName + ".teLanes")`;
+ intField -edit -value $lanes $gLanesField;
+
+ int $hasShoulder = `getAttr ($gSelectedObjectName + ".teShoulder")`;
+ checkBox -edit -value $hasShoulder $gShoulderField;
+
+ $valsSet = 1;
+ }
+ }
+
+ if ( !$valsSet )
+ {
+ textField -edit -text "" $gSelectedName;
+
+ intField -edit -value -1 $gOriginField;
+ intField -edit -value -1 $gRoadField;
+ intField -edit -value -1 $gTopField;
+ intField -edit -value -1 $gBottomField;
+ intField -edit -value 0 $gLanesField;
+ checkBox -edit -value false $gShoulderField;
+ }
+}
+
+global proc teSwitchToVertexSelection( int $on )
+{
+ if ( $on )
+ {
+ selectMode -component;
+ selectType -vertex true;
+ }
+ else
+ {
+ selectMode -object;
+ }
+}
+
+global proc teDoneEditingMesh()
+{
+ global string $gSelectedObjectName;
+
+ $gSelectedObjectName = ""; //Clear the selection.
+
+ teSwitchToVertexSelection( 0 ); //Turn on vertex selection.
+
+ teUpdateEditorWindow();
+}
+
+global proc teAddSettingsToObject( string $objectName )
+{
+ string $attr[] = `listAttr -st teOrigin $objectName`;
+
+ if ( $attr[0] == "" )
+ {
+ addAttr -ln teOrigin -sn teO -at long -defaultValue -1 $objectName;
+
+ addAttr -ln teRoad -sn teR -at long -defaultValue -1 $objectName;
+
+ addAttr -ln teTop -sn teT -at long -defaultValue -1 $objectName;
+
+ addAttr -ln teBottom -sn teB -at long -defaultValue -1 $objectName;
+
+ addAttr -ln teLanes -sn teL -at long -defaultValue 1 $objectName;
+
+ addAttr -ln teShoulder -sn teS -at bool -defaultValue true $objectName;
+
+ //This is for connecting to roads
+ addAttr -ln teWhichRoad -sn teWR -at message $objectName;
+
+ //This is a hint of the type
+ addAttr -ln teTypeHint -sn teTH -at long -defaultValue -1 $objectName;
+ }
+}
+
+global proc teSelectOrigin()
+{
+ global string $gSelectedObjectName;
+
+ int $pos = `TE_GetSelectedVertexIndex`;
+
+ if ( $pos >= 0 )
+ {
+ setAttr ( $gSelectedObjectName + ".teOrigin" ) $pos;
+ }
+
+ teUpdateEditorWindow();
+}
+
+global proc teSelectRoadDir()
+{
+ global string $gSelectedObjectName;
+
+ int $pos = `TE_GetSelectedVertexIndex`;
+
+ if ( $pos >= 0 )
+ {
+ setAttr ( $gSelectedObjectName + ".teRoad" ) $pos;
+ }
+
+ teUpdateEditorWindow();
+}
+
+global proc teSelectTOP()
+{
+ global string $gSelectedObjectName;
+
+ int $pos = `TE_GetSelectedVertexIndex`;
+
+ if ( $pos >= 0 )
+ {
+ setAttr ( $gSelectedObjectName + ".teTop" ) $pos;
+ }
+
+ teUpdateEditorWindow();
+}
+
+global proc teSelectBOTTOM()
+{
+ global string $gSelectedObjectName;
+
+ int $pos = `TE_GetSelectedVertexIndex`;
+
+ if ( $pos >= 0 )
+ {
+ setAttr ( $gSelectedObjectName + ".teBottom" ) $pos;
+ }
+
+ teUpdateEditorWindow();
+}
+
+
+global proc teSetNumLanes( int $numLanes )
+{
+ global string $gSelectedObjectName;
+
+ if ( $gSelectedObjectName != "" )
+ {
+ setAttr ( $gSelectedObjectName + ".teLanes" ) $numLanes;
+ }
+}
+
+global proc teSetShoulder( int $hasShoulder )
+{
+ global string $gSelectedObjectName;
+
+ if ( $gSelectedObjectName != "" )
+ {
+ setAttr ( $gSelectedObjectName + ".teShoulder" ) $hasShoulder;
+ }
+} \ No newline at end of file
diff --git a/tools/trackeditor/code/scripts/te_globals.mel b/tools/trackeditor/code/scripts/te_globals.mel
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/tools/trackeditor/code/scripts/te_globals.mel
@@ -0,0 +1 @@
+
diff --git a/tools/trackeditor/code/scripts/te_main.mel b/tools/trackeditor/code/scripts/te_main.mel
new file mode 100644
index 0000000..6a97582
--- /dev/null
+++ b/tools/trackeditor/code/scripts/te_main.mel
@@ -0,0 +1,195 @@
+//-----------------------------------------------------------------------------
+// Copyright (C) 2001 Radical Entertainment Ltd. All rights reserved.
+//
+// TE_main.mel
+//
+// Description: Installs the Terrain Editor (TE) interface.
+// As a convention all Terrain Editor global procedures
+// and global variables are prefixed with "te_". All commands
+// exposed through TE plugins are prefixed with "TE_".
+//
+// MCB = Menu Call Back
+// BCB = Button Call Back
+//
+// Modification History:
+// + Created Apr 11, 2001 -- bkusy
+// + Stolen & Adapted -- CBrisebois
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+// t e _ b r e a k p o i n t
+//
+// Synopsis:
+//
+// Parameters: NONE
+//
+// Returns: NOTHING
+//
+// Constraints: NONE
+//
+//-----------------------------------------------------------------------------
+global proc te_breakpoint( string $tag )
+{
+ confirmDialog -m ( "BreakPoint: " + $tag );
+}
+
+//-----------------------------------------------------------------------------
+// t e _ M C B _ A b o u t
+//
+// Synopsis: Display an About Terrain Editor window.
+//
+// Parameters: NONE
+//
+// Returns: NOTHING
+//
+// Constraints: NONE
+//
+//-----------------------------------------------------------------------------
+global proc te_MCB_About()
+{
+// string $pluginVersion = `te_GetVersion`;
+
+ string $pluginVersion = "2.0";
+
+ string $message = ( "\nSimpsons Road Rage Terrain Editor.\n\n" +
+ "Release " + $pluginVersion + "\n" +
+ "(c) 2001, Radical Entertainment, Ltd.\n\n" );
+
+
+ confirmDialog -title "About Terrain Editor"
+ -message $message
+ -button "OK"
+ -defaultButton "OK";
+}
+
+//-----------------------------------------------------------------------------
+// t e _ d o M a i n M e n u I t e m s
+//
+// Synopsis: Creates the TE menu on the menu handle passed in.
+//
+// Parameters: NONE
+//
+// Returns: NOTHING
+//
+// Constraints: NONE
+//
+//-----------------------------------------------------------------------------
+global proc te_doMainMenuItems( string $menu )
+{
+ menu -edit -tearOff true -allowOptionBoxes true $menu;
+
+ menuItem -label "Bounding Fences" -sm true;
+
+ menuItem -label "Create fence line" -command "te_MCB_StartBVLoop()";
+
+ menuItem -label "Split Fence(s)" -command "te_MCB_SplitSelectedBV()";
+
+ setParent -menu ..;
+
+ menuItem -label "Pedestrian Paths" -sm true;
+
+ menuItem -label "Create path line" -command "te_MCB_StartPPLoop()";
+
+ menuItem -label "Split Path(s)" -command "te_MCB_SplitSelectedPP()";
+
+ setParent -menu ..;
+
+ menuItem -divider true;
+
+ menuItem -label "Track Editor" -sm true;
+
+ radioMenuItemCollection;
+
+ menuItem -label "Off" -radioButton on -command "TE_StateChange(0)";
+
+ menuItem -label "Edit Mode" -radioButton off -command "TE_StateChange(1)";
+
+ menuItem -label "Display Mode" -radioButton off -command "TE_StateChange(2)";
+
+ menuItem -divider true;
+
+ menuItem -label "Create Intersections" -command "te_MCB_StartIntersection()";
+
+ menuItem -label "Edit Roads / Intersections" -command "te_MCB_EditIntersection()";
+
+ setParent -menu ..;
+
+ menuItem -divider true;
+
+ menuItem -label "Tree Line Tool" -allowOptionBoxes true -sm true;
+
+ menuItem -label "Create Tree Lines" -command "te_MCB_CreateTreeLines()";
+
+ menuItem -label "Options" -optionBox true -command "te_MCB_TreelineOptions()";
+
+ menuItem -divider true;
+
+ menuItem -label "Snap Selected Treelines" -command "te_MCB_SnapTreelines()";
+
+ menuItem -divider true;
+
+ menuItem -label "Convert Treelines to Geometry" -command "te_MCB_ConvertToGeometry()";
+
+ setParent -menu ..;
+
+ menuItem -divider true;
+
+ menuItem -label "Export" -command "te_MCB_Export()";
+
+ menuItem -optionBox true -command "TE_ExportOptions()";
+
+ menuItem -divider true;
+
+ menuItem -label "About" -command "te_MCB_About()";
+
+ setParent -m ..;
+}
+
+//-----------------------------------------------------------------------------
+// t e _ I n s t a l l U I
+//
+// Synopsis:
+//
+// Parameters: NONE
+//
+// Returns: NOTHING
+//
+// Constraints: NONE
+//
+//-----------------------------------------------------------------------------
+global proc te_InstallUI()
+{
+
+ global string $gMainWindow;
+
+ //
+ // Install TE menu as a root menu.
+ //
+ if ( `menu -exists te_MainMenu` ) deleteUI te_MainMenu;
+ menu -label "Track Editor" -allowOptionBoxes true -parent $gMainWindow te_MainMenu;
+
+ te_doMainMenuItems "te_MainMenu";
+}
+
+global proc te_MCB_Export()
+{
+ $whichCtx = `currentCtx`;
+
+ if ( $whichCtx != "" )
+ {
+ ctxCompletion;
+ }
+
+ TE_Export();
+}
+
+source "te_globals.mel";
+source "te_setup.mel";
+source "te_BVContext.mel";
+source "te_PPContext.mel";
+source "te_treelineContext.mel";
+source "te_IntersectionContext.mel";
+source "te_editorWindow.mel";
+source "AETEShowRoadSegButton.mel";
+
+evalDeferred "te_InstallUI"; \ No newline at end of file
diff --git a/tools/trackeditor/code/scripts/te_setup.mel b/tools/trackeditor/code/scripts/te_setup.mel
new file mode 100644
index 0000000..d5ca442
--- /dev/null
+++ b/tools/trackeditor/code/scripts/te_setup.mel
@@ -0,0 +1,15 @@
+//Create the TrackEditorNode.
+
+
+global proc te_Create_TrackEditorNode()
+{
+ if ( !(`objExists TrackEditorNode`) )
+ {
+ createNode "transform" -n "TrackEditorNode";
+ createNode "transform" -n "Fences" -p "TrackEditorNode";
+ createNode "transform" -n "Roads" -p "TrackEditorNode";
+ createNode "transform" -n "Intersections" -p "TrackEditorNode";
+ createNode "transform" -n "Treelines" -p "TrackEditorNode";
+ createNode "transform" -n "PedPaths" -p "TrackEditorNode";
+ }
+} \ No newline at end of file
diff --git a/tools/trackeditor/code/scripts/te_treelineContext.mel b/tools/trackeditor/code/scripts/te_treelineContext.mel
new file mode 100644
index 0000000..c8120ab
--- /dev/null
+++ b/tools/trackeditor/code/scripts/te_treelineContext.mel
@@ -0,0 +1,84 @@
+//-----------------------------------------------------------------------------
+// Copyright (C) 2001 Radical Entertainment Ltd. All rights reserved.
+//
+// te_treelineContext.mel
+//
+// Description: Defines all the scripts required by the TreeLineContext tool
+// As a convention all Terrain Editor global procedures
+// and global variables are prefixed with "te_". All commands
+// exposed through TE plugins are prefixed with "TE_".
+//
+// MCB = Menu Call Back
+// BCB = Button Call Back
+//
+// Modification History:
+// + Created -- CBrisebois
+//-----------------------------------------------------------------------------
+
+//This is the global instance of the tree line context tool.
+
+global proc te_MCB_CreateTreeLines()
+{
+ //Start the tree line context...
+ if ( ! `contextInfo -exists TreeLineCtx` )
+ {
+ TreeLineContext TreeLineCtx;
+ }
+
+ setToolTo TreeLineCtx;
+}
+
+global proc te_Delete_TreeLineContext()
+{
+ if ( `contextInfo -exists TreeLineCtx` )
+ {
+ deleteUI -toolContext TreeLineCtx;
+ }
+}
+
+global proc te_MCB_SnapTreelines()
+{
+ TE_SnapSelectedTreelines();
+}
+
+global proc te_MCB_ConvertToGeometry()
+{
+ string $whichCtx = `currentCtx`;
+
+ if ( $whichCtx == "TreeLineCtx" )
+ {
+ ctxAbort;
+ }
+
+ TE_ConvertTreelineToGeometry();
+}
+
+global int $gDeleteTreelines = true;
+
+global proc te_MCB_TreelineOptions()
+{
+ global int $gDeleteTreelines;
+
+ if ( `window -exists TE_TreelineOptions` )
+ {
+ deleteUI -window TE_TreelineOptions;
+ }
+
+ window -rtf true -title "TE Treeline Options" TE_TreelineOptions;
+
+ columnLayout -adjustableColumn true;
+
+ checkBox -label "Delete Treelines" -value $gDeleteTreelines -cc "te_BCB_SetDeleteTreelines(#1)";
+
+ setParent ..;
+
+ showWindow;
+}
+
+global proc te_BCB_SetDeleteTreelines( int $delete )
+{
+ global int $gDeleteTreelines;
+
+ $gDeleteTreelines = $delete;
+ TE_SetDeleteTreeline($delete);
+}