111 lines
6.8 KiB
Markdown
111 lines
6.8 KiB
Markdown
One point I'd like to make is that although the system-memory buffer in
|
|
Listing 45.1 has exactly the same dimensions as the screen bitmap,
|
|
that's not a requirement, and there are some good reasons not to make
|
|
the two the same size. For example, if the system buffer is bigger than
|
|
the area displayed on the screen, it's possible to pan the visible area
|
|
around the system buffer. Or, alternatively, the system buffer can be
|
|
just the size of a desired window, representing a window into a larger,
|
|
virtual buffer. We could then draw the desired portion of the virtual
|
|
bitmap into the system-memory buffer, then copy the buffer to the
|
|
screen, and the effect will be of having panned the window to the new
|
|
location.
|
|
|
|
------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
 *Another argument in favor of a small viewing window is that it restricts the amount of display memory actually drawn to. Restricting the display memory used for animation reduces the total number of display-memory accesses, which in turn boosts overall performance; it also improves the performance and appearance of panning, in which the whole window has to be redrawn or copied.*
|
|
------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
If you keep a close watch, you'll notice that many high-performance
|
|
animation games similarly restrict their full-featured animation area to
|
|
a relatively small region. Often, it's hard to tell that this is the
|
|
case, because the animation region is surrounded by flashy digitized
|
|
graphics and by items such as scoreboards and status screens, but look
|
|
closely and see if the animation region in your favorite game isn't
|
|
smaller than you thought.
|
|
|
|
### Hi-Res VGA Page Flipping {#Heading8}
|
|
|
|
On a standard VGA, hi-res mode is mode 12H, which offers 640x480
|
|
resolution with 16 colors. That's a nice mode, with plenty of pixels,
|
|
and square ones at that, but it lacks one thing—page flipping. The
|
|
problem is that the mode 12H bitmap is 150 K in size, and the standard
|
|
VGA has only 256 K total, too little memory for two of those monster
|
|
mode 12H pages. With only one page, flipping is obviously out of the
|
|
question, and without page flipping, top-flight, hi-res animation can't
|
|
be implemented. The standard fallback is to use the EGA's hi-res mode,
|
|
mode 10H (640x350, 16 colors) for page flipping, but this mode is less
|
|
than ideal for a couple of reasons: It offers sharply lower vertical
|
|
resolution, and it's lousy for handling scaled-up CGA graphics, because
|
|
the vertical resolution is a fractional multiple—1.75 times, to be
|
|
exact—of that of the CGA. CGA resolution may not seem important these
|
|
days, but many images were originally created for the CGA, as were many
|
|
graphics packages and games, and it's at least convenient to be able to
|
|
handle CGA graphics easily. Then, too, 640x350 is also a poor multiple
|
|
of the 200 scan lines of the popular 320x200 256-color mode 13H of the
|
|
VGA.
|
|
|
|
There are a couple of interesting, if imperfect, solutions to the
|
|
problem of hi-res page flipping. One is to use the split screen to
|
|
enable page flipping only in the top two-thirds of the screen; see the
|
|
previous chapter for details, and for details on the mechanics of page
|
|
flipping generally. This doesn't address the CGA problem, but it does
|
|
yield square pixels and a full 640x480 screen resolution, although not
|
|
all those pixels are flippable and thus animatable.
|
|
|
|
A second solution is to program the screen to a 640x400 mode. Such a
|
|
mode uses almost every byte of display memory (64,000 bytes, actually;
|
|
you could add another few lines, if you really wanted to), and thereby
|
|
provides the highest resolution possible on the VGA for a fully
|
|
page-flipped display. It maps well to CGA and mode 13H resolutions,
|
|
being either identical or double in both dimensions. As an added
|
|
benefit, it offers an easy-on-the-eyes 70-Hz frame rate, as opposed to
|
|
the 60 Hz that is the best that mode 12H can offer, due to the design of
|
|
standard VGA monitors. Best of all, perhaps, is that 640x400 16-color
|
|
mode is easy to set up.
|
|
|
|
The key to 640x400 mode is understanding that on a VGA, mode 10H
|
|
(640x350) is, at heart, a 400-scan-line mode. What I mean by that is
|
|
that in mode 10H, the Vertical Total register, which controls the total
|
|
number of scan lines, both displayed and nondisplayed, is set to 447,
|
|
exactly the same as in the VGA's text modes, which do in fact support
|
|
400 scan lines. A properly sized and centered display is achieved in
|
|
mode 10H by setting the polarity of the sync pulses to tell the monitor
|
|
to scan vertically at a faster rate (to make fewer lines fill the
|
|
screen), by starting the overscan after 350 lines, and by setting the
|
|
vertical sync and blanking pulses appropriately for the faster vertical
|
|
scanning rate. Changing those settings is all that's required to turn
|
|
mode 10H into a 640x400 mode, and that's easy to do, as illustrated by
|
|
Listing 45.2, which provides mode set code for 640x400 mode.
|
|
|
|
**LISTING 45.2 L45-2.C**
|
|
|
|
/* Mode set routine for VGA 640x400 16-color mode. Tested with
|
|
Borland C++ in C compilation mode. */
|
|
|
|
#include <dos.h>
|
|
|
|
void Set640x400()
|
|
{
|
|
union REGS regset;
|
|
|
|
/* First, set to standard 640x350 mode (mode 10h) */
|
|
regset.x.ax = 0x0010;
|
|
int86(0x10, ®set, ®set);
|
|
|
|
/* Modify the sync polarity bits (bits 7 & 6) of the
|
|
Miscellaneous Output register (readable at 0x3CC, writable at
|
|
0x3C2) to select the 400-scan-line vertical scanning rate */
|
|
outp(0x3C2, ((inp(0x3CC) & 0x3F) | 0x40));
|
|
|
|
/* Now, tweak the registers needed to convert the vertical
|
|
timings from 350 to 400 scan lines */
|
|
outpw(0x3D4, 0x9C10); /* adjust the Vertical Sync Start register
|
|
for 400 scan lines */
|
|
outpw(0x3D4, 0x8E11); /* adjust the Vertical Sync End register
|
|
for 400 scan lines */
|
|
outpw(0x3D4, 0x8F12); /* adjust the Vertical Display End
|
|
register for 400 scan lines */
|
|
outpw(0x3D4, 0x9615); /* adjust the Vertical Blank Start
|
|
register for 400 scan lines */
|
|
outpw(0x3D4, 0xB916); /* adjust the Vertical Blank End register
|
|
for 400 scan lines */
|
|
}
|