RANDOM MEMORY ZX Computing, November 1986 A packed column this month with Clyde Bish revealing the minimal memory route to 3-D adventure graphics plus a useful "Speedraw" routine. [There were several mistakes in this article, which I've corrected. ] [Also, several changes had to be made to Program 3 to get the picture] [it produced to match the illustration in the mag. JimG] [Programs 1/2/3 below are combined in file "3D Draw" in RAND8611.TAP.] You may remember a few issues ago I suggested using a series of short subroutines, called in succession to produce an illustration. Now's the time to follow up that idea. As 3-D pictures seem to be in vogue at the moment let's set about producing the graphics for a dungeon/passage-type adventure. We will need views into rooms, along passages, around corners, into dead-ends, through junctions etc. Although this may seem a little daunting it is in principle quite simple as all of these views can be made up of just a few, often repeated lines. Type in Program 1, keeping to the line numbers, and I'll show you what I mean. Now call a few lines with the command GOSUB (line number). In each case a few lines will appear on screen. Not very impressive you might think, but don't give up yet. These are only the picture elements. Add Program 2 to the listing for Program 1 you have on board. Now set PAPER to 0 and INK to 7 - It'll look more "dungeony" in white on black background - then GOSUB to each of the new lines in turn, with a CLS between each call and you'll see how various combinations of those original picture elements can be joined to give a series of rooms, junctions, passages, turns etc. So far so good, but our adventurer would be rather restricted in his movements. Let's add some doors, arches, openings, holes, ledges, and a crevasse! While we're at it we might as well supply some flaming torches to throw a glimmer of light on the proceedings. Add Program 3, noting that the capital letters are all UDGs, and must be entered in the G mode. [Except the "O" in line 22. JimG] We'll also need to set these UDGs so input the data from Table A [file: UDGs], using: FOR f=USR "a" TO USR '"p"+7: INPUT i: POKE f,i : NEXT f Now you can add a lot more features to your basic rooms and passages. Try: 9999 LET i=2: LET c=10: GOSUB 36 : GOSUB 37 : GOSUB 3: GOSUB 22 : GOSUB 26 : GOSUB 27 : GOSUB 28: GOSUB 39: GOSUB 41 : GOSUB 42 : GOSUB 44 You should get a view similar to that shown in Fig. 1. [RAND8611.GIF] Note that the value of c determines the position of opening, arch or hole on the facing wall produced in lines 29-37. Also the value of i in lines 41-44 determines the INK colour of the handle of the torches. (The shimmering effect in the torches is caused by nothing more than the Spectrum's infamous "dot creep". There just had to be a use for it!) I'll leave you to experiment further - the function of each line is REMed in the listing - and to discover impossible combinations. (Like trying to include a crevasse in a room!) Instant Graphics It may be that the perfectionists amongst ZXC readers are not happy with the way the picture is drawn before their very eyes. It may be that you would prefer the illustration to suddenly appear, complete, on screen. All that is needed for this effect is a combination of trickery and a short machine code routine. Use the following line to input these numbers: 33, 0, 88, 1, 192, 2, 22, 7, 114, 35, 11, 120, 177, 32, 249, 201 FOR f=USR "t" TO USR "u"+7: INPUT i: POKE f,i: NEXT f (If you want to use all the UDGs you could move this code elsewhere). To call an illustration use a line such as: 9999 CLS: INK 0 : GOSUB (each of the element subroutines): RANDOMIZE USR "t" : INK 7 This is how the trick works INK is set to 0 - the same as PAPER - before calling the subroutines so they are drawn invisibly. Calling the machine code causes all the attribute file bytes to be altered to 7, i.e. white INK on black PAPER, so the picture appears more or less instantaneously. Finally INK is reset to 7 or you wouldn't see any subsequent printing! Note that the torch subroutines have to be called after the machine code or you'll get no colour. If you want to use, say, yellow INK on blue PAPER,POKE the attribute you require - in this case 6+1x8=14 - into address (start+7) as well as making the obvious changes to the INK number. If you want your adventurer to have something to look at in the second it takes to produce the picture you could print a message after the CLS. The graphics won't affect it as long as you avoid areas which will be drawn on. Generally rows 0 to 5, columns 8 to 23 are safe, or you could use the edit lines with PRINT #0; "message". Using different combinations of doors, openings, arches etc. you can produce an enormous variety of illustrations. (There are 15 possible combinations of torches for a start, even if you don't alter the value of i!) I'll follow up this idea of picture elements further in a later article when we'll look at "Lords of Midnight'-'type scenes, but now to a completely different solution to the problem of big pics in few bytes. Speedraw If we had machine code routines to plot, draw, block in areas of paper and fill areas with ink we could build up a picture on screen very quickly from a string of data if this included information for choosing the right routine. Ladies and Gentlemen, the Great Wizard of Exon proudly presents "Speedraw"; a graphics utility to produce high resolution illustrations drawn at high speed and at an average cost of only 250 bytes per screen. (Less if you reuse parts of one picture in another). For the technically minded, this is how it's done. The secret is in the sequence of numbers the routine encounters. Let's call this the Drawcode. The value 255 (and to some extent 0) is reserved for use by the driver. 0 on its own means return. The number of 255s at the beginning of each sequence determines which mode is selected. Exit from or jumping within a routine is controlled again by 255s being encountered. Figure 2 [SPEEDRAW.GIF] gives a flow chart for each mode. Use: CLEAR 64890: FOR f=64891 TO 65367: INPUT i: POKE f,i: PRINT f,i : NEXT f to enter the data for the machine code from Table B, and save with SAVE "Speedraw" CODE 64891,477. Let's enter some example drawcodes to use each mode in turn. Plot/Draw This produces the outline drawing. Use the loader line: 10 FOR f=40000 TO 40021: INPUT i: POKE f,i : NEXT f (RUN) to enter the following sequence of numbers, pressing ENTER where there is a comma [file: demo1]: 10, 10, 50, 10, 50, 60, 10, 60, 10, 10, 255, 100, 40, 160, 40, 130, 100, 100, 40, 255, 255, 0 Now use RANDOMIZE USR 64891 to display a box and triangle to screen. If you compare the data with the flowchart you will notice (a) that this mode is called when NO 255 starts the sequence. (b) The first pair of numbers are the PLOT coordinates, subsequent pairs being absolute DRAW coordinates; i.e. you give the actual coordinates you want to draw to. No more messing about with positive/negative offsets; (c) a 255 starts a new PLOT position, (d) two 255s means return to the driver. Note that you cannot PLOT/DRAW to 0 or 255. You don't need to anyway as the routine draws a border around the picture area. (This becomes very important in the FILL mode). Fill This mode "inks in" the pixels within an area bounded by lines. As you will need an area to fill alter the FOR/TO numbers in the loader line to 40021 and 40030 and add the following data [file: demo2]: 255, 255, 57, 11, 15, 58, 101, 42, 255, 0 RANDOMIZE USR 64891 to redraw the square and triangle and fill them with red and blue inks. Work out how it runs using the flowchart, remembering that the attribute values are ink + paper*8. One or two points to note when using fill. (a) The area to be filled must be completely enclosed. The smallest gap and FILL leaks out. There may be "invisible" gaps along a line. You can close these with an extra PLOT-DRAW, but often just moving the start position of the fill will solve the problem. (b) In order to be very fast the fill is only semi- intelligent, so you need to have the start position against a left or right boundary. You will also need to have more than one start point to fill shadowed areas (e.g. filling a ring), and the fill may not spread to very narrow areas. Either complete these with PLOT-DRAW or don't have narrow areas! Finally it is just possible to crash the routine so save the drawcode before trying it out. (Of course, once you have it working correctly it won't crash when in use in a program). Block This effectively "papers in" a block of character squares. Alter the FOR/TO numbers to 40000 and 40007 and enter the following sequence, which produces a blue block, 10 by 5 with top left corner at row 15, column 1 [file: demo3]: 255, 14, 15, 1, 10, 5, 255, 0 As before RANDOMIZE USR 64891 will display it. As it is the attribute number which is used this mode can be used to change the ink within an area without affecting the paper, and so alter just the outline colour. If you want to see a large picture drawn with Speedraw use the loader line (with FOR/TO set to 40000 and 40250) to enter the data from Table C [file: demo4]. RANDOMIZE USR 64891 will quickly display a Hobbitish path in the Misty Mountains leading to the Golden Key that you don't need anyway (Oops - Sorry!). If you look carefully you'll see that the sky top left is BLOCKed, not FILLed. This is so you can FILL the moon. (Remember you can't have INK on INK). When using Speedraw in your own programs you'll need to set the data start register to the beginning of the drawcode you want it to read. Do this with the subroutine: 1 RANDOMIZE a: POKE 64917,PEEK 23670: POKE 64918,PEEK 23671: RANDOMIZE USR 64891 ENTER having first set variable a to the data start address LESS 1 of the drawcode you wish to use. You have probably worked out by now that to produce an accurate drawcode will take a lot of working out on pixel paper. This cannot be avoided, but I can offer you some help in the form of an Editor/Assembler which will find and help you correct the errors. The listing is too long to include here, but if you're interested in finding out more about it write to me care of ZX Computing enclosing an SAE. Next time we'll return to the picture element idea and produce those promised "Lords of Midnight"-type landscapes at only 30 bytes each. 'Til then, happy drawing!