;       ***********************************************************
;
;              VGAPRTSC.ASM   ver 1.3   February 1989
;
;           Hardcopy Utility for VGA-(and EGA-) Graphics Modes
;
;                          Robert Kaempf
;                         <DB3D@DDATHD21>
;                     Institut fuer Kernphysik
;                  Technische Hochschule Darmstadt
;                    6100 Darmstadt, West Germany
;
;       ***********************************************************
;
;       VGAPRTSC is similar to the MSDOS program GRAPHICS.COM.
;       The difference is: GRAPHICS supports low resolution
;       graphics modes (320x200,640x200), VGAPRTSC supports high
;       resolution graphics modes (640x480,640x350).
;       Text or low resolution graphics modes cause a call to the
;       old hardcopy routine. It is possible to install GRAPHICS
;       before VGAPRTSC. This will support any graphics modes.
;
;       Parameter:
;       /C= followed by 16 digits
;       The 16 digits correspond to the 16 screen colors.
;       An odd digit selects the color to be printed,
;       colors with even digits are not printed.
;
;       Example:
;       VGAPRTSC /C=0111111111111111   ( default )
;          prints colors 1 to 15.
;       VGAPRTSC /C=0000222211113333
;          prints highlighted colors ( 8 to 15 )
;
;       You may modify the colortable of an installed VGAPRTSC
;       version by typing: VGAPRTSC /C=... .
;       VGAPRTSC will not be installed twice !
;
;       Make VGAPRTSC.COM using MASM, LINK, EXE2BIN.
;

ESC     equ   1bh
CR      equ   0dh
LF      equ   0ah

disp    macro string
        lea   dx,string
        mov   ah,09h
        int   21h
        endm

_code   segment
        assume cs:_code,ds:_code
        org   100h
start:  jmp inst

logo    db "VGAPRTSC (c) Robert Kaempf"
logoend db 13,10,13,10,"$"
oldss   dw 0
oldsp   dw 0
int5old dd 0
used    db 0
pbyte   db 0
ymax    dw 0
pcount  dw 1
colors  db 0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1
ini6lpi db 5,esc,"A",12,esc,"2"  ; 6 lpi = 12/72 inch pro LF
ini9lpi db 5,esc,"A",08,esc,"2"  ; 9 lpi =  8/72 inch pro LF
inigrx  db 5,esc,"*"
grxden  db 0
grxlo   db 0
grxhi   db 0

jmptbl  dw offset dummy   ; graphmode 0
        dw offset dummy   ; graphmode 1
        dw offset dummy   ; graphmode 2
        dw offset dummy   ; graphmode 3
        dw offset dummy   ; graphmode 4
        dw offset dummy   ; graphmode 5
        dw offset dummy   ; graphmode 6
        dw offset dummy   ; graphmode 7
        dw offset dummy   ; graphmode 8
        dw offset dummy   ; graphmode 9
        dw offset dummy   ; graphmode a
        dw offset dummy   ; graphmode b
        dw offset dummy   ; graphmode c
        dw offset dummy   ; graphmode d
        dw offset dummy   ; graphmode e
        dw offset egapr   ; graphmode f
        dw offset egapr   ; graphmode 10
        dw offset vgapr   ; graphmode 11
        dw offset vgapr   ; graphmode 12

stack   db 100h dup ("TheStack")
tosta   db 0

beep    proc near
        push ax
        push cx
        in al,61h
        or al,03h
        out 61h,al
        mov cx,6000h
        loop $
        and al,11111100b
        out 61h,al
        pop cx
        pop ax
        ret
beep    endp

prt_al  proc   near         ; send al to LPT1
        push   ax
        push   dx
        mov    dx,0
        mov    ah,0
        int    17h
        pop    dx
        pop    ax
        ret
prt_al  endp

prtstr  proc   near         ; print string DS:DX
        push   si           ; [DS:DX+0] = length
        push   bp
        push   cx
        push   ax
        mov    bp,dx
        mov    si,0
        xor    cx,cx
        mov    cl,ds:byte ptr [bp]

psloop: inc    si
        cmp    si,cx
        ja     psexit
        mov    al,ds:byte ptr [bp][si]
        call   prt_al
        jmp    psloop
psexit: pop    ax
        pop    cx
        pop    bp
        pop    si
        ret
prtstr  endp

dummy   proc   near
        pushf                      ; int5old uses iret, needs flags
        call   dword ptr int5old   ; it's a far call
        ret
dummy   endp

hardcp  proc   near
; uses  grxinit, ymax, pcount, colors
        mov    dx,offset ini9lpi
        call   prtstr

        mov    cx,80
loopx:  push   cx
;        call   beep                ; helpful using lpt2dsk

        mov    dx,offset inigrx    ; start graphics line
        call   prtstr

        mov    dx,cx
        dec    dx
        mov    cl,3
        shl    dx,cl               ; x-pixel base

        mov    bx,0h               ; y-pixel
loopy:  mov    byte ptr pbyte,00h  ; claer printer byte

        mov    cx,08h              ; 8 pixel for printer
loop8:  push   cx
        push   dx
        push   bx
        push   di

        dec    cx
        add    cx,dx               ; x = cx
        mov    dx,bx               ; y = dx
        mov    ah,0dh              ; getcolor
        mov    bh,00h              ; page 1
        int    10h

        sal    byte ptr pbyte,01h
        mov    di,ax
        and    di,00ffh
        mov    bl,[offset colors + di]
        or     byte ptr pbyte,bl

        pop    di
        pop    bx
        pop    dx
        pop    cx
        loop   loop8

        mov    cx,pcount
ploop:  mov    al,pbyte
        call   prt_al
        loop   ploop

        inc    bx
        cmp    bx,ymax
        jb     loopy

        mov    al,cr               ; CR,LF
        call   prt_al
        mov    al,lf
        call   prt_al
        pop    cx
        loop   loopx

        mov    dx,offset ini6lpi
        call   prtstr
        ret
hardcp  endp

vgapr   proc   near                ; VGA hardcopy
        mov    dx,480
        mov    ymax,dx
        mov    word ptr pcount,01h
        mov    grxlo,dl
        mov    grxhi,dh            ; length of printerline
        mov    byte ptr grxden,00h ; use 05h for Olivetti PR17B
        jmp    hardcp
vgapr   endp

egapr   proc   near                ; EGA hardcopy
        mov    dx,350
        mov    ymax,dx
        mov    word ptr pcount,02h ; print bytes twice
        add    dx,dx               ; print bytes twice
        mov    grxlo,dl
        mov    grxhi,dh            ; length of printerline
        mov    byte ptr grxden,01h ; use 06h for Olivetti PR17B
        jmp    hardcp
egapr   endp

int5    proc   near

        cli
        push   ax
        mov    oldss,ss
        mov    oldsp,sp
        mov    ax,cs
        mov    ss,ax
        mov    sp,offset tosta
        sti

        push   ds
        push   dx
        push   cx
        push   bx

        push   cs
        pop    ds

        or     byte ptr used,00h    ; flag
        jnz    int5ex               ; vgaprtsc is running, exit

        mov    ah,0fh               ; get VGA mode
        int    10h
        cmp    al,12h
        ja     int5ex               ; mode >12h not used

        mov    used,01h             ; set prtsc flag
        xor    ah,ah                ;
        shl    ax,1                 ; make word index
        mov    bx,offset jmptbl
        add    bx,ax
        call   ds:[bx]
        mov    used,00h

int5ex:
        pop    bx
        pop    cx
        pop    dx
        pop    ds

        cli
        mov    ss,oldss
        mov    sp,oldsp
        pop    ax
        sti

        iret
int5    endp

inst:   push   cs
        pop    ds
        disp   logo

        mov    ax,3505h         ; get int5 vektor -> es:bx
        int    21h
        cmp    bx,offset int5
        jnz    i1               ; different ? yes -> install
        lea    si,logo          ; maybe installed ?
        lea    di,logo          ; check logo
        lea    cx,logoend
        sub    cx,offset logo   ; length of logo
        cld
        repz   cmpsb            ; compare  ds:si  with es:di
        jnz    i1               ; different ? yes -> install

        call   lineop           ; ES: Segment of old VGAPRTSC
        disp   notdbl
quit:   mov    ax,4c00h         ; exit with exitcode=0
        int    21h

i1:     mov    word ptr int5old,bx
        mov    word ptr int5old+2,es ;  store int5vector

        push   cs
        pop    es               ; ES: Segment of VGAPRTSC
        call   lineop

        lea    dx,int5
        mov    ax,2505h
        int    21h              ; set int5 vector to DS:DX
        disp   instok

        lea    dx,inst
        mov    cx,04h
        shr    dx,cl
        inc    dx
        mov    ax,3100h
        int    21h              ; exit resident

lineop  proc near
; ES:offset colors   points to colortable
; Paramters start at DS:80h
        mov di,80h
        mov al,20h   ; space
        xor cx,cx
        mov cl,[di]
        inc cx

splp:   inc di       ; loop while space
        dec cx
        or cx,cx
        jz lexit     ; no parameter
        cmp byte ptr [di],al
        jz splp

; ds:di points to 1st byte <> 20h
        cmp byte ptr [di], "/"
        jnz lerror
        dec cx
        or cx,cx
        jz lerror

        inc di
        cmp byte ptr [di], "c"
        jz  lc
        cmp byte ptr [di], "C"
        jnz lerror
lc:     dec cx
        or cx,cx
        jz lerror
        inc di

        cmp byte ptr [di], "="
        jnz lerror
        dec cx
        inc di
        cmp cx,16     ; 16 byte for colormap
        jb lerror

        mov cx,16
        mov si,offset colors

lp12:   mov al,[di]
        and al,01h    ; get bit #0
        mov es:[si],al
        inc si
        inc di
        loop lp12
        disp colset
lexit:  ret

lerror: disp wrngpa
        ret

lineop  endp

instok  db "VGAPRTSC ver 1.3 installed. ",13,10,"$"
notdbl  db "VGAPRTSC already installed, activate with PRTSC key.",13,10,"$"
wrngpa  db "ERROR ! Illegal parameter ! ",13,10,"$"
colset  db "New color-table installed. ",13,10,"$"

_code   ends
        end   start
        end
