OpenGL Asteroids
OpenGL Asteroids is an X Windows/OpenGL version of the
popular asteroids game. It was written as a teaching aid for
Stanford's 1996 introductory
course in computer graphics (CS 248).
The provided
execution environment comprises the executable game as
well as parameter files, sample textures and sample
sounds. game executes only on Silicon Graphics workstations
equipped with OpenGL. For those interested in porting OpenGL
Asteroids to other platforms, the source
code is also available in tar archive format; use
gunzip -c source.tar.gz | tar xf -
to unpack the archive. This source code was developed on a Silicon
Graphics workstation, equipped with the IRIS Digital
Media library. It incorporates code specific to OpenGL
Asteroids, as well as a general
purpose library for graphics applications, adapted from the
auxiliary library of The OpenGL Programming Guide.
We provide no support for OpenGL Asteroids.
Installation
Copy the provided
execution environment, available in tar archive format,
to your local disk. Then use
gunzip -c asteroids.tar.gz | tar xf -
to unpack the archive.
Executing game
Executing game as
game -help
will show a short help screen and terminate OpenGL Asteroids.
To play the game,
- Create a parameter file. This is a text file containing the
desired setup of OpenGL Asteroids, including your preferred
sounds and textures. The parameters subdirectory of the
execution environment contains several sample parameter files, for
platforms with different capabilities:
- yes_texture_yes_sound: enabling texturing and sound
effects, this parameter file is appropriate for high-end graphics
workstations, such as Silicon Graphics RealityEngines.
- yes_texture_no_sound: enabling texturing, but
disabling sound effects, this parameter file is appropriate for
high-end graphics workstations whose console resides in a different
room than the CPU tower and built-in audio system.
- no_texture_yes_sound: this parameter file disables
texturing, rendering each asteroid as a solid square of a single
color. Hence, it is appropriate for low-end graphics workstations.
- no_texture_no_sound: this parameter file disables both
texturing and sound effects, making it appropriate for execution over
the network, and display on low-end graphics workstations.
- texture_demo: this parameter file enables texturing
and draws a single asteroid. It is appropriate for demonstrating
texture mapping on low-end graphics workstations.
- debug: this parameter file is useful for developers
who wish to experiment with the source code of OpenGL
Asteroids.
- Disable automatic keystroke repetition, using
xset r off
To re-enable automatic keystroke repetition when the game is over, use
xset r on
- Make sure that your current directory is the one containing
game.
- Execute game as
game parameters/<parameter file>
where <parameter file> is the name of a parameter
file.
Playing the game
OpenGL Asteroids is a simple game where you navigate your
ship in the treacherous asteroid belt, and try to destroy the
asteroids before they destroy you. Your weapons comprise a shield of
limited energy and a cannon. You control your ship using the following
keys and mouse buttons:
- Left mouse button
- Allows you to position your ship on the game board, when the
computer asks you to do so.
- Left arrow key
- Continuously rotates your ship counter-clockwise.
- Right arrow key
- Continuously rotates your ship clockwise.
- Up arrow key
- Continuously accelerates your ship in the direction it is facing.
- Space bar
- Fires the cannon.
- Left shift key
- Activates the shield, provided you still have some shield energy
left.
- The j key
- Makes your ship jump through hyperspace. That is, your ship
dematerializes, and instantaneously rematerializes at a random
position of the game board, possibly in the interior of a fatal
asteroid.
- The p key
- Pauses an on-going game, or resumes a paused game.
- The Q key
- Destroys your ship.
- The escape key
- Terminates OpenGL Asteroids.
Technical features
OpenGL Asteroids is a teaching aid. While it may (or may not)
be a fun game to play, its main intent is to illustrate several
features of OpenGL, use of audio for Silicon Graphics machines, and
several other programming techniques.
Collision detection and signal handling
Each asteroid is drawn at a specific depth. Also, all asteroids are
drawn closer to the front than the player's ship and the
bullets. Collisions are detected after a game board position is fully
drawn, in four steps:
- The depth buffer values under the bullets are retrieved.
- If any of them is equal to a depth value characteristic of an
asteroid, or the depth value of the player's ship, the corresponding
object is destroyed.
- The depth buffer values under the ship are retrieved.
- If any of them is equal to a depth value characteristic of an
asteroid, the asteroid and the player's ship are both destroyed.
This collision detection scheme has as its primary advantages accuracy
to the level of individual pixels and simplicity. It also illustrates
a creative use of the depth buffer, as a repository of object
IDs. However, this scheme has several drawbacks, too:
- It necessitates that the OpenGL Asteroids window is
never obscured by any other window, which may corrupt the depth buffer
of OpenGL Asteroids. This is achieved by using X Windows
calls to raise the OpenGL Asteroids window whenever the game
board is redrawn.
- It necessitates that the OpenGL Asteroids window is
always in full view. If part of it is off screen limits, the
application does not have access to depth values. It is possible to
remedy this by asking the window manager to reposition the window
whenever it happens to cross a screen edge. OpenGL Asteroids
does not implement such a behavior, as it produces a hostile user
interface.
- It necessitates a data transfer between framebuffer memory and
main memory. Such a transfer may invoke several costly roundtrip X
Windows calls on some platforms, or during remote execution, and is
subject to delays as other system components (video refreshing, output
of the graphics pipeline, etc.) use the framebuffer memory.
- It requires trapping operating system signals. The aforementioned
roundtrip requests to the X Windows system can cause the application
to crash if the user suspends the application after a request is sent,
but before the reply is received. Hence, signal handling code is
needed to trap application suspension (e.g. by pressing Ctrl
Z in the terminal window) and block it when appropriate.
Texture mapping, alpha test, and display lists
When texturing is enabled, asteroids are drawn as texture-mapped
squares. In particular, at initialization time, a picture file in raw
PPM format is read from disk. This picture is loaded onto texture
memory, with its black pixels having their alpha channel set to
zero. Then, the picture is texture-mapped onto a square as a
decal. Finally, the asteroid is rendered with the alpha test enabled
and configured to discard fragments with an alpha value of zero. The
end result is that the asteroid
- has an irregular shape, as the underlying geometry - i.e. the
texture-mapped square - is invisible at pixels corresponding to
transparent texels, and
- its interior is colorful.
Moreover, in order to battle the cost of texture mapping, display
lists are used. The effect of display lists on performance is
substantial, as a texture in a display list resides permanently in the
texture memory of the graphics system; using texture mapping without
display lists requires reloading the texture memory every time a
texture-mapped object is rendered, a very slow operation.
Developers' note: the source code module image.*
contains a host of utilities for reading and writing PPM files,
reading from and writing images to the framebuffer, and loading images
onto texture memory.
Transformation matrices
As stated earlier, asteroids are rendered using a display list. The
glVertex*() commands in this display list specify the
asteroid's shape relative to a local coordinate system. In
order to render an asteroid, a transformation is pushed onto the
MODELVIEW stack prior to calling the display list. Thus,
each asteroid is translated, rotated, and scaled as appropriate for
its particular configuration.
This technique should be used with care, as matrix concatenation is an
expensive operation, justified only when many vertices will be
subsequently transformed by the compound matrix - or when a display
list is used for rendering. Hence, in OpenGL Asteroids, all
game board objects other than asteroids are rendered by direct
calculation of their transformed coordinates.
Pixel-accurate wrap-around
A mere six lines of code can be used to achieve pixel-accurate
wrap-around: that is, making objects which disappear gradually from
one side of the screen simultaneously reappear smoothly on the other
side. All it takes is rendering the scene nine times, each time
shifting the location of all objects prior to rendering, by pushing a
matrix onto the MODELVIEW stack. The shift amounts are such
that the objects are offset by zero or one screenful to the right,
left, top, and bottom - in all meaningful permutations. This is not a
a very expensive technique, since clipping quickly discards objects
which do not appear on the window.
Audio for Silicon Graphics machines
OpenGL Asteroids makes use of sound to enhance the
game-playing experience. It uses the IRIS Digital Media
library, which is the standard interface to the audio hardware of
Silicon Graphics workstations. Unlike many personal computers,
Silicon Graphics workstations support real-time playback of sampled
audio signals; but they do not support simple commands generating
single tones. Hence, playing any kind of sound is not easy from a
programmer's standpoint.
OpenGL Asteroids implements a parallel, real-time, sound
player. The main process spawns off child processes, each of which is
in charge of playing an audio clip, either until its completion, or
indefinitely by repeated looping. This division of labour between the
main process and its children is necessary in order to guarantee that
sound and graphics both proceed in real-time, without one's
performance impinging on the other's. Child processes communicate with
the main process using signals, thus allowing the main process to
interrupt a child when OpenGL Asteroids terminates, for
example.
Developers' note: the source code module audio.*
contains a host of utilities for reading and playing AIFF/AIFC files
using child processes.
Acknowledgments: the sounds distributed with OpenGL
Asteroids were copied from the sound archives of the TV series Star
Trek, Ren & Stimpy, and Danger Mouse.
Event-driven programming paradigm
OpenGL Asteroids, combined with our slightly modified version
of the auxiliary library of The OpenGL Programming Guide,
illustrate event-driven programming. This is a hard programming
technique, as it enforces a non-linear control flow within an
application: control flows into the application from the auxiliary
library, and back out, and back in, and so forth. Here are some
examples of event-driven programming using the auxiliary library:
- When the game is not paused, the auxiliary library calls an idle
function repeatedly, which updates the state of the game board and
redraws the window. To prevent this from happening when the game is
paused, the application tells the auxiliary library that no idle
function is defined; when the game resumes, the update function is
again specified as the idle function.
- When a key is pressed, the auxiliary library calls a function in
the application, called a key-press callback. When the
application returns control to the library, it calls the application's
window redraw function. This function must update the state of the
game board before drawing the window: if it did not do so,
the animation would become jerky, as the new frame would be identical
to the previous one. It follows that, as the idle function is also
expected to update the board and redraw the window, the same
application function can be used as both the idle function and the
window redraw function.
- For a smooth animation, key-press callbacks should not
incrementally update the orientation of the player's ship. If this
were the case, the ship would either turn too slowly - as the user can
only press keys so fast -, or it would turn in large, visibly
discrete, steps. Instead, most key-press callbacks in OpenGL
Asteroids set global variables, indicating a request such as "the
user wishes to turn right". These variables remain set until the user
releases the key. While the key is held down, and the corresponding
global variables are set, the player's ship turns slightly every time
the game board is updated. Since this happens 30 times a second, a
fast and smooth turn results.
Text file parsing
Parameter files are fairly structured text files: fields are separated
by whitespace, and comment lines, starting with the #
character, are supported. OpenGL Asteroids reads and parses
parameter files, performing full error checking as it does so. Helpful
error messages notify the user of missing fields, illegal parameter
values, etc.
Other programming techniques
OpenGL Asteroids illustrates several other programming
techniques:
- The movement of all game board objects is timed to a wall clock,
and is independent of the frequency that the game board is updated,
and the window redrawn; the gettimeofday() function is used
to this end. This technique ensures that OpenGL Asteroids
will behave identically when run on fast or slow machines - except, of
course, for possible jerkiness in the animation on critically slow
machines.
- Explosions in OpenGL Asteroids illustrate how a static
geometry can appear to move by changing its coloration. Explosions are
always drawn as a set of radially extending spokes. By using a smooth
shading model, and gradually varying the color at the vertices of the
spokes, the explosion appears like an expanding fireball.
- OpenGL Asteroids also illustrates some C++ features,
such as basic object-oriented programming techniques, as well as
templates (a linked list, in particular).
User interface issues
OpenGL Asteroids is somewhat user friendly, including user
interface features such as the following:
- When the player resizes the OpenGL Asteroids window, the
application responds in two intuitive ways:
- OpenGL Asteroids uses the longer dimension of the
resized window to set the size of all game board objects.
- The game board size is adjusted to have the same aspect ratio as
the resized window. Also, the positions of all game board objects are
wrapped-around to fit in the new game board.
- Messages appear on the screen to inform the player of the game's
status. These messages include a warning that the game is paused or
terminated, or that OpenGL Asteroids is waiting for the
player to position his/her ship.
- When the shield energy is low, the ship and the shield indicator
are drawn in red. Also, as soon as the low energy threshold is
reached, a warning sound is played.
- The user will not cause the application to exit if s/he
accidentally presses Ctrl C in the terminal window;
instead, a warning message will appear, requiring that the user
presses the escape key in the OpenGL Asteroids window to
terminate the application.
Distribution notice
Copyright © 1996 The Board of Trustees of The Leland Stanford Junior
University. All rights reserved.
Permission to use, copy, modify and distribute this software for any
purpose is hereby granted without fee, provided that the above
copyright notice and this permission notice appear in all copies of
this software and that you do not sell the software. Commercial
licensing is available by contacting the author.
This software is provided "as is" and without warranty of any
kind, express, implied or otherwise, including without limitation, any
warranty of merchantability or fitness for a particular
purpose.
Author: Apostolos Lerios.
© 2003 Apostolos Lerios