;*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.;
;*****************************************************************************/
; SCCSID = @(#)celldraw.asm 6.1 89/06/26
 page ,132
;---------------------------Module-Header-------------------------------;
; Module Name: CELLDRAW.INC
;
; Abstract:  This module contains drawing functions which materialize
;      the image of a logical video buffer based on pseudocode
;      placed in the stack by routines from the CellScan.asm
;      module.
;
; Created:  26-Jun-87
; Author:   ronm
;
;
;
;
; Description:
;
;   Extracted from celldraw.asm, because too much modifications
;   are necessary to support DBCS device fonts - Soh Ohta
;
;-----------------------------------------------------------------------;

;---------------------------Private Routine-----------------------------;
; GetAVioAttributes
;
; Convert miscellenious attribute format to AVio format.
; We will check current PS format and interpret color attributes
; as nessesary.
;
; Entry:
; ESI = cell attribute to be translated to AVio attributes.
; EBP = CharRect frame
; Returns:
; ESI = AVio compatible cell attributes
; Error Returns:
; None
; Registers Destroyed:
; EAX,FLAGS
; Registers Preserved:
; EAX,EBX,EDX,EBP,EDI
; Calls:
; None
; History:
;  Thu 26-Dec-90 20:00:00 -by Soh Ohta [soh]
; Wrote it!
;-----------------------------------------------------------------------;

 OPTION PROLOGUE:NONE
 OPTION EPILOGUE:NONE

;ALIGN 4
define_CharRect_frame GetAVioAttributes

ifdef IBMJ  ; IBM-Japan Vio attribute support    ;IBMJ

; Translate IBM Japan unique attributes to common DBCS format.

 cmp FormatID,FORMATID_IBMJ_COLOR
 je ps_ibmj_vio
 cmp FormatID,FORMATID_IBMJ_MONO
 je ps_ibmj_vio
 jmp have_attributes

ps_ibmj_vio:
 mov ecx,esi   ; CH = IBM-Japan Vio attribute bits
 xor esi,esi   ; SI = AVio compatible attributes

 test ch,IBMJVioVerticalGridMask
 jz @f
 or esi,AVioVerticalGridMask
@@: test ch,IBMJVioHorizontalGridMask
 jz @f
 or esi,AVioHorizontalGridMask
@@: cmp FormatID,FORMATID_IBMJ_COLOR
 jne ps_mono

ps_color:
 or esi,AVioColorRMask+AVioColorGMask+AVioColorBMask
 test dQualifier,IBMJPhysHiLighted
 jz @f
 or esi,AVioColorIMask
@@: test ch,IBMJVioColorRoffMask
 jz @f
 and esi,not AVioColorRMask
@@: test ch,IBMJVioColorGoffMask
 jz @f
 and esi,not AVioColorGMask
@@: test ch,IBMJVioColorBoffMask
 jz @f
 and esi,not AVioColorBMask
@@: test ch,IBMJVioReverseVideoMask
 jz have_attributes
 or esi,AVioReverseVideoMask
 jmp have_attributes

ps_mono:
 or esi,AVioColorRMask+AVioColorGMask+AVioColorBMask+AVioColorIMask
 and ch,IBMJVioInvisibleMask
 cmp ch,IBMJVioInvisibleMask
 jne @f
 and esi,not (AVioColorRMask+AVioColorGMask+AVioColorBMask+AVioColorIMask)
 jmp have_attributes

@@: mov cl,MM_ALL  ; white
 test ch,IBMJVioIntensityMask
 jnz @f
 and cl,bPhysColor  ; specified color
 and esi,not AVioColorIMask
@@: mov bCellColor,cl  ; color used for mono text
 test ch,IBMJVioReverseVideoMask
 jz @f
 or esi,AVioReverseVideoMask
@@: test ch,IBMJVioUnderscoreMask
 jz have_attributes
 or esi,AVioUnderscoreMask

have_attributes:
endif;IBMJ        ;IBMJ

filter_horz_grid:
 mov bHorzGridMask,0
 test esi,AVioHorizontalGridMask
 jz filter_vert_grid
 and esi,(NOT AVioHorizontalGridMask)
 cmp wTopLineOffset,0
 jne filter_vert_grid
 or esi,AVioHorizontalGridMask
 mov bHorzGridMask,0FFh ; horizontal grid pattern

filter_vert_grid:
 mov bVertGridMask,0
 test esi,AVioVerticalGridMask
 jz save_attributes
 and esi,(NOT AVioVerticalGridMask)
 cmp wLeftLineOffset,0
 jne save_attributes
 or esi,AVioVerticalGridMask
 mov bVertGridMask,080h ; vertical grid pattern

save_attributes:
 mov wAVioAttributes,esi
 ret

GetAVioAttributes endp

 OPTION PROLOGUE:PrologueDef
 OPTION EPILOGUE:EpilogueDef

 SUBTITLE AVioDrawOpaqueNVC
 PAGE +

;***************************** Private Function ******************************
;    Function: AVioDrawOpaqueNVC          *
;      Author: Soh Ohta [jl09057 @ ymtvm3]         *
;  Date: Wed 14-Aug-1991           *
;----------------------------------------------------------------------------*
; 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.             *
;----------------------------------------------------------------------------*
; Register calling convention:           *
;   Register contents:            *
;     Entry:             *
; 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.           *
;     Exit:             *
; EDI --> Points to the top scan line of the next cell to be drawn.    *
; ESP --> Moves according to the pseudocode consumed by this function. *
;   Error Returns:            *
;     None             *
; Registers Destroyed:
; AL CX SI
; Registers Preserved:
; BP
;----------------------------------------------------------------------------*
; Functions called:            *
;   External:             *
;     None             *
;   Local:             *
;     None             *
;----------------------------------------------------------------------------*
; Revision history:            *
;   PTR/DCR    Date    Who  Remarks          *
;   -------  --------  ---  ------------------------------------------------ *
;    Orig.   11/21/91  KEZ  Original          *
;*****************************************************************************

 OPTION PROLOGUE:NONE
 OPTION EPILOGUE:NONE

;ALIGN 4
define_CharRect_frame AVioDrawOpaqueNVC

; If cells include only horizontal grid, process them in special way.
; It is important for reducing runtime condition check in generic logic.

 test wAVioAttributes,AVioHorizontalGridMask
 jz aonvc_comp_scans ; no horizontal grid
 dec ah   ; -1 when horizontal grid exists
 jnz aonvc_comp_scans ; more than one scan


; Only horizontal grid scan. Draw these cells by special way.
; In this loop, we need not to get source font image address anyway.

 MOV esi,pVRAMInstance ; This gets our
 mov al,[esi+horz_grid_latches] ; get grid color into latch
 xor al,al   ; select background (grid) color
aonvc_draw_only_grid:
 pop esi   ; fetch pseudo code
 movsx esi,si
 cmp esi,-2
 jae aonvc_control_syllable0
 stosb    ; draw horizontal grid
 jmp aonvc_draw_only_grid

aonvc_control_syllable0:
 cmp esi,-2
 je aonvc_next_row0  ; -2 => goto the next row
 jmp aonvc_exit  ; -1 => an attribute or return addr.

aonvc_next_row0:
 add edi,wDest3rdIncr
 jmp aonvc_draw_only_grid


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

aonvc_comp_scans:
 mov cl,MaxSymbolLines
 sub cl,ah   ; AH is scan lines to draw.
 mov ch,cl   ; multiply cl by 3, the size of
 shl cl,1   ; movsb; add edi,edx
 add cl,ch
 movzx ecx,cl
 add ecx,OFFSET aonvc_draw_top_scan

; Setup cell background according to the vertical grid attribute.

 MOV ESI,pVRAMInstance    ; This gets our
 lea esi,[ESI+tonys_bar_n_grill]   ; cell background without grid
 test wAVioAttributes,AVioVerticalGridMask
 jz aonvc_have_cell_back ; no vertical grid

 mov ax,GRAF_BIT_MASK+(7Fh shl 8)
 mov dx,EGA_BASE+GRAF_ADDR
 out dx,ax   ; initialize cell bitmask
 mov edx,wDest1stIncr ; restore DX
 MOV esi,pVRAMInstance ; This gets our
 lea esi,[esi+vert_grid_latches] ; cell background with grid

aonvc_have_cell_back:
 mov ah,bl   ; AH = underscore mask
 mov ebx,esi   ; EBX = cell background
 mov al,[ebx]  ; load cell background to latch
 jmp aonvc_fetch_glyph ; start interpretting

; Dispatch to the appropriate cell scanlines drawing entries.
; Update bitmask and cell background if vertical grid selection is changed.
; If horizontal grid is involved, draw it first and go to the next scan.

aonvc_draw_scans:
 test wAVioAttributes,AVioHorizontalGridMask
 jnz aonvc_draw_horz_grid ; draw horizontal grid first
 jmp ecx   ; draw cell body scans

aonvc_draw_horz_grid:
 push ebx
 MOV ebx,pVRAMInstance ; This gets our
 mov al,[ebx+horz_grid_latches] ; get grid color into latch
 pop ebx
 mov byte ptr [edi],0 ; draw horz grid as cell background
 inc esi   ; skip one source scan
 inc edi
 add edi,edx
 mov al,[ebx]  ; restore current cell background
 jmp ecx   ; draw cell body scans

aonvc_draw_top_scan:
 rept MaxSymbolLines-1
 movsb
 add edi,edx
 endm
 lodsb
 or al,ah
 stosb
 add edi,wDest2ndIncr

; Fetch one pseudo code from the top of stack and process it.

aonvc_fetch_glyph:
 pop esi
 movsx esi,si
 or esi,esi
 js aonvc_control_syllable
 sub esi,wFirstGlyph
 cmp esi,wGlyphSpan
 jb aonvc_no_substitution
 mov esi,wDefaultGlyph

aonvc_no_substitution:
 imul esi,esi,6
 add esi,wselfontsave  ; ESI --> Glyph description
 mov esi,dword ptr FONTMAP.fsCharOffset[esi]
 add esi,wselfontsave ; ESI --> Character bitmap
 add esi,wTopLineOffset
 jmp aonvc_draw_scans

; The pseudo code may be the control syllable, or DBCS code point.

aonvc_control_syllable:
 cmp esi,-1   ; -1 => an attribute or return addr.
 je aonvc_exit
 cmp esi,-2   ; -2 => goto the next row
 je aonvc_next_row
 call GetFontOffset8  ; get DBCS font image offset
 add esi,wTopLineOffset
 jmp aonvc_draw_scans

aonvc_next_row:
 add edi,wDest3rdIncr
 jmp aonvc_fetch_glyph

aonvc_exit:
 mov dx,EGA_BASE+GRAF_ADDR
 mov ax,GRAF_BIT_MASK+(0FFh shl 8)
 out dx,ax   ; make bitmask as default (all pels)
 MOV eax,pVRAMInstance   ; This gets our
 mov al,[eax+tonys_bar_n_grill] ; make cell background no grid
 jmp Next_attribute_cluster

AVioDrawOpaqueNVC endp

 OPTION PROLOGUE:PrologueDef
 OPTION EPILOGUE:EpilogueDef

 SUBTITLE AVioDrawGridOHC
 PAGE +

;---------------------------Private Routine-----------------------------;
; AVioDrawGridOHC
;
; This routine draws the gridlines of a stream of opaque AVio 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.
;
; Assumes:
; GRAF_MODE     = M_PROC_WRITE
; Entry:
;    EDI = Destination pointer.  It points to the top byte of the
;    EBP = CharRect frame
; Returns:
;    EDI = will point to the top scan line of the next cell to be
;      drawn.
; Error Returns:
; None
; Registers Destroyed:
; AX,BX,CX,DX,SI,FLAGS
; Registers Preserved:
; BP,DS,ES
; Calls:
; None
; History:
;  Wed 14-Aug-1991 -by-  Soh Ohta [jl09057 @ ymtvm3]
; Wrote it!
;-----------------------------------------------------------------------;

 OPTION PROLOGUE:NONE
 OPTION EPILOGUE:NONE

;ALIGN 4
define_CharRect_frame AVioDrawGridOHC

 mov ebx,wDest1stIncr
 inc ebx   ; EBX = primary increment + 1
 mov ch,bScanLines  ; CH = number of scanlines

; Setup graphics controller for drawing gridlines.

 mov dx,EGA_BASE+SEQ_ADDR
 mov ax,SEQ_MAP_MASK+(MM_ALL shl 8)
 out dx,ax
 mov dx,EGA_BASE+GRAF_ADDR
 mov ax,GRAF_ENAB_SR+(MM_ALL shl 8)
 out dx,ax
 mov ax,GRAF_SET_RESET+(MM_ALL shl 8)
 out dx,ax   ; set grid color

 mov ah,bVertGridMask ; AH = grid pattern
 mov al,GRAF_BIT_MASK ; AL = bitmask register
 out dx,ax   ; DX = port address

agohc_fetch_glyph:
 mov esi,npinxGlyph
 add esi,4
 xchg esi,npinxGlyph
 movsx esi,word ptr [esi]

 cmp esi,-2
 jae agohc_exit

; Draw horizontal/vertical grid for this cell.

 mov cl,ch   ; CL = number of scanlines
 test wAVioAttributes,AVioHorizontalGridMask
 jnz agohc_draw_horz_grid

agohc_draw_vert_grid:
 xchg ah,[edi]
 add edi,ebx
 dec cl
 jnz agohc_draw_vert_grid
 jmp agohc_fetch_glyph

agohc_draw_horz_grid:
 mov ah,bHorzGridMask ; horizontal grid pattern
 and ah,bHorizontalClipMask
 out dx,ax
 xchg ah,[edi]
 add edi,ebx
 mov ah,bVertGridMask ; vertical grid pattern
 out dx,ax
 dec cl
 jnz agohc_draw_vert_grid
 jmp agohc_fetch_glyph

agohc_exit:
 mov ah,bHorizontalClipMask
 mov al,GRAF_BIT_MASK
 out dx,ax
 ret

AVioDrawGridOHC  endp

 OPTION PROLOGUE:PrologueDef
 OPTION EPILOGUE:EpilogueDef

 SUBTITLE AVioDrawGrid8
 PAGE +

;---------------------------Private Routine-----------------------------;
; AVioDrawGrid8
;
; Draw gridlines for 8 pels wide cells.
; This routine assumes the following graphics controller states,
; so that we only change the foreground color for drawing gridlines.
;
; Assumes:
; GRAF_MODE     = M_PROC_WRITE
; SEQ_MAP_MASK  = MM_ALL
; GRAF_ENAB_SR  = MM_ALL
; GRAF_DATA_ROT = DR_SET
; Entry:
;    EBP = CharRect frame
;    EBX = primary increment + 1
;    EDI = destination address
; Returns:
; None
; Error Returns:
; None
; Registers Destroyed:
; DI,FLAGS
; Registers Preserved:
; AX,BX,CX,DX,SI,DS,ES
; Calls:
; None
; History:
;  Wed 14-Aug-1991 -by-  Soh Ohta [jl09057 @ ymtvm3]
; Wrote it!
;-----------------------------------------------------------------------;

 OPTION PROLOGUE:NONE
 OPTION EPILOGUE:NONE

;ALIGN 4
define_CharRect_frame AVioDrawGrid8

 push eax
 push ecx
 push edx

 mov ch,bScanLines  ; CH = number of scanlines

; Setup graphics controller for drawing gridlines.

 mov dx,EGA_BASE+GRAF_ADDR ; DX = port address
 mov ax,GRAF_SET_RESET+(MM_ALL shl 8)
 and ah,bPhysColor
 out dx,ax   ; set grid color
 mov al,GRAF_BIT_MASK ; AL = bitmask register

; Draw horizontal/vertical grid for this cell.

 mov ah,bHorzGridMask ; horizontal grid pattern
 and ah,bHorizontalClipMask
 jnz ag8_draw_horz_grid
 mov ah,bVertGridMask ; vertical grid pattern
 out dx,ax

ag8_draw_vert_grid:
 xchg ah,[edi]
ag8_draw_vert_next:
 dec ch
 jz ag8_exit
 add edi,ebx
 jmp ag8_draw_vert_grid

ag8_draw_horz_grid:
 out dx,ax
 xchg ah,[edi]
 mov ah,bVertGridMask ; vertical grid pattern
 out dx,ax
 jmp ag8_draw_vert_next

; Restore graphics controller to default state.

ag8_exit:
 mov al,GRAF_SET_RESET
 mov ah,bColor
 out dx,ax   ; restore text color
 mov al,GRAF_BIT_MASK
 out dx,al   ; select bitmask register

 pop edx
 pop ecx
 pop eax
 ret

AVioDrawGrid8  endp

 OPTION PROLOGUE:PrologueDef
 OPTION EPILOGUE:EpilogueDef

 SUBTITLE GetFontOffset8
 PAGE +

;---------------------------Private Routine-----------------------------;
; GetFontOffset8
;
; Get effective font offset for specified pseudo code of 8 wide cells.
; Be sure that the pseudo code must be the DBCS cell indicators.
;
; Entry:
; ESI = pseudo code
; Returns:
; ESI = effective font offset
; Registers Destroyed:
; none.
; Registers Preserved:
; EAX,EBX,ECX,EDX,EBP,EDI
; Calls:
; None
; History:
;  Wed 14-Aug-1991 -by-  Soh Ohta [jl09057 @ ymtvm3]
; Subroutinized to reduce actual code size.
;-----------------------------------------------------------------------;

 OPTION PROLOGUE:NONE
 OPTION EPILOGUE:NONE

;ALIGN 4
define_CharRect_frame GetFontOffset8

 and esi,not PSEUDO_DBCS_1ST ; get array (cb_adbcschar) index
 test esi,1   ; odd number ?
 jnz gfo8_dbcs_2nd  ;   means DBCS trailing byte

gfo8_dbcs_1st:    ; DBCS leading byte
 mov esi,CellBLTBlock.cb_adbcschar[esi]
 imul esi,esi,6
 push ebp
 mov ebp,CellBLTBlock.cb_BPSaveSlot
 add esi,wselfontsave  ; ESI --> Glyph description
 mov esi,[esi].FONTMAP.fsCharOffset.VIO_FONT_ENTRIES.fe_dBits
 add esi,wselfontsave ; ESI --> Character bitmap
 pop ebp
 ret

gfo8_dbcs_2nd:    ; DBCS trailing byte
 dec esi
 mov esi,CellBLTBlock.cb_adbcschar[esi]
 imul esi,esi,6
 push ebp
 mov ebp,CellBLTBlock.cb_BPSaveSlot
 add esi,wselfontsave  ; ESI --> Glyph description
 mov esi,[esi].FONTMAP.fsCharOffset.VIO_FONT_ENTRIES.fe_dBits
 add esi,wselfontsave ; ESI --> Character bitmap
 pop ebp
 add esi,CellBLTBlock.cb_dbcs_2nd
     ; ESI --> DBCS 2nd byte font address
 ret

GetFontOffset8  endp

 OPTION PROLOGUE:PrologueDef
 OPTION EPILOGUE:EpilogueDef

ifdef VGA

 SUBTITLE AVioDrawText
 PAGE +

;---------------------------Private Routine-----------------------------;
; AVioDrawText
;
; Interprets pseudo code on the stack to draw Vio character cell images
; with possible horizontal clipping, but no underscoring.
;
; NB: This routine exits with a JMP next_attribute_cluster8 rather than
;     a RET.
;
; Entry:
; EBX -- Destination X coordinate
; EDI -- Destination Y coordinate
; ESP -- Pseudocode pointer.  This points to the next pseudo code
;       syllable to process.
;
; Returns:
; ESP -- will move according to the pseudo code consumed by this
;       function.
; Error Returns:
; None
; Registers Destroyed:
; ???
; Registers Preserved:
; None
; Calls:
; Nothing
;
; History:
;  Wed 22-Jun-1988 14:55:44  -by-  Mitchell McLain [gssc!mmm]
; Wrote it!
;  November 1990 Ron Bowater completely re-wrote it for VGA132
;  Tue 30-Jul-1991 -by-  Soh Ohta [jl09057 @ ymtvm3]
; Massive change to support DBCS device font.
;-----------------------------------------------------------------------;

;-------------------------------------------------------------------------------
; Entry point and initialization for AVIO character drawing         ;
;-------------------------------------------------------------------------------
 OPTION PROLOGUE:NONE
 OPTION EPILOGUE:NONE

;ALIGN 4
define_CharRect_frame DrawText

 public AVioDrawText
AVioDrawText::

 std    ; will do characters upwards

 mov eax,0   ; 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   ; Unsigned value is non-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)

@@:
 cmp esi,-1   ; -1 => an attribute or return addr.
 je next_attribute
 cmp esi,-2   ; -2 => goto the next row
 je next_row
 push OFFSET have_font_offset
 jmp GetFontOffsetNS  ; get DBCS font image offset

next_attribute:
 mov ebx,wX   ; restore ebx = dest X
 mov edi,wY   ; restore edi = dest Y

 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
 mov shadowed_graf_mode.vvr_value,ah

 mov al,GRAF_DATA_ROT ; graphics data rotate register
 mov ah,DR_SET  ; set mode with no rotate
 out dx,ax   ; do i/o
 mov shadowed_graf_rot.vvr_value,ah

 jmp Next_attribute_cluster2
    ; need to return to attribute processing

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

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

have_glyph_index:
 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
 add esi,wselfontsave ; ESI --> Character bitmap
 xor cl,cl   ; phase align = 0
have_font_offset:
 mov bFontRot0,cl

;-------------------------------------------------------------------------------
; First determine whether we are clear to draw 16 chars ahead without clipping ;
;-------------------------------------------------------------------------------

; Calculate character block limits into ax,bx,cx,dx

 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 ; cell height
 neg edx
 add edx,ecx
 inc edx  ; top row

; Determine whether clipped totally out

 cmp ebx,wClipXmin ; Clipped out on l ?
 jl bclip_invis ; go if yes
 cmp eax,wClipXmax ; Clipped out on r ?
 jge bclip_invis ; go if yes
 cmp ecx,wClipYmin ; Clipped out at bottom ?
 jl bclip_invis ; go if yes
 cmp edx,wClipYmax ; Clipped out at top ?
 jge bclip_invis ; go if yes

; Determine whether clipped totally in

 cmp eax,wClipXmin ; Clipped in on l ?
 jl bclip_invis ; go if yes
 cmp ebx,wClipXmax ; Clipped in on r ?
 jge bclip_invis ; go if yes
 cmp edx,wClipYmin ; Clipped in at bottom ?
 jl bclip_invis ; go if yes
 cmp ecx,wClipYmax ; Clipped in at top ?
 jge bclip_invis ; go if yes

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

 mov eax,16   ; maximum character count to draw
 jmp draw_n_wide_noclip ; else jump to n wide unclipped

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

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 clip_out_j  ; go if yes

 cmp eax,wClipXmax  ; Clipped out on r ?
 jge clip_out_j  ; go if yes

 cmp ecx,wClipYmin  ; Clipped out at bottom ?
 jl clip_out_j  ; go if yes

 cmp edx,wClipYmax  ; Clipped out at top ?
 jge clip_out_j  ; go if yes

 jmp clip_not_out  ; else skip to do more tests
clip_out_j:
 jmp clipped_out  ; skip to ignore character

; Determine whether clipped totally in

clip_not_out:

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

clip_not_in:
 jmp draw_n_wide_clip ; jump to draw clipped

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

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?
 jne next_row_jjj  ; Yes - jump to force new row

; Jump to fetch next psuedo code

 jmp process_pseudo_code ; else return to fetch next code

next_row_jjj:
 jmp next_row  ; 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.        ;
;==============================================================================;

draw_n_wide_clip:

; Calculate Byte address of first character to be drawn

 mov ebx,wY   ; get y
 mov eax,SCREEN_CBSCAN ; screen pitch in bytes
 mul ebx   ; result to ax
 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
x_neg:
 dec eax

 PUBLIC sv_byte_addr
sv_byte_addr::
if SCAN_CNT EQ 768
 mov ecx,pVRAMInstance
 cmp lpBitmapBits,ecx
 jne not_vram
 cmp eax,010000h
 jb not_vram
 sub eax,010000h
not_vram:
endif
 add eax,lpBitmapBits ; Point to video memory
 mov wByteAddr,eax  ; and save on stack

; Calculate update mask and bit address

 mov ax,00ffh
 movzx ecx,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

; Get effective font address

 movzx ebx,wCellHeight  ; Load bx with char height
 lea esi,[esi+ebx-1]  ; move si 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 ; Sequencer regs
 mov al,SEQ_MAP_MASK  ; Map mask register
 mov ah,MM_ALL  ; Data (all on)
 out dx,ax   ; do i/o

; Set data rotate register for no logic function

 mov dx,EGA_BASE+GRAF_ADDR ; graphics controller regs
 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
 mov shadowed_graf_rot.vvr_value,ah

; Skip background box if transparent

 mov ax,wFunction  ; get function
 cmp ax,0   ; transparent ?
 jne cl_bg_box_do  ; go if not
 jmp cl_bg_box_end  ; else skip
cl_bg_box_do:

; Set graphics mode register to write mode 0

 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
 mov shadowed_graf_mode.vvr_value,ah

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

 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 colour

 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
cl_mask_adjust:
 cmp bx,word ptr wClipXmin ; compare with ymin
 jl cl_mask_adjust_1 ; go if outside
 cmp bx,word ptr wClipXmax ; compare with ymax
 jl cl_mask_adjust_2 ; go if outside
cl_mask_adjust_1:
 and dx,ax   ; strip bit
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
 movzx ecx,wCellHeight  ; loop count = cell height
 mov bx,word ptr wY  ; get Y coordinate

cl_bg_box_loop_1:
 cmp bx,word ptr wClipYmin ; compare with ymin
 jl @f   ; go if outside
 cmp bx,word ptr wClipYmax ; compare with ymax
 jge @f   ; go if outside
 xchg al,[edi]  ; read/write VGA
@@: dec bx   ; y=y-1
 sub di,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
 movzx ecx,wCellHeight  ; loop count = cell height
 mov bx,word ptr wY  ; get Y coordinate

cl_bg_box_loop_2:
 cmp bx,word ptr wClipYmin ; compare with ymin
 jl @f   ; go if outside
 cmp bx,word ptr wClipYmax ; compare with ymax
 jge @f   ; go if outside
 xchg al,[edi]  ; read/write VGA
@@: dec bx   ; y=y-1
 sub di,SCREEN_CBSCAN ; up one line
 loop cl_bg_box_loop_2 ; loop

cl_bg_box_end:

; Set/reset reg = foreground colour

 mov ax,wColor  ; Get colours
 mov ah,al   ; fg col 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
 mov shadowed_graf_mode.vvr_value,ah

; 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

 mov cl,bFontRot0  ; phase alignment
 movzx ebx,wCellHeight  ; offset to font image 2nd column
 ror ebx,16

; Do first 2 slices (including underscore)

 push esi   ; save font pointer
 push edx   ; store out port address
 mov edi,wByteAddr  ; get byte address
 mov bx,word ptr wY  ; get Y coordinate

 cmp bx,word ptr wClipYmin ; compare with ymin
 jl @f   ; go if outside
 cmp bx,word ptr wClipYmax ; compare with ymax
 jge @f   ; go if outside

 mov al,[esi]  ; read font
 or cl,cl
 jz cl_pass1_scan1
 ror ebx,16
 movzx edx,bx
 mov ah,[esi+edx]  ; read font (2nd column)
 rol ax,cl
 ror ebx,16
cl_pass1_scan1:
 or al,bUnderscoreMask ; or underscore
 test al,0ffh   ; zero slice ?
 jz @f   ; skip if yes
 xchg al,[edi]  ; read VGA data into latches
@@:
 dec bx   ; y=y-1
 sub esi,1   ; up one line
 sub di,SCREEN_CBSCAN ; up one line

 cmp bx,word ptr wClipYmin ; compare with ymin
 jl @f   ; go if outside
 cmp bx,word ptr wClipYmax ; compare with ymax
 jge @f   ; go if outside

 mov al,[esi]  ; read font
 or cl,cl
 jz cl_pass1_scan2
 ror ebx,16
 movzx edx,bx
 mov ah,[esi+edx]  ; read font (2nd column)
 rol ax,cl
 ror ebx,16
cl_pass1_scan2:
 test al,0ffh   ; zero slice ?
 jz @f   ; skip if yes
 xchg al,[edi]  ; read VGA data into latches
@@:
 dec bx   ; y=y-1
 sub esi,1   ; up one line
 sub di,SCREEN_CBSCAN ; up one line

; Loop For remaining slices to do foreground first part

 mov ch,bCellHeight  ; loop count = cell height
 sub ch,2   ; already done 2

cl_fg_box_loop_1:
 cmp bx,word ptr wClipYmin ; compare with ymin
 jl @f   ; go if outside
 cmp bx,word ptr wClipYmax ; compare with ymax
 jge @f   ; go if outside

 mov al,[esi]  ; read font
 or cl,cl
 jz cl_pass1_scanN
 ror ebx,16
 movzx edx,bx
 mov ah,[esi+edx]  ; read font (2nd column)
 rol ax,cl
 ror ebx,16
cl_pass1_scanN:
 test al,0ffh   ; zero slice ?
 jz @f   ; skip if yes
 xchg al,[edi]  ; read VGA data into latches
@@:
 dec bx   ; y=y-1
 sub esi,1   ; up one line
 sub di,SCREEN_CBSCAN ; up one line

 dec ch
 jnz cl_fg_box_loop_1 ; loop
 pop edx   ; restore out port address
 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)

 push edx   ; store out port address
 mov edi,wByteAddr  ; get byte address
 inc edi   ; bump dx
 mov bx,word ptr wY  ; get Y coordinate

 cmp bx,word ptr wClipYmin ; compare with ymin
 jl @f   ; go if outside
 cmp bx,word ptr wClipYmax ; compare with ymax
 jge @f   ; go if outside

 mov al,[esi]  ; read font
 or cl,cl
 jz cl_pass2_scan1
 ror ebx,16
 movzx edx,bx
 mov ah,[esi+edx]  ; read font (2nd column)
 rol ax,cl
 ror ebx,16
cl_pass2_scan1:
 or al,bUnderscoreMask ; or underscore
 test al,0ffh   ; zero slice ?
 jz @f   ; skip if yes
 xchg al,[edi]  ; read VGA data into latches
@@:
 dec bx   ; y=y-1
 sub esi,1   ; up one line
 sub di,SCREEN_CBSCAN ; up one line

 cmp bx,word ptr wClipYmin ; compare with ymin
 jl @f   ; go if outside
 cmp bx,word ptr wClipYmax ; compare with ymax
 jge @f   ; go if outside

 mov al,[esi]  ; read font
 or cl,cl
 jz cl_pass2_scan2
 ror ebx,16
 movzx edx,bx
 mov ah,[esi+edx]  ; read font (2nd column)
 rol ax,cl
 ror ebx,16
cl_pass2_scan2:
 test al,0ffh   ; zero slice ?
 jz @f   ; skip if yes
 xchg al,[edi]  ; read VGA data into latches
@@:
 dec bx   ; y=y-1
 sub esi,1   ; up one line
 sub di,SCREEN_CBSCAN ; up one line

; Loop For remaining slices to do foreground second part

 mov ch,bCellHeight  ; loop count = cell height
 sub ch,2   ; already done 2

cl_fg_box_loop_2:
 cmp bx,word ptr wClipYmin ; compare with ymin
 jl @f   ; go if outside
 cmp bx,word ptr wClipYmax ; compare with ymax
 jge @f   ; go if outside

 mov al,[esi]  ; read font
 or cl,cl
 jz cl_pass2_scanN
 ror ebx,16
 movzx edx,bx
 mov ah,[esi+edx]  ; read font (2nd column)
 rol ax,cl
 ror ebx,16
cl_pass2_scanN:
 test al,0ffh   ; zero slice ?
 jz @f   ; skip if yes
 xchg al,[edi]  ; read/write vga
@@:
 dec bx   ; y=y-1
 sub esi,1   ; up one line
 sub di,SCREEN_CBSCAN ; up one line

 dec ch
 jnz cl_fg_box_loop_2 ; loop
 pop edx   ; restore out port address

cl_fg_box_end:

; Draw gridlines if necessary

 test wAVioAttributes,AVioHorizontalGridMask OR AVioVerticalGridMask
 jz cl_grid_line_end

 push edi
 mov edi,wByteAddr  ; DI = cell origin address (bottom)
 call AVioDrawGrid  ; Draw grid lines
 pop edi

cl_grid_line_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_jj  ; Yes - jump to force new row

; Jump to fetch next pseudo code

 jmp process_pseudo_code ; else jump to fetch next code

next_row_jj:
 jmp next_row  ; return to fetch next code


;==============================================================================;
; Draw any width characters on arbitrary boundary unclipped   ;
;          ;
; Characters of any width any 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.        ;
;==============================================================================;

draw_n_wide_noclip:

; Save character count

 mov wCharCount,ax  ; save char count

; jump to process first character

 mov cl,bFontRot0  ; phase align for character 0
 jmp nw_have_font_offset ; 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
ifdef  JTUNE        ;IBMJ
 test swFlags,SW_CT_DISABLE
 jnz @F
 test esi,not EXT_CELL_SAME_CHAR
 jnz @F
 jmp grid_line_end
@@:
endif ;JTUNE        ;IBMJ
 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

nw_not_default_glyph:
 cmp esi,-2   ; -1,-2 => control code
 jae nw_its_control
 push OFFSET nw_have_font_offset
 jmp GetFontOffsetNS  ; get DBCS font image offset

nw_its_control:
 push esi   ; return code to stack
 jmp draw_nw_exit  ; and exit

; Valid glyph index - Calculate address of font

draw_nw_glyph_ok:
 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
 add esi,wselfontsave ; ESI --> Character bitmap
 xor cl,cl   ; phase align = 0

 public nw_have_font_offset
nw_have_font_offset::
 mov wFontPtr0,esi  ; save on stack
 mov bFontRot0,cl
 movzx ebx,wCellHeight  ; Load ebx with char height
 lea esi,[esi+ebx-1]  ; move esi to end of definition

; determine whether the fast 6 wide code can be used

 test wAVioAttributes,AVioHorizontalGridMask OR AVioVerticalGridMask
 jnz not_67_special  ; go if yes

 cmp word ptr wCellWidth,6 ; cell width = 6 ?
 je maybe_67_special ; go if yes

 cmp word ptr wCellWidth,7 ; cell width = 7 ?
 jne not_67_special  ; go if not

maybe_67_special:
 cmp wCharCount,8  ; do we have 8 or more left ?
 jb not_67_special  ; go if not

 mov eax,wX   ; get x
 and eax,0007h  ; leave bit address and sign
 jne not_67_special  ; go if not

 cmp bHorizontalClipMask,0 ; Is this text clipped?
 jne not_67_special  ; Yes - jump to force new row

 mov ebx,esp   ; copy sp to bx
 xor eax,eax   ; sum pseudo code up here

 or ax,[ebx]
 cmp ax,-2   ; test next entry on stack (1)
 jae not_67_special  ; skip if control code

 or ax,[ebx+4]
 cmp ax,-2   ; test next entry on stack (1)
 jae not_67_special  ; skip if control code

 or ax,[ebx+8]
 cmp ax,-2   ; test next entry on stack (1)
 jae not_67_special  ; skip if control code

 or ax,[ebx+12]
 cmp ax,-2   ; test next entry on stack (1)
 jae not_67_special  ; skip if control code

 or ax,[ebx+16]
 cmp ax,-2   ; test next entry on stack (1)
 jae not_67_special  ; skip if control code

 or ax,[ebx+20]
 cmp ax,-2   ; test next entry on stack (1)
 jae not_67_special  ; skip if control code

 or ax,[ebx+24]
 cmp ax,-2   ; test next entry on stack (1)
 jae not_67_special  ; skip if control code

 cmp wFunction,0  ; is function transparent ?
 je not_67_special  ; go if yes

; Conditions good to call fast 6 wide code - do it

 test ax,08000h  ; any DBCS cells in char #1...7 ?
 jnz mbcs_6or7_wide  ; call fast 6 or 7 wide for MBCS cells
 cmp bFontRot0,0  ; is 1st char DBCS cell?
 jne mbcs_6or7_wide  ; call fast 6 or 7 wide for MBCS cells
 jmp sbcs_6or7_wide  ; call fast 6 or 7 wide for SBCS cells

;---------------------------Private Routine-----------------------------;
; not_67_special
;
; Draw 1 x any width characters on arbitrary boundary unclipped.
;
; Be sure that this routine assumes even number of cell scanlines.
;
; Entry:
; Nothing
; Returns:
; Nothing
; Registers Destroyed:
; EAX,EBX,ECX,EDX,ESI,EDI,FLAGS
; Registers Preserved:
; History:
;  Tue 30-Jul-1991 -by-  Soh Ohta [jl09057 @ ymtvm3]
; Modified to support DBCS device font.
;-----------------------------------------------------------------------;

 public not_67_special
not_67_special::

; 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 ax
 mov ebx,wX   ; get x
 shr ebx,3   ; byte address
 add eax,ebx   ; add to line address
 add eax,lpBitmapBits ; Point to video memory
 mov wByteAddr,eax  ; and save on stack

; Calculate update mask and bit address

 mov ax,00ffh
 movzx ecx,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

 xor ax,ax   ; 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 data rotate register for no logic function

 mov dx,EGA_BASE+GRAF_ADDR ; graphics controller regs
 mov ah,DR_SET  ; no logic function
 mov bx,wBitAddr  ; get bit address
 or ah,bl   ; combine
 mov al,GRAF_DATA_ROT ; graphics rotate reg
 out dx,ax   ; do i/o
 mov shadowed_graf_rot.vvr_value,ah

; Skip background box if transparent

 mov ax,wFunction  ; get function
 cmp ax,0   ; transparent ?
 je bg_box_end  ; go if yes

; Set graphics mode register to write mode 0

 mov al,GRAF_MODE  ; graphics mode
 mov ah,M_PROC_WRITE OR M_DATA_READ ; write mode 0
 out dx,ax   ; do i/o
 mov shadowed_graf_mode.vvr_value,ah

; 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 colours
 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
 movzx ecx,wCellHeight  ; loop count = cell height
 shr ecx,1   ; divide ecx by 2

bg_box_loop_1:
 xchg al,[edi]  ; read/write VGA
 sub di,SCREEN_CBSCAN ; up one line
 xchg al,[edi]  ; read/write VGA
 sub di,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
 movzx ecx,wCellHeight  ; loop count = cell height
 shr ecx,1   ; divide ecx by 2

bg_box_loop_2:
 xchg al,[edi]  ; read/write VGA
 sub di,SCREEN_CBSCAN ; up one line
 xchg al,[edi]  ; read/write VGA
 sub di,SCREEN_CBSCAN ; up one line
 loop bg_box_loop_2  ; loop

bg_box_end:

; Set/reset reg = foreground colour

 mov ax,wColor  ; Get colours
 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
 mov shadowed_graf_mode.vvr_value,ah

; 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

; Check the cell is SBCS or DBCS

 mov cl,bFontRot0  ; phase alignment
 or cl,cl   ; is zero ?
 jnz dbcs_not_67  ; no, DBCS 2nd byte cell

;-----------------------------------------------------------------------;
; SBCS or DBCS 1st byte cell.
;-----------------------------------------------------------------------;
sbcs_not_67:

; 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   ; skip if yes
 xchg al,[edi]  ; read and write vga
@@: sub di,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 di,SCREEN_CBSCAN ; up one line

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

 movzx ecx,wCellHeight  ; loop count = cell height
 sub ecx,2   ; already done 2
 shr ecx,1   ; divide cx by 2
fg_box_loop_1:

 lodsb    ; read font
 test al,0ffh   ; zero slice ?
 jz @f   ; skip if yes
 xchg al,[edi]  ; read and write VGA
@@: sub di,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 di,SCREEN_CBSCAN ; up one line

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

 lodsb    ; read font
 or al,bUnderscoreMask ; or underscore
 test al,0ffh   ; zero slice ?
 jz @f   ; skip if yes
 xchg al,[edi]  ; read and write VGA
@@: sub di,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 di,SCREEN_CBSCAN ; up one line

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

 movzx ecx,wCellHeight  ; loop count = cell height
 sub ecx,2   ; already done 2
 shr ecx,1   ; divide cx by 2
fg_box_loop_2:

 lodsb    ; read font
 test al,0ffh   ; zero slice ?
 jz @f   ; skip if yes
 xchg al,[edi]  ; read and write vga
@@: sub di,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 di,SCREEN_CBSCAN ; up one line
 loop fg_box_loop_2  ; loop

 jmp fg_box_end

;-----------------------------------------------------------------------;
; DBCS 2nd byte cell.
;-----------------------------------------------------------------------;
 public dbcs_not_67
dbcs_not_67::

 movzx ebx,wCellHeight  ; offset to font image 2nd column
 ror ebx,16

; Do first 2 slices (including underscore)

 push esi   ; save font pointer
 push edx   ; store out port address
 mov edi,wByteAddr  ; get byte address

 lodsb    ; read font
 ror ebx,16
 movzx edx,bx
 mov ah,[esi+edx+1]  ; read font (2nd column)
 rol ax,cl
 ror ebx,16
 or al,bUnderscoreMask ; or underscore
 test al,0ffh   ; zero slice ?
 jz @f   ; skip if yes
 xchg al,[edi]  ; read and write vga
@@: sub di,SCREEN_CBSCAN ; up one line

 lodsb    ; read font
 ror ebx,16
 movzx edx,bx
 mov ah,[esi+edx+1]  ; read font (2nd column)
 rol ax,cl
 ror ebx,16
 test al,0ffh   ; zero slice ?
 jz @f   ; skip if yes
 xchg al,[edi]  ; read and write VGA
@@: sub di,SCREEN_CBSCAN ; up one line

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

 mov ch,bCellHeight  ; loop count = cell height
 sub ch,2   ; already done 2
 shr ch,1   ; divide cx by 2
fg_dbcs_loop_1:

 lodsb    ; read font
 ror ebx,16
 movzx edx,bx
 mov ah,[esi+edx+1]  ; read font (2nd column)
 rol ax,cl
 ror ebx,16
 test al,0ffh   ; zero slice ?
 jz @f   ; skip if yes
 xchg al,[edi]  ; read and write VGA
@@: sub di,SCREEN_CBSCAN ; up one line

 lodsb    ; read font
 ror ebx,16
 movzx edx,bx
 mov ah,[esi+edx+1]  ; read font (2nd column)
 rol ax,cl
 ror ebx,16
 test al,0ffh   ; zero slice ?
 jz @f   ; skip if yes
 xchg al,[edi]  ; read and write VGA
@@: sub di,SCREEN_CBSCAN ; up one line

 dec ch
 jnz fg_dbcs_loop_1  ; loop
 pop edx   ; restore out port address
 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 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)

 push edx   ; store out port address
 mov edi,wByteAddr  ; get byte address
 inc edi   ; bump di

 lodsb    ; read font
 ror ebx,16
 movzx edx,bx
 mov ah,[esi+edx+1]  ; read font (2nd column)
 rol ax,cl
 ror ebx,16
 or al,bUnderscoreMask ; or underscore
 test al,0ffh   ; zero slice ?
 jz @f   ; skip if yes
 xchg al,[edi]  ; read and write VGA
@@: sub di,SCREEN_CBSCAN ; up one line

 lodsb    ; read font
 ror ebx,16
 movzx edx,bx
 mov ah,[esi+edx+1]  ; read font (2nd column)
 rol ax,cl
 ror ebx,16
 test al,0ffh   ; zero slice ?
 jz @f   ; skip if yes
 xchg al,[edi]  ; read and write VGA
@@: sub di,SCREEN_CBSCAN ; up one line

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

 mov ch,bCellHeight  ; loop count = cell height
 sub ch,2   ; already done 2
 shr ch,1   ; divide cx by 2
fg_dbcs_loop_2:

 lodsb    ; read font
 ror ebx,16
 movzx edx,bx
 mov ah,[esi+edx+1]  ; read font (2nd column)
 rol ax,cl
 ror ebx,16
 test al,0ffh   ; zero slice ?
 jz @f   ; skip if yes
 xchg al,[edi]  ; read and write vga
@@: sub di,SCREEN_CBSCAN ; up one line

 lodsb    ; read font
 ror ebx,16
 movzx edx,bx
 mov ah,[esi+edx+1]  ; read font (2nd column)
 rol ax,cl
 ror ebx,16
 test al,0ffh   ; zero slice ?
 jz @f   ; skip if yes
 xchg al,[edi]  ; read and write VGA
@@: sub di,SCREEN_CBSCAN ; up one line
 dec ch
 jnz fg_dbcs_loop_2  ; loop
 pop edx   ; restore out port address

fg_box_end:

; Draw gridlines if necessary

 test wAVioAttributes,AVioHorizontalGridMask OR AVioVerticalGridMask
 jz grid_line_end

 push edi
 mov ecx,wScanLineCount ; ECX = number of scanlines
 mov edi,wByteAddr  ; EDI = cell origin address (bottom)
 call AVioDrawGridNC  ; Draw grid lines
 pop edi

grid_line_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_j  ; Yes - jump to force new row

; Check character count, return if zero else decrement

 dec word ptr wCharCount ; dec and test character count
 jz draw_nw_exit  ; zero - exit

; Jump to top of draw loop

 jmp draw_n_wide_noclip_next ; Jump back to fetch next code

next_row_j:
 jmp next_row  ; return to fetch next code

; Exit n wide unclipped code

draw_nw_exit:
 jmp process_pseudo_code ; else return to fetch next code

;---------------------------Private Routine-----------------------------;
; sbcs_6or7_wide
;
; Draw 8 x 6 wide characters in a group (very fast) without clipping.
; This entry supports only SBCS cells without grid attributes.
; The first char font image offset was already saved in wFontPtr0.
;
; Entry:
;    ESP = pseudo code buffer
; Returns:
; Nothing
; Registers Destroyed:
; EAX,EBX,ECX,EDX,ESI,EDI,FLAGS
; Registers Preserved:
; History:
;  Tue 30-Jul-1991 -by-  Soh Ohta  [jl09057 @ ymtvm3]
; Modified to improve performance.
;  Wed 11-Dec-1991 -by-  N.Ichikawa[jl25003 @ ymtvm3]
; Modified to support special case for SBCS 7 wide characters.
;-----------------------------------------------------------------------;

 public sbcs_6or7_wide
sbcs_6or7_wide::

 mov eax,wFirstGlyph  ; keep values in hand
 mov ebx,wGlyphSpan
 mov edx,wDefaultGlyph

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

 pop esi   ; get glyph index
 movsx esi,si
 sub esi,eax   ; Subtract the lowest defined glyph
 cmp esi,ebx   ; Check against number of defined glyphs
 jb @f   ; skip if in range
 mov esi,edx   ; use default value
@@: 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
 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,eax   ; Subtract the lowest defined glyph
 cmp esi,ebx   ; Check against number of defined glyphs
 jb @f   ; skip if in range
 mov esi,edx   ; use default value
@@: 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
 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,eax   ; Subtract the lowest defined glyph
 cmp esi,ebx   ; Check against number of defined glyphs
 jb @f   ; skip if in range
 mov esi,edx   ; use default value
@@: 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
 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,eax   ; Subtract the lowest defined glyph
 cmp esi,ebx   ; Check against number of defined glyphs
 jb @f   ; skip if in range
 mov esi,edx   ; use default value
@@: 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
 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,eax   ; Subtract the lowest defined glyph
 cmp esi,ebx   ; Check against number of defined glyphs
 jb @f   ; skip if in range
 mov esi,edx   ; use default value
@@: 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
 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,eax   ; Subtract the lowest defined glyph
 cmp esi,ebx   ; Check against number of defined glyphs
 jb @f   ; skip if in range
 mov esi,edx   ; use default value
@@: 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
 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,eax   ; Subtract the lowest defined glyph
 cmp esi,ebx   ; Check against number of defined glyphs
 jb @f   ; skip if in range
 mov esi,edx   ; use default value
@@: 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
 add esi,wselfontsave ; ESI --> Character bitmap
 mov wFontPtr7,esi  ; store in stack frame

; Skip setup if 6 wide hardware setup active

 cmp word ptr wModeSet,6 ; 6 wide mode set ?
 je @f   ; go if yes
 call setup_6or7_wide  ; reprogram gpx controller

; 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 ax
 mov ebx,wX   ; get x
 shr ebx,3   ; byte address
 add eax,ebx   ; add to line address
 add eax,lpBitmapBits ; Point to video memory
 mov wByteAddr,eax  ; and save on stack

; Initialize loop to write all slices of 8 characters

 movzx ebx,wCellHeight  ; Load bx with char height
 mov edi,wByteAddr  ; get byte address for drawing
 mov dl,bUnderscoreMask ; get underscore
 cld    ; ensure count upwards

 cmp word ptr wCellWidth,6 ; cell width = 6 ?
 je charglp6  ; go 6 pel wide version

;-----------------------------------------------------------------------;
; SBCS 7 wide characters special case.
;-----------------------------------------------------------------------;

charglp7:
 or dl,dl   ; underscore involved?
 jz charglp7_body  ; no...

 mov dh,dl   ; draw underscore first
 mov [edi+0],dx
 mov [edi+2],dx
 mov [edi+4],dx
 mov [edi+6],dl
 sub di,SCREEN_CBSCAN ; decr to start of next line
 dec ebx   ; decr character slice offset

charglp7_body:
 mov esi,wFontPtr0  ; get font pointer 0
 mov al,[esi+ebx-1]  ; get slice
 shl eax,7   ; shift data up

 mov esi,wFontPtr1  ; get font pointer 1
 mov al,[esi+ebx-1]  ; get slice
 shl eax,7   ; shift data up

 mov esi,wFontPtr2  ; get font pointer 2
 mov al,[esi+ebx-1]  ; get slice
 shl eax,7   ; shift data up

 mov esi,wFontPtr3  ; get font pointer 3
 mov al,[esi+ebx-1]  ; get slice
 shl eax,3   ; shift data up

 mov esi,wFontPtr4  ; get font pointer 4
 mov cl,[esi+ebx-1]  ; get slice
 shl ecx,7   ; shift data up

 mov esi,wFontPtr5  ; get font pointer 5
 mov cl,[esi+ebx-1]  ; get slice
 shl ecx,7   ; shift data up

 mov esi,wFontPtr6  ; get font pointer 6
 mov cl,[esi+ebx-1]  ; get slice
 shl ecx,7   ; shift data up

 mov esi,wFontPtr7  ; get font pointer 7
 mov cl,[esi+ebx-1]  ; get slice
 rol ecx,7   ; shift data up

 and cl,0Fh
 or al,cl

 xchg ah,al
 ror eax,16
 xchg ah,al
 stosd    ; store dword to VGA
 mov eax,ecx
 ror eax,16
 xchg ah,al
 stosw    ; store word to VGA
 rol eax,8
 stosb    ; store byte to VGA

 sub di,SCREEN_CBSCAN+7 ; decr to start of next line
 dec ebx   ; decr character slice offset
 jnz charglp7_body  ; and loop for all slices

 add wX,8*7   ; bump X value for 8 characters
 std    ; will do characters upwards
 jmp process_pseudo_code ; and return to fetch next code

;-----------------------------------------------------------------------;
; SBCS 6 wide characters special case.
;-----------------------------------------------------------------------;
charglp6:
 or dl,dl   ; underscore involved?
 jz charglp6_body  ; no...

 mov dh,dl   ; draw underscore first
 mov [edi+0],dx
 mov [edi+2],dx
 mov [edi+4],dx
 sub di,SCREEN_CBSCAN ; decr to start of next line
 dec ebx   ; decr character slice offset

charglp6_body:
 mov esi,wFontPtr0  ; get font pointer 0
 mov ah,[esi+ebx-1]  ; get slice
 rol eax,6   ; shift data up

 mov esi,wFontPtr1  ; get font pointer 1
 mov ah,[esi+ebx-1]  ; get slice
 rol eax,6   ; shift data up

 mov esi,wFontPtr2  ; get font pointer 2
 mov ah,[esi+ebx-1]  ; get slice
 rol eax,6   ; shift data up

 mov esi,wFontPtr3  ; get font pointer 3
 mov ah,[esi+ebx-1]  ; get slice
 rol eax,6   ; shift data up

 mov esi,wFontPtr4  ; get font pointer 4
 mov ah,[esi+ebx-1]  ; get slice
 rol eax,6+2   ; shift data up

 xchg al,ah   ; adjust byte order
 stosw    ; store byte to VGA
 ror eax,2   ; adjust byte boundary

 mov esi,wFontPtr5  ; get font pointer 5
 mov ah,[esi+ebx-1]  ; get slice
 rol eax,6   ; shift data up

 mov esi,wFontPtr6  ; get font pointer 6
 mov ah,[esi+ebx-1]  ; get slice
 rol eax,6+6   ; shift data up

 xchg al,ah   ; adjust byte order
 stosw    ; store byte to VGA
 ror eax,6   ; adjust byte boundary

 mov esi,wFontPtr7  ; get font pointer 7
 mov ah,[esi+ebx-1]  ; get slice
 ror eax,2+8   ; shift data up

 xchg al,ah   ; adjust byte order
 stosw    ; store byte to VGA

 sub di,SCREEN_CBSCAN+6 ; decr to start of next line
 dec ebx   ; decr character slice offset
 jnz charglp6_body  ; and loop for all slices

 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

;---------------------------Private Routine-----------------------------;
; mbcs_6or7_wide
;
; Draw 8 x 6 wide characters in a group (very fast) without clipping.
; This entry supports MBCS cells without grid attributes.
; The first char font image offset was already saved in wFontPtr0.
;
; We always access the 2nd column of font image, to save the time to
; test and to aviod conditional jump - assumes the 2nd column address
; is always valid for read accessing.
;
; Entry:
;    ESP = pseudo code buffer
; Returns:
; Nothing
; Registers Destroyed:
; EAX,EBX,ECX,EDX,ESI,EDI,FLAGS
; Registers Preserved:
; History:
;  Tue 30-Jul-1991 -by-  Soh Ohta  [jl09057 @ ymtvm3]
; Modified to support DBCS device font.
;  Wed 11-Dec-1991 -by-  N.Ichikawa[jl25003 @ ymtvm3]
; Modified to support special case for MBCS 7 width caracters.
;-----------------------------------------------------------------------;

 public mbcs_6or7_wide
mbcs_6or7_wide::

 mov eax,wFirstGlyph  ; keep values in hand
 mov ebx,wGlyphSpan
 mov edi,wFontPtr0

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

 pop esi   ; get glyph index
 movsx esi,si
 sub esi,eax   ; Subtract the lowest defined glyph
 cmp esi,ebx   ; Check against number of defined glyphs
 jb @f   ; skip if in range
 call GetFontOffset  ; get effective value
 jmp have_font_offset1
@@: 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
 add esi,wselfontsave ; ESI --> Character bitmap
 xor cl,cl   ; phase align = 0
have_font_offset1:
 mov edx,esi
 sub edx,edi   ; get offset from 1st char
 mov wFontPtr1,edx  ; store in stack frame
 mov bFontRot1,cl
 mov edi,esi

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

 pop esi   ; get glyph index
 movsx esi,si
 sub esi,eax   ; Subtract the lowest defined glyph
 cmp esi,ebx   ; Check against number of defined glyphs
 jb @f   ; skip if in range
 call GetFontOffset  ; get effective value
 jmp have_font_offset2
@@: 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
 add esi,wselfontsave ; ESI --> Character bitmap
 xor cl,cl   ; phase align = 0
have_font_offset2:
 mov edx,esi
 sub edx,edi   ; get offset from 2nd char
 mov wFontPtr2,edx  ; store in stack frame
 mov bFontRot2,cl
 mov edi,esi

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

 pop esi   ; get glyph index
 movsx esi,si
 sub esi,eax   ; Subtract the lowest defined glyph
 cmp esi,ebx   ; Check against number of defined glyphs
 jb @f   ; skip if in range
 call GetFontOffset  ; get effective value
 jmp have_font_offset3
@@: 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
 add esi,wselfontsave ; ESI --> Character bitmap
 xor cl,cl   ; phase align = 0
have_font_offset3:
 mov edx,esi
 sub edx,edi   ; get offset from 3rd char
 mov wFontPtr3,edx  ; store in stack frame
 mov bFontRot3,cl
 mov edi,esi

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

 pop esi   ; get glyph index
 movsx esi,si
 sub esi,eax   ; Subtract the lowest defined glyph
 cmp esi,ebx   ; Check against number of defined glyphs
 jb @f   ; skip if in range
 call GetFontOffset  ; get effective value
 jmp have_font_offset4
@@: 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
 add esi,wselfontsave ; ESI --> Character bitmap
 xor cl,cl   ; phase align = 0
have_font_offset4:
 mov edx,esi
 sub edx,edi   ; get offset from 4th char
 mov wFontPtr4,edx  ; store in stack frame
 mov bFontRot4,cl
 mov edi,esi

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

 pop esi   ; get glyph index
 movsx esi,si
 sub esi,eax   ; Subtract the lowest defined glyph
 cmp esi,ebx   ; Check against number of defined glyphs
 jb @f   ; skip if in range
 call GetFontOffset  ; get effective value
 jmp have_font_offset5
@@: 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
 add esi,wselfontsave ; ESI --> Character bitmap
 xor cl,cl   ; phase align = 0
have_font_offset5:
 mov edx,esi
 sub edx,edi   ; get offset from 5th char
 mov wFontPtr5,edx  ; store in stack frame
 mov bFontRot5,cl
 mov edi,esi

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

 pop esi   ; get glyph index
 movsx esi,si
 sub esi,eax   ; Subtract the lowest defined glyph
 cmp esi,ebx   ; Check against number of defined glyphs
 jb @f   ; skip if in range
 call GetFontOffset  ; get effective value
 jmp have_font_offset6
@@: 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
 add esi,wselfontsave ; ESI --> Character bitmap
 xor cl,cl   ; phase align = 0
have_font_offset6:
 mov edx,esi
 sub edx,edi   ; get offset from 6th char
 mov wFontPtr6,edx  ; store in stack frame
 mov bFontRot6,cl
 mov edi,esi

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

 pop esi   ; get glyph index
 movsx esi,si
 sub esi,eax   ; Subtract the lowest defined glyph
 cmp esi,ebx   ; Check against number of defined glyphs
 jb @f   ; skip if in range
 call GetFontOffset  ; get effective value
 jmp have_font_offset7
@@: 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
 add esi,wselfontsave ; ESI --> Character bitmap
 xor cl,cl   ; phase align = 0
have_font_offset7:
 mov edx,esi
 sub edx,edi   ; get offset from 7th char
 mov wFontPtr7,edx  ; store in stack frame
 mov bFontRot7,cl
 mov edi,esi

; Skip setup if 5 wide hardware setup active

 cmp word ptr wModeSet,6 ; 6 wide mode set ?
 je @f   ; go if yes
 call setup_6or7_wide  ; reprogram gpx controller

; 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 ax
 mov ebx,wX   ; get x
 shr ebx,3   ; byte address
 add eax,ebx   ; add to line address
 add eax,lpBitmapBits ; Point to video memory
 mov wByteAddr,eax  ; and save on stack

; Initialize loop to write all slices of 8 characters

 movzx ebx,wCellHeight  ; Load bx with char height
 mov edi,wByteAddr  ; get byte address for drawing
 mov dl,bUnderscoreMask ; get underscore
 cld    ; ensure count upwards

 add wFontPtr0,ebx
 dec wFontPtr0  ; bottom scan of first char
 mov ch,bl   ; as loop counter

 cmp word ptr wCellWidth,6 ; cell width = 6 ?
 je mbcs_charglp6  ; go 6 pel wide version

;-----------------------------------------------------------------------;
; MBCS 7 wide characters special case.
;-----------------------------------------------------------------------;
mbcs_charglp7:
 or dl,dl   ; underscore involved?
 jz mbcs_charglp7_body ; no...

 mov dh,dl   ; draw underscore first
 mov [edi+0],dx
 mov [edi+2],dx
 mov [edi+4],dx
 mov [edi+6],dl
 sub di,SCREEN_CBSCAN ; decr to start of next line
 dec wFontPtr0  ; decr character slice offset
 dec ch   ; decr loop counter

mbcs_charglp7_body:
 mov esi,wFontPtr0  ; get font pointer 0 (base address)
 mov cl,bFontRot0  ; get phase align
 mov ah,[esi]  ; get slice
 mov al,[esi+ebx]  ; get slice (2nd)
 rol ax,cl   ; get effective slice
 rol eax,7   ; shift data up

 add esi,wFontPtr1  ; get font pointer 1
 mov cl,bFontRot1  ; get phase align
 mov ah,[esi]  ; get slice
 mov al,[esi+ebx]  ; get slice (2nd)
 rol ax,cl   ; get effective slice
 rol eax,7   ; shift data up

 add esi,wFontPtr2  ; get font pointer 2
 mov cl,bFontRot2  ; get phase align
 mov ah,[esi]  ; get slice
 mov al,[esi+ebx]  ; get slice (2nd)
 rol ax,cl   ; get effective slice
 rol eax,2+16  ; shift data up

 xchg ah,al
 stosw
 ror eax,3+8

 add esi,wFontPtr3  ; get font pointer 3
 mov cl,bFontRot3  ; get phase align
 mov ah,[esi]  ; get slice
 mov al,[esi+ebx]  ; get slice (2nd)
 rol ax,cl   ; get effective slice
 rol eax,7   ; shift data up

 add esi,wFontPtr4  ; get font pointer 4
 mov cl,bFontRot4  ; get phase align
 mov ah,[esi]  ; get slice
 mov al,[esi+ebx]  ; get slice (2nd)
 rol ax,cl   ; get effective slice
 rol eax,4+16  ; shift data up

 xchg ah,al
 stosw
 ror eax,5+8

 add esi,wFontPtr5  ; get font pointer 5
 mov cl,bFontRot5  ; get phase align
 mov ah,[esi]  ; get slice
 mov al,[esi+ebx]  ; get slice (2nd)
 rol ax,cl   ; get effective slice
 rol eax,7   ; shift data up

 add esi,wFontPtr6  ; get font pointer 6
 mov cl,bFontRot6  ; get phase align
 mov ah,[esi]  ; get slice
 mov al,[esi+ebx]  ; get slice (2nd)
 rol ax,cl   ; get effective slice
 rol eax,6+16  ; shift data up

 xchg al,ah   ; adjust byte order
 stosw    ; store byte to VGA
 ror eax,7+8   ; shift data up

 add esi,wFontPtr7  ; get font pointer 7
 mov cl,bFontRot7  ; get phase align
 mov ah,[esi]  ; get slice
 mov al,[esi+ebx]  ; get slice (2nd)
 rol ax,cl   ; get effective slice
 ror eax,1+8   ; shift data up

 stosb    ; store byte to VGA

 sub di,SCREEN_CBSCAN+7 ; decr to start of next line
 dec wFontPtr0  ; decr character slice offset
 dec ch   ; decr loop counter
 jnz    mbcs_charglp7_body ; and loop for all slices

 add wX,8*7   ; bump X value for 8 characters
 std    ; will do characters upwards
 jmp process_pseudo_code ; and return to fetch next code

;-----------------------------------------------------------------------;
; MBCS 6 wide characters special case.
;-----------------------------------------------------------------------;
mbcs_charglp6:
 or dl,dl   ; underscore involved?
 jz mbcs_charglp6_body ; no...

 mov dh,dl   ; draw underscore first
 mov [edi+0],dx
 mov [edi+2],dx
 mov [edi+4],dx
 sub di,SCREEN_CBSCAN ; decr to start of next line
 dec wFontPtr0  ; decr character slice offset
 dec ch   ; decr loop counter

mbcs_charglp6_body:
 mov esi,wFontPtr0  ; get font pointer 0 (base address)
 mov cl,bFontRot0  ; get phase align
 mov ah,[esi]  ; get slice
 mov al,[esi+ebx]  ; get slice (2nd)
 rol ax,cl   ; get effective slice
 rol eax,6   ; shift data up

 add esi,wFontPtr1  ; get font pointer 1
 mov cl,bFontRot1  ; get phase align
 mov ah,[esi]  ; get slice
 mov al,[esi+ebx]  ; get slice (2nd)
 rol ax,cl   ; get effective slice
 rol eax,6   ; shift data up

 add esi,wFontPtr2  ; get font pointer 2
 mov cl,bFontRot2  ; get phase align
 mov ah,[esi]  ; get slice
 mov al,[esi+ebx]  ; get slice (2nd)
 rol ax,cl   ; get effective slice
 rol eax,6+14  ; shift data up

 xchg al,ah   ; adjust byte order
 stosw    ; store byte to VGA
 ror eax,14   ; adjust byte boundary

 add esi,wFontPtr3  ; get font pointer 3
 mov cl,bFontRot3  ; get phase align
 mov ah,[esi]  ; get slice
 mov al,[esi+ebx]  ; get slice (2nd)
 rol ax,cl   ; get effective slice
 rol eax,6   ; shift data up

 add esi,wFontPtr4  ; get font pointer 4
 mov cl,bFontRot4  ; get phase align
 mov ah,[esi]  ; get slice
 mov al,[esi+ebx]  ; get slice (2nd)
 rol ax,cl   ; get effective slice
 rol eax,6   ; shift data up

 add esi,wFontPtr5  ; get font pointer 5
 mov cl,bFontRot5  ; get phase align
 mov ah,[esi]  ; get slice
 mov al,[esi+ebx]  ; get slice (2nd)
 rol ax,cl   ; get effective slice
 rol eax,6+12  ; shift data up

 xchg al,ah   ; adjust byte order
 stosw    ; store byte to VGA
 ror eax,12   ; shift data up

 add esi,wFontPtr6  ; get font pointer 6
 mov cl,bFontRot6  ; get phase align
 mov ah,[esi]  ; get slice
 mov al,[esi+ebx]  ; get slice (2nd)
 rol ax,cl   ; get effective slice
 rol eax,6   ; shift data up

 add esi,wFontPtr7  ; get font pointer 7
 mov cl,bFontRot7  ; get phase align
 mov ah,[esi]  ; get slice
 mov al,[esi+ebx]  ; get slice (2nd)
 rol ax,cl   ; get effective slice
 ror eax,2+8   ; shift data up

 xchg al,ah   ; adjust byte order
 stosw    ; store byte to VGA

 sub di,SCREEN_CBSCAN+6 ; decr to start of next line
 dec wFontPtr0  ; decr character slice offset
 dec ch   ; decr loop counter
 jnz    mbcs_charglp6_body ; and loop for all slices

 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


;---------------------------Private Routine-----------------------------;
; setup_6or7_wide
;
; Setup GPX controller for 6 or 7 wide characters special case.
;
; Entry:
; Nothing
; Returns:
; Nothing
; Registers Destroyed:
; EAX,EBX,EDX,FLAGS
; Registers Preserved:
; History:
;  Tue 30-Jul-1991 -by-  Soh Ohta [jl09057 @ ymtvm3]
; Subroutinized.
;-----------------------------------------------------------------------;

 public setup_6or7_wide
setup_6or7_wide::

 mov word ptr wModeSet,6 ; 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
 mov shadowed_graf_mode.vvr_value,ah

; 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
 mov shadowed_graf_rot.vvr_value,ah

; 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 ebx,pVRAMInstance ; This gets our
 mov [ebx+tonys_bar_n_grill],ah
     ; This gets our background color
 mov ah,[ebx+tonys_bar_n_grill] ; into the latches.

; Change set/reset reg to all zeroes

 xor ax,ax   ; Clear ax
 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 cols

 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
 mov shadowed_graf_rot.vvr_value,ah

 ret

DrawText endp

 OPTION PROLOGUE:PrologueDef
 OPTION EPILOGUE:EpilogueDef

 SUBTITLE AVioDrawGrid
 PAGE +

;---------------------------Private Routine-----------------------------;
; AVioDrawGrid     - with    clipping
; AVioDrawGridNC    - without clipping
;
; Draw gridlines for non 8 pels wide cells.
; This routine assumes the following graphics controller states,
; so that we only change the foreground color for drawing gridlines.
;
; Assumes:
; GRAF_MODE = M_AND_WRITE
; SEQ_MAP_MASK = MM_ALL
; GRAF_ENAB_SR = MM_ALL
; GRAF_DATA_ROT = DR_SET
; Entry:
; EBP = CharRect frame
; ECX = scanline count   (for AVioDrawGridNC)
; EDI = destination address (bottom scan)
; Returns:
; None
; Error Returns:
; None
; Registers Destroyed:
; EAX,EBX,ECX,EDX,EDI
; Registers Preserved:
; ESI,EBP
; Calls:
; None
; History:
;  Wed 14-Aug-1991 -by-  Soh Ohta [jl09057 @ ymtvm3]
; Wrote it!
;-----------------------------------------------------------------------;

 OPTION PROLOGUE:NONE
 OPTION EPILOGUE:NONE

;ALIGN 4
define_CharRect_frame AVioDrawGrid

; Compute cell address and scanline count to be drawn.

 mov ecx,wY
 inc ecx
 mov edx,ecx   ; bottom scan (exclusive)
 sub dx,wCellHeight  ; top  scan (inclusive)
 mov eax,wClipYmax  ; bottom clip (exclusive)
 mov ebx,wClipYmin  ; top  clip (inclusive)
 cmp eax,ecx   ; bottom clip >= bottom scan?
 jae @f   ; ECX = cell bottom scan (=bottom scan)
 xchg eax,ecx   ; ECX = cell bottom scan (=bottom clip)
 sub eax,ecx   ; number of scans to be skipped
 imul eax,eax,SCREEN_CBSCAN
 sub edi,eax   ; EDI = actual start address (clipped)
@@: cmp ebx,edx   ; top clip <= top scan?
 jbe @f   ; EDX = cell top scan (=top scan)
 xchg ebx,edx   ; EDX = cell top scan (=top clip)
@@: sub ecx,edx   ; ECX = number of scans to be drawn

 public AVioDrawGridNC
AVioDrawGridNC::

; Setup graphics controller for drawing gridlines.

 mov dx,EGA_BASE+GRAF_ADDR ; DX = port address
 mov ax,GRAF_SET_RESET+(MM_ALL shl 8)
 and ah,bPhysColor
 out dx,ax   ; set grid color
 mov al,GRAF_BIT_MASK
 mov ah,byte ptr wMask[1] ; first byte mask
 out dx,ax

; Draw horizontal/vertical grid for this cell.

 test wAVioAttributes,AVioVerticalGridMask
 jnz ag_draw_vert_grid
 dec ecx   ; adjust destination address
 imul ecx,ecx,SCREEN_CBSCAN
 sub edi,ecx
 jmp ag_draw_horz_grid

ag_draw_vert_grid:
 mov ch,bVertGridMask ; CH = vertical grid pattern
ag_draw_vert_loop:
 mov ah,ch
 xchg ah,[edi]
 dec cl
 jz ag_draw_horz_grid
 sub di,SCREEN_CBSCAN
 jmp ag_draw_vert_loop

ag_draw_horz_grid:
 test wAVioAttributes,AVioHorizontalGridMask
 jz ag_exit

 mov ch,bHorzGridMask ; CH = horizontal grid pattern
 mov cl,ch
 xchg ch,[edi]
 mov ah,byte ptr wMask[0] ; second byte mask
 out dx,ax
 mov ah,bHorzGridMask
 xchg cl,[edi+1]

ag_exit:
 ret
AVioDrawGrid  endp

 OPTION PROLOGUE:PrologueDef
 OPTION EPILOGUE:EpilogueDef

 SUBTITLE GetFontOffset
 PAGE +

;---------------------------Private Routine-----------------------------;
; GetFontOffset     - with    default substitution
; GetFontOffsetNS   - without default substitution
;
; Get effective font offset for specified pseudo code.
;
; Entry:
; ESI = pseudo code
; EBP = CharRect frame
; Returns:
; ESI = effective font offset
; CL = phase for this cell
; Registers Destroyed:
; none.
; Registers Preserved:
; EAX,EBX,EDX,EBP,EDI
; History:
;  Tue 30-Jul-1991 -by-  Soh Ohta [jl09057 @ ymtvm3]
; Created.
;-----------------------------------------------------------------------;

 OPTION PROLOGUE:NONE
 OPTION EPILOGUE:NONE

;ALIGN 4
define_CharRect_frame GetFontOffset

 cmp esi,-2   ; DBCS virtual glyph index?
 jb GetFontOffsetNS  ; yes...

 mov esi,wDefaultGlyph
 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
 add esi,wselfontsave ; ESI --> Character bitmap
 xor cl,cl   ; phase align = 0
 ret

 public GetFontOffsetNS
GetFontOffsetNS::

 and esi,not PSEUDO_DBCS_1ST ; get array (cb_adbcschar) index
 test esi,1   ; odd number ?
 jnz gfo_dbcs_2nd  ;   means DBCS trailing byte

gfo_dbcs_1st:    ; DBCS leading byte
 mov esi,CellBLTBlock.cb_adbcschar[esi]
 imul esi,esi,6
 add esi,wselfontsave ; ESI --> Glyph description
 mov esi,[esi].FONTMAP.fsCharOffset.VIO_FONT_ENTRIES.fe_dBits
 add esi,wselfontsave ; ESI --> Character bitmap
 xor cl,cl   ; phase align = 0
 ret

gfo_dbcs_2nd:    ; DBCS trailing byte
 dec esi
 mov esi,CellBLTBlock.cb_adbcschar[esi]
 imul esi,esi,6
 add esi,wselfontsave ; ESI --> Glyph description
 mov esi,[esi].FONTMAP.fsCharOffset.VIO_FONT_ENTRIES.fe_dBits
 add esi,wselfontsave ; ESI --> Character bitmap
 add esi,CellBLTBlock.cb_dbcs_2nd
     ; ESI --> DBCS 2nd byte font address
 mov cl,bCellWidth  ; phase align = for DBCS 2nd byte
 ret

GetFontOffset endp

 OPTION PROLOGUE:PrologueDef
 OPTION EPILOGUE:EpilogueDef

endif;VGA
