C for Yourself - part 38

Steve Mumford introduces the ColourTrans module

Last month I covered the principles of creating a user sprite area, loading and saving sprites to and from disc, and plotting them at a particular coordinate on the screen. I also mentioned one of the problems that crop up when plotting sprites in multitasking programs — the programmer can't be sure which screen mode will be used, and so has to provide functionality to plot sprites correctly without assuming anything about the display.

Put simply, we need to determine how many colours are available in the current mode, then translate the colours in our sprite to maintain their appearance on the screen. If we can create such a pixel translation table, we'll be able to make use of certain OS_SpriteOp system calls to do the translation and plotting in one operation.

This is where the ColourTrans module comes into its own; although we'll use it to solve a fairly simple problem, this utility proves itself to be particularly helpful for all manner of desktop-related tasks. Essentially, the ColourTrans module acts as an interpreter, taking the exact colours requested by the program, and translating them into the nearest on-screen equivalent given the current screen mode. It doesn't stop there; if you're interested in making use of anti-aliased fonts or sending graphical material to a printer, ColourTrans has a few more time-saving functions up its sleeve.

If you looked at the program on last month's cover disc, you'll have seen some of these calls in operation already — to set up a translation table you need to use ColourTrans_SelectTable, and plotting the sprite is carried out with OS_SpriteOp 52. Both of these calls are described in further detail below.

When building a translation table, it's necessary to specify the source mode and its palette information, as well as the same details for the destination mode. In our case, we need to extract the appropriate values from our original sprite — luckily, the ColourTrans_SelectTable call is intelligent enough to be able to tell which mode is currently being used, so we don't need to worry about the destination mode details.

The call can take up to eight parameters but we only need to worry about the first six - RO holds a pointer to our user sprite area and R1 points to a buffer holding the name of the sprite we wish to convert. Following those, R2 and R3 should contain the value -1, as this instructs ColourTrans to determine the current mode number and palette details and use these as the destination.

R4 can either be a pointer to the buffer that's going to hold the created translation table, or it can hold a value of 0 to ask ColourTrans how much memory it's likely to need. Finally, R5 holds various flags that affect the operation of the call, but in this case we can accept the defaults by loading the register with a value of 0. Here's a section of code to illustrate the above, taken from the cover disc demonstration:

unsigned char translation_buffer[1024]; /* set aside memory */
regs_in.r[0] = (int) sprite_area;
strcpy(text_buffer, "screen"); /* Name of sprite to use */
regs_in.r[l] = (int) text_buffer;
regs_in.r[2] = -1; /* Use the current mode information */
regs_in.r[3] = -1;
regs_in.r[4] = (int) translation_buffer;
regs_in.r[5] = 0; /* default flags; use sprite name in R1 */
_kernel_swi(ColourTrans_SelectTable, &regs_in, &regs_out);

Once the pixel translation table has been built, the sprite is ready to be plotted to the screen. The OS_SpriteOp call is very similar to the one used last month, but it takes two extra parameters.

Assuming the sprite area and the various buffers have been set up beforehand, here's what the chunk of code looks like:

regs_in.r[0] = 256+52; /* Plot scaled sprite from user bank */
regs_in.r[1] = (int) sprite_area;
strcpy(textbuffer, "screen");
regs_in.r[2] = (int) text buffer;
regs_in.r[3] = 300; /* x coordinate */
regs_in.r[4] = 256; /* y coordinate */
regs_in.r[5] = 0; /* plotting action */
regs_in.r[6] = 0; /* scale factors */
regs_in.r[7] = (int) translation_buffer;
_kernel_swi(OS_SpriteOp, &regs_in, &regs_out);

This particular sprite operation is used to plot scaled sprites, so if you wish to stretch or shrink a sprite in either direction, it's possible to calculate a scale factor and store this in R6. A value of 0 results in no scaling being applied.

R7 points to the all-important pixel translation table, and when this call is made, the appropriate sprite is converted and sent to the screen in one breath,

Now that we're able to plot a sprite no matter what screen mode we happen to find ourselves in, the next step is to plot sprites within a multitasking window — I'll cover this next time.


Source: Acorn User - 182 - June 1997
Publication: Acorn User
Contributor: Steve Mumford