Thursday, March 15, 2012

How I write a MEL script - Overview and Guidelines

Before we get into the code writing process, let's take a look at some simple rules I follow.

The MEL code I write tends to fall into 4 categories:

  1.  Scriptlet - A small piece of code to perform a mundane task that would have required me to press a ton of buttons in Maya. A ton to me is more than two.  Yes, I know writing even the simplest of scriptlets means pressing keys more than twice.  But I keep a repository of scriptlets that I re-use on a daily basis. These tend to be hard-coded and/or selection based in comparison to low-level tools that take user input. 
  2. Low-Level Tool - A stand-alone piece of code that performs a single/few task(s). The bulk of the code I write falls into this category as I tend to write simple tools targeting a narrow task and then collect those tools into a larger, high-level system. 
  3. UI - Similar to the low-level tool, UI code tends to be singular in purpose, but due to callbacks can be semi-complicated involving multiple procs. Personally I have to put myself in an entirely different mindset in order to create an efficient and clear UI.  Also, UI code only makes the UI framework and collects user input then passes that onto the low-level tools that do the actual work, see guideline #6 below.
  4. High-Level Tools - Collecting the low-level tools and UIs into a larger system takes organization and time. Lots of time. This is the stuff that is an integral part of a pipeline.

Aside from a scriptlet, all of my code follows a few guidelines.

  1. I only use global procs.
    Organizationally, I have never seen the need for a local proc. If I am going to write it once, chances are extremely likely that I will use it somewhere else.  
  2. I have a 5 line minimum for procs.
    I think one or two line procs are a waste of time.  The only exception to this is UI callbacks which can be a few lines and are at times unavoidable.
  3. Every global proc has a unique name.
    If I am writing code to mirror a mesh, I will call it tpMeshMirror rather than meshMirror.  The latter is too generic and if the pipeline is large enough, could have been written by someone else.  If I tag my initials, department name, show name, whatever to the front, then I know that there is a good chance no one else has written a proc with the same name.
  4. I use only one string input no matter how many flags the proc needs.
    This one is a bit odd and took a while for me to happen upon and then to follow, so my older code is all over the place.  The idea here is that I can add or subtract flags from the proc and it will not necessarily have to cascade out to anything else that calls it.  If the flags were hard-coded then every call to it would have to change.  It's a little more cumbersome to set it up this way, but I think the payoff is better in the long run.
  5. I always declare default values.
    By declaring defaults, I allow the user to enter an empty string ( remember that I use a single string as input ) and the proc will run and do something.  Also it lets me remember the parameters I intended when I wrote the script.  My memory for code that I've written years ago is pretty porous, so the more information I have to piece together what I was thinking at the time, the better.
  6. UI code is separate from the do-the-work code.
    UI code is not only in it's own global proc, many times I save it as a separate file.  The do-the-work code exists as a fully-functioning command-line procedure that never depends on any UI code to operate.  The UI itself is only widgets: the window, fields, sliders, etc. When the user hits the "go" button, the UI collects the data, optionally does error checking and sends it to the do-the-work proc(s).
  7. All UIs print out usable procedure calls.
    The UI only collects data and sends it to a do-the-work proc.  The collection process involves building a single string ( see guideline #4 ) with optional error checks and evaluating that string,  So rather than eval( $myString ), I do a evalEcho( $myString ).  That way the user can collect the low-level commands and put them into a simple script for re-use.  This is very similar to how Maya operates as it continually prints out what the user is doing in the scriptEditor.

No comments:

Post a Comment