!  EDWIN Device Driver for HP 2686A Laserjet 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.                                                            #
!#                                                                          #
!############################################################################

!       Neil Bergmann; January, 1985

from Edwin include Device
from Edwin include Icodes
from Edwin include Consts
from Imp   include Lognames

const integer Max Styles = 15

const integer HBytes = 72, VBytes = 96
const integer HRes = (HBytes * 8-1), VRes = (VBytes * 8-1)

record format HLineFm(byte array Byte(0:HBytes - 1))
record format BitmapFm(record (HLineFm) array Line(0:VRes))
record format PointFm(integer x,y)
record format DataFm(record(PointFm) p, record(DataFm) name Next)

own record(BitmapFm) name Bitmap
own record(DataFm) name First Point == 0
own record(DataFm) name Next Point == 0

own integer SX = 0, SY = 0, Drawn = False, Colour = 1
own integer LX = 0, LY = 0, Max X = 0, Max Y = 0
own integer WLX = 0, WLY = 0, WHX = HRes, WHY = VRes
own integer Start X = 864, Start Y = 1260
own integer Shade Mode = Solid
own integer Colour Mode = Or Mode
own integer Res = 100
own integer i

own integer NPts = 0

own string(255) Temp = ""

const byte Escape = 27, FF = 12, CR = 13

own byte array Style Map(0:8 * Max Styles + 7) = -
     {outline} 0(8),
     {solid}   2_11111111(8),
     {horizontal}
            2_11111111,
            2_00000000,
            2_00000000,
            2_00000000,
            2_11111111,
            2_00000000,
            2_00000000,
            2_00000000,
     {vertical}
            2_10001000,
            2_10001000,
            2_10001000,
            2_10001000,
            2_10001000,
            2_10001000,
            2_10001000,
            2_10001000,
      {/diagonal}
            2_00010001,
            2_00100010,
            2_01000100,
            2_10001000,
            2_00010001,
            2_00100010,
            2_01000100,
            2_10001000,
      {¬diagonal}
            2_10001000,
            2_01000100,
            2_00100010,
            2_00010001,
            2_10001000,
            2_01000100,
            2_00100010,
            2_00010001,
      {cross hatch}
            2_10001000,
            2_01010100,
            2_00100010,
            2_01010001,
            2_10001000,
            2_01000101,
            2_00100010,
            2_00010101,
      {grid hatch}
            2_11111111,
            2_10001000,
            2_10001000,
            2_10001000,
            2_11111111,
            2_10001000,
            2_10001000,
            2_10001000,
      {Light Stipple}
            2_00000000,
            2_01000010,
            0(4),
            2_01000010,
            2_00000000,
      {checker board}
            2_11110000,
            2_11110000,
            2_11110000,
            2_11110000,
            2_00001111,
            2_00001111,
            2_00001111,
            2_00001111,
      {bricks}
            2_11111111,
            2_01000000,
            2_01000000,
            2_01000000,
            2_11111111,
            2_00000010,
            2_00000010,
            2_00000010,
      {lime}
            2_11000011,
            2_10000001,
            0(4),
            2_10000001,
            2_11000011,
      {brown}
            2_10011001(8),
      {turquoise}
            2_11111111,0,
            2_11111111,0,
            2_11111111,0,
            2_11111111,0,
      {user defined styles 14-15 }
            0(16)
       
routine Esc(string(255) S)
   integer I
   TTPut(Escape)
   TTPut(Charno(s,i)) for i = 1, 1, Length(s)
end

routine Raster Resolution(integer i)
   Esc("*t".ItoS(i,0)."R")
end

routine Start Raster Graphics
   Esc("&a".ItoS(Start X,0)."H")
   Esc("&a".ItoS(Start Y,0)."V")
   Esc("*r1A")
end

routine Transfer Raster Graphics(integer i)

   routine Dummy Newline
      TTPut(CR)
      TTPut(NL)
      Esc("&a-1R")
   end
   Dummy Newline
   Esc("*b".ItoS(i,0)."W")
end

routine End Raster Graphics
   Esc("*rB")
end

routine Check(integer X,Y)
   if X > Max X then Max X = X
   if Y > Max Y then Max Y = Y
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 short array XCode(1:16) = 0,1,1,1,1,1,0,1,0,-1,-1,-1,-1,-1,0,-1
   const short array YCode(1:16) = 1,1,0,1,0,-1,-1,-1,-1,-1,0,-1,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 Mark
      ! make mark in line buffer - represented as a linear bit string
      byte integer name B
      byte Bit
      B == Bitmap_Line(SY)_Byte(SX//8)
      Bit = 16_80 >> (SX&7)
      B = B ! Bit
      if Colour = 0 then B = B !! Bit
      Check(SX,SY)
   end

   Drawn = True
   Mark and return if SX = TX and SY = TY

   if SX < WLX then SX = WLX
   if SY < WLY then SY = WLY
   if TX > WHX then TX = WHX
   if TY > WHY then TY = WLY

   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
          SX = SX + X
          SY = SY + Y
      else
          E = E + T
          F = F - 1
          SX = SX + XMove
          SY = SY + YMove
      finish
      exit if F <= 0
   repeat
   Mark
end

routine Clrbitmap
   Bitmap = 0
   Drawn = False
   Max X = 0
   Max Y = 0
end

routine Outpage
   record(HLineFm) name Thisline
   integer X, Y, Right
   Raster Resolution(Res)
   Start Raster Graphics
   for Y = WHY, -1, 0 cycle
      Thisline == Bitmap_Line(Y)
      Right = Max X//8
      Right = Right - 1 while Right > 1 and Thisline_Byte(Right) = 0
      Transfer Raster Graphics(1 + Right)
      TTPut(Thisline_Byte(X)) for X = 0, 1, Right
   repeat
   End Raster Graphics
   TTPut(CR)
   TTPut(FF)
   TTPut(NL)
   Flush Output
   Clrbitmap
end

routine Draw Box(integer LX, LY, UX, UY)
   integer SSX, SSY, X, Y, Highbyte, Lowbyte
   byte B, BB
   byte name Thisbyte
   record(HLineFm) name Thisline

   routine Test(integer name Low, High)
      integer i
      if Low > High start
         i = Low
         Low = High
         High = i
      finish
   end

   Test(LX,UX)
   Test(LY,UY)
   LX = LX + 1
   return if UX <= LX {%or UY = LY
   UX = UX - 1
   UY = UY - 1 if UY # LY
   return if LX > WHX or LY > WHY or UX < WLX or UY < WLY
   if LX < WLX then LX = WLX
   if LY < WLY then LY = WLY
   if UX > WHX then UX = WHX
   if UY > WHY then UY = WHY
   Drawn = True
   Check(UX,UY)
      
   { This is a solid box, outline boxes are filtered out by EDWIN before driver }
   Lowbyte = LX//8
   Highbyte = UX//8
   for Y = LY, 1, UY cycle
      Thisline == Bitmap_Line(Y)
      for X = Lowbyte, 1, Highbyte cycle
         Thisbyte == Thisline_Byte(X)
         B = 2_11111111
         BB = B
         if X = Lowbyte then B = B>>(LX&7)
         if X = Highbyte then B = (B<<(7 - (UX&7)))&2_11111111
         if Colour Mode = Replace Mode then BB = BB!!B
         B = Style Map((Y&2_111)!(Shade Mode<<3))&B
         Thisbyte = (Thisbyte&BB)!B
      repeat
   repeat
end
        
include "polyfill.hpl"

routine Draw Polygon
   integer i
   record(DataFm) name pp
   record(PointFm) array Pts(1:NPts + 1)
   pp == First Point
   for i = 1, 1, NPts cycle
      Pts(i)_x = pp_p_x 
      Pts(i)_y = pp_p_y 
      if i = 1 start
         SX = pp_p_x
         SY = pp_p_y
      else
         Draw Line(pp_p_x, pp_p_y)
      finish
      pp == pp_Next
   repeat
   Pts(NPts + 1) = Pts(1)
   Draw Line(Pts(1)_x, Pts(1)_y)
   Polyfill(NPts + 1,Pts)
   NPts = 0
end

routine Append(integer X, Y)
   if NPts = 0 start
      First Point_p_x = X
      First Point_p_y = Y
      Next Point == First Point
      NPts = 1
   finish
   return if X = SX and Y = SY
   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
   NPts = NPts + 1
   SX = X
   SY = Y
end

routine Initialise
   First Point == new(Next Point)
   First Point_Next == nil
   Bitmap == new(Bitmap)
   Clrbitmap
   Dev Data_Name = "HP 2686A Laserjet Printer"
   Dev Data_Type = 2686
   Dev Data_ARF = 100
   Dev Data_DVX = HRes
   Dev Data_DVY = VRes
   Dev Data_MVX = HRes
   Dev Data_MVY = VRes
   Dev Data_Num Char Sizes = 255
   Dev Data_Units Per CM = Res/2.54
   if Viewing = 0 start
      Temp = "EDWIN_".ItoS(Dev Data_Type,0)
      if Translate(Temp) # Temp and Viewing = 0 start
         Set Device(Temp)
      finish
      TTMode(1)
   finish
end

external routine dd2686 alias "EDWIN___Z" (integer Com, X, Y)
   switch Command(0:Max Com)
   switch Att(0:Att Maximum)

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

   Draw Polygon if NPts # 0 and (Com = 10 or Com < 5)

   -> Command(Com)

   Command(Dev Initialise): 
     if X = 2686300 start
         Res = 300
     finish else if X = 2686150 start
         Res = 150
     else
         Res = 100
     finish
     Initialise
     return

   Command(Dev Terminate):
     Outpage if Drawn = True
     dispose(Bitmap)
     return

   Command(Dev Update):
     return

   Command(Dev Newframe):
     Outpage if Drawn = True
     return

   Command(Dev Move):
     SX = X
     SY = Y
     return

   Command(Dev Line):
     if Shade Mode = 0 start
        Draw Line(X,Y)
     else
        Append(X,Y)
     finish
     return

   Command(Dev Char):
     signal 14, 14

   Command(Dev Attribute):
     if 0 <= X <= Att Maximum then -> Att(X) else return
     Att(Att Colour): 
       Y = 1 if Y # 0
       Colour = Y
       return
     Att(Att Colour Mode):
       if Y = Replace Mode or Y = Or Mode then Colour Mode = Y
       return
     Att(Att Shade Mode):
       Y = Solid unless 0 <= Y <=15
       Shade Mode = Y
     Att(*): return

   Command(Dev Low WB): 
     WLX = X
     WLY = Y
     return

   Command(Dev High WB):
     WHX = X
     WHY = Y
    return

   Command(Dev Low Box):
     LX = X
     LY = Y
     return

   Command(Dev High Box):
     Swap(LX, X) if LX > X
     Swap(LY, Y) if LY > Y
     return if LX > WHX or X < WLX or LY > WHY or Y < WLY
     LX = WLX if LX < WLX
     LY = WLY if LY < WLY
     X = WHX if X > WHX
     Y = WHY if Y > WHY
     ! Box now clipped into the screen.
     Draw Box(LX, LY, X, Y)
     ! Now outline it
     return if Colour = 0
     SX = LX
     SY = LY
     Draw Line(X,LY)
     Draw Line(X,Y)
     Draw Line(LX,Y)
     Draw Line(LX,LY)
     return

   Command(*): 

end

!%external %routine Set Laser Position %alias "EDWIN_LASER_POSITION" (%integer X,Y)
!  Start X = X
!  Start Y = Y
!%end
!
!%external %routine Set Laser Resolution %alias "EDWIN_LASER_RESOLUTION" (%integer i)
!  %if i = 75 %or i = 100 %or i = 150 %or i = 300 %then Res = i
!%end

endoffile