Friday, March 20, 2009

Yoono

Just discovered a nifty add-on for Firefox: Yoono.  It sits in a thin sidebar in the main window, and lets me hook up to pretty much everything: chat, social sites, RSS feeds, etc.  I'm even writing and posting this blog entry from it.  Pretty slickaroonie, I must say.  :)

All right, enough geekin'.  For now, anyway. ;)

Wednesday, March 18, 2009

Changing styles, changing times

Imagine if the Merrie Melodies short "One Froggy Evening" were created by today's animation production system. It's very possible that it would turn out very differently, as one blogger speculates via a series of hypothetical notes that might come back from a review session with today's content critics.

What do you think? Do you think that the creation of such a film today is likely to generate that kind of response...that kind of over-analyzation of details that, in the end, really don't matter because it's all fantasy?

At some level, I feel that we are excessively critical with some of the things we create in the name of entertainment. Even in the realm of animation, we don't always allow ourselves to let go and let loose, to just let certain things be nonsensical and come out of left field. Why not?

Think about this: if that film were made as a live-action story (with a CG frog, naturally), matching the appropriate details of the animated version as closely as possible, how would we feel about it? Would we be as willing to accept the presented absurdities and disregard certain glossed-over details like we do with the animated presentation?

I don't know that there are any firm answers, but I've got some thoughts. It's late, though, and I need my beauty sleep (yeah, right....like it's done me much good so far!). More postulating to come later...

Wednesday, February 25, 2009

Maya and Python lambdas, part 3

A thought occurred to me this morning before coming into work. I was still thinking that there had to be some way of further improving my use of lambdas in Maya GUI creation. Then it hit me: assign the data from the loop as a default value for one of the lambda's arguments!

import maya.cmds as mc

def showStuff (stuff):
print "You've given me %s!" % stuff

stuffList = ["an apple", "a pear", "a pickle"]
mc.window("Stuff to Give", w=300, h=200)
cl = columnLayout()
for item in stuffList:
mc.button(l=item, c=lambda x, i=item:showStuff(i))

Look, ma...no lambda factory! :) Here's my guess as to why this works when it doesn't work to put the variable "inside" the lambda...

By stuffing a variable into the function/method call inside the lambda function, it appears that the value of the variable isn't retrieved until the lambda function is executed. For a variable defined by a loop, this means that the variable value is the same as it was during the last iteration through the loop.

However, by taking a variable and assigning it as the default for one of the lambda's arguments, the value assigned to that variable is retrieved and stored in the lambda function definition. When called by Maya when the appropriate GUI element is used, the lambda function already has that value, and knows to pass it as the default for the appropriate argument. Because no other data is passed to replace it, it can be used reliably inside the function as part of the real function call we want to make.

The only thing to keep in mind when using this technique is the extra data that Maya passes on its own, which is caught (and promptly ignored) in the example above by the x argument.

Clean and simple. Me likey.

Tuesday, February 24, 2009

More Lambda and GUI fun

Just tripped over an interesting problem with the lambda stuff I shared in the last post. It's just peachy if you're passing a literal value:

# other code omitted for brevity
mc.button(l="click me", c=lambda x:colorMe("Purple"))

However, if you're creating a collection of controls using a loop, it no worky correctly:

names = ["me", "you", "him"]
for name in names:
mc.button(l=name, c=lambda x:nameMe(name)

In this example, no matter which button you click, it will pass "him".

I tried a number of ways to get around this, and wasn't successful until I revisited the page that flipped the lambda light switch for me. The second example on that page shows how to create a "lambda factory" of sorts. In the context of the loop situation, the factory serves to isolate the creation of the lambda function from the loop. While the factory function was a standalone item in the example on that page, it would be convenient to nest said factory inside the same function/method that contains the loop. Here's a more fleshed-out example:

import maya.cmds as mc

def addButtons (names):
# here's the factory function
def factory (nm):
return lambda x:showName(nm)

# and here's our loop
for name in names:
mc.button(l=name, c=factory(name))

It's a bit more extra code than I'd hoped for, but it's only needed when using the lambda technique inside a loop, and still allows me to keep the target functions/methods clean by avoiding nesting.

Monday, February 23, 2009

Python Lambdas and Maya GUIs

I love epiphanies. :)

For some reason, I haven't been able to figure out "lambda" functions in Python. Granted, I've not put a great deal of time into them. It's just that whenever I would see them in someone else's code, I couldn't immediately figure out what they were doing, so I'd just add another mark next to the "Need to research lambdas" entry in my mental to-do list and move along. To make a long story short, I ran across a page today that flipped the light switch on lambdas. But that's not the epiphany of which I speak. The epiphany hit when I began trying to figure out what (if anything) I could do with those lovely little lambdas in my Python programming at work.

Most of my development work involves the creation of tools with some kind of graphical user interface (GUI). When assigning a command to a Maya GUI element in Python, it expects either a string that contains some Python code to execute, or a pointer to a function or method that will be called. In the vast majority of situations, I'll use the latter option. If I don't need to pass any data to the target function, there's no problem, and Maya gets the function pointer as expected:

import maya.cmds as mc

def blah(*args):
# "*args" is required because even though the
# command doesn't pass any data, Maya passes
# some anyway. Go figure...
print "You touched me!"

mc.window(w=500, h=500)
mc.columnLayout()
mc.button(l="Touch!", c=blah)
mc.showWindow()

However, in most of the GUIs that I create, some control will need to pass specific data to the function that it calls. The problem is that once you include parentheses to pass data to the function, Maya is no longer getting a function pointer. It's getting the value (if any) returned by the called function, or None if the function doesn't return anything.

Up until now, I've been using nested functions to get around this problem. By defining and returning a "dummy" function inside the main function that is called by the GUI element, Maya will get the function pointer it wants, and I can pass in any data that I please:

import maya.cmds as mc

def blah(value):
def b(*args):
# "*args" is still required because this is the
# function that Maya will ultimately call when
# the button is pushed
print "I was given:", value
return b

mc.window(w=500, h=500)
mc.columnLayout()
mc.button(l="Touch!", c=blah(10))
mc.showWindow()

This process has been working fine, but in the back of my mind, I kept hoping to find a more elegant solution.

Enter my new friend: the lambda!

After some experimentation, I learned two very helpful things about lambdas. The first is that the expression evaluated by a lambda doesn't necessarily have to have any connection to the data it is passed. For example, a "normal" lambda definition might look something like this:

x = lambda y: y * 2

In this case, calling x(5) will return 10 (the 5 gets passed to y, when is then evaluated through the expression y*2 to yield 10, which is then returned). However, the expression can be changed to return something that has nothing to do with the value passed in through y, like so:

x = lambda y: 15

In this case, no matter what value you pass, 15 will always be returned.

Based on this example alone, I can already begin to use lambdas to simplify my example code above. (It's simpler on the function definition side of things because we get rid of the nesting issue, but some might see the syntax of assigning the desired function call to the GUI element a tad more confusing.)

import maya.cmds as mc

def blah(value):
print "I was given:", value

mc.window(w=500, h=500)
mc.columnLayout()
mc.button(l="Touch!", c=lambda x:blah(10))
mc.showWindow()

What happens is that the mystery-data passed by Maya gets assigned to x in the lambda definition, but we don't need to use it. All we need is to call our function with the desired value.

For some GUI elements, though, the data passed by Maya is actually useful. Take an intSlider, for example:
import maya.cmds as mc

def blah(value):
print "The slider value is", value

mc.window(w=500, h=500)
mc.columnLayout()
mc.intSlider(dragCommand=lambda x:blah(int(x)))
mc.showWindow()

In this situation, the data passed by Maya when dragging the slider is the slider's value. However, it's passed as a Unicode string, so I just converted it to an integer before passing it to the function. This means I don't have to query the slider, as the data I need has already been passed.

Some GUI operations, like dragging and dropping, pass more than one argument to the target function. No matter...just provide the requisite number of arguments in the lambda definition (i.e. lambda w,x,y,z: ....) and pass them along to the target function as desired. Or, as in one particular case where I wanted to substitute my own data in place of what the drag operation passed, you can take advantage of the other nifty thing I learned through my experiments: a lambda can accept arbitrary argument lists, just like normal functions.

# other GUI code here
mc.button(l="blah, dragCallback=lambda *x:boo(myData))


That's all for now. Happy Python GUI building!

Monday, February 16, 2009

Hardware woes, begone!

Okay, I think I've finally finished fiddling with this finicky figurer (the only synonym for "computer" that I could find that started with F).

After my last post, I ran across some other info that said that the power supply might be to blame, and I began seeing other evidence to support that theory. Shortly thereafter the computer just refused to boot, so I had to do something. With the exception of the first item below, most of my attempted somethings were done this past Saturday...
  • Bought a beefier power supply. Still nothing.
  • Bought a new motherboard. Got it home and found that it didn't have enough slots to take all my existing RAM sticks.
  • Exchanged the motherboard for a newer one that required a new CPU (picked a nice energy-efficient dual-core). Got home and found that the location of all the externals (keyboard and audio hookups, plus the location of the PCI slots) wouldn't work with my case.
  • Trekked to Best Buy for a new case. I was tired of messing with hardware, so I paid them to move all the guts from the old box to the new one while we went and had a nice Valentine's Day family dinner.
  • Came back a few hours later to find that my old RAM wouldn't work with the new motherboard, and that the board only had one IDE connector, so the DVD drive had no place to connect. Bought new RAM and a new SATA DVD drive, and had the Geek Squad install both. Brought everything home.
  • Nothing booted. Found that the hard drives were connected in the wrong order. Had to swap their positions in the case because of the awkwardness of the IDE cable.
  • Found that the DVD drive wasn't being recognized because it was connected to the wrong SATA connector on the motherboard.
  • Booted into BIOS, set everything up, then started to boot into Windows. Had to re-authorize Windows, which ended up taking several phone calls to MS. Thankfully I brought the old machine home, or I would not have had access to the product key label that was conveniently stuck to the back of the case.
Based on information that I read in some of the articles I found online after the last post, I thought that I would have to run a repair install of Windows in order to get it to play nice with the new hardware. Once the re-authorization was finished, though, Windows booted up without any issues and just started bugging me about all the new hardware it was finding. I haven't had any BSOD's or any noticeable system hiccups.

In the end, all this hardware futzing cost about the same as (or more likely more than) a new MAChine (*ahem*), and in the end I wound up with essentially a new machine, so I guess it kinda served its purpose. Our key concern was getting access to all the data on my hard drives again (especially financial data). It also got us thinking about where we want some of said data to reside for better long-term, computer-independent access.

So there we go! Done!



I hope!

Monday, January 05, 2009

Most definitely NOT the monitor

In the ongoing fight to get my desktop system fully functional again, I feel I've pretty much eliminated monitor problems from the equation. I just finished two quick tests. I moved the monitor to my wife's machine and hooked it up via the DVI input. No problem. I then moved it back to my machine, pulled out the new graphics card, and ran the motherboard's on-board VGA output to the monitor's VGA input. No problem. In fact, I'm using that VGA hookup now, which is the first time I've been able to use the desktop for the past several days.

All signs at this point are aiming squarely at the motherboard, and specifically the PCI Express slot in which the video card sits. The rest of the board seems to be working fine, as my presence here (hopefully) indicates. While it's nice to have a fairly solid target at which to direct my next efforts, it's not the target I wanted. If it were the monitor or video card, it wouldn't be much of an issue. Get a new one, plug it in. With the video card, there would be drivers to install, but that's still a piece of cake compared to the work involved when swapping motherboards.

A new board typically means reinstalling Windows from scratch. At least that's what it used to mean. However, I just found a couple web pages that have detailed instructions on how to swap motherboards without affecting Windows. It's still more work than installing a new video card or monitor, but much less work than a full re-install.

So....here we go!

Sunday, January 04, 2009

Curse on Apple lifted....for now

Wouldn't you know it....I found a solution not five minutes after that last post:

Import the photos into iPhoto. Then go back to iMovie and drag the photos in from the iPhoto library.

But seriously...that's still a few steps too many. They should "just work" (famous last words, Apple) when dragging the photos in from the Finder, no?

The day I curse Apple

That day is today.

I don't know why they did this, but in iMovie HD, all vertically-oriented photos get rotated back to horizontal orientation, and there is NO way provided in the software to rotate them back.

Sure, I could import them into a photo editor, lay them over a horizontal black background, save them out, then pull them back into iMovie....but come on. I just wanna make a stinkin' slideshow with some videos intercut here and there. What happened to the ease of use that they keep touting in all their ads?

I could've sworn that I used some vertical shots in a movie project a while ago, but for the life of me I can't remember how/if I pulled it off, and an hour (or more) of Googling has not yet led me to a solution.

That said, the evening wasn't a total waste. I did manage to develop a headache! Thanks, Apple!

Saturday, January 03, 2009

Third time's a (very frustrating) charm

This is just getting more annoying all the time. My initial tests led me to think it was the monitor, but later I was able to get the monitor to work with the laptop, so I thought it had to be the video card. Now I've got a brand new video card, but I still have no image from the desktop machine, and the laptop still works just fine with it. So where does that take me next? The motherboard. Ugh...

I think I'm going to see if I can get the motherboard's on-board video to work. If so, then my guess is that it would mean that something tied to the PCI Express slot is messed up.

However, that still doesn't explain why my wife's monitor worked fine with my computer in one of my earliest tests. I think I'll try that one again as well. If that still works....well, I'll be completely stumped.

NOT the monitor!

Looks like I typed that last entry too soon. While things worked okay last night, I got absolutely no signal this morning. After more cable wiggling, more detaching and reattaching, and more under-the-desk spelunking, I decided to try plugging my Mac laptop into the monitor. Bingo! Beautiful picture...and it was via the DVI input. After all the other tests, that could only mean one thing:

I've got a dead video card.

Oh joy....

(BTW...absolutely meaningless bonus points for those who can decipher the slightly cryptic reference in this post's title. Think early 90's TV...)

Friday, January 02, 2009

Minor Monitor Mayhem

I seem to have this thing with monitors. About a year-and-a-half ago, my trusty CRT died on me in the middle of a live Q&A with my Animation Mentor class. That paved the way for the purchase of the current widescreen LCD monitor, which was humming along just fine...up until this morning.

I powered the computer on, fiddled around for a half-hour or so, then hit the sleep button on the keyboard before heading off to shower. Upon returning a little later, I hit the space bar on the keyboard to wake up the machine. The computer woke up, but the monitor didn't.

At first I thought it might just be a really long delay while the system was processing something before it would fire up the video signal. It had occasionally behaved that way in the past, but after a minute or so of no picture, I figured something else was amiss, so I started testing things. Cable wiggling got me nowhere. Borrowing my wife's monitor (identical to mine...the result of one of those "as long as you're replacing yours, would you mind getting a new one for me?" requests) and plugging it into my box gave me a good picture. That told me that the video card and cable were probably fine, but that the DVI input on my monitor was probably dead, so after work I bought the necessary accoutrements to use the SVGA input, and it doth work again. Yea, verily! Glad to know it's not a total goner. The SVGA signal doesn't look horrible, but it is a tad blurry. Still, I'll gladly sacrifice a little clarity in order to save some dough.

I hope everyone had a great Christmas, and wish you all the best in 2009!

Friday, December 19, 2008

Lights up, claws out!

I was watching a movie recently with some friends. I had really enjoyed the film -- much more than I expected that I would going into it -- and was eager to discuss it with my friends after it was over. The credits rolled, the lights came up, and folks started talking.

Not one single positive comment was made.

To their credit, they weren't being venomous or vicious with their comments, and I agreed with some of what they were saying. Still, I had hoped that someone would mention at least one part that they liked.

Nope. Nothing but criticism.

I swear, it was like someone took a needle and just popped my enthusiasm balloon.

Tuesday, December 02, 2008

Big Idea nearly gone

Randy came up to me today and asked if I knew if Greg Hardin was still at Big Idea. "I think so," I said. "Why?"

"Well, because his status on FaceBook sounds like he may have been let go."

"What?!?"

Sure enough, he was gone...along with about two-thirds of the rest of the crew. Big Idea is down to eleven people, with most of them in marketing, and only three on the creative crew.

This brings back unpleasant memories of the layoff that happened right before Christmas of 2002. The studio was already on edge after the round of layoffs that practically coincided with the theatrical release of Jonah: A VeggieTales Movie, and a bunch of folks losing their jobs right before the holidays didn't help. Layoffs at any time of year are a pain, but it tends to feel especially cold if it happens before Christmas. I'm not saying that it's a decision that anyone felt good about, either then or now. It's just really rare for a single company to have to dip into those particularly cold waters twice. My gut says that for those who are left who remember both dips, the lingering chill from the second submersion probably has a bit more bite.

My heart goes out to everyone involved: those who are no longer with the company who have to figure out what to do next, and those few who are still with the company...who also have to figure out what to do next.

Monday, October 27, 2008

Site down

Looks like some clever hackers found a way into my site and planted some oh-so-fun phishing scripts in there. I was contacted earlier today by my host, and informed that they've suspended my site until we can get it worked out. Here's hoping it won't take long.

Wednesday, October 08, 2008

I am voice actor. Hear me flail!

I was asked to provide vocal noises for the guy in the large plastic ball in this DriveTime spot that we produced at work about a month ago. Most of the stuff in the early part of the spot had to be mixed really low under the main voiceover, but you can hear me loud and clear (well, muffled and clear) when the guy goes rolling toward the camera. No pay for this gig, but it was fun all the same.


Monday, October 06, 2008

Python decorators: getting a little closer...

After further searching, I finally ran across a very well-written article that attempts to explain Python decorators from a very basic level. While it hasn't brought to mind any situations in which I would want to use decorators in my code, I at least have a handle on what exactly they are and how they work.

To clarify my earlier post, one of main things that (at first) didn't click for me with regard to decorators was how exactly they allowed the programmer to effectively modify a function after it was written. Sure, I'd learned that you could assign a function to a variable and pass it around like any other piece of data, but even in that context I saw the function itself as essentially static. If I passed a function as an argument, I only expected the target function to call the function I passed as-is. I never thought about the possibility that a target function could actually do something else with/to the function I had passed.

As with other things I've unearthed in the process of learning Python, I have a hunch that this would've been easier to learn if I had a more formal background in computer science, and that's probably the biggest frustration that still crops up as I dig through Python documentation. Bits of programming terminology are often casually thrown around with the assumption that the average reader knows what they mean. One example is the term "first-class objects" that can be found at the head of the article linked above. I've seen that term used in several places, but even though the sentence immediately following the phrase in the above article is related to the phrase's definition, I still had no idea what it meant until I dug it up via a Google search. The way it was phrased in that article, it felt like the status of Python functions as first-class objects was a separate concept from that which immediately followed it, so I was left thinking, "Okay...so what are first-class objects?"

That's probably not the best example of my frustration, though. I guess the point is that it feels like there's a gap somewhere. At one end there's good introductory material, such as the tutorial by Guido von Rossum that covers a lot of ground-level topics. At the other end there is very nice reference material that covers the individual modules in the standard library, the data types that the language offers, etc. However, between Guido's tutorial and the other reference material there's a bit of a void, because some of the reference material makes reference to programming concepts that aren't explained in Guido's tut. I'm not necessarily implying that they should be covered by Guido's tutorial, but it's a gap all the same, and one that many in the Python community seem to ignore. Perhaps that is an inaccurate observation, and I'd be more than happy to be shown evidence to the contrary. However, from my observations, many experienced Python programmers seem to assume that you're either a newbie learning the basics, or you're a fellow pro. The folks in the middle who aren't totally new but aren't full-on professional programmers seem to get overlooked.

The most frustrating part is that I feel like I'm square in that gap. Yeah, I've been scripting/programming since I was about 12, but sadly that doesn't necessarily mean that I have a complete understanding of modern programming terminology and concepts. I've taken very few formal programming courses, and those few took place a long time ago. Everything else I know has been the result of self-study and on-the-job experience. However, the farther I delve into this stuff, the more I feel like self-study (at least what I'm currently doing) isn't cutting it.

So here comes the million-dollar question: do I stick with self-study and see how far it gets me, or do I go back to school? I've been around enough self-taught animators to know that it's possible to get to the very top of that game without formal instruction, but I don't know if the same holds true for the world of programming.

Wednesday, September 17, 2008

Still can't figure out decorators

After a couple months (roughly) of Python programming, I'm very happy with how far I've come and what I'm able to accomplish. When all this started my biggest struggle was the basic object-oriented programming mindset. After further study and a good bit of trial and error, though, I feel I've got a pretty good handle on it. I'm not a whiz by any stretch, but I'm a lot more comfortable with it now than I was when this all began.

That leads me to the next programming concept I'd like to grok: decorators.

I just stumbled across a blog post in which the author claims that Python's decorators are "radically simple." I'm sorry, but I've read a good number of explanations behind decorators -- including the Wikipedia article on the subject, which includes a pseudo-example in Python -- and this "radically simple" outline (i.e. the slides that Mr. Diederich used in his PyCon UK talk) hasn't made the concept any clearer for me.

Does anyone know where I can find a truly clear description of Python decorators? Perhaps this is something that could be more easily understood if I had a solid computer science background instead of an animator-who-fell-in-love-with-programming-on-the-side background.

Yarg....

Saturday, September 13, 2008

iPod Touch vs. the clock

I noticed recently that my iPod Touch wasn't syncing its date and time properly with the computer. At first I thought it might be a glitch in the Touch software, so I experimented by syncing several times in a row to see if I could find a pattern. The only pattern I noticed was it gave me a different time (and I assume a different data) with each sync: 1:24 AM, 4:11 PM, 9:18 AM, etc.

A quick Google search led me to a thread that outlined the true source of the issue: iTunes. If you put your computer to sleep with iTunes open, and then try to sync the iPod Touch after waking it up, iTunes appears to invent a random date and time to send to the device. To avoid this, simply close and re-open iTunes before syncing.

Friday, September 12, 2008

Python and list copies

While working on a tool at Reel FX, I couldn't figure out why the data lists across several different class instances were all returning the same information. Normally working with lists in Python is tons-o'-fun (especially when compared to the gymnastics required to do similar operations in MEL), but that fun can come to a screeching halt if you forget one little important detail: copying a list doesn't necessarily copy the list.

For example, say there's a list assigned as follows:
   data = ["apples","oranges","pears"]
Some time later you want stuff to be a copy of data:
   stuff = data
If you've come to Python with some previous programming/scripting experience, you might assume (as I've done more than once) that this would do the trick. However, that just tells stuff to reference the list assigned to data. If you end up changing data later on, and then look at stuff, you'll notice that it shows the same changes. That's because they're both pointing to the same list in memory.

So how does one get around this little annoyance? Pretty simply, actually:
   stuff = data[:]
That bit on the end tells Python to make stuff equal to the entire contents of data, instead of making it just another pointer. To be more accurate, it duplicates the list to which data is pointing, and then points stuff to that new list.

Dictionaries also exhibit this same point-instead-of-copy behavior, but the syntax is different if you want to make a true copy:
   newdict = olddict.copy()
(Pardon the crazy formatting. I've never tried to insert code blocks into a blog post, and getting it to look decent with the controls available in the Blogger editor is driving me nuts. Methinks it's time to consider an alternative blogging system...)