Infinite zoomer

See a larger version of the zoomer

The effect above is a classic from computer demos a decade ago. It is a lot simpler to make than it might first appear, especially with flash where you don't have to be so concerned about optimization. To make it you simply draw something on the center of the screen, then zoom in a bit. Doing this repeatedly creates the effect shown. The only questions that remain are how to do the drawing, and how to do the zooming. This tutorial will depend on some features that were not available before Flash 8.

How to do the zooming

Recently Flash has been boosted with the ability to manipulate bitmaps directly in Flash. Where before you could only draw more high-level shapes like circles and lines on the stage, you are now (since Flash 8) able to manipulate pixels directly. There now exists a class called BitmapData that can hold a rectangular array of pixels (color values, basically). The bitmap data held by BitmapData is only in memory and invisible until a BitmapData object is attached to a movie clip. There are many things that could be done with that class, but another thing used in this tutorial will be the BitmapData.draw method. The draw method takes a snapshot of the visible state of another movie clip and draws it on the BitmapData so that the pixels can be directly manipulated.

This explanation was necessary, because the way the zooming is done involves creating two BitmapData objects and rendering each on the other one, always zooming in a bit, which can be accomplished by an argument that can be given to the draw function. Two objects are needed, because you cannot render a BitmapData object on itself or things go crazy.

Getting it running

Actually not much needs to be drawn in this effect. Just put some random stuff in the center and it ends up looking pretty cool. Preferably something with lots of colors. What I did is just draw a bunch of pixels in the center with shifting colors. In my example I directly used the setPixel method of BitmapData, but you could use any of the normal drawing routines by utilizing BitmapData.draw for the center drawing part as well.

Getting something running

After creating a new flash document, click on the stage and paste in the following code in the actions section:
import flash.display.BitmapData
a_bmp = new BitmapData(Stage.width,Stage.height,false,0);
b_bmp = new BitmapData(Stage.width,Stage.height,false,0);
this.createEmptyMovieClip("a_mc",1)
this.createEmptyMovieClip("b_mc",2)
a_mc.attachBitmap(a_bmp,0);
b_mc.attachBitmap(b_bmp,0);

That is the initialization code. Of course there can be no movement unless something is done each frame, so we need some code in a repeating section. Create any movie clip for this purpose. You could for example create a rectangle, select it and press F8 to create a movie clip out of it. Then in that movie clip's actions paste the following:
onClipEvent(enterFrame) {
	import flash.geom.Matrix
	import flash.filters.BlurFilter
	
	m = new Matrix()
	z = 1.09
	m.scale(z, z)
	m.translate((Stage.width-Stage.width*z)/2,(Stage.height-Stage.height*z)/2)

	_root.b_bmp.draw(_root.a_mc, m)
	_root.a_bmp.draw(_root.b_mc)

	if (!counter) counter = 0
	counter++
	
	for (y=-10; y<10; y++) {
		for (x=-30; x<30; x++) {
			_root.a_bmp.setPixel(Stage.width/2+x+Math.random(), 
					     Stage.height/2+y+Math.random(), 
					     counter*(x*y+30*10+counter*100))
		}
	}	
}
Now if you start the flash app by pressing CTRL+ENTER you should see a zoomer similar to the one on this page. You may notice it is slower. To make it look smoother you should increase the framerate by right-clicking on the stage and entering a larger number in the frame rate section of document properties.

Okay, what does the code really do?

The initialization code creates two bitmapdata objects and attaches two movie clips to them. We need two because as I wrote earlier it isn't possible to render a bitmap onto itself. The movie clips are attached to the BitmapData objects so that their contents would be visible and also so that they can be used as sources for BitmapData.draw method.

The repeating part occurs on every frame, as the movie clip's enterFrame event is fired. The zooming is done by using the BitmapData.draw method to copy the contents of the movie clip A (which is attached to bitmapdata A) onto bitmapdata B. Then bitmapdata B's contents are again copied to bitmapdata A. This is repeated on each frame. Of course simply copying the contents would not be enough, so a matrix is used to create a zoom.

A Matrix object can be provided to the BitmapData.draw method and will be used to do a transformation before the movie clip is copied onto the BitmapData object. In this case we create a matrix which just slightly scales up. There is also a translation that is done after the scaling, so that the zoomed in version would remain in the center.

Finally, a counter is used (initialized if to zero if not set yet) to shift the colors. A rectangular array of pixels with slightly randomized positions and interesting colors are set with the setPixel method and some loops to go through x and y. The formula counter*(x*y+30*10+counter*100) was selected arbitrarily because on quick experimentation it looked cool =)

Thanks

Thank you for reading this tutorial. I hope that staring at the effect didn't make you feel ill!