/*---------------------------------------------------------------------- Maya Programming - Lab7 Daniel Loran (2007) ------------------------------------------------------------------------*/ #include // needed to compile on Windows (if you work with Unix remove this include) #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; /*---------------------------------------------------------------- Cock command class PRE: The scene must contain clock hand objects named: hour_hand minute_hand and tic0 object Those need to be selected before command is executed -----------------------------------------------------------------*/ class ClockCmd : public MPxCommand { public: static const int MAX_NUMBER_OF_HOURS_PER_DAY = 99; static const int MIN_NUMBER_OF_HOURS_PER_DAY = 5; static const int MAX_NUMBER_OF_MINUTES_PER_HOUR = 99; static const int MIN_NUMBER_OF_MINUTES_PER_HOUR = 15; virtual MStatus doIt ( const MArgList& ); virtual MStatus undoIt(); virtual MStatus redoIt(); virtual bool isUndoable() const; static void *creator() { return new ClockCmd; } static MSyntax newSyntax(); private: bool isQuery; // is command running in -query or in -edit mode? int prevTime, // = current time in format hhmm as an integer newTime, hours_per_day, // number of hours per day on an alien planet minutes_per_hour; // number of minutes per hour on an alien planet int tic_index; // scene tic objects index MDagPath hourHandPath, minuteHandPath; // paths to hour and minute hand objects MDGModifier dgMod; int getTime(); void setTime(const int time); void setTime(const int time, MDagPath dagPath); void deleteOld(); void createTics(); }; /*---------------------------------------------------------------- Define command syntax and parameters -----------------------------------------------------------------*/ const char *timeFlag = "-t", // time in format hhmm *timeLongFlag = "-time", *hoursFlag = "-h", // number of hours per day on an alien planet *hoursLongFlag = "-hours", *minutesFlag = "-m", // number of minutes per hour on an alien planet *minutesLongFlag = "-minutes"; MSyntax ClockCmd::newSyntax() { MSyntax syntax; syntax.addFlag( timeFlag, timeLongFlag, MSyntax::kLong ); syntax.addFlag( hoursFlag, hoursLongFlag, MSyntax::kLong ); syntax.addFlag( minutesFlag, minutesLongFlag, MSyntax::kLong ); syntax.enableQuery(true); syntax.enableEdit(true); return syntax; } /*---------------------------------------------------------------- Read, check and store command arguments. Set command mode (-query or -edit). Store path to selected hour and minute clock hand objects. PRE: The scene must contain clock hand objects named: hour_hand minute_hand Those need to be selected before command is executed -----------------------------------------------------------------*/ const double PI = 3.1415926535; const double TWOPI = 2.0 * PI; MStatus ClockCmd::doIt ( const MArgList &args ) { // Default values hours_per_day = 12; // Planet Earth number of hours per day minutes_per_hour = 60; // Planet Earth number of minutes per hour // Read and store command arguments MStatus stat; MArgDatabase argData( syntax(), args, &stat ); // Check command args if( !stat ){ // if any of the command args is not valid, the command initialization will fail return stat; } // Set command mode (-query or -edit) isQuery = argData.isQuery(); //cout << "-----------------------------------------" << endl; // in -edit mode check -hours -minutes -time values for certain conditions: if( ( argData.isFlagSet( hoursFlag ) || argData.isFlagSet( minutesFlag ) || argData.isFlagSet( timeFlag ) ) && !isQuery ){ if(!argData.isFlagSet( hoursFlag ) || !argData.isFlagSet( minutesFlag ) || !argData.isFlagSet( timeFlag ) ){ MGlobal::displayError( "-hours -minutes -time are mandatory to set time on alien planet." ); return MS::kFailure; } argData.getFlagArgument( hoursFlag, 0, hours_per_day ); argData.getFlagArgument( minutesFlag, 0, minutes_per_hour ); argData.getFlagArgument( timeFlag, 0, newTime ); if( minutes_per_hour <= hours_per_day ){ MGlobal::displayError( "-minutes value must be larger than -hour value"); return MS::kFailure; } if( minutes_per_hour % hours_per_day != 0 ){ MGlobal::displayError( "-minutes modulo -hour must be equal to 0"); return MS::kFailure; } if( minutes_per_hour < MIN_NUMBER_OF_MINUTES_PER_HOUR || minutes_per_hour > MAX_NUMBER_OF_MINUTES_PER_HOUR ){ MGlobal::displayError( "-minutes is out of range" ); return MS::kFailure; } if( hours_per_day < MIN_NUMBER_OF_HOURS_PER_DAY || hours_per_day > MAX_NUMBER_OF_HOURS_PER_DAY ){ MGlobal::displayError( "-hours is out of range" ); return MS::kFailure; } // Check that -time value is within the boundaries of a given time system int hour = (newTime / 100) % hours_per_day; // set the hour part from -time int minutes = newTime % 100; // set the minutes part from -time if( hour > hours_per_day || minutes > minutes_per_hour ){ MGlobal::displayError( "-time value must be within the boundaries of a given time system"); return MS::kFailure; } } // Get a list of currently selected objects MSelectionList selection; MGlobal::getActiveSelectionList(selection); MDagPath dagPath; MFnTransform transformFn; MString name; // Iterate over the transforms MItSelectionList iter( selection, MFn::kTransform ); for ( ; !iter.isDone(); iter.next() ){ iter.getDagPath( dagPath ); transformFn.setObject( dagPath ); //cout << "dagPath = " << dagPath.fullPathName().asChar() << endl; name = transformFn.name(); if( name == MString("hour_hand") ){ hourHandPath = dagPath; } else if( name == MString("minute_hand") ){ minuteHandPath = dagPath; } } // if hour_hand or minute_hand is not selected show an error if( !hourHandPath.isValid() || !minuteHandPath.isValid() ){ MGlobal::displayError( "Select hour_hand and minute_hand objects" ); return MS::kFailure; } prevTime = getTime(); // if -query mode if( isQuery ){ setResult( prevTime ); return MS::kSuccess; } // if -edit mode return redoIt(); } /*---------------------------------------------------------------- Delete previously created tics if such exist -----------------------------------------------------------------*/ void ClockCmd::deleteOld(){ // delete all tics except the original "tic0" MString sourceObject = "tic0"; tic_index = 1; // scene tic objects index for(int i=0; i < MAX_NUMBER_OF_HOURS_PER_DAY; i++){ MString objName = sourceObject + tic_index; if( MGlobal::selectByName( objName, MGlobal::kReplaceList ) == MS::kSuccess ){ MGlobal::executeCommand( MString( "delete ") + objName ); } else{ //cout << "break on i = " << i << endl; break; } tic_index += 1; } } /*---------------------------------------------------------------- Create tics to disply time in a given time system PRE: the scene must contain a tic0 object -----------------------------------------------------------------*/ void ClockCmd::createTics(){ // create tics according to the given number of hours per day MString sourceObject = "tic0"; tic_index = 1; // scene tic objects index for(int i=0; i < hours_per_day - 1; i++){ MString objName = sourceObject + tic_index; //cout << "sourceObject = " << sourceObject << endl; //cout << "objName = " << objName << endl; MGlobal::executeCommand( MString( "select -replace ") + sourceObject ); MGlobal::executeCommand( MString( "duplicate -returnRootsOnly -name ") + "\"" + objName + "\"" ); // select tic and rotate it MDagPath dagPath; // tic dagPath MSelectionList selection; MGlobal::selectByName( objName, MGlobal::kReplaceList ); MGlobal::getActiveSelectionList( selection ); selection.getDagPath( 0, dagPath ); //cout << "tic dagPath = " << dagPath.fullPathName().asChar() << endl; setTime( (tic_index * 100), dagPath); tic_index += 1; } } /*---------------------------------------------------------------- Redo support -----------------------------------------------------------------*/ MStatus ClockCmd::redoIt(){ setTime( newTime ); deleteOld(); createTics(); return MS::kSuccess; } /*---------------------------------------------------------------- Undo support -----------------------------------------------------------------*/ MStatus ClockCmd::undoIt(){ setTime( prevTime ); deleteOld(); return MS::kSuccess; } /*---------------------------------------------------------------- Calculate and return time in hhmm format, based on the RotationY of hour_hand object -----------------------------------------------------------------*/ int ClockCmd::getTime(){ // Get the time from the rotation MFnTransform transformFn; transformFn.setObject( hourHandPath ); MEulerRotation rot; transformFn.getRotation( rot ); // Determine the time and format it int a = int(-rot.y * ( (hours_per_day * 100) / TWOPI)); int time = (a / 100 * 100) + int( floor( (a % 100) * ( minutes_per_hour / 100.0) + 0.5 ) ); return time; } /*---------------------------------------------------------------- Rotate hour_hand and minute_hand objects to show a given time -----------------------------------------------------------------*/ void ClockCmd::setTime( const int time ){ MFnTransform transformFn; // Calculate the hour and minutes are int hour = (time / 100) % hours_per_day; int minutes = time % 100; // Rotate the hour hand by the required amount transformFn.setObject( hourHandPath ); transformFn.setRotation( MEulerRotation( MVector( 0.0, hour * (-TWOPI / hours_per_day) + minutes * (-TWOPI / (double) (minutes_per_hour * hours_per_day) ), 0 ) ) ); // Rotate the minute hand by the required amount transformFn.setObject( minuteHandPath ); transformFn.setRotation( MEulerRotation( MVector( 0.0, minutes * (-TWOPI / (double) minutes_per_hour), 0 ) ) ); } /*---------------------------------------------------------------- Rotate given object (e.g.: tic) by the required amount (determined by time) -----------------------------------------------------------------*/ void ClockCmd::setTime( const int time, MDagPath dagPath){ MFnTransform transformFn; // Calculate the hour and minutes are int hour = (time / 100) % hours_per_day; // Rotate given object by the required amount transformFn.setObject( dagPath ); transformFn.setRotation( MEulerRotation( MVector( 0.0, hour * (-TWOPI / hours_per_day), 0 ) ) ); } /*---------------------------------------------------------------- in -query mode we must disable undo -----------------------------------------------------------------*/ bool ClockCmd::isUndoable() const { return isQuery ? false : true; } /*---------------------------------------------------------------- Initialize plugin -----------------------------------------------------------------*/ MStatus initializePlugin( MObject obj ){ MFnPlugin plugin( obj, "Daniel Loran", "1.0" ); MStatus stat; stat = plugin.registerCommand( "mplab7", ClockCmd::creator, ClockCmd::newSyntax ); if ( !stat ) stat.perror( "registerCommand failed"); return stat; } /*---------------------------------------------------------------- Uninitialize plugin -----------------------------------------------------------------*/ MStatus uninitializePlugin( MObject obj ){ MFnPlugin plugin( obj ); MStatus stat; stat = plugin.deregisterCommand( "mplab7" ); if ( !stat ) stat.perror( "deregisterCommand failed" ); return stat; }