                          A SHORT STOS TUTORIAL
                                    
                               For ICTARI
                                    
                            By David Preston
                                    
                                Episode 2
                                    

     Well, here we are again. This time we'll add some more 
interesting ways of making graphics appear on screen.

     There are one or two overall considerations to bear in mind 
first. If we were working on a Falcon in true colour, we 
wouldn't need to worry about the colour palette at all, since 
all possible colours are available all the time, but on the 
ST(e) this is not the case. We only have a palette of 16 colours 
and each colour register can have a value chosen from 256 
colours (even on an STe under ordinary STOS). The problem we 
have is that we can only display 16 colours at a time, but in 
any two pictures we will have two different sets of 16 colours. 
So, however we change from one pic to the next we need to change 
the palette, but if at some point during the transition we have 
parts of both pictures on screen at once we need a way of coping 
with the palette. Fortunately STOS has the 'fade' command which 
works under interrupt, in other words once we call the command 
it carries on until it has finished, regardless of what our 
program is doing while that is still going on. Thus, like the 
'appear' transition in the first version of this slideshow, we 
can use this to change both the palette and the bitmap 
apparently simultaneously. Almost all of the extra routines this 
time use a variation on this theme.

     Something else we want to bear in mind is that each effect 
will take a different length of time to complete. Some have to 
be slowed down, both to have a consistent(ish) time for each to 
happen, and so that you can actually see them at all. Some 
happen so quickly without delays added that they'd hardly be 
worth the programming. Others are a bit slow when run 
interpreted, but if you compile the prog or run the compiled 
version I've included, you'll see that they can be speeded up a 
bit.

     You'll see that only a couple of lines in the original 
listings have changed, and because of the way the prog was 
designed the extra routines have just been added in easily.


     The Listing
     ===========

Lines 10-140 are essentially the same as they were, I just 
updated the REMs at the beginning.

10 rem  ____________________________
20 rem |                            |
30 rem |  STOS Tutorial for ICTARI  |
40 rem |     Slideshow program      |
50 rem |            #1              |
60 rem |                            |
70 rem |  David Preston  - Jan '97  |
80 rem |____________________________|
90 rem
100 key off : curs off : show on : hide 
110 if mode=2 then locate 0,10 : centre "Colour systems only - 
Press a key..." : wait key : default : end 
120  : 
130 mode 0
140 reserve as screen 5

We've added a new line 145 because some of the routines added 
later need an array to keep track of what they do to either 
bitmap or palette.

145 dim PAL(15),TILE_MAP(9,9)

Do you remember the problem I found (late) in the first episode? 
Well here's part of the fix. TEST$ now includes the full stop, 
so we can be sure that the extender really _is_ the extender 
when we slice it off for testing.

150 TEST$=".PI1.NEO"

Lines 160-440 are unchanged from part 1.

160  : 
170 show : palette $666,$0 : DUMMY$=file select$("*.*","Select 
path for picture files.  (Enter 'Q' in filename to Quit)") : 
hide 
180 if DUMMY$<>"" and left$(DUMMY$,1)="Q" then default : end 
190  : 
200 rem /// Main loop ///
210 EXIT_FLAG=false
220 repeat 
230  : F$=dir first$("*.*",32)
240  : if F$="" then cls : locate 0,10 : centre "No pictures! 
Press a key..." : wait key : EXIT_FLAG=true : goto 370
250  : repeat 
260  :  : gosub 410
270  :  : F$=left$(F$,12)-" "
280  :  : EXT$=right$(F$,4)-"."
290  :  : gosub 410
300  :  : L0ADED=false
310  :  : gosub 460
320  :  : gosub 410
330  :  : if L0ADED then gosub 560
340  :  : gosub 410
350  :  : F$=dir next$
360  : until F$=""
370 until EXIT_FLAG
380 goto 170
390  : 
400 rem /// Check for ESC key ///
410 K$=inkey$ : SC=scancode : AXI=asc(K$)
420 if AXI=27 then EXIT_FLAG=true
430 return 
440  :

Here's the second part of the fix for the routine to test for 
files we can load. It should now work properly. ;-)
 
450 rem /// Test file extender and branch to load routine ///
460 FTYPE=(instr(TEST$,EXT$)+3)/4
470 on FTYPE gosub 510,510
480 return 
490  :

We can still only load easy files for now!
 
500 rem /// Load Degas (*.PI1) or Neochrome (*.NEO) ///
510 load F$,5
520 L0ADED=true
530 return 
540  :

Now for the new routines! The program will choose at random from 
the 16 we now have. A word about rnd(n) - this produces a 
pseudo-random number between 0 and n _inclusive_, so, because we 
want 1-16 inclusive we add 1 to remove the chance of a zero. I 
almost always write a one or two line program in one of the 
other buffers to test that a rnd() statement will produce 
exactly the range of numbers I want.

550 rem /// Choose FX ///
560 FX=rnd(15)+1
570 on FX gosub 
620,670,730,890,1050,1150,1260,1340,1480,1560,1660, 
1820,2040,2420,2570,2670
580 return 
590  : 

This first routine was the only one we had in part 1.

600 rem /// FX ///
610 rem ### Fade + appear ###
620 fade 12 to 5
630 appear 5
640 return 
650  : 

Now the new routines. Remember that the next picture we want to 
display is held, along with its palette, in Bank 5.

First one's easy, fade the screen to black, then copy bank 5 to 
the screen (where it won't show yet), and finally fade the 
palette to the one from bank 5. Here we 'wait' for each fade cos 
we want stuff happening sequentially. It's 42 vsyncs we wait 
because 'fade' always has 7 steps so if it fades every 6 cycles 
it's 6 * 7 = 42!

660 rem ### Fade down & up again ###
670 fade 6 : wait 42
680 screen copy 5 to physic
690 fade 6 to 5 : wait 42
700 return 
710  : 

Now it starts getting a bit more techy. In all of the following 
routines that fiddle about with partial areas of the screen we 
use STOS's built-in 'divx' and 'divy' resolution conversion 
factors and base all our dimensions on a hi-res 640*400 screen, 
so _all_ these routines work in all three resolutions. Well, 
they certainly all work in low and medium but _should_ also work 
in high but they haven't been tested in high. But for now our 
program only works in low anyway, but we can add medium support 
easily later. (Terrible grammar, I apologise.)

Here are a few variations on a tiling theme. By tiles I mean 
small areas of screen we can deal with one by one. In this case 
the screen in 'split' into a 10 * 10 grid. 
Lines 730-780 use one of the extended versions of 'cls' (see 
manual for details) to sequentially clear the tiles to colour 
0.
Line 790 fades the palette to the new one, and
Lines 800-850 copy similar areas of the new picture from bank 5 
to the physical screen.
.
720 rem ### Tiles 1 ###
730 for Y=0 to 9
740 for X=0 to 9
750 cls physic,0,X*64/divx,Y*20 to X*64/divx+64/divx,Y*20+20
760 wait 1
770 next X
780 next Y
790 fade 3 to 5 : wait 21
800 for Y=0 to 9
810 for X=0 to 9
820 screen copy 5,X*64/divx,Y*20,X*64/divx+64/divx,Y*20+20 to 
physic,X*64/divx,Y*20
830 wait 1
840 next X
850 next Y
860 return 
870  : 

This next routine is almost identical to the last, but the 'X' 
and 'Y' nested loops are reversed, so where the above routine 
works in this sort of a pattern

     0 1 2 3 4 5 6 7 8 9
     0 1 2 3 4 5 6 7 8 9 
     etc, ie in repeated horizontal strips,

this one goes like so

     0 0 0 
     1 1 1
     2 2 2
     3 3 3
     etc etc, ie in repeated vertical strips.

880 rem ### Tiles 2 ###
890 for X=0 to 9
900 for Y=0 to 9
910 cls physic,0,X*64/divx,Y*20 to X*64/divx+64/divx,Y*20+20
920 wait 1
930 next Y
940 next X
950 fade 3 to 5 : wait 21
960 for X=0 to 9
970 for Y=0 to 9
980 screen copy 5,X*64/divx,Y*20,X*64/divx+64/divx,Y*20+20 to 
physic,X*64/divx,Y*20
990 wait 1
1000 next Y
1010 next X
1020 return 
1030  : 

Then these next two routines are variations on the last two, but 
set the 'fade' going and then just overwrite the existing image. 
This one's the 'vertical' version...

1040 rem ### Overwrite tile + fade - vert ###
1050 fade 12 to 5
1060 for X=0 to 9
1070 for Y=0 to 9
1080 screen copy 5,X*64/divx,Y*20,X*64/divx+64/divx,Y*20+20 to 
physic,X*64/divx,Y*20
1090 wait 1
1100 next Y
1110 next X
1120 return 
1130  : 

And this one's the 'horizontal...

1140 rem ### Overwrite tile + fade - horiz ###
1150 fade 12 to 5
1160 for Y=0 to 9
1170 for X=0 to 9
1180 screen copy 5,X*64/divx,Y*20,X*64/divx+64/divx,Y*20+20 to 
physic,X*64/divx,Y*20
1190 wait 1
1200 next X
1210 next Y
1220 return 
1230  : 

Now for some stuff! The 'rem' statement describes the effect. I 
believe it's called 'gelatin'. This is one of the effects that 
really work smoothest when compiled. And it's _very_ difficult 
to describe how it works!! Basically what happens is that each 
scanline (160 bytes) is copied up or down the screen 
sequentially, filling the area above it. I think the only way 
you'll understand what's happening is to work through the code, 
picturing what's happening within the loops in lines 1270 and 
1300.

1240 rem ### Pour out & pour in again (gelatin) ###
1250 rem Not pretty code, but faster than single statement 
lines!
1260 BANK_ADR=start(5)
1270 for X=physic to physic+32000-160 step 160 : for Z=X to 
physic step-160 : copy X,X+160 to Z : next Z : next X
1280 fade 3 to 5 : wait 21
1290 FT=physic+32000
1300 for X=BANK_ADR+32000-160 to BANK_ADR step-160 : FT=FT-160 : 
for Z=physic to FT step 160 : copy X,X+160 to Z : next Z : next 
X
1310 return 
1320  : 

This one's not quite as complicated as the last, but I think the 
advice for you to work through the code still applies!

1330 rem ### Collapse to centre line then expand ###
1340 for Z=0 to 100
1350 fill physic+Z*160 to physic+Z*160+160,0
1360 fill physic+32000-Z*160 to physic+32000-Z*160+160,0
1370 wait 1
1380 next Z
1390 fade 3 to 5 : wait 21
1400 for Z=100 to 0 step-1
1410 copy start(5)+Z*160,start(5)+Z*160+160 to physic+Z*160
1420 copy start(5)+32000-Z*160,start(5)+32000-Z*160+160 to 
physic+32000-Z*160
1430 wait 1
1440 next Z
1450 return 
1460  : 

This next one copies the image in bank 5 line by line to the 
physical screen, after starting a slow palette fade.

1470 rem ### Wipe transition + fade ###
1480 fade 28 to 5
1490 for Z=0 to 199
1500 copy start(5)+Z*160,start(5)+Z*160+160 to physic+Z*160
1510 wait vbl 
1520 next Z
1530 return 
1540  : 

Here, we copy increasingly large blocks from bank 5 to the 
screen, starting halfway down and working back to the top, but 
because the blocks extend as far down as they do up, the effect 
is of a spread of the new image from the centre line.
 
1550 rem ### Spread from centre ###
1560 fade 5 to 5
1570 Y=95
1580 for X=320/divx to 0 step-32/divx
1590 screen copy 5,X,Y,640/divx-X,200-Y to physic,X,Y
1600 wait 5
1610 Y=Y-10
1620 next X
1630 return 
1640  : 

This one's similar to the last, but the screen is cleared in a 
similar manner first.

1650 rem ### Clear from centre then spread from centre ###
1660 Y=90
1670 for X=320/divx-32/divx to 0 step-32/divx
1680 cls physic,0,X,Y to 640/divx-X,200-Y
1690 wait 2
1700 Y=Y-10
1710 next X
1720 fade 3 to 5 : wait 21
1730 Y=95
1740 for X=320/divx to 0 step-32/divx
1750 screen copy 5,X,Y,640/divx-X,200-Y to physic,X,Y
1760 wait 2
1770 Y=Y-10
1780 next X
1790 return 
1800  : 
Up to now we have taken all of our changes in a logical sequence, 
but in this routine we use a shuffling routine like the one I 
put on a recent Ictari disk so that tiles are replaced randomly. 
The tiles are tracked using a 10 * 10 array TILE_MAP. This is 
first loaded with the numbers 0-99, then shuffled. Then the 
array is interrogated sequentially and line 1970 converts the 
contents of each element from an integer back into x,y 
co-ordinates by using integer division and the modulus operator 
to separate them. That area of screen is then overwritten using 
the corresponding area from bank 5. 

1810 rem ### Random tiles + fade ###
1820 TT=0
1830 for X=0 to 9
1840 for Y=0 to 9
1850 TILE_MAP(X,Y)=TT : inc TT
1860 next Y
1870 next X
1880 for X=0 to 9
1890 for Y=0 to 9
1900 XX=rnd(9) : YY=rnd(9)
1910 swap TILE_MAP(X,Y),TILE_MAP(XX,YY)
1920 next Y
1930 next X
1940 fade 10 to 5
1950 for XX=0 to 9
1960 for YY=0 to 9
1970 Q=TILE_MAP(XX,YY) : X=Q/10 : Y=Q mod 10
1980 screen copy 5,X*64/divx,Y*20,X*64/divx+64/divx,Y*20+20 to 
physic,X*64/divx,Y*20 : wait 1
1990 next YY
2000 next XX
2010 return 
2020  : 

Now for something completely different. We've done lots of 
messing with the bitmap, but this time we'll do something with 
the palette. You'll only follow what's happening if you really 
absorb what the manual has to say about the 'palette' command. 
What's happening is that we fade each colour register to $0 
(lines 2040-2180), then fade the screen to the values from bank 
5. We then store those values in an array PAL. Then we copy the 
screen across, and fade each register up to the value in the 
array. So the net result is that the old image disappears colour 
by colour and the new one appears in the same way.

2030 rem ### Sequential fade ###
2040 fade 2,0 : wait 14
2050 fade 2,,0 : wait 14
2060 fade 2,,,0 : wait 14
2070 fade 2,,,,0 : wait 14
2080 fade 2,,,,,0 : wait 14
2090 fade 2,,,,,,0 : wait 14
2100 fade 2,,,,,,,0 : wait 14
2110 fade 2,,,,,,,,0 : wait 14
2120 fade 2,,,,,,,,,0 : wait 14
2130 fade 2,,,,,,,,,,0 : wait 14
2140 fade 2,,,,,,,,,,,0 : wait 14
2150 fade 2,,,,,,,,,,,,0 : wait 14
2160 fade 2,,,,,,,,,,,,,0 : wait 14
2170 fade 2,,,,,,,,,,,,,,0 : wait 14
2180 fade 2,,,,,,,,,,,,,,,0 : wait 14
2190 cls : fade 2 to 5 : wait 14
2200 for Z=0 to 15 : PAL(Z)=colour(Z) : next Z
2210 Z=PAL(0) : fade 2,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z : wait 14
2220 screen copy 5 to physic
2230 fade 2,PAL(0) : wait 14
2240 fade 2,,PAL(1) : wait 14
2250 fade 2,,,PAL(2) : wait 14
2260 fade 2,,,,PAL(3) : wait 14
2270 fade 2,,,,,PAL(4) : wait 14
2280 fade 2,,,,,,PAL(5) : wait 14
2290 fade 2,,,,,,,PAL(6) : wait 14
2300 fade 2,,,,,,,,PAL(7) : wait 14
2310 fade 2,,,,,,,,,PAL(8) : wait 14
2320 fade 2,,,,,,,,,,PAL(9) : wait 14
2330 fade 2,,,,,,,,,,,PAL(10) : wait 14
2340 fade 2,,,,,,,,,,,,PAL(11) : wait 14
2350 fade 2,,,,,,,,,,,,,PAL(12) : wait 14
2360 fade 2,,,,,,,,,,,,,,PAL(13) : wait 14
2370 fade 2,,,,,,,,,,,,,,,PAL(14) : wait 14
2380 fade 2,,,,,,,,,,,,,,,,PAL(15) : wait 14
2390 return 
2400  : 

This next one's quite easy, just using STOS's 'scroll' command.

2410 rem ### Scroll up, fade, then scroll up again ###
2420 cls back
2430 def scroll 1,0,0 to 640/divx,200,0,-1
2440 for Y=0 to 199
2450 screen copy back,0,Y,640/divx,Y+1 to physic,0,199
2460 scroll 1
2470 next Y
2480 fade 2 to 5 : wait 15
2490 screen copy 5 to back
2500 for Y=0 to 199
2510 screen copy back,0,Y,640/divx,Y+1 to physic,0,199
2520 scroll 1
2530 next Y
2540 return 
2550  : 

And this one's a variation on the same theme.

2560 rem ### Scroll up while fading ###
2570 def scroll 1,0,0 to 640/divx,200,0,-1
2580 fade 35 to 5
2590 screen copy 5 to back
2600 for Y=0 to 199
2610 screen copy back,0,Y,640/divx,Y+1 to physic,0,199
2620 scroll 1
2630 next Y
2640 return 
2650  : 

And finally, a real test of your visualisation skills. This one 
produces two sets of interleaved 'fingers' of the new image 
spreading from top and bottom of the screen. It's all down to 
the maths in the two 'screen copy' commands. This one really 
does run better compiled.

2660 rem ### Vertical blinds + fade ###
2670 fade 21 to 5
2680 for Y=0 to 199
2690 for X=0 to 79/divx step 2
2700 screen copy 5,X*16,Y,X*16+16,Y+1 to physic,X*16,Y
2710 screen copy 5,(X+1)*16,199-Y,(X+1)*16+16,199-Y+1 to 
physic,(X+1)*16,199-Y
2720 next X
2730 next Y
2740 return 


Well, that's it for this time. I hope my explanations have given 
you enough information to allow you to understand how each 
routine works. If there are any points needing further 
clarification, please get in touch through Ictari.

Next time we'll add some more user control and features.

David
