diff options
Diffstat (limited to 'tools/trackeditor/code')
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); +} |