mattias | niklewski.com

The rotation matrix

When I was 13, a friend lent me a Pascal book. Pascal was used in Swedish schools and this copy came from his mom who was a teacher. He also lent me a copy of Turbo Pascal, a brilliant IDE for MSDOS that was way ahead of it's time.

Soon I had picked up enough Pascal to start writing simple programs. Not sure what exactly to do yet, together we devoured whatever documentation we could find on the x86 / DOS environment.

At this time, pirated computer games used to come bundled with an 'intro', a small program that displayed game info and presented the members of the release group. Some intros featured graphics, ranging from minimalist side-scrolling text to fullblown 3D scenes like something out of the demo scene. I wasn't familiar with the demo scene yet, but I thought graphics seemed really neat, so why not try that?

The standard way to do graphics in Pascal was through something called the Borland Graphics Interface (BGI). Great for your average desktop app I'm sure, but for intro-style stuff you might need to do full-screen updates at high framerates. BGI was too slow for that.

Fortunately, there was a tutorial floating around our local BBSs. It was written by this guy named Denthor from a South African demo group called Asphyxia, and it explained how to do graphics in MCGA -- also known as mode 13h -- which was a 320x200 graphics mode with 256 indexed colors. Turbo Pascal had inline assembler, so swapping modes via BIOS services was trivial.

Procedure SetMCGA;
BEGIN
  asm
        mov     ax,0013h
        int     10h
  end;
END;

In a few lines of code, you could leave the dull 80x25 grey-on-black DOS world behind. Mode 13h was awesome because it was simple. It used 64000 bytes of video memory (320x200x8 bits), all of which fit in a single 64k real-mode segment. VGA memory was mapped at a fixed adress (0xa0000) and Pascal makes memory available as a byte vector 'mem'. So putting a pixel on the screen could be done by assigning a color to a memory slot.

mem[$A000:320*y+x] := color;

Oh, and by the way - the 256-color palette was customizable. Each of the palette entries could be replaced by any color from the 32-bit color space. A few pages into the tutorial, and already you had complete control over everything that was shown on screen. This was a mind-blowing experience for someone who up until now had been restricted to reading and printing text to the console. Mode 13h represented a blank canvas and a Spaceship of the Imagination.

The tutorial was well written and full of useful tricks. In the first few chapters it built a crude but functional graphics library on top of the putpixel() primitive. It taught the standard algorithms for drawing lines and circles. It explained how to optimize inner loops with tricks like lookup tables or by dropping down to inline assembler.

With 2D out of the way, it moved on to 3D. Rasterizing triangles, back-face culling. So far so good. Rotation in 3D space. This was where I got stuck. Linear algebra isn't taught until undergrad level in Sweden, and the tutorial didn't go into much details beyond serving up a bunch of 3D rotation matrices. It was too dense for me. I copy/pasted what I needed but promised myself that I would some day get to the bottom of this matrix wizardry.

Fast forward about 6 years. I am in the lecture room at the university, watching my professor scribble equations on the black board. This is the introduction to Linear Algebra, and the course is wrapping up. Suddenly I recognize the rotation matrix on the black board. It's in 2D this time, but doesn't that \(-\sin\alpha\) term look awefully familiar?

$$ \left(\begin{array}{r} \cos \alpha & -\sin \alpha \\ \sin \alpha & \cos \alpha \end{array}\right) \times \left(\begin{array}{c} x \\ y \end{array}\right) $$

And then it hits me. This is where I got stuck all those years ago. Only this time it all makes perfect sense. The matrix, this omnious shadow from the past, can be derived easily - just check what the transform does to the x-y axes and that's that.

I know many people who seemed destined to take up programming. Maybe they got an Apple II in their hands at age 5, or maybe their parents were C hackers and taught them first hand. I'm not one of those kids. In 1993, our first internet connection was still a few years away, and Wikipedia a few years more. If Denthor hadn't written his tutorial and if it hadn't by some chance ended up in my hands at the perfect time, I may have given up on Pascal. I am grateful that I didn't.