Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

Database

Do-It-Yourself Coordinates


JUL89: GRAPHICS PROGRAMMING

This marks what my wife would call the "six-month-aversary" of the "Graphics Programming" column. There's something about years that are multiples of five and months occurring on even boundaries of six that summon up the tendency to assess The Situation. A f rther spur is the increasing amount of mail and CompuServe traffic we've received at DDJ concerning this column. Most like it. A few hate it. One fellow even canceled his subscription because of it. I'm sorry he did. On the other hand, several thousand new members have married into the DDJ family during the past six months. Certainly, I don't take all the credit for that, but I'd like to think this column had something to do with it. Still, I feel compelled to answer a few criticisms and let you in on the grand strategy. And then we'll get down to this month's advancement of computer graphics, which is pretty significant.

Okay, critics, here's the Q&A:

Q: Why do I concentrate on the EGA/VGA, excluding all others?

A: Because that's the configuration I have, and most readers have as well. Admittedly there's also the Atari, Amiga, Mac II, TMS 34010, DGIS, Nth, Sun, Apollo. . . . You name it, and all wonderfully capable of graphics. And if I'd tried to serve every one of them, it would have taken a year to get past writing a single pixel, by which time 99 percent of the readership would have died of boredom. We have to make some progress here, and we do that by rallying around the common denominator. According to DDJ reader surveys, that's the EGA/VGA on a PC. All graphics rests, ultimately, on pixel-writing. If you have developed other machine solutions to the GRAFIX library, you're more than welcome to post them on CompuServe.

Q: Why C and assembly language?

A: Why not? Once again, we must have some common basis on which to proceed. C is used by 75 percent of DDJ readers, and it's the pre-eminent system's programming language. Most C programmers recognize that assembler is the alternative for writing high-performance subroutines. Certainly other languages are graphics capable as well. Prime examples are Pascal and Modula-2, for which I have a distinct and public fondness. A reader has offered to translate the GRAFIX library into Turbo Pascal and I'm all for it. But again, we must have a common point of reference. It's not hard to translate C code into other languages.

Q: Why don't I worry more about performance? For example, why is the Bresenham line-drawing algorithm written in C instead of assembly language?

A: Because the purpose of this column is to see how it's done. It's easier to understand C than assembler. Optimization --particularly in assembly language --obscures the underlying algorithm. Performance issues are, however, addressed. That's why hline() exists and why some other low-level routines are coded in assembly language. We're not developing a commercial graphics package here, but instead exploring the hows and whys. All of us --myself included and especially --are learning as we go along. You read a magazine that clearly states on its cover "for the professional programmer." That suggests a certain savoir faire, and I assume you're capable of rising to the occasion if you want more performance.

So much for the critics, whose wounds I have hopefully salved. Where are we going? Right now we're concentrating on the EGA, which is easier to understand than the VGA and produces acceptable graphics for most purposes. You'll note that some functions include "ega" in their names, as in egapixel(), set_ega_palreg(), and so on. Later we'll add functions with "vga" as part of their identifiers, and a top that we'll pile a set of bindings that select the appropriate function based on the current video mode.

In the long run we're headed for the VGA. It's the only commonly available and affordable PC video adapter capable of producing subtle shading and other visual effects that characterize high-level graphics.

Meanwhile, there's a lot of ground to cover. It would be wise to put a math coprocessor into your hardware budget, because by the end of the year we're going to be heavily into the floating point matrix operations that are inevitable in 3-D graphics.

In fact, if you don't have an '87 now, you'll begin this month to experience some of the performance degradation that floating point emulation introduces. For July is the month in which we enter the mystical realm of ...

Virtual Coordinates

All display devices have some sort of fixed coordinate system. In EGA graphics it's 640 x 350; for VGA it's 640 x 480. Others of less interest here might have a resolution of 1024 x 768 or 320 x 200 or whatever. This fixed system is generally referred to as the device coordinate space.

There are some problems with device coordinates. For one thing, the origin is (on the PC, at least) always in the upper left corner, which means that the Y value increases downward. That's counterintuitive, the reverse of graphing techniques taught from grade school onward. For another thing, the origin is not relocatable. What if you want the zero point in the middle of the screen with positive and negative coordinates? Yet another problem is distortion; pixels are not square in EGA graphics, yielding vertically elongated circles and other visual oddities. And finally, data values seldom map neatly into the device coordinate space. For example, how do you fit 30 data points evenly across 640 pixels?

The LINEGRAF.C program presented back in May dealt with some of these issues, but not in a very satisfying way. That's because it necessarily included a number of extraneous calculations required to convert the program's internal data representation into device coordinates.

Certainly it's necessary to perform these calculations, but there ought to be a better way: A way in which the programmer can define the screen coordinate space in terms of the data to be displayed, and then concentrate on the problem without worrying about the mechanics of mapping values to a specific display device.

And indeed there is. That's what virtual coordinates are all about.

The word virtual is so overworked in our industry that I hesitate to use it yet again. However, it's appropriate in this context. According to good old Webster, virtual means "denoting in essence or effect, without being so in fact." If you declare an effective display width of, say, 100 units when its actual width is 640, you've defined a virtual space. The same is of course true in the vertical (Y) space, which you might describe as something besides the EGA's 0 - 349 working downward.

The ability to redefine the screen dimensions in any terms you like greatly simplifies graphics programming. Your programs can then work with intuitive units as their internal data representation: dollars, percentages, months, data points, whatever. You can scale each axis independently, and also use different data types in the X and Y directions. For example, in plotting trigonometric functions you might assign the integral angles -360 to +360 as units along the X axis and floating-point increments from +1.0 at the top to -1.0 at the bottom along the Y. We'll do something like this later.

Virtual coordinates solve a number of graphics problems. The example just given "flips" the Y axis to correspond with the normal mathematical practice of increasing the Y value upward. Note also that it relocates the origin to the center of the physical screen.

Another vexing problem overcome by virtual coordinates is the "un-squareness" of pixels, a phenomenon often referred to in graphics literature as aspect ratio or orthogonal distortion. The normal display area has a height that is 75 percent of its width. If you divide height by width, the result is 0.75 if the pixels are square, or in other words if the vertical and horizontal units of measurement are equal. That works out to be true for the VGA in 640 x 480 graphics, but not for the EGA's 640 x 350 mode. The result is about 0.547, meaning that the physical height of a pixel is greater than its width. Some correction is therefore necessary on the EGA to produce round circles and square squares and other figures of consistent dimensions along both axes. Virtual coordinates let you make these corrections.

VCOORDS.C in Listing One performs the necessary magic to implement virtual coordinates. Your program defines the virtual space it wants by calling setcoords( ). The arguments are the left, top, right, and bottom of the display area, expressed in virtual units. For example, to set the trigonometric plot area mentioned earlier, write

  setcoords (-360, 1.0, 360, -1.0);

If you want a conventional (Y downward) plot area with virtually square pixels, write

  setcoords (0, 0, 639, 479);

With this virtual space, the EGA emulates the VGA's coordinate space, and it will produce images of dimensions identical to those drawn in native VGA mode.

The arguments are of type double. Because of the function prototype given in this month's additions to GRAFIX.H (Listing Two), the compiler automatically casts integral arguments to doubles, thus allowing you to pass any numeric data type to setcoords( ) with the expectation of reliability.

The secret of virtual coordinates lies in the four variables at the top of the VCOORDS compile unit: xf, yf, ox, and oy. The first two are conversion factors, which are multiplied by virtual coordinates to derive the corresponding device coordinates. By default these values are 1.0, yielding a 1-for-1 mapping of virtual to device units. If you set a virtual width of 320, however, xf becomes 2.0, meaning there are two device X units per virtual X.

The other two variables, ox and oy, represent the virtual origin in terms of device coordinates. They give the offsets to be added to converted virtual coordinates in order to map a virtual point to its specific device location. These values are normally zero, which initializes the virtual coordinate system to an origin in the upper-left corner. If you set up a virtual space with a call such as

  setcoords (-160, -120, 159, 119);

then after setcoords( ) executes, ox and oy will contain values close to the physical center of the screen.

The discussion so far assumes that you're operating in full-screen mode. However, the virtual coordinate system is relative to the current viewport. If the viewport's proportions differ from those of the full screen, the virtual space assumes a mapping that distorts accordingly. That is, when the current viewport has a physical height twice its width, a 4-to-3 ratio in the virtual space will yield "square" virtual pixels that are twice as high as wide. This characteristic produces infinite possibilities for scaling graphics output to suit your needs. We'll see an example shortly.

But first it's necessary to incorporate the virtual coordinate package into your copy of GRAFIX.LIB. Append the contents of Listing Two to GRAFIX.H, then compile VCOORDS.C. Add the object module to the library with the command

  LIB grafix + vcoords;

Having defined a virtual space with setcoords( ), your program can work internally with intuitive virtual units. An example is graphing budgeted amounts by quarter. The X axis can represent quarters 1 - 4, while the Y axis represents millions of dollars. At output time, the program calls upon the VCOORDS routines to map the virtual values to device coordinates by calling dx( ) and dy( ). Similarly, if the program wants to translate a virtual distance into device units, as in calling hline( ), draw_rect( ), and so on, it can call dxunits( ) and dyunits( ).

Let's see how it works to use virtual coordinates. The first example is TRIGPLOT.C in Listing Three. This program plots the sine, cosine, and their sum through two full circles (-360 to +360 degrees). The X axis is thus subdivided into 720 virtual units corresponding to integral degrees. The sine and cosine never exceed an absolute magnitude of 1.0, and so the Y axis uses floating point units. Addition of the curves, which have different periods, results in a fluctuation of about plus and minus 1.4, so the Y axis is scaled from +1.5 on top to -1.5 below. The virtual origin is at the center of the screen.

The program begins by scaling the axes with a call to setcoords( ), and then it draws the registration lines. The major axes appear in green, and reference lines in blue at virtual distances of +1.0 and -1.0 vertically. Three successive loops, stepping conveniently by degrees, control the drawing of the curves. The plot( ) routine does the real work, finding the virtual elevation of the point by calling the parametric function (cos( ), sin( ), or sum( )) and then advancing the curve to that point from the elevation of the previous angle.

The next example is LENDIST.C, Listing Four. This is a very different application of virtual coordinates. The program displays a histogram -- that is, a horizontal bar chart --showing the distribution of line lengths in a text file. Lines are grouped by multiples of five characters: 0 - 4, 5 - 9, etc. The longest possible line is assumed to be 80 characters. If yours are longer, modify MAXLEN at the top of the listing accordingly.

The program passes through the file named on the command line, counting the number of text lines within each grouping. It then finds the group with the highest count and normalizes all lines to that value, using 100 as the reference. That is, if maxcount is 86, the normalized value for the group containing 86 lines is 100. If another group contains 43 lines, its normalized value is 50, or half as many as the largest group.

Normalization is useful in this case because the graph must accommodate a wide range of potential values while setting aside a fixed amount of space for the bar legends. By normalizing the largest value to 100, we know how much space to leave for text: 22 virtual X units. And because there are 25 text rows on the screen, we can also establish the virtual Y axis as 25 units, with a range of -2 through 23 to leave room at the top for a label. Hence the values passed to setcoords( ) and the newlines in the printf( ) statements.

The rest is fairly obvious from the listing. The graph area setup entails drawing a rectangle around the whole works and marking registration lines at normalized intervals of 10 across the region where the bars will occur. Because of the virtual Y spacing, whose origin is two text lines down from the top, each bar lines up with its legend. Its height is 75 percent of a single Y unit to provide cosmetic spacing.

Hey, we're starting to produce useful graphics applications!

The final example considers the effect of the viewport shape on the scaling of the virtual coordinate space. A "square" space with a 4-to-3 ratio turns out not to be square if the containing viewport isn't of the same ratio as the device. Instead, the vertical and horizontal virtual spacing automatically adjust to fit the viewport dimensions.

The case in point is RESIZE.C, Listing Five. This program displays a four-pointed star in each of three viewports. The same routine -- drawstar( ) -- draws and fills the figure each time using identical virtual coordinates, which assume a square space with its origin at the center. However, because set_up( ) establishes different viewport dimensions, the lengths of the X and Y units change. The first viewport is square, with a 4-to-3 ratio. The other two, however, are tall and skinny, and short and fat. The star in each maintains its spatial relationship to the viewport, but the shape is dramatically different.

The ability to redefine the display's coordinate system opens the door to great possibilities for data representation in graphics. Now that we know how to do it, we'll use virtual coordinates often as we move onward.

Happy six-month-aversary.

Availability

All source code for articles in this issue is available on a single disk. To order, send $14.95 (Calif. residents add sales tax) to Dr. Dobb's Journal, 501 Galveston Dr., Redwood City, CA 94063; or call 800-356-2002 (from inside Calif.) or 800-533-4372 (from outside Calif.). Please specify the issue number and format (MS-DOS, Macintosh, Kaypro).

_GRAPHICS PROGRAMMING COLUMN_ by Kent Porter

[LISTING ONE]

<a name="015d_0007">


/* VCOORDS.C: Implements virtual coordinates in GRAFIX library */
/* K. Porter, DDJ Graphics Programming Column, July '89 */

#include <math.h>
#include "grafix.h"

/* Variables for this compile unit */
double xf = 1.0, yf = 1.0;                 /* x, y conversion factors */
double ox = 0.0, oy = 0.0;                     /* virtual x, y origin */
/* ------------------------------------------------------------------ */
/* set virtual coordinate space */
void far setcoords (double left, double top, double right, double bottom)
{
  xf = (double) vp_width() / (right - left);    /* conversion factors */
  yf = (double) vp_height() / (bottom - top);
  ox = (double) vp_width() - (right * xf);                  /* origin */
  oy = (double) vp_height() - (bottom * yf);
} /* ---------------------------------------------------------------- */

int far dx (double vx)               /* convert virtual x to device x */
{
  return (xf * vx) + ox;
} /* ---------------------------------------------------------------- */

int far dy (double vy)               /* convert virtual y to device y */
{
  return (yf * vy) + oy;
} /* ---------------------------------------------------------------- */

int far dxunits (double vx)                  /* device x units for vx */
{
  return (int)(fabs)(xf * vx);
} /* ---------------------------------------------------------------- */

int far dyunits (double vy)                  /* device y units for vy */
{
  return (int)(fabs)(yf * vy);
} /* ---------------------------------------------------------------- */





<a name="015d_0008"><a name="015d_0008">
<a name="015d_0009">
[LISTING TWO]
<a name="015d_0009">

Caption: Add this to your copy of GRAFIX.H

/* From July, '89 */
/* -------------- */
void far setcoords                  /* set virtual coordinate space */
        (double left, double top, double right, double bottom);

int far dx (double vx);            /* convert virtual x to device x */

int far dy (double vy);            /* convert virtual y to device y */

int far dxunits (double vx);               /* device x units for vx */

int far dyunits (double vy);               /* device y units for vy */






<a name="015d_000a"><a name="015d_000a">
<a name="015d_000b">
[LISTING THREE]
<a name="015d_000b">

/* TRIGPLOT.C: Plot sine, cosine, and their sum */
/* X axis is integral, Y axis is floating-point */

#include <math.h>
#include <conio.h>
#include "grafix.h"
#define DEG2RAD 3.1415927 / 180.0    /* degrees to radians */

int px = 999, py;                    /* previous point */

void main ()
{
void   plot (int angle, double (*fcn)(double theta));
double sum (double);
int    angle;

  if (init_video (EGA)) {

    /* Scale the axes */
    setcoords (-360, 1.5, 360, -1.5);

    /* Draw the registration lines */
    set_color1 (2);                               /* green  */
    hline (dx(-360), dy(0), dxunits (720));       /* x axis */
    draw_line (dx(0), dy(1.3), dx(0), dy(-1.3));  /* y axis */
    set_color1 (1);                               /* blue   */
    hline (dx(-360), dy(1), dxunits (720));       /* +1.0   */
    hline (dx(-360), dy(-1),dxunits (720));       /* -1.0   */

    /* Plot the sine curve */
    set_color1 (3);                               /* cyan   */
    for (angle = -360; angle <= 360; angle++)
      plot (angle, sin);

    /* Plot the cosine curve */
    set_color1 (5);                               /* magenta */
    px = 999;                                     /* new curve */
    for (angle = -360; angle <= 360; angle++)
      plot (angle, cos);

    /* Plot the sum of sine and cosine */
    set_color1 (15);                              /* white */
    px = 999;                                     /* new */
    for (angle = -360; angle <= 360; angle++)
      plot (angle, sum);

    /* Wait for keypress and quit */
    getch();
  }
} /* ------------------------ */

double sum (double theta)
{
  return (sin (theta) + cos (theta));
} /* ------------------------ */

void plot (int angle, double (*fcn)(double theta))
{
double theta, y;

  theta = (double) angle * DEG2RAD;      /* convert to radians */
  y = (*fcn) (theta);                    /* derive value       */
  if (px != 999)                         /* if not first point */
    draw_line (px, py, dx (angle), dy (y));
  px = dx (angle);                       /* save current point */
  py = dy (y);
} /* ------------------------ */






<a name="015d_000c"><a name="015d_000c">
<a name="015d_000d">
[LISTING FOUR]
<a name="015d_000d">


/* LENDIST.C: Produces a histogram of line lengths in a text file */
/* Illustrates integral virtual coords, self-scaling bar chart */

#include <stdio.h>
#include <string.h>
#include <conio.h>
#include <stdlib.h>
#include "grafix.h"
#define MAXLEN 80              /* max length of a line */
#define MAXCAT MAXLEN / 5      /* number of categories */

void main (int argc, char *argv[])
{
double group [MAXCAT];      /* results array */
int    category;            /* grouping by length (0-4, 5-9, etc) */
double maxcount = 0;        /* highest count for any category */
int    color = 1;           /* color of histogram bar */
char   buf [MAXLEN];        /* receiving buffer */
FILE   *fp;                 /* text file pointer */

  /* check command line for a filename */
  if (argc < 2) {
    puts ("Usage: LENDIST <filename.ext>");
    exit (EXIT_FAILURE);
  }

  /* clear the length array */
  for (category = 0; category < MAXCAT; category++)
    group [category] = 0.0;

  /* pass thru the file getting lengths of lines */
  if ((fp = fopen (argv[1], "r")) == NULL) {
    printf ("Unable to open %s\n", argv[1]);
    exit (EXIT_FAILURE);
  } else {
    while (fgets (buf, MAXLEN, fp)) {
      category = strlen (buf) / 5;     /* group 0-4, 5-9, etc. */
      ++group [category];              /* count */
    }
    fclose (fp);
  }

  /* find highest count of any group */
  for (category = 0; category < MAXCAT; category++)
    if (group [category] > maxcount)
      maxcount = group [category];

  /* Normalize groupings to 100 */
  for (category = 0; category < MAXCAT; category++)
    group [category] /= (maxcount / 100);

  /* enter graphics mode */
  if (init_video (EGA)) {

    /* scale the histogram width */
    /* leave space on top and left for text */
    setcoords (-22, -2, 100, 23);

    /* label the histogram */
    printf ("Distribution of line lengths in %s\n\n", argv[1]);
    for (category = 0; category < MAXCAT; category++)
      printf (" Length %2d-%2d:\n", category*5, (category*5)+4);

    /* set up the graph area */
    draw_rect (dx(-22), dy (-1), dxunits (122),
               dyunits(MAXCAT + 2));
    set_color1 (1);   /* blue */
    for (category = 0; category < 100; category+=10)
      draw_line (dx(category), dy(-0.5), dx(category), dy(MAXCAT));

    /* draw the histogram bars */
    for (category = 0; category < MAXCAT; category++) {
      set_color1 (color);
      if (++color == 16) color = 1;
      fill_rect (dx (0), dy (category), dxunits (group [category]),
                 dyunits (0.75));
    }

    /* hold for keypress, then quit */
    getch();
    pc_textmode();
  } else
    puts ("Unable to enter EGA graphics");
}






<a name="015d_000e"><a name="015d_000e">
<a name="015d_000f">
[LISTING FIVE]
<a name="015d_000f">

/* RESIZE.C: Effects of resizing virtual coords to fit viewports */

#include "grafix.h"
#include <conio.h>
#include <stdio.h>
#define  BORDER 15

void main ()
{
void set_vp (int, int, int, int);

  if (init_video (EGA)) {

    /* Set colors for shading */
    set_ega_palreg (1, ega_blend (RED3, GRN1, BLU0));
    set_ega_palreg (2, ega_blend (RED2, GRN1, BLU0));
    set_ega_palreg (3, ega_blend (RED2, GRN0, BLU0));

    /* Draw 4-pointed star in variously-sized viewports */
    set_vp (1, 1, 160, 120);          /* square */
    set_vp (200, 1, 120, 347);        /* tall and skinny */
    set_vp (360, 270, 238, 78);       /* short and fat */

    /* Wait for keypress and quit */
    getch();
    pc_textmode();
  } else
    puts ("Unable to enter EGA graphics");
} /* ---------------------------------- */

void set_vp (int left, int top, int width, int height)
{
VP_HAN vp;
void drawstar (void);

  vp = vp_open (left, top, width, height);
  set_color1 (BORDER);
  vp_outline (vp);
  setcoords (-120, 120, 120, -120);  /* constants scale to vp size */
  drawstar();
  vp_close (vp);
} /* ---------------------------------- */

void drawstar (void)
{
  set_color1 (BORDER);     /* border color */
  setfillborder (BORDER);
  draw_rect (dx(-30), dy(-30), dxunits(60), dyunits(60));
  set_color1 (3);      /* center of star */
  floodfill (dx(0), dy(0));

  set_color1 (BORDER);
  draw_line (dx(-30), dy(30), dx(0), dy(100));  /* top ray */
  draw_line (dx(0), dy(100), dx(30), dy(30));
  draw_line (dx(0), dy(100), dx(0), dy(30));

  draw_line (dx(-30), dy(30), dx(-100), dy(0));  /* left ray */
  draw_line (dx(-100), dy(0), dx(-30), dy(-30));
  draw_line (dx(-100), dy(0), dx(-30), dy(0));

  draw_line (dx(-30), dy(-30), dx(0), dy(-100));  /* bottom ray */
  draw_line (dx(0), dy(-100), dx(30), dy(-30));
  draw_line (dx(0), dy(-100), dx(0), dy(-30));

  draw_line (dx(30), dy(-30), dx(100), dy(0));  /* right ray */
  draw_line (dx(100), dy(0), dx(30), dy(30));
  draw_line (dx(100), dy(0), dx(30), dy(0));

  set_color1 (1);
  floodfill (dx(10), dy(40));
  floodfill (dx(-40), dy(20));
  floodfill (dx(10), dy(-40));
  floodfill (dx(40), dy(20));

  set_color1 (2);
  floodfill (dx(-10), dy(40));
  floodfill (dx(-40), dy(-20));
  floodfill (dx(-10), dy(-40));
  floodfill (dx(40), dy(-20));
}



[GRAFIX.LIB]

/* Include file for GRAFIX.LIB                */
/* EGA/VGA graphics subsystem                 */
/* K. Porter, DDJ Graphics Programming Column */
/* ------------------------------------------ */

/* Color constants from April, 89 */
#define Black     0        /* standard colors */
#define Blue      1
#define Green     2
#define Cyan      3
#define Red       4
#define Magenta   5
#define Brown     0x14
#define LtGray    7
#define DkGray    0x38
#define LtBlue    0x39
#define LtGreen   0x3A
#define LtCyan    0x3B
#define LtRed     0x3C
#define LtMagenta 0x3D
#define Yellow    0x3E
#define White     0x3F

#define RED0      0x00  /* basic hues for mixing */
#define RED1      0x20
#define RED2      0x04
#define RED3      0x24
#define GRN0      0x00
#define GRN1      0x10
#define GRN2      0x02
#define GRN3      0x12
#define BLU0      0x00
#define BLU1      0x08
#define BLU2      0x01
#define BLU3      0x09

#if !defined byte
#define byte unsigned char
#endif

/* Supported video modes */
#define  EGA       0x10              /* EGA 640 x 350, 16/64 colors */
#define  VGA16     0x11              /* VGA 640 x 480, 16/64 colors */

/* Function prototypes */
/* From February, '89 */
/* ------------------ */
int far init_video (int mode);        /* init display in video mode */

void far pc_textmode (void);                        /* PC text mode */

void far draw_point (int x, int y);        /* write pixel in color1 */

void far set_color1 (int palette_reg);      /* set foreground color */

/* From March, '89 */
/* --------------- */
void far draw_line (int x1, int y1, int x2, int y2);
                                /* Bresenham line drawing algorithm */

void far draw_rect (int left, int top, int width, int height);
                             /* draw rectangle from top left corner */

void far polyline (int edges, int vertices[]);     /* draw polyline */

void far hline (int x, int y, int len);          /* horizontal line */

void far fill_rect (int left, int top, int width, int height);
      /* draw solid rectangle in color1 starting at top left corner */

/* From April, '89 */
/* --------------- */
byte far ega_palreg (int preg);         /* color in EGA palette reg */

void far set_ega_palreg (int reg, int color);    /* set palette reg */

byte far colorblend (byte r, byte g, byte b);         /* blend hues */

void far get_ega_colormix (int preg, int *r, int *g, int *b);
        /* get mix of red, green, and blue in EGA pal register preg */

/* From May, '89 */
/* ------------- */
typedef int VP_HAN;                         /* viewport handle type */

void far default_viewport (int height);    /* init default viewport */

VP_HAN far vp_open (int x, int y, int width, int height);
                                   /* open viewport, make it active */

int far vp_use (VP_HAN vp);                       /* make vp active */

void far vp_close (VP_HAN vp);                    /* close viewport */

VP_HAN far vp_active (void);             /* get handle of active vp */

void far vp_outline (VP_HAN vp);                      /* outline vp */

int far vp_width (void);               /* get active viewport width */

int far vp_height (void);                             /* and height */

/* From June, '89 */
/* -------------- */
int far egapixel (int x, int y);         /* get pixel value at x, y */

int far floodfill (int  sx, int sy,        /* seed coords */
                   int  border,            /* border color */
                   int  dir,               /* pass as 0 */
                   int  pleft, int prite); /* make same as sx */











Copyright © 1989, Dr. Dobb's Journal


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.