ConstObjectPtr SceneShape::readSceneShapeObject( const MDagPath &p ) { SceneShape *sceneShape = findScene( p, true ); if ( !sceneShape ) { return 0; } MPlug pTime( sceneShape->thisMObject(), aTime ); MTime time; pTime.getValue( time ); double t = time.as( MTime::kSeconds ); return sceneShape->getSceneInterface()->readObject( t ); }
void SceneShapeUI::getDrawRequests( const MDrawInfo &info, bool objectAndActiveOnly, MDrawRequestQueue &requests ) { // it's easy if no one want to look at us if( !info.objectDisplayStatus( M3dView::kDisplayMeshes ) ) { return; } // the node we're meant to be drawing SceneShape *sceneShape = (SceneShape *)surfaceShape(); if( !sceneShape->getSceneInterface() ) { return; } // draw data encapsulating that node MDrawData drawData; getDrawData( sceneShape, drawData ); // a request for the bound if necessary MPlug pDrawBound( sceneShape->thisMObject(), SceneShape::aDrawRootBound ); bool drawBound; pDrawBound.getValue( drawBound ); if( drawBound ) { bool doDrawBound = true; // If objectOnly is true, check for an object. If none found, no need to add the bound request. MPlug pObjectOnly( sceneShape->thisMObject(), SceneShape::aObjectOnly ); bool objectOnly; pObjectOnly.getValue( objectOnly ); if( objectOnly && !sceneShape->getSceneInterface()->hasObject() ) { doDrawBound = false; } if( doDrawBound ) { MDrawRequest request = info.getPrototype( *this ); request.setDrawData( drawData ); request.setToken( BoundDrawMode ); request.setDisplayStyle( M3dView::kWireFrame ); setWireFrameColors( request, info.displayStatus() ); requests.add( request ); } } MPlug pDrawAllBounds( sceneShape->thisMObject(), SceneShape::aDrawChildBounds ); bool drawAllBounds = false; pDrawAllBounds.getValue( drawAllBounds ); // requests for the scene if necessary MPlug pGLPreview( sceneShape->thisMObject(), SceneShape::aDrawGeometry ); bool glPreview; pGLPreview.getValue( glPreview ); if( glPreview || drawAllBounds ) { if( info.displayStyle()==M3dView::kGouraudShaded || info.displayStyle()==M3dView::kFlatShaded ) { // make a request for solid drawing with a material MDrawRequest solidRequest = info.getPrototype( *this ); solidRequest.setDrawData( drawData ); MDagPath path = info.multiPath(); M3dView view = info.view(); MMaterial material = MPxSurfaceShapeUI::material( path ); if( !material.evaluateMaterial( view, path ) ) { MString pathName = path.fullPathName(); IECore::msg( IECore::Msg::Warning, "SceneShapeUI::getDrawRequests", boost::format( "Failed to evaluate material for \"%s\"." ) % pathName.asChar() ); } if( material.materialIsTextured() ) { material.evaluateTexture( drawData ); } solidRequest.setMaterial( material ); // set the transparency request. we don't have a decent way of finding out // if shaders applied by the procedural are transparent, so we've got a transparency // attribute on the procedural holder for users to use. maya materials may also say // they're transparent. if either asks for transparency then we'll ask for it here bool transparent = false; material.getHasTransparency( transparent ); solidRequest.setIsTransparent( transparent ); solidRequest.setToken( SceneDrawMode ); requests.add( solidRequest ); if( info.displayStatus()==M3dView::kActive || info.displayStatus()==M3dView::kLead || info.displayStatus()==M3dView::kHilite ) { MDrawRequest wireRequest = info.getPrototype( *this ); wireRequest.setDrawData( drawData ); wireRequest.setDisplayStyle( M3dView::kWireFrame ); wireRequest.setToken( SceneDrawMode ); setWireFrameColors( wireRequest, info.displayStatus() ); wireRequest.setComponent( MObject::kNullObj ); if ( !objectAndActiveOnly ) { if ( sceneShape->hasActiveComponents() ) { MObjectArray components = sceneShape->activeComponents(); MObject component = components[0]; wireRequest.setComponent( component ); } } requests.add( wireRequest ); } } else { MDrawRequest request = info.getPrototype( *this ); request.setDrawData( drawData ); setWireFrameColors( request, info.displayStatus() ); request.setToken( SceneDrawMode ); request.setComponent( MObject::kNullObj ); if ( !objectAndActiveOnly ) { if ( sceneShape->hasActiveComponents() ) { MObjectArray components = sceneShape->activeComponents(); MObject component = components[0]; request.setComponent( component ); } } requests.add( request ); } } }
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; }