Initial conversion to markdown
This commit is contained in:
parent
a96a114403
commit
5e10794a24
362 changed files with 67353 additions and 0 deletions
130
45-06.md
Normal file
130
45-06.md
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
------------------------ --------------------------------- --------------------
|
||||
[Previous](45-05.html) [Table of Contents](index.html) [Next](46-01.html)
|
||||
------------------------ --------------------------------- --------------------
|
||||
|
||||
The 640x400 mode I’ve described here isn’t exactly earthshaking, but it
|
||||
can come in handy for page flipping and CGA emulation, and I’m sure that
|
||||
some of you will find it useful at one time or another.
|
||||
|
||||
### Another Interesting Twist on Page Flipping {#Heading9}
|
||||
|
||||
I’ve spent a fair amount of time exploring various ways to do animation.
|
||||
I thought I had pegged all the possible ways to do animation:
|
||||
exclusive-ORing; simply drawing and erasing objects; drawing objects
|
||||
with a blank fringe to erase them at their old locations as they’re
|
||||
drawn; page flipping; and, finally, drawing to local memory and copying
|
||||
the dirty (modified) rectangles to the screen, as I’ve discussed in this
|
||||
chapter.
|
||||
|
||||
To my surprise, someone threw me an interesting and useful twist on
|
||||
animation not long ago, which turned out to be a cross between page
|
||||
flipping and dirty-rectangle animation. That someone was Serge Mathieu
|
||||
of Concepteva Inc., in Rosemere, Quebec, who informed me that he designs
|
||||
everything “from a game *point de vue*.”
|
||||
|
||||
In normal page flipping, you display one page while you update the other
|
||||
page. Then you display the new page while you update the other. This
|
||||
works fine, but the need to keep two pages current can make for a lot of
|
||||
bookkeeping and possibly extra drawing, especially in applications where
|
||||
only some of the objects are redrawn each time.
|
||||
|
||||
Serge didn’t care to do all that bookkeeping in his animation
|
||||
applications, so he came up with the following approach, which I’ve
|
||||
reworded, amplified, and slightly modified in the summary here:
|
||||
|
||||
**1.** Set the start address to display page 0.
|
||||
|
||||
**2.** Draw to page 1.
|
||||
|
||||
**3.** Set the start address to display page 1 (the newly drawn page),
|
||||
then wait for the leading edge of vertical sync, at which point the page
|
||||
has flipped and it’s safe to modify page 0.
|
||||
|
||||
**4.** Copy, via the latches, from page 1 to page 0 the areas that
|
||||
changed from the previous screen to the current one.
|
||||
|
||||
**5.** Set the start address to display page 0, which is now identical
|
||||
to page 1, then wait for the leading edge of vertical sync, at which
|
||||
point the page has flipped and it’s safe to modify page 1.
|
||||
|
||||
**6.** Go to step 2.
|
||||
|
||||
The great benefit of Serge’s approach is that the only page that is ever
|
||||
actually drawn to (as opposed to being block-copied to) is page 1. Only
|
||||
one page needs to be maintained, and the complications of maintaining
|
||||
two separate pages vanish entirely. The performance of Serge’s approach
|
||||
may be better or worse than standard page flipping, depending on whether
|
||||
a lot of extra work is required to maintain two pages or not. My guess
|
||||
is that Serge’s approach will usually be slower, owing to the
|
||||
considerable amount of display-memory copying involved, and also to the
|
||||
double page-flip per frame. There’s no doubt, however, that Serge’s
|
||||
approach is simpler, and the resultant display quality is every bit as
|
||||
good as standard page flipping. Given page flipping’s fair degree of
|
||||
complication, this approach is a valuable tool, especially for
|
||||
less-experienced animation programmers.
|
||||
|
||||
An interesting variation on Serge’s approach doesn’t page flip nor wait
|
||||
for vertical sync:
|
||||
|
||||
**1.** Set the start address to display page 0.
|
||||
|
||||
**2.** Draw to page 1.
|
||||
|
||||
**3.** Copy, via the latches, the areas that changed from the last
|
||||
screen to the current one from page 1 to page 0.
|
||||
|
||||
**4.** Go to step 2.
|
||||
|
||||
This approach totally eliminates page flipping, which can consume a
|
||||
great deal of time. The downside is that images may shear for one frame
|
||||
if they’re only partially copied when the raster beam reaches them. This
|
||||
approach is basically a standard dirty-rectangle approach, except that
|
||||
the drawing buffer is stored in display memory, rather than in system
|
||||
memory. Whether this technique is faster than drawing to system memory
|
||||
depends on whether the benefit you get from the VGA’s hardware, such as
|
||||
the Bit Mask, the ALUs, and especially the latches (for copying the
|
||||
dirty rectangles) is sufficient to outweigh the extra display-memory
|
||||
accesses involved in drawing and copying, since display memory is
|
||||
notoriously slow.
|
||||
|
||||
Finally, I’d like to point out that in any scheme that involves changing
|
||||
the display-memory start address, a clever trick can potentially reduce
|
||||
the time spent waiting for pages to flip. Normally, it’s necessary to
|
||||
wait for display enable to be active, then set the two start address
|
||||
registers, and finally wait for vertical sync to be active, so that you
|
||||
know the new start address has taken effect. The start-address registers
|
||||
must never be set around the time vertical sync is active (the new start
|
||||
address is accepted at either the start or end of vertical sync on the
|
||||
EGAs and VGAs I’m familiar with), because it would then be possible to
|
||||
load a half-changed start address (one register loaded, the other not
|
||||
yet loaded), and the screen would jump for a frame. Avoiding this
|
||||
condition is the motivation for waiting for display enable, because
|
||||
display enable is active only when vertical sync is not active and will
|
||||
not become active for a long while.
|
||||
|
||||
Suppose, however, that you arrange your page start addresses so that
|
||||
they both have a low-byte value of 0 (page 0 starts at 0000H, and page 1
|
||||
starts at 8000H, for example). Page flipping can then be done simply by
|
||||
setting the new high byte of the start address, then waiting for the
|
||||
leading edge of vertical sync. This eliminates the need to wait for
|
||||
display enable (the two bytes of the start address can never be
|
||||
mismatched); page flipping will often involve less waiting, because
|
||||
display enable becomes inactive long before vertical sync becomes
|
||||
active. Using the above approach reclaims all the time between the end
|
||||
of display enable and the start of vertical sync for doing useful work.
|
||||
(The steps I’ve given for Serge’s animation approach assume that the
|
||||
single-byte approach is in use; that’s why display enable is never
|
||||
waited for.)
|
||||
|
||||
In the next chapter, I’ll return to the original dirty-rectangle
|
||||
algorithm presented in this chapter, and goose it a little with some
|
||||
assembly, so that we can see what dirty-rectangle animation is really
|
||||
made of. (Probably not dog hair....)
|
||||
|
||||
------------------------ --------------------------------- --------------------
|
||||
[Previous](45-05.html) [Table of Contents](index.html) [Next](46-01.html)
|
||||
------------------------ --------------------------------- --------------------
|
||||
|
||||
* * * * *
|
||||
|
||||
Graphics Programming Black Book © 2001 Michael Abrash
|
||||
Loading…
Reference in a new issue