! EDWIN driver for the BBC Macro (native mode)

from Edwin include Device
from Edwin include Icodes

record format Point fm (integer x, y)

const integer MAX IN BUF = 35

own integer BBC MODE = 2
! Mode 0 = 640 x 256  @  2 cols
! Mode 1 = 320 x 256  @  4 cols
! Mode 2 = 160 x 256  @ 16 cols

! Screen information
own integer SX = 0
own integer SY = 0
own integer XL = 0
own integer XR = 1279;     !Right hand side of device window
own integer YB = 0
own integer YT = 1023
own integer VIS = 0;       !0 if CVP inside VW
own integer OMODE = 0    { Overwrite mode 
own integer CCOL = 7     { White as Current Colour

routine SWAP (integer name  A, B)
   integer C
   C = A;   A = B;   B = C
end

routine COORDS (integer X, Y)
   TTPUT (X&255)
   TTPUT ((X>>8)&255)
   TTPUT (Y&255)
   TTPUT ((Y>>8)&255)
end

routine PLOT (integer COM, X, Y)
   TTPUT (25)
   TTPUT (COM)
   COORDS (X, Y)
end

routine DO COLOUR
   TTPUT (18)
   TTPUT (OMODE)
   CCol = 1 if BBC Mode = 0 and CCol > 1
   TTPUT (CCOL)
end

external routine Set Mode alias "EDWIN_BBC_MODE" (integer MODE)
   BBC MODE = MODE & 7
end

external routine BBC alias "EDWIN___B" (integer COM, X, Y)
   const integer array COLMAP (0:7) = 0   { black }   ,
                                         7   { white }   ,
                                         4   { blue }    ,
                                         2   { green }   ,
                                         1   { red }     ,
                                         5   { magenta } ,
                                         3   { yellow }  ,
                                         6   { cyan }
   own integer WX, WY, Nlines = 0, Lmode=0
   record format Data Fm (record (point fm) p, record (Data Fm) name Next)
   own record (Data fm) name Point List == 0
   own record (Data fm) name Next point == 0
   switch SW (0:MAX COM)

   routine line (integer x1, y1, x2, y2)
      plot (4, x1, y1);   plot (5, x2, y2)
   end

   routine triangle (integer x1, y1, x2, y2, x3, y3)
      PLOT (84, x1, y1)
      PLOT (84, x2, y2)
      PLOT (85, x3, y3)
   end

   include "Polyfill.abc"

   routine draw lines
      record (Data fm) name PP
      record (point fm) array pts (1:nlines+1)
      integer i
      return if Point List == Nil
      if nlines <= 1 start
          Line (point list_p_x, point list_p_y,
                point list_p_x, point list_p_y)
      else if nlines = 2
          Line (point list_p_x, point list_p_y,
                point list_next_p_x, point list_next_p_y)
      else
          pp == point list
          for I = 1, 1, Nlines cycle
             pts(i) = pp_p
             pp == pp_next
          repeat
          nlines = nlines + 1
          pts(nlines) = pts(1)
          POLY fill (nlines, Pts)
      finish
      nlines = 0
   end

   routine FILL (integer xl, yb, xr, yt)
      SWAP (xl, xr) if xl > xr
      SWAP (yb, yt) if yb > yt
      xr = xr + 1 if xr = xl
      yt = yt + 1 if yt = yb
      TTPUT (24);   COORDS (xl, yb);      COORDS (xr, yt)
      TTPUT (18);   TTPUT (OMODE);   TTPUT (128 + CCOL)
      TTPUT (16)    { Clear }
      DO COLOUR
      TTPUT (26)
   end

   routine circle(integer x, y, r)
      integer d, e, s, da, db, dda, ddb, odb, odda, oddb
      e = 1
      s = 0
      while e<r cycle
         e = e<<1
         s = s+1
      repeat
      d = e>>1
      da = r<<s-d
      dda = r
      db = d
      ddb = 0
      cycle
         odda = dda
         oddb = ddb
         cycle
            odb = db
            db = db+da>>s
            da = da-odb>>s
            dda = da>>s
         repeat until odda#dda
         ddb = db>>s
         line(x-ddb,y+odda,x+ddb,y+odda)
         fill(x-odda,y+oddb,x+odda,y+ddb)
         fill(x-odda,y-oddb,x+odda,y-ddb)
         line(x-ddb,y-odda,x+ddb,y-odda)
      repeat until db>=da
   end

   draw lines if nlines # 0 and (com = 10 or COM < 5)
   -> SW(COM)

SW(0): ! Initialise
       ! Valid numbers are 16_BBC, 16_BBC0, 16_BBC1, 16_BBC2
       BBC MODE = X & 15
       BBC MODE = 0 unless 0<=BBC MODE<=2
       Point List == New (point list)
       point List_next == Nil
       DEV DATA_NAME = "a BBC Micro"
       DEV DATA_DVX = 1279
       DEV DATA_DVY = 1023
       DEV DATA_MVX = 1279
       DEV DATA_MVY = 1023
       DEV DATA_MAX COLOUR = 7
       TTPUT (22);    TTPUT (BBC MODE)
       CCOL = 7
       OMODE = 0
       LMODE = 0
       DO COLOUR
       return

SW(1): ! Terminate
       TTPUT (22)
       TTPUT (3)
       FLUSH OUTPUT
       return

SW(2): ! Update
       FLUSH OUTPUT
       return

SW(3): ! Newframe
       TTPUT (22);   TTPUT (BBC MODE)
       return

SW(4): ! Move
       PLOT (COM, X, Y)
       SX = X;   SY = Y
       return

SW(5): ! Line
       if Lmode >= 0 start
           PLOT (COM+LMODE, X, Y)
       else
           if Nlines = 0 start
               point list_p_x = sx;   point list_p_y = sy
               Next point == point list
               Nlines = 1
           finish
           return if x=sx and y=sy
           Nlines = Nlines + 1
           if Next point_next == Nil start
               Next point_next == New (Next point)
               Next point      == Next point_next
               Next point_next == Nil
           else
               Next point == next point_next
           finish
           next point_p_x = x;   next point_p_y = y
       finish
       SX = X;   SY = Y
       return

SW(6): ! Char
       ! Move to the bottom of the character by adding 32 to Y
       plot (4, sx, sy+32)
       ttput (5);   ttput (x);   ttput(4)
       sx = sx + 16
       plot (4, sx, sy)
       return

SW(7): ! Attribute
       if x=att colour start
           if 0<=Y<=7 start
               CCOL = COL MAP (Y)
           else
               CCOL = 7
           finish
           DO COLOUR
       finish else if x=att line style start
           if y=1 start
               LMODE = 16
           else
               LMODE = 0
           finish
       finish else if x=att colour mode start
           ! y=0 => Replace
           ! y=1 => Or    { EDWIN Uses 2 }
           ! y=2 => And   { EDWIN Uses 1 }
           ! y=3 => Xor
           ! y=4 => Invert
           if 0<=y<=4 start
               if y=1 or y=2 start
                   y = y !! 3  { swap 1 & 2 }
               finish
               OMODE = y
           else
               OMODE = 0
           finish
           DO COLOUR
       finish
       return

SW(8): ! Lower window bounds
       XL = X;   YB = Y
       return

SW(9): ! Upper window bounds
       XR = X;   YT = Y
       return

SW(10): ! Line modes
        if X=2 start { Point plot only }
            LMODE = 64
        else if X=3
            LMODE = -1
        else
            LMODE = 0
        finish
        return

SW(11): ! Overwrite mode (old entry point)
        Y = X;        X = att colour mode;        -> sw(7)

SW(12): ! Remember lower box bounds
        WX = X;   WY = Y
        return

SW(13): ! Upper box bounds & do the box
        SWAP (WX, X) if WX > X
        SWAP (WY, Y) if WY > Y
        return if WX > XR or X < XL or WY > YT or Y < YB
        WX = XL if WX < XL
        WY = YB if WY < YB
        X = XR if X > XR
        Y = YT if Y > YT
        ! Box now clipped into the screen.
        Fill (wx, wy, x, y)
        return

SW(14): ! Circle
        circle (sx, sy, x)
        return

SW(15): ! Area fill
         triangle (integer (y),    integer (y+4),
                   integer (y+8),  integer (y+12),
                   integer (y+16), integer (y+20))
         if x=4 start
             triangle (integer (y+16), integer (y+20),
                       integer (y+24), integer (y+28),
                       integer (y),    integer (y+4))
         finish
!          %for com = 1, 1, x*2 %cycle
!               write (integer(y), 1)
!               y = y + 4
!          %repeat
!          newline

SW(*):
end

!**************************************************************************
! The above bit is host independent, the following is for networked hosts,
! using the BBC as a terminal, and then follows the code for using the BBC
! when a 32016 processor is connected.
!
!**************************************************************************
!
! REMOTE HOST SPECS:
external routine Sample alias "EDWIN___B_SAM" (integer name i,x,y)
   signal 14, 8
end

external routine Cursor alias "EDWIN___B_REQ" ( integername Char, X, Y )
   signal 14, 8
end
end of file
!**************************************************************************
! 
! 32016 SPECS:

constant integer tkbyte = 6

routine osbyte  {Call OB2 With R} ( integer Which, integer name X, Y )
   * MovD _ Which, 1
   * MovD _ 0(X),  2
   * MovD _ 0(Y),  3

   * Svc  _ #TK Byte

   * MovZBD _ 2, 0(X)
   * MovZBD _ 3, 0(Y)
end

own integer char = 0
!
! >> Try <<
!
! Try and extract a character from the given buffer
!
predicate Try ( integer Buff )
   integer z
   ! zero for the keyboard
   * MovD   _ # 16_91, 1
   * MovD   _ Buff,    2
{H}* MovQD  _ #0,      3
   * SVC    _ # TK BYTE
!H!* BCS    _ No
   * MOVZBD _ 3, z
   char = z
{H}false if Char = 0
   Char = Char&127 if Buff # 0
   true
end

external routine Sample alias "EDWIN___B_SAM" (integer name i,x,y)

   integer add on = 1
   routine get cursor pos(integer name button,x,y)
      integer lr, ud

      integer function get channel(integer channel,
                                     integer name button)
         integer x, y = 0

         osbyte(16_11,channel,y)             ;! force conversion
         y = 0
         cycle
            x = 0
            osbyte(16_80,x,y)
            button = x if x # 0             ; ! record button press
         repeat until y # 0                ;  ! a conversion has been completed
         if button & 2 # 0 start           ;  ! big fat button pressed
            cycle
               x = 0
               osbyte(16_80,x,y)
            repeat until x = 0
         finish
         osbyte(16_80,channel,y)             ;! get the value from the ADC
         result = y       ; ! ((y & 255) << 8) + channel
      end

      integer function do it(integer x,num)
         if num < 40 then result = x - add on
         result = x + add on if num > 130
         result = x
      end

      lr = get channel(1,button)
      ud = get channel(2,button)
      if button & 1 = 1 start
         add on = 2
         button = button !! 1   ;! get rid off the one without disturbing
                                ;! anything else
      else
         add on = 30
      finish
      !
      ! work out what the numbers should do the x and y
      !
      x = do it(x,(¬lr & 255))
      y = do it(y,ud)
   end

   routine set up adc
      integer x = 2,y = 0

      osbyte(16_10,x,y)  ;! select two channels
   end

   set up adc
   get cursor pos(i,x,y)
   if try(0) then i = char
end

own integer joy stick = 0

external routine joystick present alias "EDWIN_BBC_JOYSTICK" ( integer joy)
   joy stick = joy if 0 <= joy <= 1
end

external routine Cursor alias "EDWIN___B_REQ" ( integername Char, X, Y )
   const byte array X Inc {offset by 1} ( 16_88: 16_8B ) = 0, 2, 1, 1
   const byte array Y Inc {offset by 1} ( 16_88: 16_8B ) = 1, 1, 0, 2
   integer Scaler
   integer new x, new y

   routine XOR Cursor
      const short array X Arm ( 1: 4 ) = -30, 30,   0,   0
      const short array Y Arm ( 1: 4 ) =   0,  0, -30,  30
      integer I
      for I = 1, 1, 4 cycle
         Plot(4,X,Y)
         Plot(1,X Arm(I),Y Arm(I))
      repeat
      Flush Output
   end

   X = SX;   Y = SY
   BBC (4, SX, SY)
   Flush OUTPUT
   TTPUT(18) ; TTPUT(3) ; TTPUT(7) { Set temporary colour }
   Xor Cursor
   if joy stick = 1 start
      new x = x ; new y = y
   finish
   cycle
      if joystick = 1 start
         char = 0
         cursor(char,newx,newy)
         !
         ! should do some form of polling the keyboard for input as well
         !
!         %if new x # x %or new y # y %start
            Xor Cursor
            new x = rem(new x + 1280,1280) ; new y = rem(new y + 1032,1032)
            x = new x  ; y = new y
            Xor Cursor
!         %finish
      finish
      if (joystick = 1 and char # 0) or joystick = 0 start
         ! if the joystick is being used, and either the second button
         ! has been pressed or there is a character in the keyboard buffer,
         ! or otherwise, the joystick is not being used, then START!
         Scaler = 2
         CHAR = TTGET if joystick = 0
         exit if Char <= 127
         if 16_98+4 <= Char <= 16_9B+4 then Char = Char-4
         if 16_98 <= Char <= 16_9B start
            Scaler = 15 ; Char = Char-16
         finish
         if 16_88+4 <= Char <= 16_8B+4 then Char = Char-4
         if 16_88 <= Char <= 16_8B start
            Xor Cursor
            X = X + (X Inc(Char) - 1)*Scaler
            Y = Y + (Y Inc(Char) - 1)*Scaler
            x = rem(x + 1280,1280) ; y = rem(y + 1032,1032)
            if joystick = 1 start
               new x = x
               new y = y
            finish
            Xor Cursor
         finish
      finish
   repeat
   Xor Cursor
   DO COLOUR
   SX =X ; SY = Y
end

end of file