! EDWIN driver for the CHARLES (Minter) Colour Graphics terminal

%external %routine %spec TTMODE (%integer I)
%external %routine %spec TTPUT (%integer CH)
%external %integer %fn %spec TTREAD
%external %routine %spec FLUSH OUTPUT
%external %integer %spec DEVICE
%external %integer %fn %spec INSTREAM

%const %integer CHARLES=2

! Control characters
%const %integer ETX =  3
%const %integer ESC = 27
%const %integer CR  = 13
%const %byte %integer %array EDWIN COLS (0:15) = 0, 15, 4, 1, 2, 6, 8, 5, 3, 7, 9, 10, 11, 12, 13, 14

! Screen information
%own %integer COLOUR SELECT MODE = 0;   ! 0 => EDWIN colours, #0 => actual regs.
%own %integer CMODE = 0;    ! 0=>display, 1=> Console active
%own %integer RMODE = 0;    ! 0 text, 1 lines, 2 dots, 3 sheets
%own %integer MODE = -1;    ! 0 if alphamode
%own %integer SX = 0;       ! Current device position
%own %integer SY = 0
%own %integer XL = 0
%own %integer XR = 511;   !Right hand side of device window
%own %integer YB = 0
%own %integer YT = 511
%own %integer VIS = 0;     !0 if CVP inside VW
%own %byte %integer TCS = 5; ! True char size.
%own %byte %integer CCS = 1; ! Current colour selected.

%routine DON
   ! Display on
   TTPUT (ESC);   TTPUT ('*');   CMODE = 0
%end

%routine cbyte(%integer val, nbytes)
  ! Charles control byte protocol - 1 to 4 bytes, but only 2 for now.
  TTPUT(K'100' ! ((NBYTES-1)<<3) ! (VAL & 7))
  TTPUT(K'40' + (VAL>>3 & 63)) %if NBYTES>1
  TTPUT(0)
%end

%routine DBYTE (%integer VAL, NBYTES)
  ! Charles data byte protocol - 1 to 4 bytes
  %integer I
  TTPUT(K'40' ! (VAL & 31))
  VAL=VAL>>5
  TTPUT(K'40' + (VAL & 63)) %and VAL=VAL>>6 %for I = 1, 1, N BYTES - 1
  TTPUT(0)
%end

%routine POINT (%integer X, Y)
   DBYTE(X, 2);   DBYTE(Y, 2)
%end

%routine UPDATE
   %if CMODE=0 %start
       TTPUT (ETX) %if MODE=0
       CBYTE (7, 2) %if MODE=3
       TTPUT (13)
       FLUSH OUTPUT
   %finish
   MODE = -1
   CMODE = 1
%end

%external %routine END MODE
   ! End to Text or Poly modes
   %return %if DEVICE#CHARLES
   TTPUT (ETX) %if MODE=0
   CBYTE (7, 2) %if MODE=3
   MODE = -1
%end

%external %routine END POLY SHEET
   %return %if DEVICE#CHARLES
   CBYTE (6, 2) %if MODE = 3
%end

%external %routine SET COLOUR MAP (%integer ADR, RED, BLUE, GREEN)
   ! red, blue, green combination for this address in color map

   %return %if DEVICE#CHARLES
   ADR = EDWIN COLS(ADR) %if COLOUR SELECT MODE = 0
   DON %if CMODE=1
   END MODE
   CBYTE (3, 2);! load colormap command
   DBYTE ((BLUE<<12) ! (GREEN<<8) ! (RED<<4) ! ADR, 3); ! 3 bytes of data
%end

%external %routine CHAS (%integer COM, X, Y)
   %switch SW(0:15)

   %routine PUT CHAR
      ! Put out a text character properly.
   
      %return %if VIS # 0
      DON %if CMODE=1
      %if MODE#0 %start
          CBYTE (K'43', 1); ! Move to start of text
          POINT (SX, SY)
          CBYTE (K'46', 1); ! Enter text mode
          MODE=0
      %finish
      TTPUT (X)
      SX = SX + TCS
      VIS = 1 %if SX>XR
   %end

   %routine DRAW LINE(%integer FX, FY, TX, TY, V)
      !Draw visible line from virtual coordinates (FX, FY) to (TX, TY).
      !But if V = 0 just move to (TX, TY).
      %const %integer %array CODE(0:4)= K'43', K'44', K'45', 5, 4
      %const %integer %array LC(0:4) = 1, 1, 1, 2, 2
      ! Command codes for TEXT, LINE, DOT, POLY, BOX modes respectivly.
   
      DON %if CMODE=1
      TTPUT (ETX) %if MODE=0; ! ETX to end text mode
      CBYTE (7, 2) %if MODE=3 %and RMODE#3
   
      %if V#0 %start
          %if MODE#RMODE %start
              CBYTE (K'43', 1) %and POINT (FX, FY) %if RMODE=1 %and MODE#1
              ! Above line fixes bug in Charles which causes move to be drawn.
              CBYTE (CODE(RMODE), LC(RMODE))
              POINT (FX, FY) %if  0 < RMODE < 4
          %finish
          %if MODE = 3 %start; ! Possible need to clip polygons
          %finish
          POINT (TX, TY)
          MODE = RMODE
      %finish %else MODE=-1
      SX=TX; SY=TY;   !Remember new position
   %end

   %routine CHANGE ATTRIBUTE
      %return %unless X=0 %or X=2; ! These are only two supported
      DON %if CMODE=1
      END MODE
      %if X=0 %start
          ! Change Colour
          CCS = Y
          Y = EDWIN COLS(Y) %if COLOUR SELECT MODE = 0
          CBYTE (K'20' ! Y, 2)
      %finish %else %start
          ! Change Character size
          %if Y<7 %then CBYTE(K'40', 2) %and TCS=5 %c
                  %else CBYTE(K'41', 2) %and TCS=10
      %finish
   %end

   %return %if DEVICE#CHARLES %or COM > 11
   -> SW(COM)

SW(0): ! Initialise
       TTMODE (1)
       DON
       COLOUR SELECT MODE = -1; ! This sets the true device registers
       SET COLOUR MAP (0, 0, 0, 0)
       SET COLOUR MAP (1, 0, 0, 10)
       SET COLOUR MAP (2, 10, 0, 0)
       SET COLOUR MAP (3, 6, 0, 6)
       SET COLOUR MAP (4, 0, 10, 0)
       SET COLOUR MAP (5, 0, 8, 6)
       SET COLOUR MAP (6, 5, 8, 0)
       SET COLOUR MAP (7, 3, 5, 5)
       SET COLOUR MAP (8, 14, 0, 14)
       SET COLOUR MAP (9, 0, 0, 15)
       SET COLOUR MAP (10, 15, 0, 0)
       SET COLOUR MAP (11, 10, 1, 10)
       SET COLOUR MAP (12, 3, 15, 3)
       SET COLOUR MAP (13, 6, 10, 12)
       SET COLOUR MAP (14, 12, 10, 6)
       SET COLOUR MAP (15, 15, 15, 15)
       COLOUR SELECT MODE = Y
       X=0; Y=0
       CHANGE ATTRIBUTE
       RMODE = 2; ! Gives invisable dot at the origin, to fix charles bug.
       DRAW LINE (0, 0, 0, 0, 1)
       X=0; Y=1
       CHANGE ATTRIBUTE; ! Colour to 1
       X=2; Y=6
       CHANGE ATTRIBUTE; ! Char size to small ones
       RMODE = 1       ; ! Line mode by default.
       %return

SW(1): !Terminate
       UPDATE
       TTMODE (0)
       %return

SW(2): ! Update
       UPDATE
       %return

SW(3): ! New frame
       DON %if CMODE=1
       END MODE
       CBYTE (1, 1)
       X = 0;   Y = CCS;      ! Restore colour.
       CHANGE ATTRIBUTE
       X = 2;   Y = TCS;      ! Restore character size
       CHANGE ATTRIBUTE
       SX = 0;   SY = 0;   MODE = -1;   VIS  =  0
       %return

SW(4): ! Move Abs
       VIS = 0
       %if MODE#3 %then DRAW LINE (SX, SY, X, Y, 0) %else DRAW LINE (SX, SY, X, Y,1)
       %return

SW(5): ! Line Abs
       VIS = 0
       DRAW LINE (SX, SY, X, Y, 1)
       %return

SW(6): ! Character
       PUT CHAR %if VIS=0
       %return

SW(7): ! Attribute  Change
       CHANGE ATTRIBUTE
       %return

SW(8): ! Set lower window settings
       XL = X;   YB = Y
       %return

SW(9): ! Set upper window bounds
       XR = X;   YT = Y
       %return

SW(10): ! Mode change
        END MODE
        RMODE = X %if 0<=X<=4
        %return

SW(11): ! Set Colour replacement mode
        DON %if CMODE=1
        END MODE
        Y = Y & 255
        X = X & 3
        %if X<3 %then CBYTE (X, 2) %else CBYTE (K'60' ! Y, 2)
        %return

SW(*):
%end

%external %routine C BOX (%integer WX, WY, BX, BY)
   ! Wee X & Y, then Big X & Y
   ! Draw a box using BOX protocol.
   %routine SWAP (%integer%name  A, B)
      %integer C
      C = A;   A = B;   B = C
   %end

   SWAP (WX, BX) %if WX > BX
   SWAP (WY, BY) %if WY > BY

   %return %if WX > XR %or BX < XL %or WY > YT %or BY < YB

   WX = XL %if WX < XL
   WY = YB %if WY < YB
   BX = XR %if BX > XR
   BY = YT %if BY > YT
   ! Box now clipped into the screen.
   DON %if CMODE = 1
   ENDMODE
   RMODE = 4
   CHAS (5, WX, WY)
   CHAS (5, BX, BY)
   RMODE = 1
%end


%routine GET CO (%integer %name X)
   %integer I, J
   
   read symbol(I)
   read symbol(J)
   X = (J&31) <<5 ! (I&31)
%end

%external %routine C BIT PAD POS (%integername X, Y)
   %integer E
   DON %if CMODE = 1
   END MODE
   CBYTE (12, 2)
   CBYTE (10, 2)
   UPDATE
   E = TTREAD %until E=ESC
   GET CO (X)
   GET CO (Y)
   Y = 453 - Y
   E = TTREAD %until E = CR
%end

%external %routine C CURSOR (%integer %name BUT, X, Y)
   %integer E,s

   DON %if CMODE = 1
   END MODE
   CBYTE (13, 2); ! Set the mouse position
   POINT (SX, SY)
   CBYTE (12, 2); ! Flush the Queue
   CBYTE (11, 2); ! Get the button change.
   UPDATE
   ! now get cursor back.
   BUT = TTREAD %until BUT=ESC
   s = in stream
   select input (0)
   GET CO (X)
   GET CO (Y)
   read symbol (E)
   read symbol (BUT)
   BUT = (BUT&31) <<5 ! (E&31)
   read symbol(E) %while E>=' '
   select input (s)
%end

%end %of %file
