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