Rotozoomer Tutorial

Linqs / Yuca Abstract

Hi everybody!

Recently, I wanted to code a rotozoomer. So I checked some tutorials in order to find a solution to that problem. This began with a wonderful cached-optimized one [1], of course in Assembler. And it's really hard to find out the basic formula from it. So, I continued searching. I've been spending 10 euros of telephone costs without finding anything really useful. But somehow zed3d [2] crossed my way and I found the so called rotation matrix. Click! And here my first tutorial starts!

What is a rotozoomer? Nothing but a simple rotation around the z axis. And therefore I found the following matrix on page 29 of zed3d:

 (x y z) ³cos(w)         -sin(w)        0³
         ³sin(w)         cos(w)         0³
         ³  0               0           1³

As we only have two dimensions we can leave out z:

 (x y) ³cos(w)         -sin(w)³
       ³sin(w)          cos(w)³

And how do I write a rotozoomer?

First you need a texture (don't care about size) and a destination page (0a000 :-). The rest is easy. You just check every pixel of the destination page (screen)...

[C/C++]

 for(y=0;y<=199;y++)
   for(x=0;x<=319;x++)
   {
   }

[PASCAL]

 for y := 0 to 199 do
   for x := 0 to 319 do
   begin
   end;

And calculate for every single point on the screen (x,y) a corresponding pixel on the texture (u,v)...

[C/C++]

     u = x*cos(W)+y*(-sin(W))
     v = x*sin(W)+y*cos(W)

[PASCAL]

     u := round(x*cos(W)+y*(-sin(W)));
     v := round(x*sin(W)+y*(cos(W)));

Now you put it in the loop:

[C/C++]

 for(y=0;y<=199;y++)
   for(x=0;x<=319;x++)
   {
     u = x*cos(W)+y*(-sin(W));
     v = x*sin(W)+y*cos(W);
     color = getpixel(u,v,quellbild);
     putpixel(x,y,color,zielbild);
   }

[PASCAL]

 for y := 0 to 199 do
   for x := 0 to 319 do
   begin
     u := round(x*cos(W)+y*(-sin(W)));
     v := round(x*sin(W)+y*(cos(W)));
     color := getpixel(u,v,quellbild);
     putpixel(x,y,color,zielbild);
   end;

And it's done.

So these are the basics of a rotozoomer... Wait a minute, the zoomer is missing :)

Just multiply the sine and cosine values with a zoom factor of the data-type float (pascal : real).

Now you know what a rotozoomer looks like.

Of course we still have a speed problem.

Here is a little tip. If you have two loops try to calculate things you could have calculated in the outer loop not 319 times in the inner loop. (x*cos(w) or x*sin(w) - hint, hint :-)

In many cases you can replace slow multiplications by fast additions. Here you could do this as well. Just think about it. Precalculating a sine and cosine-table wouldn't be a bad idea.

In addition you can use fixed point mathematics and you can optimize it by using Assembler and by checking out how the cache works [1].

There are so many things that can be done with that rotozoomer. For example the rotozoomer here always rotates around the same point (0,0). Make it more flexible!

I really don't want to explain you every single step to a perfect rotozoomer. This tutorial is supposed to tell you only the basics. The optimisations can be done later by you. You are the coder and not the "ripper". I didn't want to write a tutorial in which a rotozoomer is "explained" by simply putting my Assembler source code with a few Bavarian comments. :-)

Just the case: If you really get stuck just contact me. I'd love to help you.

Finally I want to greet those great dudes:

zed, adok^hugi, nitron^ya, fenrir^ya, sepl^ya, siriuz^kolor, wastl^kolor (shiva :]), franky^riot, the madman (join yuca), sengir, fkl, salami, submissiv, [-qb-], delta9, climax and all people on #coders.ger (melcom, mirekcz, tis... and the rest).

Have fun with coding and please tell me how it was like coding your rotozoomer. I'm really looking forward to reading mail from you.

- linqs^ya

check out: http://yuca.home.pages.de

Sources

[1] rotozoomer by pascal
http://www.hornet.org/code/effects/rotozoom/pasroto.zip

[2] zed3d by zed
http://www.hornet.org/code/effects/various/zed3d095.zip