Sunday, October 16, 2011

I translated Alexander Boswell's toy REYES renderer from C++ to Google's new Dart programming language.

Here's what the output looks like:



Try It Yourself

If your browser supports the canvas tag and JavaScript, you can see the sphere being rendered here:

Render a REYES bumpy sphere in your browser.

And the source is here: http://code.google.com/p/reyes-dart/

Translating C++ to Dart

It was pretty easy to translate the original code from C++ to Dart.
  • The original code made use of classes and overloaded operators, both of which are also in the Dart language.
  • The original code used the SDL library to display output. It was easy to switch to the HTML5 CANVAS tag.

I used an early version of the "Dart Editor" IDE. The Dart Editor IDE was helpful because of the compiler warnings and errors.

Debugging

I used a variety of techniques to debug the code:
  • print() Dart has a built-in print function that logs to the JavaScript console. This was good for logging small amounts of data.
  • write() This is a utility function I wrote that appended the argument text to the document body of my HTML document. This has several advantages over "print":
    • Easier to see output during development.
    • Much easier to search and copy/paste large amounts of text.
  • Dumping 3D geometry as text. At one point I wanted to check whether or not my geometry was correct. The easiest way to check it was to dump the geometry out as a 3D text file using "write()", and then copy-and-paste that code into a file and view it in the blender3d.org Blender app.
  • Using Chrome to step through the compiled app.js code. This was pretty painful, but was occasionally useful. The stack crawls for exceptions usually gave good hits as to what was going wrong.
Dart Limitations
  • The Dart "dom" library is not yet complete. Currently it can't write to canvas imageData. As a work-around I draw each pixel of output as a little filled rectangle.
Dart Editor Limitations

I wish the Dart Editor would support:
  • Formatting code.
  • Stripping whitespace from ends of lines on save.
  • Converting tabs to spaces on save.

Sunday, September 11, 2011

A script to upload files to Picasa Web Albums

Today I backed up all my family pictures and videos to Picasa Web Albums.

For several months I have been thinking of ways to backup my pictures to somewhere outside my house. I wanted something simple, scalable and inexpensive.

When I read that Google+ users can store unlimited pictures sized <= 2048 x 2048 and videos <= 15 minutes long, I decided to try using Google+ to back up my media.

Full disclosure: I work for Google, which probably predisposes me to like and use Google technologies.

Unfortunately I had my pictures in so many folders that it wasn't very convenient to use either Picasa or Picasa Web Albums Uploader to upload them.

Luckily, I'm a programmer, and Picasa Web Albums has a public API for uploading images. Over the course of an afternoon, I wrote a Python script to upload my pictures and videos from my home computer to my Picasa Web Album account. I put it up on GitHub: picasawebuploader

Good things:
  • The Google Data Protocol is easy to use.
  • Python's built-in libraries made file and directory traversal easy.
  • OSX's built-in "sips" image processing utility made it easy to scale images.
Bad things:
  • The documentation for the Google Data Protocol is not well organized or comprehensive.
  • It's undocumented how to upload videos. Luckily I found a Flicker-to-Picasa-Web script that showed me how.
To do:
  • Use multiple threads to upload images in parallel.
  • Prompt for password if not supplied on command line.

Saturday, August 20, 2011

What am I up to?

I'm mostly posting on google+ these days, sorry!

Monday, December 20, 2010

Asynchronous directory tree walk in node.js

I wrote an asynchronous directory tree walker in node.js. Note the use of Continuation Passing Style in the fileCb callback. That allows the callback to perform its own asynchronous operations before continuing the directory walk.

(This code is provided under the Apache Licence 2.0.)


// asynchronous tree walk
// root - root path
// fileCb - callback function (file, next) called for each file
// -- the callback must call next(falsey) to continue the iteration,
// or next(truthy) to abort the iteration.
// doneCb - callback function (err) called when iteration is finished
// or an error occurs.
//
// example:
//
// forAllFiles('~/',
// function (file, next) { sys.log(file); next(); },
// function (err) { sys.log("done: " + err); });
function forAllFiles(root, fileCb, doneCb) {
    fs.readdir(root, function processDir(err, files) {
        if (err) {
            fileCb(err);
        } else {
            if (files.length > 0) {
                var file = root + '/' + files.shift();
                fs.stat(file, function processStat(err, stat) {
                    if (err) {
                        doneCb(err);
                    } else {
                        if (stat.isFile()) {
                            fileCb(file, function(err) {
                                if (err) {
                                    doneCb(err);
                                } else {
                                    processDir(false, files);
                                }
                            });
                        } else {
                            forAllFiles(file, fileCb, function(err) {
                                if (err) {
                                    doneCb(err);
                                } else {
                                    processDir(false, files);
                                }
                            });
                        }
                    }
                });
            } else {
                doneCb(false);
            }
        }
    });
}

Friday, November 12, 2010

Getting Old Educational Software to Run on OSX 10.6

My kids' favorite piece of educational software is "Clifford The Big Red Dog Thinking Adventures" by Scholastic. We received it as a hand-me-down from their cousins. The CD was designed for Windows 95-98 and pre-OSX Macintosh. Unfortunately, it does not run on OS X 10.6. (I think it fails to run because it uses the PowerPC instruction set and Apple dropped support for emulating that instruction set in 10.6.)

After some trial and error, I found the most reliable way to run Clifford on my Mac was:
  1. Install VMWare Fusion.
  2. Install Ubuntu 10.10 32-bit in a Virtual Machine.
  3. Install the VMWare Additions to make Ubuntu work better in the VM.
  4. Install Wine on Ubuntu 10.10. (Wine provides partial Windows API emulation for Linux.)
  5. Configure the audio for Wine. (I accepted the defaults.)
  6. Insert the Clifford CD and manually run the installer.
The result is that the Clifford game runs full screen with smooth animation and audio, even on my lowly first-generation Intel Mac Mini.

You may scoff at all these steps, but (a) it's cheap, and (b) it's less work than installing and maintaining a Windows PC or VM just to play this one game.

(It's too bad there isn't a Flash, HTML5, Android or iOS version of this game, it's really quite well done.)

Sunday, September 5, 2010

Eulogy for a PC

This Labor Day weekend I decommissioned my tower PC.

If memory serves, I bought it in the summer of 2002, in one last burst of PC hobby hacking before the birth of my first child. It's served me and my growing family well over the years, first as my main machine, later as a media server.

But the world has changed, and it doesn't make much sense to keep it running any more. It's been turned off for the last year while I traveled to Taiwan. In that time I've learned to live without it.

The specific reasons for decommissioning it now are:
  • It needs a new CMOS battery.
  • It needs a year's worth of Vista service packs and security updates.
  • I don't use the media center feature any more.
  • After a year without a Windows machine I don't want to maintain one any more.
  • It's too noisy and uses too much energy to leave on as a server.
The decommissioning process

I booted it, and combed through the directories. I carefully copied off all the photos, code projects, email and documents that had accumulated over the years. Lots of good memories!

GMail Import

I discovered some old Outlook Express message archives. I wrote a Python script to import them into GMail. I didn't like any of the complicated recipes I found on the web, so I did it the easy way: I wrote a toy POP3 server in Python that served the ".eml" messages from the archive directory. Once the toy POP3 server was running, GMail was happy to import all the email messages from my server.

Erasing the disks with Parted Magic

Once I was sure I had copied all my data off the machine it was time to erase the disks. I erased the disks using the ATA Secure Erase command. I did this using a small Linux distro, Parted Magic. I downloaded the distribution ISO file and burned my own CD. Once the CD was burned, I just rebooted the PC and it loaded Parted Magic from the CD.

Parted Magic has a menu item, "Erase Disk". It lets you choose the disk and the erase method. The last method listed is the one I used. The other methods work too, but they don't use the ATA Secure Erase command.

It took quite a while to erase the disks. Each disk took about two hours to erase. (They took 200 GB per hour, to be precise.) Unfortunately, due to the limitations of my ATA drivers, I had to erase them one at a time.

While I think the ATA Secure Erase command is the fastest and most reliable way to erase modern hard disks, there is another way: Instead of having the drive erase itself, you can copy data over every sector of the drive. The advantage of this technique is that it also works with older drives. If you choose to go this route, one of the easiest way to do it is to use Darik's Boot and Nuke utility. This is a Linux distro that does nothing besides erasing all the hard disks of the computer you boot it on. You just boot the CD, then type "autonuke" to erase every disk connected to your computer.

Disposing of the computer

It's still a viable computer, so I will probably donate it to a local charity. The charity has a rule that the computer you donate must be less than 5 years old. I think while some parts of the computer are older than that, most of the parts are young enough to qualify.

Reflections on the desktop PC platform

Being able to upgrade the PC over the years is a big advantage of the traditional desktop tower form factor. Here's how I upgraded it over the years:

Initial specs (2002)
  • Windows XP
  • ASUS P4S533 motherboard
  • Pentium 4 at 1.8 GHz
  • ATI 9700 GPU
  • Dell 2001 monitor (1600 x 1200)
  • 256 MB RAM
  • 20 GB PATA HD
  • Generic case

Final specs (2010)
  • Windows Vista Ultimate
  • ASUS P4S533 motherboard
  • Pentium 4 at 1.8 GHz
  • ATI 9700 GPU
  • Dell 2001 monitor (1600 x 1200)
  • 1.5 GB RAM
  • 400 GB 7200 RPM PATA HD
  • 300 GB 7200 RPM PATA HD
  • ATI TV Theater analog capture card
  • Linksys Gigabit Ethernet PCI card
  • Antec Sonata quiet case

I think these specs show the problems endemic to the desktop PC market. Although I didn't know it at the time, the PC platform had already plateaued. In eight years of use I wasn't motivated to upgrade the CPU, motherboard, monitor, or GPU. If I hadn't been a Microsoft employee during part of this time I wouldn't have upgraded the OS either.

What killed the PC for me wasn't the hardware wearing out, it was mission change. Like most people I now use the web rather than the local PC for most of my computer activity. Maintaining the local PC is pure overhead, and I've found it's easier to maintain a Mac than a PC.

It was nostalgic to turn on the PC again and poke through the Vista UI. It brought back some good memories. (And I discovered some cute pictures of my kids that I'd forgotten about.)

Thank you trusty PC. You served me and my family well!

Sunday, August 29, 2010

An update on my car stereo

It's been a year since I bought my fancy car stereo. I wanted to mention that I've ended up not using most of the fancy features.
  • The built-in MP3 player had issues with my 1000-song / 100 album / 4 GB music collection:
    • It took a long time to scan the USB storage each time the radio turned on.
    • It was difficult to navigate the album and song lists.
    • Chinese characters were not supported.
    • It took a long time to "continue" a paused item, especially a long item like a podcast.
  • The bluetooth pairing only worked with one phone at a time, which was awkward in a two-driver family.
Here's how I use it now:
  • I connect my phone using both the radio's USB (so the phone is being charged) and mini stereo plugs.
  • I use the phone's built-in music player.
  • I have the radio set to AUX to play the music from the stereo input plug.
It's a little bit cluttered, because of the two cables, but it gets the job done. The phone's music player UI is so much better than the radio's UI.

In effect I have reduced the car stereo to serving as a volume control, an amplifier, and a USB charger.