3D Rotator Mark Jones with a program which makes his 3D rotator published in the July 1983 issue up to eight times faster. In July of last year, I wrote a program for Your Computer called 3D Rotator. This program allowed the Basic pro- grammer to manipulate simply defined 3D figures at machine- code speeds. A typical time was 0.5 seconds for a cube. Though this was extremely fast relative to Basic it was not fast enough for practical dynamic games. With this in mind I have speeded up the 3D routine by as much as eight times and made it more versatile. The speeds achieved now are as fast as those seen in commercial games such as 3D Tank Duel, with the advantage that they can be called from Basic. Data is stored as blocks of code at any memory location that you specify. The data should be followed by a blank area which = 12 * (number of sets of data). Therefore the total memory required for any one image = 19 * (number of sets of data). The data itself is made up of three 2's complement numbers and one 1 byte number. A 2's complement number is a 2 byte number where the negative form is 65536- number, e.g., -5 = 65536-5 and +5 = 5. A 2 byte number is Poked into memory as described on page 173 of the Spectrum manual. The numbers are stored as follows: x co-ordinate, y co- ordinate, z co-ordinate and the 1 byte number 0 to indicate a plot at x,y,z or 1 to draw a line from the last point plotted to x,y,z. I include a Basic program - program A - which will handle conversion of data into a suitable form for the machine-code program. The Basic program will also store the essential parameters such as the pointer to the data, number of sets of data etc., for that figure. Producing the data for a simple 3D figure is relatively easy. I refer you for further information to my article 3D Rotator of July 1983 and Ian Angell's article BBC 3D Graphics in the February 1984 edition of Your Computer. [I do not have current access to these articles. The BBC article would, naturally, not be linked from WoS, but Mr. Jones' earlier one seems to be missing as well. In any case, anyone with a passing knowledge of 3D Cartesian co-ordinates should find the single example in the Basic program sufficient.] The 3D program allows the parameters for up to 16 3D images. These parameters are stored in fixed areas from 65032 onwards and in blocks of 20 bytes. Thus the start of the parameter area for figure 4 = 4*20 + 65032 - see table 1 [at the end of this file]. Each 3D image stored in memory should have a separate set of parameters though they might share a common set of data. Draws need not point to a memory area after your 3D data but I find I keep track of my memory state better by doing so. For example, fig.0 and fig.1 might both be pyramids and so use the same data. Draws for fig.0 is as normal, after the data, but draws for fig.1 points at another section of free memory and its ADDR points to the fig.0 data. If it has all seemed rather complicated so far, do not worry - it is really quite easy to use these 3D routines. Here is an example: To set up fig.0 as a cube first of all work out your data and then store it in data statements in Basic program A. For a cube there are 16 sets of data so adjust line 15 accordingly. The data is going to be stored at 40000 on- wards so first of all ensure this area is free from the Basic system with a CLEAR 39999 and then adjust line 10 accordingly. Finally, this is going to be figure 0 so adjust line 5. Now run program A. Once the program is complete it will give you a print-out of the next free memory available for data, 40316, and also the position of the parameters area, 65032. If you now wished to have another cube that could move independently of fig.0 then simply make line 10 read LET addr=40316 Line 5 should read LET fig=1 and run the program again. This is, of course, an example and actual addresses will depend on the number of sets of data you use. Program A as printed will set up fig.0 as a cube as in the above example. Now to actually produce a 3D image on the screen there are a number of steps: # Select the current figure by Poking 64976 with the required figure number 0-15. # RANDOMIZE USR 64234 actually converts your data to a list of plots and draws stored in the figure's associated free area of memory, pointed to by Draws. # RANDOMIZE USR 64692 produces the 3D image on the screen from the list of plots and draws. # RANDOMIZE USR 64679 deletes the last image drawn by the above routine. Therefore using various sequences of these routines you can produce 3D images from within your Basic programs. As an added feature I have included a machine-code demonstration program which will put the current figure indicated by PEEK 64976 through its paces. The number of steps, and so speed of this demonstration, can be altered by Poking 63501 with a number between 1 and 150. The routine is called with RANDOMIZE USR 63500 Finally, to alter a given figure's position on the screen, distance from you or angle simply alter the 2's complement numbers PX, PY, PZ, Phi, Theta and Psi in the parameters for that figure. To run a demonstration of the routines from Basic load with program A and then GO TO 5000. This sets up three cubes, shows off the machine-code demonstration and then leaves the three cubes to float around in space spinning. If you remember the 3D Rotator routine in my last article you may be interested to compare it with these new rou- tines. The routine to handle the 3D conversion is written more efficiently, uses 2 byte x,y,z co-ordinates and does not draw the figure straight away. This allows a number of figures to be produced in memory but not drawn until needed. This routine also handles calculations for lines parti- ally off screen ensuring that the line eventually produced for the draw routine does not go off screen. The routines to draw and delete figures use a draw rou- tine specially written for this program which is extremely fast. The routine does not draw a line by plotting but by manipulating screen addresses and rotating a mask. To use the plot/draw routine for for yourself use the following method: # Set up an unused figure, e.g. fig. 15, by Poking both DrawS and DrawP with the same value, the address of an unused area of memory. Next Poke STFLG with 255. # Store your plots and draws at this address in the following form: P,x,y where P=0 to plot at x,y P=1 to draw from the last point plotted to x,y P=255 to end the data x is a normal x co-ordinate y has the range 0-191 where 0 is the bottom line of the edit area. e.g. to draw a frame around the screen the data would be: 0,0,0, 1,255,0, 1,255,191, 1,0,191, 1,0,0, 255 [ The last two paragraphs described how to enter the programs. The result is on the TZX. Program A mentioned above, with a few lines added to make it auto-load the machine code, is called "Demo". The 3D Rotator machine code itself is, of course, "3D Rotator". The final program, "codereader", is the Basic program B used to load the machine code into memory; it should not be needed any more, but I've added it for completeness. ] Table 1. Offset Bytes Parameter Description Range 0 1 NUMB Number of sets of data 1-255 1 2 ADDR Start address of data 3 2 PX X co-ord (+ve left) 5 2 PY Y co-ord (+ve up) 7 2 PZ Z co-ord (+ve forward) 9 2 PHI Angle about X axis 0-359° 11 2 THETA Angle about Y axis 0-359° 13 2 PSI Angle about Z axis 0-359° 15 2 DRAWS Address of free memory after 3D data 17 2 DRAWP 6*NUMB + DRAWS 19 1 STFLG Poke this with 0 the 0 to 255 first time you use the 3D image