abrash-black-book/35-04.html

167 lines
8.1 KiB
HTML

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta name="vsisbn" content="1576101746" />
<meta name="vstitle" content="Michael Abrash's Graphics Programming Black Book, Special Edition" />
<meta name="vsauthor" content="Michael Abrash" />
<meta name="vspublisher" content="The Coriolis Group" />
<meta name="vspubdate" content="07/01/97" />
<meta name="vscategory" content="Web and Software Development: Game Development,Web and Software Development: Graphics and Multimedia Development" />
<title>Michael Abrash's Graphics Programming Black Book Special Edition: Bresenham Is Fast, and Fast Is Good</title>
<meta name="chapter" content="35" />
<meta name="pages" content="664-667" />
</head>
<body>
<center>
<table border="1">
<tr>
<td>
<a href="35-03.html">Previous</a>
</td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td>
<a href="35-05.html">Next</a>
</td>
</tr>
</table>
</center>
<p><b>LISTING 35.2 L35-2.C</b></p>
<pre>
/*
* Sample program to illustrate EGA/VGA line drawing routines.
*
* Compiled with Borland C++
*
* By Michael Abrash
*/
#include &lt;dos.h&gt; /* 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 &lt; ( 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 &lt; ( 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 &gt;= ( XCenter - XLength ); WorkingX&mdash; )
EVGALine(XCenter, YCenter, WorkingX, WorkingY, Color);
/* Lines from center to left of rectangle */
WorkingX = XCenter - XLength;
WorkingY = YCenter + YLength - 1;
for ( ; WorkingY &gt;= ( YCenter - YLength ); WorkingY&mdash; )
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(&ldquo;%c&rdquo;, &amp;temp);
/* Return back to text mode */
_AX = TEXT_MODE;
geninterrupt(BIOS_VIDEO_INT);
}
</pre>
<h4 id="Heading7">Looking at EVGALine</h4>
<p>The <b>EVGALine</b> function itself performs four operations. <b>EVGALine</b> first sets up the VGA&rsquo;s hardware so that all pixels drawn will be in the desired color. This is accomplished by setting two of the VGA&rsquo;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 <b>EVGALine</b>, 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 <b>EVGALine</b> 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 <b>EVGALine</b> to draw a line in the specified color.</p>
<p><b>EVGALine</b> 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&rsquo;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.</p>
<table width="100%">
<tr>
<td width="5%" valign="top"><img src="images/i.jpg" /></td>
<td width="95%"><small><i>A moment of thought will show, however, that four of the line orientations are redundant. Each of the four orientations for which <b>DeltaY</b>, 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. <b>EVGALine</b> does this by swapping (X0,Y0) (the line start coordinates) with (X1,Y1) (the line end coordinates) whenever Y0 is greater than Y1.</i></small></td>
</tr>
</table>
<p>This accomplished, <b>EVGALine</b> 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 <b>DeltaX</b>, the X coordinate of the line. Consequently, for those cases where <b>DeltaX</b> is less than zero, the direction of X movement is made negative, and the absolute value of <b>DeltaX</b> is used for error term calculations.</p>
<p>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.</p>
<p><a id="Fig4"><img src="images/35-04.jpg" /><br />
<b>Figure 35.4</b></a>&nbsp;&nbsp;<i>Bresenham&rsquo;s eight possible line orientations.</i></p>
<center>
<table border="1">
<tr>
<td>
<a href="35-03.html">Previous</a>
</td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td>
<a href="35-05.html">Next</a>
</td>
</tr>
</table>
</center>
<hr width="90%" size="1" noshade="noshade" />
<div align="center">
Graphics Programming Black Book &copy; 2001 Michael Abrash
</div>
</body>
</html>