Skip to main content

 GEM-VDI CALLS PART I by Manus

Originally  published  in ST NEWS Volume 1 Issue  4,  launched  on 
September 7th 1986.

While others are exploring GFA BASIC,  I am going to tell you  all 
about GEM VDI calls as used in good old ST BASIC.
By the way,  sorry for my clumsy English, but it is about 16 years 
ago, that I had my last lesson in English.
Yes,  it  is  possible to use GEM-routines in your Basic  to  draw 
rectangles, to put your text in different modes and so on.
To  do  this,  we  use  special addresses in  which  we  poke  the 
necessary values.
The meaning of these addresses are:

INPUT: 
CONTRL           Instruction-number.
CONTRL + 2       Number of input-coordinates of a PTSIN-field.
CONTRL + 6       Number of input-data in a INTIN-field.
INTIN            Input-field (like color, textform and so on).
PTSIN            Input-field of two together belonging data.
                   (like the coordinates of a rectangle)
OUTPUT: 
CONTRL + 4       Number of output-coordinates.
CONTRL + 8       Number of output-data.
INTOUT           Output-field (like present textform).
PTSOUT           Output-field of two together belonging data.

IMPORTANT:
These addresses are 16-bits.  This means that a cell CONTRL+1  does 
not exist.
If you have changed the length of a bit by POKE,  you will have to 
set  this  back  by "DEF SEG=0",  before you  can  call  the  GEM-
routines.
Through  the statements GEMSYS and VDISYS we can call  these  AES- 
and the VDI-routines.

The GEM-SUBROUTINES have the following syntax:

* The first line contains the name of the subroutine.
* Then the variable that you have to use.
* And then the values you can use.

The  variables and subroutines used are the names of the  chapters 
and forms to make things clear to you.  You are free to use  other 
names  for the variables and the subroutines,  but remember: don't 
use  the same name for two different things.
You  can MERGE the subroutine you want to use or you can make  one 
big file with all subroutines.

TEXTMODE :

The Atari ST has different kinds of textforms like double  strike, 
italics, underlined and so on.
This  is  done  by switching byte 0 to 4 of  the  variable  called 
TEXTKIND:

       BIT:   VALUE:   TEXTMODE:
        0       1       Double strike
        1       2       Light
        2       4       Italics
        3       8       Underlined
        4      16       Hollow

The syntax is:
                  TEXTKIND = ......   (maximum is 32,normal is 0)
                  gosub TEXTMODE
The subroutine is:

65000 TEXTMODE:
65002 ' ----->      TEXTKIND
65004 '             0 = normal     1 = double strike  2 = light
65006 '             4 = italics    8 = underlined    16 = hollow
65008 '              or combinations
65010 '
65012 poke contrl    , 106
65014 poke contrl + 2, 0
65016 poke contrl + 6, 1
65018 poke intin, TEXTKIND
65020 vdisys
65022 return

Try this:

5   ' merge "TEXTMODE.bas"
9   ' 
10  fullw 2: clearw 2
20  data 1,2,4,8,16,3,5,9,10,0
30  for a = 1 to 10
40  read TEXTKIND
50  gosub TEXTMODE
60  gotoxy 14, a + 4: print "ATARI ST"
70  next a
80  waiting = inp(2)
90  end

TEXTSIZE : 

You can also change the size of the text. This means however, that 
you  can not use the PRINT-statement anymore.  You have to use the 
routine "TEXTOUTPUT". (see next routine)
The syntax is:
                     SIZE = ......
                     gosub TEXTSIZE
The subroutine is:

65030 TEXTSIZE:
65032 ' -----> SIZE:
65034 '        < 9 = very small            9 = small
65036 '    10 - 15 = normal          16 - 17 = big
65038 '    18 - 19 = very big
65040 '
65042 poke contrl    , 107
65044 poke contrl + 2, 0
65046 poke contrl + 6, 1
65048 poke intin, SIZE
65050 vdisys
65052 return

Try this once:

5   ' merge "TEXTSIZE.bas"
6   ' merge "TEXTOUTPUT.bas"
7   '
10  fullw 2: clearw 2
20  data 8,9,10,16,18,20
30  for a = 1 to 6
40  read SIZE
50  gosub TEXTSIZE
60  xpos = 220: ypos = 80 + a * 30: TEXT$ = "ST NEWS"
70  gosub TEXTOUTPUT
80  next a
90  SIZE =15: gosub TEXTSIZE
100 waiting = inp(2)
110 end

TEXTOUTPUT : 

These  routine  gives  a  string on  scale  on  the  monitor.  The 
coordinates  of  the beginning are XPOS  and  YPOS.  These  begin-
coordinates are free to use.

The syntax is:
                   XPOS = ......
                   YPOS = ......
                   TEXT$= "............"
                   gosub TEXTOUTPUT

The subroutine is:

65060 TEXTOUTPUT:
65062 ' ----->   TEXT$ ; XPOS ; YPOS
65064 '         text on scale
65066 for i = 0 to len(TEXT$) - 1
65068 poke intin + i * 2, asc(mid$(TEXT$, i + 1, 1))
65070 next i
65072 poke intin + i * 2, 0
65074 poke contrl    , 8
65076 poke contrl + 2, 1
65078 poke contrl + 6, len(TEXT$) + 1
65080 poke ptsin    , XPOS + 1
65082 poke ptsin + 2, YPOS + 38
65084 vdisys
65086 return
TEXT ANGLE :

An  other  option  is  to show the  text  in  a  different  angle. 
Unfortunate this is only possible in steps of 90 degrees.

The syntax is:
               ANGLE = ......   (=  0 ; 900 ; 1800 ; 2700 ) 
               gosub TEXTANGLE

The subroutine is:

65100 TEXTANGLE:
65102 ' ----->  ANGLE (= 0 ; 900 ; 1800 ; 2700 )
65104 '
65106 poke contrl    ,13
65108 poke contrl + 2,0
65110 poke contrl + 6,1
65112 poke intin, ANGLE
65114 vdisys
65116 return

Try this:

5   ' merge "TEXTANGLE.bas"
6   ' merge "TEXTOUTPUT.bas"
9   '
10  fullw 2: clearw 2
20  for ANGLE = 2700 to 0 step -900
30  gosub TEXTANGLE
40  XPOS = 300: YPOS = 150: TEXT$ = " ---> ATARI ST"
50  gosub TEXTOUTPUT
60  next
70  waiting = inp(2)
80  end

TEXTFORM :

This  function  defines  the  form of  the  text;  must  the  text 
overwrite  the  background or must a result to be  shown  after  a 
logical operation.
There are 4 forms of output on the screen:

           FORM:      MEANING:
          ------      -----------------
            1         Overwrite
            2         Mix
            3         XOR-operation
            4         Mix and Reverse

The syntax is:
               FORM = ..... (1 to 4)
               gosub TEXTFORM

Form 1 is the normal form. The text overwrites the background.
In form 2 the output is mixed with the existing  background.  This 
is  very useful for graphics,  because normally there is a  little 
white square behind a sign.
With form 3 there is an Exclusive OR-operation.  This means that a 
screenpoint is only set when one of the two bits has the value  1. 
The screenpoint is blank when both bits have the value 0 or 1.
In  form  4 the output is the same as in form  2,  except  for  an 
additional inversion.

The subroutine is:

65130 TEXTFORM:
65132 ' -----> FORM ( 1 = 4 )
65134 '
65138 poke contrl    ,32
65140 poke contrl + 2,0
65142 poke contrl + 6,1
65144 poke intin, FORM
65146 vdisys
65148 return

An example is:

5   ' merge "TEXTFORM.bas"
9   '
10  fullw 2: clearw 2
20  linef 100, 100, 400, 100
30  linef 100, 100, 100, 300
40  linef 100, 300, 400, 300
50  linef 200, 100, 200, 300
60  linef 400, 100, 400, 300
70  linef 300, 100, 300, 300
80  color 1, 1, 1, 2, 2: fill 110, 110
90  color 1, 1, 1, 6, 2: fill 210, 110
100 color 1, 1, 1, 8, 2: fill 310, 110
110 for FORM = 4 to 1 step -1
120 gosub TEXTFORM
130 gotoxy 9, 6 + FORM * 2
140 print chr$(14) chr$(15);
150 print " S T - C O M P U T E R  ";
160 print chr$(14) chr$(15)
170 next
180 waiting = inp(2)
190 end

GRAPHIC :

In the VDI almost any thinkable graphic functions are stored, that 
can draw geometric figures, like:

- circle                         - part of a circle
- rectangle                      - rectangle with round corners
- ellipse                        - part of an ellipse
- line                           - filled parts

Some  of these functions are available directly in  Basic,  others 
are only available through GEM-calls.
The most useful routines are described in the following part.

RECTANGLE :

Unfortunately,   there   is  no  instruction  in  Basic  to   draw 
rectangles.
With a VDI-routine we can draw a rectangle and even fill it with a 
chosen screen, faster then the FILL-instruction in Basic.
The routine needs only the two coordinates of the opposite angles, 
the sequence is not important.
The syntax is:
             XPOS1 = .....  : YPOS1 = .....
             XPOS2 = .....  : YPOS2 = .....
             gosub RECTANGLE

This  routine  (like all other GEM-routines) needs a  full  opened 
OUTPUT-field,  because  the  output of a VDI-instruction  is  done 
directly on the output-field, that is present at that time.
We have to recalculate the coordinates,  because the beginning  of 
the coordinates in Basic is different then in a output-field.
The deviation is in the X-direction 1 pixel and in the Y-direction 
38 pixels. The adjustment is done in lines 64012/64018.

The subroutine is:

64000 RECTANGLE:
64002 ' -----> XPOS1 ; YPOS1 ; XPOS2 ; YPOS2
64004 poke contrl    ,11
64006 poke contrl + 2,2
64008 poke contrl + 6,0
64010 poke contrl + 10,1
64012 poke ptsin    ,XPOS1 + 1
64014 poke ptsin + 2,YPOS1 + 38
64016 poke ptsin + 4,XPOS2 + 1
64018 poke ptsin + 6,YPOS2 + 38
64020 vdisys
64022 return
An example:

5   ' merge "RECTANGLE.bas"
9   '
10  fullw 2: clearw 2
20  color 1, 1, 1, 9, 2
30  XPOS1 = 100 : YPOS1 = 100 : XPOS2 = 300 : YPOS2 = 300
40  gosub RECTANGLE
50  color 1, 1, 1, 9, 3
60  XPOS1 = 150 : YPOS1 = 150 : XPOS2 = 230 : YPOS2 = 260
70  gosub RECTANGLE
80  waiting = inp(2)
90  end

RECTANGLE WITH ROUND ANGLES :

This  routine draws also a rectangle,  but now with round  angles. 
Like  the previous routine we have to give the coordinates of  two 
opposite angles. There are two possibilities:
to draw the rectangle and to draw and fill the rectangle.

The syntax is:  XPOS1 = ..... : YPOS1 = .....
                XPOS2 = ..... : YPOS2 = .....
                FILLING = .....
                gosub RECTANGLEROUND

The variable FILLING means:  FILLING = 0  only the rectangle
                             FILLING <>0  filled rectangle
The color of the filling has to be declared first with the  COLOR-
instruction. The subroutine is:

64030 RECTANGLEROUND:
64032 ' ----->  XPOS1 ; YPOS1 ; XPOS2 ; YPOS2
64034 '         FILLING  0 or <>0
64036 poke contrl    ,11
64038 poke contrl + 2,2
64040 poke contrl + 6,0
64042 if FILLING=0 then poke contrl+10,8 else poke contrl+10,9
64044 poke ptsin    ,XPOS1 + 1
64046 poke ptsin + 2,YPOS1 + 38
64048 poke ptsin + 4,XPOS1 + 1
64050 poke ptsin + 6,XPOS2 + 38

64052 vdisys
64054 return

An example:

5   ' merge "RECTANGLE.bas"
6   ' merge "RECTANGLEROUND.bas"
9   '
10  color 1, 1, 1, 5, 2
15  fullw 2: clearw 2
20  XPOS1 = 100 : YPOS1 = 100 : XPOS2 = 300 : YPOS2 = 300
30  gosub RECTANGLE
40  XPOS1 = 200 : YPOS1 =  80 : XPOS2 = 400 : YPOS2 = 200
50  FILLING = 1
60  color 1, 1, 1, 22, 2
70  gosub RECTANGLEROUND
80  waiting = inp(2)
90  end

LINES :

An other possibility of GEM-VDI is to change lines.  We can change 
the next things:
     - thickness of the line
     - pattern
     - form on the beginning and the end of the line.
You can use this routines also for ellipse and rectangle.

LINE-THICKNESS :

With this routine you can define the thickness of the lines, which 
have to be drawn on the screen.

The syntax is:
             THICK = .....
             gosub LINETHICKNESS

To  return to the standard thickness:  call the routine  with  the 
variable THICK = 1.
The routine is:

64220 LINETHICKNESS:
64222 ' ----> THICK
64224 poke contrl    ,16
64226 poke contrl + 2,1
64228 poke contrl + 6,0
64230 poke ptsin    ,THICK
64232 poke ptsin + 2,0
64234 vdisys
64236 return

Try this:

5   ' merge "LINETHICKNESS.bas"
9   '
10  fullw 2: clearw 2
20  for THICK = 37 to 1 step -4
30  gosub LINETHICKNESS
40  x = 20 + THICK * 15
50  linef x, 100, x, 300
60  next
70  waiting = inp(2)
80  end
LINE-PATTERN :

With this routine you can define in which form the line has to  be 
drawn, with points or with dashes.
There are available : 6 line-patterns and 1 free to define.
The pre-defined patterns and their values are:

  VALUE   BIT-PATTERN (16 Bits):
  -----   ----------------------
    1     1111111111111111
    2     1111111111110000
    3     1111000011100000
    4     1111111000111000
    5     1111111100000000
    6     1111000110011000
    7      free to define

The syntax is:
             PATTERN = .....
             gosub LINEPATTERN

To  return  to  the standard value,  call  the  routine  with  the 
variable PATTERN = 1.
The routine is:

64240 LINEPATTERN:
64242 ' ----->  PATTERN
64244 '         1 - 7
64246 poke contrl    ,15
64248 poke contrl + 2,0
64250 poke contrl + 6,1
64252 poke intin, PATTERN
64254 vdisys
64256 return

As usual, an example:

5   ' merge "LINEPATTERN.bas"
9   '
10  fullw 2: clearw 2
20  for PATTERN = 1 to 7
30  gosub LINEPATTERN
40  y = 60 + 20 * PATTERN
50  linef 50, y, 550, y
52  z = 20 + 70 * PATTERN
55  circle z, 250, 30
60  next
70  waiting = inp(2)
80  end

LINE-ENDS :

Normally  all lines are angular at the beginning and at  the  end, 
but  with  the next subroutine you can change this  in  two  other 
forms.  You  can define as well the form of the beginning  of  the 
line as the form at the end.
The values are:
  - round forms       2
  - arrow             1
  - angular           0

The syntax is:
              BEGINFORM = .....
              ENDFORM   = .....
              gosub LINESEND
The subroutine is:

64200 LINESEND:
64201 ' ----->   BEGINFORM  ; ENDFORM
64202 poke contrl    ,108
64204 poke contrl + 2,1
64206 poke contrl + 6,0
64208 poke intin    ,BEGINFORM
64210 poke intin + 2,ENDFORM
64212 vdisys
64214 return

An example is:

5   ' merge "LINETHICKNESS.bas"
6   ' merge "LINESEND.bas"
9   '
10  fullw 2: clearw 2
20  BEGINFORM = 2 : ENDFORM = 1: gosub LINESEND
30  for THICK = 21 to 1 step -4
40  gosub LINETHICKNESS
50  y = 20 + THICK * 12
60  linef 400,y ,100 , y
70  next
80  waiting = inp(2)
90  end

The next example shows you what you can do with these routines.
I  hope  that these routines are useful for  your  programming  in 
Basic and perhaps next time more routines in ST NEWS.

4   ' merge "RECTANGLEROUND.bas"
5   ' merge "LINETHICKNESS.bas"
6   ' merge "LINESENDS.bas"
7   ' merge "LINEPATTERN.bas"
8   ' merge "TEXTFORM.bas"
9   '
100 ' measuring a rectangle
110 fullw 2: clearw 2
120 thick = 3: gosub LINETHICKNESS
130 xpos1 = 100 : ypos1 = 200 : xpos2 = 300 : ypos2 = 240
140 gosub RECTANGLEROUND
150 thick = 1: gosub LINETHICKNESS
160 pattern = 4: gosub LINEPATTERN
170 linef  80, 220, 320, 220
180 pattern = 1: gosub LINEPATTERN
190 linef 100, 230, 100, 280
200 linef 300, 230, 300, 280
210 linef 295, 240, 340, 240
220 linef 295, 200, 340, 200
230 endform = 1 : beginform = 1: gosub LINESEND
240 linef 330, 200, 330, 240
250 linef 100, 270, 300, 270
255 endform = 0 : beginform = 0: gosub LINESEND
260 textkind = 4 :gosub TEXTMODE
270 gotoxy 11, 16: print "200 mm"
280 gotoxy 20, 12: print "40 mm"
290 textkind = 0: gosub TEXTMODE
300 waiting = inp(2)
310 end

This  program  is  also  added on the ST NEWS  disk  as  ST  BASIC 
program.

Disclaimer
The text of the articles is identical to the originals like they appeared in old ST NEWS issues. Please take into consideration that the author(s) was (were) a lot younger and less responsible back then. So bad jokes, bad English, youthful arrogance, insults, bravura, over-crediting and tastelessness should be taken with at least a grain of salt. Any contact and/or payment information, as well as deadlines/release dates of any kind should be regarded as outdated. Due to the fact that these pages are not actually contained in an Atari executable here, references to scroll texts, featured demo screens and hidden articles may also be irrelevant.