Previous | Table of Contents | Next

LISTING 35.2 L35-2.C

    /*
     * Sample program to illustrate EGA/VGA line drawing routines.
     *
     * Compiled with Borland C++
     *
     * By Michael Abrash
     */

    #include <dos.h>     /* contains geninterrupt */

    #define GRAPHICS_MODE   0×10
    #define TEXT_MODE       0×03
    #define BIOS_VIDEO_INT  0×10
    #define X_MAX           640      /* working screen width */
    #define Y_MAX           348      /* working screen height */

    extern void EVGALine();

    /*
     * Subroutine to draw a rectangle full of vectors, of the specified
     * length and color, around the specified rectangle center.
     */
    void VectorsUp(XCenter, YCenter, XLength, YLength, Color)
    int XCenter, YCenter;   /* center of rectangle to fill */
    int XLength, YLength;   /* distance from center to edge
                               of rectangle */
    int Color;              /* color to draw lines in */
    {
       int WorkingX, WorkingY;

       /* Lines from center to top of rectangle */
       WorkingX = XCenter - XLength;
       WorkingY = YCenter - YLength;
       for ( ; WorkingX < ( XCenter + XLength ); WorkingX++ )
          EVGALine(XCenter, YCenter, WorkingX, WorkingY, Color);

       /* Lines from center to right of rectangle */
       WorkingX = XCenter + XLength - 1;
       WorkingY = YCenter - YLength;
       for ( ; WorkingY < ( YCenter + YLength ); WorkingY++ )
          EVGALine(XCenter, YCenter, WorkingX, WorkingY, Color);

       /* Lines from center to bottom of rectangle */
       WorkingX = XCenter + XLength - 1;
       WorkingY = YCenter + YLength - 1;
       for ( ; WorkingX >= ( XCenter - XLength ); WorkingX— )
          EVGALine(XCenter, YCenter, WorkingX, WorkingY, Color);

       /* Lines from center to left of rectangle */
       WorkingX = XCenter - XLength;
       WorkingY = YCenter + YLength - 1;
       for ( ; WorkingY >= ( YCenter - YLength ); WorkingY— )
          EVGALine(XCenter, YCenter, WorkingX, WorkingY, Color );
    }

    /*
     * Sample program to draw four rectangles full of lines.
     */
    void main()
    {
       char temp;

       /* Set graphics mode */
       _AX = GRAPHICS_MODE;
       geninterrupt(BIOS_VIDEO_INT);

       /* Draw each of four rectangles full of vectors */
       VectorsUp(X_MAX / 4, Y_MAX / 4, X_MAX / 4,
          Y_MAX / 4, 1);
       VectorsUp(X_MAX * 3 / 4, Y_MAX / 4, X_MAX / 4,
          Y_MAX / 4, 2);
       VectorsUp(X_MAX / 4, Y_MAX * 3 / 4, X_MAX / 4,
          Y_MAX / 4, 3);
       VectorsUp(X_MAX * 3 / 4, Y_MAX * 3 / 4, X_MAX / 4,
          Y_MAX / 4, 4);

       /* Wait for the enter key to be pressed */
       scanf(“%c”, &temp);

       /* Return back to text mode */
       _AX = TEXT_MODE;
       geninterrupt(BIOS_VIDEO_INT);
    }

#### Looking at EVGALine

The EVGALine function itself performs four operations. EVGALine first sets up the VGA’s hardware so that all pixels drawn will be in the desired color. This is accomplished by setting two of the VGA’s registers, the Enable Set/Reset register and the Set/Reset register. Setting the Enable Set/Reset to the value 0FH, as is done in EVGALine, causes all drawing to produce pixels in the color contained in the Set/Reset register. Setting the Set/Reset register to the passed color, in conjunction with the Enable Set/Reset setting of 0FH, causes all drawing done by EVGALine and the functions it calls to generate the passed color. In summary, setting up the Enable Set/Reset and Set/Reset registers in this way causes the remainder of EVGALine to draw a line in the specified color.

EVGALine next performs a simple check to cut in half the number of line orientations that must be handled separately. Figure 35.4 shows the eight possible line orientations among which a Bresenham’s algorithm implementation must distinguish. (In interpreting Figure 35.4, assume that lines radiate outward from the center of the figure, falling into one of eight octants delineated by the horizontal and vertical axes and the two diagonals.) The need to categorize lines into these octants falls out of the major/minor axis nature of the algorithm; the orientations are distinguished by which coordinate forms the major axis and by whether each of X and Y increases or decreases from the line start to the line end.

| A moment of thought will show, however, that four of the line orientations are redundant. Each of the four orientations for which DeltaY, the Y component of the line, is less than 0 (that is, for which the line start Y coordinate is greater than the line end Y coordinate) can be transformed into one of the four orientations for which the line start Y coordinate is less than the line end Y coordinate simply by reversing the line start and end coordinates, so that the line is drawn in the other direction. EVGALine does this by swapping (X0,Y0) (the line start coordinates) with (X1,Y1) (the line end coordinates) whenever Y0 is greater than Y1.

This accomplished, EVGALine must still distinguish among the four remaining line orientations. Those four orientations form two major categories, orientations for which the X dimension is the major axis of the line and orientations for which the Y dimension is the major axis. As shown in Figure 35.4, octants 1 (where X increases from start to finish) and 2 (where X decreases from start to finish) fall into the latter category, and differ in only one respect, the direction in which the X coordinate moves when it changes. Handling of the running error of the line is exactly the same for both cases, as one would expect given the symmetry of lines differing only in the sign of DeltaX, the X coordinate of the line. Consequently, for those cases where DeltaX is less than zero, the direction of X movement is made negative, and the absolute value of DeltaX is used for error term calculations.

Similarly, octants 0 (where X increases from start to finish) and 3 (where X decreases from start to finish) differ only in the direction in which the X coordinate moves when it changes. The difference between line drawing in octants 0 and 3 and line drawing in octants 1 and 2 is that in octants 0 and 3, since X is the major axis, the X coordinate changes on every pixel of the line and the Y coordinate changes only when the running error of the line dictates. In octants 1 and 2, the Y coordinate changes on every pixel and the X coordinate changes only when the running error dictates, since Y is the major axis.

Figure 35.4 Bresenham’s eight possible line orientations.

Previous | Table of Contents | Next

Graphics Programming Black Book © 2001 Michael Abrash