Adding System Power To ST BASIC
Kevin Mykytyn, Editorial Programmer
Atari ST BASIC lacks commands for certain operations such as reading the mouse pointer, but it's possible to fill in these gaps by calling system routines with the VDISYS command. In Part 1 of this series, we'll examine the basics of calling VDI routines from BASIC and demonstrate a useful graphics routine. Part 2 will show how to read the mouse pointer with VDISYS and present a program for creating your own custom mouse pointers.
If you own an Atari ST, you've probably heard at least two of the three-letter acronyms associated with the computer: TOS stands for Tramiel Operating System-a huge system program which, at the most fundamental level, allows the computer to function. And GEM stands for Graphics Environment Manager, a separate system program that handles the ST's graphics-oriented desktop. GEM, in turn, consists of three separate parts: the VDI (Virtual Device Interface), a low-level graphics interface that also handles mouse input; the AES (Application Environment Services), which uses the VDI to manage data and the desktop; and GEMDOS, which handles disk operations.
Interesting, you may say, but what's the point? For most BASIC programming, you needn't worry about TOS, GEM, VDI, AES, or GEMDOS, any more than the average driver needs to know exactly how an auto engine works. These system programs are the invisible machinery that makes everything else happen.
However, as you may have discovered, ST BASIC lacks commands to do certain tasks, such as drawing a circle or sensing the position of the mouse pointer. That's what makes one of these strange-sounding programs-the VDI-an invaluable asset for the BASIC programmer. The VDI holds a treasure trove of system routines which can do everything from drawing boxes and circles to rotating character fonts and manipulating raster blocks. With ST BASIC's VDISYS command, you can access all of these routines-which compensates in large part for the missing ST BASIC commands.
VDISYS To The Rescue
In simplest terms, the VDISYS command calls (activates) a VDI system routine to do a task that would be difficult or impossible to perform in BASIC. Furthermore, these system routines execute very quickly-a real plus when you're working with graphics. Whether executed in immediate or program mode, the VDISYS command always takes this general form:
In this example a simple variable named x appears in the parentheses. It doesn't matter what value this variable represents; it's a dummy parameter, needed only to satisfy the syntax of the command. Don't try to enter this command yet-if you do, there's a good chance you'll see the mushroom cloud symbol that signals a system crash. A certain amount of preparation is always needed before you execute VDISYS.
When a VDISYS command is executed, control passes from your BASIC program to an internal VDI handler, which eventually passes control to the VDI routine itself. But first the VDI handler looks at certain sections of the computer's memory, called parameter blocks. The data in the parameter blocks tells the handler which particular VDI routine you want to execute. There's also other information that the VDI routine itself will need. If you don't supply all the information needed to call a routine, the VDI handler can't carry out your request.
The first thing you must tell the computer is which VDI routine you want to call. Each VDI routine is identified by a unique opcode number. For instance, the VDI routine used in the program below has the opcode 11. This is a generalized shape-drawing routine. (There are hundreds of VDI opcodes and associated parameters, so we don't have room in this article for a listing. But you can find a 42-page list of selected VDI opcodes in COMPUTE!'S ST Programmer's Guide, available from COMPUTE! Publications.)
Once you know a VDI routine's opcode number, that value must be POKEd into a special place in memory defined by the reserved variable CONTRL. Try typing PRINT CONTRL in immediate mode; even if you haven't given this variable any value, the computer prints a number on the screen. ST BASIC always predefines CONTRL along with several similar variables. The CONTRL variable represents an actual location in memory.
Since the system automatically substitutes this location for the keyword CONTRL, you don't have to memorize a series of numbers or worry about where this parameter block really resides. To select VDI routine 11, for instance, you simply execute POKE CONTRL,11.
How Many Corners?
Once you've POKEd the VDI opcode 11 into CONTRL, you must tell the computer how many vertices (corners) are needed to define the graphic shape you want to draw. Regular geometric shapes require different numbers of vertices. A triangle, for instance, requires a minimum of three corners. A rectangle, on the other hand, can be defined with only two-the upper left corner and the lower right one. Of course, a rectangle has a total of four corners, but the total is not what we're looking for. The computer cares only about the minimum number of vertices it takes to draw the shape in question. After you determine how many vertices are needed, that value is POKEd into the location defined by CONTRL +2. For example, in line 30 of the program below, the statement POKE CONTRL+2,2 tells the computer that you want to draw a rectangle (defined by only two corners).
Notice that the second POKE is directed two bytes higher in memory than the first. Now you can see the parameter block begin to take shape: It's simply a segment of memory where you place a collection of values. The first byte of the parameter block is defined by CONTRL, and the remaining locations are defined as even-numbered offsets above that starting spot (CONTRL+2, CONTRL+4, and so forth).
The particular routine used in this program (termed a generalized drawing primitive) contains several subroutines (also called subfunctions), each of which performs a different drawing task. To choose a subroutine, you must POKE its identifying number (called the primitive ID) into the location defined by CONTRL+ 10. In this case we want to use the bar-drawing subroutine, whose primitive ID happens to be 1. So in line 40 of the program, we POKE CONTRL+10,1.
PTSIN And INTIN
The next step is to tell the VDI handler where to place the graphic shape. Recall that you told the computer earlier how many vertices it takes to define the shape. To position the shape on the screen, you must now tell VDI where to put each vertex. This is done by POKEing horizontal (X) and vertical (Y) coordinate values into a second parameter block area.
The second parameter block begins at a memory location defined by the reserved variable PTSIN (Points Input). Again, you don't need to know the actual memory locations involved, since the computer keeps track of them for you. All you need to do is POKE the correct numbers into PTSIN (and even-numbered adjacent locations, in some cases).
Lines 50-80 of the example program perform this job by POKEing the bar's X and Y coordinates into memory. The X coordinate of the first point is POKEd into PTSIN; the first point's Y coordinate goes into PTSIN+2; the X coordinate of the second point goes into PTSIN+4, and so on. Keep in mind that you must supply a pair of coordinate values for every point that you defined in CONTRL+2.
A third parameter block, beginning at the address defined by the reserved variable INTIN, is used to pass attribute values, if any are required by the current subroutine. The term attribute is a catch-all that can include many different parameters-colors, rotation values, a style index, or whatever-depending on which subroutine is called. Since the subroutine used in this program requires no attributes, we don't need to POKE any values in this segment of memory. As a signal to the VDI handler that no attributes are involved, we must also POKE a zero into location CONTRL+6; this location tells the system how- many attribute values to read from the INTIN parameter block.
After all of the required values have been POKEd into memory, line 90 of the example program executes the VDISYS command, which calls the VDI routine and draws a bar on the screen. This may seem like an enormous amount of preparation for such a simple task (which some other computers can do with a single BASIC statement). On the other hand, it's better than not being able to draw a bar at all. You can cut down on the bulkiness of the code by writing setup subroutines that contain all the necessary overhead.
10 fullw 2:clearw 2:color 2,2,2
20 poke contrl,11 'VDI opcode
30 poke contrl+2,2 'number of vertices
35 poke contrl+6,0 'number of attributes
40 poke contrl+10,1 'primitive ID of bar
50 poke ptsin,50 'x coordinate of top left
60 poke ptsin+2,50 'y coordinate of top
70 poke ptsin+4,100 'x coordinate of
bottom right corner
80 poke ptsin+6,100 'y coordinate of
bottom right corner
90 vdisys (0)
General Drawing Routine
Though every VDI call requires several preparatory steps, each individual step is easy to perform. As should be apparent by now, there's nothing mystical about the process-all you need to do is leave the right pieces of information in places where the computer can find them, then signal that you want the job done. The real work is done by the system itself.
Though the general procedure is the same in every case, each VDI routine requires different types and amounts of information. One of the most useful VDI routines is the generalized drawing primitive used in the example program. Table 1 summarizes the POKES you need to call this routine.
Table 1: Generalized Drawing Primitive
POKE CONTRL, 11
POKE CONTRL+2, number of vertices
POKE CONTRL+6, number of attributes
POKE CONTRL+10, subfunction number
Again, CONTRL receives the opcode number of the VDI routine; CONTRL+2 the number of vertices in the desired shape; CONTRL+6 the number of attributes (if any); and CONTRL+ 10 the primitive ID for the subroutine you want. This particular VDI routine is extremely versatile and can draw pie-shaped segments, ellipses, filled or empty rounded rectangles, and other graphic images, including text. Table 2 lists the primitive IDs for each of this routine's subroutines.
Table 2: Drawing Subroutines
||filled rounded rectangle
||justified graphics text
To select a specific subroutine, find its primitive ID in the leftmost column of Table 2, then POKE that value into location CONTRL+10. Table 3 summarizes the POKEs needed to set up the second and third parameter blocks (PTSIN and INTIN). Remember, the value POKEd into CONTRL+2 (number of vertices) determines how many X-Y coordinate pairs you must POKE into the PTSIN parameter block. The X and Y coordinates for the first vertex go into PTSIN and PTSIN+2; the second X-Y coordinate pair goes into PTSIN+4 and PTSIN+6, and so forth.
Table 3: PTSIN And INTIN Parameter Blocks
POKE PTSIN, X coordinate of first vertex
(rectangle)POKE PTSIN+2, Y coordinate of first
X coordinate of center
X coordinate of center
vertex (rectangle)POKE PTSIN+4, X coordinate of second
Y coordinate of center
Y coordinate of center
vertex (rectangle)POKE PTSIN+6, Y coordinate of second
X radius for ellipse
X radius for ellipse
vertex (rectangle)POKE PTSIN+8, radius (circle only)
POKE PTSIN+12, radius (circular arc or
POKE INTIN, start angle for arcs and pies
POKE INTIN+2, end angle for arcs and
To draw a circle, ellipse, arc, or pie-shape segment, POKE X and Y coordinates for the shape's center point into PTSIN and PTSIN+2. A simple circle requires a radius value in PTSIN+8; arcs and pie shapes built from a part of a circle require a radius value in PTSIN+12. To draw an ellipse, or an arc or pie shape built from part of an ellipse, POKE the shape's X radius in PTSIN+4 and its Y radius into PTSIN+6.
Most of these subfunctions don't require any attribute values. To draw arcs or pie shapes, however, you must POKE two attribute values into INTIN and INTIN+2 to define starting and ending angles, respectively. Since the angle values are specified in tenths of a degree, not in whole degrees, these parameters can range from 0-3600. The starting angle specifies where you want the rounded portion of the arc or pie segment to begin, and the ending angle shows where that portion should stop. The statement POKE CONTRL+6,2 signals that you're passing two attribute values to the VDI.
As you'll learn from experimenting with these routines, VDISYS opens the gateway to a wide variety of graphics capabilities. Once you become familiar with the setup process, you'll probably find yourself using VDISYS more and more. In part 2 of this article, we'll look at VDISYS in more detail, and present a program that lets you create a custom shape for your ST'S mouse pointer.