|Previous||Table of Contents||Next|
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 isnt trivial (as weve 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.
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 VGAs 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 OUTs rather than byte OUTs. 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 its 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.
Listing 35.3 is a high-performance implementation of Bresenhams 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 performancethe difference is startling.
|Previous||Table of Contents||Next|