SaveLife

1.5 / 2000.06.13
B. Smith-Mannschott
bsmith@student.ethz.ch

download: SaveLife.Cod (AsciiCoder)

Introduction

SaveLife is an implementation of John Conway's game of life for SaveScreen, an extensible screen saver for Oberon System-3.

This version has seen a number of changes since the initial release. The screen redrawing logic has been completely rewritten, both to improve its speed and to allow a faded transition between generations. This release still has a number of rough edges. In particular, it's not possible to choose the colors used to draw the cells.

Installation Parameters

w SIGNED16 -- sets the width, in pixels, of cells drawn to the screen. (1 <= w <= 32, default 8)

h SIGNED16 -- sets the height, in pixels, of cells drawn to the screen. (1 <= h <= 32, default 8)

frameRate SIGNED16 -- requests the given number of frames per second from SaveScreen. (1 <= frameRate <= 30, default 15)

offscreen SIGNED16 -- chooses the offscreen mode. 0 disables offscreen drawing, 1 sets it to automatic and 2 enables it. (default 1)

steps SIGNED16 -- number of steps in the fade from one generation to the next. Setting steps to 2 disables the faded transition between generations. (2 <= steps <= 26, default 8).

m FLOAT32 -- a constant related to the gamma of your screen. It's generally between 0.5 and 1.0. The author's display has m=0.78, which is the default.

timing -- if this is present in the parameter list, SaveLife will report timing information when it is stopped. It's useful mainly for optimizing and debugging.

lonely SIGNED32 -- set the color of lonely live cells to the given RGB value. The color is specified in the least significant three bytes of of a longint, with blue being the LSB and. The most readable way to do this is with something of the form: 0rrggbbH, where rr, gg, bb represent hexadecimal digits.

normal SIGNED32 -- set the color of normal live cells.

crowded SIGNED32 -- set the color of crowded live cells.

Faded Transitions and the parameter m

In implementing the faded transition between generations, I quickly discovered that the relation between RGB value and actual brightness is non-linear. This means, that evenly spaced values between two colors will not produce evenly spaced brightness values. In such a case, the display will appear to darken and brighten with every generation. A great way to acquire a terrible headache.

In the case of my display, an RGB value at 78% of maximum (that is 255 * 0.78 + 0.5 for all three channels: red, green and blue) produces a perceived brightness of half-way between black and white (50% grey). The parameter m, is the value that will produce a brightness of 0.50.

To estimate the behavior of the display, I constructed a quadratic polynomial which passes through the points (0,0), (0.5, m) and (1,1) with which one can compute proper RGB values for a desired brightness.

SAVE LIFE GRAPH

If you notice that the faded transitions between generations seems to produce a throbbing change in brightness, you'll need to use a different m value. You can use SaveScreen.Calibrate.

When you execute SaveScreen.Calibrate the screen will be covered with a checkered black and white pattern. Pressing the space bar will display a solid grey fill with an RGB value of 50%. The key "D" will darken the grey fill, while "L" will lighten it. Adjust it until to checkered pattern and solid fill appear to have the same brightness. You can switch back and forth to compare them with the space bar. (You may want to take off your glasses, or squint if you don't have any to get things to blur a bit to better judge the brightness.) When the two fills agree, press "Q" to exit. The correct m value will be printed to the system log.

Offscreen Drawing

This fader will attempt to use an offscreen drawing area, allowing it to flush the updates to screen all at once. In most cases, this leads to smoother screen updates, as flushing the bitmap to screen in once pass can take less time than drawing each change directly to the screen. SaveLife is smart enough, to keep an eye on this. In the case of a slow graphics card, or a large cell size it is often faster to draw directly to the screen than to copy from an offscreen map. In such a case, SaveLife automatically disables offscreen drawing when offscreen is set to 1. The settings 0 and 2 will disable or force offscreen drawing, respectively.

Algorithm & Speed

The algorithm used by SaveScreen is a very optimized, but fairly naive implementation of Conway's Game of Life. It doesn't posess the raw speed of something like xlife, but is fast enough for these purposes, as I've found that even on the slowest machine I have access to (a 90 Mhz Pentium), the bottleneck is in generating the display list, not in calculating calculating the next generation.

Despite my efforts to optimize up SaveLife, it may be quite a CPU time hog if you run it with very small w and h (hence, a large cell grid.)

I'll leave it up to you to choose a w and h appropriate to your machine and screen resolution. You may find the output of timing interesting in this regard.

Compatability

SaveLife has been tested under Native Oberon (x86), Native Oberon (Shark/ARM), and MacOberon. Under MacOberon and Windows Oberon, you'll need to use the "\N" compiler switch in order to compile since SaveLife imports SYSTEM.

Possible Future Changes