410 lines
14 KiB
C++
410 lines
14 KiB
C++
#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;
|
|
}
|
|
|