abrash-black-book/45-04.md
2013-12-30 20:26:41 +11:00

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.
------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
![](images/i.jpg) *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, &regset, &regset);
/* 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 */
}