summaryrefslogtreecommitdiffstats
path: root/tools/trackeditor/code/nodes/road.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/trackeditor/code/nodes/road.cpp')
-rw-r--r--tools/trackeditor/code/nodes/road.cpp409
1 files changed, 409 insertions, 0 deletions
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;
+}
+