Initial conversion to markdown
This commit is contained in:
parent
a96a114403
commit
5e10794a24
362 changed files with 67353 additions and 0 deletions
142
46-03.md
Normal file
142
46-03.md
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
------------------------ --------------------------------- --------------------
|
||||
[Previous](46-02.html) [Table of Contents](index.html) [Next](47-01.html)
|
||||
------------------------ --------------------------------- --------------------
|
||||
|
||||
#### Masked Images {#Heading4}
|
||||
|
||||
Masked images are rendered by drawing an object’s pixels through a mask;
|
||||
pixels are actually drawn only where the mask specifies that drawing is
|
||||
allowed. This makes it possible to draw nonrectangular objects that
|
||||
don’t improperly interfere with one another when they overlap. Masked
|
||||
images also make it possible to have transparent areas (windows) within
|
||||
objects. Masked images produce far more realistic animation than do
|
||||
rectangular images, and therefore are more desirable. Unfortunately,
|
||||
masked images are also considerably slower to draw—however, a good
|
||||
assembly language implementation can go a long way toward making masked
|
||||
images draw rapidly enough, as illustrated by this chapter’s code.
|
||||
(Masked images are also known as *sprites*; some video hardware supports
|
||||
sprites directly, but on the PC it’s necessary to handle sprites in
|
||||
software.)
|
||||
|
||||
Masked images make it possible to render scenes so that a given image
|
||||
convincingly appears to be in front of or behind other images; that is,
|
||||
so images are displayed in *z-order* (by distance). By consistently
|
||||
drawing images that are supposed to be farther away before drawing
|
||||
nearer images, the nearer images will appear in front of the other
|
||||
images, and because masked images draw only precisely the correct pixels
|
||||
(as opposed to blank pixels in the bounding rectangle), there’s no
|
||||
interference between overlapping images to destroy the illusion.
|
||||
|
||||
In this chapter, I’ve used the approach of having separate, paired masks
|
||||
and images. Another, quite different approach to masking is to specify a
|
||||
transparent color for copying, and copy only those pixels that are not
|
||||
the transparent color. This has the advantage of not requiring separate
|
||||
mask data, so it’s more compact, and the code to implement this is a
|
||||
little less complex than the full masking I’ve implemented. On the other
|
||||
hand, the transparent color approach is less flexible because it makes
|
||||
one color undrawable. Also, with a transparent color, it’s not possible
|
||||
to keep the same base image but use different masks, because the mask
|
||||
information is embedded in the image data.
|
||||
|
||||
#### Internal Animation {#Heading5}
|
||||
|
||||
I’ve added another feature essential to producing convincing animation:
|
||||
*internal animation*, which is the process of changing the appearance of
|
||||
a given object over time, as distinguished from changing only the
|
||||
*location* of a given object. Internal animation makes images look
|
||||
active and alive. I’ve implemented the simplest possible form of
|
||||
internal animation in Listing 46.1—alternation between two images—but
|
||||
even this level of internal animation greatly improves the feel of the
|
||||
overall animation. You could easily increase the number of images cycled
|
||||
through, simply by increasing the value of **InternalAnimateMax** for a
|
||||
given entity. You could also implement more complex image-selection
|
||||
logic to produce more interesting and less predictable
|
||||
internal-animation effects, such as jumping, ducking, running, and the
|
||||
like.
|
||||
|
||||
#### Dirty-Rectangle Management {#Heading6 align="center"}
|
||||
|
||||
As mentioned above, dirty-rectangle animation makes it possible to
|
||||
access display memory a minimum number of times. The previous chapter’s
|
||||
code didn’t do any of that; instead, it copied all portions of every
|
||||
dirty rectangle to the screen, regardless of overlap between rectangles.
|
||||
The code I’ve presented in this chapter goes to the other extreme,
|
||||
taking great pains never to draw overlapped portions of rectangles more
|
||||
than once. This is accomplished by checking for overlap whenever a
|
||||
rectangle is to be added to the dirty list. When overlap with an
|
||||
existing rectangle is detected, the new rectangle is reduced to between
|
||||
zero and four nonoverlapping rectangles. Those rectangles are then again
|
||||
considered for addition to the dirty list, and may again be reduced, if
|
||||
additional overlap is detected.
|
||||
|
||||
A good deal of code is required to generate a fully nonoverlapped dirty
|
||||
list. Is it worth it? It certainly can be, but in the case of Listing
|
||||
46.1, probably not. For one thing, you’d need larger, heavily overlapped
|
||||
objects for this approach to pay off big. Besides, this program is
|
||||
mostly in C, and spends a lot of time doing things other than actually
|
||||
accessing display memory. It also takes a fair amount of time just to
|
||||
generate the nonoverlapped list; the overhead of all the looping,
|
||||
intersecting, and calling required to generate the list eats up a lot of
|
||||
the benefits of accessing display memory less often. Nonetheless, fully
|
||||
nonoverlapped drawing can be useful under the right circumstances, and
|
||||
I’ve implemented it in Listing 46.1 so you’ll have something to refer to
|
||||
should you decide to go this route.
|
||||
|
||||
There are a couple of additional techniques you might try if you want to
|
||||
wring maximum performance out of dirty-rectangle animation. You could
|
||||
try coalescing rectangles as you generate the dirty-rectangle list. That
|
||||
is, you could detect pairs of rectangles that can be joined together
|
||||
into larger rectangles, so that fewer, larger rectangles would have to
|
||||
be copied. This would boost the efficiency of the low-level copying
|
||||
code, albeit at the cost of some cycles in the dirty-list management
|
||||
code.
|
||||
|
||||
You might also try taking advantage of the natural coherence of animated
|
||||
graphics screens. In particular, because the rectangle used to erase an
|
||||
image at its old location often overlaps the rectangle within which the
|
||||
image resides at its new location, you could just directly generate the
|
||||
two or three nonoverlapped rectangles required to copy both the erase
|
||||
rectangle and the new-image rectangle for any single moving image. The
|
||||
calculation of these rectangles could be very efficient, given that you
|
||||
know in advance the direction of motion of your images. Handling this
|
||||
particular overlap case would eliminate most overlapped drawing, at a
|
||||
minimal cost. You might then decide to ignore overlapped drawing between
|
||||
different images, which tends to be both less common and more expensive
|
||||
to identify and handle.
|
||||
|
||||
#### Drawing Order and Visual Quality {#Heading7}
|
||||
|
||||
A final note on dirty-rectangle animation concerns the quality of the
|
||||
displayed screen image. In the last chapter, we simply stuffed dirty
|
||||
rectangles into a list in the order they became dirty, and then copied
|
||||
all of the rectangles in that same order. Unfortunately, this caused all
|
||||
of the erase rectangles to be copied first, followed by all of the
|
||||
rectangles of the images at their new locations. Consequently, there was
|
||||
a significant delay between the appearance of the erase rectangle for a
|
||||
given image and the appearance of the new rectangle. A byproduct was the
|
||||
fact that a partially complete—part old, part new—image was visible long
|
||||
enough to be noticed. In short, although the pixels ended up correct,
|
||||
they were in an intermediate, incorrect state for a sufficient period of
|
||||
time to make the animation look wrong.
|
||||
|
||||
This violated a fundamental rule of animation: *No pixel should ever be
|
||||
displayed in a perceptibly incorrect state*. To correct the problem,
|
||||
I’ve sorted the dirty rectangles first by Y coordinate, and secondly by
|
||||
X coordinate. This means the screen updates from to draw a given image
|
||||
should be drawn nearly simultaneously. Run the code from the last
|
||||
chapter and then this chapter; you’ll see quite a difference in
|
||||
appearance.
|
||||
|
||||
Avoid the trap of thinking animation is merely a matter of drawing the
|
||||
right pixels, one after another. Animation is the art of drawing *the
|
||||
right pixels at the right times* so that the eye and brain see what you
|
||||
want them to see. Animation is a lot more challenging than merely
|
||||
cranking out pixels, and it sure as heck isn’t a purely linear process.
|
||||
|
||||
------------------------ --------------------------------- --------------------
|
||||
[Previous](46-02.html) [Table of Contents](index.html) [Next](47-01.html)
|
||||
------------------------ --------------------------------- --------------------
|
||||
|
||||
* * * * *
|
||||
|
||||
Graphics Programming Black Book © 2001 Michael Abrash
|
||||
Loading…
Reference in a new issue