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!
