summaryrefslogtreecommitdiffstats
path: root/tools/trackeditor/code/nodes/treelineshapenode.cpp
diff options
context:
space:
mode:
authorSvxy <aidan61605@gmail.com>2023-05-31 23:31:32 +0200
committerSvxy <aidan61605@gmail.com>2023-05-31 23:31:32 +0200
commiteb4b3404aa00220d659e532151dab13d642c17a3 (patch)
tree7e1107c4995489a26c4007e41b53ea8d00ab2134 /tools/trackeditor/code/nodes/treelineshapenode.cpp
downloadThe-Simpsons-Hit-and-Run-eb4b3404aa00220d659e532151dab13d642c17a3.tar
The-Simpsons-Hit-and-Run-eb4b3404aa00220d659e532151dab13d642c17a3.tar.gz
The-Simpsons-Hit-and-Run-eb4b3404aa00220d659e532151dab13d642c17a3.tar.bz2
The-Simpsons-Hit-and-Run-eb4b3404aa00220d659e532151dab13d642c17a3.tar.lz
The-Simpsons-Hit-and-Run-eb4b3404aa00220d659e532151dab13d642c17a3.tar.xz
The-Simpsons-Hit-and-Run-eb4b3404aa00220d659e532151dab13d642c17a3.tar.zst
The-Simpsons-Hit-and-Run-eb4b3404aa00220d659e532151dab13d642c17a3.zip
Diffstat (limited to 'tools/trackeditor/code/nodes/treelineshapenode.cpp')
-rw-r--r--tools/trackeditor/code/nodes/treelineshapenode.cpp1343
1 files changed, 1343 insertions, 0 deletions
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
+
+