Initial conversion to markdown
This commit is contained in:
parent
a96a114403
commit
5e10794a24
362 changed files with 67353 additions and 0 deletions
142
35-01.md
Normal file
142
35-01.md
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
------------------------ --------------------------------- --------------------
|
||||
[Previous](34-05.html) [Table of Contents](index.html) [Next](35-02.html)
|
||||
------------------------ --------------------------------- --------------------
|
||||
|
||||
Chapter 35\
|
||||
Bresenham Is Fast, and Fast Is Good {#Heading1}
|
||||
------------------------------------
|
||||
|
||||
### Implementing and Optimizing Bresenham’s Line-Drawing Algorithm {#Heading2}
|
||||
|
||||
For all the complexity of graphics design and programming, surprisingly
|
||||
few primitive functions lie at the heart of most graphics software.
|
||||
Heavily used primitives include routines that draw dots, circles, area
|
||||
fills, bit block logical transfers, and, of course, lines. For many
|
||||
years, computer graphics were created primarily with specialized
|
||||
line-drawing hardware, so lines are in a way the *lingua franca* of
|
||||
computer graphics. Lines are used in a wide variety of microcomputer
|
||||
graphics applications today, notably CAD/CAM and computer-aided
|
||||
engineering.
|
||||
|
||||
Probably the best-known formula for drawing lines on a computer display
|
||||
is called Bresenham’s line-drawing algorithm. (We have to be specific
|
||||
here because there is also a less-well-known Bresenham’s circle-drawing
|
||||
algorithm.) In this chapter, I’ll present two implementations for the
|
||||
EGA and VGA of Bresenham’s line-drawing algorithm, which provides decent
|
||||
line quality and excellent drawing speed.
|
||||
|
||||
The first implementation is in rather plain C, with the second in
|
||||
not-so-plain assembly, and they’re both pretty good code. The assembly
|
||||
implementation is damned good code, in fact, but if you want to know
|
||||
whether it’s the fastest Bresenham’s implementation possible, I must
|
||||
tell you that it isn’t. First of all, the code could be sped up a bit by
|
||||
shuffling and combining the various error-term manipulations, but that
|
||||
results in *truly* cryptic code. I wanted you to be able to relate the
|
||||
original algorithm to the final code, so I skipped those optimizations.
|
||||
Also, write mode 3, which is unique to the VGA, could be used for
|
||||
considerably faster drawing. I’ve described write mode 3 in earlier
|
||||
chapters, and I strongly recommend its use in VGA-only line drawing.
|
||||
|
||||
Second, horizontal, vertical, and diagonal lines could be special-cased,
|
||||
since those particular lines require little calculation and can be drawn
|
||||
very rapidly. (This is especially true of horizontal lines, which can be
|
||||
drawn 8 pixels at a time.)
|
||||
|
||||
Third, run-length slice line drawing could be used to significantly
|
||||
reduce the number of calculations required per pixel, as I’ll
|
||||
demonstrate in the next two chapters.
|
||||
|
||||
Finally, unrolled loops and/or duplicated code could be used to
|
||||
eliminate most of the branches in the final assembly implementation, and
|
||||
because x86 processors are notoriously slow at branching, that would
|
||||
make quite a difference in overall performance. If you’re interested in
|
||||
unrolled loops and similar assembly techniques, I refer you to the first
|
||||
part of this book.
|
||||
|
||||
That brings us neatly to my final point: Even if I didn’t know that
|
||||
there were further optimizations to be made to my line-drawing
|
||||
implementation, I’d *assume* that there were. As I’m sure the
|
||||
experienced assembly programmers among you know, there are dozens of
|
||||
ways to tackle any problem in assembly, and someone else always seems to
|
||||
have come up with a trick that never occurred to you. I’ve incorporated
|
||||
a suggestion made by Jim Mackraz in the code in this chapter, and I’d be
|
||||
most interested in hearing of any other tricks or tips you may have.
|
||||
|
||||
Notwithstanding, the line-drawing implementation in Listing 35.3 is
|
||||
plenty fast enough for most purposes, so let’s get the discussion
|
||||
underway.
|
||||
|
||||
### The Task at Hand {#Heading3}
|
||||
|
||||
There are two important characteristics of any line-drawing function.
|
||||
First, it must draw a reasonable approximation of a line. A computer
|
||||
screen has limited resolution, and so a line-drawing function must
|
||||
actually approximate a straight line by drawing a series of pixels in
|
||||
what amounts to a jagged pattern that generally proceeds in the desired
|
||||
direction. That pattern of pixels must reliably suggest to the human eye
|
||||
the true line it represents. Second, to be usable, a line-drawing
|
||||
function must be *fast*. Minicomputers and mainframes generally have
|
||||
hardware that performs line drawing, but most microcomputers offer no
|
||||
such assistance. True, nowadays graphics accelerators such as the S3 and
|
||||
ATI chips have line drawing hardware, but some other accelerators don’t;
|
||||
when drawing lines on the latter sort of chip, when drawing on the CGA,
|
||||
EGA, and VGA, and when drawing sorts of lines not supported by
|
||||
line-drawing hardware as well, the PC’s CPU must draw lines on its own,
|
||||
and, as many users of graphics-oriented software know, that can be a
|
||||
slow process indeed.
|
||||
|
||||
Line drawing quality and speed derive from two factors: The algorithm
|
||||
used to draw the line and the implementation of that algorithm. The
|
||||
first implementation (written in Borland C++) that I’ll be presenting in
|
||||
this chapter illustrates the workings of the algorithm and draws lines
|
||||
at a good rate. The second implementation, written in assembly language
|
||||
and callable directly from Borland C++, draws lines at extremely high
|
||||
speed, on the order of three to six times faster than the C version.
|
||||
Between them, the two implementations illuminate Bresenham’s
|
||||
line-drawing algorithm and provide high-performance line-drawing
|
||||
capability.
|
||||
|
||||
The difficulty in drawing a line lies in generating a set of pixels
|
||||
that, taken together, are a reasonable facsimile of a true line. Only
|
||||
horizontal, vertical, and 1:1 diagonal lines can be drawn precisely
|
||||
along the true line being represented; all other lines must be
|
||||
approximated from the array of pixels that a given video mode supports,
|
||||
as shown in Figure 35.1.
|
||||
|
||||
Considerable thought has gone into the design of line-drawing
|
||||
algorithms, and a number of techniques for drawing high-quality lines
|
||||
have been developed. Unfortunately, most of these techniques were
|
||||
developed for powerful, expensive graphics workstations and require very
|
||||
high resolution, a large color palette, and/or floating-point hardware.
|
||||
These techniques tend to perform poorly and produce less visually
|
||||
impressive results on all but the best-endowed PCs.
|
||||
|
||||
Bresenham’s line-drawing algorithm, on the other hand, is uniquely
|
||||
suited to microcomputer implementation in that it requires no
|
||||
floating-point operations, no divides, and no multiplies inside the
|
||||
line-drawing loop. Moreover, it can be implemented with surprisingly
|
||||
little code.
|
||||
|
||||
### Bresenham’s Line-Drawing Algorithm {#Heading4}
|
||||
|
||||
The key to grasping Bresenham’s algorithm is to understand that when
|
||||
drawing an approximation of a line on a finite-resolution display, each
|
||||
pixel drawn will lie either exactly on the true line or to one side or
|
||||
the other of the true line. The amount by which the pixel actually drawn
|
||||
deviates from the true line is the *error* of the line drawing at that
|
||||
point. As the drawing of the line progresses from one pixel to the next,
|
||||
the error can be used to tell when, given the resolution of the display,
|
||||
a more accurate approximation of the line can be drawn by placing a
|
||||
given pixel one unit of screen resolution away from its predecessor in
|
||||
either the horizontal or the vertical direction, or both.
|
||||
|
||||
\
|
||||
**Figure 35.1** *Approximating a true line from a pixel array.*
|
||||
|
||||
------------------------ --------------------------------- --------------------
|
||||
[Previous](34-05.html) [Table of Contents](index.html) [Next](35-02.html)
|
||||
------------------------ --------------------------------- --------------------
|
||||
|
||||
* * * * *
|
||||
|
||||
Graphics Programming Black Book © 2001 Michael Abrash
|
||||
Loading…
Reference in a new issue