      .8086

CODE  SEGMENT BYTE PUBLIC
      ASSUME CS:CODE

;*****************************************************************************
;
; GRAPHICS DRIVER FOR CGA 320x200 4 color mode
;
; Copyright 1986,1987,1988 Protel Technology Pty. Ltd.
;
; Written By  : N.M.Martin
; Last Change : 21-June-1988
;*****************************************************************************

INCLUDE TABLE.ASM
; This gets all jumps tables and external/global definitions

;*****************************************************************************
; The Driver name below mus remain in the same position and have the same    ;
; length between then quotes.                                                ;
;*****************************************************************************

GETDRIVERNAME:    DB  32,'CGA 4 COLOR 320x200             '
MaxX          Equ 320          ;Number of Pix in X Direction
MaxY          Equ 200          ;Number of Pix in Y Direction
StatusLine    Equ 23           ;Number of Y Pix Reserved For Status Line
MaxColors     Equ 3            ;Largest Color Number that the driver supports
MaxBackColors Equ 15           ;Largest Background Color the driver supports
MenuMem       Equ 32000        ;Memory to store a screen menu
MaxSets       Equ 3            ;Number of available color sets

INCLUDE GCOMMON.ASM
;Gets RAWPLOT
;     DRAW
;     FASTCHAR
;     FULLCHAR
;     _PLOTPOINT
;     _GETDRIVERTYPE
;     _BIGCOLORS
;     _BIGBACKCOLORS
;     _XBIG
;     _YBIG
;     _COLORSETS

;These routines are common for all graphics drivers

;*************************************************;
SetGraph Proc Near
; This routines sets up the graphics system for
; drawing. It Takes the color in SI and sets
; segment registers and inits the hardware.
;*************************************************;
      mov     ax,0B800h;
      mov     es,ax
SetGraph Endp

;*********************************************;
ResetGraph proc Near                          ;
; Resets the EGA hardware to state where an   ;
; exit from the program would be acceptable.  ;
; The Driver should always leave the hardware ;
; in such a state.                            ;
;*********************************************;
      ret
ResetGraph endp


;********************************************;
_READPIXEL Proc NEAR                         ;
; Return the color of the pixel at (Rpx,Rpy) ;
; X = Cx                                     ;
; Y = Dx                                     ;
; Return Ax = color                          ;
;********************************************;
Rpx	equ	[bp+6]
Rpy   	equ	[bp+4]
      push    bp
      mov     bp,sp
      mov     ax,0B800h;
      mov     es,ax

      mov     Dx,rpy                   ;y
      mov     Cx,rpx                   ;x

      mov     ax,80                    ; yoff := (y*80)
      mul     dx                       ;Result in ax
      Mov     bx,ax                    ;bx = yoffset now
                                       ;Low 3 bits of x give pix position
                                       ;up  7 bits of x give byte offset;
      mov     dx,cx                    ;cx = x and dx = x
      shr     dx,1                     ;dx is x coordinate;
      shr     dx,1
      shr     dx,1
      add     bx,dx                    ;bx = byte now
      and     cx,7                     ;3 bits give offset to use as count
      mov     dx,0080h;
      shr     dx,cl
      mov     ch,dl

      ;bx = offset
      ;ch = bit mask

      mov     ah,3

      mov     al,es:0[bx]              ;read byte

      push    ax
      pop     ax
      pop     bp
      ret     6
_READPIXEL endp



;*************************************;
_CLEARGRAPH proc NEAR                 ;
; Set all pixels on the screen to the ;
; background color.                   ;
;*************************************;
      mov      cx,0B800h
      mov      es,cx
      cld
      mov      cx,2000h
      mov      ax,0
      mov      di,0

      rep stosw
      ret
_CLEARGRAPH endp


;*********************************************
_TEXTMODE proc NEAR                          ;
; Places the graphics hardware into textmode ;
;*********************************************
      mov    ax,0003h
      int    10h
      ret
_TEXTMODE endp


;**********************************************;
_GRAPHMODE proc NEAR                           ;
; Places the graphics hardware into Graph Mode ;
;**********************************************;
      mov    ax,4
      int    10h
      ret
_GRAPHMODE endp

;*********************************************;
_SAVEMENU proc NEAR                           ;
; This routine saves the area of the top left ;
; hand of the screen used to store data under ;
; the pop-up menu.                            ;
; The area is 320 pixels horizontal and 200   ;
; pixels vertical                             ;
; StoreOfs and storeSeg point to an area of   ;
; memory where the screen data can be stored. ;
;*********************************************;
storeOfs equ [bp+6]
storeSeg equ [bp+8]


      push     ds
      push     bp
      mov      bp,sp

      mov     di,StoreOfs              ;BX = offset to store data
      mov     ax,StoreSeg
      mov     ds,ax                    ;DS = Seg to store data

      mov     ax,0b800h
      mov     es,ax

      mov     cx,2000h                 ;200 lines;
      mov     si,0                     ;where get byte from

SaveMenuL1:
      mov     ax,es:0[si]              ;read byte
      mov     ds:0[di],ax              ;store byte
      inc     di
      inc     di
      inc     si
      inc     si
      loop    SaveMenuL1

      pop     bp
      pop     ds
      ret     4
_SAVEMENU endp


;***********************************************;
_LOADMENU proc NEAR                             ;
; This routine retrives the stored screen data  ;
; and places in into the area of the top left   ;
; hand of the screen.                           ;
; The area is 320 pixels horizontal and 200     ;
; pixels vertical                               ;
; LoadOfs and LoadSeg point to the area in mem  ;
; where the data was stashed.                   ;
;***********************************************;
LoadOfs equ [bp+6]
LoadSeg equ [bp+8]

      push     ds
      push     bp
      mov      bp,sp

      mov     di,LoadOfs	       ;BX = offset to store data
      mov     ax,LoadSeg
      mov     ds,ax                    ;DS = Seg to store data
      mov     ax,0b800h
      mov     es,ax

      mov     cx,2000h                 ;200 lines;
      mov     si,0                     ;where get byte from

LoadMenuL1:
      mov     ax,ds:0[di]              ;get byte
      mov     es:0[si],ax              ;restore byte
      inc     di
      inc     di
      inc     si
      inc     si
      loop    LoadMenuL1

      pop     bp
      pop     ds
      ret     4
_LOADMENU endp

;********************************************
_VLINE proc NEAR                            ;
; Draws a vertical line between 2 points    ;
;(vlx,vly1) and (vlx,vly2)                  ;
;********************************************
vlx	equ	[bp+10]
vly1	equ	[bp+8]
vly2	equ	[bp+6]
vlcolor	equ	[bp+4]

      push     bp
      mov      bp,sp
      Call     SetGraph

      mov     cx,vlx                   ;cx = x
      not     cx                       ;3 = right not left
      mov     ax,vlcolor
      and     ax,3
      mov     dh,al                    ;dh = color

      mov     dl,03h                   ;dl := and mask
      and     cx,3                     ;2 bits give offset to use as count
      jz      Vno_shift
Vshift_loop:
      shl     dx,1
      shl     dx,1
      loop    Vshift_loop;
Vno_shift:
      mov     cx,vly2                  ;get y2 to dx
      mov     ax,vly1                  ;get y1 to ax
      sub     cx,ax                    ;count := y2 - y1 = cx
      jz      Vone_pix

      mov     bx,vly1                  ;bx = y1
      shr     bx,1                     ;remove lowest bit of y1
      mov     al,80;                   ;y is now only 7 bits
      mul     bl                       ;Result in ax = (y1 shr1) * 80
      mov     di,ax                    ;di = yoffset now

      mov     bx,vlx                   ;bx = x
      shr     bx,1
      shr     bx,1
      add     di,bx                    ;di = Start byte
      mov     ax,vly1                  ;ax = y1

      mov     si,vlcolor               ;si := color
      or      si,si
      js      Vxorlin

      not     dl                       ;For the and mask only 2 bits = 0
Vmain1:
      mov     bx,di
      test    ax,1                     ;if bit 1 = 1 then add 2000h
      jz      Vaddoffset1
      add     bx,2000h
Vaddoffset1:
      and     es:0[bx],dl
      or      es:0[bx],dh
      test    ax,1
      jz      Vaddoffset2
      add     di,80                    ;next line
Vaddoffset2:
      inc     ax
      loop    Vmain1
      jmp short    VFinish

Vxorlin:
      mov     bx,di
      test    ax,1                     ;if bit 1 = 1 then add 2000h
      jz      Vaddoffset3
      add     bx,2000h
Vaddoffset3:
      xor     es:0[bx],dl
      test    ax,1
      jz      Vaddoffset4
      add     di,80                    ;next line
Vaddoffset4:
      inc     ax
      loop    Vxorlin
      jmp short    VFinish

Vone_pix:
      mov     cx,vlx
      mov     dx,vly1
      mov     si,vlcolor
      call    point
Vfinish:
      pop     bp
      ret     8
_VLINE ENDP



;*****************************************
HPoint Proc Near
; Subroutine called by Hline.
; X = Ax
; Color in SI
;*****************************************
      Push    ax
      Push    bx
      push    cx
      push    dx

      mov     cx,ax                    ;up  8 bits of x give byte offset;
      shr     cx,1                     ;cx is x coordinate;
      shr     cx,1                     ;8 bits left so bx = first offset
      add     cx,di                    ;cx = byte now
      mov     bx,cx                    ;bx = byte now
      mov     cx,ax                    ;cx = x
      not     cx                       ;3 = right not left

      mov     ax,si                    ;al := color
      and     ax,3

      mov     dl,03h                   ;dl := and mask
      and     cx,3                     ;2 bits give offset to use as count
      jz      hpno_shift
hpshift_loop:
      shl     al,1
      shl     al,1
      shl     dl,1
      shl     dl,1
      loop    hpshift_loop;
HPno_shift:
      or       si,si
      js       hPxorit
      not      dl
      and      es:0[bx],dl             ;zero the 2 bits concerned
      or       es:0[bx],al             ;now set them to the color
      jmp short     HPcolorit
HPxorit:
      xor      es:0[bx],dl             ;invert the 2 bits concerned
HPcolorit:
      pop      dx
      pop      cx
      pop      bx
      pop      ax
      ret
HPoint ENDP


;*******************************************;
_HLINE proc NEAR                            ;
; Draws a horizontal line between 2 points  ;
;(hlx1,hly) and (hlx2,hly)                  ;
;*******************************************;
hlx1	equ	[bp+10]
hlx2	equ	[bp+8]
hly	equ	[bp+6]
hlcolor	equ	[bp+4]

; Keep Bit mask in BX

      push     bp
      mov      bp,sp
      Call     SetGraph
;First Check if Hline OutSide of 0..Maxy
        Mov     dx,hly
        or      dx,0
        js      Houtside
        cmp     dx,MaxY
        jnb     Houtside

        Mov     cx,hlx1
        cmp     cx,MaxX                  ;if x1 > MaxY then exit
        jnb     Houtside
        Mov     cx,hlx2                  ;if x2 < 0 then exit;
        or      cx,0
        js      Houtside
        Jmp     CoordsOK

HoutSide:
        jmp     hfinish

CoordsOK:

      mov      si,hlcolor
      and      si,8003H

      mov      ax,0
      test     si,1                    ;if 1 then 01010101
      jz       Hno_ones
      or       ax,05555h
Hno_ones:
      test     si,2                    ;if 2 then 10101010
      jz       Hno_twos
      or       ax,0AAAAh
Hno_twos:
      mov      bx,ax     ;save mask = 0;

      mov     dx,hly
      xor     di,di
      test    dx,1                     ;if bit 1 = 1 then add 2000h
      jz      Haddoffset
      mov     di,2000h
Haddoffset:
      shr     dx,1                     ;remove lowest bit of y
      mov     al,80;                   ;y is now only 7 bits
      mul     dl                       ;Result in ax
      add     di,ax                    ;di = yoffset now

      mov     cx,hlx2
      mov     dx,hlx1
      sub     cx,dx                    ;x2 := x2 - x1  < 10 then no byte fill
      jz      Hone_pix                 ;
      cmp     cx,10
      js      HSmallLine               ;jump if less than 10 pixels

      mov     ax,hlx2
Hagain1:
      call    HPoint                   ;going down pixel by pixel until
      test    ax,3                     ;we cross byte boundry
      jz      HDo_next1
      dec     ax
      jmp short    Hagain1

HDo_next1:
      dec     ax
      mov     hlx2,ax                  ;Save new x2 value

      mov     ax,hlx1                  ;Get x1
Hagain2:
      call    Hpoint                   ;go up pixel by pixel until
      inc     ax                       ;we cross byte boundary
      test    ax,3
      jnz     Hagain2

      shr     ax,1                     ;Go on with x1 as it is now
      shr     ax,1
      add     di,ax                    ;di = Start byte

      mov     cx,hlx2                  ;get x2
      shr     cx,1
      shr     cx,1
      sub     cx,ax                    ;fill(start,(X2 Shr 2)-(X1 Shr 2)+1);
      inc     cx                       ;Cx = byte count;

      or      si,si                    ;if color < 0 then xor the line
      js      Hxorlin
      mov     ax,bx                    ;get color mask back
      cld                              ;incrementing di
      rep  stosb
      jmp short    Hfinish

Hxorlin:
      mov     al,0ffh
      mov     bx,di
Hmain:
      xor      es:0[bx],al
      inc      bx
      loop     Hmain
      jmp short     Hfinish
HsmallLine:
      mov     ax,dx
HsmallLoop:                              ;ax = x1  cx = pixel count
      call    Hpoint
      inc     ax
      loop    HSmallLoop
      jmp short    Hfinish

Hone_pix:
      mov     cx,hlx1
      mov     dx,hly
      mov     si,hlcolor
      call    point

Hfinish:
      pop     bp
      ret     8
_HLINE ENDP


;******************************************;
_ARROWCURSOR proc NEAR                     ;
; Draws a cursor on the screen at location ;
; (acx,acy)                                ;
;******************************************;
acx   equ      [bp+6]
acy   equ      [bp+4]
      push     bp
      mov      bp,sp

      Call     SetGraph

      mov      si,0ffffh               ;15 is xor color

      mov     cx,acx	               ;get x
      mov     dx,acy		       ;get y

      mov      bx,1                    ;y := 0
      call     ArrowPoints

      inc      dx                      ;y := 1
      mov      bx,2
      call     ArrowPoints

      inc      dx                      ;y := 2
      mov      bx,3
      call     ArrowPoints

      inc      dx                      ;y := 3
      mov      bx,4
      call     ArrowPoints

      inc      dx                      ;y := 4
      mov      bx,5
      call     ArrowPoints

      inc      dx                      ;y := 5
      mov      bx,6
      call     ArrowPoints

      inc      dx                      ;y := 6
      mov      bx,7
      call     ArrowPoints

      inc      dx                      ;y := 7
      mov      bx,8
      call     ArrowPoints

      inc      dx                      ;y := 8
      mov      bx,9
      call     ArrowPoints

      inc      dx                      ;y := 9
      mov      bx,10
      call     ArrowPoints

      inc      dx                      ;y := 10
      mov      bx,11
      call     ArrowPoints

      inc      dx                      ;y := 11
      mov      bx,12
      call     ArrowPoints

      inc      dx                      ;y := 12
      mov      bx,6
      call     ArrowPoints

      inc      dx                      ;y := 13
      mov      bx,5
      call     ArrowPoints

      inc      dx                      ;y := 14
      mov      bx,4
      call     ArrowPoints

      inc      dx                      ;y := 15
      mov      bx,3
      call     ArrowPoints

      inc      dx                      ;y := 16
      mov      bx,2
      call     ArrowPoints

      inc      dx                      ;y := 17
      call     Point                   ;x := 0

      pop     bp
      ret     4
_ARROWCURSOR endp


;*****************************************
ArrowPoints Proc Near
; Sub_Routine for ArrowCursor
; X = cx
; Yoffset = Dx
; bx = count of x
;*****************************************
      Push    cx
Ploop:
      call    Point
      inc     cx       ;next x
      dec     bx
      jnz     Ploop
      pop     cx
      ret
ArrowPoints endp


;********************************************************;
_SETBACKGROUND Proc Near                                 ;
; Sets the current background color to BackColor         ;
; Procedure SetBackGround(BackColor,ColorSet : integer); ;
;********************************************************;
BackColor equ      [bp+6]
ColorSet  equ      [bp+4]
      push     bp
      mov      bp,sp
      mov      ah,0BH
      mov      bh,1
      mov      bl,ColorSet
      And      bl,1
      int      10H

      mov      ah,0BH
      mov      bh,0
      mov      bl,BackColor
      mov      cl,ColorSet
      Test     cl,2
      jz       DontAdd
      add      bl,16
DontAdd:
      int      10h
      pop      bp
      ret 4
_SETBACKGROUND endp


;*****************************************
_SETCOLORSET Proc Near
; Selects the Color set in Cset
;*****************************************
Cset equ [bp+4]
      ret 2
_SETCOLORSET endp


;*****************************************
Point Proc Near
; X = Cx
; Y = Dx
; Color in SI
;*****************************************
      or      cx,0
      js      PAoutside
      or      dx,0
      js      PAoutside
      cmp     dx,MaxY-StatusLine       ;if y bigger then no carry
      jnb     PAoutside                  ;Jump if carry not set
      cmp     cx,MaxX                  ;if x bigger then no carry
      jnb     PAoutside                  ;Jump if carry not set

      Push    cx
      Push    dx
      push    bx
      push    ax

      xor     bx,bx
      test    dx,1                     ;if bit 1 = 1 then add 2000h
      jz      PAaddoffset
      mov     bx,2000h
PAaddoffset:
      shr     dx,1                     ;remove lowest bit of y
      mov     al,80;                   ;y is now only 7 bits
      mul     dl                       ;Result in ax
      add     bx,ax                    ;bx = yoffset now
                                       ;Low 2 bits of x give pix position
                                       ;up  8 bits of x give byte offset;
      mov     dx,cx                    ;cx = x and dx = x
      shr     dx,1                     ;dx is x coordinate;
      shr     dx,1                     ;8 bits left so bx = first offset
      add     bx,dx                    ;bx = byte now
      mov     ax,si                    ;al := color
      and     ax,3

      mov     dl,03h                   ;dl := and mask
      not     cx                       ;3 = right not left
      and     cx,3                     ;2 bits give offset to use as count
      jz      PAno_shift
PAshift_loop:
      shl     al,1
      shl     al,1
      shl     dl,1
      shl     dl,1
      loop    PAshift_loop;
PAno_shift:
      or       si,si
      js       PAxorit
      not      dl
      and      es:0[bx],dl             ;zero the 2 bits concerned
      or       es:0[bx],al             ;now set them to the color
      jmp short PAcolorit
PAxorit:
      xor      es:0[bx],dl             ;invert the 2 bits concerned
PAcolorit:
      pop      ax
      pop      bx
      pop      dx
      pop      cx
PAoutside:
      ret
POINT  ENDP


;*****************************************
TextPoint Proc Near
; X = Cx
; Y = Dx
; Color in SI
;*****************************************
      or      cx,0
      js      TAoutside
      or      dx,0
      js      TAoutside
      cmp     dx,MaxY                  ;if y bigger than 189 then no carry
      jnb     TAoutside                ;Jump if carry not set
      cmp     cx,MaxX                  ;if x bigger than 319 then no carry
      jnb     TAoutside                ;Jump if carry not set

      Push    cx
      Push    dx
      push    bx
      push    ax

      mov     ax,0b800h;
      mov     es,ax

      xor     bx,bx
      test    dx,1                     ;if bit 1 = 1 then add 2000h
      jz      TAaddoffset
      mov     bx,2000h
TAaddoffset:
      shr     dx,1                     ;remove lowest bit of y
      mov     al,80;                   ;y is now only 7 bits
      mul     dl                       ;Result in ax
      add     bx,ax                    ;bx = yoffset now
                                       ;Low 2 bits of x give pix position
                                       ;up  8 bits of x give byte offset;
      mov     dx,cx                    ;cx = x and dx = x
      shr     dx,1                     ;dx is x coordinate;
      shr     dx,1                     ;8 bits left so bx = first offset
      add     bx,dx                    ;bx = byte now
      mov     ax,si                    ;al := color
      and     ax,3

      mov     dl,03h                   ;dl := and mask
      not     cx                       ;3 = right not left
      and     cx,3                     ;2 bits give offset to use as count
      jz      TAno_shift
TAshift_loop:
      shl     al,1
      shl     al,1
      shl     dl,1
      shl     dl,1
      loop    TAshift_loop;
TAno_shift:
      or       si,si
      js       TAxorit
      not      dl
      and      es:0[bx],dl             ;zero the 2 bits concerned
      or       es:0[bx],al             ;now set them to the color
      jmp short TAcolorit
TAxorit:
      xor      es:0[bx],dl             ;invert the 2 bits concerned
TAcolorit:
      pop      ax
      pop      bx
      pop      dx
      pop      cx
TAoutside:
      ret
TEXTPOINT  ENDP

; Force the assembler to produce 4096 byte Binary file.

CodeLength = $ - GETDRIVERTYPE
db 4096-CodeLength DUP(0)


CODE  ends
      end


