72 lines
4.1 KiB
Markdown
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.
|