RISC OS SPRITE CALLS

RISC OS provides the user with a powerful set of new sprite commands, as Lee Calcraft explains.

If you have seen the RISC OS Magnifying Glass in operation, then you will have seen something of the power of the new sprite calls available in RISC OS. The two that I am going to look at here allow you to scale a sprite up or down (as used by the Magnifying Glass demonstration), and to send VDU output directly to a sprite. By combining the two of these, you can produce a scaled output from a program within a window of any size. This trick has been used from the Desktop to allow Zarch to run within a small window.

Table 1. The New Sprite Calls

35Append a sprite
36Define pointer from sprite
50Plot scaled sprite mask
51Paint scaled character
52Plot scaled sprite
53Plot grey-scaled sprite
60Switch VDU output to sprite
61Switch VDU output to mask

Add 256 to these reason codes for named user sprites, or 512 for user sprites accessed by address.

THE SPRITE CALLS

All of the new sprite calls use "OS_SpriteOp". We took a look at this operating system call in Volume 2 Issue 3, when dealing with user sprites, and the reader is referred to that article for a "refresher" if need be. In what follows, I will be using the new calls with user sprites (since this is most appropriate for multi-tasking applications), and to start with, I will look at the code necessary to set up a sprite area, load a sprite file, and plot a sprite from it. All this can be achieved in just four lines:
10 DIM sp &2000:!sp=&2000
20 sp!4=0:sp!8=16:sp!12=16
30 SYS "OS_SpriteOp",266,sp,"ICONS.Music"
40 SYS "OS_SpriteOp",290,sp,"Treble",640,512

As you can see, there is not much to it really. The first two lines set up a user sprite area of &2000 (8K) in size, as described in the article referred to above. The first of the two OS calls loads a sprite file called "ICONS.Music" (supplied on the Arthur Welcome disc) into the area, and the second plots one of the sprites (called "Treble") from this file at co-ordinates 640, 512. The first numerical parameter in each case is the reason code for the operation, and the second the address of the sprite area, again as indicated in the previous article.

In fact the reason code for all sprite operations has two components, a number between 0 and 255 indicating the type of operation to be performed, plus a high byte indicating whether user or system sprites are in use, and in the former case, whether access is by name or address. The reason code to plot a sprite, used above, could thus be given as 34 (system sprites), 34+256 (named user sprites) or 34+512 (user sprites accessed by address). We have used the value 290 (i.e. 34+256), meaning that we are using user sprites, and that they will be accessed by name (the name "Treble" in this case). In what follows we shall continue to use this form of the call, referring to named sprites in a user area.

SCALED SPRITES

To plot a scaled sprite, we use reason code 52+256 (i.e. 308), and we must set up four words in RAM to define the scale of magnification or reduction, and then supply a pointer to this 16-byte block in the call itself. The program in listing 1 achieves this, plotting the "Treble" sprite at co-ordinates 100, 100, at a horizontal magnification of 8 and a vertical magnification of 6. This is achieved using the 4 words of RAM at location scale. The first two numbers give the X and Y magnification factor, while the second two give the X and Y reduction factors. As you can see, the latter are currently set to 1. To reduce the horizontal size of the sprite by a factor of 2/3, we would use:
!scale=2scale!8=3
and so on (i.e. multiply by 2 and divide by 3). As you will appreciate, this gives us very fine control over the scale factor used for the sprite plot, and we can put this call to many uses. For example, we could make an image appear as a point on the screen, and then grow in size, while at the same time moving across the screen, by using a simple FOR loop.

Listing 1

10 REM >Ros1Sprt
20 REM Plot scaled sprite
30 :
40 MODE 12
50 DIM sp &2000:!sp=&2000
60 DIM scale 16
70 sp!4=0:sp!8=16:sp!12=16
80 SYS "OS_SpriteOp",266,sp,"ICONS.Music"
90 SYS "OS_SpriteOp",290,sp,"Treble",640,512,0
100 :
110 !scale=8 :REM X multiply
120 scale!4=6 :REM Y multiply
130 scale!8=1 :REM X Divide
140 scale!12=1 :REM Y Divide
150 SYS "OS_SpriteOp",308,sp,"Treble",100,100,0,scale

VDU OUTPUT TO A SPRITE

A call to "OS_SpriteOp" with a reason code of 60+256 can be used to send all VDU output to a named sprite instead of to the screen. The sprite can then be displayed as and when required, using the calls already treated. The program in listing 2 achieves this. It first loads the Music sprite file, and plots the sprite named "Treble" as before. Next it performs Sprite Op 316 (i.e. 60+256) setting all VDU output to the "Treble" sprite. In practice text and graphics windows are set by this call to the size of destination sprite, with the graphics origin corresponding to the bottom left hand corner of the sprite, and screen output is sent to the sprite just as if it were a small windowed screen.

Listing 2

10 REM >Ros2Sprt
20 REM VDU output to sprite
30 :
40 MODE 12
50 DIM sp &2000:!sp=&2000
60 sp!4=0:sp!8=16:sp!12=16
70 :
80 SYS "OS_SpriteOp",266,sp,"ICONS.Music"
90 SYS "OS_SpriteOp",290,sp,"Treble",640,512,0
100 :
110 REM VDU output to sprite
120 SYS "OS_SpriteOp",316,sp,"Treble" TO R0,R1,R2,R3
130 CIRCLE FILL 20,40,16
140 :
150 REM Reinstate output
160 SYS "OS_SpriteOp",R0,R1,R2,R3
170 :
180 REM Plot it again
190 SYS "OS_SpriteOp",290,sp,"Treble",768,640

Next the program draws a small filled circle at 20,40, which does not appear on the screen, but is sent to the sprite instead. Output is then reinstated (line 160) and the sprite re-plotted. Sure enough it appears with a white disc superimposed upon it.

To send VDU output to the Treble sprite, we have used just 3 parameters: the reason code, the pointer to the sprite area, and the sprite name, just as before. But now we store the register values on exit from the call in the four variables R0-R3, and these are used to reset VDU output after we have finished writing to the sprite. For this we use:
SYS "OS_Sprite_Op",R0,R1,R2,R3

These calls have been implemented by Acorn with a great deal of care, and all VDU variables are stored away and later reinstated when the calls are made. As a result the user does not need to keep track of window settings, origins, cursors and so on. It is all taken care of. Moreover, the VDU data sent to any sprite is given its own VDU queue, so that you can switch VDU output to and from sprites at any time.

To give a practical example of the use of the two new sprite calls discussed here, the program in listing 3 executes in a scaled window that can be altered using the mouse. When you run it you will see a small window near the bottom of the screen in which randomly coloured circles are being drawn. By pressing the Select button on the mouse you can move the base position of the display window, while pressing Adjust allows you to alter its size. All this is accomplished without disturbing the drawing process.

To see how this is achieved, take a look at PROCvisuals near the end of the program, and you will see that the circles are apparently being drawn on a full screen. In fact they are drawn into a sprite called "Image", which is then scaled and plotted each time around the drawing loop. To keep the program short, I have just drawn random circles, but PROCvisuals could be replaced by a much longer and more interesting procedure of your choice.

The key to the way in which the program works is the set of three sprite calls (at lines 210, 240 and 270) made within the REPEAT loop. The first sends VDU output to a sprite called "Image" which is the size of a full screen. The second resets VDU output to normal, and the third plots the "Image" sprite suitably scaled. As I hope this example shows, experimentation with these powerful calls will pay dividends.

Listing 3

10 REM >Ros3Sprt
20 REM Program windowing
30 :
40 MODE13:OFF:*POINTER
50 ON ERROR MODE12:REPORT:PRINT" at line ";ERL:END
60 DIM sp &15000:!sp=&15000
70 DIM scale 16
80 sp!4=0:sp!8=16:sp!12=16
90 :
100 scale!8=1280:scale!12=1024
110 !scale=320:scale!4=256
120 xbase%=100:ybase%=100
130 :
140 REM Get empty sprite
150 MOVE 0,0:MOVE 1279,1023
160 SYS "OS_SpriteOp",270,sp,"image",1
170 :
180 N%=0
190 REPEAT
200 REM VDU to sprite
210 SYS "OS_SpriteOp",316,sp,"image" TO R0,R1,R2,R3
220 PROCvisuals
230 REM Reinstate screen
240 SYS "OS_SpriteOp",R0,R1,R2,R3
250 REM Display sprite
260 WAIT
270 SYS "OS_SpriteOp",308,sp,"image",xbase%,ybase%,0,scale
280 PRINTTAB(10,5)"Frame number ";N%
290 PRINTTAB(8,7)"Mouse:Move,Quit,Scale"
300 N%+=1
310 MOUSE x%,y%,z%
320 IF z%<>0 THEN
330 CASE z% OF
340 WHEN 1:IF x%>xbase% THEN xmult%=x%-xbase%:!scale=xmult%
350 IF y%>ybase% THEN ymult%=y%-ybase%:scale!4=ymult%
360 WHEN 4:xbase%=x%:ybase%=y%
370 ENDCASE
380 WAIT:CLS
390 ENDIF
400 UNTIL z%=2
410 ON:END
420 :
430 DEFPROCvisuals
440 GCOL RND(63) TINT 64*RND(3)
450 CIRCLE FILL RND(1100),RND(1000), RND(300)
460 PRINT TAB(6,12)"RANDOM SPHERES IN MODE 13"
470 ENDPROC