;*DDK*************************************************************************/
;
; COPYRIGHT (C) Microsoft Corporation, 1989
; 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
;*   ??/??/92                     Paul King CMVC_53383
;*   ??/??/92                     Paul King CMVC_53468
;*   04/17/93              67423  Added Tsu Wang Chen's scrolling performance
;*                                improvement code.
;*   08/21/93              73037  wClipXmax not being treated as exclusive.
;*
;*****************************************************************************/


        .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


;/*
;** Local Data
;*/

        .DATA


ifdef   PALMGR2
externdef       AVIOColorTable:DWORD
externdef       AVIOXlate256:DWORD
externdef       AVIOXlate128:DWORD
externdef       AVIOXlate64:DWORD
externdef       AVIOXlate32:DWORD
externdef       AVIOXlate16:DWORD
externdef       pAVIOColorXlate:DWORD
else
EXTERNDEF       ColorMap:BYTE
endif

public  Origin_bank
Origin_bank     db      ?

temp_lookup_table       dd      16      dup (0)


lookup_table            dd      512     dup(0)
lookup_table_color      dw      0


;/*
;** Public Functions
;*/

_AvioSupport SEGMENT DWORD PUBLIC FLAT '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

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
;*/

        DebugMsg <CDRAW>

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



IFDEF VGA
        CMP     wCellWidth,8
        JE      Got8pel

        JMP     Not8pel
        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

ifdef   CLR256
        mul     di              ;use 16 bits so bank number will go to dx
        MOVZX   EDI,xcoordStart
        ADD     DI,AX
        adc     dl,dh
        mov     Origin_bank,dl
        call    set_bank_select
else
        MUL     EDI
        MOVZX   EDI,xcoordStart
        SHR     EDI,3
        ADD     EDI,EAX
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
ifdef   CLR256
        sub     ebx,8
else
        DEC     EBX
endif
        MOV     wDest1stIncr,EBX
        MOV     EBX,EAX
        MUL     wScanLineCount
        SUB     EBX,EAX
        MOV     wDest2ndIncr,EBX
ifdef   CLR256
        mov     EBX, wFullCols          ; NewCon 6-12-89
        shl     EBX, 3                  ; * 8
        sub     EAX, EBX
else
        SUB     EAX,wFullCols
endif
        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.
        XOR     ECX,ECX                 ; Constructing a reference Zero value.
        MOVZX   EAX,SI
        AND     EAX,(AVioReverseVideoMask OR AVioTransparentMask)
        CMP     AX,AVioReverseVideoMask ; Check for Opaque with Reverse Video.
        JNZ     Filter_UnderScore
        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::
        LODSW
        CMP     AX,-2
        JA      Found_a_control_marker  ; -1 => control marker
        JE      Check_next_syllable     ; -2 => end of row action
        MOV     [ESI-2],BX
        JMP     Check_next_syllable

        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
ClippedOpaque::
        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   PALMGR2
        mov     ebx,pAVIOColorXlate
        xor     eax,eax
        mov     al,dl
        mov     dl,[ebx][eax*sizeof DWORD]
        mov     al,dh
        mov     dh,[ebx][eax*sizeof DWORD]
else
        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]
endif

ifdef   CLR256
        mov     OpaqueColorSave, DX
        MOV     BX,DX                   ; Free up DX for the OUT instructions.
else
        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
        MOV     ESI,EAX                 ; Preserve EAX for the PUSH below.
endif


        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

ifndef  CLR256
        PUSH    EDI                     ; Save the destination pointer
                                        ; for a possible second pass.
        PUSH    ESI                     ; Save our plane mask.
endif
                                        ; code stream.
        call    AVioDrawOpaqueHC


ifndef  CLR256                          ;no need for two passes in 256 colr mode
        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.
        POP     EDI                     ; Restore EDI for the second pass.
        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

        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...

endif   ;CLR256

        PUBLIC  NoOHCPass2
NoOHCPass2::

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

        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   PALMGR2
        mov     ebx,pAVIOColorXlate
        xor     eax,eax
        mov     al,dl
        mov     dl,[ebx][eax*sizeof DWORD]
        mov     al,dh
        mov     dh,[ebx][eax*sizeof DWORD]
else
        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]
endif   ;PALMGR2

ifdef   CLR256
        MOV     OpaqueColorSave,DX
else
        MOV     BX,DX                   ; Free up DX for the OUT instructions.
endif

;/*
;** 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.
;*/

ifndef  CLR256

        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
        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
        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.

endif   ;CLR256

        PUBLIC  OpaqueColorsOK
OpaqueColorsOK::
        POP     EDX                             ; Restore the register set for
        POP     ECX                             ; the drawing function.
        POP     EBX
        POP     EAX

ifdef   CLR256
        JMP     VioDrawOpaqueNHC        ;we use same code o handle both cases
else
        TEST    SI,AVioUnderscoreMask OR AVioReverseVideoMask
        JZ      VioDrawOpaqueNHC
        JMP     AVioDrawOpaqueNVC
endif

        PUBLIC  GoingTransparent
GoingTransparent::

ifdef   CLR256                          ;get our color for xpar subr.
        MOV     DH,CH                   ; Split the color information into
        MOV     DL,DH                   ; two bytes:
        SHR     DH,4                    ;   DH -- Background
        AND     DX,0F0Fh                ;   DL -- Foreground
ifdef   PALMGR2
        mov     ebx,pAVIOColorXlate
        xor     eax,eax
        mov     al,dl
        mov     dl,[ebx][eax*sizeof DWORD]
        mov     al,dh
        mov     dh,[ebx][eax*sizeof DWORD]
else
        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]
endif   ;PALMGR2
        mov     OpaqueColorSave, DX
else
        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.
        XOR     BX,BX                   ; Map the color to the EGA color
        MOV     BL,CH                   ; planes and put that mapping into
        MOV     AL,GRAF_SET_RESET       ; the Set/Reset register.
        MOV     AH,ColorMap[EBX]
        OUT     DX,AX
        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
endif   ;CLR256

        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.

        PUBLIC  Transparent_Clipped
Transparent_Clipped::
        DEC     AL                      ; Restore the clip mask.
        JMP     AVioDrawXparentHC

IFDEF VGA

;/*
;** Alternative 'InterpretAttributes' for non 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
        MOVZX   EAX,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.

        PUBLIC  ProcessAStream2
ProcessAStream2::
        POP     ESI                     ; Get the new attribute set.
        PUSH    EBX                     ; Save coordinate
        MOV     EAX,ESI
        AND     EAX,(AVioReverseVideoMask OR AVioTransparentMask)
        CMP     EAX,AVioReverseVideoMask        ; Check for Opaque with
                                                ; Reverse Video
        JNZ     Set_hardware_colors2
        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   PALMGR2
        mov     ebx,pAVIOColorXlate
        xor     eax,eax
        mov     al,cl
        mov     cl,[ebx][eax*sizeof DWORD]
        mov     al,ch
        mov     ch,[ebx][eax*sizeof DWORD]
        MOV     wColor,CX               ; save colors
else
        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
        MOV     wColor,AX               ; save colors
endif

ifdef   CLR256
;/*
;** Initialize our character expand lookup table. Note that it is initialized
;** in nibble FLIPPED order, so that we dont have to normalize the font bits
;** that form a lookup into this table
;*/

        PUSH    EDI
        MOV     AL, BYTE PTR wColor+1   ; get background color
        MOV     AH,AL
        MOV     DI,AX
        SHL     EAX,16
        MOV     AX,DI
        MOV     EDI,OFFSET temp_lookup_table
        STOSD
        MOV     AL, BYTE PTR wColor     ; get FOREground color
        ROR     EAX,8
        STOSD
        ROR     EAX,8
        STOSD
        MOV     AH, BYTE PTR wColor     ; get FOREground color
        ROL     EAX,8
        STOSD
        ROR     EAX,16
        MOV     AL, BYTE PTR wColor+1   ; get Bground color
        STOSD
        ROL     EAX,16
        MOV     AH, BYTE PTR wColor     ; get FOREground color
        STOSD
        ROR     EAX,8
        XCHG    AH,AL
        STOSD
        MOV     AL,AH
        ROL     EAX,8
        STOSD
        MOV     AH,AL
        ROL     EAX,8
        MOV     AL,AH
        ROL     EAX,8
        STOSD
        ROR     EAX,8
        MOV     AL, BYTE PTR wColor     ; get FOREground color
        STOSD
        ROL     EAX,16
        XCHG    AH,AL
        STOSD
        MOV     AH,AL
        ROR     EAX,16
        STOSD
        MOV     AL,AH
        ROR     EAX,16
        STOSD
        ROR     EAX,8
        MOV     AH,AL
        STOSD
        ROL     EAX,8
        STOSD
        ROL     EAX,8
        MOV     AL,AH
        STOSD
        POP     EDI
endif

        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
        MOV     [ESI-4],BX                      ; Replace syllable with a
                                                ; surrogate character
        JMP     Check_next_syllable2

        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

        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

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           ;8 bits/pixel no need
        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 Modified
;*                       None
;*
;* INPUT:
;*      AH   =  The number of scan lines to draw vertically.
;*      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 pseudo code consumed by this
;*                         function.
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        OPTION  PROLOGUE:NONE
        OPTION  EPILOGUE:NONE



define_CharRect_frame VioDrawOpaqueNHC

ifdef   CLR256
;/*
;** the Mgx code for this routine can not be used because it depends on
;** the color expand features of planar VGA. THis code was adapted from the
;** WD OS/2 1.3 driver
;*/

        mov     bx, OpaqueColorSave     ; NewCon 6-11-89, dh = back dl = fore


        cmp     bx,lookup_table_color
        jz      @f
        mov     lookup_table_color,bx
        push    edi
        push    ecx
        mov     edi,offset lookup_table
        mov     ecx,255

fill_lookup_table:
        mov     al,bl
        test    ecx,10000000b
        jz      next1
        mov     al,bh
next1:
        stosb
        mov     al,bl
        test    ecx,01000000b
        jz      next2
        mov     al,bh
next2:
        stosb
        mov     al,bl
        test    ecx,00100000b
        jz      next3
        mov     al,bh
next3:
        stosb
        mov     al,bl
        test    ecx,00010000b
        jz      next4
        mov     al,bh
next4:
        stosb
        mov     al,bl
        test    ecx,00001000b
        jz      next5
        mov     al,bh
next5:
        stosb
        mov     al,bl
        test    ecx,00000100b
        jz      next6
        mov     al,bh
next6:
        stosb
        mov     al,bl
        test    ecx,00000010b
        jz      next7
        mov     al,bh
next7:
        stosb
        mov     al,bl
        test    ecx,00000001b
        jz      next8
        mov     al,bh
next8:
        stosb
        loop    fill_lookup_table

        mov     al,bl
        mov     ah,bl
        shl     eax,16
        mov     al,bl
        mov     ah,bl
        stosd
        stosd

        pop     ecx
        pop     edi
@@:


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

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]
        ADD     ESI,wselfontsave                ; ESI --> Glyph description
        ADD     ESI,wTopLineOffset
        JMP     vonhc_expand            ; NewCon 6-11-89

substitute_or_control2:
        ADD     ESI,wFirstGlyph
        JS      vonhc_Control_Syllable2

        MOV     ESI,wDefaultGlyph
        JMP     vonhc_default_substituted2

vonhc_Control_Syllable2:
        INC     ESI                     ; -1 => an attribute or return addr.
        JZ      exit_VONHC2


        mov     eax,wDest3rdIncr        ; Otherwise a cell image row boundary.
        call    Update_Bank
        jmp     Process_Pseudo_Code2

exit_VONHC2:

        jmp     Next_attribute_cluster


;/*
;**This is the inner loop opaque mono font expand code
;*/

vonhc_expand:
        mov     cl, bScanLines          ; cl = vert lines in glyph


vonhc_loop2_1:
        lodsb                           ; al = byte from glyph
        movzx   ebx,al
        shl     ebx,3
        add     ebx,offset lookup_table
        mov     eax,[ebx]

        stosd
        mov     eax,[ebx+4]
        stosd

;
;*******************************************
;  Original Code
;******************
;
;       or      di,di
;       jnz     @f
;       dec     edi
;       mov     eax,1
;       call    Update_Bank
;
;
;@@:
;
;       dec     cl                      ; update glyph line count
;       jz      vonhc_nextcell
;       mov     eax,edx
;       call    Update_Bank
;       jmp     vonhc_loop2_1           ; loop through the glyph lines
;
;********************************************

; start           
;********************************************
;
; New Code by Tsu-Wang Chen 4/14/93
; It will eliminate most of the calls to update_bank.
;
;********************************************
;
        or      di, di                  ; check if it is the beginning of
        jz      @f                      ; next bank?

NHC_nextline:

        dec     cl                      ; update glyph line count
        jz      vonhc_nextcell
        add     di, dx
        jnc     vonhc_loop2_1           ; go to next bank?

        ; update_bank
        push    edx                     ; increment the bank number by one.
        mov     dl, Origin_bank
        inc     dl
        mov     Origin_bank, dl
        call    set_bank_select         ; call tseng_bank_switch_rtn to
        pop     edx                     ; change bank.

        jmp     vonhc_loop2_1           ; loop through the glyph lines

@@:
        ; update_bank
        push    edx                     ; increment the bank number by one.
        dec     edi
        inc     di
        mov     dl, Origin_bank
        inc     dl
        mov     Origin_bank, dl
        call    set_bank_select         ; call tseng_bank_switch_rtn to
        pop     edx                     ; change bank.
        jmp    NHC_nextline


;****************************************************
;
; End of the code by Tsu-Wang Chen 4/14/93
;
;****************************************************
;end           

vonhc_nextcell:
        mov     eax, wDest2ndIncr       ; next cell
        Call    Update_Bank
        jmp     Process_Pseudo_Code2


VioDrawOpaqueNHC ENDP


Update_Bank PROC SYSCALL PUBLIC

;/*
;** Entry
;**       EDI - Current vram addr
;**       EAX - Amount to update
;*/

        push    edx
        mov     dl,Origin_bank          ;do a generic test for a bank change
        shl     edx,16                  ;that could be positive or negative
        mov     dx,di                   ;and could be more than one bank
        add     edx,eax
        mov     di, dx                  ;Added by Tsu-Wang Chen           
        shr     edx,16
        cmp     dl,Origin_bank
        je      update_done
        mov     Origin_bank,dl
        call    set_bank_select
update_done:

;**********************************************
;
;  deleted by Tsu-Wang Chen
;  The result is in "add edx,eax"
;        add     di,ax                  ;          
        pop     edx
        RET

Update_Bank ENDP

else    ;~CLR256
;/*
;** 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

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

        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
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.
;/*
;** 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

        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

        PUBLIC  VONHC_Control_Syllable
VONHC_Control_Syllable::
        INC     SI                      ; -1 => An attribute or return addr.
        JZ      Exit_VONHC
        ADD     EDI,CellBLTBlock.cb_Dest_3rd_Incr    ; Otherwise a cell image
                                                     ; row boundary.
        JMP     Process_Pseudo_Code3

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

        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

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

        PUBLIC  VONHC_Control_Syllable2
VONHC_Control_Syllable2::
        INC     ESI                     ; -1 => An attribute or return addr.
        JZ      Exit_VONHC2
        ADD     EDI,wDest3rdIncr        ; Otherwise a cell image row boundary.
        JMP     Process_Pseudo_Code2

        PUBLIC  Exit_VONHC2
Exit_VONHC2::
        JMP     Next_attribute_cluster

VioDrawOpaqueNHC ENDP

endif   ;CLR256


        OPTION  PROLOGUE:PrologueDef
        OPTION  EPILOGUE:EpilogueDef

        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

define_CharRect_frame AVioDrawOpaqueNVC

ifdef   CLR256                          ;our horz & vert are the same (SLOW!)

        JMP     VioDrawOpaqueNHC

else

        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

        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

        PUBLIC  Exit_ANVC
Exit_ANVC::
        JMP     Next_attribute_cluster

endif   ;CLR256

AVioDrawOpaqueNVC   ENDP

        OPTION  PROLOGUE:PrologueDef
        OPTION  EPILOGUE:EpilogueDef

        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

define_CharRect_frame AVioDrawXparentNVC


ifdef   CLR256                          ;sorry - can't use latches

        ;DebugMsg       <XparNVC>


        MOV     wDest2ndIncr,ECX
        MOV     bUnderscoreMask,BL
        MOV     bColor,AH               ;use an existing local cause the
                                        ;the        stk fram def. is in
                                        ;the base.
        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,bColor

        PUBLIC  NextAVioXparentNVCScanLine
NextAVioXparentNVCScanLine::
        DEC     BL
        JZ      LastAVioXparentNVCScanLine
        LODSB                                   ; Get pattern
        XOR     AL,BH                           ; XOR it with rev. vid. tgl.
        MOV     AH,byte ptr OpaqueColorSave
        CALL    Xpar_Expand
        MOV     EAX,EDX
        CALL    Update_Bank
        JMP     NextAVioXparentNVCScanLine

        PUBLIC  LastAVioXparentNVCScanLine
LastAVioXparentNVCScanLine::
        LODSB
        XOR     AL,BH
        OR      AL,bUnderscoreMask
        MOV     AH,byte ptr OpaqueColorSave
        CALL    Xpar_Expand
        MOV     EAX,wDest2ndIncr
        CALL    Update_Bank
        JMP     NextAVioXparentNVCCell

        PUBLIC  AVioXparentNVCControl
AVioXparentNVCControl::
        INC     ESI                     ; -1 => an attribute or return addr.
        JZ      Exit_AXNVC
        MOV     EAX,wDest3rdIncr        ; Otherwise a cell image row boundary.
        CALL    Update_Bank
        JMP     NextAVioXparentNVCCell

        PUBLIC  Exit_AXNVC
Exit_AXNVC::
        MOV     ECX,wDest2ndIncr
        MOV     BL,bUnderscoreMask
        JMP     Next_attribute_cluster

AVioDrawXparentNVC   ENDP


Xpar_Expand PROC SYSCALL PUBLIC

;/*
;**This is the inner loop transparent mono font expand code
;*/

xpar_loop2_1:

        mov     ch, al                  ; ch = byte from glyph
                                        ; cl = mask of when to get out
        mov     al,ah                   ; al = foreground color

xpar_Inner_Loop:

        rcl     ch,1
        jc      xpar_enter_foreground_0

xpar_enter_background_0:

        inc     edi
        rcl     ch,1
        jc      xpar_enter_foreground_1

xpar_enter_background_1:

        inc     edi
        rcl     ch,1
        jc      xpar_enter_foreground_2

xpar_enter_background_2:

        inc     edi
        rcl     ch,1
        jc      xpar_enter_foreground_3

xpar_enter_background_3:

        inc     edi
        rcl     ch,1
        jc      xpar_enter_foreground_4

xpar_enter_background_4:

        inc     edi
        rcl     ch,1
        jc      xpar_enter_foreground_5

xpar_enter_background_5:

        inc     edi
        rcl     ch,1
        jc      xpar_enter_foreground_6

xpar_enter_background_6:

        inc     edi
        rcl     ch,1
        jc      xpar_enter_foreground_7

xpar_enter_background_7:

        inc     edi
        jmp     XPAR_Inner_Loop_Exit   ; 

xpar_enter_foreground_0:
        stosb
        rcl     ch,1
        jnc     xpar_enter_background_1

xpar_enter_foreground_1:
        stosb
        rcl     ch,1
        jnc     xpar_enter_background_2

xpar_enter_foreground_2:
        stosb
        rcl     ch,1
        jnc     xpar_enter_background_3

xpar_enter_foreground_3:
        stosb
        rcl     ch,1
        jnc     xpar_enter_background_4

xpar_enter_foreground_4:
        stosb
        rcl     ch,1
        jnc     xpar_enter_background_5

xpar_enter_foreground_5:
        stosb
        rcl     ch,1
        jnc     xpar_enter_background_6

xpar_enter_foreground_6:
        stosb
        rcl     ch,1
        jnc     xpar_enter_background_7

xpar_enter_foreground_7:
        stosb

XPAR_Inner_Loop_Exit:
        RET
Xpar_Expand ENDP

else    ;~CLR256

        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

        PUBLIC  LastAVioXparentNVCScanLine
LastAVioXparentNVCScanLine::
        LODSB
        XOR     AL,BH
        OR      AL,bUnderscoreMask
        OUT     DX,AL
        XCHG    AL,[EDI]
        ADD     EDI,wDest2ndIncr
        JMP     NextAVioXparentNVCCell

        PUBLIC  AVioXparentNVCControl
AVioXparentNVCControl::
        INC     ESI                     ; -1 => an attribute or return addr.
        JZ      Exit_AXNVC
        ADD     EDI,wDest3rdIncr        ; Otherwise a cell image row boundary.
        JMP     NextAVioXparentNVCCell

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


AVioDrawXparentNVC   ENDP


endif   ;CLR256


        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

define_CharRect_frame AVioDrawXparentHC

ifdef   CLR256


        MOV     bUnderscoreMask,BL
        MOV     bColor,AH
        MOV     bHorizontalClipMask,AL
        AND     DI,0fff8h               ;mask is 0 based

        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

        ALIGN  4
                                        ; If not copy a cell image to the
NextHCScanLine:                         ; destination bitmap.
        DEC     BL
        JZ      LastHCScanLine
        LODSB                           ; Load a scan line.
        XOR     AL,BH                   ; Invert it if we're doing reverse v
        AND     AL,bHorizontalClipMask  ; Clip the line horizontally.
        MOV     AH,byte ptr OpaqueColorSave
        CALL    Xpar_Expand
        MOV     EAX,wDest1stIncr        ; Move EDI to the next target byte.
        CALL    Update_Bank
        JMP     NextHCScanLine

LastHCScanLine:                         ; Processing for the last scan line.

        LODSB
        OR      AL,bUnderscoreMask      ; If we're underscoring.
        XOR     AL,BH
        AND     AL,bHorizontalClipMask
        MOV     AH,byte ptr OpaqueColorSave
        CALL    Xpar_Expand
        MOV     EAX,wDest1stIncr        ; Move EDI to the next target byte.
        CALL    Update_Bank
        MOV     BL,bColor              ; Set the loop counter for the next
                                        ; cell image.
        JMP     NextHCCell

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.
;*/

        MOV     AL,bHorizontalClipMask  ; Restoring AL...
        JMP     Next_attribute_cluster

else    ;~CLR256
        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.

        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

        ALIGN  4
                                        ; 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

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.
        JMP     NextHCCell

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.
;*/

        DEC     wDest1stIncr            ; Restore the EDI increment to its
                                        ; its initial value.
        MOV     AL,CH                   ; Restoring AL...
        JMP     Next_attribute_cluster

endif   ;~CLR256

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

define_CharRect_frame AVioDrawOpaqueHC

ifdef   CLR256


        MOV     bUnderscoreMask,BL
        MOV     bReverse,BH             ;use an existing local cause the
                                        ;the        stk fram def. is in
                                        ;the base.
        AND     DI,0fff8h               ;mask is 0 based

        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,wTopLineOffset                              ; Top lines to skip.
        MOV     BH,bScanLines                           ; CH is the counter for the scan line

        PUBLIC  NextOHCScanLine
NextOHCScanLine::
        DEC     BH
        JZ      LastOHCScanLine

        LODSB                           ; Get character scan line
        XOR     AL,bReverse                   ; XOR against rev. vid. msk.
        MOV     BL,bHorizontalClipMask ; bl = clip mask
        MOV     CL,8
        MOV     CH,AL

OHCExpand:
        RCL     CH,1
        MOV     AL, byte ptr OpaqueColorSave + 1 ; assume background
        JNC     @f                               ; is this a background color?
        MOV     AL, byte ptr OpaqueColorSave     ;  nope, set the foreground
@@:
        RCL     BL, 1                   ; rotate a mask bit into carry
        JNC     @f
        MOV     [EDI], AL               ; set the pixel
@@:
;JMW    INC     EDI                     ; update the pixel addr
        inc     di                      ;JMW
        jnz     @f                      ;JMW
        dec     di                      ;JMW
        mov     eax,1                   ;JMW
        call    Update_Bank             ;JMW
@@:                                     ;JMW
        DEC     CL                      ; update glyph byte expansion
        JNZ     OHCExpand               ; top of innner loop
        MOV     EAX,EDX
        CALL    Update_Bank
        JMP     NextOHCScanLine         ; Do next char. line

        PUBLIC  LastOHCScanLine

LastOHCScanLine::

        LODSB                           ; Last scan line of character
        OR      AL,bUnderscoreMask                   ; Do underscore if requested
        XOR     AL,bReverse

        MOV     BL,bHorizontalClipMask ; bl = clip mask
        MOV     CL,8
        MOV     CH,AL

OHCExpand2:
        RCL     CH,1
        MOV     AL, byte ptr OpaqueColorSave + 1 ; assume background
        JNC     @f                               ; is this a background color?
        MOV     AL, byte ptr OpaqueColorSave     ;  nope, set the foreground
@@:
        RCL     BL, 1                   ; rotate a mask bit into carry
        JNC     @f
        MOV     [EDI], AL               ; set the pixel
@@:
        INC     EDI                     ; update the pixel addr
        DEC     CL                      ; update glyph byte expansion
        JNZ     OHCExpand2              ; top of innner loop

        MOV     EAX,EDX
        CALL    Update_Bank
        JMP     NextOHCSyllable

        PUBLIC  OHCControl
OHCControl::

        MOV     BL,bUnderscoreMask
        MOV     BH,bReverse
        RET

else    ;~CLR256

        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

        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

        PUBLIC  OHCControl
OHCControl::
        DEC     EDX

        RET

endif   ;CLR256


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
;*
;**************************************************************************/


SetDisplayDefaults  PROC


ifndef  CLR256
        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

endif   ;CLR256

        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
;*
;**************************************************************************/

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
;*
;**************************************************************************/

InvertScreenRect PROC SYSCALL PRIVATE


ifdef   CLR256

        ;DebugMsg <ISR>

        PUSHA

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

        MOV     AX,SCREEN_CBSCAN        ; Screen pitch in bytes
        MUL     BX                      ; * yStart and bank Result to DX
        SUB     DI,BX                   ;BX will hold scan loop count
        MOV     BX,DI
        MOVZX   EDI,CX                  ;Get start x into di
        ADD     DI,AX                   ;add in y start
        ADC     DL,DH                   ;and set the bank
        CALL    set_bank_select
        ADD     EDI,pVRAMInstance       ; Point into video memory
        SUB     SI,CX                   ;calc num x pixels
        MOV     CX,SI
        MOV     AX,-1
ISRLineLoop:
        PUSH    ECX
        PUSH    EDI
        SHR     CX,1
        JCXZ    ISRByte
ISRWordLoop:
        XOR     [EDI],AX
        ADD     EDI,2
        LOOP    ISRWordLoop
ISRByte:
        JNC     @f
        XOR     [EDI],AL
        INC     EDI
@@:
        POP     EDI
        POP     ECX
        DEC     BX
        JZ      ISR_Done
        ADD     DI,SCREEN_CBSCAN
        JNC     ISRLineLoop
        INC     DL
        CALL    set_bank_select
        JMP     ISRLineLoop
ISR_Done:
        POPA
        RET

else    ;~CLR256

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

        ;DebugMsg <InvrtScrRect>

        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
        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

        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

endif   ;CLR256

InvertScreenRect ENDP

        OPTION  PROLOGUE:NONE
        OPTION  EPILOGUE:NONE

        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
;*
;**************************************************************************/

define_CharRect_frame AVioDrawText



ifdef   CLR256
        CLD
else
        STD                     ; Will do characters upwards
endif
        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

;/*
;** 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

;/*
;** 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
                                        ; 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

;/*
;** 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 f
;*/

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

;/*
;** 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

;/*
;** 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

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

        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

;/*
;** 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::

ifdef   CLR256



;/*
;** 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

        ADD     EAX,EBX                 ; Add to line address

        PUBLIC  X_neg
X_neg::

        PUBLIC  Sv_byte_addr
Sv_byte_addr::

        ROR     EAX,16
        MOV     DL,AL                   ; isolate bank number
        MOV     Origin_bank,DL
        MOV     bColor,DL               ; save in a temp var in case char
        call    set_bank_select         ; straddles a bank boundary
        XOR     Al,AL                   ; remove bank # from address
        ROL     EAX,16                  ; restore address

        ADD     EAX,lpBitmapBits        ; Point to video memory
        MOV     wByteAddr,EAX           ; and save

;/*
;** 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

;/*
;** Now draw the character. Construct a shift count to handle
;** left side clipping, and set the total number bytes writen
;** to handle right side clipping
;*/

        XOR     DL,DL                   ; will hold left clip rotate count
        MOV     EBX,wX                  ; fetch x coord in case its negative
        MOVZX   ECX,wCellWidth          ; get max loop count
        MOV     DH,CL                   ; dh holds num pixels this column
        CMP     DH,8
        JBE     @F
        MOV     DH,8
@@:
        OR      EBX,EBX
        JNS     cxstart_ok
        ADD     ECX,EBX                 ; reduce width by amount off screen
        NEG     EBX
        MOV     DL,BL
        SUB     DH,DL
        XOR     EBX,EBX                 ; and set start x to 0

        public  cxstart_ok
cxstart_ok::

        MOV     EDI,wByteAddr           ; Get byte address
        CMP     EBX,wClipXmin           ; Compare with xmin
        JGE     cleft_clip_ok
        SUB     EBX,wClipXmin
        ADD     ECX,EBX                 ; reduce loop count by amount of left clip
        NEG     EBX
        ADD     EDI,EBX                 ; and adjust start addr to left border of clip rect
        ADD     DL,BL                   ; set right clip rotate count
        SUB     DH,BL                   ; and total pixels this column
        jae     @f                      ;          
        mov     dh,cl                   ;          
@@:                                     ;          
        MOV     EBX,wClipXmin

cleft_clip_ok:

        ADD     EBX,ECX                 ; now add width and check right clip
;;;;    DEC     EBX                     ;            xClipXmax is exlusive
        SUB     EBX,wClipXmax           ; Compare with xmax
        JLE     cright_clip_ok
        SUB     ECX,EBX                 ; Reduce loop cnt by amount of right clip
        CMP     DH,CL                   ; this column less than total ?
        JBE     cright_clip_ok
        MOV     DH,CL

cright_clip_ok:

        PUSH    ESI
        SUB     CL,DH                   ; calc num pixels next column

ifdef   cross_seg                       ;          
        push    edx                     ;          
        xor     edx,edx                 ;          
        mov     ax,di                   ;Only need offset into bank for this
        mov     bx,SCREEN_CBSCAN        ;          
        div     bx                      ;          
        mov     bx,dx                   ;          
        pop     edx                     ;          
else    ;cross_seg                      ;          
        mov     ebx,edi                 ;          
        and     ebx,03ffh               ;          

;/*
;** This only works when the bytes per scanline = 1024
;*/

endif   ;cross_seg                      ;          
        movzx   eax,dh                  ;          
        add     ebx,eax                 ;          
        sub     ebx,wClipXmax           ; Compare with xmax
        jl      @f                      ;          
        xor     ecx,ecx                 ; Reduce loop cnt by amount of right clip
@@:                                     ;          
        cmp     ecx,ebx                 ;          
        jbe     @f                      ;          
        mov     ecx,ebx                 ;          
@@:                                     ;          
        push    ecx                     ;          

        ADD     EAX,EDI                 ; calc start addr for next column
        PUSH    EAX
        MOV     AX,wColor

;/*
;** now draw bottom line of this char column with underscore
;*/

        MOV     EBX,wY                  ; Get Y coordinate
        CMP     EBX,wClipYmin           ; Compare with ymin
        JL      done_underscore_line    ; Go if outside
        CMP     EBX,wClipYmax           ; Compare with ymax
        JGE     done_underscore_line    ; Go if outside
        MOV     CH,[ESI]                ; Read font
        OR      CH,bUnderscoreMask      ; OR underscore
        PUSH    EDI
        TEST    CH,0FFh                 ; Zero slice ?
        JZ      chk_underscore_bgnd     ; Skip if yes
        MOV     CL,DL                   ; get rotate mask
        SHL     CH,CL
        MOV     CL,DH                   ; get store count
        CMP     wFunction,0
        JNE     usl_o_char

usl_t_loop:
        SHL     CH,1
        JC      @F
        INC     EDI
usl_t_ctr:
        DEC     CL
        JNZ     usl_t_loop
        JMP     SHORT finis_underscore_line
@@:
        STOSB
        JMP     SHORT usl_t_ctr

usl_o_char:
        CMP     CL,4            ; see if we can accelerate
        JB      entr_usl_oloop
        MOVZX   EAX,CH
        SHR     AL,4
        SHL     CH,4
        SUB     CL,4
        MOV     EAX,temp_lookup_table[EAX*SIZE DWORD]
        STOSD
        OR      CL,CL
        JNZ     usl_o_char
        JMP     SHORT finis_underscore_line

entr_usl_oloop:
        MOV     AX,wColor

usl_o_loop:
        SHL     CH,1
        JC      @F
        MOV     [EDI],AH
        INC     EDI
usl_o_ctr:
        DEC     CL
        JNZ     usl_o_loop
        JMP     SHORT finis_underscore_line
@@:
        STOSB
        JMP     SHORT usl_o_ctr

chk_underscore_bgnd:
        CMP     wFunction,0
        JE      finis_underscore_line
        MOV     AL,AH
        MOVZX   ECX,DH                  ; get store count
        REP     STOSB

finis_underscore_line:

        POP     EDI

done_underscore_line:


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

        SHL     EDX,16
        MOV     DX,wCellHeight          ; OUTER Loop count = cell height
        DEC     DX                      ; Already did 1
        ROR     EDX,16                  ; GET BACK SHIFT AND INNER LOOP CNTS

        PUBLIC  CL_FG_Box_loop_1
CL_FG_Box_loop_1::

        DEC     EBX                     ; Y =Y - 1
        SUB     ESI,1                   ; Up one line
        MOV     EAX,SCREEN_CBSCAN       ; Up one line
        NEG     EAX
        CALL    Update_Bank

        CMP     EBX,wClipYmin           ; Compare with ymin
        JL      done_reg_line           ; Go if outside
        CMP     EBX,wClipYmax           ; Compare with ymax
        JGE     done_reg_line           ; Go if outside
        MOV     CH,[ESI]                ; Read font
        MOV     AX,wColor
        PUSH    EDI
        TEST    CH,0FFh                 ; Zero slice ?
        JZ      chk_reg_bgnd            ; Skip if yes
        MOV     CL,DL                   ; get rotate mask
        SHL     CH,CL
        MOV     CL,DH                   ; get store count
        CMP     wFunction,0
        JNE     regl_o_char

        or      cl,cl                   ;          
        je      finis_reg_line          ;          
regl_t_loop:
        SHL     CH,1
        JC      @F
        INC     EDI
regl_t_ctr:
        DEC     CL
        JNZ     regl_t_loop
        JMP     SHORT finis_reg_line
@@:
        STOSB
        JMP     SHORT regl_t_ctr

regl_o_char:
        CMP     CL,4            ; see if we can accelerate
        JB      entr_regl_oloop
        MOVZX   EAX,CH
        SHR     AL,4
        SHL     CH,4
        SUB     CL,4
        MOV     EAX,temp_lookup_table[EAX*SIZE DWORD]
        STOSD
        OR      CL,CL
        JNZ     regl_o_char
        JMP     SHORT finis_reg_line

entr_regl_oloop:
        MOV     AX,wColor
        or      cl,cl                   ;          
        je      finis_reg_line          ;          
regl_o_loop:
        SHL     CH,1
        JC      @F
        MOV     [EDI],AH
        INC     EDI
regl_o_ctr:
        DEC     CL
        JNZ     regl_o_loop
        JMP     SHORT finis_reg_line
@@:
        STOSB
        JMP     SHORT regl_o_ctr

chk_reg_bgnd:
        CMP     wFunction,0
        JE      finis_reg_line
        MOV     AL,AH
        MOVZX   ECX,DH                  ; get store count
        REP     STOSB

finis_reg_line:

        POP     EDI

 done_reg_line:

        ROR     EDX,16
        DEC     DX
        JZ      done_column
        ROR     EDX,16
        JMP     CL_FG_Box_loop_1        ; Loop

done_column:

        POP     EDI                     ; get addr. of last line next column
        POP     ECX
        POP     ESI                     ; recover font pointer
        JECXZ   CL_FG_Box_end           ; if all done then get out
        MOVZX   EDX,wCellHeight
        ADD     ESI,EDX                 ; point to last byte next column
        MOV     DL,bColor               ; see if we changed banks
        CMP     DL,Origin_bank
        JE      @f
        MOV     Origin_bank,DL
        CALL    set_bank_select
@@:
        MOV     DX,800H                 ; set new shift and store counts
        CMP     DH,CL
        JBE     @F
        MOV     DH,CL                   ; set final count
@@:
        JMP     cright_clip_ok

        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

;/*
;** 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

;/*
;** 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

;/*
;** 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

;/*
;** 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


;/*
;** 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
        ADD     EAX,EBX                 ; Add to line address

        ROR     EAX,16
        MOV     DL,AL                   ; isolate bank number
        MOV     Origin_bank,DL
        MOV     bColor,DL               ; save in a temp var in case char
        call    set_bank_select         ; straddles a bank boundary
        XOR     Al,AL                   ; remove bank # from address
        ROL     EAX,16                  ; restore address

        ADD     EAX,lpBitmapBits        ; Point to video memory
        MOV     EDI,EAX

        MOVZX   ECX,wCellWidth          ; get max loop count
        MOV     DH,CL                   ; dh holds num pixels this column
        CMP     DH,8
        JBE     @F
        MOV     DH,8
@@:

nc_outer_loop:

        PUSH    ESI                     ; SAVE FONT ADDR
        SUB     CL,DH                   ; calc num pixels next column
        PUSH    ECX
        MOVZX   EAX,DH
        ADD     EAX,EDI                 ; calc start addr for next column
        PUSH    EAX
        MOV     AX,wColor

;/*
;** now draw bottom line of this char column with underscore
;*/

        MOV     CH,[ESI]                ; Read font
        OR      CH,bUnderscoreMask      ; OR underscore
        PUSH    EDI
        TEST    CH,0FFh                 ; Zero slice ?
        JZ      nc_chk_underscore_bgnd  ; Skip if yes
        MOV     CL,DH                   ; get store count
        CMP     wFunction,0
        JNE     nc_usl_o_char

nc_usl_t_loop:
        SHL     CH,1
        JC      @F
        INC     EDI
nc_usl_t_ctr:
        DEC     CL
        JNZ     nc_usl_t_loop
        JMP     SHORT nc_finis_underscore_line
@@:
        STOSB
        JMP     SHORT nc_usl_t_ctr

nc_usl_o_char:
        CMP     CL,4            ; see if we can accelerate
        JB      nc_entr_usl_oloop
        MOVZX   EAX,CH
        SHR     AL,4
        SHL     CH,4
        SUB     CL,4
        MOV     EAX,temp_lookup_table[EAX*SIZE DWORD]
        STOSD
        OR      CL,CL
        JNZ     nc_usl_o_char
        JMP     SHORT nc_finis_underscore_line

nc_entr_usl_oloop:
        MOV     AX,wColor

nc_usl_o_loop:
        SHL     CH,1
        JC      @F
        MOV     [EDI],AH
        INC     EDI
nc_usl_o_ctr:
        DEC     CL
        JNZ     nc_usl_o_loop
        JMP     SHORT nc_finis_underscore_line
@@:
        STOSB
        JMP     SHORT nc_usl_o_ctr

nc_chk_underscore_bgnd:
        CMP     wFunction,0
        JE      nc_finis_underscore_line
        MOV     EAX,DWORD PTR temp_lookup_table[0]      ; fetch background dword
        MOVZX   ECX,DH                  ; get store count
        SHR     ECX,2
        REP     STOSD
        MOV     CL,DH
        AND     CL,(SIZE DWORD) - 1
        JZ      nc_finis_underscore_line
        REP     STOSB

nc_finis_underscore_line:

        POP     EDI

nc_done_underscore_line:


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

        SHL     EDX,16
        MOV     DX,wCellHeight          ; OUTER Loop count = cell height
        DEC     DX                      ; Already did 1
        ROR     EDX,16                  ; GET BACK SHIFT AND INNER LOOP CNTS

        PUBLIC  FG_Box_loop_1
FG_Box_loop_1::

        SUB     ESI,1                   ; Up one line
        MOV     EAX,SCREEN_CBSCAN       ; Up one line
        NEG     EAX
        CALL    Update_Bank

        MOV     CH,[ESI]                ; Read font
        MOV     AX,wColor
        PUSH    EDI
        TEST    CH,0FFh                 ; Zero slice ?
        JZ      nc_chk_reg_bgnd           ; Skip if yes
        MOV     CL,DH                   ; get store count
        CMP     wFunction,0
        JNE     nc_regl_o_char

nc_regl_t_loop:
        SHL     CH,1
        JC      @F
        INC     EDI
nc_regl_t_ctr:
        DEC     CL
        JNZ     nc_regl_t_loop
        JMP     SHORT nc_finis_reg_line
@@:
        STOSB
        JMP     SHORT nc_regl_t_ctr

nc_regl_o_char:
        CMP     CL,4            ; see if we can accelerate
        JB      nc_entr_regl_oloop
        MOVZX   EAX,CH
        SHR     AL,4
        SHL     CH,4
        SUB     CL,4
        MOV     EAX,temp_lookup_table[EAX*SIZE DWORD]
        STOSD
        OR      CL,CL
        JNZ     nc_regl_o_char
        JMP     SHORT nc_finis_reg_line

nc_entr_regl_oloop:
        MOV     AX,wColor
nc_regl_o_loop:
        SHL     CH,1
        JC      @F
        MOV     [EDI],AH
        INC     EDI
nc_regl_o_ctr:
        DEC     CL
        JNZ     nc_regl_o_loop
        JMP     SHORT nc_finis_reg_line
@@:
        STOSB
        JMP     SHORT nc_regl_o_ctr

nc_chk_reg_bgnd:
        CMP     wFunction,0
        JE      nc_finis_reg_line
        MOV     EAX,DWORD PTR temp_lookup_table[0]      ; fetch background dword
        MOVZX   ECX,DH                  ; get store count
        SHR     ECX,2
        REP     STOSD
        MOV     CL,DH
        AND     CL,(SIZE DWORD) - 1
        JZ      nc_finis_reg_line
        REP     STOSB

nc_finis_reg_line:

        POP     EDI

nc_done_reg_line:

        ROR     EDX,16
        DEC     DX
        JZ      nc_done_column
        ROR     EDX,16
        JMP     FG_Box_loop_1   ; Loop

nc_done_column:

        POP     EDI                     ; get addr. of last line next column
        POP     ECX
        POP     ESI                     ; recover font pointer
        JECXZ   FG_Box_end              ; if all done then get out
        MOVZX   EDX,wCellHeight
        ADD     ESI,EDX                 ; point to last byte next column
        MOV     DL,bColor               ; see if we changed banks
        CMP     DL,Origin_bank
        JE      @f
        MOV     Origin_bank,DL
        CALL    set_bank_select
@@:
        MOV     DX,800H                 ; set new shift and store counts
        CMP     DH,CL
        JBE     @F
        MOV     DH,CL                   ; set final count
@@:
        JMP     nc_outer_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

else    ;~CLR256

;/*
;** 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

        PUBLIC  X_neg
X_neg::

        DEC     EAX

        PUBLIC  Sv_byte_addr
Sv_byte_addr::


        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

;/*
;** 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

;/*
;** 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

;/*
;** 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

;/*
;** 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
        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

;/*
;** 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.
;*/

        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.

;/*
;** 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
        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

        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

endif   ;CLR256


AVioDrawText ENDP

        OPTION  PROLOGUE:PrologueDef
        OPTION  EPILOGUE:EpilogueDef

ENDIF; VGA

_AvioSupport ENDS

        END


