MacDevCenter    
 Published on MacDevCenter (http://www.macdevcenter.com/)
 See this if you're having trouble printing code examples


Basics of Offscreen Buffering

by Michael J. Norton
04/30/2004

Welcome to the second installment of the Elementary Computer Graphics lessons -- where elementary means elementary school age developers and up. If you haven't read Elementary Computer Graphics: Drawing with Pixels, I encourage you to do so. Basic concepts were introduced in those lessons that will be built upon here. Also, if you are unfamiliar with the Tcl scripting language, an introductory tutorial was provided there.

We last left off with a game console we had programmed using the Wish shell and the Tcl scripting language. The game console code created a window, 640 pixels wide by 480 pixels tall. We also learned how to draw pixels to our game window in the last lesson. It was a place to start for you up and coming game developers. In this set of lessons, you're going to learn how load an art file into your video game, just as you see on your Game Boy Advance SP games.

I'm also going to cover how a computer stores a file and about a file system. Armed with this knowledge, you'll put it to use with your Tcl skills and load art into the game console. Then I'll tie all this together and show offscreen buffering concepts.

Lesson 1: The Computer File System

So what is a file system and what is it used for? Every computer must store information, even when it is turned off. For instance, when you turn on your Game Boy Advance, you must insert a game cartridge with the game you want to play. The game cartridge contains the game program to load into your Game Boy, as well as game sprites (animation cells), art, music, and sound effects. Since you can insert different game cartridges into the Game Boy, the cartridge is called removable media.

Related Reading

Physics for Game Developers
By David M. Bourg

On the other hand, your computer that you are working on has a hard drive, which you don't swap out with different hard drives before you boot the computer. This is called fixed media. The hard drive contains special programs, called an operating system, to boot your computer; a file system, used by the operating system to retrieve programs; and files from your hard drive.

Both your Game Boy and computer use an operating system and a file system. The operating system on your Game Boy is stored on a chip called a ROM, for Read Only Memory. Interestingly, we have different styles of computers with different kinds of storage media. This is where the computer file system comes into play. The file system manages the files on your computer, whether it is a Game Boy or your Macintosh or your PC.

So what is a file, then? A file is a collection of information that is stored on the media. The media is your hard drive, CD-ROM, DVD player, USB stick, Game Boy cartridge, and so forth. The most common types of files, today, are programs, picture files, music files, and text information. When you insert a new game into your Game Boy, the file system program goes out and looks for a program file to load to start the game. The game is stored on the cartridge as a file.

Understanding Your Computer's File System

In Figure 1, I have provided a snapshot of my file system. My hard drive is named the TheMatrix. The figure shows files and directories on my hard drive. You are looking at how the file system is organized on a Macintosh OS X computer. You are looking at my computer's top-most directory. This is called a root directory.

Figure 1
Figure 1. A graphical display of my computer's root directory

So what is a directory? A directory is a special file; in a windowed operating system it is called a folder, which stores your files. In my root directory, I have Applications, Developer, game_dev, and Games, directories, to name a few. The Macintosh operating system uses folders to identify directories. A directory can store other directories just as our root directory is storing other directories. A directory inside of another directory is called a subdirectory.

Learning About the File System with Tcl

Go ahead and fire up the Tcl-Tk Wish Shell and let's experiment with your computer's file system. When Wish Shell executes on a Macintosh running OS X, your current working directory is the root directory. But don't take my word for it. Prove it to yourself and type the command pwd into the Wish Shell console window.

() 1 % pwd
/
() 2 %

The command pwd is an UNIX operating system command acronym for print working directory (pwd). You'll notice the pwd command returned a forward slash (/) and nothing else. This has special meaning for the UNIX file system. A lonely slash means we are in the root directory.

Let's create a directory called game_dev, just like the one I have in Figure 2, off of the root directory. We can do this from the Tcl Wish Shell using the "make directory" command mkdir.

() 3 % file mkdir /game_dev

The forward slash (/) tells the operating system where to create the game_dev directory. In this case, we are creating the game_dev directory in our root directory.

We can move around the file system using the UNIX operating system command cd to change directories. Let's experiment and move from our root directory (/) into the /game_dev subdirectory.

() 4 % cd /game_dev
(game_dev) 6 %

You'll notice your prompt now displays the directory name enclosed in parentheses: (game_dev). Your current working directory is now set to game_dev. This would be a good time to download the game_art.gif file using your web browser. Download the file into your /game_dev directory.

(game_dev) 8 % exec ls
game_art.gif

ls is a UNIX file system command to display the contents of a directory. You can use this command from the Tcl Wish console to see if the art file is in the correct directory. You can also use the entire file pathname if you want to experiment with pathnames.

(game_dev) 11 % exec ls /game_dev/game_art.gif
/game_dev/game_art.gif

The art file is in the correct directory, so let's move on and display it.

Lesson 2: Displaying the Game Art File

Tcl has some graphics libraries included with Tk that will allow us to open a graphics file and display it. The Tk image photo library has all of the scripting tools we will need for this task. We can load our sprite's art file into our program using the following lines of code:

set filename "/game_dev/game_art.gif"
set sprites [image create photo -file $filename]

Remember that the filename variable requires that you give it the correct path to the file you downloaded.

Let's display our art file to see what the contents look like. We will need to determine the height and width of our art file. We can use the image tools to gather these values for us.

set max_x [image width $sprites]
set max_y [image height $sprites]

Now that we know the size of the art image, we can proceed and create a Tk canvas to display the art file. The following lines of code accomplish this.

# create the canvas
canvas .canv -width $max_x -height $max_y -background black
pack .canv -side top -expand yes -fill both

Our next step is to load the image onto the canvas.

# load the image to the canvas
.canv itemconfigure $sprites -image $sprites
.canv create image 0 0 -image $sprites -anchor nw

The last line of code above tells Tk how to place our image onto the canvas. We want the image origin to be placed on the canvas origin. Tk is too smart for its own good, and will attempt to center the image for us. We need to override Tk and tell the computer to attach the image at the upper left corner (or northwest: -anchor nw). You should try experimenting and remove the -anchor command to see what happens to the image.

If you're puzzled as to why the image is set in the upper left corner of the canvas, you should read the previous article. I discuss window and canvas geometry there. Figure 2 shows our image loaded using the load_art.tcl script.

Figure 2
Figure 2. /game_dev/game_art.gif

The Script

set filename "/game_dev/game_art.gif"
set sprites [image create photo -file $filename]
set max_x [image width $sprites]
set max_y [image height $sprites]

# create the canvas
canvas .canv -width $max_x -height $max_y -background black
pack .canv -side top -expand yes -fill both

# load the image to the canvas
.canv itemconfigure $sprites -image $sprites
.canv create image 0 0 -image $sprites -anchor nw

Lesson 3: Using Offscreen Buffers

Displaying the art file was a simple lesson to get your feet wet using the Tk image library. Now let's explore another important video game programming concept, the offscreen buffer. Our goal is to animate video game cells called sprites. When we animate directly to the game player's screen, the animation can appear a bit sloppy. To provide a smoother illusion of animation, video game programmers use a technique called offscreen buffering.

The idea behind offscreen buffering is to perform all of the game action updating on a screen that is not visible to the game player. Once your program has completed the rendering offscreen, it is then displayed to the game user. The end result is the game player never sees the rendering taking place, and this provides the illusion of smooth video game graphics.

Figure 3
Figure 3. Using offscreen buffering to animate sprites

Figure 3 helps illustrate the technique we're going to use. Using the Tk image library, we're going to load the entire art file into a Tk image we're calling sprites. We're going to create an offscreen buffer using Tk image library and call this offscreen. The image offscreen has precisely the same dimensions as our canvas .video_game_window. The goal is to render to the Tk image offscreen buffer using the sprites from the Tk image sprites. Let's take a look at the code that does this:

# create the game console window
set video_game_width 640
set video_game_height 480

canvas .video_game_window \
   -width $video_game_width -height $video_game_height -background black
pack .video_game_window -side top -expand yes -fill both

# load the art file
set filename "/game_dev/game_art.gif"
set sprites [image create photo -file $filename]

# create a blank offscreen image
set offscreen [image create photo \
-height $video_game_height -width $video_game_width]

The above code creates the video game window, with resolution 640 pixels wide by 480 pixels tall. We load our game art into the Tk image, sprites, and we create an image, offscreen, that is 640 pixels wide by 480 pixels tall, just like our video game window. We have the components we need in place to experiment with some simple animation concepts.

Copying the Background to the Offscreen Buffer

We now have two Tk images created: sprites, which contains all of our game art, and offscreen, which is blank. What needs to be accomplished now is the copying of images -- our background and sprites -- to the offscreen buffer. The copying of image pixels from one image to another is called blitting in computer graphics. Let's copy the background scene from the image sprites over to the image offscreen.

# copy the background mountains image
$offscreen copy $sprites -from 0 0 639 479 -to 0 0 639 479

Image blitting is carried out using rectangular boundaries. Our art file is 640 pixels wide by 1256 pixels tall. The background image we want to use is 640 pixels wide by 480 pixels tall, just the same size as our video game window. The top 640 by 480 pixels in the art file is the background art we want to blit to our offscreen buffer. This explains why we need -from and -to coordinates in the above statement.

To get a true feel of what we're doing, use an image editor, such as Photoshop, and open the game_art.gif file. Move the mouse around and look at the coordinates of the boundary of the background scenery. Then you'll get a true understanding of where these rectangular boundaries are and of how you obtain them from the art file.

Blitting Sprites

We have our background art copied over to the offscreen buffer and now we need a cell of animation -- our sprite. Using my image editor, I located a sprite to copy to the offscreen buffer. It is a single animation frame of the monster jumping. I am going to grab a sprite from the sprite image whose rectangular boundary in the sprite image is 256, 767, 328, 800. The sprite cell is going to be copied to the center of our game window. The character sprites are all 64 pixels wide and tall. The center of the game window is 320, 240. If I create a window for my sprite cell, I will need the following destination rectangle to blit to: 320, 303, 383, 366. The blit operation is as follows,

# copy the jumping monster sprite
$offscreen copy $sprites \
-from 265 737 328 800 -to 320 303 383 240

Figure 4
Figure 4. Sprite copied to offscreen buffer

Figure 4 shows the jumping monster sprite copied over the background image in the offscreen buffer. Our simple blit operation is done and our rendering is completed. Now we need to update the game screen.

# update the video game window 
.video_game_window create image 0 0 -image $offscreen -anchor nw

Voilà! You have your animated video game sequence. Not exactly a shippable product, but you get the idea of what needs to take place for your game animation.

The Script

# create the game console window
set video_game_width 640
set video_game_height 480

canvas .video_game_window \
   -width $video_game_width -height $video_game_height -background black
pack .video_game_window -side top -expand yes -fill both

# load the art file
set filename "/game_dev/game_art.gif"
set sprites [image create photo -file $filename]

# create a blank offscreen image
set offscreen [image create photo \
-height $video_game_height -width $video_game_width]

# copy the background mountains image
$offscreen copy $sprites -from 0 0 639 479 -to 0 0 639 479

# copy the jumping monster sprite
$offscreen copy $sprites \
-from 265 737 328 800 -to 320 303 383 240

# update the video game window 
.video_game_window create image 0 0 \
-image $offscreen -anchor nw

The Tip of the Iceberg

We've only covered the tip of the iceberg for video game animation. You have the basic concepts here for how to use an offscreen buffer. Games like Unreal and Quake Arena may use as many as two offscreen buffers when fast rendering is required. The idea behind two offscreen buffers is that you render to offscreen buffer A, while offscreen buffer B is being copied to the game display. Then offscreen buffer B is used for rendering while offscreen buffer A is copied to the game display.

Now it's time to go ahead and experiment. If you're really adventurous, I recommend that you Google search for "mega man sprites" or "sonic the hedgehog sprites." A lot of game sprites from old commercial games are all over the Web and at your disposal.

Michael J. Norton is a software engineer at Cisco Systems.


Return to the Mac DevCenter

Copyright © 2009 O'Reilly Media, Inc.