116 lines
6 KiB
Markdown
116 lines
6 KiB
Markdown
------------------------ --------------------------------- --------------------
|
||
[Previous](31-03.html) [Table of Contents](index.html) [Next](31-05.html)
|
||
------------------------ --------------------------------- --------------------
|
||
|
||
The interesting aspects of Listing 31.1 are three. First, the
|
||
**Set320x400Mode** subroutine selects 320x400 256-color mode. This is
|
||
accomplished by performing a mode 13H mode set followed by then putting
|
||
the VGA into standard planar byte mode. **Set320x400Mode** zeros display
|
||
memory as well. It’s necessary to clear display memory even after a mode
|
||
13H mode set because the mode 13H mode set clears only the 64K of
|
||
display memory that can be accessed in that mode, leaving 192K of
|
||
display memory untouched.
|
||
|
||
The second interesting aspect of Listing 31.1 is the **WritePixel**
|
||
subroutine, which draws a colored pixel at any *x,y* addressable
|
||
location on the screen. Although it may not be obvious because I’ve
|
||
optimized the code a little, the process of drawing a pixel is
|
||
remarkably simple. First, the pixel’s display memory address is
|
||
calculated as
|
||
|
||
*address*=(*y* \* (SCREEN\_WIDTH / 4)) + (*x* / 4)
|
||
|
||
which might be more recognizable as:
|
||
|
||
*address*=((*y* \* SCREEN\_WIDTH) + *x*) / 4
|
||
|
||
(There are 4 pixels at each display memory address in 320x400 mode,
|
||
hence the division by 4.) Then the pixel’s plane is calculated as
|
||
|
||
*plane*=*x* and 3
|
||
|
||
which is equivalent to:
|
||
|
||
*plane*=*x* modulo 4
|
||
|
||
The pixel’s color is then written to the addressed byte in the addressed
|
||
plane. That’s all there is to it!
|
||
|
||
The third item of interest in Listing 31.1 is the **ReadPixel**
|
||
subroutine. **ReadPixel** is virtually identical to **WritePixel**, save
|
||
that in **ReadPixel** the Read Map register is programmed with a plane
|
||
number, while **WritePixel** uses a plane *mask* to set the Map Mask
|
||
register. Of course, that difference merely reflects a fundamental
|
||
difference in the operation of the two registers. (If that’s Greek to
|
||
you, refer back to Chapters 23-30 for a refresher on VGA programming.)
|
||
**ReadPixel** isn’t used in Listing 31.1, but I’ve included it because,
|
||
as I said above, the read and write pixel functions together can support
|
||
a whole host of more complex graphics functions.
|
||
|
||
How does 320x400 256-color mode stack up as regards performance? As it
|
||
turns out, the programming model of 320x400 mode is actually pretty good
|
||
for pixel drawing, pretty much on a par with the model of mode 13H. When
|
||
you run Listing 31.1, you’ll no doubt notice that the lines are drawn
|
||
quite rapidly. (In fact, the drawing could be considerably faster still
|
||
with a dedicated line-drawing subroutine, which would avoid the
|
||
multiplication associated with each pixel in Listing 31.1.)
|
||
|
||
In 320x400 mode, the calculation of the memory address is not
|
||
significantly slower than in mode 13H, and the calculation and selection
|
||
of the target plane is quickly accomplished. As with mode 13H, 320x400
|
||
mode benefits tremendously from the byte-per-pixel organization of
|
||
256-color mode, which eliminates the need for the time-consuming
|
||
pixel-masking of the 16-color modes. Most important, byte-per-pixel
|
||
modes never require read-modify-write operations (which can be extremely
|
||
slow due to display memory wait states) in order to clip and draw
|
||
pixels. To draw a pixel, you just store its color in display memory—what
|
||
could be simpler?
|
||
|
||
More sophisticated operations than pixel drawing are less easy to
|
||
accomplish in 320x400 mode, but with a little ingenuity it is possible
|
||
to implement a reasonably efficient version of just about any useful
|
||
graphics function. A fast line draw for 320x400 256-color mode would be
|
||
simple (although not as fast as would be possible in mode 13H). Fast
|
||
image copies could be implemented by copying one-quarter of the image to
|
||
one plane, one-quarter to the next plane, and so on for all four planes,
|
||
thereby eliminating the **OUT** per pixel that sequential processing
|
||
requires. If you’re really into performance, you could store your images
|
||
with all the bytes for plane 0 grouped together, followed by all the
|
||
bytes for plane 1, and so on. That would allow a single **REP MOVS**
|
||
instruction to copy all the bytes for a given plane, with just four
|
||
**REP MOVS** instructions copying the whole image. In a number of cases,
|
||
in fact, 320x400 256-color mode can actually be much faster than mode
|
||
13H, because the VGA’s hardware can be used to draw four or even eight
|
||
pixels with a single access; I’ll return to the topic of
|
||
high-performance programming in 256-color modes other than mode 13H
|
||
(“non-chain 4” modes) in Chapter 47.
|
||
|
||
It’s all a bit complicated, but as I say, you should be able to design
|
||
an adequately fast—and often *very* fast—version for 320x400 mode of
|
||
whatever graphics function you need. If you’re not all that concerned
|
||
with speed, **WritePixel** and **ReadPixel** should meet your needs.
|
||
|
||
### Two 256-Color Pages {#Heading7}
|
||
|
||
Listing 31.2 demonstrates the two pages of 320x400 256-color mode by
|
||
drawing slanting color bars in page 0, then drawing color bars slanting
|
||
the other way in page 1 and flipping to page 1 on the next key press.
|
||
(Note that page 1 is accessed starting at offset 8000H in display
|
||
memory, and is—unsurprisingly—displayed by setting the start address to
|
||
8000H.) Finally, Listing 31.2 draws vertical color bars in page 0 and
|
||
flips back to page 0 when another key is pressed.
|
||
|
||
The color bar routines don’t use the **WritePixel** subroutine from
|
||
Listing 31.1; they go straight to display memory instead for improved
|
||
speed. As I mentioned above, better speed yet could be achieved by a
|
||
color-bar algorithm that draws all the pixels in plane 0, then all the
|
||
pixels in plane 1, and so on, thereby avoiding the overhead of
|
||
constantly reprogramming the Map Mask register.
|
||
|
||
------------------------ --------------------------------- --------------------
|
||
[Previous](31-03.html) [Table of Contents](index.html) [Next](31-05.html)
|
||
------------------------ --------------------------------- --------------------
|
||
|
||
* * * * *
|
||
|
||
Graphics Programming Black Book © 2001 Michael Abrash
|