🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: rec.games.programmer
Article #1538

Ghosts, multiple images, and flicker (and motion blur)

#1538
From: Greg Kuperberg
Date: Wed, 23 Dec 1992 19:11
131 lines
7622 bytes
A response that I got for my postings about motion blur have prompted
me to me make a big caveat about using motion blur:

Motion blur is a fancy method in visual animation.  Unless every other
aspect of your animation timing is nearly perfect, motion blur is a
lot of theoretical BS that you should ignore.  The problem it solves is
the strobe effect, which is similar to but not exactly the same as
ghost images or double or triple images.  If you are having one of
these problems you should look very carefully to see which one, and
unless it is the strobe effect motion blur might help some but might
also be useless.

In particular, you should first make sure that your animation is
in synch with the vertical retrace on your monitor, which therefore
means that you are using a form of clocked animation.  Also,
if your graphics could benefit greatly from some anti-aliasing, you
might want to implement that before you try motion blur.

Some more words about clocked animation.  You should banish from
your intuition the idea if your code is fast your animation will
be fast and if your code is slow your animation will be slow.
You should also qualify the notion that if part of your code takes
a large portion of your CPU time then there is something wrong with
that piece of code.

When your code finishes computing and drawing the new frame, it
will wait for the vertical retrace or clock tick because there is
nothing else for it to do.  A CPU cannot simply stop thinking without
being turned off.  If your code spends 90% of its time waiting for
vertical retrace, your CPU budget is very healthy; you have loads
of extra time.  If your code spends 5% of its time waiting for the
retrace, you can hardly afford any more animation than you already
have.

With clocked animation, if your code is fast your animation will be
exactly the same as when your code is at a moderate speed.  If your
code is slow, it will miss clock ticks.  Your animation will skip.  It
will stutter.  It will not be just a little slower.

When I explained how to set up clocked animation, I forgot about the
case where you have no interrupts or counts available, you just have
a flag that is YES during a vertical retrace and NO at other times.
In this case your only choice for the animation loop is something
of the form:

for(;;)
{
	...   /* Draw everything */
	while(!vertical_retrace_flag);
}

The problem is that if your code is slow, you will not be able to tell
the difference between having extra time and missing the vertical
retrace completely.  You will not be able to borrow CPU time from the
next frame.  Instead your animation will with certainty skip a beat.
That's the way the egg rolls and you have to make sure you live within
your CPU budget to prevent it.

Of all the advantages of clocked animation, I didn't mention that it
helps you avoid double images and sprite flicker.  You can't guarantee
that unwanted pixels won't be sent to the phosphorus unless you are
in synch with the vertical retrace.  If you are, here are some tips
on how to get the most out of it and maintain the visual integrity
of your sprites:

The cleanest way to avoid flicker and everything else is to use page
flipping.  There are two kinds:  Hardware-driven and software-driven.
With hardware-driven page flipping you tell your video chip to
alternate between displaying two different stretches of RAM.  You
always draw on the one that isn't displayed.  If you have hardware-driven
page flipping, the vertical retrace is the ideal time to use it.
That's exactly when the video chip isn't looking.  Flipping pages when
it is looking can mean ghosts and multiple images.

You use software-driven page flipping when you can't or don't want to
ask the video chip to move to a different part of your RAM.  With
software-driven page flipping you simply draw everything into an
internal copy of the screen, then copy the whole shebang onto the
real screen.  It sounds redundant but it can be a good idea.  But
you might not be able to spare the CPU time.  In that case you have
no choice but to erase and draw your sprites or whatever directly on the
video RAM.

Whether you have software pages or you are drawing sprites directly,
you are in a race with with CRT beam.  It is important to stay
ahead of the beam.  That means you should draw all your sprites
in order from top to bottom.  It is also tempting to erase all
your sprites and then redraw them all.  But if you do that, you are
running two laps while the beam is running one, and it is impossible
to stay ahead the whole time.  It will mean that some sprites will
be caught when they are erased but not redrawn.  In general you should
try to minimize the amount of time between when a sprite are erased
and when the same sprite is redrawn.

If you have software page-flipping and you have only one retrace
per animation frame, then presumably your screen copying routine is
faster than the beam or else you wouldn't have any time left over.
But you should still make sure that the bytes are copied in the same
order as they are they will appear on the screen, and you should
make sure to copy the screen immediately after the vertical retrace,
not when you're finished with everything else in the frame.
If you have, say, two retraces per frame then you are better off
if the screen copy is twice as fast as the beam.

If you have two or more retraces per frame and you can't flip pages, or
if your animation  is clocked to something other than the vertical
retrace, then will you will simply have a lesser degree of perfection
in your animation.  It is still very important to minimize time
between erase and draw for a given sprite, but even after you implement
that you may still have problems with flicker, especially when sprites
overlap.  This was exactly my situation when I wrote J-Bird for the
IBM-PC.  My solution?  Masked erasure.  I already had to use a mask
when drawing my sprites because I had a complicated background and the
sprites could overlap.  So I souped up the erase routine so that it
would use the mask also.  It wasn't perfect, because there was still
some amount of "ghost erasure" when sprites overlapped, but it
looked pretty good and even the ghost erasure looked kind-of neat.

In fact, if I may toot my own horn, J-Bird went to the limit of the
IBM-PC's CPU resources.  I spent entire days trying to optimize my
drawing routines, and the clock-tick pages of my 8088 manual got old
and soiled as I tried to squeeze out every possible clock tick.  Among
other things, I didn't have the time to bit-shift the pixels in my
sprites, so I had to have a copy of each sprite for every possible
offset relative to the bytes of the video RAM.  Not only the image, but
the mask too, which was of course expanded to the same width as the
image instead of just being a bit array.  The result?  More sprites
doing more complicated things smoothly than any other game I saw on the
market that would run on the original IBM.  Bruce Artwick's Flight
Simulator had much better graphics overall, but it didn't use
sprites and it wasn't smooth.
Technical Details
Message-ID: <1992Dec23.191151.12044@midway.uchicago.edu>
Path: arc1-ca.pugleaf.net!sparky!uunet!uchinews!news

Show Full Headers
Complete Article Headers
Newsgroups: rec.games.programmer
Path: arc1-ca.pugleaf.net!sparky!uunet!uchinews!news
From: greg@zaphod.uchicago.edu (Greg Kuperberg)
Subject:  Ghosts, multiple images, and flicker (and motion blur)
Message-ID: <1992Dec23.191151.12044@midway.uchicago.edu>
Sender: news@uchinews.uchicago.edu (News System)
Organization: Dept. of Mathematics, U. of Chicago
Date: Wed, 23 Dec 1992 19:11:51 GMT
Lines: 131