Appendix 2 - Pixel Graphics SWIs
Following is a selection of operating system routines (SWIs) that will be useful to those wishing to handle sprites from BASIC, Assembler or other languages. All use the call OS_SpriteOp (which must be spelt in exactly that way). The exact operation depends on the contents of the arm's registers. From BASIC the registers are set up by specifying their contents as a sequence of arguments.
Before you can use sprites you must set aside an area of memory in which the sprite definitions will be stored. RISC OS provides its own system sprites area, but its use is now discouraged, current practice being for applications to set up their own user sprites area. If the size of the sprites together with that of the application software exceeds 640 Kbytes, you will need to expand the size of the Next slot either manually from the Task Display before loading the application or by using the appropriate WimpSlot command in the application's !Run file.
The operation to be applied is determined by the least significant 8 bits of Register 0, giving each operation a number between 0 and 255. Bit 8 (which adds 256 to the register value) and bit 9 (which adds 512 to the register value) are used as flags to indicate respectively the choice of sprite area and the means of identifying the individual sprite concerned, If both flags are 0, the system sprites area is used and the sprite must be identified by its name. If either flag is set, the user sprite area is used, If bit 8 is set, the sprite will be identified by its name. If bit 9 is set, the sprite will be identified by its position in the area, i.e. its position in the sprite file. This is a faster means of locating sprites than by name, since it eliminates the need to search the sprite area for the occurrence of a string. It is illegal to set both bit 8 and bit 9.
Register 1 contains the address of the user sprite area and so is only used if the operation relates to such an area. In BASIC its use is simple. The BASIC application probably created the user sprites area by an instruction such as DIM sprites% 512000. It is sufficient then to specify sprites% as the content of this register. BASIC will look up the address contained in the variable and will copy it into the register. You need never know the exact address.
Register 2 identifies the individual sprite on which the operation is to be performed. If you are identifying the sprite by number, that number is inserted in the register. If you are identifying the sprite by name, the sprite name must be 'indirected' since it may well be too long to be accommodated in a 32-bit register. The register therefore must contain a memory address where the sprite name (terminated by a null) can be found. Again, however, BASIC simplifies this dramatically, it being sufficient to include the sprite name between double quotes as an argument.
Some of the calls involve plotting the specified sprite on the monitor screen. The plot action itself offers a wide range of options determined by the contents of one of the registers. These are as follows: value action
Note that options 0 to 7 are mutually exclusive.
Any of those eight options can be combined with option 8 (by adding 8 to it) and also with any one of options &10 to &50 by adding its number on to it.
OS_SpriteOp 9 Initialise sprite area
R0=9 or 265 (&109) or 521 (&209)
This initialises a sprite area. If the same area has previously been used for sprites, these are all deleted, leaving the sprite area empty. If using the system sprite area, it is equivalent to the OS command *SNEW.
If you are initialising a user sprite area, you must also initialise two words in the area header. The first word (32 bits) must contain the total size of the area and the third word the offset to the first sprite, usually 16. Thus a BASIC program which sets up a user sprite area might include the following line:
DIM sprites% 512000;!sprites%=512999:sprites%!8=16
OS_SpriteOp 10 Load sprite file
R0=10 (&0A) or 266 (&10A) or 522 (&20A)
This loads the named file into the specified sprite area, overwriting any sprites already present. The sprite area must have been previously initialised. If using the system sprite area it is equivalent to *SLOAD.
For example, in a BASIC program the following line would load a file called 'mysprites' (assumed to be in the currently selected directory) into the user sprite area defined in the previous example:
OS_SpriteOp 11 Merge sprite file
R0=11 (&0B) or 267 (&10B) or 523 (&20B)
This loads the named sprite file into the specified sprite area without overwriting sprite definitions already present. There must, of course, be sufficient space for the new as well as the existing sprite definitions. After loading, any of the original sprites having names which occur also in the newly loaded sprite file are deleted. If using the system sprites area, the call is equivalent to *SMERGE.
OS_SpriteOp 12 Save sprite file
R0=12 (&0C) or 268 (&10C) or 524 (&20C)
This saves all the sprites in the current sprite area as a sprite file. If using the system sprites area, the call is equivalent to *SSAVE.
OS_SpriteOp 14 Get screen area
R0=14 (&0E) or 268 (&10C)
Use this call to copy a portion of the current screen as a sprite. The operating system stores the last two positions of the graphics cursor in a buffer. You should therefore arrange to take the graphics cursor to two diametrically opposite corners of the area to be saved and then issue the call. You must designate a name for the new sprite; it cannot be identified by position in the user sprite area. The call creates the sprite in the designated sprite area; a separate save operation will be needed to save it to a disc or other filing system.
OS_SpriteOp 28 Plot sprite at graphics cursor
R0=28 (&1C) or 284 (&11C) or 540 (&21C)
This call is useful in games where the sprite is moved around the screen in response to the mouse or cursor keys. If the plot action is 3 (exclusive-OR), replotting the sprite in the same position will erase it, restoring whatever detail was present previously.
OS_SpriteOp 33 Flip sprite about its x-axis
R0=33 (&21) or 289 (&121) or 545 (&221)
This flips the sprite about its horizontal axis, effectively inverting it. The sprite is only inverted in memory-to see the inverted sprite you must subsequently plot it using an appropriate call.
OS_SpriteOp 34 Plot sprite at user co-ordinates
R0=34 (&22) or 290 (&122) or 546 (&222)
A fast and easy-to-use routine for plotting a sprite at any required position on the screen without affecting the graphics cursor.
OS_SpriteOp 47 Flip sprite about its y-axis
R0=47 (&2F) or 303 (&12F) or 559 (&22F)
This flips the sprite about its vertical axis, effectively mirror-imaging it. The sprite is only reversed in memory-to see the reversed sprite you must subsequently plot it using a plotting call.
OS_SpriteOp 52 Plot sprite at user co-ordinates with scaling
R0=52 (&34) or 308 (&134) or 564 (&234)
This call, because of its versatility, is widely used in graphics software for plotting sprites which must be scaled or for plotting sprites in screen modes other than those in which they originated. When you import a sprite into a Draw document, for instance, it is this call that plots it on the screen.
In order to use the scaling facilities you must set apart a block of 16 bytes as a scale table. In BASIC this might take the form DIM scale% 15. This is divided into four four-byte words, respectively the x multiplier, the y multiplier, the x divisor and the y divisor. The multipliers and divisors may be thought of as the numerators and denominators of fractions which determine the size of the sprite being plotted. In this way the call will enlarge or reduce a sprite and can scale the two axes independently if required.
The following lines in a BASIC program will cause a sprite called 'mysprite' to apparently 'grow' while remaining centred at a certain position on the screen. It is assumed that the sprite has the same number of colours as the current screen mode, so that no colour translation table is needed.
DIM scale% 15:scale%!8=&100;scale%!12=&100 FOR x%=l TO 256 !scale%=x%:scale%!4=x% WAIT SYS "OS_SpriteOp",&134,sprites%"mysprite",682-(106*x%/256),64-(62*x%/256),0,scale% NEXT x%
Beware of scaling a sprite whose design includes dither patterns. Since these will not be reproduced consistently at non-native sizes, the sprite is likely to Hash in a thoroughly disconcerting manner. (Of course, if you are looking for a psychedelic effect, you might like to try it.)
The colour translation table may be omitted if the sprite was created in a mode having the same number of colours as the mode in which it is being plotted. If, however, you wish to plot in a 256-colour mode a sprite that was created in, say, a 16-colour mode, you must include a colour translation table. This is simply a block of memory, one byte for each colour used in the sprite's original mode, which represents colours 0, 1, 2 etc. respectively. The contents of each byte represent the number in the current palette of the colour in which this colour should be rendered. In Draw and other applications which use this call, the colour translation table is set up automatically by the application, the original colours being matched as closely as possible to the present palette for their RGB content. In some other applications, such as FontEd, there is no such automatic creation of colour translation tables and so importing a two-colour sprite into a 16-colour mode screen results in the error message 'Bad colour translation table'.