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

72 lines
4.1 KiB
Markdown

The result of all this is simply a single pixel drawn in the color set
up in **EVGALine**. **EVGADot** may seem excessively complex for a
function that does nothing more that draw one pixel, but programming the
VGA isn't trivial (as we've seen in the early chapters of this part).
Besides, while the explanation of **EVGADot** is lengthy, the code
itself is only five lines long.
Line drawing would be somewhat faster if the code of **EVGADot** were
made an inline part of **Octant0** and **Octant1**, thereby saving the
overhead of preparing parameters and calling the function. Feel free to
do this if you wish; I maintained **EVGADot** as a separate function for
clarity and for ease of inserting a pixel-drawing function for a
different graphics adapter, should that be desired. If you do install a
pixel-drawing function for a different adapter, or a fundamentally
different mode such as a 256-color SuperVGA mode, remember to remove the
hardware-dependent **outportb** lines in **EVGALine** itself.
### Comments on the C Implementation {#Heading10}
**EVGALine** does no error checking whatsoever. My assumption in writing
**EVGALine** was that it would be ultimately used as the lowest-level
primitive of a graphics software package, with operations such as error
checking and clipping performed at a higher level. Similarly,
**EVGALine** is tied to the VGA's screen coordinate system of (0,0) to
(639,199) (in mode 0EH), (0,0) to (639,349) (in modes 0FH and 10H), or
(0,0) to (639,479) (in mode 12H), with the upper left corner considered
to be (0,0). Again, transformation from any coordinate system to the
coordinate system used by **EVGALine** can be performed at a higher
level. **EVGALine** is specifically designed to do one thing: draw lines
into the display memory of the VGA. Additional functionality can be
supplied by the code that calls **EVGALine**.
The version of **EVGALine** shown in Listing 35.1 is reasonably fast,
but it is not as fast as it might be. Inclusion of **EVGADot** directly
into **Octant0** and **Octant1**, and, indeed, inclusion of **Octant0**
and **Octant1** directly into **EVGALine** would speed execution by
saving the overhead of calling and parameter passing. Handpicked
register variables might speed performance as well, as would the use of
word **OUT**s rather than byte **OUT**s. A more significant performance
increase would come from eliminating separate calculation of the address
and mask for each pixel. Since the location of each pixel relative to
the previous pixel is known, the address and mask could simply be
adjusted from one pixel to the next, rather than recalculated from
scratch.
These enhancements are not incorporated into the code in Listing 35.1
for a couple of reasons. One reason is that it's important that the
workings of the algorithm be clearly visible in the code, for learning
purposes. Once the implementation is understood, rewriting it for
improved performance would certainly be a worthwhile exercise. Another
reason is that when flat-out speed is needed, assembly language is the
best way to go. Why produce hard-to-understand C code to boost speed a
bit when assembly-language code can perform the same task at two or more
times the speed?
Given which, a high-speed assembly language version of **EVGALine**
would seem to be a logical next step.
### Bresenham's Algorithm in Assembly {#Heading11}
Listing 35.3 is a high-performance implementation of Bresenham's
algorithm, written entirely in assembly language. The code is callable
from C just as is Listing 35.1, with the same name, **EVGALine**, and
with the same parameters. Either of the two can be linked to any program
that calls **EVGALine**, since they appear to be identical to the
calling program. The only difference between the two versions is that
the sample program in Listing 35.2 runs over three times as fast on a
486 with an ISA-bus VGA when calling the assembly-language version of
**EVGALine** as when calling the C version, and the difference would be
considerably greater yet on a local bus, or with the use of write mode
3. Link each version with Listing 35.2 and compare performance—the
difference is startling.