104 lines
5.4 KiB
Markdown
104 lines
5.4 KiB
Markdown
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.
|