
;************************************************************************
; Set Cursor:                                                           *
; This procedure will expand the two cursor masks into                  *
; four planes.  The expanded masks will be stored                       *
; after the last visible scan line at A000:(640/8*350).                 *
; Entry:        AND_Mask - 2x16 bytes with AND mask                     *
;               XOR_Mask - 2x16 bytes with XOR mask                     *
;               BG_Color - Foreground color                             *
;               FG_Color - Background color                             *
;************************************************************************


YSIZE           EQU     350
HBYTES          EQU     80
CUR_HEIGHT      EQU     16
GRFSEG          EQU     0A000H

AND_SAVE        EQU     (YSIZE*HBYTES+0)
XOR_SAVE        EQU     (YSIZE*HBYTES+2)
CUR_SAVE        EQU     (YSIZE*HBYTES+4)

AND_Mask        EQU     [BP+4]
XOR_Mask        EQU     [BP+6]
BG_Color        EQU     [BP+8]
FG_Color        EQU     [BP+10]

Last_Cursor     DW      0

        PUBLIC  _Set_Cursor

_Set_Cursor     PROC NEAR
        PUSH    BP
        MOV     BP,SP
        PUSH    SI
        PUSH    DI
        PUSH    ES                      ; always save seg regs
        PUSH    DS

        MOV     AX,GRFSEG               ;Point ES to video ram.
        MOV     ES,AX

        ;Set EGA to use SET/RESET register to fill with background color

        MOV     DX,3CEH                 ; enable use of reset register
        MOV     AL,1
        OUT     DX,AL
        INC     DX
        MOV     AL,0Fh
        OUT     DX,AL
        DEC     DX                      ; move color into reset register
        XOR     AL,AL
        OUT     DX,AL
        INC     DX
        MOV     AX,BG_Color
        OUT     DX,AL

        ; Fill with background

        MOV     DI,AND_SAVE             ;Pointer to save area (AND and XOR)
        MOV     CX,CUR_HEIGHT           ;Number of scanlines to do
Back_Loop1:
        STOSW                           ;16 bits for AND mask
        STOSW                           ;16 bits for XOR mask
        ADD     DI,HBYTES-4             ;Point to next scanline
        LOOP    Back_Loop1

        ; Change foreground bits for the AND mask save area

        MOV     AX,FG_Color             ;Load SET/RESET with foreground color
        OUT     DX,AL
        DEC     DX                      ;Select BIT MASK register
        MOV     AL,8
        OUT     DX,AL
        INC     DX
        MOV     CX,CUR_HEIGHT           ;Initialize counter
        MOV     DI,AND_Save             ;Get pointer to AND save area
        MOV     SI,AND_Mask             ;Get pointer to AND mask

Fore_Loop1:
        LODSB                           ;Fetch next byte from the mask
        OUT     DX,AL                   ;Set BIT MASK REGISTER using cursor mas
        MOV     AH,ES:[DI]              ;Latch data
        STOSB                           ;Write next 8 bits
        LODSB                           ;Fetch next byte from the mask
        OUT     DX,AL                   ;Set BIT MASK REGISTER using cursor mas
        MOV     AH,ES:[DI]              ;Latch data
        STOSB                           ;Write next 8 bits
        ADD     DI,HBYTES-2
        LOOP    Fore_Loop1

        ; Change foreground bits for the XOR mask save area

        MOV     CX,CUR_HEIGHT           ;Initialize counter
        MOV     DI,XOR_Save             ;Get pointer to XOR save area
        MOV     SI,XOR_Mask             ;Get pointer to XOR mask

Fore_Loop2:
        LODSB                           ;Fetch next byte from the mask
        OUT     DX,AL                   ;Set BIT MASK REGISTER using cursor mas
        MOV     AH,ES:[DI]              ;Latch data
        STOSB                           ;Write next 8 bits
        LODSB                           ;Fetch next byte from the mask
        OUT     DX,AL                   ;Set BIT MASK REGISTER using cursor mas
        MOV     AH,ES:[DI]              ;Latch data
        STOSB                           ;Write next 8 bits
        ADD     DI,HBYTES-2
        LOOP    Fore_Loop2

        ;Setup EGA registers for data copy (WRITE LATCH write mode)

        MOV     DX,3CEH                 ;Restore graphics controller
        MOV     AL,1                    ;Disable use of SET/RESET
        OUT     DX,AL
        INC     DX
        XOR     AL,AL
        OUT     DX,AL
        DEC     DX
        MOV     AL,8                    ;Enable all 8 bits for write
        OUT     DX,AL
        INC     DX
        MOV     AL,0FFH
        OUT     DX,AL
        DEC     DX
        MOV     AL,5                    ;Select WRITE LATCH write mode
        OUT     DX,AL
        INC     DX
        MOV     AL,1
        OUT     DX,AL

        ;Copy upper left corner into save area (this is needed for first
        ;call to Move_Cursor procedure, because it always restores and
        ;we need meaningfull data for the first restore).

        MOV     SI,0                    ;Copy from upper left
        MOV     CS:Last_Cursor,SI       ;Keep where it came from
        MOV     DI,CUR_SAVE             ;Copy to cursor save area
        MOV     AX,ES                   ;Point DS to display buffer
        MOV     DS,AX
        MOV     CX,CUR_HEIGHT           ;Number of lines to copy
Set_Copy_Loop:
        MOVSB                           ;Copy 24 bits from next raster
        MOVSB
        MOVSB
        ADD     DI,HBYTES-3             ;Update pointers to next raster
        ADD     SI,HBYTES-3
        LOOP    Set_Copy_Loop

        ;Restore normal write mode

        XOR     AL,AL                   ;WRITE MODE register is still selected
        OUT     DX,AL                   ;so load it with value 0

        ;Clean up and return

        POP     DS                      ;Restore segment registers
        POP     ES
        POP     DI
        POP     SI
        MOV     SP,BP
        POP     BP
        RET
_Set_Cursor     ENDP

;************************************************************************
; Move_Cursor:                                                          *
; This procedure is used to move the cursor from one                    *
; location to another.                                                  *
; Entry:        Curs_X - Position of the new cursor                     *
;               Curs_Y                                                  *
;************************************************************************

FUNC_AND        EQU     1
FUNC_XOR        EQU     3

Curs_X          EQU     [BP+4]
Curs_Y          EQU     [BP+6]

        PUBLIC  _Move_Cursor

_Move_Cursor    PROC    NEAR
        PUSH    BP
        MOV     BP,SP
        PUSH    SI
        PUSH    DI
        PUSH    ES                      ; always save seg regs
        PUSH    DS

        CALL    _Remove_Cursor          ;Restore last location

        ;Setup EGA registers for data copy (WRITE LATCH write mode)

        MOV     DX,3CEH                 ;Address of GRAPICS controller
        MOV     AL,5                    ;Select WRITE LATCH write mode
        OUT     DX,AL
        INC     DX
        MOV     AL,1
        OUT     DX,AL

        ;Copy next location of the cursor to the save area

        MOV     AX,Curs_Y               ;Convert cursor X,Y to offset
        MOV     BX,HBYTES
        MUL     BX
        MOV     SI,Curs_X
        SHR     SI,1
        SHR     SI,1
        SHR     SI,1
        ADD     SI,AX
        MOV     CS:Last_Cursor,SI       ;Keep location so we can restore later
        MOV     AX,GRFSEG               ;Point ES and DS to display buffer
        MOV     DS,AX
        MOV     ES,AX
        MOV     DI,CUR_SAVE             ;Pointer to save area
        MOV     CX,CUR_HEIGHT           ;Number of lines to copy
Move_Copy_Loop:
        MOVSB                           ;Copy 16 bits from next raster
        MOVSB
        MOVSB
        ADD     DI,HBYTES-3             ;Update pointers to next raster
        ADD     SI,HBYTES-3
        LOOP    Move_Copy_Loop

        ;Restore normal write mode

        MOV     DX,3CFH
        MOV     AL,0                    ;WRITE MODE register is still selected
        OUT     DX,AL                   ;so load it with value 0

        ;Use BITBLT procedure to copy AND and XOR masks of the cursor

        MOV     AX,FUNC_AND             ;Push function on the stack
        PUSH    AX
        MOV     AX,CUR_HEIGHT           ;Push width and height
        PUSH    AX
        PUSH    AX
        PUSH    WORD PTR Curs_Y         ;Push x and y of destination
        PUSH    WORD PTR Curs_X
        MOV     AX,YSIZE                ;Push x and y of source
        PUSH    AX
        MOV     AX,0
        PUSH    AX
        CALL    _BitBlt
        ADD     SP,14

        MOV     AX,FUNC_XOR             ;Push function on the stack
        PUSH    AX
        MOV     AX,CUR_HEIGHT           ;Push width and height
        PUSH    AX
        PUSH    AX
        PUSH    WORD PTR Curs_Y         ;Push x and y of destination
        PUSH    WORD PTR Curs_X
        MOV     AX,YSIZE                ;Push x and y of source
        PUSH    AX
        MOV     AX,16
        PUSH    AX
        CALL    _BitBlt
        ADD     SP,14

        ;Clean up and return

        POP     DS                      ;Restore segment registers
        POP     ES
        POP     DI
        POP     SI
        MOV     SP,BP
        POP     BP
        RET
_Move_Cursor    ENDP

;************************************************************************
; Remove_Cursor:                                                        *
; This procedure is used to remove the cursor from the screen           *
; and to restore the screen to its original appearance                  *
;************************************************************************

        PUBLIC  _Remove_Cursor

_Remove_Cursor  PROC NEAR
        PUSH    BP
        MOV     BP,SP
        PUSH    SI
        PUSH    DI
        PUSH    ES                      ; always save seg regs
        PUSH    DS

        ;Setup EGA registers for data copy (WRITE LATCH write mode)

        MOV     DX,3CEH                 ;Address of GRAPICS controller
        MOV     AL,5                    ;Select WRITE LATCH write mode
        OUT     DX,AL
        INC     DX
        MOV     AL,1
        OUT     DX,AL

        ;Copy save area back to last location of the cursor

        MOV     AX,0A000H               ;Set up segment pointers
        MOV     ES,AX
        MOV     DS,AX
        MOV     DI,CS:Last_Cursor       ;Copy to last X,Y of cursor
        MOV     SI,CUR_SAVE             ;Copy form cursor save area
        MOV     CX,CUR_HEIGHT           ;Number of lines to copy
Rest_Copy_Loop:
        MOVSB                           ;Copy 16 bits from next raster
        MOVSB
        MOVSB
        ADD     DI,HBYTES-3             ;Update pointers to next raster
        ADD     SI,HBYTES-3
        LOOP    Rest_Copy_Loop

        ;Restore normal write mode

        MOV     AL,0                    ;WRITE MODE register is still selected
        OUT     DX,AL                   ;so load it with value 0

        ;Clean up and return

        POP     DS                      ;Restore segment registers
        POP     ES
        POP     DI
        POP     SI
        MOV     SP,BP
        POP     BP
        RET
_Remove_Cursor  ENDP
