예제 #1
0
/* override */
bool apiSimpleShapeUI::select( MSelectInfo &selectInfo, MSelectionList &selectionList,
					MPointArray &worldSpaceSelectPts ) const
//
// Description:
//
//     Main selection routine
//
// Arguments:
//
//     selectInfo           - the selection state information
//     selectionList        - the list of selected items to add to
//     worldSpaceSelectPts  -
//
{
	bool selected = false;
	bool componentSelected = false;
	bool hilited = false;

	hilited = (selectInfo.displayStatus() == M3dView::kHilite);
	if ( hilited ) {
		componentSelected = selectVertices( selectInfo, selectionList, worldSpaceSelectPts );
		selected = selected || componentSelected;
	}

	if ( !selected ) 
	{
		// NOTE: If the geometry has an intersect routine it should
		// be called here with the selection ray to determine if the
		// the object was selected.

		selected = true;
		MSelectionMask priorityMask( MSelectionMask::kSelectNurbsSurfaces );
		MSelectionList item;
		item.add( selectInfo.selectPath() );
		MPoint xformedPt;
		if ( selectInfo.singleSelection() ) {
			MPoint center = surfaceShape()->boundingBox().center();
			xformedPt = center;
			xformedPt *= selectInfo.selectPath().inclusiveMatrix();
		}

		selectInfo.addSelection( item, xformedPt, selectionList,
								 worldSpaceSelectPts, priorityMask, false );
	}

	return selected;
}
예제 #2
0
bool DrawableHolderUI::select( MSelectInfo &selectInfo, MSelectionList &selectionList, MPointArray &worldSpaceSelectPts ) const
{
	MStatus s;

	// early out if we're not selectable. we always allow components to be selected if we're highlighted,
	// but we don't allow ourselves to be selected as a whole unless meshes are in the selection mask.
	// it's not ideal that we act like a mesh, but it's at least consistent with the drawing mask we use.
	if( selectInfo.displayStatus() != M3dView::kHilite )
	{
		MSelectionMask meshMask( MSelectionMask::kSelectMeshes );
		if( !selectInfo.selectable( meshMask ) )
		{
			return false;
		}
	}

	// early out if we have no scene to draw
	DrawableHolder *drawableHolder = static_cast<DrawableHolder *>( surfaceShape() );
	IECoreGL::ConstScenePtr scene = drawableHolder->scene();
	if( !scene )
	{
		return false;
	}

	// we want to perform the selection using an IECoreGL::Selector, so we
	// can avoid the performance penalty associated with using GL_SELECT mode.
	// that means we don't really want to call view.beginSelect(), but we have to
	// call it just to get the projection matrix for our own selection, because as far
	// as i can tell, there is no other way of getting it reliably.

	M3dView view = selectInfo.view();
	view.beginSelect();
	Imath::M44d projectionMatrix;
	glGetDoublev( GL_PROJECTION_MATRIX, projectionMatrix.getValue() );
	view.endSelect();

	view.beginGL();

		glMatrixMode( GL_PROJECTION );
		glLoadMatrixd( projectionMatrix.getValue() );

		IECoreGL::Selector::Mode selectionMode = IECoreGL::Selector::IDRender;
		if( selectInfo.displayStatus() == M3dView::kHilite && !selectInfo.singleSelection() )
		{
			selectionMode = IECoreGL::Selector::OcclusionQuery;
		}

		std::vector<IECoreGL::HitRecord> hits;
		{
			IECoreGL::Selector selector( Imath::Box2f( Imath::V2f( 0 ), Imath::V2f( 1 ) ), selectionMode, hits );

			IECoreGL::State::bindBaseState();
			selector.baseState()->bind();
			scene->render( selector.baseState() );
		}

	view.endGL();

	if( !hits.size() )
	{
		return false;
	}

	// find the depth of the closest hit:
	MIntArray componentIndices;
	float depthMin = std::numeric_limits<float>::max();
	for( int i=0, e = hits.size(); i < e; i++ )
	{
		if( hits[i].depthMin < depthMin )
		{
			depthMin = hits[i].depthMin;
		}
	}


	// figure out the world space location of the closest hit

	MDagPath camera;
	view.getCamera( camera );
	MFnCamera fnCamera( camera.node() );
	float near = fnCamera.nearClippingPlane();
	float far = fnCamera.farClippingPlane();

	float z = -1;
	if( fnCamera.isOrtho() )
	{
		z = Imath::lerp( near, far, depthMin );
	}
	else
	{
		// perspective camera - depth isn't linear so linearise to get z
		float a = far / ( far - near );
		float b = far * near / ( near - far );
		z = b / ( depthMin - a );
	}

	MPoint localRayOrigin;
	MVector localRayDirection;
	selectInfo.getLocalRay( localRayOrigin, localRayDirection );
	MMatrix localToCamera = selectInfo.selectPath().inclusiveMatrix() * camera.inclusiveMatrix().inverse();
	MPoint cameraRayOrigin = localRayOrigin * localToCamera;
	MVector cameraRayDirection = localRayDirection * localToCamera;

	MPoint cameraIntersectionPoint = cameraRayOrigin + cameraRayDirection * ( -( z - near ) / cameraRayDirection.z );
	MPoint worldIntersectionPoint = cameraIntersectionPoint * camera.inclusiveMatrix();

	MSelectionList item;
	item.add( selectInfo.selectPath() );

	selectInfo.addSelection(
		item, worldIntersectionPoint,
		selectionList, worldSpaceSelectPts,
		MSelectionMask::kSelectMeshes,
		false
	);

	return true;
}
예제 #3
0
bool ProceduralHolderUI::select( MSelectInfo &selectInfo, MSelectionList &selectionList, MPointArray &worldSpaceSelectPts ) const
{
	MStatus s;

	// early out if we're not selectable. we always allow components to be selected if we're highlighted,
	// but we don't allow ourselves to be selected as a whole unless meshes are in the selection mask.
	// it's not ideal that we act like a mesh, but it's at least consistent with the drawing mask we use.
	if( selectInfo.displayStatus() != M3dView::kHilite )
	{
		MSelectionMask meshMask( MSelectionMask::kSelectMeshes );
		if( !selectInfo.selectable( meshMask ) )
		{
			return false;
		}
	}

	// early out if we have no scene to draw
	ProceduralHolder *proceduralHolder = static_cast<ProceduralHolder *>( surfaceShape() );
	IECoreGL::ConstScenePtr scene = proceduralHolder->scene();
	if( !scene )
	{
		return false;
	}
	
	// we want to perform the selection using an IECoreGL::Selector, so we
	// can avoid the performance penalty associated with using GL_SELECT mode.
	// that means we don't really want to call view.beginSelect(), but we have to
	// call it just to get the projection matrix for our own selection, because as far
	// as i can tell, there is no other way of getting it reliably.
	
	M3dView view = selectInfo.view();
	view.beginSelect();
	Imath::M44d projectionMatrix;
	glGetDoublev( GL_PROJECTION_MATRIX, projectionMatrix.getValue() );
	view.endSelect();
	
	view.beginGL();
	
		glMatrixMode( GL_PROJECTION );
		glLoadMatrixd( projectionMatrix.getValue() );
		
		IECoreGL::Selector::Mode selectionMode = IECoreGL::Selector::IDRender;
		if( selectInfo.displayStatus() == M3dView::kHilite && !selectInfo.singleSelection() )
		{
			selectionMode = IECoreGL::Selector::OcclusionQuery;
		}
		
		std::vector<IECoreGL::HitRecord> hits;
		{
			IECoreGL::Selector selector( Imath::Box2f( Imath::V2f( 0 ), Imath::V2f( 1 ) ), selectionMode, hits );
				
			IECoreGL::State::bindBaseState();
			selector.baseState()->bind();
			scene->render( selector.baseState() );
		
			if( selectInfo.displayStatus() != M3dView::kHilite )
			{
				// we're not in component selection mode. we'd like to be able to select the procedural
				// object using the bounding box so we draw it too.
				MPlug pDrawBound( proceduralHolder->thisMObject(), ProceduralHolder::aDrawBound );
				bool drawBound = true;
				pDrawBound.getValue( drawBound );
				if( drawBound )
				{
					IECoreGL::BoxPrimitive::renderWireframe( IECore::convert<Imath::Box3f>( proceduralHolder->boundingBox() ) );
				}
			}
		}
						
	view.endGL();
	
	if( !hits.size() )
	{
		return false;
	}

	// iterate over the hits, converting them into components and also finding
	// the closest one.
	MIntArray componentIndices;
	float depthMin = std::numeric_limits<float>::max();
	int depthMinIndex = -1;
	for( int i=0, e = hits.size(); i < e; i++ )
	{		
		if( hits[i].depthMin < depthMin )
		{
			depthMin = hits[i].depthMin;
			depthMinIndex = componentIndices.length();
		}
		
		ProceduralHolder::ComponentsMap::const_iterator compIt = proceduralHolder->m_componentsMap.find( hits[i].name.value() );
		assert( compIt != proceduralHolder->m_componentsMap.end() );
		componentIndices.append( compIt->second.first );		
	}
	
	assert( depthMinIndex >= 0 );

	// figure out the world space location of the closest hit
	
	MDagPath camera;
	view.getCamera( camera );
	MFnCamera fnCamera( camera.node() );
	float near = fnCamera.nearClippingPlane();
	float far = fnCamera.farClippingPlane();
	
	float z = -1;
	if( fnCamera.isOrtho() )
	{
		z = Imath::lerp( near, far, depthMin );
	}
	else
	{
		// perspective camera - depth isn't linear so linearise to get z
		float a = far / ( far - near );
		float b = far * near / ( near - far );
		z = b / ( depthMin - a );
	}	
	
	MPoint localRayOrigin;
	MVector localRayDirection;
	selectInfo.getLocalRay( localRayOrigin, localRayDirection );
	MMatrix localToCamera = selectInfo.selectPath().inclusiveMatrix() * camera.inclusiveMatrix().inverse();	
	MPoint cameraRayOrigin = localRayOrigin * localToCamera;
	MVector cameraRayDirection = localRayDirection * localToCamera;
	
	MPoint cameraIntersectionPoint = cameraRayOrigin + cameraRayDirection * ( -( z - near ) / cameraRayDirection.z );
	MPoint worldIntersectionPoint = cameraIntersectionPoint * camera.inclusiveMatrix();
	
	// turn the processed hits into appropriate changes to the current selection
				
	if( selectInfo.displayStatus() == M3dView::kHilite )
	{
		// selecting components
		MFnSingleIndexedComponent fnComponent;
		MObject component = fnComponent.create( MFn::kMeshPolygonComponent, &s ); assert( s );
	
		if( selectInfo.singleSelection() )
		{
			fnComponent.addElement( componentIndices[depthMinIndex] );
		}
		else
		{
			fnComponent.addElements( componentIndices );
		}
		
		MSelectionList items;
		items.add( selectInfo.multiPath(), component );
		
		selectInfo.addSelection(
			items, worldIntersectionPoint,
			selectionList, worldSpaceSelectPts,
			MSelectionMask::kSelectMeshFaces,
			true
		);		
	}
	else
	{
		// selecting objects
		MSelectionList item;
		item.add( selectInfo.selectPath() );

		selectInfo.addSelection(
			item, worldIntersectionPoint,
			selectionList, worldSpaceSelectPts,
			MSelectionMask::kSelectMeshes,
			false
		);
	}
	
	return true;
}
예제 #4
0
bool apiSimpleShapeUI::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
	//
	apiSimpleShape* shape = (apiSimpleShape*) surfaceShape();
	MVectorArray* geomPtr = shape->getControlPoints();
	MVectorArray& geom = *geomPtr;


	// Loop through all vertices of the mesh and
	// see if they lie withing the selection area
	//
	int numVertices = geom.length();
	for ( vertexIndex=0; vertexIndex<numVertices; vertexIndex++ )
	{
		const MVector& point = geom[ vertexIndex ];

		// Sets OpenGL's render mode to select and stores
		// selected items in a pick buffer
		//
		view.beginSelect();

		glBegin( GL_POINTS );
		glVertex3f( (float)point[0], 
					(float)point[1], 
					(float)point[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;
}
예제 #5
0
bool SceneShapeUI::select( MSelectInfo &selectInfo, MSelectionList &selectionList, MPointArray &worldSpaceSelectPts ) const
{
	MStatus s;

	// early out if we're not selectable. we always allow components to be selected if we're highlighted,
	// but we don't allow ourselves to be selected as a whole unless meshes are in the selection mask.
	// it's not ideal that we act like a mesh, but it's at least consistent with the drawing mask we use.
	if( selectInfo.displayStatus() != M3dView::kHilite )
	{
		MSelectionMask meshMask( MSelectionMask::kSelectMeshes );
		// Apparently selectInfo.selectable() still returns true when meshes are not
		// displayed by the M3dView, so we are also testing the objectDisplay status.
		// This was last confirmed in Maya 2014, and is presumably a Maya bug.
		if( !selectInfo.selectable( meshMask ) || !selectInfo.objectDisplayStatus( M3dView::kDisplayMeshes ) )
		{
			return false;
		}
	}

	// early out if we have no scene to draw
	SceneShape *sceneShape = static_cast<SceneShape *>( surfaceShape() );
	if( !sceneShape->getSceneInterface() )
	{
		return false;
	}

	IECoreGL::ConstScenePtr scene = sceneShape->glScene();
	if( !scene )
	{
		return false;
	}

	// we want to perform the selection using an IECoreGL::Selector, so we
	// can avoid the performance penalty associated with using GL_SELECT mode.
	// that means we don't really want to call view.beginSelect(), but we have to
	// call it just to get the projection matrix for our own selection, because as far
	// as I can tell, there is no other way of getting it reliably.

	M3dView view = selectInfo.view();
	view.beginSelect();
		Imath::M44d projectionMatrix;
		glGetDoublev( GL_PROJECTION_MATRIX, projectionMatrix.getValue() );
	view.endSelect();
		
	view.beginGL();
	
		glMatrixMode( GL_PROJECTION );
		glLoadMatrixd( projectionMatrix.getValue() );
		
		IECoreGL::Selector::Mode selectionMode = IECoreGL::Selector::IDRender;
		if( selectInfo.displayStatus() == M3dView::kHilite && !selectInfo.singleSelection() )
		{
			selectionMode = IECoreGL::Selector::OcclusionQuery;
		}

		std::vector<IECoreGL::HitRecord> hits;
		{
			IECoreGL::Selector selector( Imath::Box2f( Imath::V2f( 0 ), Imath::V2f( 1 ) ), selectionMode, hits );
				
			IECoreGL::State::bindBaseState();
			selector.baseState()->bind();
			scene->render( selector.baseState() );

			if( selectInfo.displayStatus() != M3dView::kHilite )
			{
				// We're not in component selection mode. We'd like to be able to select the scene shape
				// using the bounding box so we draw it too but only if it is visible
				MPlug pDrawBound( sceneShape->thisMObject(), SceneShape::aDrawRootBound );
				bool drawBound;
				pDrawBound.getValue( drawBound );
				if( drawBound )
				{
					IECoreGL::BoxPrimitive::renderWireframe( IECore::convert<Imath::Box3f>( sceneShape->boundingBox() ) );
				}
			}
		}
						
	view.endGL();
	
	if( hits.empty() )
	{
		return false;
	}
	
	// iterate over the hits, converting them into components and also finding
	// the closest one.
	MIntArray componentIndices;
	
	float depthMin = std::numeric_limits<float>::max();
	int depthMinIndex = -1;
	for( unsigned int i=0, e = hits.size(); i < e; i++ )
	{		
		if( hits[i].depthMin < depthMin )
		{
			depthMin = hits[i].depthMin;
			depthMinIndex = componentIndices.length();
		}
		int index = sceneShape->selectionIndex( IECoreGL::NameStateComponent::nameFromGLName( hits[i].name ) );
		componentIndices.append( index );
	}
	
	assert( depthMinIndex >= 0 );

	// figure out the world space location of the closest hit	
	MDagPath camera;
	view.getCamera( camera );
	
	MPoint worldIntersectionPoint;
	selectionRayToWorldSpacePoint( camera, selectInfo, depthMin, worldIntersectionPoint );

	// turn the processed hits into appropriate changes to the current selection
	if( selectInfo.displayStatus() == M3dView::kHilite )
	{
		// selecting components
		MFnSingleIndexedComponent fnComponent;
		MObject component = fnComponent.create( MFn::kMeshPolygonComponent, &s ); assert( s );
	
		if( selectInfo.singleSelection() )
		{
			fnComponent.addElement( componentIndices[depthMinIndex] );
		}
		else
		{
			fnComponent.addElements( componentIndices );
		}
		
		MSelectionList items;
		items.add( selectInfo.multiPath(), component );
		
		MDagPath path = selectInfo.multiPath();

		selectInfo.addSelection(
			items, worldIntersectionPoint,
			selectionList, worldSpaceSelectPts,
			MSelectionMask::kSelectMeshFaces,
			true
		);
		
	}
	else
	{
		// Check if we should be able to select that object
		MPlug pObjectOnly( sceneShape->thisMObject(), SceneShape::aObjectOnly );
		bool objectOnly;
		pObjectOnly.getValue( objectOnly );
		if( objectOnly && !sceneShape->getSceneInterface()->hasObject() )
		{
			return true;
		}
		
		// selecting objects
		MSelectionList item;
		item.add( selectInfo.selectPath() );

		selectInfo.addSelection(
			item, worldIntersectionPoint,
			selectionList, worldSpaceSelectPts,
			MSelectionMask::kSelectMeshes,
			false
		);
	}
	
	return true;
}