! EDWIN driver for the PRINTRONIX 300 Matrix printer

!############################################################################
!#                                                                          #
!#  This is a module from the EDWIN Graphics Package, which was developed   #
!#  in the Department of Computer Science, at Edinburgh University, from    #
!#  1978 to the present day, release 5 of EDWIN in October 1984.            #
!#                                                                          #
!#  The principal author of the EDWIN Graphics Package was J Gordon Hughes, #
!#  while working for the Edinburgh University Computer Sceince Department. #
!#  Parts of EDWIN have been produced by many different people, too many    #
!#  too mention, working for different departments of Edinburgh and Leeds   #
!#  Universities.                                                           #
!#                                                                          #
!#  This module is regarded as being in the public domain, and the authors  #
!#  and accept no responsibility regarding the uses to which the software   #
!#  will be put.                                                            #
!#                                                                          #
!############################################################################

! JGH November 1980, revised for Heap & Dept. program standards May 83
! Note requires though if this is to be moved to a system other than -
! VMS, MOUSES or EMAS

from Edwin include Device
from Edwin include Icodes
!%from Imp %include Predef

external routine P300 alias "EDWIN___P" (integer COM, X, Y)
   own integer WX = 0, WY = 0
   switch SW(0:MAX COM)

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

const integer PLOT = 5;      ! To indicate that the line is a plot line.
const integer FF = 12;       ! Form Feed
! Nb - for MOUSES 664 x 780,  for VMS and EMAS 791 x 780
const integer DOTS WIDE = 791 , DOTS HIGH = 779
const integer LINE MAX = DOTS WIDE//8 + 1

record format LINEF (byte integer array X (0:LINE MAX))
!$IF EMAS $START
!%own %record (LINEF) %array PAGE (0:DOTS HIGH)
!$ELSE
record format PAGEF (record(LINEF) array A (0:DOTS HIGH))
own record (PAGEF) name PAGE
!$FINISH

own byte DRAWN = FALSE
own integer SX = 0, SY = 0
own integer XL = 0, XR = Dots Wide, YB = 0, YT = Dots High

routine            DRAW PAGE
   const integer LINE BUFF LEN = (DOTS WIDE+5)//6 + 4 + 2
   const integer LIM = LINE MAX // 3 * 3
   string (LINE BUFF LEN) LINE BUFF
   integer P, J, LB, I
   byte name B
   byte array name L
   ! 3-bit inversion table
   constbyteintegerarray  inverse(0:7) =
      2_000, 2_100, 2_010, 2_110,  2_001, 2_101, 2_011, 2_111
   !    0      1      2      3       4      5      6      7

   for I = DOTS HIGH, -1, 0  cycle
!$IF EMAS $START
!       L == PAGE(I)_X
!$ELSE
        L == PAGE_A(I)_X
!$FINISH
        LB = ADDR (LINE BUFF)
        for J = ADDR(L(0)), 3, ADDR(L(LIM)) cycle
             P = (((BYTE INTEGER(J)<< 8) ! BYTE INTEGER(J+1)) << 8) ! BYTE INTEGER (J+2)
             BYTE INTEGER (LB + 4) = P&63;   P = P >> 6
             BYTE INTEGER (LB + 3) = P&63;   P = P >> 6
             BYTE INTEGER (LB + 2) = P&63;   P = P >> 6
             BYTE INTEGER (LB + 1) = P&63
             LB = LB + 4
        repeat
        LENGTH(LINE BUFF) = LB - ADDR(LINE BUFF)
        if LIM#LINE MAX start
            P = 0
            for J = LIM+1, 1, LINE MAX cycle
                 P = (P<<8)!L(J)
            repeat
            P = P << (8*(3-(LINE MAX - LIM)))
            for J = 18, -6, 0 cycle
                 LINE BUFF = LINE BUFF.TO STRING((P>>J)&63)
            repeat
        finish
        ! Strip trailing spaces (represented by binary zero)
        B == LENGTH(LINE BUFF)
        B = B-1 while B>0 and CHARNO(LINE BUFF, B)=0

        ! Add various bits and characters required by Printronix printer
        for j = addr(line buff)+1,1,lb cycle
           p = byte integer(j)
           byte integer(j) = inverse(p&7)<<3 ! inverse(p>>3) ! 64
        repeat
        TTPUT (CHARNO(LINE BUFF,J)) for J = 1, 1, LENGTH(LINE BUFF)
        TTPUT (PLOT);   TTPUT (NL)
        FLUSH OUTPUT
   repeat
   DRAWN = FALSE
end

routine DRAW LINE (integer TX,TY)
   ! This is algorithm 162 in the Collected Algorithms from CACM.
   ! It computes the code string required to move the pen of a
   ! digital incremental X-Y plotter from an initial point (SX,SY) to
   ! a terminal point (TX,TY) by the "best" approximation to the
   ! straight line between the points. The permitted elemental pen
   ! movement is to an adjacent point in a plane Cartesian point latice,
   ! diagonal moves permitted.

   integer A,B,D,E,F,T,I,XMOVE,YMOVE,X,Y
   const byte integer array XCODE(1:16) = 4,0,0,0,0,0,4,0,4,5,5,5,5,5,4,5
   const byte integer array YCODE(1:16) = 1,1,0,1,0,2,2,2,2,2,0,2,0,1,1,1
   ! PY,PX+PY,PX,PX+PY,PX,PX+NY,NY,PX+NY,NY,NY+NX,NX,NX+NY,NX,NX+PY,PY,NX+PY

   routine MOVE (integer X, Y)
      ! Move incrementaly over the screen.
      SX = SX + 1 if X=0
      SX = SX - 1 if X=5
      SY = SY + 1 if Y=1
      SY = SY - 1 if Y=2
   end

   routine MARK
      ! make mark in line buffer - represented as a linear bit string
      byte integer name B
!$IF EMAS $START
!      B == PAGE(SY)_X(SX>>3)
!$ELSE
      b == page_a(sy)_x(sx>>3)
!$FINISH
A label to avert a compiler bug:
      b = b ! (16_80 >> (sx&7) )
   end

   MARK and return if SX=TX and SY=TY

   A = TX - SX
   B = TY - SY
   D = A + B
   T = B - A

   I = 0
   if B>=0 then I=2
   if D>=0 then I=I+2
   if T>=0 then I=I+2
   if A>=0 then I=8-I else I=I+10

   A =  -A if A<0
   B =  -B if B<0
   F = A + B
   D = B - A
   if D>=0 then T=A and D=-D else T= B
   E = 0

   XMOVE = XCODE (I-1)
   YMOVE = YCODE (I-1)
   X = XCODE (I)
   Y = YCODE (I)
   cycle
      A = D + E
      B = T + E + A
      MARK
      if B>=0 start
          E = A
          F = F - 2
          MOVE (X, Y)
      finish else start
          E = E + T
          F = F - 1
          MOVE (XMOVE,YMOVE)
      finish
      exit if F<=0
   repeat
   MARK
end

   routine ZERO PAGE
      integer I
!$IF EMAS $START
!     PAGE (I) = 0 %for I = 0, 1, DOTS HIGH-1
!$ELSE
      PAGE = 0
!$FINISH
      SX = 0
      SY = 0
   end

   -> SW (COM)

SW(0): ! Initialise
       DEV DATA_NAME = "a Printronix printer"
       DEV DATA_DVX = 791
       DEV DATA_DVY = 779
       DEV DATA_MVX = 791
       DEV DATA_MVY = 779
       DEV DATA_ARF = 120
       if VIEWING = 0 start
           VIEWING = NON TERMINAL DEFAULT
!$IF EMAS $START
!          OPEN OUTPUT (VIEWING, "LP#LIS")
!       %finish
!$ELSE
           OPEN OUTPUT (VIEWING, "LP.LIS")
       finish
       PAGE == NEW (PAGE)
!$FINISH
!$IF EMAS OR MOUSES $START
!      TTPUT (FF)   { For machines with banners }
!$FINISH
       ZERO PAGE
       DRAWN = FALSE
       return

SW(1): ! Terminate
       DRAW PAGE if DRAWN = TRUE
!$UNLESS EMAS $START
       DISPOSE (PAGE)
!$FINISH
       return

SW(2): ! Update
       return

SW(3): ! Newframe
       DRAW PAGE if DRAWN = TRUE
       ZERO PAGE
       DRAWN = TRUE
       return

SW(4): ! Move
       SX = X
       SY = Y
       return

SW(5): ! Line
       DRAW LINE (X,Y)
       DRAWN = TRUE
       return

SW(6): ! Character
       signal 14, 14  { to get it done as a software character }

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

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

SW(10): ! ??
        return

SW(11): ! Was overwrite mode
        return

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

SW(13): ! Upper box bounds
        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.
        for COM = Y, -1, WY cycle
             SX = WX;   SY = COM;   Draw line (X, SY)
        repeat
        return

SW(*): ! Ignore all other commands
end

end of file