diff options
Diffstat (limited to 'tools/trackeditor/code/nodes/treelineshapenode.cpp')
-rw-r--r-- | tools/trackeditor/code/nodes/treelineshapenode.cpp | 1343 |
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 + + |