Monday, March 19, 2012

How I write a MEL script - Template

Most scripts that I write, except the tiny scriptlets, all follow a template.


The Description
The the very top of the file containing N number of procs, I will generally NOT write a description.  Why?  I could say it's not from laziness or poor code writing, but I would be lying.  Personally I feel that a proc name should describe it's functionality, plus if you provide defaults anyone should be able to decipher what the proc does and how to use it.  But really I should write a brief description and some simple use examples.

The Proc Name and Input
Very simple.
global proc (return if any) myProcName( string $input ) {

Breakdown of the proc line:
  • global proc - I only use global procs.
  • return - Depends on what I'm writing and how it's intended to communicate with other code.  I often use returns.  Generally I'll name my variable $return that way I can find it in any script.
  • myProcName - I use the "camel" naming convention.  This comes from a studio-wide naming convention.  The "my" is either my initials or my department name.  The rest is descriptive but brief.  I try to put a category first so similar code can be found easily.  For example if writing a skin cluster mirror and a skin cluster copy script, I will call them spaSkinClusterMirror and spaSkinClusterCopy.  When I list the contents of the directory, my two skin cluster scripts will show up next to one another.
  • string $input - I use only a single input, no matter how many flags will be needed.  While it is more work to set it up this way, but not too bad with a template, this gives me great flexibility to add/subtract/change flags, especially in subsequent calls.  Hard-coding flags forces you to enter ALL the flags in a precise order, even if you want either the defaults or to ignore the flag.  The reason I decided to go this route is based on how Maya handles their commands.  The command sphere has 17 possible flags, but the user can input sphere; and get a sphere with all the defaults, or they can add as many flags as they wish in any order for a customized sphere.  Plus, when I look at an input, I can roughly tell what the input was supposed to be.  myRandomProc( "-geo poly1 -radius 10.0 -spans 10" ); is much more informative than myRandomProc( "poly1", 10.0, 10 );  Once you start writing lots of code, the more you can tell yourself what you were doing and what you should be inputting the better.
Template Code Block
global proc (return if any) myProcName( string $input ) {
    /*

    // this is where I put in test inputs
    // so I can run examples through the parser below
    string $input = "-something blah -value 10.5 -flag 0";
    */

    // init variables - the defaults

    // anything that the user is intended to input 
    // gets a default at the top
    string $something = "";
    float $value      = 1.0;
    int $flag         = 1; 


    // parse the input
    string $buffer[]; // holds the input array
    // break apart the input into an array
    int $tok = tokenize( $input, " ", $buffer );
    // iterate through all the pieces of the input
    for( $t=0;$t<$tok;$t++ ) {
        // use switch to look at each piece with case statements
        switch( $buffer[$t] ) {
            // the flag names match the variable names
            case "-something":
                $t++; // we found a case, so increment the counter
                $something = $buffer[$t]; // put it into a variable
                break; // go to the top of the loop
            case "-value":
                $t++; // we found a case, so increment the counter
                // notice how I don't have to re-class
                // the input as a float.
                $value = $buffer[$t]; // put it into a variable
                break; // go to the top of the loop
            case "-flag":
                $t++; // we found a case, so increment the counter
                // notice how I don't have to re-class
                // the input as an int.
                $flag = $buffer[$t]; // put it into a variable
                break; // go to the top of the loop
            // case default: // I never do this
        } // end input switch
    } // end input parse

    // error check  the input
    // do the work
}


No comments:

Post a Comment