Up till now, we've been rendering things using the canvas drawing primitives,
such as lines, rectangles, arcs and (potentially) direct pixel drawing.
These primitives certainly have their uses, but most in-game graphics are in
fact "pre-drawn" in the form of images (or, in 3D, textured triangles) which are simply copied onto the screen at the appropriate locations.
Sprites
In the early days of games technology, this process was often accelerated by
special "sprite drawing" hardware.
The purpose of the sprite hardware was to
implement fast drawing to the display, especially on systems which didn't have
enough memory (or enough CPU-power) to drive a full pixel-level frame-buffer
of the kind we use today.
SNES
For example, the Super Nintendo (SNES), as launched in 1991/1992, used this kind of
hardware, where the screen was composed of a grid of "background" tiles,
with a number of independently controllable sprites superimposed on top.
This mapped pretty well to the sort of games people were making back then,
although the relationship was of course a two-way street (i.e. what people
did was influenced by what the hardware could support!)...
Which is why SNES games all looked kind of like this:
BLIT
In more general, frame-buffer based systems, there has sometimes been another
form of "hardware acceleration" to help with the copying of images from one
buffer to another and, in some cases, to perform compositing operations while doing so e.g. supporting transparency.
This approach is known as "bit-blitting" or just "blitting", which sort-of
means "BLock Image Transfer" (though this etymology has been debated).
The origins of blitting go back to the GUI of the Alto, developed at Xerox
PARC (Palo Alto Research Centre) in the 1970s.
...where pretty much
everything else about the modern computing experience was also invented, by Alan Kay et al. ...as I keep saying ;-)
The Alto version was a software routine called BitBLT, which was later
embedded into micro-code to, in a sense, "put it into hardware"...
Didn't you get the memo?
Here is the original Xerox PARC
memo describing it.
And
here's the famous 1981 "BYTE" magazine article
about Smalltalk, which provides more context.
Later, home-computer systems, such as the Commodore Amiga (1985), and some versions of the
Atari ST (1986+)
had dedicated "blitter chips" serving the same purpose.
Those machines were awesome.
PCs
Yuck!
However, most systems (including the "IBM PC") didn't have such dedicated
hardware --- but they did had have just about enough CPU power, relative to their screen resolutions, to support a software only approach...
Today, equivalent operations are often done through the dedicated "GPU"s in the graphics card,
typically by treating a "blit" as the drawing of two front-facing triangles
with a suitable texture pattern on them.
Sprites vs BLITs
The big difference between hardware sprites and BLITs is that the former behaves
like an overlay (e.g. a mid-ground sprite-plane in front of a background layer, say) whereas
the latter is a direct frame-buffer manipulation with no innate notion of layering (just the one implied by the drawing order).
Destructive!
In particular, a BLIT operation "destroys" the background behind it, which then
needs to be restored (typically) when the object moves elsewhere.
Tracking all of this can add
a significant amount of complexity to things (imagine doing PONG that way!), unless one simply "gives up" and
decides to draw each frame "from scratch" onto an initially empty surface...
And Yet...
Nevertheless, the blitting approach is the one adopted in most modern systems,
in part because it is more flexible overall.
Sprite systems tend to have fixed
limits over the number of sprites they can draw, and tend to be designed for
situations in which the background plane is rigidly grid-like.
Web Browsers
Web browsers handle images using dedicated image-file formats of the type
I'm sure you're all familiar with (.bmp, .gif, .jpg, .png, etc).
The
canvas API can tap into that and provide some sprite/blit-like facilities which operate on them.
The key to all this is the drawImage method...
Using drawImage
drawImage exists in multiple forms, the most general of which supports arbitrary clipping and scaling.
The messy multi-parameter overloading is, in my opinion, unfortunate.
What would have been wrong with drawSubImage?
Generalise drawImage
Here's a nice illustration of the most general case:
It doesn't have a built-in rotation param, but we already know how to do that ourselves with matrix magic! :-)
Async Loading
It's important for browsers to load images asynchronously i.e. "in the background, without actually waiting for them". (This was the big innovation of the Netscape browser.)
Without async image loads, perceived page load times would be much slower,
because you'd have to wait for each image element to be fully loaded, in sequence.
With async, you typically get to see the text before the graphics, and the images
then flow into the page, having been requested largely "in parallel".
Games?
Async loading is great for typical web-pages, but it's actually a bit of an annoyance for games.
We don't want our in-game images to be subject to "random" async delays, which might
cause them to be invisible for some period after we have initially chosen to "load"
them, and we want to catch errors early too.
Provide a constructor that takes an Image object defining the sprite, and add a drawCentredAt(ctx, cx, cy, rotation) member function which renders the sprite via the specified context, at the given centre-coords, and at the desired angle of rotation (in radians).
Use this sprite to render a simple "spaceship" object, and implement a mouse-handler which sets its position to that of the most recent mouse-click.
Framework
I'll give you a basic framework, derived from last week's PONG example, which also includes a little image pre-loading helper to get you started.
You also need to implement a "wrap-around" rendering method, which may require a bit of extra thought.
We will use the additional features of this framework in Part 2 of the homework, so try not to mangle it...