//- // ========================================================================== // Copyright (C) 1995 - 2006 Autodesk, Inc. and/or its licensors. All // rights reserved. // // The coded instructions, statements, computer programs, and/or related // material (collectively the "Data") in these files contain unpublished // information proprietary to Autodesk, Inc. ("Autodesk") and/or its // licensors, which is protected by U.S. and Canadian federal copyright // law and by international treaties. // // The Data is provided for use exclusively by You. You have the right // to use, modify, and incorporate this Data into other products for // purposes authorized by the Autodesk software license agreement, // without fee. // // The copyright notices in the Software and this entire statement, // including the above license grant, this restriction and the // following disclaimer, must be included in all copies of the // Software, in whole or in part, and all derivative works of // the Software, unless such copies or derivative works are solely // in the form of machine-executable object code generated by a // source language processor. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. // AUTODESK DOES NOT MAKE AND HEREBY DISCLAIMS ANY EXPRESS OR IMPLIED // WARRANTIES INCLUDING, BUT NOT LIMITED TO, THE WARRANTIES OF // NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR // PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE, OR // TRADE PRACTICE. IN NO EVENT WILL AUTODESK AND/OR ITS LICENSORS // BE LIABLE FOR ANY LOST REVENUES, DATA, OR PROFITS, OR SPECIAL, // DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES, EVEN IF AUTODESK // AND/OR ITS LICENSORS HAS BEEN ADVISED OF THE POSSIBILITY // OR PROBABILITY OF SUCH DAMAGES. // // ========================================================================== //+ // // Lasso selection within a user defined context. // #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(OSMac_MachO_) #include #include #else #include #include #endif #include #include #include #include #include #include #include #ifdef _WIN32 LPCSTR lassoToolCursor = "lassoToolCursor.cur"; #else #include #include #define lassoToolCursor_x_hot 1 #define lassoToolCursor_y_hot 16 #endif class coord { public: short h; short v; }; extern "C" int xycompare( coord *p1, coord *p2 ); int xycompare( coord *p1, coord *p2 ) { if ( p1->v > p2->v ) return 1; if ( p2->v > p1->v ) return -1; if ( p1->h > p2->h ) return 1; if ( p2->h > p1->h ) return -1; return 0; } ////////////////////////////////////////////// // The user Context ////////////////////////////////////////////// const int initialSize = 1024; const int increment = 256; const char helpString[] = "drag mouse to select points by encircling"; class lassoTool : public MPxContext { public: lassoTool(); virtual ~lassoTool(); void* creator(); virtual void toolOnSetup( MEvent & event ); virtual MStatus doPress( MEvent & event ); virtual MStatus doDrag( MEvent & event ); virtual MStatus doRelease( MEvent & event ); private: void append_lasso( int x, int y ); bool point_in_lasso( coord pt ); coord min; coord max; unsigned maxSize; unsigned num_points; coord* lasso; MGlobal::ListAdjustment listAdjustment; M3dView view; MCursor lassoCursor; }; lassoTool::lassoTool() : maxSize(0) , num_points(0) , lasso(NULL) #ifdef _WIN32 , lassoCursor(lassoToolCursor) #else , lassoCursor(lassoToolCursor_width, lassoToolCursor_height, lassoToolCursor_x_hot, lassoToolCursor_y_hot, lassoToolCursor_bits, lassoToolCursorMask_bits) #endif { setTitleString ( "Lasso Pick" ); // set the initial state of the cursor setCursor(lassoCursor); // Tell the context which XPM to use so the tool can properly // be a candidate for the 6th position on the mini-bar. setImage("lassoTool.xpm", MPxContext::kImage1 ); } lassoTool::~lassoTool() {} void* lassoTool::creator() { return new lassoTool; } void lassoTool::toolOnSetup ( MEvent & ) { setHelpString( helpString ); } MStatus lassoTool::doPress( MEvent & event ) // Set up for overlay drawing, and remember our starting point { // Figure out which modifier keys were pressed, and set up the // listAdjustment parameter to reflect what to do with the selected points. if (event.isModifierShift() || event.isModifierControl() ) { if ( event.isModifierShift() ) { if ( event.isModifierControl() ) { // both shift and control pressed, merge new selections listAdjustment = MGlobal::kAddToList; } else { // shift only, xor new selections with previous ones listAdjustment = MGlobal::kXORWithList; } } else if ( event.isModifierControl() ) { // control only, remove new selections from the previous list listAdjustment = MGlobal::kRemoveFromList; } } else { listAdjustment = MGlobal::kReplaceList; } // Get the active 3D view and set the context // view = M3dView::active3dView(); view.beginGL(); view.beginOverlayDrawing(); // Create an array to hold out lasso points. Assume no mem failures maxSize = initialSize; lasso = (coord*) malloc (sizeof(coord) * maxSize); coord start; event.getPosition( start.h, start.v ); num_points = 1; lasso[0] = min = max = start; return MS::kSuccess; } MStatus lassoTool::doDrag( MEvent & event ) // Add to the growing lasso { coord currentPos; event.getPosition( currentPos.h, currentPos.v ); append_lasso( currentPos.h, currentPos.v ); // clear the overlay planes // view.clearOverlayPlane(); // Set up the orthographic projection matix // glMatrixMode( GL_PROJECTION ); glLoadIdentity(); gluOrtho2D( 0.0, (GLdouble) view.portWidth(), 0.0, (GLdouble) view.portHeight() ); glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); glTranslatef(0.375, 0.375, 0.0); // Set line values // glLineStipple( 1, 0x5555 ); glLineWidth( 1.0 ); glEnable( GL_LINE_STIPPLE ); glIndexi( 2 ); // Draw lasso // glBegin( GL_LINE_LOOP ); for ( unsigned i = 0; i < num_points ; i++ ){ glVertex2i( lasso[i].h, lasso[i].v ); } glEnd(); #ifdef _WIN32 SwapBuffers( view.deviceContext() ); #elif defined (OSMac_) ::aglSwapBuffers(view.display()); #else glXSwapBuffers( view.display(), view.window() ); #endif // _WIN32 glDisable( GL_LINE_STIPPLE ); return MS::kSuccess; } MStatus lassoTool::doRelease( MEvent & /*event*/ ) // Selects objects within the lasso { MStatus stat; MSelectionList incomingList, boundingBoxList, newList; // Clear the overlay plane & restore from overlay drawing view.clearOverlayPlane(); view.endOverlayDrawing(); view.endGL(); // We have a non-zero sized lasso. Close the lasso, and sort // all the points on it. append_lasso(lasso[0].h, lasso[0].v); qsort( &(lasso[0]), num_points, sizeof( coord ), (int (*)(const void *, const void *))xycompare); // Save the state of the current selections. The "selectFromSceen" // below will alter the active list, and we have to be able to put // it back. MGlobal::getActiveSelectionList(incomingList); // As a first approximation to the lasso, select all components with // the bounding box that just contains the lasso. MGlobal::selectFromScreen( min.h, min.v, max.h, max.v, MGlobal::kReplaceList ); // Get the list of selected items from within the bounding box // and create a iterator for them. MGlobal::getActiveSelectionList(boundingBoxList); // Restore the active selection list to what it was before we // the "selectFromScreen" MGlobal::setActiveSelectionList(incomingList, MGlobal::kReplaceList); // Iterate over the objects within the bounding box, extract the // ones that are within the lasso, and add those to newList. MItSelectionList iter(boundingBoxList); newList.clear(); for ( ; !iter.isDone(); iter.next() ) { MDagPath dagPath; MObject component; MPoint point; coord pt; MObject singleComponent; iter.getDagPath( dagPath, component ); if (component.isNull()) continue; // not a component switch (component.apiType()) { case MFn::kCurveCVComponent: { MItCurveCV curveCVIter( dagPath, component, &stat ); for ( ; !curveCVIter.isDone(); curveCVIter.next() ) { point = curveCVIter.position(MSpace::kWorld, &stat ); view.worldToView( point, pt.h, pt.v, &stat ); if (!stat) { stat.perror("Could not get position"); continue; } if ( point_in_lasso( pt ) ) { singleComponent = curveCVIter.cv(); newList.add (dagPath, singleComponent); } } break; } case MFn::kSurfaceCVComponent: { MItSurfaceCV surfCVIter( dagPath, component, true, &stat ); for ( ; !surfCVIter.isDone(); surfCVIter.next() ) { point = surfCVIter.position(MSpace::kWorld, &stat ); view.worldToView( point, pt.h, pt.v, &stat ); if (!stat) { stat.perror("Could not get position"); continue; } if ( point_in_lasso( pt ) ) { singleComponent = surfCVIter.cv(); newList.add (dagPath, singleComponent); } } break; } case MFn::kMeshVertComponent: { MItMeshVertex vertexIter( dagPath, component, &stat ); for ( ; !vertexIter.isDone(); vertexIter.next() ) { point = vertexIter.position(MSpace::kWorld, &stat ); view.worldToView( point, pt.h, pt.v, &stat ); if (!stat) { stat.perror("Could not get position"); continue; } if ( point_in_lasso( pt ) ) { singleComponent = vertexIter.vertex(); newList.add (dagPath, singleComponent); } } break; } case MFn::kMeshEdgeComponent: { MItMeshEdge edgeIter( dagPath, component, &stat ); for ( ; !edgeIter.isDone(); edgeIter.next() ) { point = edgeIter.center(MSpace::kWorld, &stat ); view.worldToView( point, pt.h, pt.v, &stat ); if (!stat) { stat.perror("Could not get position"); continue; } if ( point_in_lasso( pt ) ) { singleComponent = edgeIter.edge(); newList.add (dagPath, singleComponent); } } break; } case MFn::kMeshPolygonComponent: { MItMeshPolygon polygonIter( dagPath, component, &stat ); for ( ; !polygonIter.isDone(); polygonIter.next() ) { point = polygonIter.center(MSpace::kWorld, &stat ); view.worldToView( point, pt.h, pt.v, &stat ); if (!stat) { stat.perror("Could not get position"); continue; } if ( point_in_lasso( pt ) ) { singleComponent = polygonIter.polygon(); newList.add (dagPath, singleComponent); } } break; } default: #ifdef DEBUG cerr << "Selected unsupported type: (" << component.apiType() << "): " << component.apiTypeStr() << endl; #endif /* DEBUG */ continue; } } // Update the selection list as indicated by the modifier keys. MGlobal::selectCommand(newList, listAdjustment); // Free the memory that held our lasso points. free(lasso); lasso = (coord*) 0; maxSize = 0; num_points = 0; return MS::kSuccess; } void lassoTool::append_lasso( int x, int y ) { int cy, iy, ix, ydif, yinc, i; float fx, xinc; iy = (int)lasso[num_points-1].v; ix = (int)lasso[num_points-1].h; ydif = abs( y - iy ); if ( ydif == 0 ) return; // Keep track of smallest rectangular area of the screen that // completely contains the lasso. if ( min.h > x ) min.h = x; if ( max.h < x ) max.h = x; if ( min.v > y ) min.v = y; if ( max.v < y ) max.v = y; if ( ((int)y - iy ) < 0 ) yinc = -1; else yinc = 1; xinc = (float)((int)x - ix)/(float)ydif; fx = (float)ix + xinc; cy = iy + yinc; for ( i = 0; i < ydif; i++ ) { if ( num_points >= maxSize ) { // Make the array of lasso points bigger maxSize += increment; lasso = (coord*) realloc (lasso, sizeof(coord) * maxSize); // Assume no mem failures } lasso[num_points].h = (short) fx; lasso[num_points].v = cy; fx += xinc; cy += yinc; num_points++; } return; } bool lassoTool::point_in_lasso( coord pt ) { unsigned i, sides; for ( i = 0; i < num_points; i++ ) { if ( lasso[i].v == pt.v ) { while ( (lasso[i].v == pt.v ) && (lasso[i].h < pt.h) ) i++; if ( lasso[i].v != pt.v ) return( false ); sides = 0; i++; while ( lasso[i].v == pt.v ) { i++; sides++; } if ( sides % 2 ) return( false ); else return( true ); } } return( false ); } ////////////////////////////////////////////// // Command to create contexts ////////////////////////////////////////////// class lassoContextCmd : public MPxContextCommand { public: lassoContextCmd() {}; virtual MPxContext* makeObj(); static void* creator(); }; MPxContext* lassoContextCmd::makeObj() { return new lassoTool; } void* lassoContextCmd::creator() { return new lassoContextCmd; } ////////////////////////////////////////////// // plugin initialization ////////////////////////////////////////////// MStatus initializePlugin( MObject obj ) { MStatus status; MFnPlugin plugin( obj, PLUGIN_COMPANY, "3.0", "Any"); status = plugin.registerContextCommand( "lassoToolContext", lassoContextCmd::creator ); if (!status) { status.perror("registerContextCommand"); return status; } // set the mel scripts to be run when the plugin is loaded / unloaded status = plugin.registerUI("lassoToolCreateUI", "lassoToolDeleteUI"); if (!status) { status.perror("registerUIScripts"); return status; } return status; } MStatus uninitializePlugin( MObject obj ) { MStatus status; MFnPlugin plugin( obj ); status = plugin.deregisterContextCommand( "lassoToolContext" ); return status; }