abrash-black-book/35-04.md
2013-12-30 20:26:41 +11:00

143 lines
7.8 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

**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 0x10
#define TEXT_MODE 0x03
#define BIOS_VIDEO_INT 0x10
#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 {#Heading7}
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.
------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
![](images/i.jpg) *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.
![](images/35-04.jpg)\
**Figure 35.4**  *Bresenham's eight possible line orientations.*