Single-Image Stereograms

Three-dimensional illusions are cropping up in everything from the funny papers to magazine advertisements. Dennis examines how the illusion works, then presents and implements an algorithm that lets you generate your own images.


July 01, 1995
URL:http://www.drdobbs.com/security/single-image-stereograms/184409585

Figure 2


Copyright © 1995, Dr. Dobb's Journal

Figure 2


Copyright © 1995, Dr. Dobb's Journal

Figure 3


Copyright © 1995, Dr. Dobb's Journal

Figure 2


Copyright © 1995, Dr. Dobb's Journal

Figure 3


Copyright © 1995, Dr. Dobb's Journal

JUL95: Single-Image Stereograms

Single-Image Stereograms

Seeing (double) is believing

Dennis Cronin

Dennis writes drivers for Central Data's scsiTerminal Servers. He can be contacted at [email protected].


Three-dimensional illusions are showing up in everything from magazine advertisements to the comic pages of daily newspapers. Although appearing to be nothing more than a random field of dots or wavy patterns, striking 3-D images emerge when you "correctly" view the designs. Once you learn to get a fix on an image (and almost everyone can), you can look around the virtual 3-D image just like looking out a window. Figure 1 is a typical stereogram in which the word "SONY" appears. If you haven't been able to pick the images out, understanding the concept behind them may help you experience the illusion.

In this article, I'll discuss how the illusion works and the origins of the technique. I'll also examine the basic algorithm for generating the images and present a sample program (available electronically; see "Availability," page 3) that lets you display 3-D images on your PC screen. You'll then be able to quickly design and generate your own custom 3-D illusions using a standard PC paint program.

A 3-D Backgrounder

The terms "single-image stereogram" and "autostereogram" refer to a 3-D illusion composed of only one image and requiring no special viewing apparatus. Other types of stereograms use two small, side-by-side images or require special glasses or other optics for viewing.

The most basic single-image stereogram is the single-image, random-dot stereogram (SIRDS), which looks like a field of random dots with no apparent texture or pattern. In its simplest form, the image is composed only of black and white dots, yet a vivid 3-D image is clearly visible when viewed correctly. Commercial 3-D illusion posters take SIRDS a step further, replacing the TV-not-tuned-in dot field with a more visually appealing texture or repeated pattern. Nevertheless, the principle behind the illusion is the same.

The current crop of 3-D illusions has its roots in basic vision research. Bela Julesz is generally credited with being the first to use computer-generated, random-dot images to create a sense of depth. In his early-1960s depth-perception studies, Julesz used pairs of random-dot images to demonstrate that a sense of depth could be achieved with no other visual cues. Christopher Tyler and Maureen Clark, in turn, are generally credited for combining two images into a single, random-dot image circa 1990, creating the forerunner of today's gift-shop rage.

Since then, numerous companies and individuals have advanced the art with clever posters, books, and online images of autostereograms. The newsgroup alt.3d, for instance, carries a steady discussion of SIRDS-related issues, and the FTP site katz.anu.edu.au is probably the most active central clearing house of autostereograms, information, and programs (see the directory /pub/stereograms).

Making a Point

To understand how single-image stereograms work, I'll first examine the most fundamental case of how you make a single dot appear at some point out in virtual 3-D space.

Assume that you want to make point A appear somewhere off in the distance beyond the plane of the paper (or screen). Imagine for a minute that the image is transparent; your eyes will have to converge (or triangulate) to view point A off beyond the plane of the image. Note the points where the rays from each eye intersect the plane of the image; see Figure 2. By placing a pair of dots at exactly those locations, you can imply the first point in the 3-D landscape.

It's not easy to get much feeling of depth from setting up just one virtual point with two dots. The brain has no additional cues to help it interpret those two lonely dots as a magic point in deep space. The effect doesn't kick in until you start to build a larger set of information for your brain to cue from.

Now let's see what happens if you want to make a dot appear somewhere further away than point A. Referring again to Figure 2, notice which rays converge at point B and where they cross the image plane. They are slightly farther apart than the two points identified for point A.

With some basic geometry, you can formulate the distance of that virtual point as a function of dot separation; see Example 1. Figure 3 shows the basic convergence diagram again, but with the parameters in Example 1 indicated. To give a convincing illusion of depth, you have to build a complete system of dots that map out a 3-D scene. In doing so, you will be able to use the formula in Example 1 to map out a system of dot pairs such that a complete 3-D scene will be visible to the unaided eye.

Getting the Effect

As you stare at a stereogram, you shift the convergence of your eyes and let your focus wander. When you triangulate on a normal object, your brain tends to select a focal length that will closely match the distance implied by your eyes' convergence.

To see a stereogram, you need to break focal length away from triangulation. When you find the exact point of triangulation that makes the dot pairs overlap, a portion of the 3-D image fuses. When your brain stumbles on the right triangulation and starts to note this image appearing, it will attempt to adjust focus to cause the image to solidify. For some people, this separation of triangulation and focus comes quite easily; others have trouble with it.

When the image finally locks in for you, it's astounding how naturally the brain adjusts its vision machinery to this new set of rules. With a little practice, you can effortlessly maintain a good lock on the image as you look around in it. The effect for most people is exhilarating--some of the fun comes from just seeing the image appear, and some of it comes from the strange, unnatural feeling of having your eyes operating in a way they're not used to.

Making the Scene

Rendering a scene is a three-step process:

  1. Develop a 2-D depth map of the scene to be displayed.
  2. Process the depth map and build a map of dot-pair constraints.
  3. Assign colors such that the constraints are met.
In Step #1, you scan the scene you want to render, developing a depth map of Z values for every point in the scene at the desired resolution. There are various ways to accomplish this, but this simple approach suffices: Imagine a line perpendicular to the scene scanning the scene side-to-side and top-to-bottom. You take a perpendicular-depth reading for every point and record that in your depth map. While this technique ignores some basic tenets of real 3-D geometry, it is more than adequate for generating these illusions.

Depth maps can also be generated which are not based on any real 3-D scene. I use a paint program to generate a depth map using different colors to represent different depths. The test program in Listing One (page 92) generates this type of color depth map using a simple mathematical formula.

In Step #2 of the rendering process, you develop a constraint map that describes all the dot pairings necessary to create the final image. You don't describe what color the dot pairs have to be, just which ones have to match which other ones.

A major simplifying assumption is that humans keep their heads oriented vertically with respect to the image. Thus, for every point in virtual 3-D space, you need define only two dots along the horizontal axis to imply that virtual point. In fact, if you tilt your head slightly when viewing a commercial stereogram, you will quickly lose the image.

This assumption allows you to break the problem into a single case of rendering one horizontal line of the scene at a time. When you have devised an algorithm for rendering a single horizontal line, you are ready to generate the constraint map for the entire scene.

The traditional algorithm for constraint mapping is quite simple. An adaptation of it (included in the sample program provided electronically) looks like Example 2, where base_period is the number of pixels between the dot pairs with the greatest separation. Picking this value correctly is critical to the success of the illusion. Usually, base_period pixels should map to 1.5-2 inches on the output device. cmap is the array in which you build the constraint map. The get_depth function returns a small integer value representing the z-coordinate (or depth), with larger values for closer virtual points. An index value is just an ID used to identify points which must be the same color.

This algorithm simply scans a horizontal line, "looking back" and copying a previous index value. For closer virtual points, it looks back a smaller number of points; for maximum depth (get_depth returns 0), it looks back the full base_period number of points.

While this algorithm does a nice job, several limitations make it unusable for more-serious stereogram work. A right-shift distortion becomes apparent as the depth variations increase and, more fatally, it can develop rather distracting artifacts or echoes around sudden jumps in depth.

In Step #3, you pick colors for all the points in the scene adhering to the constraints developed in Step #2. For black-and-white stereograms, picking colors can be as simple as looking at each possible index value in the constraint map and randomly assigning it to be either black or white. For color stereograms, you randomly assign a color value from an available palette. Note that constraint-index values carry no meaning outside an individual horizontal line. A given value can be assigned one color in one line and another in the next, as long as consistency is maintained within each individual line.

As you assign a color to each constraint index in a line, you scan the line and replace all occurrences of the index with the selected final-output color value. When you have finished processing all the lines this way, you've created the classic SIRDS.

While a SIRDS certainly provides the 3-D experience, the random nature of the color-assignment process can lend a drab sameness to the final product. You can improve the aesthetics of the image by embellishing Step #3.

Just Stare, It's There

There are techniques to help spot the image in these illusions. The most well-known is to put the image behind glass and look for your reflection in the glass. Since the sample program displays directly to your computer screen, all you have to do is orient your screen and/or adjust the ambient lighting until you can see your reflection in the screen. This technique helps you achieve a fixed triangulation beyond the plane of the image. With a little practice, your brain will spot the emerging lines and acquire a focal lock on this image.

Note that this technique will not work with all stereograms--it is suited for stereograms where the virtual image is rendered to appear at approximately twice the viewing distance. These stereograms use pattern separations mostly in the 1.25- to 1.5-inch range. It is also possible to make stereograms that use wider separations, requiring you to stare farther off into the distance to get the proper triangulation. Although these can be more difficult for novice viewers, I find them somewhat more breathtaking, possibly because the vision machinery is operating even farther out of its normal parameters using close focal lengths and very distant triangulations.

Some stereograms provide a pair of registration dots immediately above or below the main image. By staring at these dots and adjusting your triangulation until you see exactly three dots, you can set your eyes to the depth for which the image was designed.

Another technique for viewing images on paper is to pick an object in the distance and focus on it, then slowly interpose the stereogram, trying not to move your eyes. This is helpful in acquiring the image in stereograms designed with more-distant triangulations.

If you don't find the image right away, keep trying. Almost anyone with normal or reasonably corrected binocular vision can eventually perceive the image. I've seen people spot the image within 30 seconds, and I've seen them struggle for hours. It generally gets easier with practice.

Going into Depth

In the SIRDS algorithm, the right-hand dot of the dot pair is always in fixed relation to the point in the depth map. This means that at closer virtual distances, the center of the dot pair is skewed to the right of the actual point in the depth map. You can easily correct this by calculating the necessary separation as before, then splitting it equally and symmetrically about the point in the depth map.

It is important to clean up artifacts (or echoes), false images that result from unplanned repetitions in the pattern, or sudden depth changes. The paper "Displaying 3D Images: Algorithms for Single Image Random Dot Stereograms," by Thimbleby, Inglis, and Witten (available via FTP from katz.anu.edu.au in /pub/stereograms/papers) covers this artifacting phenomenon in some detail. Thimbleby et al. propose a method for removing artifacts based on hidden surface removal (HSR); however, this method removes portions of the image necessary for a solid illusion. This results in blurry areas to the sides of sudden depth transitions. HSR assumes that if a point in the scene is hidden from one eye by a foreground object, then constraints need not be developed for a dot pair describing that partially hidden point. While there is some geometric basis for this approach, it doesn't benefit the overall effect of the illusion. In real life, when a point is hidden from one eye, the other eye can still focus on it solo, providing some information about it. Illusions benefit from providing information about this partially hidden point to both eyes, even though this defies real-life physics.

Despite its faults, HSR is on the right track: The solution to artifacts is to deconstrain points immediately to either side of the edges of foreground objects. You deconstrain only the number of points necessary to control unwanted repetitions of the pattern. This lets you reduce the number of points on which you sacrifice constraints, yielding a more-solid image overall while still removing artifacts.

The program 3D.C (available electronically in both source and executable form) allows the artifact-removal parameter to be varied. At its maximum value of 10, it removes more constraints than it really needs, which leads to blurring. At its nominal value of 7, the program removes artifacts from all images I've tested, causing only slight, mostly unnoticeable blurring around foreground objects. (I haven't tried to prove that this technique can fully remove artifacts--I'll leave that to commercial stereogram developers.) The routine symmetrical_constraint_map in 3D.C gives details about the artifact-removal process.

Many commercial stereograms have scenes that appear to have smooth, contoured, 3-D surfaces. In other stereograms, including those generated to the screen by 3D.C, the levels are discrete and distinguishable. This is not a fault of the rendering algorithm, but a product of the relatively low resolution of the output device. A 53-dpi EGA/VGA screen can't provide the smooth depth changes because the pixel width is too coarse to present very fine changes in spacing.

Colors, Textures, and Sprites

Coloring the final image is an art. At this stage, you have a constraint map, and as long as you assign colors based on the constraints, you can do just about anything. A simple method for improving the look of the stereogram is to map a texture onto the constraint map. An interesting texture is more appealing than a spray of random dots, and it may make it easier to lock onto the image from a distance, since the elements of the texture are coarser than little random dots. See the color_texture routine in 3D.C for my approach to developing textures on top of the constraints.

Possibly the most ingenious method of coloring a stereogram is to map a repeated smaller image onto the constraint maps. This yields an attractive wallpaper effect when viewed normally; upon achieving proper focus, the 3-D image jumps out just as crisply as from any random dot or textured image. The scene itself then looks as if its been wallpapered.

I've borrowed the term "sprite" from computer-game animation to describe the little image to be repeated. The sprite-mapping process should start near the center of the image and proceed outward. Some distortion of the sprite is inherent to the process, and starting at the center makes its mangling more symmetrical. Certain subjects may warrant starting the sprite mapping at a particular part of the screen so that the main subject matter gets mapped with relatively intact sprites.

Clever choice of material for both the sprite and the 3-D scene can conceal the sprite distortions. Remember that this sprite-mapping technique is as much art as science and may require extensive fiddling to generate a pleasing final product.

One additional trick 3D.C provides to conceal some of the side effects of the sprite distortion is the ability to sweep the sprite image from side to side in a gentle, wavy motion. This helps disguise fragmentation of the sprite image and can add some interesting effects to the sprite itself.

About the Example Program

The 3D.C example stereogram program showcases some of the popular stereogram techniques, displaying the images directly to the screen of your computer monitor. It was designed for use by the largest number of PC users: It runs in DOS mode, requires no extended memory, needs only 640x480 EGA/VGA graphics mode, and is built with a standard, 16-bit C compiler. To easily and quickly generate a custom 3-D scene, you use a standard, PCX-format file as a 3-D depth map. You can use any PC paint program that can generate a 16-color PCX image to edit a scene, with colors 0-15 being mapped to 16 depth levels.

While it would have been nice to support more levels of depth, higher resolutions, and larger image sizes, PC memory limitations and compiler issues constrained the program design. However, you should have no trouble expanding upon the basic functionality.

The program was built and tested with Borland Turbo C 2.0 and Borland C++ 2.0. Borland's graphics driver module EGAVGA.BGI must be accessible to the program at run time. If you use another compiler, you will need the graphics primitives or equivalents in Table 1.

Painting in Space

Before editing a scene, you will need to work out what colors map to what color numbers so you can control depth. Using the Edit Colors option, you can specify the color components. Set up a palette as in Table 2 and save it to a file using the Save Colors option. With this palette, color 0 (black) will be the farthest away, while color 15 (white) will yield the closest foreground image. Once you have established a known palette, you are ready to begin editing depth maps.

Next, build a simple, depth-map image with the paint program. Start with large, uncomplicated shapes until you get a feel for how things work in 3-D. Your image will be more believable if you maintain depth order and don't let background-depth colors obscure foreground images. Once you have an image you want to look at in 3-D, save it as a PCX file and exit the paint program.

Run 3D.EXE in DOS mode to render the scene; it runs extremely slow under Windows. Invoking 3D with no options other than the filename of the depth map (3D [filename.pcx]) causes it to default to a textured-coloring mode, picking random image colors and control parameters. First it loads and displays the depth-map image, then renders the image to 3D, line by line. An average image takes about 30 seconds on a 486/33.

When you are done viewing the image, hit any key to exit. As the program exits, it prints out the random parameters it selected. You can use the parameters in command-line options to (more or less) re-create an image.

Two other coloring modes are possible besides the default. To generate a traditional SIRDS using random dots, specify the -r option, or use the -s option to render the image using a sprite as coloring material. To view an image using the traditional constraint-mapping algorithm, use the -f option. The artifact-removal option (-a) has no effect in this mode.

Images can be dramatically altered by using the control parameters horizontal, vertical, and wiggles. These have different meaning in texture and sprite modes; in random-dot mode, they are meaningless.

In texture mode, the "horizontal" parameter determines the length of horizontal runs of like-colored pixels. The vertical parameter is a True/False value (1/0) that enables vertical runs. The wiggles parameter can be anything in the range 0-500 and only takes effect when the horizontal parameter is greater than 1. If wiggles is 0, the horizontal runs all drift right; if wiggles is greater than 480, the horizontal runs all drift left; in all other cases, the horizontal drifts reverse direction every line.

In sprite mode, the parameter's functions are somewhat different. The horizontal parameter determines the maximum amount of horizontal waviness that can be injected into the sprite mapping. The vertical parameter can be: -1, where wiggles start at top of screen and decrease toward bottom; 0, where wiggle depth is constant top to bottom; and 1, where wiggle depth increases toward the bottom of the screen. The wiggles parameter controls the wiggle frequency, as in the texturing mode.

While the limited depth resolution resulting from the use of a 16-color PCX image as a depth map is restrictive, clever scene design can still result in striking stereograms.

The Egg-Carton Test

Listing One is EGGCARTN.C, a test program. Compiling this program lets you see stereograms without editing a depth-map yourself. The program generates an example PCX depth-map file called "EGGCARTN.PCX." Invoking the program with an optional command-line parameter 0-15 causes it to generate different surfaces of varying degrees of interest.

In DOS mode, you should first run the test program to generate the PCX depth map (type EGGCARTN and press Enter). Next run the stereogram program to view the results by entering 3D EGGCARTN.PCX. You should be able to see a repeating contour not unlike that of an egg carton.

Conclusion

Many areas of single-image-stereogram generation are still being explored. An example is "shimmering," which involves rendering the image several different ways, then rapidly flipping the graphics page between the different images. The image appears very solidly, but has a shimmering quality. Some people find the images easier to view this way. Shimmering paves the way for possible stereogram animation.

So keep your eyes peeled. That apparently random texture on the stone front of a building, the slight shift in the wallpaper of your company's bathroom, the advertisement with the undulating, repeated logo in the background (that one's real already)--they all might be carrying secret messages in 3-D.

Figure 1: Typical stereogram (courtesy of NVision Grafix and Sony Corp.). This figure is unavailable in electronic format.

Figure 2: Making point A appear in the distance beyond the plane of the screen.

Figure 3: Basic convergence in Figure 1, with the parameters in Example 1 indicated.

Example 1: Equation for determining the distance of a virtual point as a function of dot separation. virt=virtual distance of point; sep=spacing between the dot pair; eyes=spacing between the eyes.

      view*eyes
virt=-----------
      eyes-sep
Example 2: Basic constraint-mapping algorithm. simple_constraint_map(int y)

{
    int lx,     /* left hand X coor */
        mx,     /* middle X coor */
        rx,     /* right hand X coor */
        dx;     /* left hand coor w/ delta */
    for(rx = 0,
     lx = -base_period,
     mx = lx / 2,
     index = CMAP_INDEX;
     rx < MAX_X;
     rx++, mx++, lx++)
    {
        /* if dx on screen, copy to right */
        if((dx = lx + get_depth(mx,y)) >= 0)
            cmap[rx] = cmap[dx];
        /* otherwise, just pick new index */
        else
            cmap[rx] = index++;
    }
}
Table 1: Graphic primitives required by the 3D program.
Function     Description

initgraph    Sets up 640x480 EGA/VGA graphics mode.
closegraph   Restores original screen mode.
setpixel     Plots a point on screen with a specified color.
getpixel     Returns the color at a point on screen.
setcolor     Sets the draw color for line drawing.
line         Draws a line from point x1,y1 to point x2,y2.
Table 2: Setting up the palette.
     Color #     Red  Green  Blue
     0            0     0     0
     1           128    0     0
     2            0    128    0
     3           128   128    0
     4            0     0    128
     5           128    0    128
     6            0    128   128
     7           128   128   128
     8           192   192   192
     9           255    0     0
     10           0    255    0
     11          255   255    0
     12           0     0    255
     13          255    0    255
     14           0    255   255
     15          255   255   255

Listing One

/*  EGGCARTN.C - generates a sample PCX depth map file called "eggcartn.pcx" 
for testing 3D.C stereogram program. Command-line param 0-15 generates 
different surfaces */
#include <stdio.h>
#include <graphics.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <conio.h>
#define MAX_X   640
#define MAX_Y   480
#define BPP     80      /* bytes per plane */
#define NPLANES 4       /* number of color planes */
void main(int argc,char **argv);
void doodle(void);
void dump_screen(void);
void put_line(unsigned char *data,int cnt);
void out_run(int byte,int rep_cnt);
void open_pcx(char *name);
void init_graphics(void);
double func(int val);
int mode;
double eggsz = 200.0;
/*      main        */
void main(int argc,char **argv)
{
    if(argc == 2)
        mode = atoi(argv[1]);
    open_pcx("eggcartn.pcx");
    init_graphics();
    doodle();
    dump_screen();
    closegraph();
    printf("Output in 'eggcartn.pcx'.\n");
    exit(0);
}  
/*      doodle      */
void doodle(void)
{
    int x,y,color;
    double xf,yf;
    if(mode & 4) eggsz *= 2.0;
    for(y = 0; y < MAX_Y; y++) {
        if(kbhit()) {
            getch();
            closegraph();
            exit(0);
        }
        yf = func(y);
        for(x = 0; x < MAX_X; x++) {
            xf = func(x);
            color = (int)(7.99 * (1 + xf * yf));
            putpixel(x,y,color);
        }
    }
}
/*      func    */
double func(int val)
{
    double res;
    
    res = mode & 1 ? val % (int) eggsz : val;
    if(mode & 2) {
        res /= eggsz / 2.0;
        res -= 1.0;
    }
    else {
        res *= M_PI / eggsz;
        res = cos(res);
    }
    return(mode & 8 ? res * 1.666 : res);
}
/* stuff for PCX dump routines */
struct pcx_header {
    char manufacturer, version, encoding, bits_per_pixel;
    int xmin, ymin, xmax, ymax, hres, vres;
    char colormap[16 * 3];
    char reserved, num_planes;
    int bytes_per_line, palette_code;
    char filler[58];
} header = {
    10,             /* manu */      5,              /* version */
    1,              /* encoding */  1,              /* bits per pixel */
    0,              /* xmin */      0,              /* ymin */
    639,            /* xmax */      479,            /* ymax */
    800,            /* src hres */  600,            /* src vres */
    0,0,0,          /* color 0 */   0x80,0,0,       /* color 1 */
    0,0x80,0,       /* color 2 */   0x80,0x80,0,    /* color 3 */
    0,0,0x80,       /* color 4 */   0x80,0,0x80,    /* color 5 */
    0,0x80,0x80,    /* color 6 */   0x80,0x80,0x80, /* color 7 */
    0xc0,0xc0,0xc0, /* color 8 */   0xff,0,0,       /* color 9 */
    0,0xff,0,       /* color 10 */  0xff,0xff,0,    /* color 11 */
    0,0,0xff,       /* color 12 */  0xff,0,0xff,    /* color 13 */
    0,0xff,0xff,    /* color 14 */  0xff,0xff,0xff, /* color 15 */
    0,              /* reserved */  4,              /* # planes */
    80,             /* bytes per line */
};
unsigned char planes[BPP * NPLANES];
FILE *pcx_fp;
#define pcx_putc(c) fputc(c,pcx_fp);
/*      dump_screen     */
void dump_screen(void)
{
    int x,y,color,mask;
    unsigned char *p;
    static masktab[] = {0x80,0x40,0x20,0x10,0x8,0x4,0x2,0x1};
    /* write PCX header */
    for(x = 0, p = (unsigned char *)&header; x < sizeof(header); x++)
        pcx_putc(*p++);
    /* write out the screen */  
    for(y = 0; y < MAX_Y; y++) {
        memset(planes,0,sizeof(planes)); /* clear planes */
        for(x = 0; x < MAX_X; x++) {     /* break color into sep planes */
            color = getpixel(x,y);
            mask = masktab[x & 7];
            p = &planes[x >> 3];
            if(color & 1) *p |= mask;
            p += BPP;
            if(color & 2) *p |= mask;
            p += BPP;
            if(color & 4) *p |= mask;
            p += BPP;
            if(color & 8) *p |= mask;
        }
        put_line(planes,BPP * NPLANES);
    }                   
}
/*      put_line    */
void put_line(unsigned char *data,int cnt)
{
    int i,byte,rep_cnt;
    for(i = rep_cnt = 0; i < cnt; i++) {
        if(rep_cnt == 0) {      /* no "current byte" */
            byte = data[i];
            rep_cnt = 1;
            continue;
        }
        if(data[i] == byte) {   /* same as previous, inc run length */
            rep_cnt++;
            /* full run then output */
            if(rep_cnt == 0x3f) {
                out_run(byte,rep_cnt);
                rep_cnt = 0;
            }
            continue;
        }
        out_run(byte,rep_cnt);  /* not equal to previous */
        byte = data[i];
        rep_cnt = 1;
    }
    if(rep_cnt)                 /* shove out any stragglers */
        out_run(byte,rep_cnt);
}
/*      out_run     */
void out_run(int byte,int rep_cnt)
{
    if((byte & 0xc0) == 0xc0 || rep_cnt > 1)
        pcx_putc(0xc0 | rep_cnt);
    pcx_putc(byte);
}
/*      open_pcx    */
void open_pcx(char *name)
{
    pcx_fp = fopen(name,"wb");
    if(pcx_fp == NULL) {
        printf("Can't open output PCX file '%s'.\n",name);
        exit(1);
    }
}
/*      init_graphics   */
void init_graphics(void)
{
    int graphdriver,graphmode,grapherr;
    /* set VGA 640x480 graphics mode */
    graphdriver = VGA;
    graphmode = VGAHI;
    initgraph(&graphdriver,&graphmode,"" );
    if((grapherr = graphresult()) != grOk) {
        printf("Graphics init error: %s\n",grapherrormsg(grapherr));
        exit(1);
    }
    /* make double sure we hit 640x480 mode */
    if(getmaxx() != MAX_X - 1 || getmaxy() != MAX_Y - 1) {
        closegraph();
        printf("Wrong screen size, x=%u y=%u.\n",getmaxx(),getmaxy());
        exit(1);
    }

Copyright © 1995, Dr. Dobb's Journal

Terms of Service | Privacy Statement | Copyright © 2024 UBM Tech, All rights reserved.