Abe's Demoschool Part V

lens and similar effects, color quantification

Welcome to part V of Abe's Demoschool.

In Part 4 I said that this part would be about 3d vector graphics but I've changed my mind because I'm taking a course about 3d computer graphics in the spring of 1997 and I thought it would be best to wait with the 3d stuff until after that course so I'll be sure I'm not telling any lies.

Instead I'm going to write about some easier common demoeffects and I'll start with the lens effect and similar transformations. A lens effect is when a picture is shown and it looks like a magnifying glass is beeing drawn over the picture. One of the most famous demos that has a lens effect is 2nd reality by future crew. The first time I saw this effect I was astonished and had no idea of how it was done. Then somebody told me and I thought wow, this is really cool.

The trick is to precalculate the entire effect. Just make an array that for each pixel in the destination picture tells which pixel to take from the source picture. This array is called the transformation array. The tricky part is to calculate the transformation array to make the destination look like a lens is beeing held over the source picture. I didn't come up with the algorithm myself, I found it at x2ftp.oulu.fi somewhere.

        Pseudocode for lens transformation array:
        (actually it's straight C-code)

int tfm[D*D];   //The transformation array
int M=10;        //Magnificationfactor
int r,m,y,x,a,b;
float s,z;
r =D/2;         //D is the Diameter of the lens, I use 64
s = sqrt(r*r - M*M);

for(y = -r;y < r;y++)
{
        for(x=-r;x < r;x++)
        {
                if(x*x + y*y > = s*s)
                {
                        a = x;
                        b = y;
                }
                else
                {
                        z = sqrt(r*r - x*x - y*y);
                        a = (x * M /(float)z + 0.5);
                        b = (y * M /(float)z + 0.5);
                }
                tfm[(y + r)*D + (x + r)] = (b + r)*D + (a + r);
        }
}

actually the lens effect is kind of symmetric so it would be enough to loop halfway through x and y and reflect around the axes but it's easier to loop through everything and it doesn't take very long time anyway.

Now when the hard part is done, the tfm array is calculated, just follow these simple steps:

        1. Save the background of the D*D pixels rectangle at the 
           coordinates where the lens effect will be applied.
        
        2. For each pixel in the destination rectangle, apply the color
           from the appropriate pixel in the saved background. The tfm
           array tells the offset into the saved background.
        
        3. Restore the original picture by drawing back the saved background.

        4. Calculate new coordinates and goto 1.

On a slow computer the lens may flicker in the upper part of the screen. You can remove the flicker by using a virtual screen like in part 3 and 4 of the demoschool. I left that part out to make the code smaller. There are already 4 files involved:

Abedemo5.c #includes mklens.c and viewtga.c. Compile everything with:

If you change the tfm array, the entire effect changes. Here are some cool transformations (D is both width and height):

Invert area (flip in both x- and y-directions):

        for(i=0;i < D*D;i++) tfm[D*D-i-1]=i;

Flip area in x-direction:

        
        for(i=0;i < D;i++)
        {
                for(j=0;j < D;j++)
                tfm[i*D+j] = i*D + D-1 - j;
        }

Flip area in y-direction:

        
        for(i=0;i < D;i++)
        {
                for(j=0;j < D;j++)
                tfm[j*D+i] = (D-1-j)*D + i;
        }

Magnify upper left corner of area:

int MAG=2;      //magnificationfactor
        for(i=0;i < D;i++)
        {
                for(j=0;j < D;j++)
                tfm[i*D+j] = (i/MAG)*D + (j/MAG);
        }

All these transformations are included in mklens.c. You can probably think of more transformations like exchanging the upper left corner, the lower right corner, the upper right corner and the lower left corner with each other or perhaps make it look like a letter or a logo of glass is held over the image. Just use your imagination (and a lot of math if you're trying the logo of glass thing).

If you examine the lens effect in 2nd reality you see that the lens also changes the color of the source image and gives it a slightly bluish touch. This can be done by drawing the image with, say, colors 0 to 63. Then let colors 64 to 127 be copies of colors 0 to 63 but a little bluish and 128 to 191 more bluish and 192 to 255 most bluish. Then make a second array, the same size as the transformation array. But let this one have numbers 0, 1, 2 or 3. 0 means don't change the color, 1 means add 64, 2 means add 128 and 3 means add 192. The tfm array and the color-filter array have to be matched to make the effects look good together.

To help you get going I wrote a color quantifying program, quant.c. It takes a 256-color tga image and converts it to 64 colors. The rest of the colors in the palette are copies but in rising shades of blue. I also added functions to make green shades and fog shades. Fog shades are good for simulating ... fog. The further away an object is, the more fog shade. It's easy and fast, even doom uses similar techniques only the opposite, the further away, the darker. You could easily change the green shades to dark shades to get the same effect.

I once saw an animated cursor on the Amiga where the mouse cursor had a small magnifying glass with the center at the hot spot (the active place when you click). After this you should be able to do a similar animated cursor in mode 13h on the PC. This looks really cool if you ever make a program where the mouse is used. It looks even cooler if you first draw a sprite of the magnifying glass and leave a hole where the glass is. Then apply the lens effect at the coordinates of the hole. If you also add the color filter dicussed above the effect would be outstanding. Again, use your imagination.

The source code is pretty easy to follow, the routines in lens.asm is very similar to the sprite routines in part 3 of the demoschool. The only difference is the tfm array and that the routines don't use a virtual screen. You can easily add a virtual screen, just peek at graph.asm from demo 4.

If you're using Borland C, compile quant.c with:

and abedemo5.c with . Have all the files in the same directory.

The tga image, boris.tga is a part of a Boris Vallejo painting I think. I don't remember where I got it from but change .tga image if you don't like it. If you don't manage to compile abedemo5 you can still change .tga image. Just name your image boris.tga and put it in the same directory as abedemo5.exe. download abedemo5.zip which contains the source codes and demo5exe.zip for the executables if you fail to compile. Unzip the executables into the same directory as the files from abedemo5.zip.

2nd reality and a LOT of other demos can be downloaded from: ftp.luth.se.

Lookout for more demoeffects in part VI that will be available soon.


/Abe Racadabra, October 1996

s-mail: Albert Veli
        Spisringsg. 9
        S-724 76 Väster;ås;
        SWEDEN
mail:dat94avi@bilbo.mdh.se.


Copyleft:
You are free to do whatever you like with the code of the parts of the demoschool. If you spread them please don't change anything unless it's an improvement (that works). Use the code in your own programs if you want but remember that the code is not 100% optimized.

Back to the Demoschool.