Next: , Previous: Animated GIFs, Up: C Programming


9.2.8 X Window System animations in C

You may use GNU libplot to produce vector graphics animations on any Plotter that does real-time plotting (i.e., an X, X Drawable, ReGIS, Tektronix, or Metafile Plotter). By definition, the `frames' in any page of graphics are separated by invocations of erase. So the graphics display will be cleared after each frame. If successive frames differ only slightly, a smooth animation will result.

The following is a sample application, written in C, that produces an animation for the X Window System. It displays a `drifting eye'. As the eye drifts across a popped-up window from left to right, it slowly rotates. After the eye has drifted across twice, the window will vanish.

     #include <stdio.h>
     #include <plot.h>
     
     int main ()
     {
       plPlotter *plotter;
       plPlotterParams *plotter_params;
       int i = 0, j;
     
       /* set Plotter parameters */
       plotter_params = pl_newplparams ();
       pl_setplparam (plotter_params, "BITMAPSIZE", "300x150");
       pl_setplparam (plotter_params, "VANISH_ON_DELETE", "yes");
       pl_setplparam (plotter_params, "USE_DOUBLE_BUFFERING", "yes");
     
       /* create an X Plotter with the specified parameters */
       if ((plotter = pl_newpl_r ("X", stdin, stdout, stderr,
                                  plotter_params)) == NULL)
         {
           fprintf (stderr, "Couldn't create Plotter\n");
           return 1;
         }
     
       if (pl_openpl_r (plotter) < 0)         /* open Plotter */
         {
           fprintf (stderr, "Couldn't open Plotter\n");
           return 1;
         }
       pl_fspace_r (plotter,
                    -0.5, -0.5, 299.5, 149.5);  /* set user coor system */
       pl_linewidth_r (plotter, 8);           /* set line thickness */
       pl_filltype_r (plotter, 1);            /* objects will be filled */
       pl_bgcolorname_r (plotter, "saddle brown"); /* set background color */
       for (j = 0; j < 300; j++)
         {
           pl_erase_r (plotter);                 /* erase window */
           pl_pencolorname_r (plotter, "red");   /* use red pen */
           pl_fillcolorname_r (plotter, "cyan"); /* use cyan filling */
           pl_ellipse_r (plotter, i, 75, 35, 50, i);  /* draw an ellipse */
           pl_colorname_r (plotter, "black"); /* use black pen and filling */
           pl_circle_r (plotter, i, 75, 12);  /* draw a circle [the pupil] */
           i = (i + 2) % 300;                 /* shift rightwards */
         }
       if (pl_closepl_r (plotter) < 0)        /* close Plotter */
         {
           fprintf (stderr, "Couldn't close Plotter\n");
           return 1;
         }
     
       if (pl_deletepl_r (plotter) < 0)       /* delete Plotter */
         {
           fprintf (stderr, "Couldn't delete Plotter\n");
           return 1;
         }
       return 0;
     }

As you can see, this application begins by calling pl_setplparam several times to set Plotter parameters, and then calls pl_newpl_r to create an X Plotter. The X Plotter window will have size 300x150 pixels. This window will vanish when the Plotter is deleted. If the VANISH_ON_DELETE parameter were not set to "yes", the window would remain on the screen until removed by the user (by typingq’ in it, or by clicking with a mouse).

Setting the parameter USE_DOUBLE_BUFFERING to "yes" requests that double buffering be used. This is very important if you wish to produce a smooth animation, with no jerkiness. Normally, an X Plotter draws graphics into a window in real time, and erases the window when pl_erase_r is called. But if double buffering is used, each frame of graphics is written into an off-screen buffer, and is copied into the window, pixel by pixel, when pl_erase_r is called or the Plotter is closed. This is exactly what is needed for smooth animation.

After the Plotter is created, it is selected for use and opened. When pl_openpl_r is called, the window pops up, and the animation begins. In the body of the for loop there is a call to pl_erase_r, and also a sequence of libplot operations that draws the eye. The pen color and fill color are changed twice with each passage through the loop. You may wish to experiment with the animation parameters to produce the best effects on your video hardware.

The positions of the objects that are plotted in the animation are expressed in terms of user coordinates, not pixel coordinates. But the call to pl_fspace_r defines user and pixel coordinates to be effectively the same. User coordinates are chosen so that the lower left corner of the rectangle mapped to the X window is (−0.5,−0.5) and the upper right corner is (299.5,149.5). Since this agrees with the window size, individual pixels may be addressed in terms of integer user coordinates. For example, pl_point_r(plotter,299,149) would set the pixel in the upper right corner of the window to the current pen color.

The following is another sample animation, this time of a rotating letter `A'.

     #include <stdio.h>
     #include <plot.h>
     
     int main()
     {
       plPlotter *plotter;
       plPlotterParams *plotter_params;
       int angle = 0;
     
       /* set Plotter parameters */
       plotter_params = pl_newplparams ();
       pl_setplparam (plotter_params, "BITMAPSIZE", "300x300");
       pl_setplparam (plotter_params, "USE_DOUBLE_BUFFERING", "yes");
       pl_setplparam (plotter_params, "BG_COLOR", "blue");
     
       /* create an X Plotter with the specified parameters */
       plotter = pl_newpl_r ("X", stdin, stdout, stderr, plotter_params);
     
       /* open X Plotter, initialize coordinates, pen, and font */
       pl_openpl_r (plotter);
       pl_fspace_r (plotter, 0.0, 0.0, 1.0, 1.0);  /* use normalized coors */
       pl_pencolorname_r (plotter, "white");
       pl_ffontsize_r (plotter, 1.0);
       pl_fontname_r (plotter, "NewCenturySchlbk-Roman");
     
       pl_fmove_r (plotter, 0.5, 0.5);        /* move to center */
       while (1)                              /* loop endlessly */
         {
           pl_erase_r (plotter);
           pl_textangle_r (plotter, angle++); /* set new rotation angle */
           pl_alabel_r (plotter, 'c', 'c', "A"); /* draw a centered `A' */
         }
       pl_closepl_r (plotter);                /* close Plotter */
     
       pl_deletepl_r (plotter);               /* delete Plotter */
       return 0;
     }

This animation serves as a good test of the capabilities of an X Window System display. On a modern X11R6 display, animation will be smooth and fast. That is because X11R6 displays can retrieve individual characters from a font without retrieving the entire font. If your X display does not support the "NewCenturySchlbk-Roman" font, you may substitute most core X fonts, such as the widely available scalable font "charter-medium-r-normal", or the traditional screen font "fixed". For the format of font names, see Text Fonts in X. If the X Plotter is unable to retrieve the font you specify, it will first attempt to use a default scalable font ("Helvetica", interpreted in the context of the X Window System as "helvetica-medium-r-normal"). If that too fails, it will use a default Hershey vector font ("HersheySerif") instead.

Animations that use Hershey fonts are normally faster than ones that use Postscript fonts or other X Window System fonts, since the Hershey fonts are constructed from line segments. Rasterizing line segments can be done rapidly.

If you are writing an application that performs a lengthy sequence of drawing operations on an X Plotter, you may find it useful to set the Plotter parameter X_AUTO_FLUSH to "no". By default, an X Plotter flushes all graphics to its X Window System display after each drawing operation. This flushing ensures that graphics are visible to the user immediately after they are drawn. However, it sometimes slows down the rendering process. For additional details on Plotter parameters, see Plotter Parameters.