;*DDK*************************************************************************/
;
; COPYRIGHT    Copyright (C) 1995 IBM Corporation
;
;    The following IBM OS/2 WARP source code is provided to you solely for
;    the purpose of assisting you in your development of OS/2 WARP device
;    drivers. You may use this code in accordance with the IBM License
;    Agreement provided in the IBM Device Driver Source Kit for OS/2. This
;    Copyright statement may not be removed.;
;*****************************************************************************/
        PAGE     55,132
        TITLE    AVIO Drawing Functions
        SUBTITLE Header

;/*****************************************************************************
;*
;* SOURCE FILE NAME = CELLDRAW.ASM
;*
;* DESCRIPTIVE NAME = Draw from a LVB
;*
;*
;* VERSION      V2.0
;*
;* DATE         11/19/91
;*
;* DESCRIPTION  This module contains drawing functions which materialize the image 
;*              of a logical video buffer based on pseudocode placed in the stack by routine
;*              by routine from the CELLSCAN.ASM module.                                          
;*
;* FUNCTIONS   InvertClippedRect 
;*             InvertScreenRect  
;*             InvertScreenRect  
;*                              
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   11/19/91                     KEZ  Original
;*
;*****************************************************************************/

        .386P
        .MODEL FLAT,SYSCALL

VGA     EQU 1
;*****************************************************************************
; Included files                                                             *
;*****************************************************************************

        OPTION  OLDSTRUCTS

INCL_DDIFONTSTRUCS EQU 1
INCL_GPIPRIMITIVES EQU 1
INCL_NOBASEAPI     EQU 1
INCL_SAADEFS       EQU 1
        INCLUDE PMGRE.INC

DINCL_BITMAP       EQU 1
DINCL_ENABLE       EQU 1
        include fontmap.inc
        INCLUDE DRIVER.INC
        INCLUDE EXTERN.INC
        INCLUDE PROTOS.INC
        INCLUDE EGAFAM.INC
        INCLUDE CELLBLT.INC
        INCLUDE POINTER.INC
if SCAN_CNT EQ 768
        include oem_macs.inc
endif

;/*
;** Local Data
;*/

        .DATA

ColorMap    DB  0,1,2,3,4,5,6,8,7,9,10,11,12,13,14,15

ifdef DBCS  ; DBCS AVio attribute support    ;IBMJ
EspSave   DWORD ?
endif;DBCS        ;IBMJ

EGAColorPlaneMask EQU 0Fh

;/*
;** Public Functions
;*/

        .CODE

SUBTITLE InterpretAttributes
        PAGE +

;/***************************************************************************
;*
;* PUBLIC ROUTINE  InterpretAttributes 
;*
;* DESCRIPTION   = Pops a word of attribute information off the stack, adjusts the
;*                 drawing environment as necessary, and jumps to an appropriate 
;*                 drawing function. It presumes the EBP stack environment created 
;*                 by DrawImageRect.
;*                 
;*                 This routine usually exits with a JMP rather than a RET! 
;*
;*                 Registers Destroyed:         
;*                       AH, AL, BH, BL, CX, DX 
;*                 Registers Preserved:         
;*                       None                   
;*
;* INPUT         = EDI is assumed to be set as required by the EGA drawing functions
;*                 Assumes a WORD of descriptor information is at [ESP].            
;* OUTPUT        = ESP advances to the next pseudo code word.
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        OPTION  PROLOGUE:NONE
        OPTION  EPILOGUE:NONE

ALIGN 4
define_CharRect_frame InterpretAttributes

;/*
;**
;**    A pseudo code plan for InterpretAttributes:
;**    Set up initial destination address.
;**
;**    SP = pReturnAddress?
;**        ret
;**
;**    Opaque and Reverse Video?
;**        Switch Foreground/Background Attributes.
;**        Reset the Reverse Video Attribute bit.
;**
;**    Set registers
;**    Preserve registers
;**
;**    LCID Changed?
;**        Map the LCID to a Font Selector.
;**
;**        Zero Selector?
;**            Scan the pseudo code until the next control marker,
;**                replacing offsets by wUnusableSurrogate.
;**            Change the Selector to reference the base symbol set.
;**
;**        Load the selector into DS.
;**        Set up the glyph mapping attributes
;**
;**    Transparent or Opaque?
;**
;**        Opaque:
;**               HorizontalClipping?
;**                    Set Opaque Clipping Colors
;**                    Pass 1 if necessary
;**                    Pass 2 if necessary
;**
;**               If LastPass was Transparent or Colors are different,
;**                    Set Opaque Colors
;**
;**               Restore Regs
;**
;**        ;    Horizontal Clipping?
;**        ;           JMP to AVioDrawCellHC
;**
;**               Underscoring or Reverse Video?
;**                     JMP to AVioDrawOpaqueNVC
;**               ELSE: JMP to VioDrawOpaqueNHC
;**
;**        Transparent:
;**                If LastPass was Opaque or Color is different,
;**                    Set Transparent Color.
;**
;**                Restore Regs
;**
;**                Horizontal Clipping?
;**                      JMP to AVioDrawCellHC
;**                Else: JMP to AVioDrawXparentNVC
;**
;**  End of the Pseudo Code for InterpretAttributes
;*/

ifdef DBCS  ; DBCS device font support     ;IBMJ
; If any DBCS characters are detected during scanning cells, we should
; realize font image for these DBCS characters.
; All of found DBCS character code-points are saved in the array at
; ss:[cb_adbcschar].
; Here we will translate these code-points to glyph-index.

 mov ecx,CellBLTBlock.cb_cdbcschar ; any DBCS char detected ?
 jcxz no_dbcs_chars

 pop esi
 push esi
 and esi,AVioLCIDMask  ; ESI = local set id

 mov eax,wSymbolSetSelectors[ESI*4] ; EAX --> fontseg
 mov ecx,CellBLTBlock.cb_cdbcschar ; ECX = number of DBCS chars
 lea edi,CellBLTBlock.cb_adbcschar ; EDI --> DBCS char array

 mov EspSave,esp
 lea esp,LastValue
 sub esp,100h   ; fire wall
 call DbcsValidateVioChar  ; do translation
 mov esp,EspSave

 mov CellBLTBlock.cb_dbcs_2nd,eax ; offset to get DBCS 2nd byte

no_dbcs_chars:
endif;DBCS        ;IBMJ

;/*
;** Check the width of characters. If not 8 then jump to alternative character
;** drawing code.
;*/

IFDEF VGA
        CMP     wCellWidth,8
        JE      Got8pel
        JMP     Not8pel
ALIGN 4
        PUBLIC  Got8pel
Got8pel::

ENDIF ; VGA

;/*
;** InterpretAttributes begins with a prologue for establishing part
;** of the environment assumed by the drawing functions.  The drawing
;** functions are presumed to preserve or properly update this state
;** information across cell clusters with a common set of attributes.
;*/

;/*
;** If wVertLineCount is smaller than wCellWidth, we must construct a
;** horizontal clipping mask.
;*/

        MOV     AX,0FFFFh
        MOV     CX,wVertLineCount
        CMP     CX,wCellWidth
        JE      No_horizontal_clipping
        SHR     AX,CL
        NOT     AX
        MOV     CX,wLeftLineOffset
        SHR     AX,CL

        PUBLIC  No_horizontal_clipping
No_horizontal_clipping::
        MOV     bHorizontalClipMask,AH

;/*
;** The initial drawing position is defined by the pel coordinates xcoordStart
;** and ycoordStart.  Here we convert that to the starting address.  Devices
;** with interleaved bitmaps (viz. CGA and Hercules) would also set up phase
;** control information here.
;*/

        MOVZX   EAX,ycoordStart
        MOVZX   EDI,wDestBMWidth
        MUL     EDI
        MOVZX   EDI,xcoordStart
        SHR     EDI,3
        ADD     EDI,EAX
if SCAN_CNT EQ 768
        cmp     edi,010000h
        jb      @F
        sub     edi,010000h
@@:
endif
        ADD     EDI,pVRAMInstance        ; Initial drawing address.

;/*
;** Now we construct three increments for the destination pointer:
;**
;**   1.  The distance to move to the next scan line in a cell image after a
;**       MOVSB or STOSB instruction.
;**
;**   2.  The distance to move from the bottom scan line of a cell to the top
;**       scan line in the same cell.
;**
;**   3.  The distance to move from just to the right of the last scan line in
;**       the rightmost cell in a column set to the top scan line in the lefmost
;**       column in the next row of the same column set.
;*/

        MOVZX   EAX,wDestBMWidth
        MOV     EBX,EAX
        DEC     EBX
        MOV     wDest1stIncr,EBX
        MOV     EBX,EAX
        MUL     wScanLineCount
        SUB     EBX,EAX
        MOV     wDest2ndIncr,EBX
        SUB     EAX,wFullCols
        MOV     wDest3rdIncr,EAX

;/*
;** The drawing functions use addresses in an upward sequence.  Hence the need
;** to have the direction flag cleared.
;*/

        CLD

;/*
;** The following label is the return point for all the device-dependent
;** drawing functions.  Most of them terminate with a JMP instead of a RET.
;*/

        PUBLIC  Next_attribute_cluster
Next_attribute_cluster::
        CMP     ESP,pReturnAddress      ; Have we exhausted the pseudocode?
        JE      IA_Exit                 ; If so return to the scanner.
        POP     ESI                     ; Get the new attribute set.
ifdef DBCS  ; DBCS AVio attribute support    ;IBMJ
 CALL GetAVioAttributes ; ESI = AVio attribute bits
endif;DBCS        ;IBMJ
        XOR     ECX,ECX                 ; Constructing a reference Zero value.
ifndef JFIX        ;IBMJ
        MOVZX   EAX,SI
        AND     EAX,(AVioReverseVideoMask OR AVioTransparentMask)
        CMP     AX,AVioReverseVideoMask ; Check for Opaque with Reverse Video.
        JNZ     Filter_UnderScore
else ;JFIX  ; PTR SM88864 @ PM20 implementation    ;IBMJ
 TEST ESI,AVioReverseVideoMask
 JZ Filter_UnderScore
endif;JFIX        ;IBMJ
        MOVZX   EAX,SI                  ; For that case we do the reversing
        MOV     BL,AH                   ; by just swapping foreground and
        SHR     AH,4                    ; background color attributes.
        SHL     BX,4
        OR      AH,BL
        AND     EAX,(NOT AVioReverseVideoMask)
        MOV     ESI,EAX                 ; ESI = Attribute set

        PUBLIC  Filter_UnderScore
Filter_UnderScore::
        TEST    ESI,AVioUnderscoreMask
        JZ      Set_up_registers
        MOV     EAX,wTopLineOffset
        ADD     EAX,wScanLineCount
        CMP        AX,wCellHeight
        JZ         Set_up_registers
        AND     ESI,(NOT AVioUnderscoreMask)

        PUBLIC  Set_up_registers
Set_up_registers::
        MOV     AX,AVioUnderscoreMask   ; If underscoring,BL => 0FFh else 0.
        AND     AX,SI
        CMP     CX,AX
        SBB     BL,BL
        MOV     AX,AVioReverseVideoMask ; If reverse video,BH => 0FFh else 0.
        AND     AX,SI
        CMP     CX,AX
        SBB     BH,BH
        MOV     EDX,wDest1stIncr        ; Set up the other registers we use.
        MOV     ECX,wDest2ndIncr
        MOV     AL,bHorizontalClipMask
        MOV     AH,bScanLines
        PUSH    EAX                     ; Preserve the registers we
        PUSH    EBX                     ; use herein.
        PUSH    ECX
        PUSH    EDX
        MOV     EDX,EAX
        MOV     EAX,ESI                 ; Get the previous attribute set
        MOV     ECX,ESI
        XCHG    AX,wLastAttributes      ; and preserve this attribute set
                                        ; for the next InterpretAttributes
                                        ; call.
        MOVZX   EBX,AX                  ; Compare the old and
        XOR     EBX,ESI                 ; new LCID bit fields.
        AND     EBX,AVioLCIDMask        ; Are they different?
        JZ      SameSymbolSet
        AND     ESI,AVioLCIDMask                ; If so set up DS for the new
        MOV     EBX,wSymbolSetSelectors[ESI*4]
        OR      EBX,EBX                         ; Is this selector usable?
        JNZ     ValidSymbolSetSelector

;/*
;** If we don't have a usable selector, we use the selector for the base symbol
;** set, and map all of the glyph points for that LCID to a surrogate glyph.
;*/

        CLD                             ; Set up to scan forward through the
                                        ; glyphs on the stack.
        MOV     EBX,SURROGATE_CHARACTER
        MOV     ESI,ESP
        ADD     ESI,8*2                 ; Skip over saved registers

        PUBLIC  Check_next_syllable
Check_next_syllable::
ifndef JFIX        ;IBMJ
        LODSW
else  ;JFIX        ;IBMJ
        LODSD                                   ; Get next syllable
endif ;JFIX        ;IBMJ
        CMP     AX,-2
        JA      Found_a_control_marker  ; -1 => control marker
        JE      Check_next_syllable     ; -2 => end of row action
ifndef DBCS        ;IBMJ
ifndef JFIX        ;IBMJ
        MOV     [ESI-2],BX
else  ;JFIX        ;IBMJ
        MOV     [ESI-4],BX                      ; Replace syllable with a
                                                ; surrogate character
endif ;JFIX        ;IBMJ
endif ;DBCS        ;IBMJ
        JMP     Check_next_syllable
ALIGN 4

        PUBLIC  Found_a_control_marker
Found_a_control_marker::
        MOV     EBX,wSymbolSetSelectors[0]      ; Substitute the selector for
                                                ; the base symbol set.

        PUBLIC  ValidSymbolSetSelector
ValidSymbolSetSelector::
        MOV     wselfontsave,EBX        ; Point to symbol set to use
        MOV     ESI,EBX

;/*
;** Here we set up the data which characterizes the font which is becoming
;** active.
;*/

        MOVZX   EBX,[ESI].FOCAFONT.ff_fmMetrics.foca_usLastChar
        INC     EBX
        MOV     wGlyphSpan,EBX
        MOVZX   EBX,[ESI].FOCAFONT.ff_fmMetrics.foca_usFirstChar
        MOV     wFirstGlyph,EBX
        MOVZX   EBX,[ESI].FOCAFONT.ff_fmMetrics.foca_usDefaultChar
        MOV     wDefaultGlyph,EBX
        MOV     ESI,ECX

        PUBLIC  SameSymbolSet
SameSymbolSet::
        TEST    ESI,AVioTransparentMask ; Transparent cells or Opaque cells ?
        JNZ     GoingTransparent

;/*
;**---------------------- Opaque cells ---------------------------
;*/

        INC     DL                      ; Horizontally clipped?
        JNZ     ClippedOpaque
        JMP     OpaqueNoHorzClippping
ALIGN 4

        PUBLIC  ClippedOpaque
ClippedOpaque::
ifdef DBCS  ; DBCS AVio attribute support    ;IBMJ
 MOV wDestOffsetSave,EDI ; Save the destination pointer.
endif;DBCS        ;IBMJ
        DEC     DL                      ; If so, get the clip mask
        MOV     AH,DL                   ; in AH for the OUT below.
        MOV     DH,CH                   ; Split the color information into
        MOV     DL,DH                   ; two bytes:
        SHR     DH,4                    ;   DH -- Background
        AND     DX,0F0Fh                ;   DL -- Foreground
ifdef IBMJ  ; IBM-Japan Vio attribute support    ;IBMJ
 CMP FormatID,FORMATID_IBMJ_MONO
 JNE get_colors_clipped

 XOR EBX,EBX   ; Use specified physical color
 CMP BH,DH   ;   for IBM-Japan mono vio mode.
 SBB BH,0   ; 
 CMP BL,DL   ; BH = 0FFh if background != 0
 SBB BL,0   ; BL = 0FFh if foreground != 0
 AND BH,bCellColor  ;        BH -- Background
 AND BL,bCellColor  ;        BL -- Foreground
 JMP have_colors_clipped

get_colors_clipped:
endif;IBMJ        ;IBMJ
        XOR     EBX,EBX
        MOV     BL,DL                   ; Map the foreground/background
        MOV     DL,ColorMap[EBX]        ; into the correct EGA planes.
        MOV     BL,DH
        MOV     DH,ColorMap[EBX]
        MOV     BX,DX                   ; Free up DX for the OUT instructions.
have_colors_clipped:       ;IBMJ
        MOV     DX,EGA_BASE+GRAF_ADDR   ; Latch clip mask into Bit Mask reg.
        MOV     AL,GRAF_BIT_MASK
        OUT     DX,AX
        MOV     AL,GRAF_MODE                    ; Set Mode reg. to following:
        MOV     AH,M_PROC_WRITE OR M_DATA_READ  ;   Even mode,
        OUT     DX,AX                           ;   Color cmp.mode disabled
                                                ;   Direct processor write
        MOV     AL,GRAF_DATA_ROT        ; Set Data Rot./Func. Sel. reg to:
        MOV     AH,DR_SET               ;   Not rotate data,
        OUT     DX,AX                   ;   Write data unmodified
        MOV     AL,GRAF_SET_RESET       ; Set Set/Reset reg. to foreground
        MOV     AH,BL                   ; color
        OUT     DX,AX
        XOR     AH,BH                   ; SetResetEnable <- FullColors and
        MOV     CH,AH                   ;   Foreground = Background
        NOT     AH
        MOV     CL,AH
        AND     AH,MM_ALL
        MOV     AL,GRAF_ENAB_SR
        OUT     DX,AX
        MOV     DX,EGA_BASE+SEQ_ADDR    ; Set up to select the planes for
        MOV     AL,SEQ_MAP_MASK         ; each pass.
        MOV     AH,CH                   ; Set AH to the planes that can't
        AND     AH,BL                   ; be done on the second pass.
        JZ      NoOHCPass1              ; If none, skip the first pass.
        MOV     AH,CL                   ; The first pass always includes
        OR      AH,BL                   ; the planes controlled by Set/Reset
        OUT     DX,AX                   ; in addition to the ones for which
                                        ; fg and fg != bg.
        MOV     ESI,EAX                 ; Preserve EAX for the PUSH below.
        POP     EDX                     ; Restore the other registers
        POP     ECX                     ; we'll need.
        POP     EBX
        POP     EAX
        MOV     npinxGlyph,ESP          ; Store a pointer to the base of the
                                        ; pseudo code sequence.
ifndef DBCS ; DBCS AVio attribute support    ;IBMJ
        PUSH    EDI                     ; Save the destination pointer
                                        ; for a possible second pass.
endif;not DBCS        ;IBMJ
        PUSH    ESI                     ; Save our plane mask.
        CALL    AVioDrawOpaqueHC        ; Make the first pass.
        MOV     ESI,EAX                 ; Preserve EAX so we can retrieve
        POP     EAX                     ; the plane mask.
        NOT     AH                      ; AH now masks the planes to be
        OR      AH,AH                   ; done on the second pass.
        JZ      NoOHCPass2              ; If there aren't any we skip the
                                        ; second pass.
ifndef DBCS        ;IBMJ
        POP     EDI                     ; Restore EDI for the second pass.
else ;DBCS  ; DBCS AVio attribute support    ;IBMJ
 MOV EDI,wDestOffsetSave ; Restore DI for the second pass.
endif;DBCS        ;IBMJ
        MOV     ECX,EDX
        MOV     EDX,EGA_BASE+SEQ_ADDR   ; Select the planes for pass 2.
        OUT     DX,AX
        MOV     EDX,ECX                 ; Set up the registers for pass 2.
        MOV     npinxGlyph,ESP          ; Store a pointer to the base of
                                        ; the code stream.
        MOV     EAX,ESI
        NOT     BH                      ; Toggle the reverse video byte.
        CALL    AVioDrawOpaqueHC        ; The second pass...
        JMP     NoOHCPass2
ALIGN 4

        PUBLIC  NoOHCPass1
NoOHCPass1::
        NOT     AH                      ; Select the planes for the second
        MOV     DX,EGA_BASE+SEQ_ADDR    ; pass.
        OUT     DX,AX
        POP     EDX                     ; Set up the register environment
        POP     ECX                     ; for the second pass.
        POP     EBX
        POP     EAX
        NOT     BH                      ; Toggle the reverse video byte.
        MOV     npinxGlyph,ESP          ; Store a pointer to the base of the
                                        ; code stream.
        CALL    AVioDrawOpaqueHC        ; The second pass...

        PUBLIC  NoOHCPass2
NoOHCPass2::
ifdef DBCS  ; DBCS AVio attribute support    ;IBMJ
 TEST wAVioAttributes,AVioHorizontalGridMask OR AVioVerticalGridMask
 JZ ClippedOpaqueOK  ; No grid attributes

 MOV EDI,wDestOffsetSave ; Restore DI for the grid pass.
 MOV npinxGlyph,ESP  ; Store a pointer to pseudo code base.
 CALL AVioDrawGridOHC  ; The grid pass...
ClippedOpaqueOK:
endif;DBCS        ;IBMJ

        MOV     ESP,npinxGlyph          ; Move ESP to the next control point
                                        ; in the pseudo code.
        JMP     Next_attribute_cluster  ; Go interpret the control point.
ALIGN 4

        PUBLIC  OpaqueNoHorzClippping
OpaqueNoHorzClippping::
        TEST    AX,AVioTransparentMask  ; Was the last stream transparent?
        JNZ     SetOpaqueColors
        CMP     AH,CH                   ; Were the fg/bg colors different?
        JZ      OpaqueColorsOK

        PUBLIC  SetOpaqueColors
SetOpaqueColors::
        MOV     DH,CH                   ; Split the color information into
        MOV     DL,DH                   ; two bytes:
        SHR     DH,4                    ;   DH -- Background
        AND     DX,0F0Fh                ;   DL -- Foreground
ifdef IBMJ  ; IBM-Japan Vio attribute support    ;IBMJ
 CMP FormatID,FORMATID_IBMJ_MONO
 JNE get_colors

 XOR EBX,EBX   ; Use specified physical color
 CMP BH,DH   ;   for IBM-Japan mono vio mode.
 SBB BH,0   ; 
 CMP BL,DL   ; BH = 0FFh if background != 0
 SBB BL,0   ; BL = 0FFh if foreground != 0
 AND BH,bCellColor  ;        BH -- Background
 AND BL,bCellColor  ;        BL -- Foreground
 JMP have_colors

get_colors:
endif;IBMJ        ;IBMJ
        XOR     EBX,EBX
        MOV     BL,DL                   ; Map the foreground/background
        MOV     DL,ColorMap[EBX]        ; into the correct EGA planes.
        MOV     BL,DH
        MOV     DH,ColorMap[EBX]
        MOV     BX,DX                   ; Free up DX for the OUT instructions.
have_colors:        ;IBMJ

;/*
;** Much of the following code consists of constants sent to the EGA I/O address
;** interface.  It should be converted to a structure with fields for the
;** variable information, then the code can be reduced to filling in the
;** variable fields and using REP OUTSW or its equivalent through a MACRO
;** definition.
;*/

        MOV     DX,EGA_BASE+SEQ_ADDR            ; Enable all the available EGA
        MOV     AX,(MM_ALL shl 8)+SEQ_MAP_MASK  ; planes.
        OUT     DX,AX
        MOV     DX,EGA_BASE+GRAF_ADDR           ; Prepare to set the EGA
                                                ; graphics registers.

        MOV     AX,((M_PROC_WRITE OR M_DATA_READ) shl 8)+GRAF_MODE
        OUT     DX,AX
        MOV     AX,(DR_SET shl 8)+GRAF_DATA_ROT ; Set up to write data without
        OUT     DX,AX                           ; interacting with the latches
        MOV     AL,GRAF_SET_RESET               ; Put the background color in
        MOV     AH,BH                           ; the Set/Reset register.
        OUT     DX,AX
        MOV     AX,(MM_ALL shl 8)+GRAF_ENAB_SR  ; That color is used for all
        OUT     DX,AX                           ; planes.
        MOV     AX, 0FF00h+GRAF_BIT_MASK        ; Use all pixel positions.
        OUT     DX,AX

        OVAccess        ;access offscreen VRAM

        MOV     ECX,pVRAMInstance                        ; This gets our
        MOV     [ECX+tonys_bar_n_grill],AH      ; background color
        MOV     AH,[ECX+tonys_bar_n_grill]      ; into the latches

        OVRestore       ;Restore VGA to previouse state

ifdef DBCS  ; DBCS AVio attribute support    ;IBMJ
 MOV AL,GRAF_SET_RESET  ; Put the grid color in the
 MOV AH,MM_ALL   ; Set/Reset register.
 AND AH,bPhysColor
 OUT DX,AX

 MOV AL,GRAF_BIT_MASK  ; Use vertical grid mask.
 MOV AH,80h
 OUT DX,AX
 MOV [ECX+vert_grid_latches],AH ; Prepare for vertical grid.

 MOV AL,GRAF_BIT_MASK  ; Use all pixel positions.
 MOV AH,0FFh
 OUT DX,AX
 MOV [ECX+horz_grid_latches],AH ; Prepare for horizontal grid.
endif;DBCS        ;IBMJ
        MOV     AX,GRAF_SET_RESET               ; Change the Set/Reset reg. to
        OUT     DX,AX                           ; be all zeroes.
        MOV     AH,BH                           ; The Set/Reset Enable reg.
        XOR     AH,BL                           ; now flags where the
        NOT     AH                              ; foreground/background colors
        AND     AH,0Fh                          ; are the same.
        MOV     AL,GRAF_ENAB_SR
        OUT     DX,AX
        MOV     AX,(DR_XOR shl 8)+GRAF_DATA_ROT ; Color differences will be
        OUT     DX,AX                           ; XOR'd with the latches.

        PUBLIC  OpaqueColorsOK
OpaqueColorsOK::
        POP     EDX                             ; Restore the register set for
        POP     ECX                             ; the drawing function.
        POP     EBX
        POP     EAX
ifndef DBCS        ;IBMJ
        TEST    SI,AVioUnderscoreMask OR AVioReverseVideoMask
else ;DBCS  ; DBCS AVio attribute support    ;IBMJ
 TEST SI,AVioUnderscoreMask OR AVioReverseVideoMask OR \
   AVioHorizontalGridMask OR AVioVerticalGridMask
endif;DBCS        ;IBMJ
        JZ      VioDrawOpaqueNHC
        JMP     AVioDrawOpaqueNVC
ALIGN 4

        PUBLIC  GoingTransparent
GoingTransparent::
        TEST    AX,AVioTransparentMask  ; Was the last stream transparent?
        JZ      SetTransparentColor
        CMP     AH,CH                   ; Was its color different?
        JE      TransparentColorOK

        PUBLIC  SetTransparentColor
SetTransparentColor::

;/*
;** Much of the following code consists of constants sent to the EGA I/O
;** address interface.  It should be converted to a structure with fields for
;** the variable information, then the code can be reduced to filling in the
;** variable fields and using REP OUTSW or its equivalent through a MACRO
;** definition.
;*/

        MOV     DX,EGA_BASE+SEQ_ADDR    ; Enable all the available EGA planes.
        MOV     AX,(MM_ALL shl 8)+SEQ_MAP_MASK
        OUT     DX,AX
        MOV     DX,EGA_BASE+GRAF_ADDR           ; Prepare to set the EGA
                                                ; graphics registers.
        MOV     AX,(DR_SET shl 8)+GRAF_DATA_ROT ; Set up to write data
        OUT     DX,AX                           ; without interacting with the
                                                ; latches.
ifndef JFIX        ;IBMJ
        XOR     BX,BX                   ; Map the color to the EGA color
        MOV     BL,CH                   ; planes and put that mapping into
else ;JFIX        ;IBMJ
 MOV BX,0Fh   ; Map the color to the EGA color
 AND BL,CH   ; planes and put that mapping into
endif;JFIX        ;IBMJ
        MOV     AL,GRAF_SET_RESET       ; the Set/Reset register.
        MOV     AH,ColorMap[EBX]
        OUT     DX,AX
ifdef DBCS  ; DBCS AVio attribute support    ;IBMJ
 MOV bColor,AH  ; Save cooked foreground color.
endif;DBCS        ;IBMJ
        MOV     AX,(MM_ALL shl 8)+GRAF_ENAB_SR  ; That color goes to all
        OUT     DX,AX                           ; planes.
        MOV     AL,GRAF_BIT_MASK        ; Prepare for OUT's to GRAF_BIT_MASK.
        OUT     DX,AL

        PUBLIC  TransparentColorOK
TransparentColorOK::
        POP     EDX                     ; Restore the register set for
        POP     ECX                     ; the drawing function.
        POP     EBX
        POP     EAX
        INC     AL
        JNZ     Transparent_Clipped     ; Horizontal clipping?
        JMP     AVioDrawXparentNVC      ; All other transparent cases.
ALIGN 4

        PUBLIC  Transparent_Clipped
Transparent_Clipped::
        DEC     AL                      ; Restore the clip mask.
        JMP     AVioDrawXparentHC
ALIGN 4
IFDEF VGA

;/*
;** Alternative 'InterpretAttributes' for 8 pel wide characters only.         
;**                                                                           
;** InterpretAttributes begins with a prologue for establishing part of the   
;** environment assumed by the drawing functions.  The drawing functions are  
;** presumed to preserve or properly update this state information across cell
;** clusters with a common set of attributes.                                 
;**                                                                           
;** Set up the hardware clip rectangle first.  It remains constant throughout 
;** the display of the text.  Note that the clip rectangle is given as lower  
;** left/upper right instead of upper left/lower right as the 8514 would like 
;** it.                                                                       
;**                                                                           
;** It appears that the text clip rectangle is different than the normal PM   
;** clip rectangle in terms of which edges are inclusive and which are        
;** exclusive, just as in the STRBLT path.  In PM, the left and bottom edges  
;** are inclusive and the top and right edges are exclusive.  The text path,  
;** however, is based on         code, and in         the top and left edges  
;** are inclusive and the bottom and right edges are exclusive.  Set up the   
;** hardware clip rectangle with that in mind.                                
;*/

        PUBLIC  Not8pel
Not8pel::
        MOVZX   ECX,wDestHeight                 ; Height of destination bitmap
        MOV     EAX,ECX
        SUB     EAX,rClipRect.rcs_yTop          ; Top (flipped and inclusive)
        MOV     wClipYmin,EAX
        MOV     EAX,ECX                         ; Height of destination bitmap
        SUB     EAX,rClipRect.rcs_yBottom       ; Btm (flipped and exclusive)
        MOV     wClipYmax,EAX
        MOV     EAX,rClipRect.rcs_xLeft         ; Left (inclusive)
        MOV     wClipXmin,EAX
        MOV     EAX,rClipRect.rcs_xRight        ; Right (exclusive)
        MOV     wClipXmax,EAX

;/*
;** Construct the horizontal clip flag.
;*/

        XOR     AH,AH                           ; Assume there is no clipping
        MOV     CX,wVertLineCount
        CMP     CX,wCellWidth
        JE      @f
        NOT     AH                      ; All 1s mean there is clipping

@@:
        MOV     bHorizontalClipMask,AH
        MOVZX   EBX,xcoordStart
        MOVSX   EDI,wLeftLineOffset
        SUB     EBX,EDI
        MOVZX   EDI,ycoordStart
        MOV     ECX,wTopLineOffset
        SUB     EDI,ECX
        MOVZX   ECX,wCellHeight
        ADD     EDI,ECX
        DEC     EDI
        MOV     CX,AX
        MOV     AX,wCellWidth
        OR      CH,CH                   ; Clip flag set?
        JNZ     @f                      ;  Y - Partial column, use wCellWidth
        MUL     wFullCols               ;  N - Some number of full columns

@@:
        MOV     wDest3rdIncr,EAX

;/*
;** The drawing functions use addresses in an upward sequence.  Hence the need
;** to have the direction flag cleared.
;*/

        CLD

;/*
;** The following label is the return point for all the device-dependent
;** drawing functions.  Most of them terminate with a JMP instead of a RET.
;*/

        PUBLIC  Next_attribute_cluster2
Next_attribute_cluster2::
        CMP     ESP,pReturnAddress      ; Have we exhausted the pseudocode?
        JNE     ProcessAStream2
        CLD                             ; Direction must be clear on return
        JMP     IA_Exit                ; If so return to the scanner.
ALIGN 4

        PUBLIC  ProcessAStream2
ProcessAStream2::
        POP     ESI                     ; Get the new attribute set.
ifdef DBCS  ; DBCS AVio attribute support    ;IBMJ
 CALL GetAVioAttributes ; ESI = AVio attribute bits
endif;DBCS        ;IBMJ
        PUSH    EBX                     ; Save coordinate
ifndef JFIX        ;IBMJ
        MOV     EAX,ESI
        AND     EAX,(AVioReverseVideoMask OR AVioTransparentMask)
        CMP     EAX,AVioReverseVideoMask        ; Check for Opaque with
                                                ; Reverse Video
        JNZ     Set_hardware_colors2
else ;JFIX  ; PTR SM88864 @ PM20 implementation    ;IBMJ
 TEST ESI,AVioReverseVideoMask
 JZ Set_hardware_colors2
endif;JFIX        ;IBMJ
        XCHG    EAX,ESI                 ; For that case we do the reversing
        MOV     BL,AH                   ;   by just swapping foreground and
        SHR     AH,4                    ;   background color attributes.
        SHL     BX,4
        OR      AH,BL
        XCHG    EAX,ESI                 ; Put colors back in ESI

        PUBLIC  Set_hardware_colors2
Set_hardware_colors2::
        MOV     ECX,ESI                 ; Colors to CH
        MOV     CL,CH
        SHR     CH,4                    ; CH = background color and
        AND     ECX,0F0Fh               ; CL = foreground color
ifdef IBMJ  ; IBM-Japan Vio attribute support    ;IBMJ
 CMP FormatID,FORMATID_IBMJ_MONO
 JNE get_colors2

 XOR EAX,EAX   ; Use specified physical color
 CMP AH,CH   ;   for IBM-Japan mono vio mode.
 SBB AH,0   ; 
 CMP AL,CL   ; AH = 0FFh if background != 0
 SBB AL,0   ; AL = 0FFh if foreground != 0
 AND AH,bCellColor  ;        AH -- Background
 AND AL,bCellColor  ;        AL -- Foreground
 JMP have_colors2

get_colors2:
endif;IBMJ        ;IBMJ
        XOR     EBX,EBX
        MOV     BL,CH                   ; EBX = background color
        MOV     AH,ColorMap[EBX]        ; Set hardware background color
        MOV     BL,CL                   ; EBX = foreground index
        MOV     AL,ColorMap[EBX]        ; Set hardware foreground color
have_colors2:        ;IBMJ
        MOV     wColor,AX               ; save colors
        TEST    ESI,AVioUnderscoreMask
        JZ      Set_up_registers2
        MOV     EAX,wTopLineOffset
        ADD     EAX,wScanLineCount
        MOVZX   ECX,wCellHeight
        CMP     EAX,ECX
        JZ      Set_up_registers2
        AND     ESI,(NOT AVioUnderscoreMask)

        PUBLIC  Set_up_registers2
Set_up_registers2::
        XOR     ECX,ECX                 ; Zero reference value
        MOV     EAX,AVioUnderscoreMask  ; If underscoring,BL => 0FFh else 0.
        AND     EAX,ESI
        CMP     ECX,EAX
        SBB     EBX,EBX
        MOV     bUnderscoreMask,BL
        MOV     EAX,ESI                 ; Get the previous attribute set
        MOV     ECX,ESI
        XCHG    AX,wLastAttributes      ; and preserve this attribute set for
                                        ; the next InterpretAttributes call.
        MOV     EBX,EAX                 ; Compare the old
        XOR     EBX,ESI                 ; new LCID bit fields.
        AND     EBX,AVioLCIDMask        ; Are they different?
        JZ      SameSymbolSet2

        PUBLIC  Set_up_LCID2
Set_up_LCID2::
        AND     ESI,AVioLCIDMask                ; If so set up DS for the new
        MOV     EBX,wSymbolSetSelectors[ESI*4]
        OR      EBX,EBX                         ; Is this selector usable?
        JNZ     ValidSymbolSetSelector2

;/*
;** If we don't have a usable selector, we use the selector for the base symbol
;** set, and map all of the glyph points for that LCID to a surrogate glyph.
;*/

        CLD                                     ; Set up to scan forward
        MOV     EBX,SURROGATE_CHARACTER         ; through the glyphs on the
        MOV     ESI,ESP                         ; stack.
        ADD     ESI,4                           ; We pushed EBX above,must
                                                ; counter!
                                                ; ESI --> Syllables on stack

        PUBLIC  Check_next_syllable2
Check_next_syllable2::
        LODSD                                   ; Get next syllable
        CMP     AX,-2
        JA      Found_a_control_marker2         ; -1 => Control marker
        JE      Check_next_syllable2            ; -2 => End of row action
ifndef DBCS        ;IBMJ
        MOV     [ESI-4],BX                      ; Replace syllable with a
                                                ; surrogate character
endif ;DBCS        ;IBMJ
        JMP     Check_next_syllable2
ALIGN 4

        PUBLIC  Found_a_control_marker2
Found_a_control_marker2::
        MOV     EBX,wSymbolSetSelectors[0]      ; Substitute the selector for
                                                ; the base symbol set.

        PUBLIC  ValidSymbolSetSelector2
ValidSymbolSetSelector2::
        MOV     wselfontsave,EBX                ; Point to symbol set to use
        MOV     ESI,EBX

;/*
;** Here we set up the data which characterizes the font which is becoming
;** active.
;*/

        MOVZX   EBX,[ESI].FOCAFONT.ff_fmMetrics.foca_usLastChar
        INC     EBX
        MOV     wGlyphSpan,EBX
        MOVZX   EBX,[ESI].FOCAFONT.ff_fmMetrics.foca_usFirstChar
        MOV     wFirstGlyph,EBX
        MOVZX   EBX,[ESI].FOCAFONT.ff_fmMetrics.foca_usDefaultChar
        MOV     wDefaultGlyph,EBX
        MOV     ESI,ECX

        PUBLIC  SameSymbolSet2
SameSymbolSet2::
        MOV     EAX,1                   ; Assume opaque cells.
        TEST    ESI,AVioTransparentMask ; Opaque cells?
        JZ      Set_modes2              ;  Y - Indicate it
        MOV     EAX,0                   ;  N - Indicate not opaque

        PUBLIC  Set_modes2
Set_modes2::
        MOV     wFunction,AX            ; Save function
        POP     EBX                     ; Restore coordinate
        JMP     AVioDrawText
ALIGN 4

        PUBLIC  IA_Exit
IA_Exit::
        RET                             ; This is not the normal exit point.
                                        ; Normally, one of the drawing
                                        ; functions JMPs back out.

ENDIF ; VGA

InterpretAttributes ENDP

        OPTION  PROLOGUE:PrologueDef
        OPTION  EPILOGUE:EpilogueDef

;/*
;**                      Ega HiRes Drawing Functions
;**                      ---------------------------
;**
;** The functions below draw text on the EGA adapter in its High Resolution
;** color mode.  They provide the low level semantics for materializing all
;** of the Vio and AVio text attributes on the screen.  The functions are
;** driven by a stream of pseudocode syllables placed on the stack by the
;** ScanCells routine, and by their initial register state as specified by
;** the InterpretAttributes routine.
;**
;** This table defines how the drawing functions use the register set:
;**---------------------------------------------------------------+
;** Reg |   VONHC    |   AONVC      |   AXNVC      |  OHC & XHC   |
;**---------------------------------------------------------------|
;** AH  | Scan Lines | Scan Lines   | Scan Lines   | Scan Lines   |
;**     |            |              |              |              |
;** AL  |            |  -------     |  -------     | Clip Mask    |
;**     |            |              |              |              |
;** BH  | ---------- | Reverse Video| Reverse Video| Reverse Video|
;**     |            |              |              |              |
;** BL  | ---------- | UnderScore   | UnderScore   | UnderScore   |
;**     |            |              |              |              |
;** CX  | 2nd Incr.  | 2nd Incr.    | 2nd Incr.    |  -------     |
;**     |            |              |              |              |
;** DX  | 1st Incr.  | 1st Incr.    | 1st Incr.    | 1st Incr.    |
;**     |            |              |              |              |
;** SI  |  -------   |  -------     |  -------     |  -------     |
;**     |            |              |              |              |
;** DI  | Dest. Addr | Dest. Addr.  | Dest. Addr.  | Dest. Addr.  |
;**     |            |              |              |              |
;** DS  | Symbol Seg.| Symbol Seg.  | Symbol Seg.  | Symbol Seg.  |
;**     |            |              |              |              |
;** ES  | Dest.  Seg.| Dest.  Seg.  | Dest.  Seg.  | Dest.  Seg.  |
;*/


;/*
;** The dashed lines marks registers whose content is destroyed by the function.
;** The text strings denote quantities they expect in particular registers at
;** entry time.  Except for DI, those initial values are preserved through exit
;** time.
;**
;**   Parameter     Interpretation
;**   ------------- -----------------------------------------------------------
;**   Scan Lines    The number of scan lines to draw for a single image cell.
;**
;**   Clip Mask     Horizontal clipping mask applied against each scan line.
;**
;**   Reverse Video 0 => Normal Video;  0FFh => Reversed Foreground/Background.
;**
;**   UnderScore    0 => No Underscore; 0FFh => Underscore the cell image.
;**
;**   2nd Incr.     DI increment to move to the top of the next cell image.
;**
;**   1st Incr.     DI increment to move to the next scan line of current cell.
;**
;**   Dest. Addr    Initial scan line address.  This will be altered by the code.
;**
;**   Symbol Seg.   Segment which contains the symbol set(s) for drawing.
;**
;**   Dest.  Seg.   Segment which contains the destination area.
;**
;**
;** The full function names were abreviated for use as column headings.  The
;** correspondence between the two is:
;**
;**     Heading       Full Name            Domain
;**     -------       -------------------  ---------------------------------
;**      VONHC        VioDrawOpaqueNHC     Opaque Vio cells with no horizontal
;**                                        clipping, may be vertically clipped.
;**
;**      AONVC        AVioDrawOpaqueNVC    Opaque AVio cells which may be
;**                                        clipped vertically.
;**
;**      AXNVC        AVioDrawXparentNVC   Transparent AVio cells which may
;**                                        be clipped vertically
;**
;**      OHC          AVioDrawOpaqueHC     Vio and AVio opaque cells which
;**                                        must be clipped horizontally.
;**
;**      XHC          AVioDrawXparentHC    AVio transparent cells which must
;**                                        be clipped horizontally.
;**
;**
;** Pseudo Code Conventions
;** -----------------------
;**
;** Each of the drawing functions consumes a stream of pseudo code syllables by
;** POPing words off the SS:SP stack.  Three kinds of syllables exist:
;**
;**
;**       CodeValue  >=  0    Assumed to be the starting address within a
;**                           symbol set of the scan lines for a character
;**                           image.
;**
;**       CodeValue  <  -1    Request to apply a tertiary increment to EDI.
;**                           This moves EDI to the beginning of the next
;**                           cell row.
;**
;**       CodeValue  == -1    This signals an attribute change.  It will
;**                           usually be followed by a WORD containing
;**                           the new attribute information in AVio format.
;**                           When a drawing function encounters this signal
;**                           it exits with a JMP to Next_attribute_cluster.
;**
;** NB: This coding scheme requires that Symbol Set offsets must be less
;**     than 8000h.
;**
;** InterpretAttributes takes care of setting up the proper EGA environment
;** for new attribute sets and invoking the proper drawing function.  Usually
;** that invocation consists of a JMP to the appropriate function.  That
;** function will, in turn JMP to Next_attribute_cluster when it reaches the
;** next -1 code syllable.
;**
;** The exception to this rule is DrawOpaqueHC.  There the invocation is
;** by call/ret.  This is necessary to implement the two passes that are
;** sometimes necessary to horizontally clip opaque text.
;**
;** When all the pseudo code has been exhausted, InterpretAttributes will
;** do a RET to the scanning function which created the pseudo code.
;*/

 
        SUBTITLE InvertClippedRect
        PAGE +

;/***************************************************************************
;*
;* FUNCTION NAME = InvertClippedRect 
;*
;* DESCRIPTION   = This routine does the display work for the InvertTextCursor 
;*                 routine.  It is driven by enumerate_clip_rects.             
;*                                                                             
;* INPUT         = ESI is the stack frame address for InvertTextCursor.       
;*                 EBX is the address of a rectangle structure which defines a                                                            
;*                        component of the region to be inverted.                                                                         
;*                                                                             
;*                 Registers Destroyed:                                                                     
;*                       AX, BX, CX, DX, DI, ES                                                             
;*                 Registers Preserved:                                                                     
;*                       BP, SI                                                                             
;*                                                                             
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        OPTION  PROLOGUE:NONE
        OPTION  EPILOGUE:NONE

ALIGN 4
InvertClippedRect PROC SYSCALL PUBLIC,hdc:HDC,pDDC:DWORD,
                         afFunN:WORD,lpBitmapBits:DWORD,
                         wDestHeight:WORD,wDestBMWidth:WORD,
                         wXCoord:WORD,wYCoord:WORD,
                         wHeight:WORD,wWidth:WORD

        LOCAL   fSomethingDrawn :WORD
        LOCAL   drBounds        :RECTL

;/*
;** First we save the stack frame for enumerate_clip_rects and set the frame
;** pointer to reference the local environment of InvertTextCursor.
;*/

        PUSH    EBP
        MOV     EBP,ESI
        MOV     fSomethingDrawn,1       ; to denote a non-null vis region

;/*
;** Now we retrieve the screen coordinates of the rectangle to invert.  For
;** convenience we map the coordinates to top left origin.
;*/

        MOVZX   EDI,wDestHeight
        MOV     EDX,EDI
        SUB     EDI,[EBX].RECTL.rcl_yBottom
        SUB     EDX,[EBX].RECTL.rcl_yTop
        MOV     ECX,[EBX].RECTL.rcl_xLeft
        MOV     ESI,[EBX].RECTL.rcl_xRight

;/*
;** If the rectangle is empty we do nothing.
;*/

        CMP     EDX,EDI
        JGE     Null_invert_rect
        CMP     ECX,ESI
        JGE     Null_invert_rect

;/*
;** Otherwise we save the coordinates on the stack and exclude the mouse cursor.
;*/

        PUSH    ESI
        PUSH    ECX
        PUSH    EDX
        PUSH    EDI
        INVOKE  far_exclude

;/*
;** Now we retrieve the coordinates and map them into a set of parameters for
;** driving the InvertRect routine.
;*/

        POP     EDI     ; ... Bottom ...
        POP     EBX     ; ... Top    ...
        POP     ECX     ; ... Left   ...
        POP     ESI     ; ... Right  ...

IFNDEF VGA      ; This is not needed for VGA drivers, as InvertScreenRect has
                ; been rewritten to deal with a variety of cell widths.

        MOVZX   EAX,wDestBMWidth
        MUL     EBX
        ADD     EAX,lpBitmapBits
        SUB     EDI,EBX

;/*
;** EDI now holds the number of scan lines involved.
;*/

        MOV     EBX,ECX
        SHR     EBX,3
        ADD     EAX,EBX

;/*
;** EAX now holds the offset to the first BYTE to be altered.
;** Now we compute the mask for the byte column.  A key assumption here is that
;** the rectangle will always fit within a single byte column.  That will always
;** be valid for the text cursor.
;*/

        XOR     EBX,EBX
        NOT     EBX
        AND     ECX,7
        SHR     BL,CL
        MOV     ECX,ESI
        DEC     ECX
        AND     ECX,7
        INC     ECX
        SHR     BH,CL
        NOT     BH
        AND     BL,BH

;/*
;** Now we've got all the information together.  After a little reshuffling to
;** get things into the correct registers we invoke InvertScreenRect.
;*/

        MOV     ECX,EDI
        MOV     EDI,EAX
        MOVZX   ESI,wDestBMWidth

ENDIF ; !VGA

        CALL    InvertScreenRect
        INVOKE  far_unexclude

        PUBLIC  Null_invert_rect
Null_invert_rect::

;/*
;** Before we return to enumerate_clip_rects, we must restore ESI and EBP to the
;** values they had on entry.
;*/

        MOV     ESI,EBP
        POP     EBP

;/*
;** enumerate_clip_rects requires a non-zero result to keep going.  A zero
;** result stops the enumeration.
;*/

        MOV     EAX,ESP

        RET

InvertClippedRect ENDP

        OPTION  PROLOGUE:PrologueDef
        OPTION  EPILOGUE:EpilogueDef

          SUBTITLE VioDrawOpaqueNHC
        PAGE +

;/***************************************************************************
;*
;* PUBLIC ROUTINE  VioDrawOpaqueNHC  
;*
;* DESCRIPTION   = Interprets pseudo code on the stack to draw Vio character
;*                 cell image which are not horizontally clipped.  NB:  This
;*                 routine exits with a JMP Next_attribute_cluster rather
;*                 than a RET.
;*
;*                 Registers Destroyed:
;*                       SI BX                                                                    
;*                 Registers Preserved:                                                           
;*                         process.                                                    
;*
;* OUTPUT        = EDI --> Top scan line of the next cell to be drawn.        
;*                 ESP --  Moves according to the pseudo code consumed by this
;*                         function.                                          
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        OPTION  PROLOGUE:NONE
        OPTION  EPILOGUE:NONE

ALIGN 4
define_CharRect_frame VioDrawOpaqueNHC

;/*
;** We first must set up the start address for the unrolled drawing code.
;** That address is based on the number of scan lines we'll be drawing.
;*/

        MOV     BL,MaxSymbolLines
        SUB     BL,AH                   ; AH is scan lines to draw.
        MOV     BH,BL                   ; Multiply BL by 3,the size of
        SHL     BL,1                    ; MOVSW add DI,DX
        ADD     BL,BH
        MOVZX   EBX,BL
        ADD     EBX,Draw_Top_Scan

;/*
;** For speed two versions of this code exist.  The first version
;** (Draw_Top_Scan, ...) is used when wTopLineOffset is zero.  Otherwise
;** we use the second version (Draw_Top_Scan2, ...).
;*/

        MOV     ESI,wTopLineOffset
        OR      ESI,ESI
        JNZ     VONHC_Vertically_clipped
        MOV     CellBLTBlock.cb_BPSaveSlot,EBP
        MOV     ESI,wDefaultGlyph
        MOV     CellBLTBlock.cb_Default_Glyph,SI
        MOV     ESI,wDest3rdIncr
        MOV     CellBLTBlock.cb_Dest_3rd_Incr,ESI
        MOV     EAX,wFirstGlyph
        MOV     EBP,wGlyphSpan
        JMP     Process_Pseudo_Code3
ALIGN 4

        PUBLIC  VONHC_Vertically_clipped
VONHC_Vertically_clipped::
        ADD     EBX,Draw_Top_Scan2-Draw_Top_Scan
        JMP     Process_Pseudo_Code2
ALIGN 4

        PUBLIC  Draw_Top_Scan
Draw_Top_Scan::
        REPT    MaxSymbolLines-1
        MOVSB
        ADD     EDI,EDX
        ENDM

        PUBLIC  Code_Pattern_Pref
Code_Pattern_Pref::
        MOVSB
        ADD     EDI,ECX

        PUBLIC  Code_Pattern_Suff
Code_Pattern_Suff::
        .ERRNZ   (Code_Pattern_Suff - Code_Pattern_Pref) - 3

;/*
;** That assumption is critical to the EBX address calculations above.
;*/

        PUBLIC  Process_Pseudo_Code3
ifndef JTUNE        ;IBMJ
Process_Pseudo_Code3::

;/*
;** If SI is non-negative, it's a glyph index.  Negative values denote
;** control actions:  -1 => a signal to return control to InterpretAttributes.
;**                   -2 => we've come to the end of a row of cell images
;**                         and must move to the beginning of the next row.
;*/

        POP     ESI                     ; Get the next code syllable.
else  ;JTUNE        ;IBMJ
 JMP Process_Pseudo_Code3
@@:
 INC EDI
Process_Pseudo_Code3::
 POP ESI
 TEST swFlags,SW_CT_DISABLE
 JNZ @F
 CMP EBX,offset Draw_Top_Scan ;          
 JNE @F    ;          
 TEST ESI,NOT EXT_CELL_SAME_CHAR
 JZ @B
@@:
 MOVSX ESI,SI
endif ;JTUNE        ;IBMJ

;/*
;** A particular font includes a span of glyphs which may not be complete.
;** That is, some valid glyph indices may Not have defined pel images.
;** The span of defined glyphs is characterized by wFirstGlyph and
;** wGlyphSpan.  Glyph indices outside this range are mapped to wDefaultGlyph.
;*/

        SUB     SI,AX                   ; The lowest defined glyph
        CMP     SI,BP                   ; The number of defined glyphs
        JNB     Substitute_or_control

        PUBLIC  VONHC_Default_substituted
VONHC_Default_substituted::
        IMUL    SI,SI,6                 ; Glyph descriptors are 6 bytes long.
        MOVZX   ESI,SI                  ; ESI = Index to proper glyph
        PUSH    EBP
        MOV     EBP,CellBLTBlock.cb_BPSaveSlot
        ADD     ESI,wselfontsave                ; ESI --> Glyph description
        MOV     ESI,DWORD ptr FONTMAP.fsCharOffset[ESI]  ; ESI = bitmap offst
        ADD     ESI,wselfontsave        ; ESI -> Character bitmap
        POP     EBP
        JMP     EBX                             ; Draw it
ALIGN 4

        PUBLIC  Substitute_or_control
Substitute_or_control::
        ADD     SI,AX
        JS      VONHC_Control_Syllable          ; Control syllable - handle it
        MOVZX   ESI,CellBLTBlock.cb_Default_Glyph       ; Glyph not defined,
        JMP     VONHC_Default_substituted               ; use default glyph
ALIGN 4

        PUBLIC  VONHC_Control_Syllable
VONHC_Control_Syllable::
ifndef DBCS        ;IBMJ
        INC     SI                      ; -1 => An attribute or return addr.
        JZ      Exit_VONHC

else ;DBCS  ; DBCS device font support     ;IBMJ
 CMP SI,-1   ; -1 => an attribute or return addr.
 JE Exit_VONHC
 CMP SI,-2   ; -2 => goto the next row
 JE vonhc_next_row
 CALL GetFontOffset8  ; get DBCS font image offset
 JMP EBX
vonhc_next_row:
endif;DBCS        ;IBMJ
        ADD     EDI,CellBLTBlock.cb_Dest_3rd_Incr    ; Otherwise a cell image
                                                     ; row boundary.
        JMP     Process_Pseudo_Code3
ALIGN 4

        PUBLIC  Exit_VONHC
Exit_VONHC::
        MOV     EBP,CellBLTBlock.cb_BPSaveSlot
        JMP     Next_attribute_cluster
ALIGN 4

        PUBLIC  Draw_Top_Scan2
Draw_Top_Scan2::
        REPT    MaxSymbolLines-1
        MOVSB
        ADD     EDI,EDX
        ENDM
        MOVSB
        ADD     EDI,ECX

        PUBLIC  Process_Pseudo_Code2
Process_Pseudo_Code2::

;/*
;** If SI is non-negative, it's a glyph index.  Negative values denote
;** control actions:  -1 => a signal to return control to InterpretAttributes.
;**                   -2 => we've come to the end of a row of cell images
;**                         and must move to the beginning of the next row.
;*/

        POP     ESI     ; Get the next code syllable.

;/*
;** A particular font includes a span of glyphs which may not be complete.
;** That is, some valid glyph indices may Not have defined pel images.  The
;** span of defined glyphs is characterized by wFirstGlyph and wGlyphSpan.
;** Glyph indices outside this range are mapped to wDefaultGlyph.
;*/

        MOVSX   ESI,SI
        SUB     ESI,wFirstGlyph         ; The lowest defined glyph
        CMP     ESI,wGlyphSpan          ; The number of defined glyphs
        JNB     Substitute_or_control2

        PUBLIC  VONHC_Default_substituted2
VONHC_Default_substituted2::
        IMUL    ESI,ESI,6               ; Glyph descriptors are 6 bytes.
        ADD     ESI,wselfontsave                ; ESI --> Glyph description
        MOV     ESI,DWORD ptr FONTMAP.fsCharOffset[ESI]
                                        ; ESI --> Offset of char. bitmap
        ADD     ESI,wselfontsave        ; ESI --> Ch. bitmap
        ADD     ESI,wTopLineOffset              ; ESI --> First line of
                                                ;         character bitmap to
                                                ;         be used
        JMP     EBX                     ; Draw it
ALIGN 4

        PUBLIC  Substitute_or_control2
Substitute_or_control2::
        ADD     ESI,wFirstGlyph
        JS      VONHC_Control_Syllable2 ; Control syllable
        MOV     ESI,wDefaultGlyph
        JMP     VONHC_Default_substituted2
ALIGN 4

        PUBLIC  VONHC_Control_Syllable2
VONHC_Control_Syllable2::
ifndef DBCS        ;IBMJ
        INC     ESI                     ; -1 => An attribute or return addr.
        JZ      Exit_VONHC2

else ;DBCS  ; DBCS device font support     ;IBMJ
 CMP ESI,-1   ; -1 => an attribute or return addr.
 JE Exit_VONHC2
 CMP ESI,-2   ; -2 => goto the next row
 JE vonhc_next_row2
 CALL GetFontOffset8  ; get DBCS font image offset
 ADD ESI,wTopLineOffset
 JMP EBX

vonhc_next_row2:
endif;DBCS        ;IBMJ
        ADD     EDI,wDest3rdIncr        ; Otherwise a cell image row boundary.
        JMP     Process_Pseudo_Code2
ALIGN 4

        PUBLIC  Exit_VONHC2
Exit_VONHC2::
        JMP     Next_attribute_cluster
ALIGN 4

VioDrawOpaqueNHC ENDP

        OPTION  PROLOGUE:PrologueDef
        OPTION  EPILOGUE:EpilogueDef

ifndef DBCS ; Replaced for DBCS device font / AVio attribute support. ;IBMJ

        SUBTITLE AVioDrawOpaqueNVC
        PAGE +

;/***************************************************************************
;*
;* FUNCTION NAME = AVioDrawOpaqueNVC 
;*
;* DESCRIPTION   = This routine draws the image of a stream of AVio cells which
;*                 may require vertical clipping, but not horizontal clipping. 
;*                 NB:  This routine exits with a JMP Next_attribute_cluster   
;*                 rather than a RET.                                          
;*                                                                             
;*                 Registers Destroyed: 
;*                       AL CX SI                                              
;*                 Registers Preserved:                                        
;*                       BP                                                    
;*                                                                             
;* INPUT         = AH  --  The number of scan lines in a cell images.                  
;*                 BL  --  The Underscore Mask  --  OR'd with the last scan line.                                                                  
;*                 ECX --  The secondary increment for EDI.  It's used to move EDI to                                                              
;*                         the top scan line of the next image cell on the right.                                                                  
;*                 EDX --  The primary increment for EDI.  It's used to move EDI down                                                              
;*                         to the next scan line in the current image cell.                                                                        
;*                 EDI --> Destination.  It points to the top byte of the first image                                                              
;*                         cell to be drawn over.                                                                                                  
;*                 ESP --> Pseudocode.  This points to the next pseudo code syllable to                                                            
;*                         process.                                                                                                                
;*                                                                             
;* OUTPUT        = EDI --> Points to the top scan line of the next cell to be drawn.   
;*                 ESP --> Moves according to the pseudocode consumed by this function.
;*                                                                             
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

        OPTION  PROLOGUE:NONE
        OPTION  EPILOGUE:NONE

ALIGN 4
define_CharRect_frame AVioDrawOpaqueNVC

        PUBLIC  NextAVioOpaqueNVCCell
NextAVioOpaqueNVCCell::
        POP     ESI                      ; SI = Pseudocode syllable
        MOVSX   ESI,SI
        OR      ESI,ESI
        JS      AVioOpaqueNVCControl

;/*
;** A particular font includes a span of glyphs which may not be complete.
;** That is, some valid glyph indices may Not have defined pel images.  The
;** span of defined glyphs is characterized by wFirstGlyph and wGlyphSpan.
;** Glyph indices outside this range are mapped to wDefaultGlyph.
;*/

        SUB     ESI,wFirstGlyph         ; The lowest defined glyph
        CMP     ESI,wGlyphSpan          ; The number of defined glyphs
        JB      AONVC_No_substitution
        MOV     ESI,wDefaultGlyph       ; Substitution relative to wFirst

        PUBLIC  AONVC_No_substitution
AONVC_No_substitution::
        IMUL    ESI,ESI,6               ; Glyph descriptors are 6 bytes.
        ADD     ESI,wselfontsave                ; ESI --> Glyph description
        MOV     ESI,DWORD ptr FONTMAP.fsCharOffset[ESI]
                                        ; ESI --> Offset of char. bitmap
        ADD     ESI,wselfontsave        ; ESI --> Character bitmap
        ADD     ESI,wTopLineOffset
        MOVZX   ECX,AH
        DEC     ECX
        JECXZ   LastAVioOpaqueNVCScanLine

        PUBLIC  NextAVioOpaqueNVCScanLine
NextAVioOpaqueNVCScanLine::
        MOVSB
        ADD     EDI,EDX
        LOOP    NextAVioOpaqueNVCScanLine

        PUBLIC  LastAVioOpaqueNVCScanLine
LastAVioOpaqueNVCScanLine::
        LODSB
        OR      AL,BL
        STOSB
        ADD     EDI,wDest2ndIncr
        JMP     NextAVioOpaqueNVCCell
ALIGN 4

        PUBLIC  AVioOpaqueNVCControl
AVioOpaqueNVCControl::
        INC     ESI                     ; -1 => an attribute or return addr.
        JZ      Exit_ANVC
        ADD     EDI,wDest3rdIncr        ; Otherwise a cell image row boundary.
        JMP     NextAVioOpaqueNVCCell
ALIGN 4

        PUBLIC  Exit_ANVC
Exit_ANVC::
        JMP     Next_attribute_cluster
ALIGN 4

AVioDrawOpaqueNVC   ENDP

        OPTION  PROLOGUE:PrologueDef
        OPTION  EPILOGUE:EpilogueDef

endif;not DBCS        ;IBMJ

        SUBTITLE AVioDrawXparentNVC
        PAGE +

;/***************************************************************************
;*
;* FUNCTION NAME = AVioDrawXparentNVC    
;*
;* DESCRIPTION   = This routine draws the image of a stream of transparent AVio 
;*                 cells whic may need to be clipped vertically, but not        
;*                 horizontally.  NB:  This routine exits with a JMP            
;*                 Next_attribute_cluster rather than a RET.                    
;*                                                                              
;*                 Registers Destroyed:                                                              
;*                       AL SI                                                                       
;*                 Registers Preserved: 
;*                       BL CX          
;*
;* INPUT         = AH  --  The number of scan lines in a cell image.                   
;*                 BH  --  Reverse Video toggle -- XOR'd with each scan line.          
;*                 BL  --  The Underscore Mask -- Or'd with the last scan line.        
;*                 ECX --  The secondary increment for EDI.  It's used to move EDI to  
;*                         the top scan line of the next image cell on the right.      
;*                 EDX --  The primary increment for EDI.  It's used to move EDI down  
;*                         to the next scan line in the current image cell.            
;*                 EDI --> Destination.  It points to the top byte of the first image  
;*                         cell to be drawn over.                                      
;*                 ESP --> Pseudocode.  This points to the next pseudo code syllable to
;*                         process.                                                    
;*
;*
;* OUTPUT        = EDI --> Top scan line of the next cell to be drawn.                 
;*                 ESP --> Moves according to the pseudocode consumed by this function.
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        OPTION  PROLOGUE:NONE
        OPTION  EPILOGUE:NONE

ALIGN 4
define_CharRect_frame AVioDrawXparentNVC

        INC     ECX
        INC     EDX
        XCHG    ECX,EDX
        MOV     wDest2ndIncr,EDX
        MOV     EDX,EGA_BASE+GRAF_ADDR+1
        MOV     bUnderscoreMask,BL

        PUBLIC  NextAVioXparentNVCCell
NextAVioXparentNVCCell::
        POP     ESI
        MOVSX   ESI,SI
        OR      ESI,ESI
        JS      AVioXparentNVCControl

;/*
;** A particular font includes a span of glyphs which may not be complete.
;** That is, some valid glyph indices may Not have defined pel images.
;** The span of defined glyphs is characterized by wFirstGlyph and
;** wGlyphSpan.  Glyph indices outside this range are mapped to wDefaultGlyph.
;*/

        SUB     ESI,wFirstGlyph         ; The lowest defined glyph
        CMP     ESI,wGlyphSpan          ; The number of defined glyphs
        JB      AXNVC_N0_substitution
        MOV     ESI,wDefaultGlyph       ; Substitution relative to wFirst

        PUBLIC  AXNVC_N0_substitution
AXNVC_N0_substitution::
        IMUL    ESI,ESI,6               ; Glyph descriptors are 6 bytes.
        ADD     ESI,wselfontsave        ; ESI --> Glyph descriptions, sort of
        MOV     ESI,DWORD ptr [ESI].FONTMAP.fsCharOffset
                                        ; ESI --> Offset of char bitmap
        ADD     ESI,wselfontsave        ; ESI --> Char bitmap
        ADD     ESI,wTopLineOffset      ; ESI --> First line of char.
                                        ;         bitmap to use
        MOV     BL,AH                   ; BL = No. of scan lines in cell

        PUBLIC  NextAVioXparentNVCScanLine
NextAVioXparentNVCScanLine::
        DEC     BL
        JZ      LastAVioXparentNVCScanLine
        LODSB                                   ; Get pattern
        XOR     AL,BH                           ; XOR it with rev. vid. tgl.
        OUT     DX,AL                           ; Set VGA bitmask

;/*
;** The XCHG instruction issues a read of the video address, which
;** latches it in the VGA, then it issues a write which causes the
;** value in AL to be combined with the contents of the latches.
;*/

        XCHG    AL,[EDI]                ; Combine it with what is on the scrn.
        ADD     EDI,ECX
        JMP     NextAVioXparentNVCScanLine
ALIGN 4

        PUBLIC  LastAVioXparentNVCScanLine
LastAVioXparentNVCScanLine::
        LODSB
        XOR     AL,BH
        OR      AL,bUnderscoreMask
        OUT     DX,AL
        XCHG    AL,[EDI]
        ADD     EDI,wDest2ndIncr
ifdef DBCS  ; DBCS AVio attrubutes support    ;IBMJ

 TEST wAVioAttributes,AVioHorizontalGridMask OR AVioVerticalGridMask
 JZ NextAVioXparentNVCCell

 PUSH EBX
 MOV EBX,ECX   ; EBX = primary increment + 1
 DEC EDI   ; EDI = cell origin address
 CALL AVioDrawGrid8  ; Draw grid lines
 ADD EDI,wDest2ndIncr
 POP EBX

endif;DBCS        ;IBMJ
        JMP     NextAVioXparentNVCCell
ALIGN 4

        PUBLIC  AVioXparentNVCControl
AVioXparentNVCControl::
ifndef DBCS        ;IBMJ
        INC     ESI                     ; -1 => an attribute or return addr.
        JZ      Exit_AXNVC
else ;DBCS  ; DBCS device font support     ;IBMJ

 CMP ESI,-1   ; -1 => an attribute or return addr.
 JE Exit_AXNVC
 CMP ESI,-2   ; -2 => goto the next row
 JE axnvc_next_row
 CALL GetFontOffset8  ; get DBCS font image offset
 ADD ESI,wTopLineOffset
 MOV BL,AH
 JMP NextAVioXparentNVCScanLine

axnvc_next_row:
endif;DBCS        ;IBMJ
        ADD     EDI,wDest3rdIncr        ; Otherwise a cell image row boundary.
        JMP     NextAVioXparentNVCCell
ALIGN 4

        PUBLIC  Exit_AXNVC
Exit_AXNVC::
        MOV     EDX,ECX
        DEC     EDX
        DEC     wDest2ndIncr
        MOV     ECX,wDest2ndIncr
        MOV     BL,bUnderscoreMask
        JMP     Next_attribute_cluster
ALIGN 4

AVioDrawXparentNVC   ENDP

        OPTION  PROLOGUE:PrologueDef
        OPTION  EPILOGUE:EpilogueDef

        SUBTITLE AVioDrawXparentHC
        PAGE +

;/***************************************************************************
;*
;* FUNCTION NAME = AVioDrawXparentHC     
;*
;* DESCRIPTION   = This routine draws a stream of cells which need to be        
;*                 clipped horizontally.  NB:  This routine exits with a JMP    
;*                 Next_attribute_cluster rather than a RET.                    
;*                                                                              
;*                 Registers Destroyed:                                                              
;*                       AL SI                                                                       
;*                 Registers Preserved: 
;*                       BL CX          
;*
;* INPUT         = AH  --  The number of scan lines in a cell image.                   
;*                 BH  --  Reverse Video toggle -- XOR'd with each scan line.          
;*                 BL  --  The Underscore Mask -- Or'd with the last scan line.        
;*                 ECX --  The secondary increment for EDI.  It's used to move EDI to  
;*                         the top scan line of the next image cell on the right.      
;*                 EDX --  The primary increment for EDI.  It's used to move EDI down  
;*                         to the next scan line in the current image cell.            
;*                 EDI --> Destination.  It points to the top byte of the first image  
;*                         cell to be drawn over.                                      
;*                 ESP --> Pseudocode.  This points to the next pseudo code syllable to
;*                         process.                                                    
;*
;*
;* OUTPUT        = EDI --> Top scan line of the next cell to be drawn.                 
;*                 ESP --> Moves according to the pseudocode consumed by this function.
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        OPTION  PROLOGUE:NONE
        OPTION  EPILOGUE:NONE

ALIGN 4
define_CharRect_frame AVioDrawXparentHC

        INC     wDest1stIncr            ; Adjust the EDI increment to match
                                        ; the needs of this routine.
        MOV     CL,AH                   ; LineCount for the top cell image.
        MOV     CH,AL                   ; Since we'll be using AL for image
                                        ; lines
        MOV     DX,EGA_BASE+GRAF_ADDR+1 ; Set up DX for OUT's to GRAF_BIT_MASK
                                        ; We assume GRAF_ADDR has been set to
                                        ; point to GRAF_BIT_MASK.
ifdef DBCS  ; DBCS AVio attrubutes support    ;IBMJ
 MOV wDestOffsetSave,EDI ; Save intial cell address.
endif;DBCS        ;IBMJ

        PUBLIC  NextHCCell
NextHCCell::
        POP     ESI                     ; Get the next code syllable.
        MOVSX   ESI,SI
        OR      ESI,ESI
        JS      HCControl               ; Is it a control syllable?

;/*
;** A particular font includes a span of glyphs which may not be complete.
;** That is, some valid glyph indices may Not have defined pel images.  The
;** span of defined glyphs is characterized by wFirstGlyph and wGlyphSpan.
;** Glyph indices outside this range are mapped to wDefaultGlyph.
;*/

        SUB     ESI,wFirstGlyph         ; The lowest defined glyph
        CMP     ESI,wGlyphSpan          ; The number of defined glyphs
        JB      AXHC_No_substitution
        MOV     ESI,wDefaultGlyph       ; Substitution relative to wFirst

        PUBLIC  AXHC_No_substitution
AXHC_No_substitution::
        IMUL    ESI,ESI,6                       ; Glyph descriptors are 6 bytes.
        ADD     ESI,wselfontsave                ; ESI --> Glyph description
        MOV     ESI,DWORD ptr FONTMAP.fsCharOffset[ESI]
                                        ; ESI --> Character bitmap offset
        ADD     ESI,wselfontsave        ; ESI -> Character bitmap
        ADD     ESI,wTopLineOffset              ; ESI --> First line of bitmap

                                        ; If not copy a cell image to the
NextHCScanLine:                         ; destination bitmap.
        DEC     CL
        JZ      LastHCScanLine
        LODSB                           ; Load a scan line.
        XOR     AL,BH                   ; Invert it if we're doing reverse v
        AND     AL,CH                   ; Clip the line horizontally.
        OUT     DX,AL                   ; Define the pixels we're setting.
        XCHG    AL,[EDI]                ; Latch the target BYTE,merge it
                                        ; with our new stuff, and write it
                                        ; back.
        ADD     EDI,wDest1stIncr        ; Move EDI to the next target byte.
        JMP     NextHCScanLine
ALIGN 4

LastHCScanLine:                         ; Processing for the last scan line.

        LODSB
        OR      AL,BL                   ; If we're underscoring.
        XOR     AL,BH
        AND     AL,CH
        OUT     DX,AL
        XCHG    AL,[EDI]
        ADD     EDI,wDest1stIncr
        MOV     CL,AH                   ; Set the loop counter for the next
                                        ; cell image.
ifdef DBCS  ; DBCS AVio attrubutes support    ;IBMJ

 TEST wAVioAttributes,AVioHorizontalGridMask OR AVioVerticalGridMask
 JZ NextHCCell

 PUSH EBX
 MOV EBX,wDest1stIncr ; EBX = primary increment + 1
 XCHG EDI,wDestOffsetSave ; EDI = cell origin address
 CALL AVioDrawGrid8  ; Draw grid lines
 MOV EDI,wDestOffsetSave
 POP EBX

endif;DBCS        ;IBMJ
        JMP     NextHCCell
ALIGN 4

HCControl:                              ; ESI is a control value.

;/*
;** Since a sequence of horizontally clipped cells always fits
;** in a single column, the only control value we'll see is -1.
;** We won't see any -2 row boundary marks.
;*/

ifdef DBCS  ; DBCS device font support     ;IBMJ
 CMP ESI,-1   ; -1 => goto the next row
 JE axhc_next_row
 CALL GetFontOffset8  ; get DBCS font image offset
 ADD ESI,wTopLineOffset
 JMP NextHCScanLine

axhc_next_row:
endif;DBCS        ;IBMJ
        DEC     wDest1stIncr            ; Restore the EDI increment to its
                                        ; its initial value.
        MOV     AL,CH                   ; Restoring AL...
        JMP     Next_attribute_cluster
ALIGN 4

AVioDrawXparentHC   ENDP

        OPTION  PROLOGUE:PrologueDef
        OPTION  EPILOGUE:EpilogueDef

        SUBTITLE AVioDrawOpaqueHC
        PAGE +

;/***************************************************************************
;*
;* FUNCTION NAME =  AVioDrawOpaqueHC     
;*
;* DESCRIPTION   = Each call to this routine performs one of the possible       
;*                 two passes required to draw opaque cells which must be       
;*                 clipped horizontally.  NB:  This routine exits with a RET    
;*                 rather than a JMP Next_attribute_cluster.  That's to         
;*                 allow for the two-pass logic within InterpretAttributes.     
;*                                                                              
;*                 Registers Destroyed:                                                              
;*                       AL CX SI                                                                    
;*                 Registers Preserved: 
;*                       None           
;*
;* INPUT         = AH  --  The number of scan lines in an image cell.                  
;*                 BH  --  Reverse Video Mask --  Used in the two pass drawing scheme. 
;*                 BL  --  Underscore Mask -- OR'd with the last scan line.            
;*                 CX  --  The number of top lines to skip for each cell image.        
;*                 EDX --  The primary increment for EDI.  It's used to move EDI down  
;*                         to the next scan line in the current image cell.            
;*                 EDI --> Destination.  It points to the top byte of the first image  
;*                         cell to be drawn over.                                      
;*                 EBP --> Pseudocode.  This points to the next pseudo code syllable to
;*                         process.  EBP is used instead of ESP to preserve the pseudo 
;*                         code for a possible second pass.                            
;*
;*
;* OUTPUT        = EDI --> Top scan line of the next cell to be drawn.                 
;*                 EBP --> Moves according to the pseudocode processed by this function
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        OPTION  PROLOGUE:NONE
        OPTION  EPILOGUE:NONE
ALIGN 4

define_CharRect_frame AVioDrawOpaqueHC

        MOV     ECX,wTopLineOffset      ; CL will hold the top line
                                        ; offset during the code below
        INC     EDX                     ; Adjust the EDI increment to
                                        ; account for the use of XCHG
                                        ; instead of MOVSB or STOSB.

        PUBLIC  NextOHCSyllable
NextOHCSyllable::
        MOV     ESI,npinxGlyph
        ADD     ESI,4
        XCHG    ESI,npinxGlyph
        MOVSX   ESI,WORD ptr [ESI]
        OR      ESI,ESI
        JS      OHCControl

;/*
;** A particular font includes a span of glyphs which may not be complete.
;** That is, some valid glyph indices may Not have defined pel images.  The
;** span of defined glyphs is characterized by wFirstGlyph and wGlyphSpan.
;** Glyph indices outside this range are mapped to wDefaultGlyph.
;*/

        SUB     ESI,wFirstGlyph         ; The lowest defined glyph
        CMP     ESI,wGlyphSpan          ; The number of defined glyphs
        JB      AOHC_No_substitution
        MOV     ESI,wDefaultGlyph       ; Substitution relative to wFirst

        PUBLIC  AOHC_No_substitution
AOHC_No_substitution::
        IMUL    ESI,ESI,6               ; Glyph descriptors are 6 bytes.
        ADD     ESI,wselfontsave        ; ESI --> Glyph description
        MOV     ESI,DWORD ptr FONTMAP.fsCharOffset[ESI]
                                        ; ESI --> Offset of char. bitmap
        ADD     ESI,wselfontsave        ; ESI --> Char bitmap
        ADD     ESI,ECX                         ; Top lines to skip.
        MOV     CH,AH                   ; CH is the counter for the scan line

        PUBLIC  NextOHCScanLine
NextOHCScanLine::
        DEC     CH
        JZ      LastOHCScanLine
        LODSB                           ; Get character scan line
        XOR     AL,BH                   ; XOR against rev. vid. msk.
        XCHG    AL,[EDI]                ; Write it to screen
        ADD     EDI,EDX                 ; Point to next screen location
        JMP     NextOHCScanLine         ; Do next char. line
ALIGN 4

        PUBLIC  LastOHCScanLine
LastOHCScanLine::
        LODSB                           ; Last scan line of character
        OR      AL,BL                   ; Do underscore if requested
        XOR     AL,BH
        XCHG    AL,[EDI]
        ADD     EDI,EDX
        JMP     NextOHCSyllable
ALIGN 4

        PUBLIC  OHCControl
OHCControl::
ifdef DBCS  ; DBCS device font support     ;IBMJ
 CMP ESI,-1   ; -1 => goto the next row
 JE aohc_next_row
 CALL GetFontOffset8  ; get DBCS font image offset
 ADD ESI,ECX
 MOV CH,AH   ; CH is the counter for the loop.
 JMP NextOHCScanLine

aohc_next_row:
endif;DBCS        ;IBMJ
        DEC     EDX

        RET

AVioDrawOpaqueHC    ENDP

        OPTION  PROLOGUE:PrologueDef
        OPTION  EPILOGUE:EpilogueDef

        SUBTITLE SetDisplayDefaults
        PAGE +

;/***************************************************************************
;*
;* FUNCTION NAME = SetDisplayDefaults 
;*
;* DESCRIPTION   =  Puts the EGA registers into the state expected by the rest of 
;*                  PM
;*
;*                  Registers Destroyed:  
;*                        AX DX           
;*                  Registers Preserved:  
;*                        None            
;*
;* INPUT         = C Prototype:                              
;*                   void _syscall SetDisplayDefaults (void);
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

ALIGN 4
SetDisplayDefaults  PROC


        MOV     DX,EGA_BASE+SEQ_ADDR
        MOV     AL,SEQ_MAP_MASK
        MOV     AH,MM_ALL
        OUT     DX,AX
        MOV     DX,EGA_BASE+GRAF_ADDR
        MOV     AL,GRAF_DATA_ROT
        MOV     AH,DR_SET
        OUT     DX,AX
        MOV     AL,GRAF_MODE
        MOV     AH,M_PROC_WRITE OR M_DATA_READ
        OUT     DX,AX
        MOV     AL,GRAF_SET_RESET
        MOV     AH,0
        OUT     DX,AX
        MOV     AL,GRAF_ENAB_SR
        OUT     DX,AX
        MOV     AL,GRAF_BIT_MASK
        MOV     AH,0FFh
        OUT     DX,AX

;        DebugMsgKZ <Leaving SetDisplayDefaults>
;~

        RET

SetDisplayDefaults  ENDP

IFNDEF VGA    ; VGA has its own version of this later

        SUBTITLE InvertScreenRect
        PAGE +

;/***************************************************************************
;*
;* FUNCTION NAME = InvertScreenRect 
;*
;* DESCRIPTION   = This routine inverts a rectangle of pixels within a byte
;*                 column on the screen.  It's used to toggle the text     
;*                 cursor, which is guaranteed to fit within a byte column.
;*                                                                         
;*                 Registers Destroyed:                                                         
;*                       AX, CX, DI                                                             
;*                 Registers Preserved:                                                         
;*                       None                                                                   
;*                                                                         
;* INPUT         = EDI --> Address of the top byte in the column rectangle.   
;*                 BL  --  A mask for the bits to invert within the column.                                                           
;*                 ECX --  The number of rows in the rectangle.                                                                       
;*                 ESI --> Increment to advance EDI to the next row.                                                                  
;*                                                                         
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

ALIGN 4
InvertScreenRect PROC SYSCALL PRIVATE

        MOV     DX,EGA_BASE+SEQ_ADDR
        MOV     AL,SEQ_MAP_MASK
        MOV     AH,MM_ALL
        OUT     DX,AX
        MOV     DX,EGA_BASE+GRAF_ADDR
        MOV     AH,BL
        MOV     AL,GRAF_BIT_MASK
        OUT     DX,AX
        MOV     AH,MM_ALL
        MOV     AL,GRAF_SET_RESET
        OUT     DX,AX
        MOV     AL,GRAF_ENAB_SR
        OUT     DX,AX
        MOV     AL,GRAF_DATA_ROT
        MOV     AH,DR_XOR
        OUT     DX,AX

        PUBLIC  Invert_Next_Line
Invert_Next_Line::
        XCHG    AL,[EDI]
        ADD     EDI,ESI
        LOOP    Invert_Next_Line

        RET

InvertScreenRect ENDP

ELSE ; VGA

        SUBTITLE InvertScreenRect
        PAGE +

;/***************************************************************************
;*
;* FUNCTION NAME = InvertScreenRect 
;*
;* DESCRIPTION   = This routine inverts a rectangle of pixels on the screen.
;*                 It's used to toggle the text cursor.                     
;*                                                                          
;*                 Registers Destroyed:                                                          
;*                       AX, DX                                                                  
;*                 Registers Preserved:                                                          
;*                       None                                                                    
;*                                                                          
;* INPUT         = EBX  =  Top of rectangle    
;*                 ECX  =  Left of rectangle                                                            
;*                 EDI  =  Bottom of rectangle                                                          
;*                 ESI  =  Right of rectangle                                                           
;*                                                                          
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

ALIGN 4
InvertScreenRect PROC SYSCALL PRIVATE

        LOCAL   wX1:DWORD
        LOCAL   wX2:DWORD
        LOCAL   wY1:DWORD
        LOCAL   wY2:DWORD


        PUSHA                                   ; Save all regs

;/*
;** Save parameters on stack.
;*/

        MOV     wX1,ECX                         ; Save left
        MOV     wX2,ESI                         ; Save right
        MOV     wY1,EBX                         ; Save top
        MOV     wY2,EDI                         ; Save bottom

;/*
;** Setup VGA I/O ready for operation.
;*/

        MOV     DX,EGA_BASE+SEQ_ADDR            ; Sequencer regs
        MOV     AL,SEQ_MAP_MASK                 ; Map mask register
        MOV     AH,MM_ALL                       ; Data (all on)
        OUT     DX,AX                           ; Do I/O
        MOV     DX,EGA_BASE+GRAF_ADDR           ; Graphics controller regs
        MOV     AL,GRAF_MODE                    ; Graphics mode
        MOV     AH,M_PROC_WRITE OR M_DATA_READ  ; Set mode
        OUT     DX,AX                           ; Do I/O
        MOV     AL,GRAF_SET_RESET               ; Graphics set reset reg
        MOV     AH,MM_ALL                       ; All bits
        OUT     DX,AX                           ; Do I/O
        MOV     AL,GRAF_ENAB_SR                 ; Graphics snable s/r reg
        MOV     AH,0                            ; Clear data
        OUT     DX,AX                           ; Do I/O
        MOV     AL,GRAF_DATA_ROT                ; Graphics rotate and function
        MOV     AH,DR_XOR                       ; Exclusive OR
        OUT     DX,AX                           ; Do I/O

;/*
;** Calculate byte address of box to be drawn.
;*/

        MOV     EBX,wY1                 ; Get Y
        MOV     EAX,SCREEN_CBSCAN       ; Screen pitch in bytes
        MUL     EBX                     ; Result to EAX
        MOV     EBX,wX1                 ; Get X
        SHR     EBX,3                   ; Byte address
        ADD     EAX,EBX                 ; Add to line address
if SCAN_CNT EQ 768
        cmp     eax,010000h
        jb      @F
        sub     eax,010000h
@@:
endif
        ADD     EAX,pVRAMInstance        ; Point into video memory
        MOV     EDI,EAX                 ; And save in EDI

;/*
;** Calculate initial bit mask.
;*/

        MOV     EAX,wX1                 ; Get X1
        AND     EAX,0007h               ; Strip all but bit offset
        MOV     BX,08000h               ; Mask for zero offset

        PUBLIC  Mask_loop
Mask_loop::
        CMP     AX,0                    ; In right pos ?
        JZ      Done_mask               ; Go if yes
        SHR     BH,1                    ; Shift mask down
        DEC     AX                      ; Decrment AX
        JMP     Mask_loop               ; and loop
ALIGN 4

        PUBLIC  Done_mask
Done_mask::
        MOV     DX,EGA_BASE+GRAF_ADDR   ; Graphics controller address reg
        MOV     AL,GRAF_BIT_MASK        ; Graphics bit mask
        OUT     DX,AL                   ; Select bit mask register only
        MOV     DX,EGA_BASE+GRAF_ADDR+1 ; Graphics controller data reg

;/*
;** Loop to do all lines.
;*/

        MOV     ECX,wY2                 ; Get Y2
        SUB     ECX,wY1                 ; Y2 - Y1

        PUBLIC  Inv_rect_line_loop
Inv_rect_line_loop::
        PUSH    EDI                     ; Save address
        PUSH    EBX                     ; Save mask and ff

;/*
;** Loop to do all pixels along line.
;*/

        PUSH    ECX                     ; Save outer loop count
        MOV     ECX,wX2                 ; Get X2
        SUB     ECX,wX1                 ; X2 - X1
        MOV     BL,0                    ; Clear BH

        PUBLIC  Inv_rect_pixel_loop
Inv_rect_pixel_loop::

;/*
;** Accumulate pixel mask.
;*/

        OR      BL,BH                   ; OR into mask

;/*
;** Shift mask and adjust address.
;*/

        ROR     BH,1                    ; Rotate mask
        CMP     BH,080h                 ; Has it rolled over ?
        JNE     Not_new_byte            ; Go if not
        MOV     AL,BL                   ; Mask to AH
        OUT     DX,AL                   ; Do I/O to bit mask reg
        MOV     BL,0                    ; Clear mask
        MOV     AL,0FFh                 ; Data
        XCHG    AL,[EDI]                ; Read/write VGA
        INC     EDI                     ; Else bump address

        PUBLIC  Not_new_byte
Not_new_byte::

;/*
;** End loop to do all pixels outputting mask if necessary.
;*/

        LOOP    Inv_rect_pixel_loop     ; Loop for all lines
        CMP     BL,0                    ; Any remaining mask ?
        JZ      No_bits_in_mask
        MOV     AL,BL                   ; Mask to AL
        OUT     DX,AL                   ; Do I/O to bit mask reg
        MOV     BL,0                    ; Clear mask
        MOV     AL,0FFh                 ; Data
        XCHG    AL,[EDI]                ; Read/write VGA

        PUBLIC  No_bits_in_mask
No_bits_in_mask::
        POP     ECX                     ; Restore outer loop count

;/*
;** End loop to do all lines.
;*/

        POP     EBX                     ; Restore mask
        POP     EDI                     ; Restore address
        ADD     EDI,SCREEN_CBSCAN       ; Next line
        LOOP    Inv_rect_line_loop      ; Loop for all lines

;/*
;** Restore stack and return to caller.
;*/

        POPA                            ; Restore all registers


        RET

InvertScreenRect ENDP

        OPTION  PROLOGUE:NONE
        OPTION  EPILOGUE:NONE

ifndef DBCS ; Replaced for DBCS device font support   ;IBMJ

        SUBTITLE AVioDrawText
        PAGE +

;/***************************************************************************
;*
;* FUNCTION NAME = AVioDrawText  
;*
;* DESCRIPTION   = Interprets pseudo code on the stack to draw Vio character
;*                 cell images with possible horizontal clipping, but no    
;*                 underscoring.                                            
;*
;* INPUT         = EBX -- Destination X coordinate                                                                                         
;*                 EDI -- Destination Y coordinate                                
;*                 ESP -- Pseudocode pointer.  This points to the next pseudo code
;*                        syllable to process.                                    
;*                                                                                
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

ALIGN 4
define_CharRect_frame AVioDrawText


        STD                     ; Will do characters upwards
        XOR     EAX,EAX         ; No mode set
        MOV     wModeSet,AX     ; Remember no modeset
        MOV     wX,EBX          ; EBX = Destination X for this column
        MOV     wY,EDI          ; EDI = Destination Y for this column
        NOP                     ; NOP instructions will magically
        NOP                     ; align Process+pseudo_code onto a
        NOP                     ; 4 byte boundary

;/*
;** Get next value from stack into SI                                          
;** If SI is non-negative, it's a glyph index.  Negative values denote control 
;** actions:                                                                   
;**                                                                            
;**    -1 => A signal to return control to InterpretAttributes.                
;**    -2 => The end of a row of cell images has been reached.  Move to the    
;**          beginning of the next row.                                        
;*/

        PUBLIC  Process_pseudo_code
Process_pseudo_code::
        POP     ESI                     ; Fetch glyph index
        MOVSX   ESI,SI
        SUB     ESI,wFirstGlyph         ; Subtract the lowest defined glyph
        CMP     ESI,wGlyphSpan          ; Check against number of defined
                                        ; glyphs
        JB      Have_glyph_index        ; Jump if in range

;/*
;** Glyph index is out of range - use default if not control code.
;*/

        ADD     ESI,wFirstGlyph         ; Add back in lowest defined glyph
        JS      @f                      ; Signed value is control code
        MOV     ESI,wDefaultGlyph       ; Use default value
        JMP     Have_glyph_index        ; and skip to process
ALIGN 4

;/*
;** Check for -1 value meaning end of string (attribute or return)
;*/

@@:
        INC     ESI                     ; -1 = An attribute or return addr.
        JS      Next_row                ; Skip if not - assume new row code
        MOV     EBX,wX                  ; Restore EBX = dest X
        MOV     EDI,wY                  ; Restore EDI = dest Y

        JMP     Next_attribute_cluster2 ; Need to return to attribute
ALIGN 4
                                        ; processing

;/*
;** Still negative - assume -2 = new line. Bump addresses and get next code.
;*/

        PUBLIC  Next_row
Next_row::
        MOV     EAX,wDest3rdIncr        ; X decrement to start of row
        SUB     wX,EAX                  ; Adjust x
        MOVZX   EAX,wCellHeight         ; Get cell height
        ADD     wY,EAX                  ; Adjust y
        JMP     Process_pseudo_code     ; and fetch next code
ALIGN 4

;/*
;** Have a valid glyph index to process
;*/

        PUBLIC  Have_glyph_index
Have_glyph_index::

;/*
;** First, determine whether we are clear to draw 16 chars ahead without    
;** clipping.                                                               
;*/

;/*
;** Calculate character block limits into EAX, EBX, ECX, EDX
;*/

        MOV     EAX,wX          ; Get X
        MOVZX   EBX,wCellWidth  ; Get cell width
        IMUL    EBX,EBX,16      ; Calculate end of block of 16 chars
        ADD     EBX,EAX         ; Add to start position
        DEC     EBX             ; Last pos
        MOV     ECX,wY          ; Get Y
        MOVZX   EDX,wCellHeight ; Subtract cell height from Y
        NEG     EDX
        ADD     EDX,ECX
        INC     EDX             ; Top row

;/*
;** Determine whether clipped totally out.
;*/

        CMP     EBX,wClipXmin   ; Clipped out on l ?
        JL      Bclip_invis     ; Go if yes
        CMP     EAX,wClipXmax   ; Clipped out on r ?
        JGE     Bclip_invis     ; Go if yes
        CMP     ECX,wClipYmin   ; Clipped out at bottom ?
        JL      Bclip_invis     ; Go if yes
        CMP     EDX,wClipYmax   ; Clipped out at top ?
        JGE     Bclip_invis     ; Go if yes

;/*
;** Determine whether clipped totally in.
;*/

        CMP     EAX,wClipXmin   ; Clipped in on l ?
        JL      Bclip_invis     ; Go if yes
        CMP     EBX,wClipXmax   ; Clipped in on r ?
        JGE     Bclip_invis     ; Go if yes
        CMP     EDX,wClipYmin   ; Clipped in at bottom ?
        JL      Bclip_invis     ; Go if yes
        CMP     ECX,wClipYmax   ; Clipped in at top ?
        JGE     Bclip_invis     ; Go if yes

;/*
;** We are totally visible for 16 chars ahead, call routine to get going fast. 
;*/

        MOV     EAX,16                  ; Maximum character count to draw
        JMP     Draw_n_wide_noclip      ; Else jump to n wide unclipped
ALIGN 4

;/*
;** The clip window intersects some part of a 16 character string starting
;** here.  Determine whether this current character is clipped itself
;*/

        PUBLIC  Bclip_invis
Bclip_invis::

;/*
;** Recalulate character box right edge.
;*/

        MOVZX   EBX,wCellWidth          ; Get cell width
        ADD     EBX,EAX                 ; Add to start position
        DEC     EBX                     ; Last pos

;/*
;** Determine whether this character is clipped totally out.
;*/

        CMP     EBX,wClipXmin           ; Clipped out on l ?
        JL      Clipped_out              ; Go if yes
        CMP     EAX,wClipXmax           ; Clipped out on r ?
        JGE     Clipped_out              ; Go if yes
        CMP     ECX,wClipYmin           ; Clipped out at bottom ?
        JL      Clipped_out              ; Go if yes
        CMP     EDX,wClipYmax           ; Clipped out at top ?
        JGE     Clipped_out             ; Go if yes

;/*
;** Determine whether clipped totally in.
;*/

        CMP     EAX,wClipXmin           ; Clipped in on l ?
        JL      Clip_not_in             ; Go if yes
        CMP     EBX,wClipXmax           ; Clipped in on r ?
        JGE     Clip_not_in             ; Go if yes
        CMP     EDX,wClipYmin           ; Clipped in at bottom ?
        JL      Clip_not_in             ; Go if yes
        CMP     ECX,wClipYmax           ; Clipped in at top ?
        JGE     Clip_not_in             ; Go if yes

;/*
;** We are totally visible for this char, call routine to draw it.  
;*/

        MOV     EAX,1                   ; Maximum character count to draw
        JMP     Draw_n_wide_noclip      ; Else jump to n wide unclipped
ALIGN 4

;/*
;** We have a character that needs some clip attention - call the routine.
;*/

        PUBLIC  Clip_not_in
Clip_not_in::
        JMP     Draw_n_wide_clip        ; Jump to draw clipped
ALIGN 4

;/*
;** We have a character that is totally clipped out - update ptrs and continue
;*/

        PUBLIC  Clipped_out
Clipped_out::

;/*
;** Bump horizontal address by cell width.
;*/

        MOVZX   EAX,wCellWidth          ; Get cell width
        ADD     wX,EAX                  ; Bump X value

;/*
;** test for horizontal clip (?) - move to next row if yes.
;*/

        CMP     bHorizontalClipMask,0   ; Is this text clipped?
        JE      Process_pseudo_code     ;  N - Return to fetch next code
        JMP     Next_row                ;  Y - Return to fetch next code
ALIGN 4

;/*
;** Draw any width character on arbitrary boundary clipped.
;**
;** Characters of any width any any boundary and opaque or transparent are
;** drawn clipped by this code. Character drawing will continue until either
;** the block count reaches zero, or a non-glyph index value is found on the
;** stack.
;*/

        PUBLIC  Draw_n_wide_clip
Draw_n_wide_clip::

;/*
;** Calculate Byte address of first character to be drawn.
;*/

        MOV     EBX,wY                  ; Get y
        MOV     EAX,SCREEN_CBSCAN       ; Screen pitch in bytes
        MUL     EBX                     ; Result to EAX
        MOV     EBX,wX                  ; Get x
        CMP     EBX,-1
        JLE     X_neg                   ; X negative
        SHR     EBX,3                   ; Byte address
        ADD     EAX,EBX                 ; Add to line address
        JMP     Sv_byte_addr
ALIGN 4

        PUBLIC  X_neg
X_neg::
        DEC     EAX

        PUBLIC  Sv_byte_addr
Sv_byte_addr::
if SCAN_CNT EQ 768
        mov     ecx,pVRAMInstance
        cmp     lpBitmapBits,ecx
        jne     not_vram
        cmp     eax,010000h
        jb      not_vram
        sub     eax,010000h
not_vram:
endif
        ADD     EAX,lpBitmapBits        ; Point to video memory
        MOV     wByteAddr,EAX           ; and save

;/*
;** Calculate update mask and bit address.
;*/

        MOV     AX,00FFh
        MOV     CX,wCellWidth           ; Get cell width
        ROR     AX,CL                   ; N bits to AH
        MOV     AL,0
        MOV     ECX,wX                  ; Get x
        AND     ECX,0007h               ; Bit address
        MOV     wBitAddr,CX
        SHR     AX,CL                   ; Shift down to align
        MOV     wMask,AX                ; Store mask

;/*
;** Calculate font address for glpyh.
;*/

        MOVSX   ESI,SI
        IMUL    ESI,ESI,6               ; Glyph entries are 6 bytes
        ADD     ESI,wselfontsave        ; ESI --> Glyph description
        MOV     ESI,[ESI].FONTMAP.fsCharOffset.VIO_FONT_ENTRIES.fe_dBits
                                        ; ESI --> Character data offset
        ADD     ESI,wselfontsave        ; ESI -> Character bitmap
        MOVZX   EBX,wCellHeight         ; Load EBX with char height
        LEA     ESI,[ESI+EBX-1]         ; Move ESI to end of definition

;/*
;** Indicate no modeset in hardware.
;*/

        MOV     EAX,0                   ; No mode set
        MOV     wModeSet,AX             ; Remember no modeset

;/*
;** Enable all plames for update.
;*/

        MOV     DX,EGA_BASE+SEQ_ADDR    ; Sequncer regs
        MOV     AL,SEQ_MAP_MASK         ; Map mask register
        MOV     AH,MM_ALL               ; Data (all on)
        OUT     DX,AX                   ; Do i/o

;/*
;** Set graphics mode register to write mode 0.
;*/

        MOV     DX,EGA_BASE+GRAF_ADDR           ; Graphics controller regs
        MOV     AL,GRAF_MODE                    ; Graphics mode register
        MOV     AH,M_PROC_WRITE OR M_DATA_READ  ; Data to be written
        OUT     DX,AX                           ; Do i/o

;/*
;** Set data rotate register for no logic function.
;*/

        MOV     AH,DR_SET               ; No logic function
        MOV     BX,wBitAddr             ; Get bit address
        OR      AH,BL                   ; Combine
        MOV     AL,GRAF_DATA_ROT        ; Rotate register
        OUT     DX,AX                   ; Do i/o

;/*
;** Skip background box if transparent.
;*/

        MOV     AX,wFunction            ; Get function
        CMP     AX,0                    ; Transparent ?
        JE      CL_BG_Box_end           ;  Y - Skip

        PUBLIC  CL_BG_Box_do
CL_BG_Box_do::

;/*
;** Set all bits on in enable set/reset reg (select s/r reg).
;*/

        MOV     DX,EGA_BASE+GRAF_ADDR   ; Graphics controller regs
        MOV     AL,GRAF_ENAB_SR         ; Graphics enable s/r reg
        MOV     AH,0FFh                 ; All ones
        OUT     DX,AX                   ; Do i/o

;/*
;** Set/reset reg = background color.
;*/

        MOV     AX,wColor               ; Get colours
        MOV     AL,GRAF_SET_RESET       ; Set/reset reg
        OUT     DX,AX                   ; Do i/o

;/*
;** Adjust hardware mask for x clipping.
;*/

        MOV     EBX,wX                  ; Get x coordinate
        AND     EBX,0FFF8h              ; Byte boundary x
        MOV     DX,wMask                ; Get mask
        MOV     AX,07FFFh               ; First bit mask
        MOV     CX,16                   ; Possible 16 bits

        PUBLIC  CL_Mask_adjust
CL_Mask_adjust::
        CMP     EBX,wClipXmin           ; Compare with ymin
        JL      CL_Mask_adjust_1        ; Go if outside
        CMP     EBX,wClipXmax           ; Compare with ymax
        JL      CL_Mask_adjust_2        ; Go if outside

        PUBLIC  CL_Mask_adjust_1
CL_Mask_adjust_1::
        AND     DX,AX                   ; Strip bit

        PUBLIC  CL_Mask_adjust_2
CL_Mask_adjust_2::
        ROR     AX,1                    ; Rotate mask
        INC     EBX                     ; Bump x
        LOOP    CL_Mask_adjust          ; Loop 16 bits
        MOV     wMask,DX

;/*
;** Set bit mask = char mask first part.
;*/

        MOV     AX,wMask                ; Get mask
        MOV     DX,EGA_BASE+GRAF_ADDR   ; Graphics controller regs
        MOV     AL,GRAF_BIT_MASK        ; Graphics bit mask
        OUT     DX,AX                   ; Do i/o

;/*
;** Loop For all slices to do background box first part.
;*/

        MOV     EDI,wByteAddr           ; Get byte address
        MOV     CX,wCellHeight          ; Loop count = cell height
        MOV     EBX,wY                  ; Get Y coordinate

        PUBLIC  CL_BG_Box_loop_1
CL_BG_Box_loop_1::
        CMP     EBX,wClipYmin           ; Compare with ymin
        JL      @f                      ; Go if outside
        CMP     EBX,wClipYmax           ; Compare with ymax
        JGE     @f                      ; Go if outside
        XCHG    AL,[EDI]                ; Read/write VGA

@@:
        DEC     EBX                     ; Y = Y - 1
        SUB     EDI,SCREEN_CBSCAN       ; Up one line
        LOOP    CL_BG_Box_loop_1        ; Loop

;/*
;** Set bit mask = char mask second part (unless no second run exists).
;*/

        MOV     AX,wMask                ; Get mask
        TEST    AL,0FFh                 ; Any second mask ?
        JZ      CL_BG_Box_end           ; Skip if not
        MOV     AH,AL                   ; Mask to AH
        MOV     AL,GRAF_BIT_MASK        ; Graphics bit mask
        OUT     DX,AX                   ; Output to h/w

;/*
;** Loop for all slices to do background box second part.
;*/

        MOV     EDI,wByteAddr           ; Get byte address
        INC     EDI                     ; Bump address
        MOV     CX,wCellHeight          ; Loop count = cell height
        MOV     EBX,wY                  ; Get Y coordinate

        PUBLIC  CL_BG_Box_loop_2
CL_BG_Box_loop_2::
        CMP     EBX,wClipYmin           ; Compare with ymin
        JL      @f                      ; Go if outside
        CMP     EBX,wClipYmax           ; Compare with ymax
        JGE     @f                      ; Go if outside
        XCHG    AL,[EDI]                ; Read/write VGA

@@:
        DEC     EBX                     ; Y = Y - 1
        SUB     EDI,SCREEN_CBSCAN       ; Up one line
        LOOP    CL_BG_Box_loop_2        ; Loop

        PUBLIC  CL_BG_Box_end
CL_BG_Box_end::

;/*
;** Set/reset reg = foreground color.
;*/

        MOV     AX,wColor               ; Get colors
        MOV     AH,AL                   ; FG color to AL
        MOV     DX,EGA_BASE+GRAF_ADDR   ; Graphics controller regs
        MOV     AL,GRAF_SET_RESET       ; graphics set/reset reg
        OUT     DX,AX                   ; Do i/o

;/*
;** Set graphics mode register to write mode 3.
;*/

        MOV     AL,GRAF_MODE                    ; Graphics mode
        MOV     AH,M_AND_WRITE OR M_DATA_READ   ; Write mode 3
        OUT     DX,AX                           ; Do i/o
;/*
;** Set bit mask = char mask first part.
;*/

        MOV     AX,wMask                ; Get mask
        MOV     AL,GRAF_BIT_MASK        ; Graphics bit mask
        OUT     DX,AX                   ; Do i/o

;/*
;** Do first 2 slices (including underscore).
;*/

        PUSH    ESI                     ; Save font pointer
        MOV     EDI,wByteAddr           ; Get byte address
        MOV     EBX,wY                  ; Get Y coordinate
        CMP     EBX,wClipYmin           ; Compare with ymin
        JL      @f                      ; Go if outside
        CMP     EBX,wClipYmax           ; Compare with ymax
        JGE     @f                      ; Go if outside
        MOV     AL,[ESI]                ; Read font
        OR      AL,bUnderscoreMask      ; OR underscore
        TEST    AL,0FFh                 ; Zero slice ?
        JZ      @f                      ; Skip if yes
        XCHG    AL,[EDI]                ; Read VGA data into latches

@@:
        DEC     EBX                     ; Y = Y - 1
        SUB     ESI,1                   ; Up one line
        SUB     EDI,SCREEN_CBSCAN       ; Up one line
        CMP     EBX,wClipYmin           ; Compare with ymin
        JL      @f                      ; Go if outside
        CMP     eBX,wClipYmax           ; Compare with ymax
        JGE     @f                      ; Go if outside
        MOV     AL,[ESI]                ; Read font
        TEST    AL,0FFh                 ; Zero slice ?
        JZ      @f                      ; Skip if yes
        XCHG    AL,[EDI]                ; Read VGA data into latches

@@:
        DEC     EBX                     ; Y =Y - 1
        SUB     ESI,1                   ; Up one line
        SUB     EDI,SCREEN_CBSCAN       ; Up one line

;/*
;** Loop for remaining slices to do foreground first part.
;*/

        MOV     CX,wCellHeight          ; Loop count = cell height
        SUB     CX,2                    ; Already done 2

        PUBLIC  CL_FG_Box_loop_1
CL_FG_Box_loop_1::
        CMP     EBX,wClipYmin           ; Compare with ymin
        JL      @f                      ; Go if outside
        CMP     EBX,wClipYmax           ; Compare with ymax
        JGE     @f                      ; Go if outside
        MOV     AL,[ESI]                ; Read font
        TEST    AL,0FFh                 ; Zero slice ?
        JZ      @f                      ; Skip if yes
        XCHG    AL,[EDI]                ; Read VGA data into latches

@@:
        DEC     EBX                     ; Y = Y - 1
        SUB     ESI,1                   ; Up one line
        SUB     EDI,SCREEN_CBSCAN       ; Up one line
        LOOP    CL_FG_Box_loop_1        ; Loop
        POP     ESI                     ; Rest font pointer

;/*
;** Set bit mask = char mask second part (unless no second run exists).
;*/

        MOV     AX,wMask                ; Get mask
        TEST    AL,0FFh                 ; Any second mask ?
        JZ      CL_FG_Box_end           ; Skip if not
        MOV     AH,AL                   ; Data to AH
        MOV     AL,GRAF_BIT_MASK        ; Graphics bit mask
        OUT     DX,AX                   ; Output to h/w

;/*
;** Do first 2 slices (including underscore).
;*/

        MOV     EDI,wByteAddr           ; Get byte address
        INC     EDI                     ; Bump DX
        MOV     EBX,wY                  ; Get Y coordinate
        CMP     EBX,wClipYmin           ; Compare with ymin
        JL      @f                      ; Go if outside
        CMP     EBX,wClipYmax           ; Compare with ymax
        JGE     @f                      ; Go if outside
        MOV     AL,[ESI]                ; Read font
        OR      AL,bUnderscoreMask      ; OR underscore
        TEST    AL,0FFh                 ; Zero slice ?
        JZ      @f                      ; Skip if yes
        XCHG    AL,[EDI]                ; Read VGA data into latches

@@:
        DEC     EBX                     ; Y = Y - 1
        SUB     ESI,1                   ; Up one line
        SUB     EDI,SCREEN_CBSCAN       ; Up one line
        CMP     EBX,wClipYmin           ; Compare with ymin
        JL      @f                      ; Go if outside
        CMP     EBX,wClipYmax           ; Compare with ymax
        JGE     @f                      ; Go if outside
        MOV     AL,[ESI]                ; Read font
        TEST    AL,0FFh                 ; Zero slice ?
        JZ      @f                      ; Skip if yes
        XCHG    AL,[EDI]                ; Read VGA data into latches

@@:
        DEC     EBX                     ; Y =Y - 1
        SUB     ESI,1                   ; Up one line
        SUB     EDI,SCREEN_CBSCAN       ; Up one line

;/*
;** Loop for remaining slices to do foreground second part.
;*/

        MOV     CX,wCellHeight          ; Loop count = cell height
        SUB     CX,2                    ; Already done 2

        PUBLIC  CL_FG_Box_loop_2
CL_FG_Box_loop_2::
        CMP     EBX,wClipYmin           ; Compare with ymin
        JL      @f                      ; Go if outside
        CMP     EBX,wClipYmax           ; Compare with ymax
        JGE     @f                      ; Go if outside
        MOV     AL,[ESI]                ; Read font
        TEST    AL,0FFh                 ; Zero slice ?
        JZ      @f                      ; Skip if yes
        XCHG    AL,[EDI]                ; Read/write VGA

@@:
        DEC     EBX                     ; Y = Y - 1
        SUB     ESI,1                   ; Up one line
        SUB     EDI,SCREEN_CBSCAN       ; Up one line
        LOOP    CL_FG_Box_loop_2        ; Loop

        PUBLIC  CL_FG_Box_end
CL_FG_Box_end::

;/*
;** Bump horizontal address by cell width.
;*/

        MOVZX   EAX,wCellWidth          ; Get cell width
        ADD     wX,EAX                  ; Bump X value

;/*
;** Test for horizontal clip (?) - move to next row if yes.
;*/

        CMP     bHorizontalClipMask,0   ; Is this text clipped?
        JE      Process_pseudo_code     ;  N - Jump to fetch next code
        JMP     Next_row                ;  Y - Return to fetch next code
ALIGN 4

;/*
;** Draw any width characters on arbitrary boundary unclipped.
;**
;** Characters of any width and any boundary and opaque or transparent and
;** drawn totally unclipped by this code. Drawing will continue until either
;** the block count reaches zero, or a non-glyph index value is found on the
;** stack.
;*/

        PUBLIC  Draw_n_wide_noclip
Draw_n_wide_noclip::

;/*
;** Save character count.
;*/

        MOV     wCharCount,AX           ; Save char count

;/*
;** Jump to process first character.
;*/

        JMP     Draw_nw_glyph_ok        ; Skip fetch code first time
ALIGN 4

;/*
;** Fetch glyph code - check for valid index value.
;*/

        PUBLIC  Draw_n_wide_noclip_next
Draw_n_wide_noclip_next::
        POP     ESI                     ; Get glyph index
        MOVSX   ESI,SI
        SUB     ESI,wFirstGlyph         ; Subtract the lowest defined glyph
        CMP     ESI,wGlyphSpan          ; Check against number of defined
                                        ; glyphs
        JB      Draw_nw_glyph_ok        ; Jump if in range
        ADD     ESI,wFirstGlyph         ; Add back in lowest defined glyph
        JS      NW_Not_default_glyph    ; Unsigned value is non-control code
        MOV     ESI,wDefaultGlyph       ; Use default value
        JMP     Draw_nw_glyph_ok        ; Jump if in range
ALIGN 4

;/*
;** Control code - put pcode back on stack and return to process.
;*/

        PUBLIC  NW_Not_default_glyph
NW_Not_default_glyph::
        PUSH    ESI                     ; Return code to stack
        JMP     Draw_NW_Exit            ; and exit
ALIGN 4

;/*
;** Valid glyph index - Calculate address of font.
;*/

        PUBLIC  Draw_nw_glyph_ok
Draw_nw_glyph_ok::
        IMUL    ESI,ESI,6               ; Glyph entries are 6 bytes
        ADD     ESI,wselfontsave        ; ESI --> Glyph to use
        MOV     ESI,[ESI].FONTMAP.fsCharOffset.VIO_FONT_ENTRIES.fe_dBits
                                        ; ESI --> character data offset
        ADD     ESI,wselfontsave        ; ESI -> Character bitmap
        MOV     wFontPtr0,ESI           ; Save
        MOVZX   EBX,wCellHeight         ; Load EBX with char height
        LEA     ESI,[ESI+EBX-1]         ; Move ESI to end of definition

;/*
;** Determine whether the fast 5 wide code can be used.
;*/

        CMP     wCellWidth,6            ; Cell width = 6 ?
        JE      Maybe_56_special        ; Go if yes
        CMP     wCellWidth,5            ; Cell width = 5 ?
        JNE     Not_56_special          ; Go if not

        PUBLIC  Maybe_56_special
Maybe_56_special::
        CMP     wCharCount,8                    ; Do we have 8 or more left ?
        JB      Not_56_special                  ;  N - Not so special
        MOV     EAX,wX                          ;  Y - Get X
        AND     AX,0007h                        ; Leave bit address and sign
        JNZ     Not_56_special                  ; Not special if not zero
        CMP     bHorizontalClipMask,0           ; Is this text clipped?
        JNE     Not_56_special                  ;  Y - Jump to force new row
        MOV     EBX,ESP                         ;  N - Copy ESP to EBX
        TEST    DWORD ptr [EBX],080000000h      ; Test next entry on stack (1)
        JNZ     Not_56_special                  ; Skip if control code
        TEST    DWORD ptr [EBX+4],080000000h    ; Test next entry on stack (2)
        JNZ     Not_56_special                  ; Skip if control code
        TEST    DWORD ptr [EBX+8],080000000h    ; Test next entry on stack (3)
        JNZ     Not_56_special                  ; Skip if control code
        TEST    DWORD ptr [EBX+12],080000000h   ; Test next entry on stack (4)
        JNZ     Not_56_special                  ; Skip if control code
        TEST    DWORD ptr [EBX+16],080000000h   ; Test next entry on stack (5)
        JNZ     Not_56_special                  ; Skip if control code
        TEST    DWORD ptr [EBX+20],080000000h   ; Test next entry on stack (6)
        JNZ     Not_56_special                  ; Skip if control code
        TEST    DWORD ptr [EBX+24],080000000h   ; Test next entry on stack (7)
        JNZ     Not_56_special                  ; Skip if control code
        MOV     AX,wFunction                    ; Get function
        CMP     AX,0                            ; Transparent ?

;/*
;** Conditions good to call fast 5 wide code - do it
;*/

        JNE     Fast_5or6_wide          ; Call fast 5 or 6 wide

;/*
;** Continue with normal draw - calculate update address in VGA
;*/

        PUBLIC  Not_56_special
Not_56_special::
        MOV     EBX,wY                  ; Get Y
        MOV     EAX,SCREEN_CBSCAN       ; Screen pitch in bytes
        MUL     EBX                     ; Result to EAX
        MOV     EBX,wX                  ; Get X
        SHR     EBX,3                   ; Byte address
        ADD     EAX,EBX                 ; Add to line address
if SCAN_CNT EQ 768
        mov     ecx,pVRAMInstance
        cmp     lpBitmapBits,ecx
        jne     not_vram2
        cmp     eax,010000h
        jb      not_vram2
        sub     eax,010000h
not_vram2:
endif
        ADD     EAX,lpBitmapBits
        MOV     wByteAddr,EAX           ; and save on stack

;/*
;** Calculate update mask and bit address.
;*/

        MOV     AX,00FFh
        MOV     CX,wCellWidth           ; Get cell width
        ROR     AX,CL                   ; N bits to AH
        MOV     AL,0
        MOV     ECX,wX                  ; Get X
        AND     ECX,0007h               ; Bit address
        MOV     wBitAddr,CX
        SHR     AX,CL                   ; Shift down to align
        MOV     wMask,AX                ; Store mask

;/*
;** Indicate no modeset in hardware.
;*/

        MOV     AX,0                    ; No mode set
        MOV     wModeSet,AX             ; Remember no modeset

;/*
;** Enable all planes for update.
;*/

        MOV     DX,EGA_BASE+SEQ_ADDR    ; Sequencer regs
        MOV     AL,SEQ_MAP_MASK         ; Map mask register
        MOV     AH,MM_ALL               ; Data (all on)
        OUT     DX,AX                   ; Do i/o

;/*
;** Set graphics mode register to write mode 0.
;*/

        MOV     DX,EGA_BASE+GRAF_ADDR           ; Graphics controller regs
        MOV     AL,GRAF_MODE                    ; Graphics mode
        MOV     AH,M_PROC_WRITE OR M_DATA_READ  ; Write mode 0
        OUT     DX,AX                           ; Do i/o


;/*
;** Set data rotate register for no logic function.
;*/

        MOV     AH,DR_SET               ; No logic function
        MOVZX   EBX,wBitAddr            ; Get bit address
        OR      AH,BL                   ; Combine
        MOV     AL,GRAF_DATA_ROT        ; Graphics rotate reg
        OUT     DX,AX                   ; Do i/o


;/*
;** Skip background box if transparent.
;*/

        MOV     AX,wFunction            ; Get function
        CMP     AX,0                    ; Transparent ?
        JE      BG_Box_end              ; Go if yes

;/*
;** Set all bits on in enable set/reset reg (select s/r reg).
;*/

        MOV     AL,GRAF_ENAB_SR         ; Graphics enable s/r
        MOV     AH,0FFh                 ; All bits on
        OUT     DX,AX                   ; Do i/o

;/*
;** Set/reset reg = background colour.
;*/

        MOV     AX,wColor               ; Get colors
        MOV     AL,GRAF_SET_RESET       ; Graphics set reset reg
        OUT     DX,AX                   ; Do i/o

;/*
;** Set bit mask = char mask first part.
;*/

        MOV     AX,wMask                ; Get mask
        MOV     AL,GRAF_BIT_MASK        ; Graphics bit mask
        OUT     DX,AX                   ; Do i/o

;/*
;** Loop For all slices to do background box first part (2x unrolled loop).
;*/

        MOV     EDI,wByteAddr           ; Get byte address
        MOV     CX,wCellHeight          ; Loop count = cell height
        SHR     CX,1                    ; Divide CX by 2

        PUBLIC  BG_Box_loop_1
BG_Box_loop_1::
        XCHG    AL,[EDI]                ; Read/write VGA
        SUB     EDI,SCREEN_CBSCAN       ; Up one line
        XCHG    AL,[EDI]                ; Read/write VGA
        SUB     EDI,SCREEN_CBSCAN       ; Up one line
        LOOP    BG_Box_loop_1           ; Loop

;/*
;** Set bit mask = char mask second part (unless no second run exists).
;*/

        MOV     AX,wMask                ; Get mask
        TEST    AL,0FFh                 ; Any second mask ?
        JZ      BG_Box_end              ; Skip if not
        MOV     AH,AL                   ; Mask to AH
        MOV     AL,GRAF_BIT_MASK        ; Graphics bit mask
        OUT     DX,AX                   ; Output to h/w

;/*
;** Loop For all slices to do background box second part.
;*/

        MOV     EDI,wByteAddr           ; Get byte address
        INC     EDI                     ; Bump address
        MOV     CX,wCellHeight          ; Loop count = cell height
        SHR     CX,1                    ; Divide CX by 2

        PUBLIC  BG_Box_loop_2
BG_Box_loop_2::
        XCHG    AL,[EDI]                ; Read/write VGA
        SUB     EDI,SCREEN_CBSCAN       ; Up one line
        XCHG    AL,[EDI]                ; Read/write VGA
        SUB     EDI,SCREEN_CBSCAN       ; Up one line
        LOOP    BG_Box_loop_2           ; Loop

        PUBLIC  BG_Box_end
BG_Box_end::

;/*
;** Set/reset reg = foreground colour
;*/

        MOV     AX,wColor               ; Get colors
        MOV     AH,AL                   ; FG to AH
        MOV     AL,GRAF_SET_RESET       ; Graphics set reset reg
        OUT     DX,AX                   ; Do I/O

;/*
;** Set graphics mode register to write mode 3.
;*/

        MOV     AL,GRAF_MODE                    ; Graphics mode
        MOV     AH,M_AND_WRITE OR M_DATA_READ   ; Write mode 3
        OUT     DX,AX                           ; Do I/O

;/*
;** Set bit mask = char mask first part.
;*/

        MOV     AX,wMask                ; Get mask
        MOV     AL,GRAF_BIT_MASK        ; Graphics bit mask
        OUT     DX,AX                   ; Do I/O

;/*
;** Do first 2 slices (including underscore).
;*/

        PUSH    ESI                     ; Save font pointer
        MOV     EDI,wByteAddr           ; Get byte address
        LODSB                           ; Read font
        OR      AL,bUnderscoreMask      ; OR underscore
        TEST    AL,0FFh                 ; Zero slice ?
        JZ      @f                      ;  Y - Skip
        XCHG    AL,[EDI]                ;  N - Read and write VGA

@@:
        SUB     EDI,SCREEN_CBSCAN       ; Up one line
        LODSB                           ; Read font
        TEST    AL,0FFh                 ; Zero slice ?
        JZ      @f                      ; Skip if yes
        XCHG    AL,[EDI]                ; Read and write VGA

@@:
        SUB     EDI,SCREEN_CBSCAN       ; Up one line

;/*
;** Loop For remaining slices to do foreground first part (2x unrolled).
;*/

        MOV     CX,wCellHeight          ; Loop count = cell height
        SUB     CX,2                    ; Already done 2
        SHR     CX,1                    ; Divide CX by 2

        PUBLIC  FG_Box_loop_1
FG_Box_loop_1::
        LODSB                           ; Read font
        TEST    AL,0FFh                 ; Zero slice ?
        JZ      @f                      ;  Y - Skip
        XCHG    AL,[EDI]                ;  N - Read and write VGA

@@:
        SUB     EDI,SCREEN_CBSCAN       ; Up one line
        LODSB                           ; Read font
        TEST    AL,0FFh                 ; Zero slice ?
        JZ      @f                      ;  Y - Skip
        XCHG    AL,[EDI]                ;  N - Read and write VGA

@@:
        SUB     EDI,SCREEN_CBSCAN       ; Up one line
        LOOP    FG_Box_loop_1           ; Loop
        POP     ESI                     ; Restore font pointer

;/*
;** Set bit mask = char mask second part (unless no second run exists).
;*/

        MOV     AX,wMask                ; Get mask
        TEST    AL,0FFh                 ; Any second mask ?
        JZ      FG_Box_end              ; Skip if not
        MOV     AH,AL                   ; Mask to AH
        MOV     AL,GRAF_BIT_MASK        ; Graphics bit mask
        OUT     DX,AX                   ; Output to h/w

;/*
;** Do first 2 slices (including underscore).
;*/

        MOV     EDI,wByteAddr           ; Get byte address
        INC     EDI                     ; Bump EDI
        LODSB                           ; Read font
        OR      AL,bUnderscoreMask      ; OR underscore
        TEST    AL,0FFh                 ; Zero slice ?
        JZ      @f                      ;  Y - Skip
        XCHG    AL,[EDI]                ;  N - Read and write VGA

@@:
        SUB     EDI,SCREEN_CBSCAN       ; Up one line
        LODSB                           ; Read font
        TEST    AL,0FFh                 ; Zero slice ?
        JZ      @f                      ;  Y - Skip
        XCHG    AL,[EDI]                ;  N - Read and write VGA

@@:
        SUB     EDI,SCREEN_CBSCAN       ; Up one line

;/*
;** Loop For remaining slices to do foreground second part (2x unrolled).
;*/

        MOV     CX,wCellHeight          ; Loop count = cell height
        SUB     CX,2                    ; Already done 2
        SHR     CX,1                    ; Divide CX by 2

        PUBLIC  FG_Box_loop_2
FG_Box_loop_2::
        LODSB                           ; Read font
        TEST    AL,0FFh                 ; Zero slice ?
        JZ      @f                      ;  Y - Skip
        XCHG    AL,[EDI]                ;  N - Read and write VGA

@@:
        SUB     EDI,SCREEN_CBSCAN       ; Up one line
        LODSB                           ; Read font
        TEST    AL,0FFh                 ; Zero slice ?
        JZ      @f                      ;  Y - Skip
        XCHG    AL,[EDI]                ;  N - Read and write VGA

@@:
        SUB     EDI,SCREEN_CBSCAN       ; Up one line
        LOOP    FG_Box_loop_2           ; Loop

        PUBLIC  FG_Box_end
FG_Box_end::

;/*
;** Bump horizontal address by cell width.
;*/

        MOVZX   EAX,wCellWidth          ; Get cell width
        ADD     wX,EAX                  ; Bump X value

;/*
;** Test for horizontal clip (?) - move to next row if yes.
;*/

        CMP     bHorizontalClipMask,0   ; Is this text clipped?
        JNE     Next_row                ;  Y - Jump to force new row

;/*
;** Check character count, return if zero else decrement.
;*/

        DEC     wCharCount              ; Dec and test character count
        JNZ     Draw_n_wide_noclip_next ; Jump back to fetch next code

;/*
;** Exit n-wide unclipped code.
;*/

        PUBLIC  Draw_NW_Exit
Draw_NW_Exit::
        JMP     Process_pseudo_code     ; Return to fetch next code
ALIGN 4

;/*
;** Draw 8 x 5 wide characters in a group (very fast) without clipping.
;*/

        PUBLIC  Fast_5or6_wide
Fast_5or6_wide::

;/*
;** Fetch pseudo-code from stack and calculate font address for second char.
;*/

        POP     ESI                     ; Get glyph index
        MOVSX   ESI,SI
        SUB     ESI,wFirstGlyph         ; Subtract the lowest defined glyph
        CMP     ESI,wGlyphSpan          ; Check against number of defined
                                        ; glyphs
        JB      @f                      ; Skip if in range
        MOV     ESI,wDefaultGlyph       ; Use default value

@@:
        IMUL    ESI,ESI,6               ; Glyph entries are 6 bytes
        ADD     ESI,wselfontsave        ; ESI --> Glyph to use
        MOV     ESI,[ESI].FONTMAP.fsCharOffset.VIO_FONT_ENTRIES.fe_dBits
                                        ; ESI --> Character data offset
        ADD     ESI,wselfontsave        ; ESI -> Character bitmap
        MOV     wFontPtr1,ESI           ; Store in stack frame

;/*
;** Fetch pseudo-code from stack and calculate font address for third char.
;*/

        POP     ESI                     ; Get glyph index
        MOVSX   ESI,SI
        SUB     ESI,wFirstGlyph         ; Subtract the lowest defined glyph
        CMP     ESI,wGlyphSpan          ; Check against number of defined
                                        ; glyphs
        JB      @f                      ; Skip if in range
        MOV     ESI,wDefaultGlyph       ; Use default value

@@:
        IMUL    ESI,ESI,6               ; Glyph entries are 6 bytes
        ADD     ESI,wselfontsave        ; ESI --> Glyph to use
        MOV     ESI,[ESI].FONTMAP.fsCharOffset.VIO_FONT_ENTRIES.fe_dBits
                                        ; ESI --> Character data offset
        ADD     ESI,wselfontsave        ; ESI -> Character bitmap
        MOV     wFontPtr2,ESI           ; Store in stack frame

;/*
;** Fetch pseudo-code from stack and calculate font address for fourth char.
;*/

        POP     ESI                     ; Get glyph index
        MOVSX   ESI,SI
        SUB     ESI,wFirstGlyph         ; Subtract the lowest defined glyph
        CMP     ESI,wGlyphSpan          ; Check against number of defined
                                        ; glyphs
        JB      @f                      ; Skip if in range
        MOV     ESI,wDefaultGlyph       ; Use default value

@@:
        IMUL    ESI,ESI,6               ; Glyph entries are 6 bytes
        ADD     ESI,wselfontsave        ; ESI --> Glyph to use
        MOV     ESI,[ESI].FONTMAP.fsCharOffset.VIO_FONT_ENTRIES.fe_dBits
                                        ; ESI --> Offset of char. bitmap
        ADD     ESI,wselfontsave        ; ESI --> Character bitmap
        MOV     wFontPtr3,ESI           ; Store in stack frame

;/*
;** Fetch pseudo-code from stack and calculate font address for fifth char.
;*/

        POP     ESI                     ; Get glyph index
        MOVSX   ESI,SI
        SUB     ESI,wFirstGlyph         ; Subtract the lowest defined glyph
        CMP     ESI,wGlyphSpan          ; Check against no. of defined glyphs
        JB      @f                      ; Skip if in range
        MOV     ESI,wDefaultGlyph       ; Use default value

@@:
        IMUL    ESI,ESI,6               ; Glyph entries are 6 bytes
        ADD     ESI,wselfontsave        ; ESI --> Glyph to use
        MOV     ESI,[ESI].FONTMAP.fsCharOffset.VIO_FONT_ENTRIES.fe_dBits
                                        ; ESI --> Offset of char. bitmap
        ADD     ESI,wselfontsave        ; ESI --> Character bitmap
        MOV     wFontPtr4,ESI           ; Store in stack frame

;/*
;** Fetch pseudo-code from stack and calculate font address for sixth char.
;*/

        POP     ESI                     ; Get glyph index
        MOVSX   ESI,SI
        SUB     ESI,wFirstGlyph         ; Subtract the lowest defined glyph
        CMP     ESI,wGlyphSpan          ; Check against num. of defined glyphs
        JB      @f                      ; Skip if in range
        MOV     ESI,wDefaultGlyph       ; Use default value

@@:
        IMUL    ESI,ESI,6               ; Glyph entries are 6 bytes
        ADD     ESI,wselfontsave        ; ESI --> Glyph to use
        MOV     ESI,[ESI].FONTMAP.fsCharOffset.VIO_FONT_ENTRIES.fe_dBits
                                        ; ESI --> Offset of char. bitmap
        ADD     ESI,wselfontsave        ; ESI --> Character bitmap
        MOV     wFontPtr5,ESI           ; Store in stack frame

;/*
;** Fetch pseudo-code from stack and calculate font address for seventh char.
;*/

        POP     ESI                     ; Get glyph index
        MOVSX   ESI,SI
        SUB     ESI,wFirstGlyph         ; Subtract the lowest defined glyph
        CMP     ESI,wGlyphSpan          ; Check against num. of defined glyphs
        JB      @f                      ; Skip if in range
        MOV     ESI,wDefaultGlyph       ; Use default value

@@:
        IMUL    ESI,ESI,6               ; Glyph entries are 6 bytes
        ADD     ESI,wselfontsave        ; ESI --> Glyph to use
        MOV     ESI,[ESI].FONTMAP.fsCharOffset.VIO_FONT_ENTRIES.fe_dBits
                                        ; ESI --> Offset of char. bitmap
        ADD     ESI,wselfontsave        ; ESI --> Character bitmap
        MOV     wFontPtr6,ESI           ; Store in stack frame

;/*
;** Fetch pseudo-code from stack and calculate font address for eighth char.
;*/

        POP     ESI                     ; Get glyph index
        MOVSX   ESI,SI
        SUB     ESI,wFirstGlyph         ; Subtract the lowest defined glyph
        CMP     ESI,wGlyphSpan          ; Check against num. of defined glyphs
        JB      @f                      ; Skip if in range
        MOV     ESI,wDefaultGlyph       ; Use default value

@@:
        IMUL    ESI,ESI,6               ; Glyph entries are 6 bytes
        ADD     ESI,wselfontsave        ; ESI --> Glyph to use
        MOV     ESI,[ESI].FONTMAP.fsCharOffset.VIO_FONT_ENTRIES.fe_dBits
                                        ; ESI --> Offset of char. bitmap
        ADD     ESI,wselfontsave        ; ESI --> Character bitmap
        MOV     wFontPtr7,ESI           ; Store in stack frame

;/*
;** Skip setup if 5 wide hardware setup active.
;*/

        CMP     WORD ptr wModeSet,5     ; 5 wide mode set ?
        JE      @f                      ;  Y - Go
        MOV     WORD ptr wModeSet,5     ; Remember 5 wide modeset

;/*
;** Enable all planes for update in VGA sequencer.
;*/

        MOV     DX,EGA_BASE+SEQ_ADDR    ; Sequncer regs
        MOV     AL,SEQ_MAP_MASK         ; Map mask register
        MOV     AH,MM_ALL               ; Data (all on)
        OUT     DX,AX                   ; Do I/O

;/*
;** Set write mode in graphics controller.
;*/

        MOV     DX,EGA_BASE+GRAF_ADDR           ; Graphics controller regs
        MOV     AL,GRAF_MODE                    ; Graphics mode register
        MOV     AH,M_PROC_WRITE OR M_DATA_READ  ; Data to be written
        OUT     DX,AX                           ; Do I/O

;/*
;** Set data rotate=0 and no logic function.
;*/

        MOV     AL,GRAF_DATA_ROT        ; Graphics data rotate register
        MOV     AH,DR_SET               ; Set mode with no rotate
        OUT     DX,AX                   ; Do I/O

;/*
;** Set set/reset reg = Background col.
;*/

        MOV     AX,wColor               ; Get colour
        MOV     AL,GRAF_SET_RESET       ; Graphics set/reset register
        OUT     DX,AX                   ; Do I/O

;/*
;** Enable s/r for all planes
;*/

        MOV     AL,GRAF_ENAB_SR         ; Graphics set/reset enable register
        MOV     AH,MM_ALL               ; All on
        OUT     DX,AX                   ; Do I/O

;/*
;** Enable all bits in bit mask.
;*/

        MOV     AL,GRAF_BIT_MASK        ; Graphics bit mask
        MOV     AH,0FFh                 ; All on
        OUT     DX,AX                   ; Do I/O

;/*
;** Write and read VGA to get bgcol into latches.
;*/

if SCAN_CNT EQ 768
        MOV     BH,AH
        OVAccess
        MOV     ESI,pVRAMInstance               ; This gets our
        MOV     [ESI+tonys_bar_n_grill],BH      ; background color
        MOV     AH,[ESI+tonys_bar_n_grill]      ; into the latches.
        OVRestore
else
        MOV     ESI,pVRAMInstance                 ; This gets our
        MOV     [ESI+tonys_bar_n_grill],AH      ; background color
        MOV     AH,[ESI+tonys_bar_n_grill]      ; into the latches.
endif

;/*
;** Change set/reset reg to all zeroes
;*/

        XOR     EAX,EAX                 ; Clear EAX
        MOV     AL,GRAF_SET_RESET       ; Graphics set/reset register
        OUT     DX,AX                   ; Do I/O

;/*
;** Set enable s/r to difference between FG and BG colors.
;*/

        MOV     BX,wColor       ; Get colors
        MOV     AH,BH           ; The Set/Reset enable register now
        XOR     AH,BL           ; flags where the foreground/background
        NOT     AH              ; colors are the same.
        AND     AH,0Fh          ; Leave LO nibble
        MOV     AL,GRAF_ENAB_SR ; Graphics set/reset enable regsiter
        OUT     DX,AX           ; Do I/O

;/*
;** Set data rotate to XOR with zero rotate.
;*/

        MOV     AL,GRAF_DATA_ROT        ; Color differences will be XOR'd
        MOV     AH,DR_XOR               ; with the latches.
        OUT     DX,AX                   ; Do I/O

;/*
;** Continue with normal draw - calculate update address in VGA.
;*/

@@:
        MOV     EBX,wY                  ; Get Y
        MOV     EAX,SCREEN_CBSCAN       ; Screen pitch in bytes
        MUL     EBX                     ; Result to EAX
        MOV     EBX,wX                  ; Get x
        SHR     EBX,3                   ; Byte address
        ADD     EAX,EBX                 ; Add to line address
if SCAN_CNT EQ 768
        mov     ebx,pVRAMInstance
        cmp     lpBitmapBits,ebx
        jne     not_vram3
        cmp     eax,010000h
        jb      not_vram3
        sub     eax,010000h
not_vram3:
endif
        ADD     EAX,lpBitmapBits
        MOV     wByteAddr,EAX           ; and save on stack

;/*
;** Initialize loop to write all slices of 8 characters.
;*/

        MOVZX   EBX,wCellHeight         ; Load EBX with char height
        MOV     EDI,wByteAddr           ; Get byte address for drawing
        MOV     DL,bUnderscoreMask      ; Get underscore
        CLD                             ; Ensure count upwards
        CMP     wCellWidth,6            ; Cell width = 6 ?
        JE      Charglp6                ; Go 6 pel wide version

;/*
;** Fetch slice from characters 0 and 1
;*/

        PUBLIC  Charglp5
Charglp5::
        MOV     ESI,wFontPtr0   ; Get font pointer 0
        MOV     AH,[ESI+EBX-1]  ; Get slice into AL
        MOV     CL,5            ; Shift count
        ROL     AX,CL           ; Shift data up
        MOV     ESI,wFontPtr1   ; Get font pointer 1
        MOV     AH,[ESI+EBX-1]  ; Get slice
        MOV     CL,3            ; Shift count
        ROL     AX,CL           ; Shift data up

;/*
;** Store byte 0 and move remaining bits down.
;*/

        OR      AL,DL           ; Turn on underscore mask
        STOSB                   ; Store byte to VGA
        MOV     CL,2            ; Shift count
        ROL     AX,CL           ; Get remaining 2 bits

;/*
;** Fetch slice from characters 2 and 3.
;*/

        MOV     ESI,wFontPtr2   ; Get font pointer 2
        MOV     AH,[ESI+EBX-1]  ; Get slice
        MOV     CL,5            ; Shift count
        ROL     AX,CL           ; Shift data up
        MOV     ESI,wFontPtr3   ; Get font pointer 3
        MOV     AH,[ESI+EBX-1]  ; Get slice
        ROL     AX,1            ; Shift data up

;/*
;** Store byte 1 and move remaining bits down.
;*/

        OR      AL,DL           ; Turn on underscore mask
        STOSB                   ; Store byte to VGA
        MOV     CL,4            ; Shift count
        ROL     AX,CL           ; Get remaining 4 bits

;/*
;** Fetch slice from character 4.
;*/

        MOV     ESI,wFontPtr4   ; Get font pointer 4
        MOV     AH,[ESI+EBX-1]  ; Get slice
        MOV     CL,4            ; Shift count
        ROL     AX,CL           ; Shift data up

;/*
;** Store BYTE 2 and move remaining bit down.
;*/

        OR      AL,DL           ; Turn on underscore mask
        STOSB                   ; Store byte to VGA
        ROL     AX,1            ; Get remaining bit

;/*
;** Fetch slice from characters 5 and 6.
;*/

        MOV     ESI,wFontPtr5   ; Get font pointer 5
        MOV     AH,[ESI+EBX-1]  ; Get slice
        MOV     CL,5            ; Shift count
        ROL     AX,CL           ; Shift data up
        MOV     ESI,wFontPtr6   ; Get font pointer 6
        MOV     AH,[ESI+EBX-1]  ; Get slice
        MOV     CL,2            ; Shift count
        ROL     AX,CL           ; Shift data up

;/*
;** Store byte 3 and move remaining bits down.
;*/

        OR      AL,DL           ; Turn on underscore mask
        STOSB                   ; Store byte to VGA
        MOV     CL,3            ; Shift count
        ROL     AX,CL           ; Shift data up

;/*
;** Fetch slice from character 7.
;*/

        MOV     ESI,wFontPtr7   ; Get font pointer 7
        MOV     AH,[ESI+EBX-1]  ; Get slice
        MOV     CL,5            ; Shift count
        ROL     AX,CL           ; Shift data up

;/*
;** Store byte 4.
;*/

        OR      AL,DL           ; Turn on underscore mask
        STOSB                   ; Store byte to VGA

;/*
;** End of main loop - bump pointers and test for end.
;*/

        XOR     EDX,EDX                 ; Clear underscore mask
        SUB     EDI,SCREEN_CBSCAN+5     ; Decrement to start of next line
        DEC     EBX                     ; Decrement character slice offset
        JNZ     Charglp5                ; and loop for all slices

;/*
;** Update all pointers before returing to get more to draw.
;*/

        ADD     wX,8*5                  ; Bump X value for 8 characters
        STD                             ; Will do characters upwards
        JMP     Process_pseudo_code     ; and return to fetch next code
ALIGN 4

        PUBLIC  Charglp6
Charglp6::
        MOV     ESI,wFontPtr0   ; Get font pointer 0
        MOV     AH,[ESI+EBX-1]  ; Get slice into AL
        MOV     CL,6            ; Shift count
        ROL     AX,CL           ; Shift data up
        MOV     ESI,wFontPtr1   ; Get font pointer 1
        MOV     AH,[ESI+EBX-1]  ; Get slice
        MOV     CL,2            ; Shift count
        ROL     AX,CL           ; Shift data up

;/*
;** Store BYTE 0 and move remaining bits down.
;*/

        OR      AL,DL           ; Turn on underscore mask
        STOSB                   ; Store BYTE to VGA
        MOV     CL,4            ; Shift count
        ROL     AX,CL           ; Get remaining 4 bits

;/*
;** Fetch slice from characters 2.
;*/

        MOV     ESI,wFontPtr2   ; Get font pointer 2
        MOV     AH,[ESI+EBX-1]  ; Get slice
        MOV     CL,4            ; Shift count
        ROL     AX,CL           ; Shift data up

;/*
;** Store byte 1 and move remaining bits down.
;*/

        OR      AL,DL           ; Turn on underscore mask
        STOSB                   ; Store byte to VGA
        MOV     CL,2            ; Shift count
        ROL     AX,CL           ; Get remaining 2 bits

;/*
;** Fetch slice from character 3.
;*/

        MOV     ESI,wFontPtr3   ; Get font pointer 3
        MOV     AH,[ESI+EBX-1]  ; Get slice
        MOV     CL,6            ; Shift count
        ROL     AX,CL           ; Shift data up

;/*
;** Store byte 2.
;*/

        OR      AL,DL           ; Turn on underscore mask
        STOSB                   ; Store byte to VGA

; Fetch slice from characters 4 and 5.

        MOV     ESI,wFontPtr4   ; Get font pointer 4
        MOV     AH,[ESI+EBX-1]  ; Get slice
        MOV     CL,6            ; Shift count
        ROL     AX,CL           ; Shift data up
        MOV     ESI,wFontPtr5   ; Get font pointer 5
        MOV     AH,[ESI+EBX-1]  ; Get slice
        MOV     CL,2            ; Shift count
        ROL     AX,CL           ; Shift data up

;/*
;** Store BYTE 3 and move remaining bits down.
;*/

        OR      AL,DL           ; Turn on underscore mask
        STOSB                   ; Store byte to VGA
        MOV     CL,4            ; Shift count
        ROL     AX,CL           ; Shift data up

;/*
;** Fetch slice from character 6.
;*/

        MOV     ESI,wFontPtr6   ; Get font pointer 6
        MOV     AH,[ESI+EBX-1]  ; Get slice
        MOV     CL,4            ; Shift count
        ROL     AX,CL           ; Shift data up

;/*
;** Store byte 4.
;*/

        OR      AL,DL           ; Turn on underscore mask
        STOSB                   ; Store byte to VGA
        MOV     CL,2            ; Shift count
        ROL     AX,CL           ; Get remaining 2 bits

;/*
;** Fetch slice from character 7.
;*/

        MOV     ESI,wFontPtr7   ; Get font pointer 3
        MOV     AH,[ESI+EBX-1]  ; Get slice
        MOV     CL,6            ; Shift count
        ROL     AX,CL           ; Shift data up

;/*
;** Store byte 5.
;*/

        OR      AL,DL           ; Turn on underscore mask
        STOSB                   ; Store byte to VGA

;/*
;** End of main loop - bump pointers and test for end.
;*/

        XOR     EDX,EDX                 ; Clear underscore mask
        SUB     EDI,SCREEN_CBSCAN+6     ; Decrement to start of next line
        DEC     EBX                     ; Decrement character slice offset
        JNZ     Charglp6                ; and loop for all slices

;/*
;** Update all pointers before returing to get more to draw.
;*/

        ADD     wX,8*6                  ; Bump X value for 8 characters
        STD                             ; Will do characters upwards
        JMP     Process_pseudo_code     ; and return to fetch next code
ALIGN 4

AVioDrawText ENDP

        OPTION  PROLOGUE:PrologueDef
        OPTION  EPILOGUE:EpilogueDef

endif;not DBCS        ;IBMJ

ENDIF; VGA

ifdef DBCS  ; DBCS device font support     ;IBMJ
 include celldraw.inc
endif;DBCS        ;IBMJ

        END
