Sprites/Updating the screen

Hi all,

Since this topic seems to come up frequently on this mailing list, why
not put it in the FAQ? Or maybe it’s really time someone writes a
(free!) book about Linux game programming :wink:

Anyway, here is my approach to the sprite/background-problem:

The idea is to maintain a list of “dirty rectangles”, i.e., rectangular
areas on the screen, that need to be redrawn. This can be used for two
things:

a) For updating (via SDL_UpdateRect) only those areas of the screen that
actually need to be updated.

b) For restoring only those areas of the framebuffer before drawing the
new frame that need to be restored.

When displaying sprites on a static background, the pseudocode for the
mainloop would look like this (I’ve been playing a bit with Python
lately; I guess it shows):

for sprite in spritelist:
sprite.draw()
dirtylist.add(sprite.rect)
for rect in dirtylist:
SDL_UpdateRect(rect)
framebuffer.restore(rect)
dirtylist.clear()

The trick here is to implement a rectangle list that makes sure that the
contained areas do not overlap. This requires some overhead, but I
think updating the same region on the screen twice or although it didn’t
change is much more costly in the long run.

For those of you interested, I appended an implementation of this kind
of rectangle list I wrote some time ago. It’s written in C++, but it
shouldn’t be a problem to port this to vanilla C. Incidentally, I think
this would make a nice addition to SDL; but then again, maybe it is
already to high-level :wink:

Do with the code whatever you like. I hereby place it in the public
domain.

Cheers
Daniel
-------------- next part --------------
#include
#include

using namespace std;

/----------------------------------------
CRect interface.
----------------------------------------
/
class CRect
{
public:
int X, Y, W, H;

CRect (int x=0, int y=0, int w=0, int h=0);
void  assign (int x, int y, int w, int h);
void  resize(int w, int h);
void  move(int x, int y);
bool  point_inside(int x, int y);
bool  overlaps(const CRect& rect) const;
CRect intersect(const CRect& rect) const;

};

/----------------------------------------
CRect implementation.
----------------------------------------
/
CRect::CRect(int x, int y, int w, int h)
: X (x)
, Y (y)
, W (w)
, H (h)
{}

void
CRect::assign(int x, int y, int w, int h)
{
X = x; Y = y;
W = w; H = h;
}

void
CRect::resize(int w, int h)
{
W = w; H = h;
}

void
CRect::move(int x, int y)
{
X = x; Y = y;
}

bool
CRect::point_inside(int x, int y)
{
return (x >= X && x < X+W && y >= Y && y<Y+H);
}

bool
CRect::overlaps(const CRect& rect) const
{
int x1 = max(X, rect.X);
int y1 = max(Y, rect.Y);
int x2 = min(X+W, rect.X + rect.W);
int y2 = min(Y+H, rect.Y + rect.H);

return !(x2 <= x1 || y2 <= y1);

}

CRect
CRect::intersect (const CRect& rect) const
{
int x1 = max(X, rect.X);
int y1 = max(Y, rect.Y);
int x2 = min(X+W, rect.X + rect.W);
int y2 = min(Y+H, rect.Y + rect.H);

return CRect(x1, y1, max(x2-x1, 0), max(y2-y1,0));

}

/----------------------------------------
CRectList interface.
----------------------------------------
/
class CRectList
{
vector* Rectangles;

// Hide copying methods.
CRectList(const CRectList&);
CRectList& operator=(const CRectList&);

public:
// Constructor.
CRectList();
~CRectList();
// Functions.
void clear();
int size() const;
bool empty() const;
CRect& operator[](int index);
const CRect& operator[](int index) const;

void 	 append(const CRect& rect);
void	 intersect(const CRect& rect);
void	 add(const CRect& rect);
void	 sub(const CRect& rect);
void	 append(const CRectList& rectlist);
void	 merge(const CRectList& rectlist);

};

/----------------------------------------
CRectList implementation.
----------------------------------------
/
CRectList::CRectList()
: Rectangles (new vector)
{}

CRectList::~CRectList()
{
delete Rectangles;
}

void
CRectList::clear()
{
Rectangles->clear();
}

int
CRectList::size() const
{
return Rectangles->size();
}

bool
CRectList::empty() const
{
return Rectangles->empty();
}

CRect&
CRectList::operator[](int i)
{
return (*Rectangles)[i];
}

const CRect&
CRectList::operator[](int i) const
{
return (*Rectangles)[i];
}

void
CRectList::append(const CRect& rect)
{
if (rect.W > 0 && rect.H > 0)
Rectangles->push_back(rect);
}

void
CRectList::append (const CRectList& rectlist)
{
Rectangles->insert(Rectangles->end(),
rectlist.Rectangles->begin(),
rectlist.Rectangles->end());
}

void
CRectList::add (const CRect& rect)
{
CRectList rl;
rl.append(rect);

vector<CRect>::iterator iter;
for (iter = Rectangles->begin(); iter != Rectangles->end(); ++iter)
rl.sub(*iter);
this->append(rl);

}

void
CRectList::intersect(const CRect& rect)
{
CRectList* rl = new CRectList;

vector<CRect>::iterator iter = Rectangles->begin();
for (; iter != Rectangles->end(); ++iter)
{
const CRect& r = *iter;

const int x1 = max( r.X, rect.X );
const int x2 = min( r.X+r.W, rect.X+rect.W );
const int y1 = max( r.Y, rect.Y );
const int y2 = min( r.Y+r.H, rect.Y+rect.H );

rl->append( CRect( x1, y1, x2-x1, y2-y1 ));
}
delete Rectangles;
Rectangles = rl->Rectangles;
rl->Rectangles = NULL;
delete rl;

}

void
CRectList::sub(const CRect& rect)
{
CRectList* rl = new CRectList;

vector<CRect>::iterator iter;
for (iter = Rectangles->begin(); iter != Rectangles->end(); ++iter)
{
const CRect& r = *iter;
if (r.overlaps(rect))
{
    const int x1 = max( r.X, rect.X );
    const int x2 = min( r.X+r.W, rect.X+rect.W );
    const int y1 = max( r.Y, rect.Y );
    const int y2 = min( r.Y+r.H, rect.Y+rect.H );
    
    rl->append( CRect( r.X, r.Y, r.W,        y1-r.Y ));
    rl->append( CRect( r.X, y1,  x1-r.X,     y2-y1 ));
    rl->append( CRect( x2,  y1,  r.X+r.W-x2, y2-y1 ));
    rl->append( CRect( r.X, y2,  r.W,        r.Y+r.H-y2 ));
}
else
    rl->append(r);
}
delete Rectangles;
Rectangles = rl->Rectangles;
rl->Rectangles = NULL;
delete rl;

}

/** Merge two rectangle lists. */
void
CRectList::merge(const CRectList& rl)
{
for (int i=0; i<rl.size(); i++)
this->add( rl[i] );
}

hi`

usually it isn’t worth to maintain a dirty rectangles list - in some
cases it can be even worse than updating all. Well and double buffering
renders this dirty list mostly useless too. Keep in mind that a full
blit is REALLY FAST on modern HW with DirectX and ‘fast enough’ on
Linux. Personally I think it is wasted code and people overemphasize it
a lot. Most games I played need to redraw the whole screen anyways - and
those which didn’t weren’t time critical at all. So the standard
approach to do sprites IMO is to simply redraw everything -> cleaner
code and in average not much slower (if at all).

Daniel Heck wrote:>

The idea is to maintain a list of “dirty rectangles”, i.e., rectangular
areas on the screen, that need to be redrawn. This can be used for two
things:

a) For updating (via SDL_UpdateRect) only those areas of the screen that
actually need to be updated.

b) For restoring only those areas of the framebuffer before drawing the
new frame that need to be restored.


Daniel Vogel My opinions may have changed,
666 @ http://grafzahl.de but not the fact that I am right

As far as full-screen updates…
Doom did it long ago, before our current X11 speed advancements. Given,
much lower resolutions. But the hardware acceleration under X has advanced
enough so that we can get better frame rates at even higher resolutions
than they did.

Some 2D games can function very well at 10FPS. A friend of mine did
research and found that Diablo’s animations and artwork were designed for
10FPS or less. In a 3D game, frame rate is very important because the
faster you can redraw the screen, the faster you can get a new updated
view of whats going on. But in a 2D game, which typically uses a fixed
number of frames and a fixed animation time, a frame rate faster than the
speed of your animations is a waste.

You want your animation to take a certain amount of time in a 2D game.
You don’t want it to go faster on faster hardware, or slower on slower
hardware.

Making larger animations to support faster FPS (with more frames than
absolutely necessary to make your game look good) just gets you closer to
not fitting on that CD. It’s already hard enough to keep our games small
enough to distribute.

Take a moment to figure out how many frames you want to do in an
animation… and how long you want that animation to run. It might give
you an idea of how fast you need your game to run. I tested with walking
animations. I started with 12 frames. It looked good but my bottlneck
was graphics… I cut the number of frames in half and still had extremely
smooth walking animation… the difference wasn’t even noticeable.

Of course… this is all out the window with a 3D game… :-)–
Brian

hi`

usually it isn’t worth to maintain a dirty rectangles list - in some
cases it can be even worse than updating all. Well and double buffering
renders this dirty list mostly useless too. Keep in mind that a full
blit is REALLY FAST on modern HW with DirectX and ‘fast enough’ on
Linux. Personally I think it is wasted code and people overemphasize it
a lot. Most games I played need to redraw the whole screen anyways - and
those which didn’t weren’t time critical at all. So the standard
approach to do sprites IMO is to simply redraw everything -> cleaner
code and in average not much slower (if at all).

Daniel Heck wrote:

The idea is to maintain a list of “dirty rectangles”, i.e., rectangular
areas on the screen, that need to be redrawn. This can be used for two
things:

a) For updating (via SDL_UpdateRect) only those areas of the screen that
actually need to be updated.

b) For restoring only those areas of the framebuffer before drawing the
new frame that need to be restored.


Daniel Vogel My opinions may have changed,
666 @ http://grafzahl.de but not the fact that I am right

> view of whats going on. But in a 2D game, which typically uses a fixed > number of frames and a fixed animation time, a frame rate faster than the > speed of your animations is a waste.

Well, the animation may be slow, but the on-screen movement (ie, the
scrolling around of sprites) will be faster than 10FPS, hopefully. :slight_smile:

> Making larger animations to support faster FPS (with more frames than > absolutely necessary to make your game look good) just gets you closer to > not fitting on that CD. It's already hard enough to keep our games small > enough to distribute.

DVD. :wink: And that new FDM or whatever it’s called (140GB per disk :slight_smile: )

> Of course.. this is all out the window with a 3D game... :-)

With 3D games, the faster framerate is good for when you’re spinning
your perspective around (say, turning 180 to see who’s shooting at you).

Of course, motion blur can let you reduce FPS and make it look good (or
even better), but it’s been argued that things like motion blur and
depth cuing (making stuff in the distance blurier) wouldn’t be such a good
thing in games like QUake where you wanna be able to see your enemies
crisp-and-clearly. :wink:

-bill!

“Daniel Vogel” <666 at grafzahl.de> wrote in message
news:38BB326B.E0E25BF9 at grafzahl.de

hi`

usually it isn’t worth to maintain a dirty rectangles list - in some
cases it can be even worse than updating all. Well and double buffering
renders this dirty list mostly useless too. Keep in mind that a full
blit is REALLY FAST on modern HW with DirectX and ‘fast enough’ on
Linux. Personally I think it is wasted code and people overemphasize it
a lot. Most games I played need to redraw the whole screen anyways - and
those which didn’t weren’t time critical at all. So the standard
approach to do sprites IMO is to simply redraw everything -> cleaner
code and in average not much slower (if at all).

I agree with you, but I want to point out for Gabriele: if you don’t call
SDL_UpdateRect between the refresh of the background and the redraw, you get
no flicker.

Amedeo Storni

Well, the animation may be slow, but the on-screen movement (ie, the
scrolling around of sprites) will be faster than 10FPS, hopefully. :slight_smile:

Not exactly the case, though.
Speed is related to pixels, not FPS. How fast it moves is based on the
pixel difference between each frame in the animation sequence. For
example… say you have a 3 frame animation walking, that moves 4 pixels
between each frame. Now how fast do you want to update them? Speed is a
combination of the pixel difference between each frame and your FPS. I
doubt your on-screen movement will be much faster than 10FPS. If your
onscreen animation is faster than your FPS, you are basically doing frame
skipping, where a movement happens and a screen update isn’t displayed.
This leads to rougher looking animations.–
Brian

Uhm, realy, why ? Because more is not possible (may be with complex games
and weak machines) or not needed (no way!) ? Like, if I want move my
2d-starship from the top of the screen to the bottom, in 320x200. It has to
cross about 200 pixels, and how fast would you imagine it to go in a fast
action-game ? Let’s say 2 seconds, then it could (and idealy should !) make
100 little steps each second. So I would want 100FPS for optimal smoothness.
Sure, you can do it with 10FPS, but then the ship takes jumps of 10 pixels a
time wich doesn’t look as good (and might cause collision-problems). Perhaps
I misunderstood you, because why would you not want to have the maximum
possible framrate ? If not for animations (nobody paints 100 FPS, although
with lots of memory and rendered sprites… :wink: then surely for movement it
does obvious good.
To pull this post vaguely back on topic (sdl ;), I just recently tried to
code a “proof of concept” for a nebulus-style game (little frog climbs
pseudo-3d-rotated tower, very pretty). I found that doing as much little
SDL_Blitsurfaces as were needed to create the perspective distortion pulls
the framrate to around 3FPS (200mmx, riva128). I took that as a proof that
for some strange tasks assembly still rules, because by the time you
explained to the compiler what you want you’re doing asm anyway, just more
complicated :wink:
But the question this raises is: how to accelerate a lot of tiny blits ?
Is it even worth blitting 64 or 32 pixels (2000 times each frame), or should
I rather copy the pixels myself, to save the overhead ?
Are single-pixel-wide blits extra-slow, compared to, say, 4-byte-blits ?
Or vertical lines compared to horizontal lines ?

All the best,
robOn Tue, Feb 29, 2000 at 08:09:15AM -0600, hayward at slothmud.org wrote:

Well, the animation may be slow, but the on-screen movement (ie, the
scrolling around of sprites) will be faster than 10FPS, hopefully. :slight_smile:

Not exactly the case, though.
Speed is related to pixels, not FPS. How fast it moves is based on the
pixel difference between each frame in the animation sequence. For
example… say you have a 3 frame animation walking, that moves 4 pixels
between each frame. Now how fast do you want to update them? Speed is a
combination of the pixel difference between each frame and your FPS. I
doubt your on-screen movement will be much faster than 10FPS.

You’re actually right in your scenario.

I was thinking about an RPG of sorts.
Think about an animated guy. One whole footstep is 4 frames, for a total
of 16 pixels. Each frame in the footstep shows movement of 4 pixels.
This means you can’t move him more than 4 pixels or else the animation
won’t look right.

Your example is not really an “frame animation” example, it is a
"projectile moving" example. You’re right… your action happens at the
same speed no matter what the FPS are. Your’s is very similar to a 3D
engine, where the faster screen rates you get, the quicker you get your
information.

Keep in mind, though, you don’t need to update the screen every two
pixels. The human eye won’t detect the difference between your
fast-moving ship moving in steps of 4 pixels as opposed to 2 pixels. They
are both minute advancements as far as the eye can tell… but mean a
difference of twice the graphics performance!–
Brian

Uhm, realy, why ? Because more is not possible (may be with complex games
and weak machines) or not needed (no way!) ? Like, if I want move my
2d-starship from the top of the screen to the bottom, in 320x200. It has to
cross about 200 pixels, and how fast would you imagine it to go in a fast
action-game ? Let’s say 2 seconds, then it could (and idealy should !) make
100 little steps each second. So I would want 100FPS for optimal smoothness.
Sure, you can do it with 10FPS, but then the ship takes jumps of 10 pixels a
time wich doesn’t look as good (and might cause collision-problems). Perhaps
I misunderstood you, because why would you not want to have the maximum
possible framrate ? If not for animations (nobody paints 100 FPS, although
with lots of memory and rendered sprites… :wink: then surely for movement it
does obvious good.
To pull this post vaguely back on topic (sdl ;), I just recently tried to
code a “proof of concept” for a nebulus-style game (little frog climbs
pseudo-3d-rotated tower, very pretty). I found that doing as much little
SDL_Blitsurfaces as were needed to create the perspective distortion pulls
the framrate to around 3FPS (200mmx, riva128). I took that as a proof that
for some strange tasks assembly still rules, because by the time you
explained to the compiler what you want you’re doing asm anyway, just more
complicated :wink:
But the question this raises is: how to accelerate a lot of tiny blits ?
Is it even worth blitting 64 or 32 pixels (2000 times each frame), or should
I rather copy the pixels myself, to save the overhead ?
Are single-pixel-wide blits extra-slow, compared to, say, 4-byte-blits ?
Or vertical lines compared to horizontal lines ?

All the best,
rob

I was thinking about an RPG of sorts.
Think about an animated guy. One whole footstep is 4 frames, for a total
of 16 pixels. Each frame in the footstep shows movement of 4 pixels.
This means you can’t move him more than 4 pixels or else the animation
won’t look right.

Oh - NOW I understand :slight_smile: You mean that the feet wouldn’t touch the ground
at the right moments, making your little guy “slide” as if on ice or
something. I’ve seen that in some old games, and I agree, it looks very odd.

Your example is not really an “frame animation” example, it is a
"projectile moving" example. You’re right… your action happens at the
same speed no matter what the FPS are. Your’s is very similar to a 3D
engine, where the faster screen rates you get, the quicker you get your
information.

Yes, that’s right. Perhaps the concept of morphing/interpolating
(key-framing ?) between animation steps should be explored in 2d-games too,
to take advantage of fast machines/big memory. That could look real neat.
Has anybody seen something like this ?

Keep in mind, though, you don’t need to update the screen every two
pixels. The human eye won’t detect the difference between your
fast-moving ship moving in steps of 4 pixels as opposed to 2 pixels. They
are both minute advancements as far as the eye can tell… but mean a
difference of twice the graphics performance!

I once had a game-creation-kit for my old atari ST, and it was only able
to scroll the screen 16 pixels (32 bit) at a time, claiming that it would
be smooth enough. Looked absolutely horrible :slight_smile: But 4 vs 2 would be ok,
especially in resolutions above 320x200.
It’s a pity that there are no real 2d-hardware-acceleration-standards for
games, with sprites, parallaxscrolling, tiles, whatever… I should move on
to hardware-design :slight_smile: (yeah, or buy a gamesconsole (if they still have good
2d-power, now in the age of 3d, dunno…)
How good can 3d-accelerators be “abused” for 2d-stuff ? Like using textured
polys as sprites or background-layers ?

All the best,
robOn Tue, Feb 29, 2000 at 12:33:27PM -0600, hayward at slothmud.org wrote:

especially in resolutions above 320x200.

Well… at that resolution, you should be able to get great FPS. :-)–
Brian

Robert Linden schrieb am 29 Feb 2000:

How good can 3d-accelerators be “abused” for 2d-stuff ? Like using textured
polys as sprites or background-layers ?

Very well. And what’s best, you get anti-aliasing for free. Though, in
some cases, that’s not desired. But there is still GL_NEAREST to help out.

Have a look at fxmame, the mame port for 3d cards (I think only glide
is supported, but that may have changed).

  • Andreas–
    Probably one of the smallest 3D-Games in the world: http://www.gltron.org
    More than 50’000 Downloads of the latest version (0.53)

“Andreas Umbach” wrote:

Robert Linden schrieb am 29 Feb 2000:

How good can 3d-accelerators be “abused” for 2d-stuff ? Like using textured
polys as sprites or background-layers ?

Very well. And what’s best, you get anti-aliasing for free. Though, in
some cases, that’s not desired. But there is still GL_NEAREST to help out.

Actually most 3d accelerators suck for 2d stuff. The Voodoo has a
texture size limit of 256 texels so you have to split up large textures
and waste memory (most likely), glDraw/CopyPixels is slow as hell and
texture changes are expensive. The only benefit is when you e.g. draw
the background using one single quad (via glTexSubImage2D) and then do
all your fancy alpha blitting. This is the only situation you will
benefit from 3d acceleration.

E.g. a game like Diablo could draw the background onto a surface and
then use glTexSubImage2D to draw all that preblitted stuff. Then the
graphics effects and sprites get blitted seperately - that will boost
performance if you have much alpha blending involved. But if you simply
intend to write a GLX target for SDL that allows blitting of surfaces it
will be a waste of time (I did it for another library ;-)).

So the conclusion is to do as much blitting by yourself, use
glTexSubImage2D and only use ‘HW blits with Quads (GL_TRIANGLE_STRIPS
are better)’ when you have alpha involved.–
Daniel Vogel My opinions may have changed,
666 @ http://grafzahl.de but not the fact that I am right

Daniel Vogel wrote:

hi`

usually it isn’t worth to maintain a dirty rectangles list - in some
cases it can be even worse than updating all. Well and double buffering
renders this dirty list mostly useless too. Keep in mind that a full
blit is REALLY FAST on modern HW with DirectX and ‘fast enough’ on
Linux. Personally I think it is wasted code and people overemphasize it
a lot. Most games I played need to redraw the whole screen anyways - and
those which didn’t weren’t time critical at all. So the standard
approach to do sprites IMO is to simply redraw everything -> cleaner
code and in average not much slower (if at all).

Yes, I agree. It might be tempting to start out with a dirty rectangle
list, since you’re just moving one or two sprites. But as you keep
developing and adding more and more animation, you end up wanting to
just blit the whole screen anyway.

In my project (“exult”), I ask SDL for a ‘software’ surface, so that I
get an offscreen
chunk of memory where all the drawing is done. The game loop then looks
like:
while (!time_to_quit)
{
SDL_Delay(20); // Wait 1/50 sec.
while (!time_to_quit && SDL_PollEvent(&event))
Handle_event(event);
// Handle any time-queued events (i.e. animation) due at this time.
unsigned long ticks = SDL_GetTicks();
time_queue->activate(ticks);
// If the surface was updated, then blit() to the actual screen:
if (updated_surface)
SDL_UpdateRect(surface, 0, 0, w, h);
}
So far, this seems to be fast enough. And the only thing I have to
worry about is to make sure that any method that writes to the surface
sets the ‘updated_surface’ flag.

— Daniel Vogel <666 at grafzahl.de> wrote:

“Andreas Umbach” wrote:

Robert Linden schrieb am 29 Feb 2000:

How good can 3d-accelerators be “abused” for 2d-stuff ? Like
using textured

polys as sprites or background-layers ?

Very well. And what’s best, you get anti-aliasing for free. Though,
in
some cases, that’s not desired. But there is still GL_NEAREST to
help out.

Actually most 3d accelerators suck for 2d stuff. The Voodoo has a
texture size limit of 256 texels so you have to split up large
textures
and waste memory (most likely)

Not really a waste of memory, just more work to handle larger texels.
Other manufactures support sizes up to 2048x2048x32, while the most
common is 2048x2048x16 (heck even the nvidia 128zx does that).

There is also the question whether to write for 2d mode or 3d mode
within a 2d game… You can do some very intesting things with 2d within
3d, but is the complexity worth it?=====
Jason Platt.

“In theory: theory and practice are the same.
In practice: they arn’t.”

ICQ# 1546328


Do You Yahoo!?
Talk to your friends online with Yahoo! Messenger.

Jason Platt wrote:

Not really a waste of memory, just more work to handle larger texels.
Other manufactures support sizes up to 2048x2048x32, while the most
common is 2048x2048x16 (heck even the nvidia 128zx does that).

Well, if I want a 800x600 surface I had to go for a 1024x1024 texture
and I’d call that waste of texture. Besides you can’t rely ont he max
size - you still had to write much code to split up things. Okay, you
could try to stack smaller surfaces in the free texture space but this
will get really really complex.

There is also the question whether to write for 2d mode or 3d mode
within a 2d game… You can do some very intesting things with 2d within
3d, but is the complexity worth it?

Depends on the game. If you think about this all in advance you can have
some cool effects for free (rotation, zooming, filtering, alpha
blending, …) but adding it afterwards hardly pays off. I guess I might
write a little demo demonstrating what I mean sometime… some day…

"In theory: theory and practice are the same.

In theory, there is no practice.–
Daniel Vogel My opinions may have changed,
666 @ http://grafzahl.de but not the fact that I am right

But the question this raises is: how to accelerate a lot of tiny blits ?
Is it even worth blitting 64 or 32 pixels (2000 times each frame), or should
I rather copy the pixels myself, to save the overhead ?
Are single-pixel-wide blits extra-slow, compared to, say, 4-byte-blits ?
Or vertical lines compared to horizontal lines ?
On modern hardware drawing four seperate pixels(8-bit) will usually be
slower than drawing one block of four pixels(32-bit). A horizontal line
should usually be quicker to draw than a vertical one. A horizontal line
can be drawn in 32-bit chunks in the string copy while a vertical line
must draw-pixel, add screen-width, draw-pixel, add screen width etc.

Long live the confused,
Akawaka.On Tue, 29 Feb 2000, Robert Linden wrote:

Bother! said Pooh, as the alien burst from his chest.